141 lines
3.8 KiB
Python
141 lines
3.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
# vi:si:et:sw=4:sts=4:ts=4
|
|
|
|
|
|
import json
|
|
import os
|
|
import signal
|
|
import sys
|
|
|
|
from tornado.httpserver import HTTPServer
|
|
from tornado.ioloop import IOLoop
|
|
from tornado.web import Application
|
|
import tornado
|
|
|
|
from .proxy import ProxyHandler
|
|
from . import nodes
|
|
from . import nodeserver
|
|
from . import settings
|
|
from . import state
|
|
|
|
import logging
|
|
logger = logging.getLogger('server')
|
|
|
|
|
|
def render_json(handler, response):
|
|
response = json.dumps(response, indent=2)
|
|
handler.set_header('Content-Type', 'application/json')
|
|
handler.set_header('Content-Length', str(len(response)))
|
|
handler.write(response)
|
|
handler.finish()
|
|
|
|
class ServiceHandler(tornado.web.RequestHandler):
|
|
|
|
def handle(self, action):
|
|
response = {}
|
|
if self.request.body:
|
|
data = json.loads(self.request.body)
|
|
else:
|
|
data = {}
|
|
if action == 'add':
|
|
settings.services[data['name']] = data['url']
|
|
response = {'status': 200}
|
|
elif action == 'remove':
|
|
if data['name'] in settings.services:
|
|
del settings.services[data['name']]
|
|
response = {'status': 200}
|
|
elif action == 'info':
|
|
response['id'] = settings.USER_ID
|
|
response['online'] = state.online
|
|
response.update(state.nodes.info())
|
|
else:
|
|
self.set_status(500)
|
|
response = {'error': 'unknown action'}
|
|
return render_json(self, response)
|
|
|
|
def get(self, action):
|
|
return self.handle(action)
|
|
|
|
def post(self, action):
|
|
return self.handle(action)
|
|
|
|
class RequestHandler(ProxyHandler):
|
|
|
|
def sign(self):
|
|
if self.request.body:
|
|
sig = settings.sk.sign(self.request.body, encoding=settings.ENCODING)
|
|
self.request.headers['X-Ed25519-Key'] = settings.USER_ID
|
|
self.request.headers['X-Ed25519-Signature'] = sig
|
|
|
|
def remote_url(self):
|
|
try:
|
|
user_id, uri = self.request.uri[1:].split('/', 1)
|
|
except:
|
|
return None
|
|
node = state.nodes.get(user_id)
|
|
if node:
|
|
self.sign()
|
|
url = node['url'] + '/' + uri
|
|
return url, node['cert']
|
|
else:
|
|
if state.online:
|
|
self.set_status(404)
|
|
render_json(self, {'status': 'unknown peer'})
|
|
else:
|
|
self.set_status(500)
|
|
render_json(self, {'status': 'offline'})
|
|
return None
|
|
|
|
def run(root_dir=None):
|
|
if not root_dir:
|
|
root_dir = os.path.normpath(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..'))
|
|
os.chdir(root_dir)
|
|
PID = sys.argv[1] if len(sys.argv) > 1 else None
|
|
|
|
if not PID:
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
options = {
|
|
'debug': False,
|
|
}
|
|
handlers = [
|
|
(r'/(add|remove|info)', ServiceHandler),
|
|
(r".*", RequestHandler),
|
|
]
|
|
|
|
http_server = HTTPServer(Application(handlers, **options))
|
|
|
|
http_server.listen(settings.server['port'], settings.server['address'])
|
|
|
|
if PID:
|
|
with open(PID, 'w') as pid:
|
|
pid.write('%s' % os.getpid())
|
|
|
|
state.main = IOLoop.instance()
|
|
state.node = nodeserver.start()
|
|
def start_node():
|
|
state.nodes = nodes.Nodes()
|
|
state.main.add_callback(start_node)
|
|
|
|
if ':' in settings.server['address']:
|
|
host = '[%s]' % settings.server['address']
|
|
elif not settings.server['address']:
|
|
host = '127.0.0.1'
|
|
else:
|
|
host = settings.server['address']
|
|
url = 'http://%s:%s/' % (host, settings.server['port'])
|
|
print('peerlink runnig at %s' % url)
|
|
|
|
def shutdown():
|
|
state.nodes.join()
|
|
state.node.stop()
|
|
http_server.stop()
|
|
|
|
signal.signal(signal.SIGTERM, shutdown)
|
|
|
|
try:
|
|
state.main.start()
|
|
except:
|
|
print('shutting down...')
|
|
shutdown()
|