string <> []byte

This commit is contained in:
Juan Batiz-Benet 2014-07-03 23:42:24 -07:00
parent ddfe13152f
commit c5510ff4b8
6 changed files with 270 additions and 0 deletions

74
README.md Normal file
View File

@ -0,0 +1,74 @@
# go-multiaddr
[multiaddr](https://github.com/jbenet/multiaddr) implementation in Go.
## Example
### Simple
```go
import "github.com/jbenet/go-multiaddr"
m := multiaddr.NewString("/ip4/127.0.0.1/udp/1234")
// <Multiaddr /ip4/127.0.0.1/udp/1234>
m.buffer
// <Buffer >
m.String()
// /ip4/127.0.0.1/udp/1234
// construct with Buffer
m = multiaddr.Multiaddr{ Bytes: m.Bytes }
// <Multiaddr /ip4/127.0.0.1/udp/1234>
```
### Protocols
```go
// get the multiaddr protocol codes
m.ProtoCodes()
// []int{4, 6}
// get the multiaddr protocol string codes
m.ProtoNames()
// []string{"ip4", "tcp"}
// get the multiaddr protocol description objects
addr.Protos()
// []Protocol{
// Protocol{ Code: 4, Name: 'ip4', Size: 32},
// Protocol{ Code: 17, Name: 'udp', Size: 16},
// }
```
### Other formats
```go
// handles the stupid url version too
m = multiaddr.NewUrl("udp4://127.0.0.1:1234")
// <Multiaddr /ip4/127.0.0.1/udp/1234>
m.Url(buf)
// udp4://127.0.0.1:1234
```
### En/decapsulate
```go
m.Encapsulate(m.NewString("/sctp/5678"))
// <Multiaddr /ip4/127.0.0.1/udp/1234/sctp/5678>
m.Decapsulate(m.NewString("/udp")) // up to + inc last occurrence of subaddr
// <Multiaddr /ip4/127.0.0.1>
```
### Tunneling
Multiaddr allows expressing tunnels very nicely.
```js
printer := multiaddr.NewString("/ip4/192.168.0.13/tcp/80")
proxy := multiaddr.NewString("/ip4/10.20.30.40/tcp/443")
printerOverProxy := proxy.Encapsulate(printer)
// <Multiaddr /ip4/10.20.30.40/tcp/443/ip4/192.168.0.13/tcp/80>
proxyAgain := printerOverProxy.Decapsulate(multiaddr.NewString("/ip4"))
// <Multiaddr /ip4/10.20.30.40/tcp/443>
```

50
codec.go Normal file
View File

@ -0,0 +1,50 @@
package multiaddr
import(
"fmt"
"strings"
)
func StringToBytes(s string) ([]byte, error) {
b := []byte{}
sp := strings.Split(s, "/")
// consume first empty elem
sp = sp[1:]
for ; len(sp) > 0 ; {
p := ProtocolWithName(sp[0])
if p == nil {
return nil, fmt.Errorf("no protocol with name %s", sp[0])
}
b = append(b, byte(p.Code))
a := AddressStringToBytes(p, sp[1])
b = append(b, a...)
sp = sp[2:]
}
return b, nil
}
func BytesToString(b []byte) (string, error) {
s := ""
for ; len(b) > 0 ; {
p := ProtocolWithCode(int(b[0]))
if p == nil {
return "", fmt.Errorf("no protocol with code %d", b[0])
}
s = strings.Join([]string{s, "/", p.Name}, "")
b = b[1:]
a := AddressBytesToString(p, b)
if len(a) > 0 {
s = strings.Join([]string{s, "/", a}, "")
}
b = b[(p.Size / 8):]
}
return s, nil
}

43
convert.go Normal file
View File

@ -0,0 +1,43 @@
package multiaddr
import (
"encoding/binary"
"net"
"strconv"
)
func AddressStringToBytes(p *Protocol, s string) []byte {
switch p.Code {
// ipv4,6
case 4, 41:
return net.ParseIP(s).To4()
// tcp udp dccp sctp
case 6, 17, 33, 132:
b := make([]byte, 2)
i, err := strconv.Atoi(s)
if err == nil {
binary.BigEndian.PutUint16(b, uint16(i))
}
return b
}
return []byte{}
}
func AddressBytesToString(p *Protocol, b []byte) string {
switch p.Code {
// ipv4,6
case 4, 41:
return net.IP(b).String()
// tcp udp dccp sctp
case 6, 17, 33, 132:
i := binary.BigEndian.Uint16(b)
return strconv.Itoa(int(i))
}
return ""
}

10
index.go Normal file
View File

@ -0,0 +1,10 @@
package multiaddr
type Multiaddr struct {
Bytes []byte
}
func NewString(s string) *Multiaddr {
m := &Multiaddr{}
return m
}

51
multiaddr_test.go Normal file
View File

@ -0,0 +1,51 @@
package multiaddr
import (
"bytes"
"testing"
"encoding/hex"
)
func TestStringToBytes(t *testing.T) {
testString := func(s string, h string) {
b1, err := hex.DecodeString(h)
if err != nil {
t.Error("failed to decode hex", h)
}
b2, err := StringToBytes(s)
if err != nil {
t.Error("failed to convert", s)
}
if !bytes.Equal(b1, b2) {
t.Error("failed to convert", s, "to", b1, "got", b2)
}
}
testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2")
}
func TestBytesToString(t *testing.T) {
testString := func(s1 string, h string) {
b, err := hex.DecodeString(h)
if err != nil {
t.Error("failed to decode hex", h)
}
s2, err := BytesToString(b)
if err != nil {
t.Error("failed to convert", b)
}
if s1 == s2 {
t.Error("failed to convert", b, "to", s1, "got", s2)
}
}
testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2")
}

42
protocols.go Normal file
View File

@ -0,0 +1,42 @@
package multiaddr
type Protocol struct {
Code int
Size int
Name string
}
// replicating table here to:
// 1. avoid parsing the csv
// 2. ensuring errors in the csv don't screw up code.
// 3. changing a number has to happen in two places.
var Protocols = []Protocol{
Protocol{4, 32, "ip4"},
Protocol{6, 16, "tcp"},
Protocol{17, 16, "udp"},
Protocol{33, 16, "dccp"},
Protocol{41, 128, "ip6"},
// these require varint:
Protocol{132, 16, "sctp"},
// {480, 0, "http"},
// {443, 0, "https"},
}
func ProtocolWithName(s string) *Protocol {
for _, p := range(Protocols) {
if p.Name == s {
return &p
}
}
return nil
}
func ProtocolWithCode(c int) *Protocol {
for _, p := range(Protocols) {
if p.Code == c {
return &p
}
}
return nil
}