Esempio n. 1
0
    def handle(self):

        key = self.request.input[self.new_key_elem]
        value = self.request.input.value or ''

        key = int(key) if self.request.input.get(
            'key_data_type') == CACHE.BUILTIN_KV_DATA_TYPE.INT.id else key
        value = int(value) if self.request.input.get(
            'value_data_type') == CACHE.BUILTIN_KV_DATA_TYPE.INT.id else value

        expiry = self.request.input.get('expiry', None) or 0

        # Double check expiry is actually an integer
        try:
            int(expiry)
        except ValueError:
            raise BadRequest(
                self.cid, 'Expiry {} must be an integer instead of {}'.format(
                    repr(expiry)), type(expiry))

        cache = self._get_cache_by_input()

        # Note that the try/except/else/set operation below is not atomic

        existing_value = cache.get(key)
        if existing_value:
            if not self.request.input.get('replace_existing'):
                raise BadRequest(
                    self.cid,
                    'Key `{}` already exists with a value of `{}`'.format(
                        key, existing_value))

        # If we get here it means the key doesn't exist or it's fine to overwrite it.
        cache.set(key, value, expiry)
Esempio n. 2
0
    def handle(self, _internal=('zato', 'pub.zato')):

        # Service name is given in URL path
        service_name = self.request.http.params.service_name

        # Are we invoking a Zato built-in service or a user-defined one?
        is_internal = service_name.startswith(_internal)  # type: bool

        # Before invoking a service that is potentially internal we need to confirm
        # that our channel can be used for such invocations.
        if is_internal:
            if self.channel.name not in self.server.fs_server_config.misc.service_invoker_allow_internal:
                self.logger.warn(
                    'Service `%s` could not be invoked; channel `%s` not among `%s` (service_invoker_allow_internal)',
                    service_name, self.channel.name, self.server.
                    fs_server_config.misc.service_invoker_allow_internal)
                self.response.data_format = 'text/plain'
                raise BadRequest(self.cid,
                                 'No such service `{}`'.format(service_name))

        # Make sure the service exists
        if self.server.service_store.has_service(service_name):

            # Depending on HTTP verb used, we may need to look up input in different places
            if self.request.http.method == 'GET':
                payload = self.request.http.GET
            else:
                payload = self.request.raw_request
                payload = loads(payload) if payload else None

            # Invoke the service now
            response = self.invoke(
                service_name,
                payload,
                wsgi_environ={'HTTP_METHOD': self.request.http.method})

            # All internal services wrap their responses in top-level elements that we need to shed here ..
            if is_internal and response:
                top_level = list(iterkeys(response))[0]
                response = response[top_level]

            # Assign response to outgoing payload
            self.response.payload = dumps(response)
            self.response.data_format = 'application/json'

        # No such service as given on input
        else:
            self.response.data_format = 'text/plain'
            raise BadRequest(self.cid,
                             'No such service `{}`'.format(service_name))
Esempio n. 3
0
    def handle_POST(self):
        """ POST /zato/pubsub/subscribe/topic/{topic_name}
        """
        # Checks credentials and returns endpoint_id if valid
        endpoint_id = self._pubsub_check_credentials()

        # Make sure this endpoint has correct subscribe permissions (patterns)
        self._check_sub_access(endpoint_id)

        try:
            response = self.invoke(
                'zato.pubsub.subscription.subscribe-rest', {
                    'topic_name':
                    self.request.input.topic_name,
                    'endpoint_id':
                    endpoint_id,
                    'delivery_batch_size':
                    PUBSUB.DEFAULT.DELIVERY_BATCH_SIZE,
                    'delivery_method':
                    self.request.input.delivery_method
                    or PUBSUB.DELIVERY_METHOD.PULL.id,
                    'server_id':
                    self.server.id,
                })['response']
        except PubSubSubscriptionExists:
            self.logger.warn(format_exc())
            raise BadRequest(
                self.cid, 'Subscription to topic `{}` already exists'.format(
                    self.request.input.topic_name))
        else:
            self.response.payload.sub_key = response['sub_key']
            self.response.payload.queue_depth = response['queue_depth']
