1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-08 01:15:49 +02:00
unleash.unleash/src/lib/features/unique-connection/unique-connection-service.ts
2025-01-13 14:06:09 +01:00

91 lines
3.1 KiB
TypeScript

import type { IUnleashConfig } from '../../types/option';
import type { IFlagResolver, IUnleashStores } from '../../types';
import type { Logger } from '../../logger';
import type { IUniqueConnectionStore } from './unique-connection-store-type';
import HyperLogLog from 'hyperloglog-lite';
import type EventEmitter from 'events';
import { SDK_CONNECTION_ID_RECEIVED } from '../../metric-events';
import { REGISTERS_EXPONENT } from './hyperloglog-config';
export class UniqueConnectionService {
private logger: Logger;
private uniqueConnectionStore: IUniqueConnectionStore;
private flagResolver: IFlagResolver;
private eventBus: EventEmitter;
private activeHour: number;
private hll = HyperLogLog(REGISTERS_EXPONENT);
constructor(
{
uniqueConnectionStore,
}: Pick<IUnleashStores, 'uniqueConnectionStore'>,
config: Pick<IUnleashConfig, 'getLogger' | 'flagResolver' | 'eventBus'>,
) {
this.uniqueConnectionStore = uniqueConnectionStore;
this.logger = config.getLogger('services/unique-connection-service.ts');
this.flagResolver = config.flagResolver;
this.eventBus = config.eventBus;
this.activeHour = new Date().getHours();
}
listen() {
this.eventBus.on(SDK_CONNECTION_ID_RECEIVED, this.count.bind(this));
}
count(connectionId: string) {
if (!this.flagResolver.isEnabled('uniqueSdkTracking')) return;
this.hll.add(HyperLogLog.hash(connectionId));
}
async sync(currentTime = new Date()): Promise<void> {
if (!this.flagResolver.isEnabled('uniqueSdkTracking')) return;
const currentHour = currentTime.getHours();
const currentBucket = await this.uniqueConnectionStore.get('current');
if (this.activeHour !== currentHour && currentBucket) {
if (currentBucket.updatedAt.getHours() < currentHour) {
this.hll.merge({
n: REGISTERS_EXPONENT,
buckets: currentBucket.hll,
});
await this.uniqueConnectionStore.insert({
hll: this.hll.output().buckets,
id: 'previous',
});
} else {
const previousBucket =
await this.uniqueConnectionStore.get('previous');
if (previousBucket) {
this.hll.merge({
n: REGISTERS_EXPONENT,
buckets: previousBucket.hll,
});
}
await this.uniqueConnectionStore.insert({
hll: this.hll.output().buckets,
id: 'previous',
});
}
this.activeHour = currentHour;
this.hll = HyperLogLog(REGISTERS_EXPONENT);
} else if (currentBucket) {
this.hll.merge({
n: REGISTERS_EXPONENT,
buckets: currentBucket.hll,
});
}
await this.uniqueConnectionStore.insert({
hll: this.hll.output().buckets,
id: 'current',
});
}
}