Skip to content

Commit b8ca134

Browse files
add /quic-v1
1 parent 8ad906c commit b8ca134

File tree

1 file changed

+78
-171
lines changed

1 file changed

+78
-171
lines changed

multiaddr/protocols.py

Lines changed: 78 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
# -*- coding: utf-8 -*-
2+
import six
13
import varint
24

35
from . import exceptions
46
from .codecs import codec_by_name
57

6-
__all__ = ("Protocol", "PROTOCOLS", "REGISTRY")
7-
88

99
# source of protocols https://github.com/multiformats/multicodec/blob/master/table.csv#L382
1010
# replicating table here to:
@@ -23,8 +23,8 @@
2323
P_P2P = 0x01A5
2424
P_HTTP = 0x01E0
2525
P_HTTPS = 0x01BB
26-
P_TLS = 0x01C0
2726
P_QUIC = 0x01CC
27+
P_QUIC1 = 0x01CD
2828
P_WS = 0x01DD
2929
P_WSS = 0x01DE
3030
P_ONION = 0x01BC
@@ -39,20 +39,50 @@
3939
P_P2P_WEBRTC_DIRECT = 0x0114
4040
P_UNIX = 0x0190
4141

42+
_CODES = [
43+
P_IP4,
44+
P_IP6,
45+
P_IP6ZONE,
46+
P_TCP,
47+
P_UDP,
48+
P_DCCP,
49+
P_SCTP,
50+
P_UDT,
51+
P_UTP,
52+
P_P2P,
53+
P_HTTP,
54+
P_HTTPS,
55+
P_QUIC,
56+
P_QUIC1,
57+
P_WS,
58+
P_WSS,
59+
P_ONION,
60+
P_ONION3,
61+
P_P2P_CIRCUIT,
62+
P_DNS,
63+
P_DNS4,
64+
P_DNS6,
65+
P_DNSADDR,
66+
P_P2P_WEBSOCKET_STAR,
67+
P_P2P_WEBRTC_STAR,
68+
P_P2P_WEBRTC_DIRECT,
69+
P_UNIX,
70+
]
71+
4272

43-
class Protocol:
73+
class Protocol(object):
4474
__slots__ = [
4575
"code", # int
4676
"name", # string
4777
"codec", # string
4878
]
4979

5080
def __init__(self, code, name, codec):
51-
if not isinstance(code, int):
81+
if not isinstance(code, six.integer_types):
5282
raise TypeError("code must be an integer")
53-
if not isinstance(name, str):
83+
if not isinstance(name, six.string_types):
5484
raise TypeError("name must be a string")
55-
if not isinstance(codec, str) and codec is not None:
85+
if not isinstance(codec, six.string_types) and codec is not None:
5686
raise TypeError("codec must be a string or None")
5787

5888
self.code = code
@@ -91,28 +121,28 @@ def __repr__(self):
91121
)
92122

93123

94-
# List of multiaddr protocols supported by this module by default
124+
# Protocols is the list of multiaddr protocols supported by this module.
95125
PROTOCOLS = [
96126
Protocol(P_IP4, 'ip4', 'ip4'),
97127
Protocol(P_TCP, 'tcp', 'uint16be'),
98128
Protocol(P_UDP, 'udp', 'uint16be'),
99129
Protocol(P_DCCP, 'dccp', 'uint16be'),
100130
Protocol(P_IP6, 'ip6', 'ip6'),
101131
Protocol(P_IP6ZONE, 'ip6zone', 'utf8'),
102-
Protocol(P_DNS, 'dns', 'domain'),
103-
Protocol(P_DNS4, 'dns4', 'domain'),
104-
Protocol(P_DNS6, 'dns6', 'domain'),
105-
Protocol(P_DNSADDR, 'dnsaddr', 'domain'),
132+
Protocol(P_DNS, 'dns', 'idna'),
133+
Protocol(P_DNS4, 'dns4', 'idna'),
134+
Protocol(P_DNS6, 'dns6', 'idna'),
135+
Protocol(P_DNSADDR, 'dnsaddr', 'idna'),
106136
Protocol(P_SCTP, 'sctp', 'uint16be'),
107137
Protocol(P_UDT, 'udt', None),
108138
Protocol(P_UTP, 'utp', None),
109-
Protocol(P_P2P, 'p2p', 'cid'),
139+
Protocol(P_P2P, 'p2p', 'p2p'),
110140
Protocol(P_ONION, 'onion', 'onion'),
111141
Protocol(P_ONION3, 'onion3', 'onion3'),
112142
Protocol(P_QUIC, 'quic', None),
143+
Protocol(P_QUIC1, 'quic-v1', None),
113144
Protocol(P_HTTP, 'http', None),
114145
Protocol(P_HTTPS, 'https', None),
115-
Protocol(P_TLS, 'tls', None),
116146
Protocol(P_WS, 'ws', None),
117147
Protocol(P_WSS, 'wss', None),
118148
Protocol(P_P2P_WEBSOCKET_STAR, 'p2p-websocket-star', None),
@@ -122,180 +152,57 @@ def __repr__(self):
122152
Protocol(P_UNIX, 'unix', 'fspath'),
123153
]
124154

