mmnode-peerblocks 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2017 Philemon <mmgen-py@yandex.com>
  5. #
  6. # This program is free software: you can redistribute it and/or modify it under
  7. # the terms of the GNU General Public License as published by the Free Software
  8. # Foundation, either version 3 of the License, or (at your option) any later
  9. # version.
  10. #
  11. # This program is distributed in the hope that it will be useful, but WITHOUT
  12. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  13. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  14. # details.
  15. #
  16. # You should have received a copy of the GNU General Public License along with
  17. # this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. mmgen-peerblocks: List blocks in flight, disconnect stalling nodes
  20. """
  21. import time,threading
  22. from mmgen.common import *
  23. opts_data = lambda: {
  24. 'desc': 'List blocks in flight, disconnect stalling nodes',
  25. 'usage': '[opts]',
  26. 'options': """
  27. -h, --help Print this help message
  28. --, --longhelp Print help message for long options (common options)
  29. """
  30. }
  31. cmd_args = opts.init(opts_data)
  32. colors = ['\033[38;5;%s;1m' % c for c in (238,240,242,244,246,247,249,251,253,255)]
  33. _red,_reset = '\033[31m','\033[0m'
  34. ERASE_ALL,ERASE_LINE,CUR_HOME,CUR_HIDE,CUR_SHOW = \
  35. '\033[J','\033[K','\033[H','\033[?25l','\033[?25h'
  36. import atexit
  37. def at_exit():
  38. import os
  39. os.system('stty sane')
  40. sys.stderr.write('\n')
  41. atexit.register(at_exit)
  42. bc = rpc_init()
  43. msg_r(CUR_HOME+ERASE_ALL)
  44. def do_display():
  45. from mmgen.term import get_terminal_size
  46. global data
  47. count = 1
  48. while True:
  49. twid = get_terminal_size()[0]
  50. data = bc.getpeerinfo()
  51. min_t = None
  52. lines = []
  53. with lock:
  54. msg('{}{}{}ACTIVE PEERS ({}) - poll {}'.format(
  55. CUR_HOME,ERASE_ALL,CUR_HOME,len(data),count))
  56. for d in data:
  57. line = { 'id': d['id'], 'data': [] }
  58. if 'inflight' in d and d['inflight']:
  59. blks = [str(e) for e in d['inflight']]
  60. min_p = min(e for e in d['inflight'])
  61. if not min_t or min_t > min_p: min_t = min_p
  62. line_d = ' '.join(blks)[:twid-6]
  63. blks = blks[:len(line_d) - len(line_d.replace(' ','')) + 1]
  64. blks[-1] = blks[-1][:len(line_d.split(' ')[-1])]
  65. line['data'] = [[colors[int(i)%10],i,_reset] for i in blks if i]
  66. else:
  67. line['data'] = []
  68. lines.append(line)
  69. for line in lines:
  70. d = ' '.join([(a,_red)[int(b)==min_t]+b+c for a,b,c in line['data']])
  71. sys.stderr.write('\r{} {:>3}: {}\n'.format(ERASE_LINE,line['id'],d))
  72. msg_r(ERASE_ALL+'Hit ENTER for disconnect prompt: ')
  73. time.sleep(2)
  74. count += 1
  75. lock = threading.Lock()
  76. data = {}
  77. t = threading.Thread(target=do_display,name='display')
  78. t.daemon = True
  79. t.start()
  80. def do_loop():
  81. global data
  82. while True:
  83. input()
  84. with lock:
  85. ids = [str(d['id']) for d in data]
  86. msg('{}{}{}ACTIVE PEERS ({})'.format(CUR_HOME,ERASE_ALL,CUR_HOME,len(data)))
  87. msg(' '+'\n '.join(['{:>3}: {:30} {}'.format(*[d[k] for k in ('id','addr','subver')]) for d in data]))
  88. reply = input('Enter a peer number to disconnect> ')
  89. if reply == '':
  90. pass
  91. elif reply in ids:
  92. idx = ids.index(reply)
  93. msg("Disconnecting peer {} ('{}')".format(reply,data[idx]['addr']))
  94. bc.disconnectnode(data[idx]['addr'])
  95. time.sleep(1.5)
  96. else:
  97. msg("'{}': invalid peer number".format(reply))
  98. time.sleep(0.5)
  99. try:
  100. do_loop()
  101. except KeyboardInterrupt:
  102. pass