Пример #1
0
 def router_option_extender(options):
     from wheezy.routing import PathRouter
     from wheezy.web.middleware.routing import PathRoutingMiddleware
     path_router = PathRouter()
     path_router.add_routes(urls() if callable(urls) else urls)
     options['path_router'] = path_router
     options['path_for'] = path_router.path_for
     return PathRoutingMiddleware(path_router)
Пример #2
0
class PicroscopyWsgiApp(object):
    def __init__(self, **kwargs):
        super().__init__()
        self.library = PicroscopyLibrary(**kwargs)
        self.helpers = WebHelpers(self.library)
        self.clients = kwargs.get('clients', IPv4Network('0.0.0.0/0'))
        logging.info('Clients must be on network %s', self.clients)
        self.static_dir = os.path.abspath(
            os.path.normpath(
                kwargs.get('static_dir', os.path.join(HERE, 'static'))))
        logging.info('Static files: %s', self.static_dir)
        self.templates_dir = os.path.abspath(
            os.path.normpath(
                kwargs.get('templates_dir', os.path.join(HERE, 'templates'))))
        logging.info('Chameleon templates: %s', self.templates_dir)
        self.templates = PageTemplateLoader(self.templates_dir,
                                            default_extension='.pt')
        self.layout = self.templates['layout']
        # No need to make flashes a per-session thing - it's a single user app!
        self.flashes = []
        self.router = PathRouter()
        # XXX Add handler for exiting system
        # XXX Make exit code conditional? (upgrade/reboot/shutdown/etc.)
        self.router.add_routes([
            url('/', self.do_template, kwargs={'page': 'library'},
                name='home'),
            url('/{page}.html', self.do_template, name='template'),
            url('/view/{image}.html',
                self.do_template,
                kwargs={'page': 'image'},
                name='view'),
            url('/static/{path:any}', self.do_static, name='static'),
            url('/images/{image}', self.do_image, name='image'),
            url('/thumbs/{image}', self.do_thumb, name='thumb'),
            url('/delete/{image}', self.do_delete, name='delete'),
            url('/config', self.do_config, name='config'),
            url('/reset', self.do_reset, name='reset'),
            url('/capture', self.do_capture, name='capture'),
            url('/download', self.do_download, name='download'),
            url('/send', self.do_send, name='send'),
            url('/logout', self.do_logout, name='logout'),
        ])

    def __call__(self, environ, start_response):
        req = Request(environ)
        try:
            if not IPv4Address(req.remote_addr) in self.clients:
                raise exc.HTTPForbidden()
            handler, kwargs = self.router.match(req.path_info)
            if handler:
                # XXX Why does route_name only appear in kwargs sometimes?!
                if 'route_name' in kwargs:
                    del kwargs['route_name']
                resp = handler(req, **kwargs)
            else:
                self.not_found(req)
        except exc.HTTPException as e:
            # The exception itself is a WSGI response
            resp = e
        return resp(environ, start_response)

    def not_found(self, req):
        """
        Handler for unknown locations (404)
        """
        raise exc.HTTPNotFound('The resource at %s could not be found' %
                               req.path_info)

    def do_reset(self, req):
        """
        Reset all settings to their defaults
        """
        self.library.camera_reset()
        self.flashes.append('Camera settings reset to defaults')
        raise exc.HTTPFound(
            location=self.router.path_for('template', page='library'))

    def do_config(self, req):
        """
        Configure the library and camera settings
        """
        # Resolution is handled specially as the camera needs to stop the
        # preview in order to change it
        try:
            new_resolution = tuple(
                int(i) for i in req.params['resolution'].split('x', 1))
            if len(new_resolution) != 2:
                raise ValueError()
        except ValueError:
            self.flashes.append('Invalid resolution: %s' %
                                req.params['resolution'])
        if self.library.camera.resolution != new_resolution:
            try:
                self.library.camera.stop_preview()
                try:
                    self.library.camera.resolution = new_resolution
                finally:
                    self.library.camera.start_preview()
            except PiCameraError:
                self.flashes.append('Unable to change camera resolution '
                                    'to %s' % req.params['resolution'])
        # Everything else is handled generically...
        for setting in (
                'sharpness',
                'contrast',
                'brightness',
                'saturation',  #'ISO',
                'exposure-compensation'):
            try:
                setattr(self.library.camera, setting.replace('-', '_'),
                        int(req.params[setting]))
            except ValueError:
                self.flashes.append('Invalid %s: %s' %
                                    (setting, req.params[setting]))
        for setting in ('hflip', 'vflip'):
            try:
                setattr(self.library.camera, setting.replace('-', '_'),
                        bool(req.params.get(setting, 0)))
            except ValueError:
                self.flashes.append('Invalid %s: %s' %
                                    (setting, req.params[setting]))
        for setting in ('meter-mode', 'awb-mode', 'exposure-mode'):
            try:
                setattr(self.library.camera, setting.replace('-', '_'),
                        req.params[setting])
            except ValueError:
                self.flashes.append('Invalid %s: %s' %
                                    (setting, req.params[setting]))
        for setting in ('artist', 'email', 'copyright', 'description',
                        'filename-template', 'format'):
            try:
                setattr(self.library, setting.replace('-', '_'),
                        req.params[setting])
            except ValueError:
                self.flashes.append('Invalid %s: %s' %
                                    (setting, req.params[setting]))
        # If any settings failed, re-render the settings form
        if self.flashes:
            return self.do_template(req, 'settings')
        raise exc.HTTPFound(
            location=self.router.path_for('template', page='library'))

    def do_capture(self, req):
        """
        Take a new image with the camera and add it to the library
        """
        self.library.capture()
        raise exc.HTTPFound(
            location=self.router.path_for('template', page='library'))

    def do_download(self, req):
        """
        Send the library as a .zip archive
        """
        archive = self.library.archive()
        size = archive.seek(0, io.SEEK_END)
        archive.seek(0)
        resp = Response()
        resp.content_type = 'application/zip'
        resp.content_length = size
        resp.content_disposition = 'attachment; filename=images.zip'
        resp.app_iter = FileWrapper(archive)
        return resp

    def do_send(self, req):
        """
        Send the library as a set of attachments to an email
        """
        self.library.send()
        self.flashes.append('Email sent to %s' % library.email)
        raise exc.HTTPFound(
            location=self.router.path_for('template', page='library'))

    def do_delete(self, req, image):
        """
        Delete the selected images from library
        """
        self.library.remove(image)
        raise exc.HTTPFound(
            location=self.router.path_for('template', page='library'))

    def do_logout(self, req):
        """
        Clear the library of all images, reset all settings
        """
        self.library.clear()
        self.library.user_reset()
        self.library.camera_reset()
        raise exc.HTTPFound(
            location=self.router.path_for('template', page='settings'))

    def do_image(self, req, image):
        """
        Serve an image from the library
        """
        if not image in self.library:
            self.not_found(req)
        resp = Response()
        resp.content_type, resp.content_encoding = mimetypes.guess_type(
            image, strict=False)
        resp.content_length = self.library.stat_image(image).st_size
        resp.app_iter = FileWrapper(self.library.open_image(image))
        return resp

    def do_thumb(self, req, image):
        """
        Serve a thumbnail of an image from the library
        """
        if not image in self.library:
            self.not_found(req)
        resp = Response()
        resp.content_type = 'image/jpeg'
        resp.content_length = self.library.stat_thumbnail(image).st_size
        resp.app_iter = FileWrapper(self.library.open_thumbnail(image))
        return resp

    def do_static(self, req, path):
        """
        Serve static files from disk
        """
        path = os.path.normpath(os.path.join(self.static_dir, path))
        if not path.startswith(self.static_dir):
            self.not_found(req)
        resp = Response()
        resp.content_type, resp.content_encoding = mimetypes.guess_type(
            path, strict=False)
        if resp.content_type is None:
            resp.content_type = 'application/octet-stream'
        resp.content_length = os.stat(path).st_size
        resp.app_iter = FileWrapper(io.open(path, 'rb'))
        return resp

    def do_template(self, req, page, image=None):
        """
        Serve a Chameleon template-based page
        """
        resp = Response()
        resp.content_type = 'text/html'
        resp.content_encoding = 'utf-8'
        try:
            template = self.templates[page]
        except ValueError:
            self.not_found(req)
        resp.text = template(req=req,
                             page=page,
                             image=image,
                             helpers=self.helpers,
                             layout=self.layout,
                             flashes=self.flashes,
                             library=self.library,
                             camera=self.library.camera,
                             router=self.router)
        del self.flashes[:]
        return resp
