1
+ import { ISettings } from '../../../../types/splitio' ;
2
+ import { ISplitChangesResponse } from '../../../dtos/types' ;
1
3
import { IFetchSplitChanges , IResponse } from '../../../services/types' ;
4
+ import { IStorageBase } from '../../../storages/types' ;
5
+ import { FLAG_SPEC_VERSION } from '../../../utils/constants' ;
6
+ import { base } from '../../../utils/settingsValidation' ;
2
7
import { ISplitChangesFetcher } from './types' ;
3
8
9
+ const PROXY_CHECK_INTERVAL_MILLIS_CS = 60 * 60 * 1000 ; // 1 hour in Client Side
10
+ const PROXY_CHECK_INTERVAL_MILLIS_SS = 24 * PROXY_CHECK_INTERVAL_MILLIS_CS ; // 24 hours in Server Side
11
+
12
+ function sdkEndpointOverriden ( settings : ISettings ) {
13
+ return settings . urls . sdk !== base . urls . sdk ;
14
+ }
15
+
4
16
/**
5
17
* Factory of SplitChanges fetcher.
6
18
* SplitChanges fetcher is a wrapper around `splitChanges` API service that parses the response and handle errors.
7
19
*/
8
- export function splitChangesFetcherFactory ( fetchSplitChanges : IFetchSplitChanges ) : ISplitChangesFetcher {
20
+ export function splitChangesFetcherFactory ( fetchSplitChanges : IFetchSplitChanges , settings : ISettings , storage : Pick < IStorageBase , 'splits' | 'rbSegments' > ) : ISplitChangesFetcher {
21
+
22
+ const PROXY_CHECK_INTERVAL_MILLIS = settings . core . key !== undefined ? PROXY_CHECK_INTERVAL_MILLIS_CS : PROXY_CHECK_INTERVAL_MILLIS_SS ;
23
+ let _lastProxyCheckTimestamp : number | undefined ;
9
24
10
25
return function splitChangesFetcher (
11
26
since : number ,
@@ -14,12 +29,48 @@ export function splitChangesFetcherFactory(fetchSplitChanges: IFetchSplitChanges
14
29
rbSince ?: number ,
15
30
// Optional decorator for `fetchSplitChanges` promise, such as timeout or time tracker
16
31
decorator ?: ( promise : Promise < IResponse > ) => Promise < IResponse >
17
- ) {
32
+ ) : Promise < ISplitChangesResponse > {
33
+
34
+ if ( _lastProxyCheckTimestamp && ( Date . now ( ) - _lastProxyCheckTimestamp ) > PROXY_CHECK_INTERVAL_MILLIS ) {
35
+ settings . sync . flagSpecVersion = FLAG_SPEC_VERSION ;
36
+ }
37
+
38
+ let splitsPromise = fetchSplitChanges ( since , noCache , till , rbSince )
39
+ // Handle proxy errors with spec 1.3
40
+ . catch ( ( err ) => {
41
+ if ( err . statusCode === 400 && sdkEndpointOverriden ( settings ) && settings . sync . flagSpecVersion === FLAG_SPEC_VERSION ) {
42
+ _lastProxyCheckTimestamp = Date . now ( ) ;
43
+ settings . sync . flagSpecVersion = '1.2' ; // fallback to 1.2 spec
44
+ return fetchSplitChanges ( since , noCache , till ) ; // retry request without rbSince
45
+ }
46
+ throw err ;
47
+ } ) ;
18
48
19
- let splitsPromise = fetchSplitChanges ( since , noCache , till , rbSince ) ;
20
49
if ( decorator ) splitsPromise = decorator ( splitsPromise ) ;
21
50
22
- return splitsPromise . then ( resp => resp . json ( ) ) ;
51
+ return splitsPromise
52
+ . then ( resp => resp . json ( ) )
53
+ . then ( data => {
54
+ // Using flag spec version 1.2
55
+ if ( data . splits ) {
56
+ return {
57
+ ff : {
58
+ d : data . splits ,
59
+ s : data . since ,
60
+ t : data . till
61
+ }
62
+ } ;
63
+ }
64
+
65
+ // Proxy recovery
66
+ if ( _lastProxyCheckTimestamp ) {
67
+ _lastProxyCheckTimestamp = undefined ;
68
+ return Promise . all ( [ storage . splits . clear ( ) , storage . rbSegments . clear ( ) ] )
69
+ . then ( ( ) => splitChangesFetcher ( - 1 , undefined , undefined , - 1 ) ) ;
70
+ }
71
+
72
+ return data ;
73
+ } ) ;
23
74
} ;
24
75
25
76
}
0 commit comments