From 4e7a8332f8659f16ccdc7076daf19ccb2f113d00 Mon Sep 17 00:00:00 2001 From: MMGen Date: Fri, 15 Feb 2019 15:45:17 +0000 Subject: [PATCH] py3port: 2to3 on all files --- btc-ticker | 1029 -------------------------------------- mmgen/node_tools/Util.py | 12 +- mmnode-peerblocks | 8 +- setup.py | 2 +- 4 files changed, 11 insertions(+), 1040 deletions(-) delete mode 100755 btc-ticker diff --git a/btc-ticker b/btc-ticker deleted file mode 100755 index ef76152..0000000 --- a/btc-ticker +++ /dev/null @@ -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 -# -# 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 . -# -""" -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] [ ]', -#-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: - :[,:[,…]] - 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]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') diff --git a/mmgen/node_tools/Util.py b/mmgen/node_tools/Util.py index 13e471a..bd91ff0 100644 --- a/mmgen/node_tools/Util.py +++ b/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=' +')) diff --git a/mmnode-peerblocks b/mmnode-peerblocks index 0f5abcd..0ac70e7 100755 --- a/mmnode-peerblocks +++ b/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: diff --git a/setup.py b/setup.py index 8c4fd8f..b0afa40 100755 --- a/setup.py +++ b/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(