Esempio n. 4
0
    def _publish(self, endpoint_id):
        """ POST /zato/pubsub/topic/{topic_name} {"data":"my data", ...}
        """
        # We always require some data on input
        if not self.request.input.data:
            raise BadRequest(self.cid, 'No data sent on input')

        # Ignore the header set by curl and similar tools
        mime_type = self.wsgi_environ.get('CONTENT_TYPE')
        mime_type = mime_type if mime_type != 'application/x-www-form-urlencoded' else CONTENT_TYPE.JSON

        input = self.request.input

        ctx = {
            'mime_type': mime_type,
            'data': input.data,
            'priority': input.priority,
            'expiration': input.expiration,
            'correl_id': input.correl_id,
            'in_reply_to': input.in_reply_to,
            'ext_client_id': input.ext_client_id,
            'has_gd': input.has_gd or False,
            'endpoint_id': endpoint_id,
        }

        return self.pubsub.publish(input.topic_name, **ctx)
Esempio n. 5
0
    def handle_POST(self):

        # Check credentials first
        security_id = self._pubsub_check_credentials()

        # Regardless of mime-type, we always accept it in JSON payload
        try:
            data_parsed = loads(self.request.raw_request)
        except ValueError:
            raise BadRequest(self.cid, 'JSON input could not be parsed')
        else:
            data = self.request.raw_request

        # Ignore the header set by curl and similar tools
        mime_type = self.wsgi_environ.get('CONTENT_TYPE')
        mime_type = mime_type if mime_type != 'application/x-www-form-urlencoded' else CONTENT_TYPE.JSON

        input = self.request.input

        self.response.payload.msg_id = self.invoke(
            'zato.pubsub.publish.publish', {
                'topic_name': input.topic_name,
                'mime_type': mime_type,
                'security_id': security_id,
                'data': data,
                'data_parsed': data_parsed,
                'priority': input.priority,
                'expiration': input.expiration,
                'correl_id': input.correl_id,
                'in_reply_to': input.in_reply_to,
                'ext_client_id': input.ext_client_id,
                'has_gd': input.gd,
            })['response']['msg_id']
Esempio n. 6
0
    def handle(self, _queue_type=COMMON_PUBSUB.QUEUE_TYPE):

        # Make sure the (optional) queue type is one of allowed values
        queue_type = self.request.input.queue_type

        if queue_type:
            if queue_type not in _queue_type:
                raise BadRequest(self.cid,
                                 'Invalid queue_type:`{}`'.format(queue_type))
            else:
                if queue_type == _queue_type.CURRENT:
                    is_in_staging = False
                elif queue_type == _queue_type.STAGING:
                    is_in_staging = True
        else:
            is_in_staging = None

        # Remove all references to the queue given on input
        with closing(self.odb.session()) as session:
            q = session.query(PubSubEndpointEnqueuedMessage).\
                filter(PubSubEndpointEnqueuedMessage.cluster_id==self.request.input.cluster_id).\
                filter(PubSubEndpointEnqueuedMessage.subscription_id==self.request.input.id)

            if is_in_staging is not None:
                q = q.filter(
                    PubSubEndpointEnqueuedMessage.is_in_staging.is_(
                        is_in_staging))
            q.delete()

            session.commit()
Esempio n. 7
0
 def handle(self):
     try:
         server = self.pubsub.get_sub_key_server(self.request.input.sub_key)
     except KeyError, e:
         raise BadRequest(
             self.cid, 'No such sub_key found `{}`'.format(
                 self.request.input.sub_key))
Esempio n. 8
0
    def _get_pattern_matched(self, topic_name, ws_channel_id, sql_ws_client_id,
                             security_id, endpoint_id):
        pubsub = self.server.worker_store.pubsub

        if ws_channel_id and (not sql_ws_client_id):
            raise BadRequest(
                self.cid,
                'sql_ws_client_id must not be empty if ws_channel_id is given on input'
            )

        # Confirm if this client may subscribe at all to the topic it chose
        if endpoint_id:
            pattern_matched = pubsub.is_allowed_sub_topic_by_endpoint_id(
                topic_name, endpoint_id)
        else:
            kwargs = {
                'security_id': security_id
            } if security_id else {
                'ws_channel_id': ws_channel_id
            }
            pattern_matched = pubsub.is_allowed_sub_topic(topic_name, **kwargs)

        # Not allowed - raise an exception then
        if not pattern_matched:
            raise Forbidden(self.cid)

        # Alright, we can proceed
        else:
            return pattern_matched
