Esempio n. 1
0
def _create_transport(index, transport, check_native_endpoint=None):
    """
    Internal helper to insert defaults and create _Transport instances.

    :param transport: a (possibly valid) transport configuration
    :type transport: dict

    :returns: a _Transport instance

    :raises: ValueError on invalid configuration
    """
    if type(transport) != dict:
        raise ValueError(
            'invalid type {} for transport configuration - must be a dict'.
            format(type(transport)))

    valid_transport_keys = [
        'type',
        'url',
        'endpoint',
        'serializer',
        'serializers',
        'options',
        'max_retries',
        'max_retry_delay',
        'initial_retry_delay',
        'retry_delay_growth',
        'retry_delay_jitter',
    ]
    for k in transport.keys():
        if k not in valid_transport_keys:
            raise ValueError(
                "'{}' is not a valid configuration item".format(k))

    kind = 'websocket'
    if 'type' in transport:
        if transport['type'] not in ['websocket', 'rawsocket']:
            raise ValueError('Invalid transport type {}'.format(
                transport['type']))
        kind = transport['type']
    else:
        transport['type'] = 'websocket'

    options = dict()
    if 'options' in transport:
        options = transport['options']
        if not isinstance(options, dict):
            raise ValueError('options must be a dict, not {}'.format(
                type(options)))

    if kind == 'websocket':
        for key in ['url']:
            if key not in transport:
                raise ValueError("Transport requires '{}' key".format(key))
        # endpoint not required; we will deduce from URL if it's not provided
        # XXX not in the branch I rebased; can this go away? (is it redundant??)
        if 'endpoint' not in transport:
            is_secure, host, port, resource, path, params = parse_ws_url(
                transport['url'])
            endpoint_config = {
                'type': 'tcp',
                'host': host,
                'port': port,
                'tls': is_secure,
            }
        else:
            # note: we're avoiding mutating the incoming "configuration"
            # dict, so this should avoid that too...
            endpoint_config = transport['endpoint']
            _validate_endpoint(endpoint_config, check_native_endpoint)

        if 'serializer' in transport:
            raise ValueError(
                "'serializer' is only for rawsocket; use 'serializers'")
        if 'serializers' in transport:
            if not isinstance(transport['serializers'], (list, tuple)):
                raise ValueError("'serializers' must be a list of strings")
            if not all([
                    isinstance(s, (six.text_type, str))
                    for s in transport['serializers']
            ]):
                raise ValueError("'serializers' must be a list of strings")
            valid_serializers = SERID_TO_SER.keys()
            for serial in transport['serializers']:
                if serial not in valid_serializers:
                    raise ValueError(
                        "Invalid serializer '{}' (expected one of: {})".format(
                            serial,
                            ', '.join([repr(s) for s in valid_serializers]),
                        ))
        serializer_config = transport.get('serializers', [u'cbor', u'json'])

    elif kind == 'rawsocket':
        if 'endpoint' not in transport:
            if transport['url'].startswith('rs'):
                # # try to parse RawSocket URL ..
                isSecure, host, port = parse_rs_url(transport['url'])
            elif transport['url'].startswith('ws'):
                # try to parse WebSocket URL ..
                isSecure, host, port, resource, path, params = parse_ws_url(
                    transport['url'])
            else:
                raise RuntimeError()
            if host == 'unix':
                # here, "port" is actually holding the path on the host, eg "/tmp/file.sock"
                endpoint_config = {
                    'type': 'unix',
                    'path': port,
                }
            else:
                endpoint_config = {
                    'type': 'tcp',
                    'host': host,
                    'port': port,
                }
        else:
            endpoint_config = transport['endpoint']
        if 'serializers' in transport:
            raise ValueError(
                "'serializers' is only for websocket; use 'serializer'")
        # always a list; len == 1 for rawsocket
        if 'serializer' in transport:
            if not isinstance(transport['serializer'], (six.text_type, str)):
                raise ValueError("'serializer' must be a string")
            serializer_config = [transport['serializer']]
        else:
            serializer_config = [u'cbor']

    else:
        assert False, 'should not arrive here'

    kw = {}
    for key in [
            'max_retries', 'max_retry_delay', 'initial_retry_delay',
            'retry_delay_growth', 'retry_delay_jitter'
    ]:
        if key in transport:
            kw[key] = transport[key]

    return _Transport(index,
                      kind=kind,
                      url=transport['url'],
                      endpoint=endpoint_config,
                      serializers=serializer_config,
                      options=options,
                      **kw)
