1
+ # -*- coding: utf-8 -*-
2
+ import six
1
3
import varint
2
4
3
5
from . import exceptions
4
6
from .codecs import codec_by_name
5
7
6
- __all__ = ("Protocol" , "PROTOCOLS" , "REGISTRY" )
7
-
8
8
9
9
# source of protocols https://github.com/multiformats/multicodec/blob/master/table.csv#L382
10
10
# replicating table here to:
23
23
P_P2P = 0x01A5
24
24
P_HTTP = 0x01E0
25
25
P_HTTPS = 0x01BB
26
- P_TLS = 0x01C0
27
26
P_QUIC = 0x01CC
27
+ P_QUIC1 = 0x01CD
28
28
P_WS = 0x01DD
29
29
P_WSS = 0x01DE
30
30
P_ONION = 0x01BC
39
39
P_P2P_WEBRTC_DIRECT = 0x0114
40
40
P_UNIX = 0x0190
41
41
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
+
42
72
43
- class Protocol :
73
+ class Protocol ( object ) :
44
74
__slots__ = [
45
75
"code" , # int
46
76
"name" , # string
47
77
"codec" , # string
48
78
]
49
79
50
80
def __init__ (self , code , name , codec ):
51
- if not isinstance (code , int ):
81
+ if not isinstance (code , six . integer_types ):
52
82
raise TypeError ("code must be an integer" )
53
- if not isinstance (name , str ):
83
+ if not isinstance (name , six . string_types ):
54
84
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 :
56
86
raise TypeError ("codec must be a string or None" )
57
87
58
88
self .code = code
@@ -91,28 +121,28 @@ def __repr__(self):
91
121
)
92
122
93
123
94
- # List of multiaddr protocols supported by this module by default
124
+ # Protocols is the list of multiaddr protocols supported by this module.
95
125
PROTOCOLS = [
96
126
Protocol (P_IP4 , 'ip4' , 'ip4' ),
97
127
Protocol (P_TCP , 'tcp' , 'uint16be' ),
98
128
Protocol (P_UDP , 'udp' , 'uint16be' ),
99
129
Protocol (P_DCCP , 'dccp' , 'uint16be' ),
100
130
Protocol (P_IP6 , 'ip6' , 'ip6' ),
101
131
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 ' ),
106
136
Protocol (P_SCTP , 'sctp' , 'uint16be' ),
107
137
Protocol (P_UDT , 'udt' , None ),
108
138
Protocol (P_UTP , 'utp' , None ),
109
- Protocol (P_P2P , 'p2p' , 'cid ' ),
139
+ Protocol (P_P2P , 'p2p' , 'p2p ' ),
110
140
Protocol (P_ONION , 'onion' , 'onion' ),
111
141
Protocol (P_ONION3 , 'onion3' , 'onion3' ),
112
142
Protocol (P_QUIC , 'quic' , None ),
143
+ Protocol (P_QUIC1 , 'quic-v1' , None ),
113
144
Protocol (P_HTTP , 'http' , None ),
114
145
Protocol (P_HTTPS , 'https' , None ),
115
- Protocol (P_TLS , 'tls' , None ),
116
146
Protocol (P_WS , 'ws' , None ),
117
147
Protocol (P_WSS , 'wss' , None ),
118
148
Protocol (P_P2P_WEBSOCKET_STAR , 'p2p-websocket-star' , None ),
@@ -122,180 +152,57 @@ def __repr__(self):
122
152
Protocol (P_UNIX , 'unix' , 'fspath' ),
123
153
]
124
154
155
+ _names_to_protocols = dict ((proto .name , proto ) for proto in PROTOCOLS )
156
+ _codes_to_protocols = dict ((proto .code , proto ) for proto in PROTOCOLS )
125
157
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
190
158
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" )
195
162
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" )
205
165
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
281
170
282
171
283
172
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 ]
285
177
286
178
287
179
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 ]
289
183
290
184
291
185
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 ))
293
194
294
195
295
196
def protocols_with_string (string ):
296
197
"""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
+
297
205
ret = []
298
206
for name in string .split ("/" ):
299
- if len (name ) > 0 :
300
- ret .append (protocol_with_name (name ))
207
+ ret .append (protocol_with_name (name ))
301
208
return ret
0 commit comments