class PololuRobotWebControlApp(object):
  def __init__(self, **kwargs):
    self.form = WebControlFormHelper(**kwargs)
    self.logger = kwargs.get('logger',)
    self.robot = kwargs.get('robot')
    #initialize speed in form with robot speed
    self.form.speed = self.robot.setDriveSpeed
    #create routes to web pages
    self.router = PathRouter()
    self.router.add_routes([
      url('/', self.do_main_page, name='home'),
      url('/doRobotControl', self.do_process_form, name='execute'),
      url('/showRobotControlForm', self.do_display_form, name='view')
      ])

  def __call__(self, environ, start_response):
    req = Request(environ)
    try:
      handler, kwargs = self.router.match(req.path_info)
      if handler:
        # XXX Why does route_name only appear in kwargs sometimes?!
        if 'route_name' in kwargs:
            del kwargs['route_name']
        resp = handler(req, **kwargs)
      else:
        self.not_found(req)
    except exc.HTTPException as e:
      # The exception itself is a WSGI response
      resp = e
    return resp(environ, start_response)

  def not_found(self, req):
    """Handler for unknown locations (404)"""
    raise exc.HTTPNotFound('The resource at %s could not be found' % req.path_info)


  #------------------------------------------------------------------------------#
  # do_main_page: load the mainpage. The main page contains an iFrame which      #
  #               triggers the consecutive loading of the control form           #
  #               The main page contains a link to mjpgStreamServer, which shows #
  #               a video stream from the attached raspicam. The url for this    #
  #               server is configured in etc/config.ini                         #
  #------------------------------------------------------------------------------#
  # version who when       description                                           #
  # 1.00    hta 15.05.2014 Initial version                                       #
  #------------------------------------------------------------------------------# 
  def do_main_page(self, req):
    res = Response()
    res.content_type = 'text/html'
    res.text         = self.form.mainPage % {'mjpgStreamServer':self.form.mjpgStreamServer}
    return res

  #------------------------------------------------------------------------------#
  # do_display_form: the control form, and set the color of the button text and  #
  #                  set the message to be shown to the user (if any)            #
  # parameters: message: Text message to be shown to user                        #
  #             speed  : Speed, value for the slider bar                         #
  #             toggleRovingButtonText: Roving OFF, Roving ON                   #
  #             backwardButtonColor, forwardButtonColor, leftButtonColor,        #
  #             rightButtonColor, stopButtonColor, toggleRovingButtonColor:     #
  #                      Color for the text on the control buttons. The purpose  #
  #                      is to highlight the currently active action suchs as    #
  #                      forward, left etc.                                      #
  #------------------------------------------------------------------------------#
  # version who when       description                                           #
  # 1.00    hta 15.05.2014 Initial version                                       #
  #------------------------------------------------------------------------------# 
  def do_display_form(self, req):
    res = Response()
    res.content_type = 'text/html'
    res.text         = self.form.controlForm % {'message':self.form.message, 
                                    'speed':  self.form.speed, 
                                    'backwardButtonColor':     self.form.backwardButtonColor, 
                                    'forwardButtonColor':      self.form.forwardButtonColor, 
                                    'leftButtonColor':         self.form.leftButtonColor, 
                                    'rightButtonColor':        self.form.rightButtonColor, 
                                    'stopButtonColor':         self.form.stopButtonColor,
                                    'toggleRovingButtonColor': self.form.toggleRovingButtonColor,
                                    'toggleRovingButtonText':  self.form.toggleRovingButtonText}   
    return res
    
  #------------------------------------------------------------------------------#
  # process_form: Processes the user input from the control form, executes the   #
  #               desired action (e.g. forward, backward) and give feedback to   #
  #               the user indicating what action has been taken                 #
  #                  is highlighted                                              #
  # parameters: params: dictionary object containing parameters and their values #
  #                     from the form.                                           #
  #                     action: possbile values: forward, backward, left, right, #
  #                                              stop, setSpeed                  #
  #                     speed:  possible values: 0-127
  #------------------------------------------------------------------------------#
  # version who when       description                                           #
  # 1.00    hta 15.05.2014 Initial version                                       #
  #------------------------------------------------------------------------------# 
  def do_process_form(self, req):
    
    action           = req.params['action'] 
    speedSliderValue = req.params['speed']
    self.logger.debug('action['+action+'] speedSliderValue['+speedSliderValue+']')
    if action == 'forward':
      self.form.message='Going '+action
      self.form.setButtonColors(backward=False, forward=True, left=False, right=False, stop=False, roving=False)
      self.robot.stopRoving()
      self.robot.driveForwards()
    elif action == 'backward':
      self.form.message='Going '+action
      self.form.setButtonColors(backward=True, forward=False, left=False, right=False, stop=False, roving=False)
      self.robot.stopRoving()
      self.robot.driveBackwards()
    elif action == 'left':
      self.form.message='Turning '+action    
      self.form.setButtonColors(backward=False, forward=False, left=True, right=False, stop=False, roving=False)
      self.robot.stopRoving()
      self.robot.turnLeft()
    elif action == 'right':
      self.form.message='Turning '+action   
      self.form.setButtonColors(backward=False, forward=False, left=False, right=True, stop=False, roving=False)
      self.robot.stopRoving()
      self.robot.turnRight()
    elif action == 'setSpeed':
      self.form.message='Setting speed to '+speedSliderValue
      self.form.speed = int(speedSliderValue)
      self.robot.setSpeed(self.form.speed)
    elif action == 'stop':
      self.form.message='Stopping'  
      self.form.setButtonColors(backward=False, forward=False, left=False, right=False, stop=True, roving=False)
      self.robot.stop()
      if self.robot.isRoving:
        self.robot.stopRoving()
    elif action == 'roving':
      #Toggle roving, of roving on then turn it of and vice versa
      if self.robot.isRoving:
        self.form.message='End roving'  
        self.form.setButtonColors(backward=False, forward=False, left=False, right=False, stop=False, roving=False)
        self.robot.stopRoving()
      else:
        self.form.message='Start roving'  
        self.form.setButtonColors(backward=False, forward=False, left=False, right=False, stop=False, roving=True)      
        self.robot.runRoving()
    #return updated control form to web client  
    return self.do_display_form (req)
