Skip to content

Commit afd5068

Browse files
authored
chore: moved snapshotWatcher from client to lib (#206)
1 parent 70836b7 commit afd5068

File tree

3 files changed

+89
-61
lines changed

3 files changed

+89
-61
lines changed

src/client.js

Lines changed: 35 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
import { writeFileSync, watchFile, unwatchFile } from 'node:fs';
1+
import { writeFileSync } from 'node:fs';
22

33
import * as remote from './lib/remote.js';
44
import * as util from './lib/utils/index.js';
55
import Bypasser from './lib/bypasser/index.js';
6-
import {
7-
DEFAULT_ENVIRONMENT,
8-
DEFAULT_LOCAL,
9-
DEFAULT_LOGGER,
10-
DEFAULT_REGEX_MAX_BLACKLISTED,
11-
DEFAULT_REGEX_MAX_TIME_LIMIT,
6+
import {
7+
DEFAULT_ENVIRONMENT,
8+
DEFAULT_LOCAL,
9+
DEFAULT_LOGGER,
10+
DEFAULT_REGEX_MAX_BLACKLISTED,
11+
DEFAULT_REGEX_MAX_TIME_LIMIT,
1212
DEFAULT_STATIC,
1313
DEFAULT_TEST_MODE,
14-
SWITCHER_OPTIONS
14+
SWITCHER_OPTIONS
1515
} from './lib/constants.js';
1616
import TimedMatch from './lib/utils/timed-match/index.js';
1717
import ExecutionLogger from './lib/utils/executionLogger.js';
@@ -22,15 +22,16 @@ import { Switcher } from './switcher.js';
2222
import { Auth } from './lib/remoteAuth.js';
2323
import { GlobalOptions } from './lib/globals/globalOptions.js';
2424
import { GlobalSnapshot } from './lib/globals/globalSnapshot.js';
25+
import { SnapshotWatcher } from './lib/snapshotWatcher.js';
2526

2627
export class Client {
27-
28+
static #snapshotWatcher = new SnapshotWatcher();
29+
static #testEnabled;
2830
static #context;
2931

3032
static buildContext(context, options) {
31-
this.testEnabled = DEFAULT_TEST_MODE;
32-
3333
this.#context = context;
34+
this.#testEnabled = DEFAULT_TEST_MODE;
3435
this.#context.environment = util.get(context.environment, DEFAULT_ENVIRONMENT);
3536

3637
// Default values
@@ -44,16 +45,16 @@ export class Client {
4445
});
4546

4647
if (options) {
47-
Client.#buildOptions(options);
48+
Client.#buildOptions(options);
4849
}
49-
50+
5051
// Initialize Auth
5152
Auth.init(this.#context);
5253
}
5354

5455
static #buildOptions(options) {
5556
remote.removeAgent();
56-
57+
5758
const optionsHandler = {
5859
[SWITCHER_OPTIONS.CERT_PATH]: (val) => val && remote.setCerts(val),
5960
[SWITCHER_OPTIONS.SILENT_MODE]: (val) => val && this.#initSilentMode(val),
@@ -85,7 +86,7 @@ export class Client {
8586
GlobalOptions.updateOptions({ silentMode });
8687
Client.loadSnapshot();
8788
}
88-
89+
8990
static #initTimedMatch(options) {
9091
if (SWITCHER_OPTIONS.REGEX_MAX_BLACK_LIST in options) {
9192
TimedMatch.setMaxBlackListed(util.get(options.regexMaxBlackList, DEFAULT_REGEX_MAX_BLACKLISTED));
@@ -114,12 +115,12 @@ export class Client {
114115
if (Auth.isTokenExpired()) {
115116
await Auth.auth();
116117
}
117-
118+
118119
const snapshot = await validateSnapshot(
119-
Client.#context,
120-
GlobalSnapshot.snapshot.data.domain.version
120+
Client.#context,
121+
GlobalSnapshot.snapshot.data.domain.version
121122
);
122-
123+
123124
if (snapshot) {
124125
if (GlobalOptions.snapshotLocation?.length) {
125126
writeFileSync(`${GlobalOptions.snapshotLocation}/${Client.#context.environment}.json`, snapshot);
@@ -136,7 +137,7 @@ export class Client {
136137
const { fetchRemote = false, watchSnapshot = false } = options;
137138

138139
GlobalSnapshot.init(loadDomain(
139-
util.get(GlobalOptions.snapshotLocation, ''),
140+
util.get(GlobalOptions.snapshotLocation, ''),
140141
util.get(Client.#context.environment, DEFAULT_ENVIRONMENT)
141142
));
142143

@@ -145,7 +146,7 @@ export class Client {
145146
}
146147

147148
if (watchSnapshot) {
148-
Client.watchSnapshot();
149+
Client.watchSnapshot();
149150
}
150151

151152
return GlobalSnapshot.snapshot?.data.domain.version || 0;
@@ -163,50 +164,39 @@ export class Client {
163164
}
164165

165166
static watchSnapshot(callback = {}) {
166-
const { success = () => {}, reject = () => {} } = callback;
167+
const { reject = () => { } } = callback;
167168

168-
if (Client.testEnabled || !GlobalOptions.snapshotLocation?.length) {
169+
if (Client.#testEnabled || !GlobalOptions.snapshotLocation?.length) {
169170
return reject(new Error('Watch Snapshot cannot be used in test mode or without a snapshot location'));
170171
}
171172

172-
const snapshotFile = `${GlobalOptions.snapshotLocation}/${Client.#context.environment}.json`;
173-
let lastUpdate;
174-
watchFile(snapshotFile, (listener) => {
175-
try {
176-
if (!lastUpdate || listener.ctime > lastUpdate) {
177-
GlobalSnapshot.init(loadDomain(GlobalOptions.snapshotLocation, Client.#context.environment));
178-
success();
179-
}
180-
} catch (e) {
181-
reject(e);
182-
} finally {
183-
lastUpdate = listener.ctime;
184-
}
185-
});
173+
Client.#snapshotWatcher.watchSnapshot(
174+
util.get(Client.#context.environment, DEFAULT_ENVIRONMENT),
175+
callback
176+
);
186177
}
187178

188179
static unloadSnapshot() {
189-
if (Client.testEnabled) {
180+
if (Client.#testEnabled) {
190181
return;
191182
}
192183

193-
const snapshotFile = `${GlobalOptions.snapshotLocation}${Client.#context.environment}.json`;
194184
GlobalSnapshot.clear();
195-
unwatchFile(snapshotFile);
185+
Client.#snapshotWatcher.stopWatching();
196186
}
197187

198188
static scheduleSnapshotAutoUpdate(interval, callback = {}) {
199-
const { success = () => {}, reject = () => {} } = callback;
189+
const { success = () => { }, reject = () => { } } = callback;
200190

201191
if (interval) {
202192
GlobalOptions.updateOptions({ snapshotAutoUpdateInterval: interval });
203193
}
204194

205195
if (GlobalOptions.snapshotAutoUpdateInterval && GlobalOptions.snapshotAutoUpdateInterval > 0) {
206196
SnapshotAutoUpdater.schedule(
207-
GlobalOptions.snapshotAutoUpdateInterval,
208-
this.checkSnapshot,
209-
success,
197+
GlobalOptions.snapshotAutoUpdateInterval,
198+
this.checkSnapshot,
199+
success,
210200
reject
211201
);
212202
}
@@ -262,7 +252,7 @@ export class Client {
262252
}
263253

264254
static testMode(testEnabled = true) {
265-
Client.testEnabled = testEnabled;
255+
Client.#testEnabled = testEnabled;
266256
}
267257

268258
static get snapshotVersion() {

src/lib/snapshotWatcher.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { watchFile, unwatchFile } from 'node:fs';
2+
import { GlobalOptions } from './globals/globalOptions.js';
3+
import { GlobalSnapshot } from './globals/globalSnapshot.js';
4+
import { loadDomain } from './snapshot.js';
5+
6+
/**
7+
* SnapshotWatcher is a utility class that watches for changes in the snapshot file
8+
* and triggers a callback when the file is modified.
9+
*/
10+
export class SnapshotWatcher {
11+
#snapshotFile;
12+
13+
watchSnapshot(environment, callback = {}) {
14+
const { success = () => { }, reject = () => { } } = callback;
15+
16+
this.#snapshotFile = `${GlobalOptions.snapshotLocation}/${environment}.json`;
17+
let lastUpdate;
18+
watchFile(this.#snapshotFile, (listener) => {
19+
try {
20+
if (!lastUpdate || listener.ctime > lastUpdate) {
21+
GlobalSnapshot.init(loadDomain(GlobalOptions.snapshotLocation, environment));
22+
success();
23+
}
24+
} catch (e) {
25+
reject(e);
26+
} finally {
27+
lastUpdate = listener.ctime;
28+
}
29+
});
30+
}
31+
32+
stopWatching() {
33+
if (this.#snapshotFile) {
34+
unwatchFile(this.#snapshotFile);
35+
this.#snapshotFile = undefined;
36+
}
37+
}
38+
}

tests/playground/index.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ async function setupSwitcher(local) {
2626
* Snapshot is loaded from file at tests/playground/snapshot/local.json
2727
*/
2828
const _testLocal = async () => {
29-
Client.buildContext({
30-
domain: 'Local Playground',
31-
environment: 'local'
32-
}, {
33-
snapshotLocation: './tests/playground/snapshot/',
29+
Client.buildContext({
30+
domain: 'Local Playground',
31+
environment: 'local'
32+
}, {
33+
snapshotLocation: './tests/playground/snapshot/',
3434
local: true
3535
});
3636

@@ -39,7 +39,7 @@ const _testLocal = async () => {
3939
.catch(() => console.log('Failed to load Snapshot'));
4040

4141
const switcher = Client.getSwitcher(SWITCHER_KEY)
42-
.detail();
42+
.detail();
4343

4444
setInterval(() => {
4545
const time = Date.now();
@@ -52,7 +52,7 @@ const _testLocal = async () => {
5252
// Requires remote API
5353
const _testSimpleAPICall = async (local) => {
5454
await setupSwitcher(local);
55-
55+
5656
await Client.checkSwitchers([SWITCHER_KEY])
5757
.then(() => console.log('Switcher checked'))
5858
.catch(error => console.log(error));
@@ -69,7 +69,7 @@ const _testSimpleAPICall = async (local) => {
6969
// Requires remote API
7070
const _testThrottledAPICall = async () => {
7171
setupSwitcher(false);
72-
72+
7373
await Client.checkSwitchers([SWITCHER_KEY]);
7474
Client.subscribeNotifyError((error) => console.log(error));
7575

@@ -81,7 +81,7 @@ const _testThrottledAPICall = async () => {
8181
const result = await switcher
8282
.detail()
8383
.isItOn(SWITCHER_KEY);
84-
84+
8585
console.log(`- ${Date.now() - time} ms - ${JSON.stringify(result)}`);
8686
}, 1000);
8787
};
@@ -90,7 +90,7 @@ const _testThrottledAPICall = async () => {
9090
const _testSnapshotUpdate = async () => {
9191
setupSwitcher(false);
9292
await sleep(2000);
93-
93+
9494
console.log('checkSnapshot:', await Client.checkSnapshot());
9595
};
9696

@@ -148,18 +148,18 @@ const _testWatchSnapshot = async () => {
148148
};
149149

150150
// Does not require remote API
151-
const _testWatchSnapshotContextOptions = async () => {
152-
Client.buildContext({ domain, environment }, {
151+
const _testWatchSnapshotContextOptions = async () => {
152+
Client.buildContext({ domain, environment }, {
153153
snapshotLocation,
154154
snapshotWatcher: true,
155-
local: true,
155+
local: true,
156156
logger: true
157157
});
158158

159159
await Client.loadSnapshot();
160160

161161
const switcher = Client.getSwitcher();
162-
162+
163163
setInterval(async () => {
164164
const time = Date.now();
165165
const result = await switcher
@@ -172,7 +172,7 @@ const _testWatchSnapshotContextOptions = async () => {
172172

173173
// Requires remote API
174174
const _testSnapshotAutoUpdate = async () => {
175-
Client.buildContext({ url, apiKey, domain, component, environment },
175+
Client.buildContext({ url, apiKey, domain, component, environment },
176176
{ local: true, logger: true });
177177

178178
await Client.loadSnapshot({ watchSnapshot: false, fetchRemote: true });
@@ -191,4 +191,4 @@ const _testSnapshotAutoUpdate = async () => {
191191
}, 2000);
192192
};
193193

194-
_testWatchSnapshot();
194+
_testLocal();

0 commit comments

Comments
 (0)