@@ -2,12 +2,31 @@ package web
22
33import (
44 "encoding/json"
5- "github.com/labstack/echo/v4 "
5+ "errors "
66 "net/http"
77 "slices"
88 "time"
9+
10+ "github.com/labstack/echo/v4"
11+ "golang.org/x/sync/errgroup"
912)
1013
14+ type apiResult [T any ] struct {
15+ Value T
16+ Error error
17+ }
18+
19+ type gw2StatusRoute struct {
20+ Path string `json:"path"`
21+ Lang string `json:"lang"`
22+ Auth string `json:"auth"`
23+ Active bool `json:"active"`
24+ }
25+
26+ type gw2StatusResponse struct {
27+ Routes []gw2StatusRoute `json:"routes"`
28+ }
29+
1130type gw2EffApiStatusElement struct {
1231 Name string `json:"name"`
1332 Status int `json:"status"`
@@ -61,47 +80,117 @@ func NotificationsEndpoint(httpClient *http.Client) echo.HandlerFunc {
6180
6281 return func (c echo.Context ) error {
6382 ctx := c .Request ().Context ()
64- req , err := http .NewRequestWithContext (ctx , http .MethodGet , "https://status.gw2efficiency.com/api" , nil )
65- if err != nil {
66- return echo .NewHTTPError (http .StatusInternalServerError , err )
67- }
83+ g , ctx := errgroup .WithContext (ctx )
6884
69- req .Header .Set ("User-Agent" , "GW2Auth" )
85+ gw2Chan := make (chan apiResult [[]string ], 1 )
86+ gw2EffChan := make (chan apiResult [[]string ], 1 )
7087
71- res , err := httpClient .Do (req )
72- if err != nil {
73- return echo .NewHTTPError (http .StatusBadGateway , err )
74- }
88+ g .Go (func () error {
89+ req , err := http .NewRequestWithContext (ctx , http .MethodGet , "https://api.guildwars2.com/v2.json" , nil )
90+ if err != nil {
91+ gw2Chan <- apiResult [[]string ]{Error : err }
92+ return err
93+ }
7594
76- defer res . Body . Close ( )
95+ req . Header . Set ( "User-Agent" , "GW2Auth" )
7796
78- if res .StatusCode != http .StatusOK {
79- return echo .NewHTTPError (http .StatusBadGateway , res .Status )
80- }
97+ res , err := httpClient .Do (req )
98+ if err != nil || res .StatusCode != http .StatusOK {
99+ gw2Chan <- apiResult [[]string ]{Error : err }
100+ return nil
101+ }
81102
82- var gw2EffStatus gw2EffApiStatusResponse
83- if err = json .NewDecoder (res .Body ).Decode (& gw2EffStatus ); err != nil {
84- return echo .NewHTTPError (http .StatusBadGateway , err )
85- }
103+ var gw2Status gw2StatusResponse
104+ if err = json .NewDecoder (res .Body ).Decode (& gw2Status ); err != nil {
105+ gw2Chan <- apiResult [[]string ]{Error : err }
106+ return nil
107+ }
86108
87- var endpointsWithIssues []string
88- for _ , element := range gw2EffStatus .Data {
89- if slices .Contains (relevantEndpoints , element .Name ) && (element .Status != http .StatusOK || element .CheckError () || element .Duration >= 15_000 ) {
90- endpointsWithIssues = append (endpointsWithIssues , element .Name )
109+ var disabledEndpoints []string
110+ for _ , element := range gw2Status .Routes {
111+ if slices .Contains (relevantEndpoints , element .Path ) && ! element .Active {
112+ disabledEndpoints = append (disabledEndpoints , element .Path )
113+ }
91114 }
92- }
115+
116+ gw2Chan <- apiResult [[]string ]{Value : disabledEndpoints }
117+
118+ defer res .Body .Close ()
119+ return nil
120+ })
121+
122+ g .Go (func () error {
123+ req , err := http .NewRequestWithContext (ctx , http .MethodGet , "https://status.gw2efficiency.com/api" , nil )
124+ if err != nil {
125+ return err
126+ }
127+
128+ req .Header .Set ("User-Agent" , "GW2Auth" )
129+
130+ res , err := httpClient .Do (req )
131+ if err != nil {
132+ gw2Chan <- apiResult [[]string ]{Error : err }
133+ return nil
134+ }
135+
136+ if res .StatusCode != http .StatusOK {
137+ gw2Chan <- apiResult [[]string ]{Error : errors .New (res .Status )}
138+ return nil
139+ }
140+
141+ var gw2EffStatus gw2EffApiStatusResponse
142+ if err = json .NewDecoder (res .Body ).Decode (& gw2EffStatus ); err != nil {
143+ return echo .NewHTTPError (http .StatusBadGateway , err )
144+ }
145+
146+ var endpointsWithIssues []string
147+ for _ , element := range gw2EffStatus .Data {
148+ if slices .Contains (relevantEndpoints , element .Name ) && (element .Status != http .StatusOK || element .CheckError () || element .Duration >= 15_000 ) {
149+ endpointsWithIssues = append (endpointsWithIssues , element .Name )
150+ }
151+ }
152+
153+ defer res .Body .Close ()
154+ return nil
155+ })
93156
94157 var notifications []notification
95- if len (endpointsWithIssues ) > 0 {
96- notifications = []notification {
97- {
98- Type : notificationTypeWarning ,
99- Header : "The Guild Wars 2 API experiences issues right now" ,
100- 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. " ,
101- },
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+ }
172+ } else {
173+ notifications = make ([]notification , 0 )
102174 }
103175 } else {
104- notifications = make ([]notification , 0 )
176+ gw2EffResult := <- gw2EffChan
177+
178+ if gw2EffResult .Error == nil {
179+ return echo .NewHTTPError (http .StatusBadGateway , gw2EffResult .Error )
180+ }
181+
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+ }
105194 }
106195
107196 now := time .Now ()
0 commit comments