Esempio n. 9
0
 def handle(self):
     try:
         server = self.pubsub.get_sub_key_server(self.request.input.sub_key)
     except KeyError:
         raise BadRequest(self.cid, 'No such sub_key found `{}`'.format(self.request.input.sub_key))
     else:
         self.response.payload.server_pid = server.server_pid
Esempio n. 10
0
    def handle(self, _internal=('zato', 'pub.zato')):

        # Service name is given in URL path
        service_name = self.request.http.params.service_name

        # Make sure the service exists
        if self.server.service_store.has_service(service_name):

            # Depending on HTTP verb used, we may need to look up input in different places
            if self.request.http.method == 'GET':
                payload = self.request.http.GET
            else:
                payload = self.request.raw_request
                payload = loads(payload) if payload else None

            # Invoke the service now
            response = self.invoke(service_name, payload, wsgi_environ={'HTTP_METHOD':self.request.http.method})

            # All internal services wrap their responses in top-level elements that we need to shed here.
            if service_name.startswith(_internal):
                if response:
                    top_level = response.keys()[0]
                    response = response[top_level]

            # Assign response to outgoing payload
            self.response.payload = dumps(response)
            self.response.data_format = 'application/json'

        # No such service as given on input
        else:
            self.response.data_format = 'text/plain'
            raise BadRequest(self.cid, 'No such service `{}`'.format(service_name))
Esempio n. 11
0
def get_expiration(cid, input, default_expiration=2147483647):
    """ Get and validate message expiration. Returns 2 ** 31 - 1 (around 68 years) if not expiration is set explicitly.
    """
    expiration = input.get('expiration')
    if expiration is not None and expiration < 0:
        raise BadRequest(cid, 'Expiration `{}` must not be negative'.format(expiration))

    return expiration or default_expiration
Esempio n. 12
0
def get_expiration(cid, input, default_expiration=_default_expiration):
    """ Get and validate message expiration.
    Returns (2 ** 31 - 1) * 1000 milliseconds (around 68 years) if expiration is not set explicitly.
    """
    expiration = input.get('expiration')
    if expiration is not None and expiration < 0:
        raise BadRequest(cid, 'Expiration `{}` must not be negative'.format(expiration))

    return expiration or default_expiration
Esempio n. 13
0
    def handle(self):

        # This is a multi-line string of topic names
        topic_list_text = [
            elem.strip()
            for elem in (self.request.raw_request.pop('topic_list_text', '')
                         or '').splitlines()
        ]

        # This is a JSON list of topic names
        topic_list_json = self.request.raw_request.pop('topic_list_json', [])

        # This is a single topic
        topic_name = self.request.raw_request.pop('topic_name', '').strip()

        if topic_name:
            topic_name = [topic_name]

        if not (topic_list_text or topic_list_json or topic_name):
            raise BadRequest(self.cid,
                             'No topics to subscribe to were given on input')
        else:
            if topic_list_text:
                topic_list = topic_list_text
            elif topic_list_json:
                topic_list = topic_list_json
            else:
                topic_list = topic_name

            # For all topics given on input, check it upfront if caller may subscribe to all of them
            check_input = [
                int(self.request.raw_request.get('ws_channel_id') or 0),
                int(self.request.raw_request.get('sql_ws_client_id') or 0),
                int(self.request.raw_request.get('security_id') or 0),
                int(self.request.raw_request.get('endpoint_id') or 0),
            ]
            for topic_name in topic_list:
                try:
                    # Assignment to sub_pattern_matched will need to be changed once
                    # we support subscriptions to multiple topics at a time,
                    # but for the time being, this is fine.
                    self.request.raw_request[
                        'sub_pattern_matched'] = self._is_subscription_allowed(
                            topic_name, *check_input)
                except Forbidden:
                    self.logger.warn('Could not subscribe to `%r` using `%r`',
                                     topic_name, check_input)
                    raise

            sub_service = 'zato.pubsub.subscription.subscribe-{}'.format(
                self.request.raw_request['endpoint_type'])
            sub_request = self.request.raw_request

            # Invoke subscription for each topic given on input. At this point we know we can subscribe to all of them.
            for topic_name in topic_list:
                sub_request['topic_name'] = topic_name
                self.response.payload = self.invoke(sub_service, sub_request)
