95 lines
2.5 KiB
Go
95 lines
2.5 KiB
Go
package multiprotocol
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/multiformats/go-multiaddr"
|
|
)
|
|
|
|
// These are special sizes
|
|
const (
|
|
LengthPrefixedVarSize = -1
|
|
)
|
|
|
|
// Protocol is a protocol description structure. This was taken from Multiaddr
|
|
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
|
|
|
|
// 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 multiaddr.Transcoder
|
|
}
|
|
|
|
var protocolsByName = map[string]Protocol{}
|
|
var protocolsByCode = map[int]Protocol{}
|
|
|
|
// Protocols is the list of multiprotocol protocols supported by this module.
|
|
var Protocols = []Protocol{}
|
|
|
|
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")
|
|
}
|
|
|
|
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
|
|
}
|