Skip to content

Commit 03570b2

Browse files
committed
feat: add VoE api downtime
1 parent 504ea6d commit 03570b2

File tree

1 file changed

+49
-68
lines changed

1 file changed

+49
-68
lines changed

web/notifications.go

Lines changed: 49 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package web
33
import (
44
"encoding/json"
55
"errors"
6+
"fmt"
67
"net/http"
78
"slices"
89
"time"
@@ -11,15 +12,8 @@ import (
1112
"golang.org/x/sync/errgroup"
1213
)
1314

14-
type apiResult[T any] struct {
15-
Value T
16-
Error error
17-
}
18-
1915
type gw2StatusRoute struct {
2016
Path string `json:"path"`
21-
Lang string `json:"lang"`
22-
Auth string `json:"auth"`
2317
Active bool `json:"active"`
2418
}
2519

@@ -69,7 +63,8 @@ type notification struct {
6963
}
7064

7165
func NotificationsEndpoint(httpClient *http.Client) echo.HandlerFunc {
72-
apiDowntimeEnd := time.Unix(1731366000, 0)
66+
apiDowntimeStart := time.Unix(1761325200, 0)
67+
apiDowntimeEnd := time.Unix(1761843600, 0)
7368
relevantEndpoints := []string{
7469
"/v2/tokeninfo",
7570
"/v2/account",
@@ -80,125 +75,111 @@ func NotificationsEndpoint(httpClient *http.Client) echo.HandlerFunc {
8075

8176
return func(c echo.Context) error {
8277
ctx := c.Request().Context()
83-
g, ctx := errgroup.WithContext(ctx)
78+
g, gCtx := errgroup.WithContext(ctx)
8479

85-
gw2Chan := make(chan apiResult[[]string], 1)
86-
gw2EffChan := make(chan apiResult[[]string], 1)
80+
var disabledEndpoints []string
81+
var endpointsWithIssues []string
8782

8883
g.Go(func() error {
89-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.guildwars2.com/v2.json", nil)
84+
req, err := http.NewRequestWithContext(gCtx, http.MethodGet, "https://api.guildwars2.com/v2.json", nil)
9085
if err != nil {
91-
gw2Chan <- apiResult[[]string]{Error: err}
92-
return err
86+
return echo.NewHTTPError(http.StatusInternalServerError)
9387
}
9488

9589
req.Header.Set("User-Agent", "GW2Auth")
9690

9791
res, err := httpClient.Do(req)
98-
if err != nil || res.StatusCode != http.StatusOK {
99-
gw2Chan <- apiResult[[]string]{Error: err}
100-
return nil
92+
if err != nil {
93+
return echo.NewHTTPError(http.StatusBadGateway, err)
94+
}
95+
96+
defer res.Body.Close()
97+
98+
if res.StatusCode != http.StatusOK {
99+
return echo.NewHTTPError(http.StatusBadGateway, fmt.Errorf("unexpected status code: %d", res.StatusCode))
101100
}
102101

103102
var gw2Status gw2StatusResponse
104103
if err = json.NewDecoder(res.Body).Decode(&gw2Status); err != nil {
105-
gw2Chan <- apiResult[[]string]{Error: err}
106-
return nil
104+
return echo.NewHTTPError(http.StatusBadGateway, err)
107105
}
108106

109-
var disabledEndpoints []string
110107
for _, element := range gw2Status.Routes {
111108
if slices.Contains(relevantEndpoints, element.Path) && !element.Active {
112109
disabledEndpoints = append(disabledEndpoints, element.Path)
113110
}
114111
}
115112

116-
gw2Chan <- apiResult[[]string]{Value: disabledEndpoints}
117-
118-
defer res.Body.Close()
119113
return nil
120114
})
121115

122116
g.Go(func() error {
123-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://status.gw2efficiency.com/api", nil)
117+
req, err := http.NewRequestWithContext(gCtx, http.MethodGet, "https://status.gw2efficiency.com/api", nil)
124118
if err != nil {
125-
return err
119+
return echo.NewHTTPError(http.StatusInternalServerError)
126120
}
127121

128122
req.Header.Set("User-Agent", "GW2Auth")
129123

130124
res, err := httpClient.Do(req)
131125
if err != nil {
132-
gw2Chan <- apiResult[[]string]{Error: err}
133-
return nil
126+
return echo.NewHTTPError(http.StatusBadGateway, err)
134127
}
135128

129+
defer res.Body.Close()
130+
136131
if res.StatusCode != http.StatusOK {
137-
gw2Chan <- apiResult[[]string]{Error: errors.New(res.Status)}
138-
return nil
132+
return echo.NewHTTPError(http.StatusBadGateway, fmt.Errorf("unexpected status code: %d", res.StatusCode))
139133
}
140134

141135
var gw2EffStatus gw2EffApiStatusResponse
142136
if err = json.NewDecoder(res.Body).Decode(&gw2EffStatus); err != nil {
143137
return echo.NewHTTPError(http.StatusBadGateway, err)
144138
}
145139

146-
var endpointsWithIssues []string
147140
for _, element := range gw2EffStatus.Data {
148141
if slices.Contains(relevantEndpoints, element.Name) && (element.Status != http.StatusOK || element.CheckError() || element.Duration >= 15_000) {
149142
endpointsWithIssues = append(endpointsWithIssues, element.Name)
150143
}
151144
}
152145

153-
defer res.Body.Close()
154146
return nil
155147
})
156148

157-
var notifications []notification
158-
159-
gw2Result := <-gw2Chan
160-
161-
if gw2Result.Error == nil {
162-
disabledEndpoints := gw2Result.Value
163-
164-
if len(disabledEndpoints) > 0 {
165-
notifications = []notification{
166-
{
167-
Type: notificationTypeError,
168-
Header: "The Guild Wars 2 API is unavailable",
169-
Content: "Some of the endpoints used by GW2Auth are currently disabled. This might impact your experience with GW2Auth and Applications using GW2Auth.",
170-
},
171-
}
149+
if err := g.Wait(); err != nil {
150+
var httpErr *echo.HTTPError
151+
if errors.As(err, &httpErr) {
152+
return httpErr
172153
} else {
173-
notifications = make([]notification, 0)
154+
return echo.NewHTTPError(http.StatusInternalServerError)
174155
}
175-
} else {
176-
gw2EffResult := <-gw2EffChan
156+
}
177157

178-
if gw2EffResult.Error == nil {
179-
return echo.NewHTTPError(http.StatusBadGateway, gw2EffResult.Error)
180-
}
158+
notifications := make([]notification, 0)
181159

182-
endpointsWithIssues := gw2EffResult.Value
183-
if len(endpointsWithIssues) > 0 {
184-
notifications = []notification{
185-
{
186-
Type: notificationTypeWarning,
187-
Header: "The Guild Wars 2 API experiences issues right now",
188-
Content: "Some of the endpoints used by GW2Auth appear to be in a degraded state right now. This might impact your experience with GW2Auth and Applications using GW2Auth.",
189-
},
190-
}
191-
} else {
192-
notifications = make([]notification, 0)
193-
}
160+
if len(disabledEndpoints) > 0 {
161+
notifications = append(notifications, notification{
162+
Type: notificationTypeError,
163+
Header: "The Guild Wars 2 API is unavailable",
164+
Content: "Some of the endpoints used by GW2Auth are currently disabled. This might impact your experience with GW2Auth and Applications using GW2Auth.",
165+
})
166+
} else if len(endpointsWithIssues) > 0 {
167+
notifications = append(notifications, notification{
168+
Type: notificationTypeWarning,
169+
Header: "The Guild Wars 2 API experiences issues right now",
170+
Content: "Some of the endpoints used by GW2Auth appear to be in a degraded state right now. This might impact your experience with GW2Auth and Applications using GW2Auth.",
171+
})
194172
}
195173

196174
now := time.Now()
197-
if now.Before(apiDowntimeEnd) {
175+
if now.After(apiDowntimeStart) && now.Before(apiDowntimeEnd) {
198176
notifications = append(notifications, notification{
199-
Type: notificationTypeWarning,
200-
Header: "Issues with the Guild Wars 2 API",
201-
Content: "Please be aware of issues with the official Guild Wars 2 API. Applications using GW2Auth might not work properly. GW2Auth itself is not affected.\nSee: [Issues with the Guild Wars 2 API](https://en-forum.guildwars2.com/topic/153373-issues-with-the-guild-wars-2-api/)",
177+
Type: notificationTypeError,
178+
Header: "VoE Release - Guild Wars 2 API Disabled",
179+
Content: fmt.Sprintf(
180+
"The Guild Wars 2 API will be disabled until %s to prevent spoilers of Visions of Eternity. While the API is disabled, you will not be able to add or update API Tokens or verify accounts.\nSee: [Guild Wars 2 API Disabled from October 24–30](https://en-forum.guildwars2.com/topic/163562-guild-wars-2-api-disabled-from-october-24%%E2%%80%%9330/)",
181+
apiDowntimeEnd.Format(time.RFC3339),
182+
),
202183
})
203184
}
204185

0 commit comments

Comments
 (0)