Пример #4
0
class PicroscopyWsgiApp(object):
    def __init__(self, **kwargs):
        super().__init__()
        self.library = PicroscopyLibrary(**kwargs)
        self.helpers = WebHelpers(self.library)
        self.clients = kwargs.get('clients', IPv4Network('0.0.0.0/0'))
        logging.info('Clients must be on network %s', self.clients)
        self.static_dir = os.path.abspath(os.path.normpath(kwargs.get(
            'static_dir', os.path.join(HERE, 'static')
            )))
        logging.info('Static files: %s', self.static_dir)
        self.templates_dir = os.path.abspath(os.path.normpath(kwargs.get(
            'templates_dir', os.path.join(HERE, 'templates')
            )))
        logging.info('Chameleon templates: %s', self.templates_dir)
        self.templates = PageTemplateLoader(
            self.templates_dir, default_extension='.pt')
        self.layout = self.templates['layout']
        # No need to make flashes a per-session thing - it's a single user app!
        self.flashes = []
        self.router = PathRouter()
        # XXX Add handler for exiting system
        # XXX Make exit code conditional? (upgrade/reboot/shutdown/etc.)
        self.router.add_routes([
            url('/',                   self.do_template, kwargs={'page': 'library'}, name='home'),
            url('/{page}.html',        self.do_template, name='template'),
            url('/view/{image}.html',  self.do_template, kwargs={'page': 'image'}, name='view'),
            url('/static/{path:any}',  self.do_static,   name='static'),
            url('/images/{image}',     self.do_image,    name='image'),
            url('/thumbs/{image}',     self.do_thumb,    name='thumb'),
            url('/delete/{image}',     self.do_delete,   name='delete'),
            url('/config',             self.do_config,   name='config'),
            url('/reset',              self.do_reset,    name='reset'),
            url('/capture',            self.do_capture,  name='capture'),
            url('/download',           self.do_download, name='download'),
            url('/send',               self.do_send,     name='send'),
            url('/logout',             self.do_logout,   name='logout'),
            ])

    def __call__(self, environ, start_response):
        req = Request(environ)
        try:
            if not IPv4Address(req.remote_addr) in self.clients:
                raise exc.HTTPForbidden()
            handler, kwargs = self.router.match(req.path_info)
            if handler:
                # XXX Why does route_name only appear in kwargs sometimes?!
                if 'route_name' in kwargs:
                    del kwargs['route_name']
                resp = handler(req, **kwargs)
            else:
                self.not_found(req)
        except exc.HTTPException as e:
            # The exception itself is a WSGI response
            resp = e
        return resp(environ, start_response)

    def not_found(self, req):
        """
        Handler for unknown locations (404)
        """
        raise exc.HTTPNotFound(
            'The resource at %s could not be found' % req.path_info)

    def do_reset(self, req):
        """
        Reset all settings to their defaults
        """
        self.library.camera_reset()
        self.flashes.append('Camera settings reset to defaults')
        raise exc.HTTPFound(
            location=self.router.path_for('template', page='library'))

    def do_config(self, req):
        """
        Configure the library and camera settings
        """
        # Resolution is handled specially as the camera needs to stop the
        # preview in order to change it
        try:
            new_resolution = tuple(
                int(i) for i in req.params['resolution'].split('x', 1))
            if len(new_resolution) != 2:
                raise ValueError()
        except ValueError:
            self.flashes.append(
                'Invalid resolution: %s' % req.params['resolution'])
        if self.library.camera.resolution != new_resolution:
            try:
                self.library.camera.stop_preview()
                try:
                    self.library.camera.resolution = new_resolution
                finally:
                    self.library.camera.start_preview()
            except PiCameraError:
                self.flashes.append(
                    'Unable to change camera resolution '
                    'to %s' % req.params['resolution'])
        # Everything else is handled generically...
        for setting in (
                'sharpness', 'contrast', 'brightness', 'saturation', #'ISO',
                'exposure-compensation'):
            try:
                setattr(
                    self.library.camera, setting.replace('-', '_'),
                    int(req.params[setting])
                    )
            except ValueError:
                self.flashes.append(
                    'Invalid %s: %s' % (setting, req.params[setting]))
        for setting in ('hflip', 'vflip'):
            try:
                setattr(
                    self.library.camera, setting.replace('-', '_'),
                    bool(req.params.get(setting, 0))
                    )
            except ValueError:
                self.flashes.append(
                    'Invalid %s: %s' % (setting, req.params[setting]))
        for setting in ('meter-mode', 'awb-mode', 'exposure-mode'):
            try:
                setattr(
                    self.library.camera, setting.replace('-', '_'),
                    req.params[setting]
                    )
            except ValueError:
                self.flashes.append(
                    'Invalid %s: %s' % (setting, req.params[setting]))
        for setting in (
                'artist', 'email', 'copyright', 'description',
                'filename-template', 'format'):
            try:
                setattr(
                    self.library, setting.replace('-', '_'),
                    req.params[setting]
                    )
            except ValueError:
                self.flashes.append(
                    'Invalid %s: %s' % (setting, req.params[setting]))
        # If any settings failed, re-render the settings form
        if self.flashes:
            return self.do_template(req, 'settings')
        raise exc.HTTPFound(
            location=self.router.path_for('template', page='library'))

    def do_capture(self, req):
        """
        Take a new image with the camera and add it to the library
        """
        self.library.capture()
        raise exc.HTTPFound(
            location=self.router.path_for('template', page='library'))

    def do_download(self, req):
        """
        Send the library as a .zip archive
        """
        archive = self.library.archive()
        size = archive.seek(0, io.SEEK_END)
        archive.seek(0)
        resp = Response()
        resp.content_type = 'application/zip'
        resp.content_length = size
        resp.content_disposition = 'attachment; filename=images.zip'
        resp.app_iter = FileWrapper(archive)
        return resp

    def do_send(self, req):
        """
        Send the library as a set of attachments to an email
        """
        self.library.send()
        self.flashes.append('Email sent to %s' % library.email)
        raise exc.HTTPFound(
            location=self.router.path_for('template', page='library'))

    def do_delete(self, req, image):
        """
        Delete the selected images from library
        """
        self.library.remove(image)
        raise exc.HTTPFound(
            location=self.router.path_for('template', page='library'))

    def do_logout(self, req):
        """
        Clear the library of all images, reset all settings
        """
        self.library.clear()
        self.library.user_reset()
        self.library.camera_reset()
        raise exc.HTTPFound(
            location=self.router.path_for('template', page='settings'))

    def do_image(self, req, image):
        """
        Serve an image from the library
        """
        if not image in self.library:
            self.not_found(req)
        resp = Response()
        resp.content_type, resp.content_encoding = mimetypes.guess_type(
                image, strict=False)
        resp.content_length = self.library.stat_image(image).st_size
        resp.app_iter = FileWrapper(self.library.open_image(image))
        return resp

    def do_thumb(self, req, image):
        """
        Serve a thumbnail of an image from the library
        """
        if not image in self.library:
            self.not_found(req)
        resp = Response()
        resp.content_type = 'image/jpeg'
        resp.content_length = self.library.stat_thumbnail(image).st_size
        resp.app_iter = FileWrapper(self.library.open_thumbnail(image))
        return resp

    def do_static(self, req, path):
        """
        Serve static files from disk
        """
        path = os.path.normpath(os.path.join(self.static_dir, path))
        if not path.startswith(self.static_dir):
            self.not_found(req)
        resp = Response()
        resp.content_type, resp.content_encoding = mimetypes.guess_type(
                path, strict=False)
        if resp.content_type is None:
            resp.content_type = 'application/octet-stream'
        resp.content_length = os.stat(path).st_size
        resp.app_iter = FileWrapper(io.open(path, 'rb'))
        return resp

    def do_template(self, req, page, image=None):
        """
        Serve a Chameleon template-based page
        """
        resp = Response()
        resp.content_type = 'text/html'
        resp.content_encoding = 'utf-8'
        try:
            template = self.templates[page]
        except ValueError:
            self.not_found(req)
        resp.text = template(
            req=req,
            page=page,
            image=image,
            helpers=self.helpers,
            layout=self.layout,
            flashes=self.flashes,
            library=self.library,
            camera=self.library.camera,
            router=self.router)
        del self.flashes[:]
        return resp
