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