From a3fa9450e17906a95c7141ca3a7fc1d8f98ee67d Mon Sep 17 00:00:00 2001 From: Marc Szanto <11840265+Xemdo@users.noreply.github.com> Date: Tue, 11 Apr 2023 13:24:46 -0700 Subject: [PATCH 1/3] Changed response to /eventsub/subscriptions; Fixes #226 --- .../events/websocket/mock_server/manager.go | 28 ++++++++++--------- .../websocket/mock_server/subscription.go | 2 +- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/internal/events/websocket/mock_server/manager.go b/internal/events/websocket/mock_server/manager.go index c436bed2..44c9ef9a 100644 --- a/internal/events/websocket/mock_server/manager.go +++ b/internal/events/websocket/mock_server/manager.go @@ -397,19 +397,21 @@ func subscriptionPageHandlerPost(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusAccepted) json.NewEncoder(w).Encode(&SubscriptionPostSuccessResponse{ - Body: SubscriptionPostSuccessResponseBody{ - ID: subscription.SubscriptionID, - Status: subscription.Status, - Type: subscription.Type, - Version: subscription.Version, - Condition: EmptyStruct{}, - CreatedAt: subscription.CreatedAt, - Transport: SubscriptionTransport{ - Method: "websocket", - SessionID: fmt.Sprintf("%v_%v", server.ServerId, clientName), - ConnectedAt: client.ConnectedAtTimestamp, + Data: []SubscriptionPostSuccessResponseBody{ + { + ID: subscription.SubscriptionID, + Status: subscription.Status, + Type: subscription.Type, + Version: subscription.Version, + Condition: EmptyStruct{}, + CreatedAt: subscription.CreatedAt, + Transport: SubscriptionTransport{ + Method: "websocket", + SessionID: fmt.Sprintf("%v_%v", server.ServerId, clientName), + ConnectedAt: client.ConnectedAtTimestamp, + }, + Cost: 0, }, - Cost: 0, }, Total: 0, MaxTotalCost: 10, @@ -519,7 +521,7 @@ func handlerResponseErrorUnauthorized(w http.ResponseWriter, message string) { func handlerResponseErrorConflict(w http.ResponseWriter, message string) { w.WriteHeader(http.StatusConflict) bytes, _ := json.Marshal(&SubscriptionPostErrorResponse{ - Error: "Unauthorized", + Error: "Conflict", Message: message, Status: 409, }) diff --git a/internal/events/websocket/mock_server/subscription.go b/internal/events/websocket/mock_server/subscription.go index 39e98f11..283ffd6c 100644 --- a/internal/events/websocket/mock_server/subscription.go +++ b/internal/events/websocket/mock_server/subscription.go @@ -27,7 +27,7 @@ type SubscriptionPostRequestTransport struct { // Response (Success) - POST /eventsub/subscriptions type SubscriptionPostSuccessResponse struct { - Body SubscriptionPostSuccessResponseBody `json:"body"` + Data []SubscriptionPostSuccessResponseBody `json:"data"` Total int `json:"total"` MaxTotalCost int `json:"max_total_cost"` From 4a59142351578a0f5e268bdb6bf263ec7d2dacbd Mon Sep 17 00:00:00 2001 From: Marc Szanto <11840265+Xemdo@users.noreply.github.com> Date: Tue, 11 Apr 2023 14:04:25 -0700 Subject: [PATCH 2/3] Added condition to /eventsub/subscriptions addressing #227 --- .../websocket/mock_server/close_messages.go | 5 ++++ .../events/websocket/mock_server/manager.go | 23 ++++++++++--------- .../events/websocket/mock_server/server.go | 10 ++++---- .../websocket/mock_server/subscription.go | 18 ++++++++++----- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/internal/events/websocket/mock_server/close_messages.go b/internal/events/websocket/mock_server/close_messages.go index 3867595e..27a81507 100644 --- a/internal/events/websocket/mock_server/close_messages.go +++ b/internal/events/websocket/mock_server/close_messages.go @@ -6,6 +6,11 @@ type CloseMessage struct { } var ( + closeClientDisconnected = &CloseMessage{ + code: 1000, + message: "client disconnected", + } + closeInternalServerError = &CloseMessage{ code: 4000, message: "internal server error", diff --git a/internal/events/websocket/mock_server/manager.go b/internal/events/websocket/mock_server/manager.go index 44c9ef9a..89241610 100644 --- a/internal/events/websocket/mock_server/manager.go +++ b/internal/events/websocket/mock_server/manager.go @@ -24,15 +24,15 @@ import ( type ServerManager struct { serverList *util.List[WebSocketServer] - reconnectTesting bool - primaryServer string - ip string - port int - debugEnabled bool - strictMode bool - sslEnabled bool - protocolHttp string - protocolWs string + reconnectTesting bool // Indicates if the server is in the process of running a simulation server reconnect/restart + primaryServer string // The current primary server by its ID. This should be in serverList + ip string // IP the server will bind to + port int // Port the server will bind to + debugEnabled bool // Indicates if the server was started with --debug + strictMode bool // Indicates if the server was started with --require-subscriptions + sslEnabled bool // Indicates if the server was started with --ssl + protocolHttp string // String for the HTTP protocol URIs (http or https) + protocolWs string // String for the WS protocol URIs (ws or wss) } var serverManager *ServerManager @@ -269,7 +269,7 @@ func subscriptionPageHandlerGet(w http.ResponseWriter, r *http.Request) { Status: subscription.Status, Type: subscription.Type, Version: subscription.Version, - Condition: EmptyStruct{}, + Condition: subscription.Conditions, CreatedAt: subscription.CreatedAt, Transport: SubscriptionTransport{ Method: "websocket", @@ -378,6 +378,7 @@ func subscriptionPageHandlerPost(w http.ResponseWriter, r *http.Request) { CreatedAt: time.Now().UTC().Format(time.RFC3339Nano), Status: STATUS_ENABLED, // https://dev.twitch.tv/docs/api/reference/#get-eventsub-subscriptions SessionClientName: clientName, + Conditions: body.Condition, } var subs []Subscription @@ -403,7 +404,7 @@ func subscriptionPageHandlerPost(w http.ResponseWriter, r *http.Request) { Status: subscription.Status, Type: subscription.Type, Version: subscription.Version, - Condition: EmptyStruct{}, + Condition: subscription.Conditions, CreatedAt: subscription.CreatedAt, Transport: SubscriptionTransport{ Method: "websocket", diff --git a/internal/events/websocket/mock_server/server.go b/internal/events/websocket/mock_server/server.go index 7e5ac2b5..17367d5d 100644 --- a/internal/events/websocket/mock_server/server.go +++ b/internal/events/websocket/mock_server/server.go @@ -223,8 +223,8 @@ func (ws *WebSocketServer) WsPageHandler(w http.ResponseWriter, r *http.Request) log.Printf("read err [%v]: %v", client.clientName, err) ws.muClients.Lock() - client.CloseWithReason(closeNetworkError) - ws.handleClientConnectionClose(client, closeNetworkError) + client.CloseWithReason(closeClientDisconnected) + ws.handleClientConnectionClose(client, closeClientDisconnected) ws.muClients.Unlock() break } @@ -488,9 +488,9 @@ func (ws *WebSocketServer) handleClientConnectionClose(client *Client, closeReas if ws.Status == 2 { ws.muSubscriptions.Lock() subscriptions := ws.Subscriptions[client.clientName] - for _, subscription := range subscriptions { - if subscription.Status == STATUS_ENABLED { - subscription.Status = getStatusFromCloseMessage(closeReason) + for i := range subscriptions { + if subscriptions[i].Status == STATUS_ENABLED { + subscriptions[i].Status = getStatusFromCloseMessage(closeReason) } } ws.Subscriptions[client.clientName] = subscriptions diff --git a/internal/events/websocket/mock_server/subscription.go b/internal/events/websocket/mock_server/subscription.go index 283ffd6c..11840dbf 100644 --- a/internal/events/websocket/mock_server/subscription.go +++ b/internal/events/websocket/mock_server/subscription.go @@ -1,5 +1,7 @@ package mock_server +import "github.com/twitchdev/twitch-cli/internal/models" + type Subscription struct { SubscriptionID string // Random GUID for the subscription ClientID string // Client ID included in headers @@ -8,14 +10,16 @@ type Subscription struct { CreatedAt string // Timestamp of when the subscription was created Status string // Status of the subscription SessionClientName string // Client name of the session this is associated with. + + Conditions models.EventsubCondition // Values of the subscription's condition object } // Request - POST /eventsub/subscriptions type SubscriptionPostRequest struct { - Type string `json:"type"` - Version string `json:"version"` - Condition interface{} `json:"condition"` + Type string `json:"type"` + Version string `json:"version"` + Condition models.EventsubCondition `json:"condition"` Transport SubscriptionPostRequestTransport `json:"transport"` } @@ -44,8 +48,8 @@ type SubscriptionPostSuccessResponseBody struct { CreatedAt string `json:"created_at"` Cost int `json:"cost"` - Condition EmptyStruct `json:"condition"` - Transport SubscriptionTransport `json:"transport"` + Condition models.EventsubCondition `json:"condition"` + Transport SubscriptionTransport `json:"transport"` } // Response (Error) - POST /eventsub/subscriptions @@ -69,7 +73,7 @@ type SubscriptionGetSuccessResponse struct { type SubscriptionTransport struct { Method string `json:"method"` SessionID string `json:"session_id"` - ConnectedAt string `json:"connected_at"` + ConnectedAt string `json:"connected_at,omitempty"` } // Cross-usage @@ -112,6 +116,8 @@ func getStatusFromCloseMessage(reason *CloseMessage) string { code := reason.code switch code { + case 1000: + return STATUS_WEBSOCKET_DISCONNECTED case 4000: return STATUS_INTERNAL_ERROR case 4001: From 403aa1898820662e8f25ac2b3e106ca342a21f1c Mon Sep 17 00:00:00 2001 From: Marc Szanto <11840265+Xemdo@users.noreply.github.com> Date: Tue, 11 Apr 2023 14:18:17 -0700 Subject: [PATCH 3/3] Corrected missing connected_at and disconnected_at timestamps on /eventsub/subscriptions --- internal/events/websocket/mock_server/manager.go | 7 +++++-- internal/events/websocket/mock_server/server.go | 2 ++ internal/events/websocket/mock_server/subscription.go | 10 +++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/internal/events/websocket/mock_server/manager.go b/internal/events/websocket/mock_server/manager.go index 89241610..768633ee 100644 --- a/internal/events/websocket/mock_server/manager.go +++ b/internal/events/websocket/mock_server/manager.go @@ -272,8 +272,10 @@ func subscriptionPageHandlerGet(w http.ResponseWriter, r *http.Request) { Condition: subscription.Conditions, CreatedAt: subscription.CreatedAt, Transport: SubscriptionTransport{ - Method: "websocket", - SessionID: fmt.Sprintf("%v_%v", server.ServerId, clientName), + Method: "websocket", + SessionID: fmt.Sprintf("%v_%v", server.ServerId, clientName), + ConnectedAt: subscription.ClientConnectedAt, + DisconnectedAt: subscription.ClientDisconnectedAt, }, Cost: 0, }) @@ -379,6 +381,7 @@ func subscriptionPageHandlerPost(w http.ResponseWriter, r *http.Request) { Status: STATUS_ENABLED, // https://dev.twitch.tv/docs/api/reference/#get-eventsub-subscriptions SessionClientName: clientName, Conditions: body.Condition, + ClientConnectedAt: client.ConnectedAtTimestamp, } var subs []Subscription diff --git a/internal/events/websocket/mock_server/server.go b/internal/events/websocket/mock_server/server.go index 17367d5d..4b4a5595 100644 --- a/internal/events/websocket/mock_server/server.go +++ b/internal/events/websocket/mock_server/server.go @@ -491,6 +491,8 @@ func (ws *WebSocketServer) handleClientConnectionClose(client *Client, closeReas for i := range subscriptions { if subscriptions[i].Status == STATUS_ENABLED { subscriptions[i].Status = getStatusFromCloseMessage(closeReason) + subscriptions[i].ClientConnectedAt = "" + subscriptions[i].ClientDisconnectedAt = time.Now().UTC().Format(time.RFC3339Nano) } } ws.Subscriptions[client.clientName] = subscriptions diff --git a/internal/events/websocket/mock_server/subscription.go b/internal/events/websocket/mock_server/subscription.go index 11840dbf..d78177cf 100644 --- a/internal/events/websocket/mock_server/subscription.go +++ b/internal/events/websocket/mock_server/subscription.go @@ -11,6 +11,9 @@ type Subscription struct { Status string // Status of the subscription SessionClientName string // Client name of the session this is associated with. + ClientConnectedAt string // Time client connected + ClientDisconnectedAt string // Time client disconnected + Conditions models.EventsubCondition // Values of the subscription's condition object } @@ -71,9 +74,10 @@ type SubscriptionGetSuccessResponse struct { // Cross-usage type SubscriptionTransport struct { - Method string `json:"method"` - SessionID string `json:"session_id"` - ConnectedAt string `json:"connected_at,omitempty"` + Method string `json:"method"` + SessionID string `json:"session_id"` + ConnectedAt string `json:"connected_at,omitempty"` + DisconnectedAt string `json:"disconnected_at,omitempty"` } // Cross-usage