From 24f175df385466e04ef21d153713d2ecf3a9733b Mon Sep 17 00:00:00 2001 From: Mel Date: Fri, 8 Apr 2022 12:54:09 +0200 Subject: Subdivide discord into packages --- pkg/discord/gateway.go | 201 ------------------------------------------------- 1 file changed, 201 deletions(-) delete mode 100644 pkg/discord/gateway.go (limited to 'pkg/discord/gateway.go') diff --git a/pkg/discord/gateway.go b/pkg/discord/gateway.go deleted file mode 100644 index 32a1e99..0000000 --- a/pkg/discord/gateway.go +++ /dev/null @@ -1,201 +0,0 @@ -package discord - -import ( - "context" - "encoding/json" - "fmt" - "jinx/pkg/libs/cancellablewebsocket" - "net/http" - - "github.com/gorilla/websocket" - "github.com/rs/zerolog" -) - -type Gateway interface { - Start(ctx context.Context, url string, token string) error - Close() error - - Heartbeat() error -} - -var _ Gateway = &GatewayImpl{} - -type GatewayImpl struct { - ctx context.Context - logger *zerolog.Logger - conn *cancellablewebsocket.CancellableWebSocket - heartbeat Heartbeat - eventHandler EventHandler - lastSeq uint64 -} - -func NewGateway(logger *zerolog.Logger, eventHandler EventHandler) *GatewayImpl { - gateway := &GatewayImpl{ - ctx: nil, - logger: logger, - conn: nil, - eventHandler: eventHandler, - heartbeat: nil, - lastSeq: 0, - } - - // Cycle dependency, is this the best way to do this? - heartbeat := NewHeartbeat(logger, gateway) - gateway.heartbeat = heartbeat - - return gateway -} - -func (g *GatewayImpl) Start(ctx context.Context, url string, token string) error { - connectHeader := http.Header{} - conn, err := cancellablewebsocket.Dial(websocket.DefaultDialer, ctx, url, connectHeader) - if err != nil { - return err - } - - g.conn = conn - g.ctx = ctx - - hello, err := g.hello() - if err != nil { - return err - } - - g.heartbeat.Start(ctx, hello.HeartbeatInterval) - - if err = g.identify(token); err != nil { - return err - } - - go g.listen() - - return nil -} - -func (g *GatewayImpl) Close() error { - return g.conn.Close() -} - -func (g *GatewayImpl) Heartbeat() error { - msg := GatewayPayload[uint64]{ - Op: GATEWAY_OP_HEARTBEAT, - Data: g.lastSeq, - } - - return g.send(msg) -} - -func (g *GatewayImpl) hello() (GatewayHelloEvent, error) { - var msg GatewayPayload[GatewayHelloEvent] - if err := receive(g, &msg); err != nil { - return GatewayHelloEvent{}, err - } - - if msg.Op != GATEWAY_OP_HELLO { - return GatewayHelloEvent{}, fmt.Errorf("expected opcode %d, got %d", GATEWAY_OP_HELLO, msg.Op) - } - - return msg.Data, nil -} - -func (g *GatewayImpl) identify(token string) error { - msg := GatewayPayload[GatewayIdentifyMsg]{ - Op: GATEWAY_OP_IDENTIFY, - Data: GatewayIdentifyMsg{ - Token: token, - Intents: 13991, - Properties: GatewayIdentifyProperties{ - OS: "linux", - Browser: "jinx", - Device: "jinx", - }, - }, - Sequence: 0, - } - - if err := g.send(msg); err != nil { - return err - } - - var res GatewayPayload[GatewayReadyEvent] - if err := receive(g, &res); err != nil { - return err - } - - g.logger.Debug().Msgf("identify response payload: %+v", res) - - if res.Op != GATEWAY_OP_DISPATCH { - return fmt.Errorf("expected opcode %d, got %d", GATEWAY_OP_DISPATCH, res.Op) - } - - if res.EventName != "READY" { - return fmt.Errorf("expected event name %s, got %s", "READY", res.EventName) - } - - return nil -} - -func (g *GatewayImpl) listen() { - for { - var msg GatewayPayload[json.RawMessage] - if err := receive(g, &msg); err != nil { - g.logger.Error().Err(err).Msgf("error reading message") - continue - } - - select { - case <-g.ctx.Done(): - return - default: - g.onEvent(msg) - } - } -} - -func (g *GatewayImpl) onEvent(msg GatewayPayload[json.RawMessage]) error { - switch msg.Op { - case GATEWAY_OP_HEARTBEAT_ACK: - g.heartbeat.Ack() - case GATEWAY_OP_HEARTBEAT: - g.heartbeat.ForceHeartbeat() - case GATEWAY_OP_DISPATCH: - return g.onDispatch(msg.EventName, msg.Data) - default: - g.logger.Warn().Msgf("received unknown opcode: %d", msg.Op) - } - - return nil -} - -func (g *GatewayImpl) onDispatch(eventName string, body json.RawMessage) error { - switch eventName { - case "MESSAGE_CREATE": - var payload GatewayMessageCreateEvent - if err := json.Unmarshal(body, &payload); err != nil { - return err - } - - g.eventHandler.Fire(DISCORD_EVENT_MESSAGE, payload) - default: - g.logger.Warn().Msgf("received unknown event: %s", eventName) - } - - return nil -} - -func (g *GatewayImpl) send(payload any) error { - return g.conn.WriteJSON(payload) -} - -func receive[D any](g *GatewayImpl, res *GatewayPayload[D]) error { - err := g.conn.ReadJSON(&res) - if err != nil { - return err - } - - if res.Sequence != 0 { - g.lastSeq = res.Sequence - } - - return nil -} -- cgit 1.4.1