refactor: Improve SpotifyPollingService by encapsulating state management and simplifying polling logic
This commit is contained in:
@@ -6,10 +6,12 @@ import { UserService } from "./db/UserService";
|
||||
import { SpotifyTokenService } from "./spotifyTokenService";
|
||||
import logger from "../utils/logger";
|
||||
|
||||
const userStateCache = new Map<string, any>();
|
||||
const activePolls = new Map<string, NodeJS.Timeout>();
|
||||
|
||||
export class SpotifyPollingService {
|
||||
|
||||
private readonly userStateCache = new Map<string, any>();
|
||||
private readonly activePolls = new Map<string, NodeJS.Timeout>();
|
||||
|
||||
constructor(
|
||||
private readonly userService: UserService,
|
||||
private readonly spotifyApiService: SpotifyApiService,
|
||||
@@ -18,21 +20,33 @@ export class SpotifyPollingService {
|
||||
|
||||
public startPollingForUser(user: IUser): void {
|
||||
const uuid = user.uuid;
|
||||
if (activePolls.has(uuid)) return;
|
||||
if (this.activePolls.has(uuid)) return;
|
||||
|
||||
logger.info(`Starting Spotify polling service for user ${uuid}`);
|
||||
const intervalId = setInterval(() => this._pollUser(uuid), 3000);
|
||||
activePolls.set(uuid, intervalId);
|
||||
|
||||
this._pollUser(uuid);
|
||||
const poll = async () => {
|
||||
if (!this.activePolls.has(uuid)) return;
|
||||
|
||||
await this._pollUser(uuid);
|
||||
|
||||
if (this.activePolls.has(uuid)) {
|
||||
const timeoutId = setTimeout(poll, 3000);
|
||||
this.activePolls.set(uuid, timeoutId);
|
||||
}
|
||||
};
|
||||
|
||||
this.activePolls.set(uuid, null as any);
|
||||
|
||||
poll();
|
||||
}
|
||||
|
||||
|
||||
public stopPollingForUser(uuid: string): void {
|
||||
if (activePolls.has(uuid)) {
|
||||
if (this.activePolls.has(uuid)) {
|
||||
logger.info(`Stopping Spotify polling service for user ${uuid}`);
|
||||
clearInterval(activePolls.get(uuid)!);
|
||||
activePolls.delete(uuid);
|
||||
userStateCache.delete(uuid);
|
||||
clearInterval(this.activePolls.get(uuid)!);
|
||||
this.activePolls.delete(uuid);
|
||||
this.userStateCache.delete(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,11 +73,11 @@ export class SpotifyPollingService {
|
||||
}
|
||||
|
||||
const currentState = await this.spotifyApiService.getCurrentlyPlaying(user!.spotifyConfig!.accessToken);
|
||||
const lastState = userStateCache.get(uuid);
|
||||
const lastState = this.userStateCache.get(uuid);
|
||||
|
||||
if (this._hasStateChanged(lastState, currentState)) {
|
||||
logger.debug(`Spotify state changed for user ${uuid} - emitting update event`);
|
||||
userStateCache.set(uuid, currentState);
|
||||
this.userStateCache.set(uuid, currentState);
|
||||
appEventBus.emit(SPOTIFY_STATE_UPDATED_EVENT, { uuid, state: currentState });
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -90,9 +104,9 @@ export class SpotifyPollingService {
|
||||
}
|
||||
|
||||
private _pausePolling(uuid: string, durationMs: number): void {
|
||||
if (activePolls.has(uuid)) {
|
||||
clearInterval(activePolls.get(uuid)!);
|
||||
activePolls.delete(uuid);
|
||||
if (this.activePolls.has(uuid)) {
|
||||
clearInterval(this.activePolls.get(uuid)!);
|
||||
this.activePolls.delete(uuid);
|
||||
setTimeout(() => {
|
||||
logger.debug(`Resuming Spotify polling service for user ${uuid}`);
|
||||
this.userService.getUserByUUID(uuid).then((user) => {
|
||||
|
||||
@@ -34,8 +34,7 @@ describe("SpotifyPollingService", () => {
|
||||
},
|
||||
} as any;
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.useFakeTimers();
|
||||
|
||||
@@ -45,9 +44,7 @@ describe("SpotifyPollingService", () => {
|
||||
mockedTokenService = createMockSpotifyTokenService() as any;
|
||||
mockedAppEventBus = appEventBus as Mocked<typeof appEventBus>;
|
||||
|
||||
const { SpotifyPollingService: FreshSpotifyPollingService } = await import('../../src/services/spotifyPollingService');
|
||||
|
||||
pollingService = new FreshSpotifyPollingService(
|
||||
pollingService = new SpotifyPollingService(
|
||||
mockedUserService,
|
||||
mockedApiService,
|
||||
mockedTokenService
|
||||
@@ -57,6 +54,11 @@ describe("SpotifyPollingService", () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (pollingService) {
|
||||
pollingService.stopPollingForUser(mockUser.uuid);
|
||||
}
|
||||
|
||||
vi.clearAllTimers();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
@@ -97,7 +99,7 @@ describe("SpotifyPollingService", () => {
|
||||
expect(vi.getTimerCount()).toBe(1);
|
||||
|
||||
pollingService.stopPollingForUser(mockUser.uuid);
|
||||
expect(vi.getTimerCount()).toBe(0);
|
||||
expect(pollingService.activePolls.size).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -190,7 +192,7 @@ describe("SpotifyPollingService", () => {
|
||||
await vi.advanceTimersByTimeAsync(5000);
|
||||
|
||||
expect(mockedApiService.getCurrentlyPlaying).toHaveBeenCalledTimes(2);
|
||||
expect(vi.getTimerCount()).toBe(1);
|
||||
expect(pollingService.activePolls.size).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user