Пример #5
0
class MancifyWsgiApp(object):
    def __init__(self, **kwargs):
        super(MancifyWsgiApp, self).__init__()
        self.sms = MancifySMSService(kwargs['clockwork_api_key'])
        self.exec_timeout = kwargs.get('exec_timeout', 10)
        self.connect_timeout = kwargs.get('connect_timeout', 30)
        self.session_timeout = kwargs.get('session_timeout', 300)
        self.output_limit = kwargs.get('output_limit', 1024)
        self.router = PathRouter()
        self.router.add_routes([
            url('/',          self.do_index),
            url('/ssh',       self.do_ssh),
            url('/translate', self.do_translate),
            ])
        self.lock = threading.Lock()
        self.sessions = {}
        self.messages = set()
        self.terminate = threading.Event()
        self.reap_thread = threading.Thread(target=self.reap_sessions)
        self.reap_thread.daemon = True
        self.reap_thread.start()

    def close(self):
        self.terminate.set()
        self.reap_thread.join(5)

    def reap_sessions(self):
        while True:
            reap_list = []
            now = time.time()
            with self.lock:
                for recipient, session in self.sessions.iteritems():
                    if not session.timestamp:
                        reap_list.append((recipient, session))
                    if (now - session.timestamp) > self.session_timeout:
                        reap_list.append((recipient, session))
                for recipient, session in reap_list:
                    try:
                        session.close(quiet=True)
                    finally:
                        del self.sessions[recipient]
                        session = None
            if self.terminate.wait(10):
                break

    def __call__(self, environ, start_response):
        req = Request(environ)
        try:
            handler, kwargs = self.router.match(req.path_info)
            if handler:
                # XXX Workaround wheezy bug
                if 'route_name' in kwargs:
                    del kwargs['route_name']
                resp = handler(req, **kwargs)
            else:
                self.not_found(req)
        except exc.HTTPException as e:
            # The exception is the response
            resp = e
        return resp(environ, start_response)

    def not_found(self, req):
        raise exc.HTTPNotFound(
            "The resource at %s could not be found" % req.path_info)

    def do_index(self, req):
        resp = Response()
        resp.content_type = b'text/html'
        resp.content_encoding = b'utf-8'
        resp.text = """\
<html>
<head><title>Mancify</title></head>
<body>
<h1>Mancify</h1>
<p>Probably the silliest webapp in the world...</p>
</body>
</html>
"""
        return resp

    def do_translate(self, req):
        # Check the request has the required parameters
        if not 'msg_id' in req.params:
            raise exc.HTTPBadRequest('Missing msg_id parameter')
        if not 'from' in req.params:
            raise exc.HTTPBadRequest('Missing from parameter')
        if not 'content' in req.params:
            raise exc.HTTPBadRequest('Missing content parameter')
        msg_id = req.params['msg_id']
        recipient = req.params['from']
        sender = req.params['to']
        content = req.params['content']
        # If we've seen the message before it's a duplicate. Return 200 OK so
        # the server doesn't keep retrying but otherwise ignore it
        if msg_id in self.messages:
            raise exc.HTTPOk('Message already processed')
        self.messages.add(msg_id)
        self.sms.send(sender, recipient, translator.translate(content, manc))
        raise exc.HTTPOk('Message processed')

    def do_ssh(self, req):
        # Check the request has the required parameters
        if not 'msg_id' in req.params:
            raise exc.HTTPBadRequest('Missing msg_id parameter')
        if not 'from' in req.params:
            raise exc.HTTPBadRequest('Missing from parameter')
        if not 'content' in req.params:
            raise exc.HTTPBadRequest('Missing content parameter')
        msg_id = req.params['msg_id']
        recipient = req.params['from']
        sender = req.params['to']
        content = req.params['content']
        # If we've seen the message before it's a duplicate. Return 200 OK so
        # the server doesn't keep retrying but otherwise ignore it
        if msg_id in self.messages:
            raise exc.HTTPOk('Message already processed')
        self.messages.add(msg_id)
        try:
            with self.lock:
                try:
                    session = self.sessions[recipient]
                except KeyError:
                    session = MancifySSHSession(
                        self.sms, sender, recipient,
                        self.connect_timeout, self.exec_timeout)
                    self.sessions[recipient] = session
                session.timestamp = time.time()
            session.execute(content)
        except Exception as e:
            msg = str(e)
            if len(msg) > 140:
                msg = msg[:137] + '...'
            self.sms.send(sender, recipient, msg)
        raise exc.HTTPOk('Message processed')