peerlink/peerlink/server.py

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 = '[::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()