peerlink/peerlink/server.py

141 lines
3.8 KiB
Python

# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division, print_function
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
import nodes
import nodeserver
import settings
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()