@isaac-platform/isaac-integration-sdk
Version:
A Typescript SDK for integrating with ISAAC
151 lines (150 loc) • 6.67 kB
JavaScript
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);
}
}