66 "encoding/json"
77 "fmt"
88 "io"
9- "io/ioutil"
109 "net/http"
10+ "net/url"
1111 "strconv"
1212 "strings"
1313 "time"
@@ -23,43 +23,21 @@ const (
2323 backoffMultiplier = 10
2424)
2525
26- type apis struct {
27- downloadConfigSpecs string
28- getIDLists string
29- logEvent string
30- }
31-
3226type transport struct {
33- api apis
3427 sdkKey string
3528 metadata statsigMetadata // Safe to read from but not thread safe to write into. If value needs to change, please ensure thread safety.
3629 client * http.Client
3730 options * Options
3831}
3932
4033func newTransport (secret string , options * Options ) * transport {
41- api := apis {
42- downloadConfigSpecs : strings .TrimSuffix (defaultString (
43- options .APIOverrides .DownloadConfigSpecs ,
44- defaultString (options .API , StatsigCDN ),
45- ), "/" ),
46- getIDLists : strings .TrimSuffix (defaultString (
47- options .APIOverrides .GetIDLists ,
48- defaultString (options .API , StatsigAPI ),
49- ), "/" ),
50- logEvent : strings .TrimSuffix (defaultString (
51- options .APIOverrides .LogEvent ,
52- defaultString (options .API , StatsigAPI ),
53- ), "/" ),
54- }
5534 defer func () {
5635 if err := recover (); err != nil {
5736 Logger ().LogError (err )
5837 }
5938 }()
6039
6140 return & transport {
62- api : api ,
6341 metadata : getStatsigMetadata (),
6442 sdkKey : secret ,
6543 client : & http.Client {
@@ -89,11 +67,19 @@ func (transport *transport) download_config_specs(sinceTime int64, responseBody
8967 } else {
9068 endpoint = fmt .Sprintf ("/download_config_specs/%s.json?sinceTime=%d" , transport .sdkKey , sinceTime )
9169 }
92- return transport .get (endpoint , responseBody , RequestOptions {})
70+ options := RequestOptions {}
71+ if transport .options .FallbackToStatsigAPI {
72+ options .retries = 1
73+ }
74+ return transport .get (endpoint , responseBody , options )
9375}
9476
9577func (transport * transport ) get_id_lists (responseBody interface {}) (* http.Response , error ) {
96- return transport .post ("/get_id_lists" , nil , responseBody , RequestOptions {})
78+ options := RequestOptions {}
79+ if transport .options .FallbackToStatsigAPI {
80+ options .retries = 1
81+ }
82+ return transport .post ("/get_id_lists" , nil , responseBody , options )
9783}
9884
9985func (transport * transport ) get_id_list (url string , headers map [string ]string ) (* http.Response , error ) {
@@ -171,7 +157,11 @@ func (transport *transport) buildRequest(method, endpoint string, body interface
171157 bodyBuf = bytes .NewBufferString ("{}" )
172158 }
173159 }
174- req , err := http .NewRequest (method , transport .buildURL (endpoint ), bodyBuf )
160+ url , err := transport .buildURL (endpoint , false )
161+ if err != nil {
162+ return nil , err
163+ }
164+ req , err := http .NewRequest (method , url .String (), bodyBuf )
175165 if err != nil {
176166 return nil , err
177167 }
@@ -193,16 +183,47 @@ func (transport *transport) buildRequest(method, endpoint string, body interface
193183 return req , nil
194184}
195185
196- func (transport * transport ) buildURL (endpoint string ) string {
186+ func (t * transport ) buildURL (path string , isRetry bool ) (* url.URL , error ) {
187+ var api string
188+ useDefaultAPI := isRetry && t .options .FallbackToStatsigAPI
189+ endpoint := strings .TrimPrefix (path , "/v1" )
197190 if strings .Contains (endpoint , "download_config_specs" ) {
198- return transport .api .downloadConfigSpecs + endpoint
191+ if useDefaultAPI {
192+ api = StatsigCDN
193+ } else {
194+ api = defaultString (t .options .APIOverrides .DownloadConfigSpecs , defaultString (t .options .API , StatsigCDN ))
195+ }
199196 } else if strings .Contains (endpoint , "get_id_list" ) {
200- return transport .api .getIDLists + endpoint
197+ if useDefaultAPI {
198+ api = StatsigAPI
199+ } else {
200+ api = defaultString (t .options .APIOverrides .GetIDLists , defaultString (t .options .API , StatsigAPI ))
201+ }
201202 } else if strings .Contains (endpoint , "log_event" ) {
202- return transport .api .logEvent + endpoint
203+ if useDefaultAPI {
204+ api = StatsigAPI
205+ } else {
206+ api = defaultString (t .options .APIOverrides .LogEvent , defaultString (t .options .API , StatsigAPI ))
207+ }
203208 } else {
204- return defaultString (transport .options .API , StatsigAPI ) + endpoint
209+ if useDefaultAPI {
210+ api = StatsigAPI
211+ } else {
212+ api = defaultString (t .options .API , StatsigAPI )
213+ }
205214 }
215+ return url .Parse (strings .TrimSuffix (api , "/" ) + endpoint )
216+ }
217+
218+ func (t * transport ) updateRequestForRetry (r * http.Request ) * http.Request {
219+ retryURL , err := t .buildURL (r .URL .Path , true )
220+ if err == nil && strings .Compare (r .URL .Host , retryURL .Host ) != 0 {
221+ retryRequest , err := http .NewRequest (r .Method , retryURL .String (), r .Body )
222+ if err == nil {
223+ return retryRequest
224+ }
225+ }
226+ return nil
206227}
207228
208229func (transport * transport ) doRequest (
@@ -225,10 +246,16 @@ func (transport *transport) doRequest(
225246 if err != nil {
226247 return response , response != nil , err
227248 }
249+
250+ retryRequest := transport .updateRequestForRetry (request )
251+ if retryRequest != nil {
252+ request = retryRequest
253+ }
254+
228255 drainAndCloseBody := func () {
229256 if response .Body != nil {
230257 // Drain body to re-use the same connection
231- _ , _ = io .Copy (ioutil .Discard , response .Body )
258+ _ , _ = io .Copy (io .Discard , response .Body )
232259 response .Body .Close ()
233260 }
234261 }
0 commit comments