mmnode-peerblocks 3.4 KB

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