This repository has been archived by the owner on Mar 5, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathevents.go
154 lines (123 loc) · 4.24 KB
/
events.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
package dshardorchestrator
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/pkg/errors"
"github.com/vmihailenco/msgpack"
"reflect"
)
// The internal event IDs are hardcoded to preserve compatibility between versions
type EventType uint32
const (
// sent from nodes when they connect to establish a session
EvtIdentify EventType = 1
// sent by the orchestrator in response to identify to complete the session establishment
EvtIdentified EventType = 2
EvtStartShard EventType = 3
EvtStopShard EventType = 4
EvtShutdown EventType = 5
EvtPrepareShardmigration EventType = 6
EvtStartShardMigration EventType = 7
EvtShardMigrationDataProcessed EventType = 8
EvtAllUserdataSent EventType = 9
// This isn't an event per se, but this marks where user id's start
// events with higher ID than this are registered and fully handled by implementations of the node interface
// and will not be decoded or touched by the orchestrator.
//
// This can be used to transfer any kind of data during shard migration from the old node to the new node
// to do that you could register a new event for "Guild" states, and send those over one by one.
EvtShardMigrationDataStartID EventType = 100
)
var EventsToStringMap = map[EventType]string{
1: "Identify",
2: "Identified",
3: "StartShard",
4: "StopShard",
5: "Shutdown",
6: "PrepareShardmigration",
7: "StartShardMigration",
8: "ShardMigrationDataProcessed",
9: "AllUserdataSent",
}
func (evt EventType) String() string {
if s, ok := EventsToStringMap[evt]; ok {
return s
}
return "Unknown"
}
// Mapping of events to structs for their data
var EvtDataMap = map[EventType]interface{}{
EvtIdentify: IdentifyData{},
EvtIdentified: IdentifiedData{},
EvtStartShard: StartShardData{},
EvtStopShard: StopShardData{},
EvtPrepareShardmigration: PrepareShardmigrationData{},
EvtStartShardMigration: StartshardMigrationData{},
EvtAllUserdataSent: AllUserDataSentData{},
}
// RegisterUserEvent registers a new user event to be used in shard migration for example
// calling this after opening a connection or otherwise concurrently will cause race conditions
// the reccomended way would be to call this in init()
//
// panics if id is less than 100, as that's reserved id's for inernal use
func RegisterUserEvent(name string, id EventType, dataType interface{}) {
if id < EvtShardMigrationDataStartID {
panic(errors.New("tried registering user event with event type less than 100"))
}
EvtDataMap[id] = dataType
EventsToStringMap[id] = "UserEvt:" + name
}
type Message struct {
EvtID EventType
// only 1 of RawBody or DecodeBody is present, not both
RawBody []byte
DecodedBody interface{}
}
// EncodeMessage is the same as EncodeMessageRaw but also encodes the data passed using msgpack
func EncodeMessage(evtID EventType, data interface{}) ([]byte, error) {
if data == nil {
return EncodeMessageRaw(evtID, nil), nil
}
if c, ok := data.([]byte); ok {
return EncodeMessageRaw(evtID, c), nil
}
serialized, err := msgpack.Marshal(data)
if err != nil {
return nil, errors.WithMessage(err, "msgpack.Marshal")
}
return EncodeMessageRaw(evtID, serialized), nil
}
// EncodeMessageRaw encodes the event to the wire format
// The wire format is pretty basic, first 4 bytes is a uin32 representing what type of event this is
// next 4 bytes is another uin32 which represents the length of the body
// next n bytes is the body itself, which can even be empty in some cases
func EncodeMessageRaw(evtID EventType, data []byte) []byte {
var buf bytes.Buffer
tmpBuf := make([]byte, 4)
binary.LittleEndian.PutUint32(tmpBuf, uint32(evtID))
buf.Write(tmpBuf)
l := uint32(len(data))
binary.LittleEndian.PutUint32(tmpBuf, l)
buf.Write(tmpBuf)
buf.Write(data)
return buf.Bytes()
}
type UnknownEventError struct {
Evt EventType
}
func (uee *UnknownEventError) Error() string {
return fmt.Sprintf("Unknown event: %d", uee.Evt)
}
func DecodePayload(evtID EventType, payload []byte) (interface{}, error) {
t, ok := EvtDataMap[evtID]
if !ok {
return nil, &UnknownEventError{Evt: evtID}
}
if t == nil {
return nil, nil
}
clone := reflect.New(reflect.TypeOf(t)).Interface()
err := msgpack.Unmarshal(payload, clone)
return clone, err
}