Esempio n. 2
0
def _create_transport(index, transport, check_native_endpoint=None):
    """
    Internal helper to insert defaults and create _Transport instances.

    :param transport: a (possibly valid) transport configuration
    :type transport: dict

    :returns: a _Transport instance

    :raises: ValueError on invalid configuration
    """
    if type(transport) != dict:
        raise ValueError('invalid type {} for transport configuration - must be a dict'.format(type(transport)))

    valid_transport_keys = [
        'type', 'url', 'endpoint', 'serializer', 'serializers', 'options',
        'max_retries', 'max_retry_delay', 'initial_retry_delay',
        'retry_delay_growth', 'retry_delay_jitter', 'proxy',
    ]
    for k in transport.keys():
        if k not in valid_transport_keys:
            raise ValueError(
                "'{}' is not a valid configuration item".format(k)
            )

    kind = 'websocket'
    if 'type' in transport:
        if transport['type'] not in ['websocket', 'rawsocket']:
            raise ValueError('Invalid transport type {}'.format(transport['type']))
        kind = transport['type']
    else:
        transport['type'] = 'websocket'

    if 'proxy' in transport and kind != 'websocket':
        raise ValueError(
            "proxy= only supported for type=websocket transports"
        )
    proxy = transport.get("proxy", None)
    if proxy is not None:
        for k in proxy.keys():
            if k not in ['host', 'port']:
                raise ValueError(
                    "Unknown key '{}' in proxy config".format(k)
                )
        for k in ['host', 'port']:
            if k not in proxy:
                raise ValueError(
                    "Proxy config requires '{}'".formaT(k)
                )

    options = dict()
    if 'options' in transport:
        options = transport['options']
        if not isinstance(options, dict):
            raise ValueError(
                'options must be a dict, not {}'.format(type(options))
            )

    if kind == 'websocket':
        for key in ['url']:
            if key not in transport:
                raise ValueError("Transport requires '{}' key".format(key))
        # endpoint not required; we will deduce from URL if it's not provided
        # XXX not in the branch I rebased; can this go away? (is it redundant??)
        if 'endpoint' not in transport:
            is_secure, host, port, resource, path, params = parse_ws_url(transport['url'])
            endpoint_config = {
                'type': 'tcp',
                'host': host,
                'port': port,
                'tls': is_secure,
            }
        else:
            # note: we're avoiding mutating the incoming "configuration"
            # dict, so this should avoid that too...
            endpoint_config = transport['endpoint']
            _validate_endpoint(endpoint_config, check_native_endpoint)

        if 'serializer' in transport:
            raise ValueError("'serializer' is only for rawsocket; use 'serializers'")
        if 'serializers' in transport:
            if not isinstance(transport['serializers'], (list, tuple)):
                raise ValueError("'serializers' must be a list of strings")
            if not all([
                    isinstance(s, (six.text_type, str))
                    for s in transport['serializers']]):
                raise ValueError("'serializers' must be a list of strings")
            valid_serializers = SERID_TO_SER.keys()
            for serial in transport['serializers']:
                if serial not in valid_serializers:
                    raise ValueError(
                        "Invalid serializer '{}' (expected one of: {})".format(
                            serial,
                            ', '.join([repr(s) for s in valid_serializers]),
                        )
                    )
        serializer_config = transport.get('serializers', [u'cbor', u'json'])

    elif kind == 'rawsocket':
        if 'endpoint' not in transport:
            if transport['url'].startswith('rs'):
                # # try to parse RawSocket URL ..
                isSecure, host, port = parse_rs_url(transport['url'])
            elif transport['url'].startswith('ws'):
                # try to parse WebSocket URL ..
                isSecure, host, port, resource, path, params = parse_ws_url(transport['url'])
            else:
                raise RuntimeError()
            if host == 'unix':
                # here, "port" is actually holding the path on the host, eg "/tmp/file.sock"
                endpoint_config = {
                    'type': 'unix',
                    'path': port,
                }
            else:
                endpoint_config = {
                    'type': 'tcp',
                    'host': host,
                    'port': port,
                }
        else:
            endpoint_config = transport['endpoint']
        if 'serializers' in transport:
            raise ValueError("'serializers' is only for websocket; use 'serializer'")
        # always a list; len == 1 for rawsocket
        if 'serializer' in transport:
            if not isinstance(transport['serializer'], (six.text_type, str)):
                raise ValueError("'serializer' must be a string")
            serializer_config = [transport['serializer']]
        else:
            serializer_config = [u'cbor']

    else:
        assert False, 'should not arrive here'

    kw = {}
    for key in ['max_retries', 'max_retry_delay', 'initial_retry_delay',
                'retry_delay_growth', 'retry_delay_jitter']:
        if key in transport:
            kw[key] = transport[key]

    return _Transport(
        index,
        kind=kind,
        url=transport.get('url', None),
        endpoint=endpoint_config,
        serializers=serializer_config,
        proxy=proxy,
        options=options,
        **kw
    )