UNPKG

@isaac-platform/isaac-integration-sdk

Version:

A Typescript SDK for integrating with ISAAC

151 lines (150 loc) 6.67 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import * as isaacBlocks from "./blocks/index.js"; import * as isaacPlaylists from "./playlists/index.js"; import * as isaacEvents from "./events/index.js"; import * as isaacPlayables from "./playables/index.js"; import { EventEmitter } from "events"; import isaacConnection from "../controller/isaac.js"; export class ScheduleController extends EventEmitter { constructor() { super(); // Default Configuration this.pollingInterval = 10000; this.windowInterval = 1000; this.updateCount = 0; this.beforeCount = 0; this.afterCount = null; this.timeWindow = 5000; this.scheduleData = null; // Running scheduleData parameters this.pollScheduleInterval = null; this.scheduleWindowUpdateInterval = null; this.running = false; this.upNext = []; this.timeoutStack = new Map(); /** * Starts automatic scheduleData updates and ticks */ this.start = () => { if (this.running) return; this.pollScheduleInterval = setInterval(this.updateSchedule, this.pollingInterval); this.scheduleWindowUpdateInterval = setInterval(this.updateWindow, this.windowInterval); this.running = true; }; /** * Stops automatic scheduleData updates and ticks */ this.stop = () => { if (!this.running) return; clearInterval(this.pollScheduleInterval); clearInterval(this.scheduleWindowUpdateInterval); this.pollScheduleInterval = null; this.scheduleWindowUpdateInterval = null; this.running = false; }; /** * Retrieves the latest scheduleData from ISAAC, caches it in this.scheduleData, and emits the scheduleData */ this.getSchedule = () => __awaiter(this, void 0, void 0, function* () { const beforeCount = this.beforeCount; const afterCount = this.afterCount; const requestParameters = { subsystemExternalId: isaacConnection.subsystemID, beforeCount: beforeCount, afterCount: afterCount }; try { const rawSchedule = yield isaacConnection.getRequest(`schedule`, { params: requestParameters, }); this.scheduleData = rawSchedule[0]; this.updateCount = 0; } catch (error) { console.error('ISAAC SDK: Failed to get schedule:', error); } this.emit('newSchedule', this.scheduleData); return this.scheduleData; }); /** * Updates the scheduleData if there has been any change since the last retrieval. */ this.updateSchedule = () => __awaiter(this, void 0, void 0, function* () { try { // TODO: make updateCountLimit configurable if (!this.scheduleData || this.updateCount > 100) return yield this.getSchedule(); // Get scheduleData if empty const response = yield isaacConnection.getRequest(`schedule`, { params: { subsystemExternalId: isaacConnection.subsystemID }, headers: { "If-Modified-Since": `${this.scheduleData.generatedAt}` } }); if (response && Array.isArray(response) && response.length > 0) { this.scheduleData = response[0]; this.emit('scheduleUpdate'); } this.updateCount++; } catch (error) { console.error('Failed to update schedule:', error); } return this.scheduleData; }); /** * Processes the currently loaded scheduleData */ this.updateWindow = () => __awaiter(this, void 0, void 0, function* () { if (!this.running) return; // Don't tick if not running if (!this.scheduleData) return; // Don't tick if no scheduleData if (this.scheduleData.values.length <= 0) return; // Don't tick if empty scheduleData const now = Date.now(); this.upNext = this.scheduleData.values.filter((entry) => { return entry.startTimeUnix * 1000 <= now + this.timeWindow && entry.startTimeUnix * 1000 >= now; }); for (let entry of this.upNext) { const startTime = entry.startTimeUnix * 1000; const timeUntilStart = startTime - now; // If the entry is already in the timeout stack, don't add it again. if (this.timeoutStack.has(entry.externalRef)) return; // Create a new timeout for the entry and add it to the timeout stack. const newTimeout = setTimeout(this.handleEntryStart, timeUntilStart, entry); this.timeoutStack.set(entry.externalRef, newTimeout); } }); this.handleEntryStart = (entry) => __awaiter(this, void 0, void 0, function* () { this.emit('scheduleEntryStart', entry); this.timeoutStack.delete(entry.externalRef); }); this.blocks = new isaacBlocks.blockController(); this.playlists = new isaacPlaylists.playlistController(); this.events = new isaacEvents.EventController(); this.playables = new isaacPlayables.PlayableController(); } // Override EventEmitter Events for safer typing from emits. emit(event, ...args) { return super.emit(event, ...args); } on(event, listener) { return super.on(event, listener); } off(event, listener) { return super.off(event, listener); } }