modified: mmgen/node_tools/Sound.py
modified: mmgen/node_tools/Util.py modified: mmnode-netrate modified: mmnode-peerblocks modified: mmnode-play-sound
This commit is contained in:
parent
b0cd68af35
commit
9f801a9cb3
5 changed files with 138 additions and 95 deletions
|
|
@ -42,22 +42,22 @@ def parse_repeat_spec(rs):
|
|||
def init_sound():
|
||||
def _restore_sound():
|
||||
# msg('Restoring sound volume')
|
||||
do_system('alsactl restore -f ' + _alsa_config_file)
|
||||
do_system('sudo alsactl restore -f ' + _alsa_config_file)
|
||||
os.unlink(_alsa_config_file)
|
||||
import atexit
|
||||
atexit.register(_restore_sound)
|
||||
do_system('alsactl store -f ' + _alsa_config_file)
|
||||
do_system('sudo alsactl store -f ' + _alsa_config_file)
|
||||
|
||||
def play_sound(fn,vol,repeat_spec='',remote_host='',kill_flg=None,testing=False):
|
||||
if not remote_host:
|
||||
do_system('alsactl store -f ' + _alsa_config_file)
|
||||
do_system('sudo alsactl store -f ' + _alsa_config_file)
|
||||
for k in 'Master','Speaker','Headphone':
|
||||
do_system(('amixer -q set %s on' % k),testing)
|
||||
do_system(('sudo amixer -q set %s on' % k),testing)
|
||||
# do_system('amixer -q set Headphone off')
|
||||
|
||||
vols = dict([(k,int(_dvols[k] * float(vol) / 100)) for k in _dvols])
|
||||
for k in vols:
|
||||
do_system('amixer -q set %s %s' % (k,vols[k]),testing)
|
||||
do_system('sudo amixer -q set %s %s' % (k,vols[k]),testing)
|
||||
|
||||
fn = os.path.expanduser(fn)
|
||||
cmd = (
|
||||
|
|
@ -72,9 +72,9 @@ def play_sound(fn,vol,repeat_spec='',remote_host='',kill_flg=None,testing=False)
|
|||
do_system(cmd,testing)
|
||||
if kill_flg.wait(interval):
|
||||
if not remote_host:
|
||||
do_system('alsactl restore -f ' + _alsa_config_file)
|
||||
do_system('sudo alsactl restore -f ' + _alsa_config_file)
|
||||
return
|
||||
else: # Play once
|
||||
do_system(cmd,testing)
|
||||
if not remote_host:
|
||||
do_system('alsactl restore -f ' + _alsa_config_file)
|
||||
do_system('sudo alsactl restore -f ' + _alsa_config_file)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ mmgen.node_tools.Util: utility functions for MMGen node tools
|
|||
"""
|
||||
|
||||
import time,subprocess
|
||||
from mmgen.util import msg
|
||||
|
||||
def get_hms(t=None,utc=False,no_secs=False):
|
||||
secs = t or time.time()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C)2013-2017 Philemon <mmgen-py@yandex.com>
|
||||
# Copyright (C)2013-2020 The MMGen Project <mmgen@tuta.io>
|
||||
#
|
||||
# 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
|
||||
|
|
@ -37,24 +37,33 @@ opts_data = {
|
|||
cmd_args = opts.init(opts_data)
|
||||
|
||||
ERASE_LINE,CUR_UP = '\033[K','\033[1A'
|
||||
c = rpc_init()
|
||||
|
||||
def do_loop():
|
||||
def get_data():
|
||||
d = c.getnettotals()
|
||||
async def main():
|
||||
from mmgen.rpc import rpc_init
|
||||
c = await rpc_init()
|
||||
|
||||
async def get_data():
|
||||
d = await c.call('getnettotals')
|
||||
return [float(e) for e in (d['totalbytesrecv'],d['totalbytessent'],d['timemillis'])]
|
||||
|
||||
r,s,t = get_data()
|
||||
time.sleep(0.2)
|
||||
rs = None
|
||||
while True:
|
||||
rs,ss,ts = r,s,t
|
||||
r,s,t = get_data()
|
||||
td = t-ts
|
||||
sys.stderr.write('\rrcvd: {:9.2f} kB/s\nsent: {:9.2f} kB/s '.format((r-rs)/td,(s-ss)/td))
|
||||
r,s,t = await get_data()
|
||||
|
||||
if rs is not None:
|
||||
sys.stderr.write(
|
||||
'\rrcvd: {:9.2f} kB/s\nsent: {:9.2f} kB/s '.format(
|
||||
(r-rs)/(t-ts),
|
||||
(s-ss)/(t-ts) ))
|
||||
|
||||
time.sleep(2)
|
||||
sys.stderr.write('{}{}{}'.format(ERASE_LINE,CUR_UP,ERASE_LINE))
|
||||
|
||||
if rs is not None:
|
||||
sys.stderr.write('{}{}{}'.format(ERASE_LINE,CUR_UP,ERASE_LINE))
|
||||
|
||||
rs,ss,ts = r,s,t
|
||||
|
||||
try:
|
||||
do_loop()
|
||||
run_session(main(),do_rpc_init=False)
|
||||
except KeyboardInterrupt:
|
||||
sys.stderr.write('\n')
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C)2013-2017 Philemon <mmgen-py@yandex.com>
|
||||
# Copyright (C)2013-2020 The MMGen Project <mmgen@tuta.io>
|
||||
#
|
||||
# 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
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
mmgen-peerblocks: List blocks in flight, disconnect stalling nodes
|
||||
"""
|
||||
|
||||
import time,threading
|
||||
import asyncio
|
||||
from mmgen.common import *
|
||||
|
||||
opts_data = {
|
||||
|
|
@ -34,85 +34,119 @@ opts_data = {
|
|||
}
|
||||
}
|
||||
|
||||
cmd_args = opts.init(opts_data)
|
||||
opts.init(opts_data)
|
||||
|
||||
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'
|
||||
async def inflight_display(rpc):
|
||||
|
||||
ERASE_ALL,ERASE_LINE,CUR_HOME,CUR_HIDE,CUR_SHOW = \
|
||||
'\033[J','\033[K','\033[H','\033[?25l','\033[?25h'
|
||||
def gen_peers(peerinfo):
|
||||
global min_height
|
||||
min_height = None
|
||||
for d in peerinfo:
|
||||
if 'inflight' in d and d['inflight']:
|
||||
blks = d['inflight']
|
||||
if not min_height or min_height > blks[0]:
|
||||
min_height = blks[0]
|
||||
blks_trunc = ' '.join(map(str,blks))[:term_width-6].split()
|
||||
trim = blks_trunc[-1] != str(blks[len(blks_trunc)-1])
|
||||
blks = blks[:len(blks_trunc)-trim]
|
||||
else:
|
||||
blks = []
|
||||
yield { 'id': d['id'], 'data': blks }
|
||||
|
||||
import atexit
|
||||
def at_exit():
|
||||
import os
|
||||
os.system('stty sane')
|
||||
sys.stderr.write('\n')
|
||||
atexit.register(at_exit)
|
||||
def gen_line(peer):
|
||||
for blk in peer['data']:
|
||||
if blk == min_height:
|
||||
yield RED + str(blk) + RESET
|
||||
else:
|
||||
yield COLORS[blk % 10] + str(blk) + RESET
|
||||
|
||||
bc = rpc_init()
|
||||
|
||||
msg_r(CUR_HOME+ERASE_ALL)
|
||||
|
||||
def do_display():
|
||||
from mmgen.term import get_terminal_size
|
||||
global data
|
||||
term_width = get_terminal_size()[0]
|
||||
|
||||
count = 1
|
||||
while True:
|
||||
twid = get_terminal_size()[0]
|
||||
data = bc.getpeerinfo()
|
||||
min_t = None
|
||||
lines = []
|
||||
with lock:
|
||||
msg('{}{}{}ACTIVE PEERS ({}) - poll {}'.format(
|
||||
CUR_HOME,ERASE_ALL,CUR_HOME,len(data),count))
|
||||
for d in data:
|
||||
line = { 'id': d['id'], 'data': [] }
|
||||
if 'inflight' in d and d['inflight']:
|
||||
blks = [str(e) for e in d['inflight']]
|
||||
min_p = min(e for e in d['inflight'])
|
||||
if not min_t or min_t > min_p: min_t = min_p
|
||||
line_d = ' '.join(blks)[:twid-6]
|
||||
blks = blks[:len(line_d) - len(line_d.replace(' ','')) + 1]
|
||||
blks[-1] = blks[-1][:len(line_d.split(' ')[-1])]
|
||||
line['data'] = [[colors[int(i)%10],i,_reset] for i in blks if i]
|
||||
else:
|
||||
line['data'] = []
|
||||
lines.append(line)
|
||||
for line in lines:
|
||||
d = ' '.join([(a,_red)[int(b)==min_t]+b+c for a,b,c in line['data']])
|
||||
sys.stderr.write('\r{} {:>3}: {}\n'.format(ERASE_LINE,line['id'],d))
|
||||
msg_r(ERASE_ALL+'Hit ENTER for disconnect prompt: ')
|
||||
time.sleep(2)
|
||||
info = await rpc.call('getpeerinfo')
|
||||
|
||||
msg_r(CUR_HOME+ERASE_ALL+CUR_HOME)
|
||||
msg(f'ACTIVE PEERS ({len(info)}) - poll {count}')
|
||||
|
||||
for peer in gen_peers(info):
|
||||
sys.stderr.write('\r{} {:>3}: {}\n'.format(
|
||||
ERASE_LINE,
|
||||
peer['id'],
|
||||
' '.join(gen_line(peer)) ))
|
||||
|
||||
msg_r(ERASE_ALL+'Hit ENTER for disconnect prompt: ')
|
||||
await asyncio.sleep(2)
|
||||
count += 1
|
||||
|
||||
lock = threading.Lock()
|
||||
data = {}
|
||||
async def do_inflight(rpc):
|
||||
task = asyncio.ensure_future(inflight_display(rpc)) # Python 3.7+: create_task()
|
||||
from select import select
|
||||
|
||||
t = threading.Thread(target=do_display,name='display')
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
def do_loop():
|
||||
global data
|
||||
while True:
|
||||
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 = input('Enter a peer number to disconnect> ')
|
||||
if reply == '':
|
||||
pass
|
||||
elif reply in ids:
|
||||
idx = ids.index(reply)
|
||||
msg("Disconnecting peer {} ('{}')".format(reply,data[idx]['addr']))
|
||||
bc.disconnectnode(data[idx]['addr'])
|
||||
time.sleep(1.5)
|
||||
else:
|
||||
msg("'{}': invalid peer number".format(reply))
|
||||
time.sleep(0.5)
|
||||
key = select([sys.stdin], [], [], 0.1)[0]
|
||||
if key:
|
||||
sys.stdin.read(1)
|
||||
task.cancel()
|
||||
break
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
try:
|
||||
await task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
async def do_disconnect_menu(rpc):
|
||||
|
||||
while True:
|
||||
peerinfo = await rpc.call('getpeerinfo')
|
||||
ids = [str(d['id']) for d in peerinfo]
|
||||
|
||||
msg_r(CUR_HOME+ERASE_ALL+CUR_HOME)
|
||||
msg(f'ACTIVE PEERS ({len(peerinfo)})')
|
||||
|
||||
if peerinfo:
|
||||
msg('\n'.join([f"{d['id']:>3}: {d['addr']:30} {d['subver']}" for d in peerinfo]))
|
||||
|
||||
reply = input("Peer number to disconnect, ENTER to quit menu, 'u' to update peer list> ")
|
||||
|
||||
if reply == '':
|
||||
return
|
||||
elif reply == 'u':
|
||||
msg(f'Updating peer list')
|
||||
await asyncio.sleep(0.5)
|
||||
elif reply in ids:
|
||||
addr = peerinfo[ids.index(reply)]['addr']
|
||||
msg(f'Disconnecting peer {reply} ({addr})')
|
||||
try:
|
||||
await rpc.call('disconnectnode',addr)
|
||||
except RPCFailure:
|
||||
msg(f'Unable to disconnect peer {addr}')
|
||||
await asyncio.sleep(1.5)
|
||||
else:
|
||||
msg(f'{reply!r}: invalid peer number')
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
async def main():
|
||||
|
||||
msg_r(CUR_HOME+ERASE_ALL)
|
||||
|
||||
from mmgen.rpc import rpc_init
|
||||
rpc = await rpc_init()
|
||||
|
||||
while True:
|
||||
await do_inflight(rpc)
|
||||
await do_disconnect_menu(rpc)
|
||||
|
||||
RED,RESET = ('\033[31m','\033[0m')
|
||||
COLORS = ['\033[38;5;%s;1m' % c for c in (238,240,242,244,246,247,249,251,253,255)]
|
||||
ERASE_ALL,ERASE_LINE,CUR_HOME,CUR_HIDE,CUR_SHOW = (
|
||||
'\033[J','\033[K','\033[H','\033[?25l','\033[?25h')
|
||||
|
||||
try:
|
||||
do_loop()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
run_session(main(),do_rpc_init=False)
|
||||
except:
|
||||
from subprocess import run
|
||||
run(['stty','sane'])
|
||||
msg('')
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C)2013-2016 Philemon <mmgen-py@yandex.com>
|
||||
# Copyright (C)2013-2020 The MMGen Project <mmgen@tuta.io>
|
||||
#
|
||||
# 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
|
||||
|
|
@ -32,6 +32,7 @@ opts_data = {
|
|||
'usage': '[opts]',
|
||||
'options': """
|
||||
-h, --help Print this help message
|
||||
-t, --testing Test, don't execute shell commands
|
||||
-v, --volume= n Adjust sound volume by percentage 'n' (default: {})
|
||||
""".format(volume)
|
||||
}
|
||||
|
|
@ -40,10 +41,8 @@ opts_data = {
|
|||
args = opts.init(opts_data)
|
||||
|
||||
if opt.volume:
|
||||
volume = opt.volume
|
||||
try:
|
||||
volume = int(volume)
|
||||
assert 1 <= volume <= 120
|
||||
assert 1 <= int(opt.volume) <= 120
|
||||
except:
|
||||
die(1,'Sound volume must be an integer between 1 and 120')
|
||||
|
||||
|
|
@ -53,4 +52,4 @@ if len(args) != 1:
|
|||
try: os.stat(args[0])
|
||||
except: die(1,"Couldn't stat file '{}'".format(args[0]))
|
||||
|
||||
play_sound(args[0],volume)
|
||||
play_sound(args[0],int(opt.volume),testing=opt.testing)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue