Browse Source

py3port: 2to3 on all files

MMGen 6 years ago
parent
commit
4e7a8332f8
4 changed files with 11 additions and 1040 deletions
  1. 0 1029
      btc-ticker
  2. 6 6
      mmgen/node_tools/Util.py
  3. 4 4
      mmnode-peerblocks
  4. 1 1
      setup.py

+ 0 - 1029
btc-ticker

@@ -1,1029 +0,0 @@
-#!/usr/bin/python
-# -*- coding: UTF-8 -*-
-#
-# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C)2013-2016 Philemon <mmgen-py@yandex.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-"""
-btc-ticker: ticker and alarm clock for mmgen-node-tools
-"""
-
-import sys,os,time,subprocess
-import threading as th
-from collections import OrderedDict
-from decimal import Decimal
-
-from mmgen.share import Opts
-from mmgen.util import msg,msg_r,die,die_pause
-from mmgen.node_tools.Global import *
-from mmgen.node_tools.Util import *
-from mmgen.node_tools.Sound import *
-from mmgen.node_tools.Term import *
-
-die_pause(1,'Ticker temporarily disabled') # DEBUG
-
-from mmgen.color import *
-init_color()
-
-quit = False
-sound_vol = float(100)
-audio_host,repeat_spec = '','3s:5m,1m:30m,5m:1h,30m:1d'
-# repeat_spec = '1:5m'  # DEBUG
-valid_loglevels = OrderedDict([(1,'info'),(2,'data'),(3,'debug')])
-logfile = 'ticker_log.txt'
-alrm_clock = 'off'
-num_digits = 6
-proxy = None
-fx_host= 'https://finance.yahoo.com'
-
-sounds_dir = nt.system_data_dir+'/audio'
-sounds = {
-	'lo':          [sounds_dir+'/ringtone.wav',     95],
-	'hi':          [sounds_dir+'/Positive.wav',     102],
-	'conn_err':    [sounds_dir+'/Rhodes.wav',       105],
-	'alrm_clock':  [sounds_dir+'/Counterpoint.wav', 105],
-}
-alrm_names = tuple(sounds.keys())
-
-dlock,llock,alock = th.Lock(),th.Lock(),th.Lock()
-
-data_dir = nt.data_dir+'/lib/ticker/'
-
-try: os.makedirs(data_dir)
-except: pass
-
-def update_fx(a,b,debug=False):
-	if debug:
-		with open('/tmp/ticker.out') as f: text = f.read()
-	else:
-		text = get_url('{}/q?s={}{}'.format(fx_host,a,b),gzip_ok=True,proxy=proxy,debug=debug_curl)
-	if not text: return False
-	import re
-	ret = re.split('yfs_l10_{}{}=.+?>'.format(a,b),text,maxsplit=1)[1].split('<',1)[0][:10]
-	try:
-		globals()[a+b] = float(ret)
-		with open(data_dir+'/{}{}.txt'.format(a,b),'wb') as f: f.write(ret+'\n')
-		return True
-	except:
-		return False
-
-def get_fx(a,b):
-	try:
-		with open(data_dir+'/{}{}.txt'.format(a,b)) as f:
-			d = f.read().rstrip()
-		globals()[a+b] = float(d)
-		return True
-	except:
-		return update_fx(a,b)
-
-with open('/etc/timezone') as f:
-	os.environ['TZ'] = f.read().rstrip()
-
-class Xch(object): pass
-class Src(object): pass
-
-num_xchgs = 2
-xchgs = tuple([Xch() for i in range(num_xchgs)])
-
-sources = OrderedDict([('tc','ticker')])
-for g in xchgs:
-	for k in sources:
-		setattr(g,k,Src())
-		setattr(getattr(g,k),'desc',sources[k])
-
-for g in [xchgs[0]]:
-	g.cur = 'USD'
-# 	g.Desc = 'OKCoin USD'
-# 	g.desc = 'okcoin_usd'
-# 	g.desc_short = 'okc'
-# 	g.tc.url = 'https://www.okcoin.com/api/v1/ticker.do?symbol=btc_usd'
-	g.Desc = 'Gemini'
-	g.desc = 'gemini'
-	g.desc_short = 'gem'
-	g.tc.url = 'https://api.gemini.com/v1/pubticker/btcusd'
-	g.poll_secs = 60
-	g.cur_sign = '$'
-	g.xcur_sign = '¥'
-	g.fiat_precision = 2
-	g.hi_alrm = 999999
-	g.lo_alrm = 1
-	g.cc_unit = 'BTC'
-
-for g in [xchgs[1]]:
-	g.cur = 'CNY'
-	g.Desc = 'OKCoin CNY'
-	g.desc = 'okcoin_cny'
-	g.desc_short = 'okc'
-	g.tc.url = 'https://www.okcoin.cn/api/v1/ticker.do?symbol=btc_cny'
-	g.poll_secs = 60
-	g.cur_sign = '¥'
-	g.xcur_sign = '$'
-	g.fiat_precision = 1
-	g.hi_alrm = 999999
-	g.lo_alrm = 1
-	g.cc_unit = 'BTC'
-
-# 	g.cur = 'USD'
-# 	g.Desc = 'BitFinex'
-# 	g.desc = 'bitfinex'
-# 	g.desc_short = 'bfx'
-# 	g.tc.url = 'https://api.bitfinex.com/v1/pubticker/btcusd'
-
-# Gemini - available symbols: btcusd ethbtc ethusd
-# 	g.cur = 'USD'
-# 	g.Desc = 'Gemini'
-# 	g.desc = 'gemini'
-# 	g.desc_short = 'gem'
-# 	g.tc.url = 'https://api.gemini.com/v1/pubticker/btcusd'
-
-opts_data = {
-	'prog_name': sys.argv[0].split('/')[-1],
-	'desc': 'Price alarm for Bitcoin exchange',
-	'usage': '[opts] [<low price alarm> <high price alarm>]',
-#-b, --big-number         Print big numbers
-	'options': """
--h, --help               Print this help message
--a, --alarm-clock-only   Disable ticker, use as alarm clock only
--c, --cur-ticker-only    Display only current exchange's ticker price
--d, --debug              Debug mode.  Use saved HTTP data from files
--D, --debug-curl         Debug curl
--l, --log=             l Log all data to file '{lf}' at levels 'l' (comma-separated: {lls})
--n, --num-digits=      n Display 'n' number of big digits
--p, --poll-intervals=i1[,i2] Poll servers every 'i' seconds (default: '{pi}')
--P, --proxy=           x Connect via proxy 'x' (see PROXY EXAMPLES below for format)
--r, --repeat-spec        Sleep interval/duration program for the alarm
-                         (default: '{r}')
-                         (see REPEAT SPEC FORMAT below)
--R, --resize-window      Resize window to optimum dimensions
--t, --testing            Testing mode.  Don't execute shell commands
--u, --utc                Show times in UTC rather than local time
--v, --volume=          n Adjust sound volume by percentage 'n' (default: {v})
--V, --test-volume        Test the alarm volume and exit
--x, --xchgs=     x,y[,…] Display only exchanges 'x,y[,…]' (comma-separated
-                         list of integers, see CONFIGURED EXCHANGES below)
-""".format(
-		v=int(sound_vol),
-		pi = ','.join([str(g.poll_secs) for g in xchgs]),
-		r=repeat_spec,
-		lf=logfile,
-		lls=', '.join(['%s=%s'%(i,j) for i,j in valid_loglevels.items()])
-	),
-	'notes': '''
-
-REPEAT SPEC FORMAT:
-  <interval>:<duration>[,<interval>:<duration>[,…]]
-  For example, '3s:5m,1m:2h,30m:1d' means:
-    ring alarm every 3 seconds for 5 minutes,
-    then every minute for 2 hours,
-    then every 30 minutes for 1 day
-
-PROXY EXAMPLES:
-  socks5h://localhost:9050 (for Tor running on localhost)
-  http://192.168.0.4:8118 (for Privoxy running on host 192.168.0.4)
-
-CONFIGURED EXCHANGES:
-  {x}
-'''.format(
-		x='\n  '.join(['%s - %s'%(n,x.Desc) for n,x in enumerate(xchgs,1)])
-	)
-}
-
-opts,args = Opts.parse_opts(sys.argv,opts_data)[:2]
-
-debug_curl = 'debug_curl' in opts
-proxy = opts['proxy'] if 'proxy' in opts else None
-
-# Global var: the currently displayed exchange
-if 'alarm_clock_only' in opts:
-	num_digits = 4
-	mute_alrms = False
-	ga = None
-	xchgs = []
-else:
-	mute_alrms = True
-	ga = xchgs[0]
-	fx_pairs = [('usd','cny')]
-	for a,b in fx_pairs:
-		msg_r('Getting {}/{} exchange rate...'.format(a.upper(),b.upper()))
-		if get_fx(a,b):
-			msg('OK')
-		else:
-			die_pause(1,'Unable to get {}/{} exchange rate'.format(a.upper(),b.upper()))
-
-	if 'xchgs' in opts:
-		usr_xchgs = [int(i)-1 for i in opts['xchgs'].split(',')]
-		xchgs = [xchgs[i] for i in usr_xchgs]
-
-	# Initialize some variables for active exchanges
-	for g in xchgs:
-		g.retry_interval = 30
-		g.conn_alrm_timeout = 300
-		g.tc.bal = 0.0,0.0,0.0
-		if not hasattr(g,'desc_short'): g.desc_short = g.desc
-		for k in sources:
-			s = getattr(g,k)
-
-main_thrd_names = tuple([x.desc+'_ticker' for x in xchgs])
-kill_flgs = dict([(k,th.Event()) for k in main_thrd_names + ('alrm','clock','log')])
-
-debug = 'debug' in opts
-
-if debug: msg('Debugging mode.  Using saved data from files')
-
-def do_errmsg(s,k='ticker'):
-	if k == 'ticker':
-		with dlock:
-			blank_ticker()
-			msg_r(CUR_HOME)
-			msgred_r(s)
-			time.sleep(5)
-
-def toggle_option(k):
-	with dlock:
-		if k in opts: del opts[k]
-		else: opts[k] = True
-
-def get_thrd_names(): return [i.name for i in th.enumerate()]
-
-def start_alrm(name):
-	kill_flgs['alrm'].clear()
-	t = th.Thread(
-			target = play_sound,
-			name = name,
-			kwargs = {
-				'fn': sounds[name][0], # (fn,vol)
-				'repeat_spec': repeat_spec,
-				'remote_host': audio_host,
-				'vol': sound_vol * sounds[name][1] / 100,
-				'kill_flg': kill_flgs['alrm'],
-				'testing': False
-			}
-		)
-	t.daemon = True
-	t.start()
-
-def start_alrm_maybe(my_thrd_name,kill_list=None):
-
-	if mute_alrms: return
-
-	# Allow for an empty kill list
-	klist = kill_list if kill_list != None else alrm_names
-
-	with alock: # kill alarm thrds except mine
-		if any([n in klist and n != my_thrd_name for n in get_thrd_names()]):
-			kill_flgs['alrm'].set()
-
-		if not my_thrd_name: return  # if thread name 'None', kill first, then return
-
-		if not any([n in alrm_names for n in get_thrd_names()]):
-			start_alrm(my_thrd_name)
-
-def parse_loglevel_arg(s):
-	m1 = 'Invalid loglevel argument: %s\n' % s
-	try: ret = [int(i) for i in s.split(',')]
-	except:
-		m2 = 'Loglevels must be comma-separated int values'
-		return False, m1+m2
-	if not set(ret) <= set(valid_loglevels):
-		m2 = 'Valid loglevels: %s' % ','.join([str(i) for i in valid_loglevels])
-		return False, m1+m2
-	return ret,'OK'
-
-def set_alrm_vals(s):
-	ret = []
-	m1 = 'Invalid alarm argument: %s\n' % s
-	for e in s.split(':'):
-		try: ret.append([Decimal(i) for i in e.split(',')])
-		except:
-			m2 = 'Alarms must be comma-separated decimal values'
-			return False, m1+m2
-		if len(ret[-1]) != 2:
-			m2 = 'Each element of alarm list must have 2 items (lo_alrm,hi_alrm)'
-			return False, m1+m2
-
-	if len(ret) != len(xchgs):
-		m2 = 'Alarm list must be %s colon-separated comma-separated lists' % len(xchgs)
-		return False, m1+m2
-
-	for g,a in zip(xchgs,ret):
-		lo,hi = a
-		if lo > hi:
-			m2 = 'Low alarm (%s) is greater than high alarm (%s)' % (lo,hi)
-			return False, m1+m2
-		setattr(g,'lo_alrm',lo)
-		setattr(g,'hi_alrm',hi)
-
-	return ret,'OK'
-
-def set_poll_intervals(s,xchg=None):
-	ret = []
-	m1 = 'Invalid poll interval argument: %s\n' % s
-	m2 = 'Poll intervals must be comma-separated integer values'
-	m3 = 'Poll interval must be integer value'
-	for e in (s.split(','),[s])[bool(xchg)]:
-		try: ret.append(float(e))
-		except:
-			return False, m1+(m2,m3)[bool(xchg)]
-
-	if not xchg and len(ret) != len(xchgs):
-		m2 = 'Poll interval list have %s items' % len(xchgs)
-		return False, m1+m2
-
-	for g,p in zip((xchgs,[xchg])[bool(xchg)],ret):
-		setattr(g,'poll_secs',float(p))
-
-	return ret,'OK'
-
-def set_xch_param(source,param,s,desc):
-	ret = []
-	m1 = 'Invalid %s argument: %s\n' % (desc,s)
-	for e in s.split(':'):
-		try: ret.append(float(e))
-		except:
-			m2 = '%s arg must be colon-separated float values' % desc.capitalize()
-			return False, m1+m2
-
-	if len(ret) != len(xchgs):
-		m2 = '%s list must have %s colon-separated items' % (
-			desc.capitalize(),len(xchgs))
-		return False, m1+m2
-
-	for g,p in zip(xchgs,ret):
-		a = getattr(g,source)
-		setattr(a,param,float(p))
-
-	return ret,'OK'
-
-if 'log' in opts:
-	loglevels,errmsg = parse_loglevel_arg(opts['log'])
-	if not loglevels: die_pause(1,errmsg)
-	msg('Logging at level{} {}'.format(
-		('s','')[len(loglevels)==1],
-		' '.join([valid_loglevels[i].upper() for i in loglevels])))
-else:
-	loglevels = []
-
-if 'repeat_spec' in opts:
-	repeat_spec = opts['repeat_spec']
-	msg("Using program '{}' for alarm".format(repeat_spec))
-
-if 'num_digits' in opts:
-	n = opts['num_digits']
-	if len(n) != 1 or n not in '56789':
-		die_pause(1,"'%s': invalid value for --num-digits option" % n)
-	num_digits = int(n)
-
-if 'volume' in opts:
-	sound_vol = int(opts['volume'])
-	for k in sounds:
-		sounds[k][1] = float(sounds[k][1] * sound_vol / 100)
-	msg('Adjusting sound volume by {}%'.format(sound_vol))
-
-if 'test_volume' in opts:
-	for k in sounds:
-		msg("Playing '{}' ({})".format(k,sounds[k][0]))
-		play_sound(
-			fn=sounds[k][0],
-			vol=sound_vol * sounds[k][1] / 100,
-			testing='testing' in opts
-		)
-	sys.exit()
-
-if len(args) > 1: Opts.usage(opts_data)
-
-if len(args) == 1:
-	ret,errmsg = set_alrm_vals(args[0])
-	if not ret: die_pause(1,'Error: ' + errmsg)
-	msg('Setting alarms to %s' % ', '.join(['{} {}'.format(i,j) for i,j in ret]))
-
-if 'poll_intervals' in opts:
-	ret,errmsg = set_poll_intervals(opts['poll_intervals'])
-	if not ret: die_pause(1,errmsg)
-	msg('Polling every %s seconds' % ret)
-
-tmux = 'TMUX' in os.environ
-if tmux:
-	subprocess.check_output(['tmux','set','set-titles','on'])
-	subprocess.check_output(['tmux','set','status','off'])
-#	dcmd = "date -R%s | cut -d' ' -f2-5" % ('','u')['utc' in opts]
-#	subprocess.check_output(['tmux','set','status-right','#(%s)' % dcmd])
-
-infoW = 15
-bigDigitsW = big_digits['w']*num_digits + big_digits['pw']*1
-lPaneW = bigDigitsW+infoW+1
-topPaneH,rPaneW = 6,23
-
-def CUR_UP(n):    return '\033[%sA' % n
-def CUR_DOWN(n):  return '\033[%sB' % n
-def CUR_RIGHT(n): return '\033[%sC' % n
-def CUR_LEFT(n):  return '\033[%sD' % n
-def WIN_TITLE(s): return '\033]0;%s\033\\' % s
-def WIN_RESIZE(w,h): return '\033[8;%s;%st' % (h,w)
-def WIN_CORNER(): return '\033[3;200;0t'
-
-CUR_UP1    = '\033[A'
-CUR_DN1    = '\033[B'
-CUR_SHOW    = '\033[?25h'
-CUR_HIDE    = '\033[?25l'
-BLINK       = '\033[5m'
-RESET       = '\033[0m'
-CUR_HOME    = '\033[H'
-ERASE_ALL   = '\033[0J'
-
-def draw_rectangle(s,l,h):
-	msg_r(s + '\n'.join([l] * h))
-def blank_ticker():
-	draw_rectangle(CUR_HOME,' ' * lPaneW,topPaneH)
-def blank_big_digits():
-	draw_rectangle(CUR_HOME,' ' * (bigDigitsW+1),topPaneH)
-def park_cursor():
-	msg_r('\r' + CUR_RIGHT(lPaneW-1))
-def colorize_bal(g,n):
-	d = g.tc
-	fs = '{:.%sf}' % g.fiat_precision
-	return (nocolor,green,red)[
-			(bool(d.save_bal[n]) and
-				(d.bal[n]!=d.save_bal[n]) + (d.bal[n]<d.save_bal[n]))
-		](fs.format(d.bal[n]))
-
-def display_ac_info():
-	ac_fmt = green('--:--') if alrm_clock == 'off' else yelbg(alrm_clock)
-	info_lines = (
-		'{}'.format(ac_fmt),
-		'snd vol: {}%'.format(int(sound_vol)),
-		'{}'.format((yellow('unmuted'),'muted')[mute_alrms]),
-		'{}'.format(blue(audio_host[:infoW] or 'localhost')),
-		'',
-		"'?' for help"
-		)
-	r = CUR_RIGHT(bigDigitsW+1)
-	msg_r(CUR_HOME+r+('\n'+r).join(info_lines))
-	park_cursor()
-	ts = 'Alarm Clock: {}{}'.format(alrm_clock.upper(),('',' (m)')[mute_alrms])
-	if tmux:
- 		subprocess.check_output(['tmux','set','set-titles-string',ts])
- 	else:
-		msg_r(WIN_TITLE(ts))
-
-def display_ticker(g,called_by_clock=False):
-	if not g: return
-	d = g.tc
-	log(3,'display_ticker(): ' + repr(d.__dict__))
-	if not hasattr(d,'timestamp'): return # DEBUG
-
-	avg = sum((d.bal[i] or d.save_bal[i]) for i in range(3)) / 3
-	alrm,lb,hb,rst = (
-		(None,'','',''),
-		('lo',BLINK,'',RESET),
-		('hi','',BLINK,RESET)
-		)[(avg<g.lo_alrm)+(avg>g.hi_alrm)*2]
-
-	start_alrm_maybe(alrm,['lo','hi'])
-
-	if (g is not ga) and not called_by_clock: return
-
-	lfmt = '{n:.{p}f}'.format(p=g.fiat_precision,n=d.bal[2])
-	msg_r(CUR_HOME+lb+hb+display_big_digits(lfmt,pre=' '+rst))
-
-	if (g is not ga) and called_by_clock:
-		park_cursor()
-		return
-
-	hms = get_hms(d.timestamp,utc='utc' in opts)
-	xcur = '{:.2f}'.format(d.bal[2]/usdcny if g.cur == 'CNY' else d.bal[2]*usdcny)
-	ac_fmt = green('--:--') if alrm_clock == 'off' else yelbg(alrm_clock)
-	info_lines = (
-		'{} {}'.format(hms,('%ss'%int(g.poll_secs))),
-		'{} bid/ask'.format(cyan(g.desc_short)),
-		'{} {}'.format(colorize_bal(g,0), colorize_bal(g,1)),
-		'{g.xcur_sign}{x} {h}'.format(g=g,x=xcur,
-			h=('',blue(audio_host[:infoW-len(xcur)-2]))[bool(audio_host)]),
-		'{} {} {}'.format(yellow(('♫','-')[mute_alrms]),
-			lb+yellow(str(g.lo_alrm))+rst,
-			hb+yellow(str(g.hi_alrm))+rst),
-		'{} vol {}%'.format(ac_fmt,int(sound_vol))
-		)
-
-	r = CUR_RIGHT(bigDigitsW+1)
-	msg_r(CUR_HOME+r+('\n'+r).join(info_lines))
-	park_cursor()
-
-	ccs = ('฿','Ł')[g.cc_unit=='LTC']
-
-	if len(xchgs) == 2:
-		x1,x2 = xchgs
-		ts = '{}{:.{}f} / {}{:.{}f}'.format(
-			x1.cur_sign,
-			x1.tc.bal[2],
-			x1.fiat_precision,
-			x2.cur_sign,
-			x2.tc.bal[2],
-			x2.fiat_precision,
-			)
-	else:
-		ts = '{}: {}{:.{}f} ({})'.format(
-			ccs,
-			g.cur_sign,
-			d.bal[2],
-			g.fiat_precision,
-			g.Desc
-			)
-	if tmux:
-# 		subprocess.call(['tmux','rename-session',g.Desc], stderr=subprocess.PIPE)
- 		subprocess.check_output(['tmux','set','set-titles-string',ts])
- 	else:
-		msg_r(WIN_TITLE(ts))
-
-def log(*args): # [lvl,g,src,data] OR [lvl,data]
-	if 'log' in opts and args[0] in loglevels + [0]:
-		if len(args) == 2:
-			s = '{}: {}\n'.format(get_day_hms(),args[1])
-		elif len(args) == 4:
-			s = '{}: {} {} - {}\n'.format(
-				get_day_hms(),
-				args[1].desc_short.upper(),
-				args[2].upper(),
-				args[3]
-			)
-		with llock:
-			fd = os.open(logfile,os.O_RDWR|os.O_APPEND|os.O_CREAT|os.O_SYNC)
-			os.write(fd,s)
-			os.close(fd)
-
-def get_market_data(g,d,connfail_msg='full'):
-#		, post_data={}
-
-	tcd = 'TRADING_CONSOLE_DEBUG_CONNFAIL'
-	debug_connfail = tcd in os.environ and os.environ[tcd]
-	null = None  # hack for eval'ing Huobi trades data
-
-	if debug:
-		fn = 'debug_market_data/%s_ticker.json' % g.desc
-		try:
-			with open(fn) as f: text = f.read()
-			log(3,'get_market_data(): {} {}'.format(g.desc,text))
-			return eval(text)
-		except:
-			die(2,'Unable to open datafile %s' % fn)
-
-	fail_count,conn_begin_time = 0,time.time()
-	if debug_connfail:
-		retry_interval,conn_alrm_timeout = 10,0
-	else:
-		retry_interval,conn_alrm_timeout = g.retry_interval,g.conn_alrm_timeout
-
-	while True:
-		try:
-			text = get_url(d.url,proxy=proxy,debug=debug_curl)
-			log(2,g,d.desc,text)
-			return eval(text)
-		except KeyboardInterrupt:
-			die(1,'\nUser interrupt (get_market_data)\n')
-		except EOFError:
-			die(1,'\nEnd of file\n')
-		except Exception as e:
-			fail_count += 1
-			if connfail_msg:
-				with dlock:
-					if g is ga:
-						m = {
-							'short':'Connect fail ({})'.format(fail_count),
-							'full': 'Connect fail.  Retry in {} seconds ({})'.format(
-											retry_interval,fail_count)
-						}
-						dn = CUR_DOWN(topPaneH-1)
-						blank_big_digits()
-						msg_r(CUR_HOME+dn+m[connfail_msg]+' \b')
-
-			k = '%s_%s' % (g.desc,d.desc)
-
-			if time.time() - conn_begin_time > conn_alrm_timeout:
-				if fail_count == 1:
-					log(1,'Connect error (%s)' % k)
-				if d.desc == 'ticker':
-					with dlock: d.bal = d.bal[:2] + (0.0,) # can't assign to tuple, so this
-				start_alrm_maybe('conn_err')
-
-			# Sleep until user interrupt
-			if kill_flgs[k].wait(retry_interval):
-				kill_flgs[k].clear()
-				return False
-
-def killwait(g,d):
-	log(3,g,d.desc,'Begin wait')
-
-	k = '%s_%s' % (g.desc,d.desc)
-	if kill_flgs[k].wait(g.poll_secs):
-		kill_flgs[k].clear()
-		if quit: return True
-
-	log(3,g,d.desc,'End wait')
-
-	return False
-
-def log_loop():
-	while True:
-		for g in xchgs:
-			with dlock:
-				lstr = '{} last: {}{}'.format(g.desc_short.upper(),g.cur_sign,g.tc.bal[2])
-			log(1,lstr)
-
-		if kill_flgs['log'].wait(30):
-			kill_flgs['log'].clear()
-			if quit: return True
-
-def ticker_loop(g):
-	d = g.tc
-	while True:
-		ret = get_market_data(g,d)
-		log(3,'get_market_data() returned: {}'.format(repr(ret)))
-
-		if not ret: # kill flag was set
-			if quit: break
-			continue
-
-		errmsg = 'ticker_loop: HTTP returned bad data'
-		with dlock:
-			millisec = False
-			if g.desc == 'bitfinex':
-				a = ret
-				bal = 'bid','ask','last_price'
-				ts = ret['timestamp']
-			elif g.desc == 'gemini':
-				a = ret
-				bal = 'bid','ask','last'
-				try:
-					ts = ret['volume']['timestamp']
-				except:
-					log(1,errmsg); continue
-				millisec = True
-			elif g.desc in ('okcoin_usd','okcoin_cny','huobi'):
-				try:
-					a = ret['ticker']
-				except:
-					log(1,errmsg); continue
-				bal = 'buy','sell','last'
-				ts = ret[('time','date')[g.desc[:6]=='okcoin']]
-			else:
-				die(1,"Can't handle symbol '{}'".format(g.desc))
-# okcoin.cn CNY: {"date":"1477932232","ticker":{"buy":"4844.13","high":"4873.36","last":"4844.16","low":"4660.0","sell":"4844.14","vol":"2992115.73393084"}}
-# gemini: {"bid":"1025.64","ask":"1026.93","volume":{"BTC":"1710.8752181914","USD":"1734356.065049020336","timestamp":1486377600000},"last":"1026.93"}
-# okcoin.com USD {"date":"1486581152","ticker":{"buy":"1057.59","high":"1070.0","last":"1059.63","low":"1002.51","sell":"1058.34","vol":"4118.856"}}
-
-			try:
-				d.timestamp = int(float(ts))
-			except:
-				log(1,errmsg); continue
-
-			if millisec: d.timestamp /= 1000
-
-			d.save_bal = d.bal
-			try:
-				d.bal = tuple([float(a[k]) for k in bal])
-			except:
-				log(1,errmsg); continue
-
-			log(3,'{}: timestamp {}, bal {}'.format(g.desc,d.timestamp,d.bal))
-
-		if killwait(g,d): break
-
-def clock_loop():
-	ac_active = False
-	ac_prefix=('     ','')['alarm_clock_only' in opts]
-
-	def do_ticker(x):
-		with dlock:
-			blank_big_digits()
-			display_ticker(x,called_by_clock=True)
-		if kill_flgs['clock'].wait(2): sys.exit()
-
-	while True:
-		if 'alarm_clock_only' in opts:
-			with dlock:
-				blank_ticker()
-				display_ac_info()
-		elif not ac_active:
-			if 'cur_ticker_only' in opts:
-				do_ticker(ga)
-			else:
-				for x in xchgs: do_ticker(x)
-
-		if alrm_clock == 'off' and ac_active:
-			ac_active = False
-
-		if alrm_clock != 'off' or 'alarm_clock_only' in opts:
-			now = get_hms(no_secs=True)
-			if now == alrm_clock:
-				ac_active = True
-				start_alrm_maybe('alrm_clock',['alrm_clock'])
-			if not any([(n in alrm_names and n != 'alrm_clock') for n in get_thrd_names()]):
-				bl,rs = (('',''),(BLINK,RESET))[ac_active]
-				with dlock:
-					blank_big_digits()
-					msg_r(CUR_HOME+bl+display_big_digits(now,pre=ac_prefix)+rs)
-					park_cursor()
-				if kill_flgs['clock'].wait(2): return
-
-def input_loop():
-
-	global ga,sound_vol,alrm_clock,quit,mute_alrms
-	from mmgen.node_tools.Term import get_keypress
-
-	if 'alarm_clock_only' not in opts:
-		msg("Type '?' for help after the ticker starts")
-	ch = get_keypress("Hit 'q' to quit, any other key to continue: ")
-	if ch == 'q': die(0,'')
-
-	if 'resize_window' in opts:
-		if tmux:
-			msg('\nWARNING: Window resizing doesn\'t work in tmux')
-		else:
-			msg_r(WIN_RESIZE(lPaneW,topPaneH))
-			msg_r(WIN_CORNER())
-			time.sleep(0.1)
-
-	from mmgen.term import set_terminal_vars
-	set_terminal_vars()
-	from mmgen.term import get_terminal_size
-	twid = get_terminal_size()[0]
-	if twid < lPaneW:
-		die_pause(1,'\nTerminal window must be at least %s characters wide' % lPaneW)
-
-	msg_r(CUR_HIDE)
-#	raw_input('\nPress any key to exit'); sys.exit() # DEBUG
-	blank_ticker()
-
-	for k in xchgs:
-		th.Thread(target=globals()['ticker_loop'],args=[k],name=k.desc+'_ticker').start()
-
-	th.Thread(target=clock_loop,name='clock').start()
-	th.Thread(target=log_loop,name='log').start()
-
-	time.sleep(1)  # Hack for get_keypress()
-	def redraw():
-		blank_ticker()
-		display_ticker(ga)
-
-	help_texts = {
-		'tc': '''
-a - set alarm clock          l - set low alarm
-A - set remote audio host    m - mute alarms
-e - update USD/CNY rate      M - write message to log
-G - set log levels           p - set poll interval
-h - set high alarm           t - reload ticker
-k - kill alarm               v - set sound volume
-L - log current state        x - cycle thru exchanges
-c - toggle display of current ticker only
--/+ - adjust sound volume
-''',
-		'ac': '''
-a - set alarm clock         m - mute alarms
-A - set remote audio host   k - kill alarm
-M - write message to log    v - set sound volume
--/+ - adjust sound volume
-'''
-	}
-	help_text = ['{:^{w}}'.format('KEYSTROKE COMMANDS',w=lPaneW)]
-	help_text += help_texts[('tc','ac')['alarm_clock_only' in opts]].strip().split('\n')
-	help_text_prompt = 'ESC or ENTER to exit, ↑ and ↓ to scroll'
-
-	def do_help():
-		scrollpos = 0
-		def fmt_help_txt(pos):
-			return '\n'.join(help_text[pos:pos+5])+'\n'+help_text_prompt+' '
-		with dlock:
-			while True:
-				blank_ticker()
-				ch = get_keypress(CUR_HOME+fmt_help_txt(scrollpos),esc_sequences=True)
-				if ch == CUR_DN1 and scrollpos < len(help_text) - topPaneH + 1:
-					scrollpos += 1
-				elif ch == CUR_UP1 and scrollpos != 0:
-					scrollpos -= 1
-				elif ch in '\n\033': break
-			blank_ticker()
-			display_ticker(ga)
-
-	def ks_msg_nolock(s,delay):
-		blank_ticker()
-		msg_r(CUR_HOME+s)
-		time.sleep(delay)
-		blank_ticker()
-		display_ticker(ga)
-
-	def ks_msg(s,delay):
-		with dlock:
-			ks_msg_nolock(s,delay)
-
-	def set_value(v,prompt,vtype=int,poll=False,source=None,
-					all_srcs=False,global_var=False,allow_empty=False):
-
-		def type_chk(vtype,val):
-			try:
-				vtype(val); return True
-			except:
-				return False
-
-		errmsg = ''
-		with dlock:
-			while True:
-				blank_ticker()
-				em = errmsg+'\n' if errmsg else ''
-				termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, old_termattrs)
-#				time.sleep(0.1)
-				s = raw_input(CUR_HOME+CUR_SHOW+em+prompt)
-				msg_r(CUR_HIDE)
-				if not s:
-					if allow_empty:
-						ks_msg_nolock('Value unset',0.5)
-					else:
-						blank_ticker()
-						display_ticker(ga)
-						return False
-
-				if v == 'alrm_clock':
-					if s == 'off':
-						globals()[v] = s
-						if v in get_thrd_names():
-							kill_flgs['alrm'].set()
-						return s
-					a = s.split(':')
-					ok = True
-					if len(a) != 2: ok = False
-					if ok:
-						try:    h,m = int(a[0]),int(a[1])
-						except: ok = False
-					if ok:
-						if not (24 >= h >= 0): ok = False
-						if not (60 >= m >= 0): ok = False
-					if ok:
-						globals()[v] = '{:02d}:{:02d}'.format(h,m)
-						break
-					else:
-						errmsg = 'Incorrect alarm clock value'
-						continue
-				elif v == 'loglevels':
-					ret,err = parse_loglevel_arg(s)
-					if ret:
-						globals()[v] = ret; break
-					else:
-						errmsg = err; continue
-				elif v == 'poll_secs':
-					ret,errmsg = set_poll_intervals(s,xchg=ga)
-					if ret: break
-					else: continue
-				elif all_srcs:
-					vals = s.split(',')
-					if len(vals) != len(sources):
-						errmsg = 'Input must be %s comma-separated %s values'%(
-							len(sources),vtype.__name__)
-						continue
-					for k,val in zip(sources,vals):
-						ret = type_chk(vtype,val)
-						if ret: setattr(getattr(ga,k),v,vtype(val))
-						else: break
-					if ret: break
-				elif source:
-					if type_chk(vtype,s):
-						setattr(getattr(ga,source),v,vtype(s)); break
-				else:
-					if type_chk(vtype,s):
-						if v == 'hi_alrm' and vtype(s) < ga.lo_alrm:
-							errmsg = 'High alarm must be >= low alarm'
-							continue
-						if v == 'lo_alrm' and vtype(s) > ga.hi_alrm:
-							errmsg = 'Low alarm must be <= high alarm'
-							continue
-						if global_var:
-							globals()[v] = vtype(s); break
-						else:
-							setattr(ga,v,vtype(s)); break
-
-				errmsg = 'Value%s must be of type %s' % (
-						('','s')[all_srcs],vtype.__name__)
-
-			redraw()
-
- 		if poll:
-			kill_flgs[ga.desc+'_ticker'].set()
-
-		return True
-
-	while True:
-		ch = get_keypress()
-		if ch == 'q':
-			quit = True
-			for k in kill_flgs: kill_flgs[k].set()
-			for i in th.enumerate():
-				if i.name in main_thrd_names + alrm_names + ('clock',): i.join()
-			msg('')
-			break
-		elif ch == 'a':
-			m1 = 'Current alarm clock: %s' % alrm_clock
-			m2 = "Enter alarm clock time or 'off': "
-			if set_value('alrm_clock',m1+'\n'+m2):
-				ks_msg("Alarm clock set to %s" % alrm_clock,1.5)
-		elif ch == 'A':
-			set_value('audio_host','Enter remote audio host: ',
-				vtype=str,global_var=True,allow_empty=True)
-		elif ch in 'H?': do_help()
-		elif ch == 'k':
-			if 'alrm_clock' in get_thrd_names(): alrm_clock = 'off'
-			a = any([i in alrm_names for i in get_thrd_names()])
-			log(3,'\n  alrm_names: {}\n  get_thrd_names(): {}'.format(
-				alrm_names,get_thrd_names()))
-			if a: kill_flgs['alrm'].set()
-			ks_msg(('No active alarms','Killing alarm')[a],0.5)
-		elif ch == 'M':
-			with dlock:
-				blank_ticker()
-				termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, old_termattrs)
-				s = raw_input(CUR_HOME+'Enter log message: ')
-				log(0,'USR_MSG: '+s)
-				display_ticker(ga)
-		elif ch == 'm':
-			mute_alrms = not mute_alrms
-			if mute_alrms: kill_flgs['alrm'].set()
-			ks_msg(('Unm','M')[mute_alrms] + 'uting alarms',1)
-			with dlock:
-				blank_ticker()
-				display_ticker(ga)
-		elif ch == 'v': set_value('sound_vol','Enter sound volume: ',global_var=True)
-		elif ch in '-+':
-			with dlock:
-				sound_vol += (1,-1)[ch=='-']
-				blank_ticker(); display_ticker(ga)
-		elif not 'alarm_clock_only' in opts:
-			if ch == 'c':
-				toggle_option('cur_ticker_only')
-				ks_msg('Displaying %s' %
-					('all tickers','current ticker only')['cur_ticker_only' in opts],0.5)
-			elif ch == 'G': set_value('loglevels','Enter log levels: ',global_var=True)
-			elif ch == 'h': set_value('hi_alrm','Enter high alarm: ',Decimal)
-			elif ch == 'l': set_value('lo_alrm','Enter low alarm: ',Decimal)
-			elif ch == 'L':
-				ks_msg('Logging current ticker at %s' % get_hms(),1.5)
-				with dlock:
-					log(0,'{} CUR_STATE\n BID/ASK/LAST {}\n'.format(ga.desc.upper(),ga.tc.bal))
-			elif ch == 'p': set_value('poll_secs',
-				'Enter poll interval: ',float,poll=True)
-			elif ch == 't':
-				key = '%s_ticker' % (ga.desc)
-				if key in kill_flgs:
-					kill_flgs[key].set()
-					ks_msg('Reloading ticker data',1)
-				else:
-					ks_msg('%s: no such key' % key,1)
-			elif ch == 'x':
-				for x in range(len(xchgs)):
-					if ga is xchgs[x]: break
-				new_g = xchgs[x+1 if x+1 < len(xchgs) else 0]
-				ks_msg('Switching to exchange %s' % new_g.Desc,0.5)
-				with dlock:
-					ga = new_g
-					redraw()
-			elif ch == 'e':
-				for a,b in fx_pairs:
-					ks_msg('Updating {}/{} rate'.format(a.upper(),b.upper()),0.5)
-					ret = update_fx(a,b)
-					m,d = (('Unable to update',2),('Updated',0.7))[bool(ret)]
-					ks_msg('{} {}/{} rate'.format(m,a.upper(),b.upper()),d)
-
-def launch(name,*args,**kwargs):
-
-	def at_exit():
-# 		msg_r(CUR_HOME+ERASE_ALL) # DEBUG
- 		msg_r(CUR_SHOW)
-		termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, old_termattrs)
-		for k in kill_flgs: kill_flgs[k].set()
-		for i in th.enumerate():
-			if i.name in main_thrd_names + alrm_names + ('clock',): i.join()
-		if 'log' in opts: log(0,'Exiting')
-
-	import atexit
-	atexit.register(at_exit)
-
-	log(0,'Starting log')
-
-	try:
-		globals()[name](*args,**kwargs)
-	except KeyboardInterrupt:
-		quit = True
-		for k in kill_flgs: kill_flgs[k].set()
-		sys.stderr.write('\nUser interrupt\n')
-
-import termios
-old_termattrs = termios.tcgetattr(sys.stdin.fileno())
-launch('input_loop')

+ 6 - 6
mmgen/node_tools/Util.py

@@ -42,12 +42,12 @@ def do_system(cmd,testing=False,shell=False):
 
 def get_url(url,gzip_ok=False,proxy=None,timeout=60,verbose=False,debug=False):
 	if debug:
-		print 'get_url():'
-		print '  url', url
-		print '  gzip_ok:',gzip_ok, 'proxy:',proxy, 'timeout:',timeout, 'verbose:',verbose
-	import pycurl,cStringIO
+		print('get_url():')
+		print('  url', url)
+		print('  gzip_ok:',gzip_ok, 'proxy:',proxy, 'timeout:',timeout, 'verbose:',verbose)
+	import pycurl,io
 	c = pycurl.Curl()
-	c_out = cStringIO.StringIO()
+	c_out = io.StringIO()
 	c.setopt(pycurl.WRITEFUNCTION,c_out.write)
 	c.setopt(pycurl.TIMEOUT,timeout)
 	c.setopt(pycurl.FOLLOWLOCATION,True)
@@ -118,4 +118,4 @@ def display_big_digits(s,pre='',suf=''):
 
 if __name__ == '__main__':
 	num = '2345.17'
-	print display_big_digits(num,pre='+ ',suf='  +')
+	print(display_big_digits(num,pre='+ ',suf='  +'))

+ 4 - 4
mmnode-peerblocks

@@ -35,7 +35,7 @@ opts_data = lambda: {
 
 cmd_args = opts.init(opts_data)
 
-colors = ['\033[38;5;%s;1m' % c for c in 238,240,242,244,246,247,249,251,253,255]
+colors = ['\033[38;5;%s;1m' % c for c in (238,240,242,244,246,247,249,251,253,255)]
 _red,_reset = '\033[31m','\033[0m'
 
 ERASE_ALL,ERASE_LINE,CUR_HOME,CUR_HIDE,CUR_SHOW = \
@@ -94,12 +94,12 @@ t.start()
 def do_loop():
 	global data
 	while True:
-		raw_input()
+		input()
 		with lock:
 			ids = [str(d['id']) for d in data]
 			msg('{}{}{}ACTIVE PEERS ({})'.format(CUR_HOME,ERASE_ALL,CUR_HOME,len(data)))
-			msg(' '+'\n '.join(['{:>3}: {:30} {}'.format(*[d[k] for k in 'id','addr','subver']) for d in data]))
-			reply = raw_input('Enter a peer number to disconnect> ')
+			msg(' '+'\n '.join(['{:>3}: {:30} {}'.format(*[d[k] for k in ('id','addr','subver')]) for d in data]))
+			reply = input('Enter a peer number to disconnect> ')
 			if reply == '':
 				pass
 			elif reply in ids:

+ 1 - 1
setup.py

@@ -25,7 +25,7 @@ class my_install_data(install_data):
 	def run(self):
 		sdir = os.path.join('data_files','audio')
 		for f in [e for e in os.listdir(sdir) if e[-4:] == '.wav']:
-			os.chmod(os.path.join(sdir,f),0644)
+			os.chmod(os.path.join(sdir,f),0o644)
 		install_data.run(self)
 
 setup(