-
Notifications
You must be signed in to change notification settings - Fork 7
/
structs.go
145 lines (118 loc) · 3.8 KB
/
structs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package service
import (
"errors"
"fmt"
"capnproto.org/go/capnp/v3"
"github.com/libp2p/go-libp2p/core/record"
ma "github.com/multiformats/go-multiaddr"
api "github.com/wetware/pkg/api/registry"
)
// TODO: register this once stable.
// https://github.com/multiformats/multicodec/blob/master/table.csv
var (
EnvelopeDomain = "ww/registry/location"
EnvelopePayloadType = []byte{0x1f, 0x01}
ErrInavlidType = errors.New("invalid type")
)
func init() {
record.RegisterType(&Location{})
}
var ErrInvalidSignature = errors.New("invalid signature")
type Location struct {
api.Location
}
func NewLocation() (Location, error) {
_, seg := capnp.NewSingleSegmentMessage(nil)
loc, err := api.NewRootLocation(seg)
if err != nil {
return Location{}, fmt.Errorf("failed to create location: %w", err)
}
return Location{Location: loc}, nil
}
func (loc Location) Validate(topic string) error {
service, err := loc.Service()
if err != nil {
return fmt.Errorf("failed to read service name: %w", err)
}
if topic != service {
return fmt.Errorf("the topic and the service name are different, topic: %s - service: %s", topic, service)
}
return nil
}
func (loc Location) SetMaddrs(maddrs []ma.Multiaddr) error {
capMaddrs, err := loc.NewMaddrs(int32(len(maddrs)))
if err != nil {
return fmt.Errorf("fail to create capnp Multiaddr: %w", err)
}
for i, maddr := range maddrs {
if err := capMaddrs.Set(i, maddr.Bytes()); err != nil {
return fmt.Errorf("fail to set maddr in Location: %w", err)
}
}
return nil
}
func (loc Location) SetAnchor(anchor string) error {
if err := loc.Location.SetAnchor(anchor); err != nil {
return fmt.Errorf("fail to set anchor in capnp Location: %w", err)
}
return nil
}
func (loc Location) SetCustom(custom capnp.Ptr) error {
if err := loc.Location.SetCustom(custom); err != nil {
return fmt.Errorf("fail to set custom in capnp Location: %w", err)
}
return nil
}
func (loc Location) Maddrs() ([]ma.Multiaddr, error) {
capMaddrs, err := loc.Location.Maddrs()
if err != nil {
return nil, fmt.Errorf("failed to get Multiaddresses: %w", err)
}
maddrs := make([]ma.Multiaddr, 0, capMaddrs.Len())
for i := 0; i < capMaddrs.Len(); i++ {
buffer, err := capMaddrs.At(i)
if err != nil {
return nil, fmt.Errorf("failed to get Multiaddress at index %d: %w", i, err)
}
b := make([]byte, len(buffer))
copy(b, buffer)
maddr, err := ma.NewMultiaddrBytes(b)
if err != nil {
return nil, fmt.Errorf("failed to decode Multiaddress: %w", err)
}
maddrs = append(maddrs, maddr)
}
return maddrs, nil
}
// Domain is the "signature domain" used when signing and verifying a particular
// Record type. The Domain string should be unique to your Record type, and all
// instances of the Record type must have the same Domain string.
func (loc Location) Domain() string {
return EnvelopeDomain
}
// Codec is a binary identifier for this type of record, ideally a registered multicodec
// (see https://github.com/multiformats/multicodec).
// When a Record is put into an Envelope (see record.Seal), the Codec value will be used
// as the Envelope's PayloadType. When the Envelope is later unsealed, the PayloadType
// will be used to lookup the correct Record type to unmarshal the Envelope payload into.
func (loc Location) Codec() []byte {
return EnvelopePayloadType
}
// MarshalRecord converts a Record instance to a []byte, so that it can be used as an
// Envelope payload.
func (loc Location) MarshalRecord() ([]byte, error) {
return loc.Message().MarshalPacked()
}
// UnmarshalRecord unmarshals a []byte payload into an instance of a particular Record type.
func (loc *Location) UnmarshalRecord(b []byte) error {
m, err := capnp.UnmarshalPacked(b)
if err != nil {
return err
}
capLoc, err := api.ReadRootLocation(m)
if err != nil {
return err
}
loc.Location = capLoc
return nil
}