github.com/annchain/OG@v0.0.9/scripts/boostrap_server/run.py (about)

     1  import os
     2  import threading
     3  import time
     4  
     5  from http.server import BaseHTTPRequestHandler, HTTPServer
     6  import json
     7  import cgi
     8  from urllib.parse import parse_qs
     9  
    10  ttl = 60 * 2
    11  PARTNERS = 2
    12  
    13  # req:
    14  # {"networkid": 1, "publickey":"0x01000000000", "partners": 4, "onode": "onode://d2469187c351fad31b84f4afb2939cb19c03b7c9359f07447aea3a85664cd33d39afc0c531ad4a8e9ff5ed76b58216e19b0ba208b45d5017ca40c9bd351d29ee@47.100.222.11:8001"}
    15  
    16  # resp:
    17  # {"status":"wait/ok/error",
    18  # "bootstrap_node": true,
    19  # "bootstrap_nodes": "onode://d2469187c351fad31b84f4afb2939cb19c03b7c9359f07447aea3a85664cd33d39afc0c531ad4a8e9ff5ed76b58216e19b0ba208b45d5017ca40c9bd351d29ee@47.100.222.11:8001",
    20  # "genesis_pk": "genesis_pk"}
    21  networks = {}
    22  
    23  
    24  def handle(req, sourceip, requirePartners):
    25      network_id = req['networkid']
    26      publickey = req['publickey']
    27      # partners = req['partners']
    28      onode: str = req['onode']
    29      # modify onode's ip to source ip
    30      origin_host = onode[onode.index("@") + 1:onode.index(":", 10)]
    31      if origin_host == '127.0.0.1':
    32          onode = onode[0: onode.index("@") + 1] + sourceip + onode[onode.index(":", 10):]
    33          print('replaced %s to %s' % (origin_host, sourceip))
    34      req['onode'] = onode
    35  
    36      if network_id not in networks:
    37          networks[network_id] = {
    38              'time': time.time(),
    39              'require': requirePartners,
    40              'peers': {}
    41          }
    42      else:
    43          if networks[network_id]['require'] != requirePartners:
    44              msg = {'status': 'error',
    45                     'message': 'someone else specified required partners as %d, earlier than your %d' % (
    46                         networks[network_id]['require'], requirePartners)}
    47              print(msg)
    48              return msg
    49  
    50      d = networks[network_id]
    51  
    52      if publickey not in d['peers']:
    53          req['id'] = len(d['peers'])
    54          d['peers'][publickey] = req
    55  
    56      if len(d['peers']) != d['require']:
    57          msg = {'status': 'wait',
    58                 'message': '%d of %d is registered... waiting for more' % (len(d['peers']), d['require'])}
    59          print(msg)
    60          return msg
    61      items = d['peers'].values()
    62      msg = {'status': 'ok',
    63             'bootstrap_node': d['peers'][publickey]['id'] == 0,
    64             'bootstrap_nodes': ';'.join([x['onode'] for x in items]),
    65             'genesis_pk': ';'.join([x['publickey'] for x in items]),
    66             'partners': len(d['peers'])
    67             }
    68      print(msg)
    69      return msg
    70  
    71  
    72  class Server(BaseHTTPRequestHandler):
    73      def __init__(self, *args, directory=None, **kwargs):
    74          self.lock = threading.Lock()
    75          t = threading.Thread(target=self.wipe)
    76          t.daemon = True
    77          t.start()
    78  
    79          if directory is None:
    80              directory = os.getcwd()
    81          self.directory = directory
    82          super().__init__(*args, **kwargs)
    83  
    84      def _set_headers(self, length):
    85          self.send_response(200)
    86          self.send_header('Content-type', 'application/json')
    87          self.send_header('Content-Length', length)
    88          self.end_headers()
    89  
    90      def do_HEAD(self):
    91          self._set_headers(0)
    92  
    93      # GET sends back a Hello world message
    94      def do_GET(self):
    95          j = bytes(json.dumps(networks, indent=4), 'utf-8')
    96          self._set_headers(len(j))
    97          self.wfile.write(j)
    98  
    99      # POST echoes the message adding a JSON field
   100      def do_POST(self):
   101          ctype, pdict = cgi.parse_header(self.headers.get('content-type'))
   102  
   103          # refuse to receive non-json content
   104          if ctype != 'application/json':
   105              self.send_response(400)
   106              self.end_headers()
   107              return
   108  
   109          # read the message and convert it into a python dictionary
   110          length = int(self.headers.get('content-length'))
   111          message = json.loads(self.rfile.read(length))
   112          required = int(self.path[1:])
   113  
   114          self.lock.acquire()
   115          try:
   116              resp = handle(message, self.client_address[0], required)
   117          finally:
   118              self.lock.release()
   119  
   120          # send the message back
   121          j = bytes(json.dumps(resp), 'utf-8')
   122          self._set_headers(len(j))
   123          self.wfile.write(j)
   124  
   125      def wipe(self):
   126          while True:
   127              self.lock.acquire()
   128              try:
   129                  to_remove = []
   130                  for k, v in networks.items():
   131                      if time.time() - v['time'] > ttl:
   132                          # remove it
   133                          to_remove.append(k)
   134  
   135                  for k in to_remove:
   136                      print('Removing network id', k)
   137                      del networks[k]
   138              finally:
   139                  self.lock.release()
   140              time.sleep(3)
   141  
   142  
   143  def run(server_class=HTTPServer, handler_class=Server, port=8008):
   144      server_address = ('0.0.0.0', port)
   145      httpd = server_class(server_address, handler_class)
   146  
   147      print('Starting httpd on port %d...' % port)
   148      httpd.serve_forever()
   149  
   150  
   151  if __name__ == "__main__":
   152      from sys import argv
   153  
   154      if len(argv) == 2:
   155          run(port=int(argv[1]))
   156      else:
   157          run()