130 lines
3.8 KiB
Go
130 lines
3.8 KiB
Go
|
package multiaddr
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// These are special sizes
|
||
|
const (
|
||
|
LengthPrefixedVarSize = -1
|
||
|
)
|
||
|
|
||
|
// Protocol is a Multiaddr protocol description structure.
|
||
|
type Protocol struct {
|
||
|
// Name is the string representation of the protocol code. E.g., ip4,
|
||
|
// ip6, tcp, udp, etc.
|
||
|
Name string
|
||
|
|
||
|
// Code is the protocol's multicodec (a normal, non-varint number).
|
||
|
Code int
|
||
|
|
||
|
// VCode is a precomputed varint encoded version of Code.
|
||
|
VCode []byte
|
||
|
|
||
|
// Size is the size of the argument to this protocol.
|
||
|
//
|
||
|
// * Size == 0 means this protocol takes no argument.
|
||
|
// * Size > 0 means this protocol takes a constant sized argument.
|
||
|
// * Size < 0 means this protocol takes a variable length, varint
|
||
|
// prefixed argument.
|
||
|
Size int // a size of -1 indicates a length-prefixed variable size
|
||
|
|
||
|
// Path indicates a path protocol (e.g., unix). When parsing multiaddr
|
||
|
// strings, path protocols consume the remainder of the address instead
|
||
|
// of stopping at the next forward slash.
|
||
|
//
|
||
|
// Size must be LengthPrefixedVarSize.
|
||
|
Path bool
|
||
|
|
||
|
// Transcoder converts between the byte representation and the string
|
||
|
// representation of this protocol's argument (if any).
|
||
|
//
|
||
|
// This should only be non-nil if Size != 0
|
||
|
Transcoder Transcoder
|
||
|
}
|
||
|
|
||
|
var protocolsByName = map[string]Protocol{}
|
||
|
var protocolsByCode = map[int]Protocol{}
|
||
|
|
||
|
// Protocols is the list of multiaddr protocols supported by this module.
|
||
|
var Protocols = []Protocol{}
|
||
|
|
||
|
// SwapToP2pMultiaddrs is a function to make the transition from /ipfs/...
|
||
|
// multiaddrs to /p2p/... multiaddrs easier
|
||
|
// The first stage of the rollout is to ship this package to all users so
|
||
|
// that all users of multiaddr can parse both /ipfs/ and /p2p/ multiaddrs
|
||
|
// as the same code (P_P2P). During this stage of the rollout, all addresses
|
||
|
// with P_P2P will continue printing as /ipfs/, so that older clients without
|
||
|
// the new parsing code won't break.
|
||
|
// Once the network has adopted the new parsing code broadly enough, users of
|
||
|
// multiaddr can add a call to this method to an init function in their codebase.
|
||
|
// This will cause any P_P2P multiaddr to print out as /p2p/ instead of /ipfs/.
|
||
|
// Note that the binary serialization of this multiaddr does not change at any
|
||
|
// point. This means that this code is not a breaking network change at any point
|
||
|
func SwapToP2pMultiaddrs() {
|
||
|
for i := range Protocols {
|
||
|
if Protocols[i].Code == P_P2P {
|
||
|
Protocols[i].Name = "p2p"
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protoP2P.Name = "p2p"
|
||
|
|
||
|
protocolsByName["ipfs"] = protoP2P
|
||
|
protocolsByName["p2p"] = protoP2P
|
||
|
protocolsByCode[protoP2P.Code] = protoP2P
|
||
|
}
|
||
|
|
||
|
func AddProtocol(p Protocol) error {
|
||
|
if _, ok := protocolsByName[p.Name]; ok {
|
||
|
return fmt.Errorf("protocol by the name %q already exists", p.Name)
|
||
|
}
|
||
|
|
||
|
if _, ok := protocolsByCode[p.Code]; ok {
|
||
|
return fmt.Errorf("protocol code %d already taken by %q", p.Code, p.Code)
|
||
|
}
|
||
|
|
||
|
if p.Size != 0 && p.Transcoder == nil {
|
||
|
return fmt.Errorf("protocols with arguments must define transcoders")
|
||
|
}
|
||
|
if p.Path && p.Size >= 0 {
|
||
|
return fmt.Errorf("path protocols must have variable-length sizes")
|
||
|
}
|
||
|
|
||
|
Protocols = append(Protocols, p)
|
||
|
protocolsByName[p.Name] = p
|
||
|
protocolsByCode[p.Code] = p
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// ProtocolWithName returns the Protocol description with given string name.
|
||
|
func ProtocolWithName(s string) Protocol {
|
||
|
return protocolsByName[s]
|
||
|
}
|
||
|
|
||
|
// ProtocolWithCode returns the Protocol description with given protocol code.
|
||
|
func ProtocolWithCode(c int) Protocol {
|
||
|
return protocolsByCode[c]
|
||
|
}
|
||
|
|
||
|
// ProtocolsWithString returns a slice of protocols matching given string.
|
||
|
func ProtocolsWithString(s string) ([]Protocol, error) {
|
||
|
s = strings.Trim(s, "/")
|
||
|
sp := strings.Split(s, "/")
|
||
|
if len(sp) == 0 {
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
t := make([]Protocol, len(sp))
|
||
|
for i, name := range sp {
|
||
|
p := ProtocolWithName(name)
|
||
|
if p.Code == 0 {
|
||
|
return nil, fmt.Errorf("no protocol with name: %s", name)
|
||
|
}
|
||
|
t[i] = p
|
||
|
}
|
||
|
return t, nil
|
||
|
}
|