Skip to content

Commit 653b2f0

Browse files
committed
vuidman
1 parent f2364af commit 653b2f0

File tree

4 files changed

+111
-52
lines changed

4 files changed

+111
-52
lines changed

lib/vuid/vuid_manager.spec.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,19 @@
1616

1717
import { describe, it, expect, vi } from 'vitest';
1818

19-
import { VuidManager } from './vuid_manager'
19+
import { DefaultVuidManager } from './vuid_manager'
2020
import { getMockAsyncCache, getMockSyncCache } from '../tests/mock/mock_cache';
2121
import { isVuid } from './vuid';
2222
import { resolvablePromise } from '../utils/promise/resolvablePromise';
2323
import { exhaustMicrotasks } from '../tests/testUtils';
2424

2525
const vuidCacheKey = 'optimizely-vuid';
2626

27-
describe('VuidManager', () => {;
27+
describe('DefaultVuidManager', () => {;
2828
describe('when configured with enableVuid = true', () => {
2929
it('should create and save a new vuid if there is no vuid in cache', async () => {
3030
const cache = getMockSyncCache<string>();
31-
const manager = new VuidManager(cache);
31+
const manager = new DefaultVuidManager(cache);
3232

3333
await manager.configure({ enableVuid: true });
3434

@@ -41,7 +41,7 @@ describe('VuidManager', () => {;
4141
const cache = getMockSyncCache<string>();
4242
cache.set(vuidCacheKey, 'invalid-vuid');
4343

44-
const manager = new VuidManager(cache);
44+
const manager = new DefaultVuidManager(cache);
4545
await manager.configure({ enableVuid: true });
4646

4747
const savedVuid = cache.get(vuidCacheKey);
@@ -53,7 +53,7 @@ describe('VuidManager', () => {;
5353
const cache = getMockSyncCache<string>();
5454
cache.set(vuidCacheKey, 'vuid_valid');
5555

56-
const manager = new VuidManager(cache);
56+
const manager = new DefaultVuidManager(cache);
5757
await manager.configure({ enableVuid: true });
5858

5959
const savedVuid = cache.get(vuidCacheKey);
@@ -66,7 +66,7 @@ describe('VuidManager', () => {;
6666
describe('when configured with enableVuid = false', () => {
6767
it('should remove existing vuid form memory and cache', async () => {
6868
const cache = getMockSyncCache<string>();
69-
const manager = new VuidManager(cache);
69+
const manager = new DefaultVuidManager(cache);
7070

7171
await manager.configure({ enableVuid: true });
7272

@@ -95,7 +95,7 @@ describe('VuidManager', () => {;
9595
const setPromise = resolvablePromise();
9696
setSpy.mockReturnValueOnce(setPromise.promise);
9797

98-
const manager = new VuidManager(cache);
98+
const manager = new DefaultVuidManager(cache);
9999

100100
// this should try to remove vuid, which should stay pending
101101
const configure1 = manager.configure({ enableVuid: false });

lib/vuid/vuid_manager.ts

Lines changed: 74 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,27 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
1716
import { LogHandler } from '../modules/logging';
1817
import { Cache } from '../utils/cache/cache';
18+
import { AsyncProducer, Maybe } from '../utils/type';
1919
import { isVuid, makeVuid } from './vuid';
2020

21-
export type VuidManagerOptions = {
22-
enableVuid: boolean;
21+
export interface VuidManager {
22+
getVuid(): Maybe<string>;
23+
isVuidEnabled(): boolean;
24+
initialize(): Promise<void>;
2325
}
2426

25-
export class VuidManager {
27+
export class VuidCacheManager {
2628
private logger?: LogHandler;
2729
private vuidCacheKey = 'optimizely-vuid';
28-
private vuid?: string;
29-
private vuidEnabled = false;
3030
private cache: Cache<string>;
31+
// if this value is not undefined, this means the same value is in the cache
32+
// if this is undefined, it could either mean that there is no value in the cache
33+
// or that there is a value in the cache but it has not been loaded yet
34+
private vuid?: string;
3135
private waitPromise: Promise<unknown> = Promise.resolve();
3236

33-
getVuid(): string | undefined {
34-
return this.vuid;
35-
}
36-
37-
isVuidEnabled(): boolean {
38-
return this.vuidEnabled;
39-
}
40-
4137
constructor(cache: Cache<string>, logger?: LogHandler) {
4238
this.cache = cache;
4339
this.logger = logger;
@@ -47,46 +43,79 @@ export class VuidManager {
4743
this.logger = logger;
4844
}
4945

50-
/**
51-
* Configures the VuidManager
52-
* @returns Promise that resolves when the VuidManager is configured
53-
*/
54-
async configure(options: VuidManagerOptions): Promise<unknown> {
55-
const configureFn = async () => {
56-
this.vuidEnabled = options.enableVuid;
57-
58-
if (!this.vuidEnabled) {
59-
await this.cache.remove(this.vuidCacheKey);
60-
this.vuid = undefined;
61-
return;
62-
}
63-
64-
if (!this.vuid) {
65-
await this.initializeVuid();
66-
}
46+
async serialize<T>(fn: AsyncProducer<T>): Promise<T> {
47+
const resultPromise = this.waitPromise.then(fn, fn);
48+
this.waitPromise = resultPromise.catch(() => {});
49+
return resultPromise;
50+
}
51+
52+
async remove(): Promise<unknown> {
53+
const removeFn = async () => {
54+
this.vuid = undefined;
55+
await this.cache.remove(this.vuidCacheKey);
6756
}
6857

69-
this.waitPromise = this.waitPromise.then(configureFn, configureFn);
70-
this.waitPromise.catch(() => {});
71-
return this.waitPromise;
58+
return this.serialize(removeFn);
7259
}
7360

74-
/**
75-
* Attempts to load a VUID from persistent cache or generates a new VUID
76-
* and saves it in the cache
77-
* @private
78-
*/
79-
private async initializeVuid(): Promise<void> {
61+
async load(): Promise<string> {
62+
if (this.vuid) {
63+
return this.vuid;
64+
}
65+
8066
const cachedValue = await this.cache.get(this.vuidCacheKey);
8167
if (cachedValue && isVuid(cachedValue)) {
8268
this.vuid = cachedValue;
83-
} else {
84-
await this.save(makeVuid());
69+
return this.vuid;
70+
}
71+
72+
const saveFn = async () => {
73+
const newVuid = makeVuid();
74+
await this.cache.set(this.vuidCacheKey, newVuid);
75+
this.vuid = newVuid;
76+
return newVuid;
8577
}
78+
return this.serialize(saveFn);
8679
}
80+
}
81+
82+
export type VuidManagerConfig = {
83+
enableVuid?: boolean;
84+
vuidCacheManager: VuidCacheManager;
85+
}
86+
87+
export class DefaultVuidManger implements VuidManager {
88+
private vuidCacheManager: VuidCacheManager;
89+
private logger?: LogHandler;
90+
private vuid?: string;
91+
private vuidEnabled = false;
92+
private initialized = false;
93+
94+
constructor(config: VuidManagerConfig) {
95+
this.vuidCacheManager = config.vuidCacheManager;
96+
this.vuidEnabled = config.enableVuid || false;
97+
}
98+
99+
getVuid(): Maybe<string> {
100+
return this.vuid;
101+
}
102+
103+
isVuidEnabled(): boolean {
104+
return this.vuidEnabled;
105+
}
106+
107+
/**
108+
* initializes the VuidManager
109+
* @returns Promise that resolves when the VuidManager is initialized
110+
*/
111+
async initialize(): Promise<void> {
112+
if (!this.vuidEnabled) {
113+
await this.vuidCacheManager.remove();
114+
this.initialized = true;
115+
return;
116+
}
87117

88-
private async save(vuid: string): Promise<void> {
89-
await this.cache.set(this.vuidCacheKey, vuid);
90-
this.vuid = vuid;
118+
this.vuid = await this.vuidCacheManager.load();
119+
this.initialized = true;
91120
}
92121
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright 2024, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import { DefaultVuidManger, VuidCacheManager, VuidManager } from './vuid_manager';
17+
import { LocalStorageCache } from '../utils/cache/local_storage_cache.browser';
18+
import { VuidManagerOptions } from './vuid_manager_factory';
19+
20+
export const vuidCacheManager = new VuidCacheManager(new LocalStorageCache<string>());
21+
22+
export const createVuidManager = (options: VuidManagerOptions): VuidManager => {
23+
return new DefaultVuidManger({
24+
vuidCacheManager,
25+
enableVuid: options.enableVuid
26+
});
27+
}

lib/vuid/vuid_manager_factory.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export type VuidManagerOptions = {
2+
enableVuid: boolean;
3+
}

0 commit comments

Comments
 (0)