mmnode-peerblocks 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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 = {
  24. 'text': {
  25. 'desc': 'List blocks in flight, disconnect stalling nodes',
  26. 'usage': '[opts]',
  27. 'options': """
  28. -h, --help Print this help message
  29. --, --longhelp Print help message for long options (common options)
  30. """
  31. }
  32. }
  33. cmd_args = opts.init(opts_data)
  34. colors = ['\033[38;5;%s;1m' % c for c in (238,240,242,244,246,247,249,251,253,255)]
  35. _red,_reset = '\033[31m','\033[0m'
  36. ERASE_ALL,ERASE_LINE,CUR_HOME,CUR_HIDE,CUR_SHOW = \
  37. '\033[J','\033[K','\033[H','\033[?25l','\033[?25h'
  38. import atexit
  39. def at_exit():
  40. import os
  41. os.system('stty sane')
  42. sys.stderr.write('\n')
  43. atexit.register(at_exit)
  44. bc = rpc_init()
  45. msg_r(CUR_HOME+ERASE_ALL)
  46. def do_display():
  47. from mmgen.term import get_terminal_size
  48. global data
  49. count = 1
  50. while True:
  51. twid = get_terminal_size()[0]
  52. data = bc.getpeerinfo()
  53. min_t = None
  54. lines = []
  55. with lock:
  56. msg('{}{}{}ACTIVE PEERS ({}) - poll {}'.format(
  57. CUR_HOME,ERASE_ALL,CUR_HOME,len(data),count))
  58. for d in data:
  59. line = { 'id': d['id'], 'data': [] }
  60. if 'inflight' in d and d['inflight']:
  61. blks = [str(e) for e in d['inflight']]
  62. min_p = min(e for e in d['inflight'])
  63. if not min_t or min_t > min_p: min_t = min_p
  64. line_d = ' '.join(blks)[:twid-6]
  65. blks = blks[:len(line_d) - len(line_d.replace(' ','')) + 1]
  66. blks[-1] = blks[-1][:len(line_d.split(' ')[-1])]
  67. line['data'] = [[colors[int(i)%10],i,_reset] for i in blks if i]
  68. else:
  69. line['data'] = []
  70. lines.append(line)
  71. for line in lines:
  72. d = ' '.join([(a,_red)[int(b)==min_t]+b+c for a,b,c in line['data']])
  73. sys.stderr.write('\r{} {:>3}: {}\n'.format(ERASE_LINE,line['id'],d))
  74. msg_r(ERASE_ALL+'Hit ENTER for disconnect prompt: ')
  75. time.sleep(2)
  76. count += 1
  77. lock = threading.Lock()
  78. data = {}
  79. t = threading.Thread(target=do_display,name='display')
  80. t.daemon = True
  81. t.start()
  82. def do_loop():
  83. global data
  84. while True:
  85. input()
  86. with lock:
  87. ids = [str(d['id']) for d in data]
  88. msg('{}{}{}ACTIVE PEERS ({})'.format(CUR_HOME,ERASE_ALL,CUR_HOME,len(data)))
  89. msg(' '+'\n '.join(['{:>3}: {:30} {}'.format(*[d[k] for k in ('id','addr','subver')]) for d in data]))
  90. reply = input('Enter a peer number to disconnect> ')
  91. if reply == '':
  92. pass
  93. elif reply in ids:
  94. idx = ids.index(reply)
  95. msg("Disconnecting peer {} ('{}')".format(reply,data[idx]['addr']))
  96. bc.disconnectnode(data[idx]['addr'])
  97. time.sleep(1.5)
  98. else:
  99. msg("'{}': invalid peer number".format(reply))
  100. time.sleep(0.5)
  101. try:
  102. do_loop()
  103. except KeyboardInterrupt:
  104. pass