Esempio n. 14
0
    def handle(self):

        sub_key = self.request.input.sub_key
        sub_key_list = self.request.input.sub_key_list

        if not (sub_key or sub_key_list):
            raise BadRequest(
                self.cid, 'Exactly one of sub_key or sub_key_list is required')

        if sub_key and sub_key_list:
            raise BadRequest(
                self.cid,
                'Cannot provide both sub_key and sub_key_list on input')

        if sub_key:
            sub_key_list = [
                sub_key
            ]  # Otherwise, we already had sub_key_list on input so 'else' is not needed

        cluster_id = self.request.input.cluster_id
        topic_sub_keys = {}

        with closing(self.odb.session()) as session:

            # First we need a list of topics to which sub_keys were related - required by broker messages.
            for item in pubsub_endpoint_queue_list_by_sub_keys(
                    session, cluster_id, sub_key_list):
                sub_keys = topic_sub_keys.setdefault(item.topic_name, [])
                sub_keys.append(item.sub_key)

            # Remove the subscription object which in turn cascades and removes all dependant objects
            session.query(PubSubSubscription).\
                filter(PubSubSubscription.cluster_id==self.request.input.cluster_id).\
                filter(PubSubSubscription.sub_key.in_(sub_key_list)).\
                delete(synchronize_session=False)
            session.expire_all()

            session.commit()

        # Notify workers that this subscription needs to be deleted
        self.broker_client.publish({
            'topic_sub_keys': topic_sub_keys,
            'action': PUBSUB.SUBSCRIPTION_DELETE.value,
        })
Esempio n. 15
0
    def handle(self):

        sub_key = self.request.input.sub_key
        sub_key_list = self.request.input.sub_key_list

        if not (sub_key or sub_key_list):
            raise BadRequest(
                self.cid, 'Exactly one of sub_key or sub_key_list is required')

        if sub_key and sub_key_list:
            raise BadRequest(
                self.cid,
                'Cannot provide both sub_key and sub_key_list on input')

        if sub_key:
            sub_key_list = [
                sub_key
            ]  # Otherwise, we already had sub_key_list on input so 'else' is not needed

        cluster_id = self.request.input.cluster_id

        with closing(self.odb.session()) as session:

            # First we need a list of topics to which sub_keys were related - required by broker messages.
            topic_sub_keys = get_topic_sub_keys_from_sub_keys(
                session, cluster_id, sub_key_list)

            # Remove the subscription object which in turn cascades and removes all dependant objects
            session.query(PubSubSubscription).\
                filter(PubSubSubscription.cluster_id==self.request.input.cluster_id).\
                filter(PubSubSubscription.sub_key.in_(sub_key_list)).\
                delete(synchronize_session=False)

            self.logger.info('Deleting subscriptions `%s`', topic_sub_keys)

            session.expire_all()
            session.commit()

        # Notify workers about deleted subscription(s)
        self.broker_client.publish({
            'topic_sub_keys': topic_sub_keys,
            'action': PUBSUB.SUBSCRIPTION_DELETE.value,
        })
Esempio n. 16
0
def insert_topic_messages(session, cid, msg_list):
    """ Publishes messages to a topic, i.e. runs an INSERT that inserts rows, one for each message.
    """
    try:
        session.execute(MsgInsert().values(msg_list))
    except IntegrityError, e:
        if 'pubsb_msg_pubmsg_id_idx' in e.message:
            raise BadRequest(cid, 'Duplicate msg_id:`{}`'.format(e.message))
        else:
            raise
Esempio n. 17
0
def get_priority(cid, input, _pri_min=_PRIORITY.MIN, _pri_max=_PRIORITY.MAX, _pri_def=_PRIORITY.DEFAULT):
    """ Get and validate message priority.
    """
    priority = input.get('priority')
    if priority:
        if priority < _pri_min or priority > _pri_max:
            raise BadRequest(cid, 'Priority `{}` outside of allowed range {}-{}'.format(priority, _pri_min, _pri_max))
    else:
        priority = _pri_def

    return priority
