Пример #1
0
    def _api_out_as(self, out):
        """ Formats the response to the desired output """

        if self._api_cmd == 'docs_md':
            return out['response']['data']

        elif self._api_cmd and self._api_cmd.startswith('download_'):
            return

        elif self._api_cmd == 'pms_image_proxy':
            if 'return_hash' not in self._api_kwargs:
                cherrypy.response.headers['Content-Type'] = 'image/jpeg'
                return out['response']['data']

        if self._api_out_type == 'json':
            cherrypy.response.headers['Content-Type'] = 'application/json;charset=UTF-8'
            try:
                if self._api_debug:
                    out = json.dumps(out, indent=4, sort_keys=True, ensure_ascii=False).encode('utf-8')
                else:
                    out = json.dumps(out, ensure_ascii=False).encode('utf-8')
                if self._api_callback is not None:
                    cherrypy.response.headers['Content-Type'] = 'application/javascript'
                    # wrap with JSONP call if requested
                    out = self._api_callback + '(' + out + ');'
            # if we fail to generate the output fake an error
            except Exception as e:
                logger.api_exception(u'Tautulli APIv2 :: ' + traceback.format_exc())
                cherrypy.response.status = 500
                out['message'] = traceback.format_exc()
                out['result'] = 'error'

        elif self._api_out_type == 'xml':
            cherrypy.response.headers['Content-Type'] = 'application/xml'
            try:
                out = xmltodict.unparse(out, pretty=True)
            except Exception as e:
                logger.api_error(u'Tautulli APIv2 :: Failed to parse xml result')
                cherrypy.response.status = 500
                try:
                    out['message'] = e
                    out['result'] = 'error'
                    out = xmltodict.unparse(out, pretty=True)

                except Exception as e:
                    logger.api_error(u'Tautulli APIv2 :: Failed to parse xml result error message %s' % e)
                    out = '''<?xml version="1.0" encoding="utf-8"?>
                                <response>
                                    <message>%s</message>
                                    <data></data>
                                    <result>error</result>
                                </response>
                          ''' % e

        return out
Пример #2
0
    def _api_run(self, *args, **kwargs):
        """ handles the stuff from the handler """

        # Make sure the device ID is not shown in the logs
        if self._api_cmd == 'register_device':
            if kwargs.get('device_id'):
                logger._BLACKLIST_WORDS.add(kwargs['device_id'])
            if kwargs.get('onesignal_id'):
                logger._BLACKLIST_WORDS.add(kwargs['onesignal_id'])

        result = {}
        logger.api_debug('Tautulli APIv2 :: API called with kwargs: %s' %
                         kwargs)

        self._api_validate(**kwargs)

        if self._api_cmd and self._api_authenticated:
            call = getattr(self, self._api_cmd)

            # Profile is written to console.
            if self._api_profileme:
                from profilehooks import profile
                call = profile(call, immediate=True)

            # We allow this to fail so we get a
            # traceback in the browser
            try:

                result = call(**self._api_kwargs)
            except Exception as e:
                logger.api_error(
                    'Tautulli APIv2 :: Failed to run %s with %s: %s' %
                    (self._api_cmd, self._api_kwargs, e))
                self._api_response_code = 500
                if self._api_debug:
                    cherrypy.request.show_tracebacks = True
                    # Reraise the exception so the traceback hits the browser
                    raise
                self._api_msg = 'Check the logs for errors'

        ret = None
        # The api decorated function can return different result types.
        # convert it to a list/dict before we change it to the users
        # wanted output
        try:
            if isinstance(result, (dict, list)):
                ret = result
            else:
                raise Exception
        except Exception:
            try:
                ret = json.loads(result)
            except (ValueError, TypeError):
                try:
                    ret = xmltodict.parse(result, attr_prefix='')
                except:
                    pass

        # Fallback if we cant "parse the response"
        if ret is None:
            ret = result

        if (ret is not None or self._api_result_type
                == 'success') and self._api_authenticated:
            # To allow override for restart etc
            # if the call returns some data we are gonna assume its a success
            self._api_result_type = 'success'
            self._api_response_code = 200

        # Since some of them methods use a api like response for the ui
        # {result: error, message: 'Some shit happened'}
        if isinstance(ret, dict):
            if ret.get('message'):
                self._api_msg = ret.pop('message', None)

            if ret.get('result'):
                self._api_result_type = ret.pop('result', None)

        if self._api_result_type == 'success' and not self._api_response_code:
            self._api_response_code = 200
        elif self._api_result_type == 'error' and not self._api_response_code:
            self._api_response_code = 400

        if not self._api_response_code:
            self._api_response_code = 500

        cherrypy.response.status = self._api_response_code
        return self._api_out_as(
            self._api_responds(result_type=self._api_result_type,
                               msg=self._api_msg,
                               data=ret))