-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
state_hello.go
71 lines (60 loc) · 2 KB
/
state_hello.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
package gateway
import (
"errors"
"fmt"
"github.com/discordpkg/gateway/encoding"
"io"
"time"
"github.com/discordpkg/gateway/event"
"github.com/discordpkg/gateway/event/opcode"
)
type Hello struct {
HeartbeatIntervalMilli int64 `json:"heartbeat_interval"`
}
// HelloState is one of several initial state for the client. It's responsibility are as follows
// 1. Process incoming Hello event
// 2. Initiate a heartbeat process
// 3. Send Identify message
// 4. Transition to the ReadyState
//
// This state is responsible for handling the Hello phase of the gateway connection. See the Discord documentation
// for more information:
// - https://discord.com/developers/docs/topics/gateway#connecting
// - https://discord.com/developers/docs/topics/gateway#hello-event
// - https://discord.com/developers/docs/topics/gateway#sending-heartbeats
// - https://discord.com/developers/docs/topics/gateway#identifying
type HelloState struct {
ctx *StateCtx
Identity *Identify
}
func (st *HelloState) String() string {
return "hello"
}
func (st *HelloState) Process(payload *Payload, pipe io.Writer) error {
if payload.Op != opcode.Hello {
st.ctx.SetState(&ClosedState{})
return errors.New(fmt.Sprintf("incorrect opcode: %d", int(payload.Op)))
}
var hello Hello
if err := encoding.Unmarshal(payload.Data, &hello); err != nil {
st.ctx.SetState(&ClosedState{})
return err
}
st.ctx.logger.Debug("starting heartbeat process")
var handler HeartbeatHandler
handler, st.ctx.client.heartbeatHandler = st.ctx.client.heartbeatHandler, nil
handler.Configure(st.ctx, time.Duration(hello.HeartbeatIntervalMilli)*time.Millisecond)
st.ctx.heartbeatACK.Store(true)
go handler.Run()
data, err := encoding.Marshal(st.Identity)
if err != nil {
st.ctx.SetState(&ClosedState{})
return fmt.Errorf("unable to marshal identify payload. %w", err)
}
if err = st.ctx.Write(pipe, event.Identify, data); err != nil {
st.ctx.SetState(&ClosedState{})
return err
}
st.ctx.SetState(&ReadyState{ctx: st.ctx})
return nil
}