Esempio n. 18
0
    def handle(self):

        # REST and SOAP outconn IDs have different input names but they both map
        # to the same SQL-level attribute. This means that at most one of them may be
        # provided on input. It's an error to provide both.
        out_rest_http_soap_id = self.request.input.get('out_rest_http_soap_id')
        out_soap_http_soap_id = self.request.input.get('out_soap_http_soap_id')

        if out_rest_http_soap_id and out_soap_http_soap_id:
            raise BadRequest(self.cid, 'Cannot provide both out_rest_http_soap_id and out_soap_http_soap_id on input')

        # We know we don't have both out_rest_http_soap_id and out_soap_http_soap_id on input
        # but we still need to find out if we have any at all.
        if out_rest_http_soap_id:
            out_http_soap_id = out_rest_http_soap_id
        elif out_soap_http_soap_id:
            out_http_soap_id = out_soap_http_soap_id
        else:
            out_http_soap_id = None

        with closing(self.odb.session()) as session:
            item = session.query(PubSubSubscription).\
                filter(PubSubSubscription.id==self.request.input.id).\
                filter(PubSubSubscription.cluster_id==self.request.input.cluster_id).\
                one()

            old_delivery_server_id = item.server_id
            new_delivery_server_id = self.request.input.server_id
            new_delivery_server_name = server_by_id(session, self.server.cluster_id, new_delivery_server_id).name

            for key, value in sorted(self.request.input.items()):
                if key not in _sub_skip_update:
                    setattr(item, key, value)

            # This one we set manually based on logic at the top of the method
            item.out_http_soap_id = out_http_soap_id

            session.add(item)
            session.commit()

            self.response.payload.id = self.request.input.id
            self.response.payload.name = item.topic.name

            # We change the delivery server in background - note how we send name, not ID, on input.
            # This is because our invocation target will want to use self.servers[server_name].invoke(...)
            if old_delivery_server_id != new_delivery_server_id:
                self.broker_client.publish({
                    'sub_key': self.request.input.sub_key,
                    'endpoint_type': item.endpoint.endpoint_type,
                    'old_delivery_server_id': old_delivery_server_id,
                    'new_delivery_server_name': new_delivery_server_name,
                    'action': PUBSUB.DELIVERY_SERVER_CHANGE.value,
                })
Esempio n. 19
0
def instance_hook(self, input, instance, attrs):
    common_instance_hook(self, input, instance, attrs)

    if attrs.is_create_edit:
        # Parse extra arguments to confirm their syntax is correct
        parse_extra_into_dict(input.extra)

    elif attrs.is_delete:
        if instance.is_default:
            raise BadRequest(self.cid, 'Cannot delete the default cache')
        else:
            input.cache_type = instance.cache_type
Esempio n. 20
0
def insert_topic_messages(session, cid, msg_list):
    """ Publishes messages to a topic, i.e. runs an INSERT that inserts rows, one for each message.
    """
    try:
        return sql_op_with_deadlock_retry(cid, 'insert_topic_messages',
                                          _insert_topic_messages, session,
                                          msg_list)
    # Catch duplicate MsgId values sent by clients
    except IntegrityError as e:
        if 'pubsb_msg_pubmsg_id_idx' in e.message:
            raise BadRequest(cid, 'Duplicate msg_id:`{}`'.format(e.message))
        else:
            raise
