forked from hyperledger-labs/go-perun
-
Notifications
You must be signed in to change notification settings - Fork 2
/
msg.go
174 lines (154 loc) · 5.3 KB
/
msg.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Copyright 2019 - See NOTICE file for copyright holders.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package wire
import (
"fmt"
"io"
"strconv"
"github.com/pkg/errors"
perunio "perun.network/go-perun/pkg/io"
)
type (
// Msg is the top-level abstraction for all messages sent between Perun
// nodes.
Msg interface {
// Type returns the message's type.
Type() Type
// encoding of payload. Type byte should not be encoded.
perunio.Encoder
}
// An Envelope encapsulates a message with routing information, that is, the
// sender and intended recipient.
Envelope struct {
Sender Address // Sender of the message.
Recipient Address // Recipient of the message.
// Msg contained in this Envelope. Not embedded so Envelope doesn't implement Msg.
Msg Msg
}
)
// Encode encodes an Envelope into an io.Writer.
func (env *Envelope) Encode(w io.Writer) error {
if err := perunio.Encode(w, env.Sender, env.Recipient); err != nil {
return err
}
return Encode(env.Msg, w)
}
// Decode decodes an Envelope from an io.Reader.
func (env *Envelope) Decode(r io.Reader) (err error) {
if env.Sender, err = DecodeAddress(r); err != nil {
return err
}
if env.Recipient, err = DecodeAddress(r); err != nil {
return err
}
env.Msg, err = Decode(r)
return err
}
// Encode encodes a message into an io.Writer. It also encodes the
// message type whereas the Msg.Encode implementation is assumed not to write
// the type.
func Encode(msg Msg, w io.Writer) error {
// Encode the message type and payload
return perunio.Encode(w, byte(msg.Type()), msg)
}
// Decode decodes a message from an io.Reader.
func Decode(r io.Reader) (Msg, error) {
var t Type
if err := perunio.Decode(r, (*byte)(&t)); err != nil {
return nil, errors.WithMessage(err, "failed to decode message Type")
}
if !t.Valid() {
return nil, errors.Errorf("wire: no decoder known for message Type): %v", t)
}
return decoders[t](r)
}
var decoders = make(map[Type]func(io.Reader) (Msg, error))
// RegisterDecoder sets the decoder of messages of Type `t`.
func RegisterDecoder(t Type, decoder func(io.Reader) (Msg, error)) {
if decoders[t] != nil {
panic(fmt.Sprintf("wire: decoder for Type %v already set", t))
}
decoders[t] = decoder
}
// RegisterExternalDecoder sets the decoder of messages of external type `t`.
// This is like RegisterDecoder but for message types not part of the Perun wire
// protocol and thus not known natively. This can be used by users of the
// framework to create additional message types and send them over the same
// peer connection. It also comes in handy to register types for testing.
func RegisterExternalDecoder(t Type, decoder func(io.Reader) (Msg, error), name string) {
if t < LastType {
panic("external decoders can only be registered for alien types")
}
RegisterDecoder(t, decoder)
// above registration panics if already set, so we don't need to check the
// next assignment.
typeNames[t] = name
}
// Type is an enumeration used for (de)serializing messages and
// identifying a message's Type.
type Type uint8
// Enumeration of message categories known to the Perun framework.
const (
Ping Type = iota
Pong
Shutdown
AuthResponse
LedgerChannelProposal
LedgerChannelProposalAcc
SubChannelProposal
SubChannelProposalAcc
VirtualChannelProposal
VirtualChannelProposalAcc
ChannelProposalRej
ChannelUpdate
VirtualChannelFundingProposal
VirtualChannelSettlementProposal
ChannelUpdateAcc
ChannelUpdateRej
ChannelSync
LastType // upper bound on the message types of the Perun wire protocol
)
var typeNames = map[Type]string{
Ping: "Ping",
Pong: "Pong",
Shutdown: "Shutdown",
AuthResponse: "AuthResponse",
LedgerChannelProposal: "LedgerChannelProposal",
LedgerChannelProposalAcc: "LedgerChannelProposalAcc",
SubChannelProposal: "SubChannelProposal",
SubChannelProposalAcc: "SubChannelProposalAcc",
VirtualChannelProposal: "VirtualChannelProposal",
VirtualChannelProposalAcc: "VirtualChannelProposalAcc",
ChannelProposalRej: "ChannelProposalRej",
ChannelUpdate: "ChannelUpdate",
VirtualChannelFundingProposal: "VirtualChannelFundingProposal",
VirtualChannelSettlementProposal: "VirtualChannelSettlementProposal",
ChannelUpdateAcc: "ChannelUpdateAcc",
ChannelUpdateRej: "ChannelUpdateRej",
ChannelSync: "ChannelSync",
}
// String returns the name of a message type if it is valid and name known
// or otherwise its numerical representation.
func (t Type) String() string {
name, ok := typeNames[t]
if !ok {
return strconv.Itoa(int(t))
}
return name
}
// Valid checks whether a decoder is known for the type.
func (t Type) Valid() bool {
_, ok := decoders[t]
return ok
}