155+
_names_to_protocols = dict((proto.name, proto) for proto in PROTOCOLS)
156+
_codes_to_protocols = dict((proto.code, proto) for proto in PROTOCOLS)
125157

126-
class ProtocolRegistry:
127-
"""A collection of individual Multiaddr protocols indexed for fast lookup"""
128-
__slots__ = ("_codes_to_protocols", "_locked", "_names_to_protocols")
129-
130-
def __init__(self, protocols=()):
131-
self._locked = False
132-
self._codes_to_protocols = {proto.code: proto for proto in protocols}
133-
self._names_to_protocols = {proto.name: proto for proto in protocols}
134-
135-
def add(self, proto):
136-
"""Add the given protocol description to this registry
137-
138-
Raises
139-
------
140-
~multiaddr.exceptions.ProtocolRegistryLocked
141-
Protocol registry is locked and does not accept any new entries.
142-
143-
You can use `.copy(unlock=True)` to copy an existing locked registry
144-
and unlock it.
145-
~multiaddr.exceptions.ProtocolExistsError
146-
A protocol with the given name or code already exists.
147-
"""
148-
if self._locked:
149-
raise exceptions.ProtocolRegistryLocked()
150-
151-
if proto.name in self._names_to_protocols:
152-
raise exceptions.ProtocolExistsError(proto, "name")
153-
154-
if proto.code in self._codes_to_protocols:
155-
raise exceptions.ProtocolExistsError(proto, "code")
156-
157-
self._names_to_protocols[proto.name] = proto
158-
self._codes_to_protocols[proto.code] = proto
159-
return proto
160-
161-
def add_alias_name(self, proto, alias_name):
162-
"""Add an alternate name for an existing protocol description to the registry
163-
164-
Raises
165-
------
166-
~multiaddr.exceptions.ProtocolRegistryLocked
167-
Protocol registry is locked and does not accept any new entries.
168-
169-
You can use `.copy(unlock=True)` to copy an existing locked registry
170-
and unlock it.
171-
~multiaddr.exceptions.ProtocolExistsError
172-
A protocol with the given name already exists.
173-
~multiaddr.exceptions.ProtocolNotFoundError
174-
No protocol matching *proto* could be found.
175-
"""
176-
if self._locked:
177-
raise exceptions.ProtocolRegistryLocked()
178-
179-
proto = self.find(proto)
180-
assert self._names_to_protocols.get(proto.name) is proto, \
181-
"Protocol to alias must have already been added to the registry"
182-
183-
if alias_name in self._names_to_protocols:
184-
raise exceptions.ProtocolExistsError(self._names_to_protocols[alias_name], "name")
185-
186-
self._names_to_protocols[alias_name] = proto
187-
188-
def add_alias_code(self, proto, alias_code):
189-
"""Add an alternate code for an existing protocol description to the registry
190158

191-
Raises
192-
------
193-
~multiaddr.exceptions.ProtocolRegistryLocked
194-
Protocol registry is locked and does not accept any new entries.
159+
def add_protocol(proto):
160+
if proto.name in _names_to_protocols:
161+
raise exceptions.ProtocolExistsError(proto, "name")
195162

196-
You can use `.copy(unlock=True)` to copy an existing locked registry
197-
and unlock it.
198-
~multiaddr.exceptions.ProtocolExistsError
199-
A protocol with the given code already exists.
200-
~multiaddr.exceptions.ProtocolNotFoundError
201-
No protocol matching *proto* could be found.
202-
"""
203-
if self._locked:
204-
raise exceptions.ProtocolRegistryLocked()
163+
if proto.code in _codes_to_protocols:
164+
raise exceptions.ProtocolExistsError(proto, "code")
205165

