Source code for pypot.server.httpserver

import json
import socket
import errno
import numpy
import logging

from tornado.ioloop import IOLoop
from tornado.web import RequestHandler
from tornado.web import Application

from .server import AbstractServer

logger = logging.getLogger(__name__)


[docs]class MyJSONEncoder(json.JSONEncoder): """ JSONEncoder which tries to call a json property before using the enconding default function. """
[docs] def default(self, obj): if hasattr(obj, 'json'): return obj.json if isinstance(obj, numpy.ndarray): return list(obj) if isinstance(obj, numpy.integer): return int(obj) return json.JSONEncoder.default(self, obj)
[docs]class PoppyRequestHandler(RequestHandler): """Custom request handler. Automatically sets CORS and cache headers, and manages every OPTIONS request."""
[docs] def set_default_headers(self): self.set_header('Cache-control', 'no-store') self.set_header('Access-Control-Allow-Origin', '*') self.set_header('Access-Control-Allow-Headers', 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token') self.set_header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
[docs] def options(self, *args, **kwargs): self.set_status(204)
[docs] def write_json(self, obj): self.write(json.dumps(obj, cls=MyJSONEncoder))
[docs]class IndexHandler(PoppyRequestHandler):
[docs] def get(self, *args): out = { 'motors': [], 'primitives': [] } for m in self.restful_robot.get_motors_list('motors'): motor = {} for r in self.restful_robot.get_motor_registers_list(m): try: motor[r] = self.restful_robot.get_motor_register_value(m, r) except AttributeError: pass out['motors'].append(motor) running_primitives = self.restful_robot.get_running_primitives_list() for prim in self.restful_robot.get_primitives_list(): primitve = { 'primitive': prim, 'running': prim in running_primitives, 'properties': [], # XXX pas de self en param ? 'methods': self.restful_robot.get_primitive_methods_list(prim) } for prop in self.restful_robot.get_primitive_properties_list(prim): primitve['properties'].append({ 'property': prop, 'value': self.restful_robot.get_primitive_property(prim, prop) }) out['primitives'].append(primitve) self.write_json(out)
[docs]class MotorsListHandler(PoppyRequestHandler):
[docs] def get(self, alias='motors'): self.write_json({ 'alias': self.restful_robot.get_motors_list(alias) })
[docs]class SensorsListHandler(PoppyRequestHandler):
[docs] def get(self): self.write_json({ 'sensors': self.restful_robot.get_sensors_list() })
[docs]class MotorsAliasesListHandler(PoppyRequestHandler):
[docs] def get(self): self.write_json({ 'alias': self.restful_robot.get_motors_alias() })
[docs]class MotorRegistersListHandler(PoppyRequestHandler):
[docs] def get(self, motor_name): self.write_json({ 'registers': self.restful_robot.get_motor_registers_list(motor_name) })
[docs]class MotorRegisterHandler(PoppyRequestHandler):
[docs] def get(self, motor_name, register_name): self.write_json({ register_name: self.restful_robot.get_motor_register_value(motor_name, register_name) })
[docs]class UpdateMotorRegisterHandler(PoppyRequestHandler):
[docs] def post(self, motor_name, register_name): data = json.loads(self.request.body.decode()) self.restful_robot.set_motor_register_value(motor_name, register_name, data) self.write_json({})
[docs]class PrimitivesListHandler(PoppyRequestHandler):
[docs] def get(self): self.write_json({ 'primitives': self.restful_robot.get_primitives_list() })
[docs]class RunningPrimitivesListHandler(PoppyRequestHandler):
[docs] def get(self): self.write_json({ 'running_primitives': self.restful_robot.get_running_primitives_list() })
[docs]class StartPrimitiveHandler(PoppyRequestHandler):
[docs] def get(self, primitive_name): self.restful_robot.start_primitive(primitive_name)
[docs]class StopPrimitiveHandler(PoppyRequestHandler):
[docs] def get(self, primitive_name): self.restful_robot.stop_primitive(primitive_name)
[docs]class PausePrimitiveHandler(PoppyRequestHandler):
[docs] def get(self, primitive_name): self.restful_robot.pause_primitive(primitive_name)
[docs]class ResumePrimitiveHandler(PoppyRequestHandler):
[docs] def get(self, primitive_name): self.restful_robot.resume_primitive(primitive_name)
[docs]class PrimitivePropertiesListHandler(PoppyRequestHandler):
[docs] def get(self, primitive_name): self.write_json({ 'property': self.restful_robot.get_primitive_properties_list(primitive_name) })
[docs]class PrimitivePropertyHandler(PoppyRequestHandler):
[docs] def get(self, primitive_name, prop): response = self.restful_robot.get_primitive_property(primitive_name, prop) self.write_json({ '{}.{}'.format(primitive_name, prop): response })
[docs]class SetPrimitivePropertyHandler(PoppyRequestHandler):
[docs] def post(self, primitive_name, prop): data = json.loads(self.request.body.decode()) self.restful_robot.set_primitive_property(primitive_name, prop, data) self.set_status(204)
[docs]class ListPrimitiveMethodsHandler(PoppyRequestHandler):
[docs] def get(self, primitive_name): self.write_json({ 'methods': self.restful_robot.get_primitive_methods_list(primitive_name) })
[docs]class CallPrimitiveMethodHandler(PoppyRequestHandler):
[docs] def post(self, primitive_name, method_name): data = json.loads(self.request.body.decode()) response = self.restful_robot.call_primitive_method(primitive_name, method_name, data) self.write_json({ '{}:{}'.format(primitive_name, method_name): response })
[docs]class MotorsRegistersHandler(PoppyRequestHandler):
[docs] def get(self, register_name): motors_list = self.restful_robot.get_motors_list('motors') registers_motors = {} for motor_name in motors_list: registers_motors[motor_name] = { register_name: self.restful_robot.get_motor_register_value( motor_name, register_name) } self.write_json(registers_motors)
[docs]class HTTPRobotServer(AbstractServer): """Refer to the REST API for an exhaustive list of the possible routes.""" def __init__(self, robot, host='0.0.0.0', port='8080', cross_domain_origin='*', **kwargs): AbstractServer.__init__(self, robot, host, port)
[docs] def make_app(self): PoppyRequestHandler.restful_robot = self.restful_robot return Application([ (r'/(robot\.json)?', IndexHandler), (r'/motor/alias/list\.json', MotorsAliasesListHandler), (r'/motor/(?P<alias>[a-zA-Z0-9_]+)/?list\.json', MotorsListHandler), (r'/sensor/list\.json', SensorsListHandler), (r'/motor/(?P<motor_name>[a-zA-Z0-9_]+)/register/list\.json', MotorRegistersListHandler), (r'/sensor/(?P<motor_name>[a-zA-Z0-9_]+)/register/list\.json', MotorRegistersListHandler), (r'/motor/(?P<motor_name>[a-zA-Z0-9_]+)/register/(?P<register_name>[a-zA-Z0-9_]+)/list\.json', MotorRegisterHandler), (r'/sensor/(?P<motor_name>[a-zA-Z0-9_]+)/register/(?P<register_name>[a-zA-Z0-9_]+)/list\.json', MotorRegisterHandler), (r'/motor/(?P<motor_name>[a-zA-Z0-9_]+)/register/(?P<register_name>[a-zA-Z0-9_]+)', MotorRegisterHandler), (r'/sensor/(?P<motor_name>[a-zA-Z0-9_]+)/register/(?P<register_name>[a-zA-Z0-9_]+)', MotorRegisterHandler), (r'/motor/(?P<motor_name>[a-zA-Z0-9_]+)/register/(?P<register_name>[a-zA-Z0-9_]+)/value\.json', UpdateMotorRegisterHandler), (r'/sensor/(?P<motor_name>[a-zA-Z0-9_]+)/register/(?P<register_name>[a-zA-Z0-9_]+)/value\.json', UpdateMotorRegisterHandler), (r'/primitive/list\.json', PrimitivesListHandler), (r'/primitive/running/list\.json', RunningPrimitivesListHandler), (r'/primitive/(?P<primitive_name>[a-zA-Z0-9_]+)/start\.json', StartPrimitiveHandler), (r'/primitive/(?P<primitive_name>[a-zA-Z0-9_]+)/stop\.json', StopPrimitiveHandler), (r'/primitive/(?P<primitive_name>[a-zA-Z0-9_]+)/pause\.json', PausePrimitiveHandler), (r'/primitive/(?P<primitive_name>[a-zA-Z0-9_]+)/resume\.json', ResumePrimitiveHandler), (r'/primitive/(?P<primitive_name>[a-zA-Z0-9_]+)/property/list\.json', PrimitivePropertiesListHandler), (r'/primitive/(?P<primitive_name>[a-zA-Z0-9_]+)/property/(?P<prop>[a-zA-Z0-9_]+)', PrimitivePropertyHandler), (r'/primitive/(?P<primitive_name>[a-zA-Z0-9_]+)/property/(?P<prop>[a-zA-Z0-9_]+)/value\.json', SetPrimitivePropertyHandler), (r'/primitive/(?P<primitive_name>[a-zA-Z0-9_]+)/method/list\.json', ListPrimitiveMethodsHandler), (r'/primitive/(?P<primitive_name>[a-zA-Z0-9_]+)/method/(?P<method_name>[a-zA-Z0-9_]+)/args\.json', CallPrimitiveMethodHandler), (r'/motors/register/(?P<register_name>[a-zA-Z0-9_]+)', MotorsRegistersHandler), ])
[docs] def run(self, **kwargs): """ Start the tornado server, run forever""" try: loop = IOLoop() app = self.make_app() app.listen(self.port) loop.start() except socket.error as serr: # Re raise the socket error if not "[Errno 98] Address already in use" if serr.errno != errno.EADDRINUSE: raise serr else: logger.warning('The webserver port {} is already used. May be the HttpRobotServer is already running or another software is using this port.'.format(self.port))