Esempio n. 21
0
    def handle(self):
        topic_list_text = [
            elem.strip()
            for elem in (self.request.raw_request.pop('topic_list_text', '')
                         or '').splitlines()
        ]
        topic_list_json = self.request.raw_request.pop('topic_list_json', [])
        topic_name = self.request.raw_request.pop('topic_name', '').strip()

        if topic_name:
            topic_name = [topic_name]

        if not (topic_list_text or topic_list_json or topic_name):
            raise BadRequest(self.cid,
                             'No topics to subscribe to given on input')
        else:
            if topic_list_text:
                topic_list = topic_list_text
            elif topic_list_json:
                topic_list = topic_list_json
            else:
                topic_list = topic_name

            # For all topics given on input, check it upfront if caller may subscribe to all of them
            check_input = [
                int(self.request.raw_request.get('ws_channel_id') or 0),
                int(self.request.raw_request.get('sql_ws_client_id') or 0),
                int(self.request.raw_request.get('security_id') or 0),
                int(self.request.raw_request.get('endpoint_id') or 0),
            ]
            for topic_name in topic_list:
                try:
                    self._is_subscription_allowed(topic_name, *check_input)
                except Forbidden:
                    self.logger.warn('Could not subscribe to `%r` using `%r`',
                                     topic_name, check_input)
                    raise

            sub_service = 'zato.pubsub.subscription.subscribe-{}'.format(
                self.request.raw_request['endpoint_type'])
            sub_request = self.request.raw_request

            # Invoke subscription for each topic given on input. At this point we know we can subscribe to all of them.
            for topic_name in topic_list:
                sub_request['topic_name'] = topic_name
                self.response.payload = self.invoke(sub_service, sub_request)
Esempio n. 22
0
def insert_topic_messages(session, cid, msg_list):
    """ Publishes messages to a topic, i.e. runs an INSERT that inserts rows, one for each message.
    """
    try:
        return sql_op_with_deadlock_retry(cid, 'insert_topic_messages', _insert_topic_messages, session, msg_list)

    # Catch duplicate MsgId values sent by clients
    except IntegrityError as e:

        if has_debug:
            logger_zato.info('Caught IntegrityError (insert_topic_messages) `%s` `%s`', cid, format_exc())

        str_e = str(e)

        if 'pubsb_msg_pubmsg_id_idx' in str_e:
            raise BadRequest(cid, 'Duplicate msg_id:`{}`'.format(str_e))
        else:
            raise
Esempio n. 23
0
    def handle_POST(self):
        """ Stores new cache entries or updates existing ones, including setting their expiry time.
        """
        input = self.request.input
        key = input['key']
        cache = self._get_cache(input)

        # This is an update of value and, possibly, an entry's expiry
        if input.get('value'):
            prev_value = cache.set(input['key'], input.value, input.get('expiry') or 0.0)
            if input.get('return_prev'):
                self.response.payload.prev_value = prev_value

        # We only update the expiry time
        else:
            if not input.get('expiry'):
                raise BadRequest(self.cid, 'At least one of `value` or `expiry` is needed on input')
            else:
                found_key = cache.expire(input['key'], input.expiry)
                if not found_key:
                    raise NotFound(self.cid, 'No such key `{}`'.format(key))
Esempio n. 24
0
    def handle(self):

        # Local aliases
        topic_name = self.request.input.topic_name
        topic_name_list = set(self.request.input.topic_name_list)
        environ = self.wsgi_environ['zato.request_ctx.async_msg']['environ']
        ws_channel_id = environ['ws_channel_config'].id

        # Make sure the WSX channel actually points to an endpoint. If it does not,
        # we cannot proceed, i.e. there is no such API client.

        try:
            self.pubsub.get_endpoint_id_by_ws_channel_id(ws_channel_id)
        except KeyError:
            self.logger.warn('There is no endpoint for WSX chan ID `%s`',
                             ws_channel_id)
            raise Forbidden(self.cid)

        # Either an exact topic name or a list thereof is needed ..
        if not (topic_name or topic_name_list):
            raise BadRequest(
                self.cid,
                'Either or topic_name or topic_name_list is required')

        # .. but we cannot accept both of them.
        elif topic_name and topic_name_list:
            raise BadRequest(
                self.cid,
                'Cannot provide both topic_name and topic_name_list on input')

        subscribe_to = [topic_name] if topic_name else topic_name_list
        responses = {}

        for item in subscribe_to:
            response = self.invoke(
                'zato.pubsub.subscription.subscribe-websockets', {
                    'topic_name': item,
                    'ws_channel_id': ws_channel_id,
                    'ext_client_id': environ['ext_client_id'],
                    'ws_pub_client_id': environ['pub_client_id'],
                    'ws_channel_name': environ['ws_channel_config']['name'],
                    'sql_ws_client_id': environ['sql_ws_client_id'],
                    'web_socket': environ['web_socket'],
                })['response']

            responses[item] = response

        # There was only one topic on input ..
        if topic_name:
            self.response.payload = responses[topic_name]

        # .. or a list of topics on was given on input.
        else:
            out = []
            for key, value in responses.items():
                out.append({
                    'topic_name': key,
                    'sub_key': value['sub_key'],
                    'current_depth': value['queue_depth'],
                })

            self.response.payload.sub_data = out