206-
proto = self.find(proto)
207-
assert self._codes_to_protocols.get(proto.code) is proto, \
208-
"Protocol to alias must have already been added to the registry"
209-
210-
if alias_code in self._codes_to_protocols:
211-
raise exceptions.ProtocolExistsError(self._codes_to_protocols[alias_code], "name")
212-
213-
self._codes_to_protocols[alias_code] = proto
214-
215-
def lock(self):
216-
"""Lock this registry instance to deny any further changes"""
217-
self._locked = True
218-
219-
@property
220-
def locked(self):
221-
return self._locked
222-
223-
def copy(self, *, unlock=False):
224-
"""Create a copy of this protocol registry
225-
226-
Arguments
227-
---------
228-
unlock
229-
Create the copied registry unlocked even if the current one is locked?
230-
"""
231-
registry = ProtocolRegistry()
232-
registry._locked = self._locked and not unlock
233-
registry._codes_to_protocols = self._codes_to_protocols.copy()
234-
registry._names_to_protocols = self._names_to_protocols.copy()
235-
return registry
236-
237-
__copy__ = copy
238-
239-
def find_by_name(self, name):
240-
"""Look up a protocol by its human-readable name
241-
242-
Raises
243-
------
244-
~multiaddr.exceptions.ProtocolNotFoundError
245-
"""
246-
if name not in self._names_to_protocols:
247-
raise exceptions.ProtocolNotFoundError(name, "name")
248-
return self._names_to_protocols[name]
249-
250-
def find_by_code(self, code):
251-
"""Look up a protocol by its binary representation code
252-
253-
Raises
254-
------
255-
~multiaddr.exceptions.ProtocolNotFoundError
256-
"""
257-
if code not in self._codes_to_protocols:
258-
raise exceptions.ProtocolNotFoundError(code, "code")
259-
return self._codes_to_protocols[code]
260-
261-
def find(self, proto):
262-
"""Look up a protocol by its name or code, return existing protocol objects unchanged
263-
264-
Raises
265-
------
266-
~multiaddr.exceptions.ProtocolNotFoundError
267-
"""
268-
if isinstance(proto, Protocol):
269-
return proto
270-
elif isinstance(proto, str):
271-
return self.find_by_name(proto)
272-
elif isinstance(proto, int):
273-
return self.find_by_code(proto)
274-
else:
275-
raise TypeError("Protocol object, name or code expected, got {0!r}".format(proto))
276-
277-
278-
REGISTRY = ProtocolRegistry(PROTOCOLS)
279-
REGISTRY.add_alias_name("p2p", "ipfs")
280-
REGISTRY.lock()
166+
PROTOCOLS.append(proto)
167+
_names_to_protocols[proto.name] = proto
168+
_codes_to_protocols[proto.code] = proto
169+
return None
281170

282171

283172
def protocol_with_name(name):
284-
return REGISTRY.find_by_name(name)
173+
name = str(name) # PY2: Convert Unicode strings to native/binary representation
174+
if name not in _names_to_protocols:
175+
raise exceptions.ProtocolNotFoundError(name, "name")
176+
return _names_to_protocols[name]
285177

286178

287179
def protocol_with_code(code):
288-
return REGISTRY.find_by_code(code)
180+
if code not in _codes_to_protocols:
181+
raise exceptions.ProtocolNotFoundError(code, "code")
182+
return _codes_to_protocols[code]
289183

290184

291185
def protocol_with_any(proto):
292-
return REGISTRY.find(proto)
186+
if isinstance(proto, Protocol):
187+
return proto
188+
elif isinstance(proto, int):
189+
return protocol_with_code(proto)
190+
elif isinstance(proto, six.string_types):
191+
return protocol_with_name(proto)
192+
else:
193+
raise TypeError("Protocol object, name or code expected, got {0!r}".format(proto))
293194

294195

295196
def protocols_with_string(string):
296197
"""Return a list of protocols matching given string."""
198+
# Normalize string
199+
while "//" in string:
200+
string = string.replace("//", "/")
201+
string = string.strip("/")
202+
if not string:
203+
return []
204+
297205
ret = []
298206
for name in string.split("/"):
299-
if len(name) > 0:
300-
ret.append(protocol_with_name(name))
207+
ret.append(protocol_with_name(name))
301208
return ret

0 commit comments

Comments
 (0)