mirror of
https://github.com/logos-messaging/go-multiaddr.git
synced 2026-01-03 05:23:08 +00:00
The error in String should not actually ocurr, as the multiaddr should have been valid to be constructed successfully, and thus should be encoded back to its string rep correctly. This will be bolstered by creating an interface (to prevent messing with the internal bytes)
117 lines
2.7 KiB
Go
117 lines
2.7 KiB
Go
package multiaddr
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Multiaddr is the data structure representing a multiaddr
|
|
type Multiaddr struct {
|
|
Bytes []byte
|
|
}
|
|
|
|
// NewMultiaddr parses and validates an input string, returning a *Multiaddr
|
|
func NewMultiaddr(s string) (*Multiaddr, error) {
|
|
b, err := stringToBytes(s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Multiaddr{Bytes: b}, nil
|
|
}
|
|
|
|
// Equal tests whether two multiaddrs are equal
|
|
func (m *Multiaddr) Equal(m2 *Multiaddr) bool {
|
|
return bytes.Equal(m.Bytes, m2.Bytes)
|
|
}
|
|
|
|
// String returns the string representation of a Multiaddr
|
|
func (m *Multiaddr) String() string {
|
|
s, err := bytesToString(m.Bytes)
|
|
if err != nil {
|
|
panic("multiaddr failed to convert back to string. corrupted?")
|
|
}
|
|
return s
|
|
}
|
|
|
|
// Protocols returns the list of protocols this Multiaddr has.
|
|
func (m *Multiaddr) Protocols() (ret []*Protocol, err error) {
|
|
|
|
// panic handler, in case we try accessing bytes incorrectly.
|
|
defer func() {
|
|
if e := recover(); e != nil {
|
|
ret = nil
|
|
err = e.(error)
|
|
}
|
|
}()
|
|
|
|
ps := []*Protocol{}
|
|
b := m.Bytes[:]
|
|
for len(b) > 0 {
|
|
p := ProtocolWithCode(int(b[0]))
|
|
if p == nil {
|
|
return nil, fmt.Errorf("no protocol with code %d", b[0])
|
|
}
|
|
ps = append(ps, p)
|
|
b = b[1+(p.Size/8):]
|
|
}
|
|
return ps, nil
|
|
}
|
|
|
|
// Encapsulate wraps a given Multiaddr, returning the resulting joined Multiaddr
|
|
func (m *Multiaddr) Encapsulate(o *Multiaddr) *Multiaddr {
|
|
b := make([]byte, len(m.Bytes)+len(o.Bytes))
|
|
b = append(m.Bytes, o.Bytes...)
|
|
return &Multiaddr{Bytes: b}
|
|
}
|
|
|
|
// Decapsulate unwraps Multiaddr up until the given Multiaddr is found.
|
|
func (m *Multiaddr) Decapsulate(o *Multiaddr) (*Multiaddr, error) {
|
|
s1 := m.String()
|
|
s2 := o.String()
|
|
i := strings.LastIndex(s1, s2)
|
|
if i < 0 {
|
|
return nil, fmt.Errorf("%s not contained in %s", s2, s1)
|
|
}
|
|
return NewMultiaddr(s1[:i])
|
|
}
|
|
|
|
// DialArgs is a convenience function returning arguments for use in net.Dial
|
|
func (m *Multiaddr) DialArgs() (string, string, error) {
|
|
if !m.IsThinWaist() {
|
|
return "", "", fmt.Errorf("%s is not a 'thin waist' address", m)
|
|
}
|
|
|
|
str := m.String()
|
|
parts := strings.Split(str, "/")[1:]
|
|
network := parts[2]
|
|
|
|
var host string
|
|
switch parts[0] {
|
|
case "ip4":
|
|
host = strings.Join([]string{parts[1], parts[3]}, ":")
|
|
case "ip6":
|
|
host = fmt.Sprintf("[%s]:%s", parts[1], parts[3])
|
|
}
|
|
return network, host, nil
|
|
}
|
|
|
|
// IsThinWaist returns whether this multiaddr includes "Thin Waist" Protocols.
|
|
// This means: /{IP4, IP6}/{TCP, UDP}
|
|
func (m *Multiaddr) IsThinWaist() bool {
|
|
p, err := m.Protocols()
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
if p[0].Code != P_IP4 && p[0].Code != P_IP6 {
|
|
return false
|
|
}
|
|
|
|
if p[1].Code != P_TCP && p[1].Code != P_UDP {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|