Esempio n. 25
0
 def __init__(self, cid, message):
     # type: (unicode, unicode)
     BadRequest.__init__(self, cid, msg=message)
Esempio n. 26
0
    def handle(self):

        # Local aliases
        topic_name = self.request.input.topic_name
        topic_name_list = set(self.request.input.topic_name_list)
        async_msg = self.wsgi_environ['zato.request_ctx.async_msg']

        unsub_on_wsx_close = async_msg['wsgi_environ'].get(
            'zato.request_ctx.pubsub.unsub_on_wsx_close')

        # This will exist if we are being invoked directly ..
        environ = async_msg.get('environ')

        # .. however, if there is a service on whose behalf we are invoked, the 'environ' key will be further nested.
        if not environ:
            _wsgi_environ = async_msg['wsgi_environ']
            _async_msg = _wsgi_environ['zato.request_ctx.async_msg']
            environ = _async_msg['environ']

        ws_channel_id = environ['ws_channel_config'].id

        # Make sure the WSX channel actually points to an endpoint. If it does not,
        # we cannot proceed, i.e. there is no such API client.

        try:
            self.pubsub.get_endpoint_id_by_ws_channel_id(ws_channel_id)
        except KeyError:
            self.logger.warn('There is no endpoint for WSX channel ID `%s`',
                             ws_channel_id)
            raise Forbidden(self.cid)

        # Either an exact topic name or a list thereof is needed ..
        if not (topic_name or topic_name_list):
            raise BadRequest(
                self.cid,
                'Either or topic_name or topic_name_list is required')

        # .. but we cannot accept both of them.
        elif topic_name and topic_name_list:
            raise BadRequest(
                self.cid,
                'Cannot provide both topic_name and topic_name_list on input')

        subscribe_to = [topic_name] if topic_name else topic_name_list
        responses = {}

        for item in subscribe_to:

            request = {
                'topic_name': item,
                'ws_channel_id': ws_channel_id,
                'ext_client_id': environ['ext_client_id'],
                'ws_pub_client_id': environ['pub_client_id'],
                'ws_channel_name': environ['ws_channel_config']['name'],
                'sql_ws_client_id': environ['sql_ws_client_id'],
                'unsub_on_wsx_close': unsub_on_wsx_close,
                'web_socket': environ['web_socket'],
            }

            for name in 'wrap_one_msg_in_list', 'delivery_batch_size':
                request[name] = self.request.input.get(name)

            response = self.invoke(
                'zato.pubsub.subscription.subscribe-websockets',
                request)['response']
            responses[item] = response

        # There was only one topic on input ..
        if topic_name:
            self.response.payload = responses[topic_name]

        # .. or a list of topics on was given on input.
        else:
            out = []
            for key, value in responses.items():
                out.append({
                    'topic_name': key,
                    'sub_key': value['sub_key'],
                    'current_depth': value['queue_depth'],
                })

            self.response.payload.sub_data = out
Esempio n. 27
0
 def __init__(self, cid, message):
     # type: (str, str)
     BadRequest.__init__(self, cid, msg=message)
Esempio n. 28
0
 def from_json(self, value, *ignored):
     try:
         return float(value)
     except ValueError:
         raise BadRequest(None,
                          'Cannot convert `{}` to float'.format(value))
Esempio n. 29
0
 def _raise_bad_request(self, sub_key):
     raise BadRequest(self.cid, 'No such sub_key found `{}`'.format(sub_key))
Esempio n. 30
0
 def validate_input(self):
     if self.request.input.dict_name not in self._keys_allowed:
         raise BadRequest(self.cid, 'Invalid value `{}`'.format(self.request.input.dict_name))