diff --git a/libs/castmate-core/src/index.ts b/libs/castmate-core/src/index.ts index dad6202d..399a17ca 100644 --- a/libs/castmate-core/src/index.ts +++ b/libs/castmate-core/src/index.ts @@ -49,3 +49,5 @@ export * from "./util/generic-login" export * from "./analytics/analytics-manager" export * from "./info/info-manager" + +export * from "./util/time-utils" diff --git a/libs/castmate-core/src/plugins/plugin.ts b/libs/castmate-core/src/plugins/plugin.ts index d2576fb0..6fb7b4d5 100644 --- a/libs/castmate-core/src/plugins/plugin.ts +++ b/libs/castmate-core/src/plugins/plugin.ts @@ -40,6 +40,7 @@ import { import { ResourceBase, ResourceConstructor } from "../resources/resource" import { PluginManager } from "./plugin-manager" import { Logger, globalLogger, usePluginLogger } from "../logging/logging" +import { startPerfTime } from "../util/time-utils" interface PluginSpec { id: string @@ -97,8 +98,15 @@ export function onUnload(unloadFunc: PluginCallback) { } export function definePluginResource(resourceConstructor: ResourceConstructor) { + const logger = usePluginLogger() + onLoad(async () => { - await resourceConstructor.initialize() + const perf = startPerfTime(`Initing ${resourceConstructor.storage.name}`) + try { + await resourceConstructor.initialize() + } finally { + perf.stop(logger) + } }) onUnload(async () => { diff --git a/libs/castmate-core/src/util/time-utils.ts b/libs/castmate-core/src/util/time-utils.ts new file mode 100644 index 00000000..e706367a --- /dev/null +++ b/libs/castmate-core/src/util/time-utils.ts @@ -0,0 +1,82 @@ +import { isPromise } from "util/types" +import { Logger, usePluginLogger } from "../logging/logging" + +export interface PerfTimer { + name: string + startTime: number + stop(logger: Logger): void +} + +export function startPerfTime(name: string): PerfTimer { + return { + name, + startTime: Date.now(), + stop(logger) { + logger.log("Completed ", name, (Date.now() - this.startTime) / 1000, "seconds") + }, + } +} + +export function measurePerf any>( + original: T, + context: ClassMethodDecoratorContext +) { + const logger = usePluginLogger("perf") + + function replacement(this: This, ...args: Parameters): ReturnType { + const perf = startPerfTime(String(context.name)) + + let result: ReturnType + try { + result = original.call(this, ...args) + + if (isPromise(result)) { + //@ts-ignore Type system too stupid again. + return (async () => { + try { + return await result + } finally { + perf.stop(logger) + } + })() + } else { + perf.stop(logger) + return result + } + } catch (err) { + perf.stop(logger) + throw err + } + } + + return replacement +} + +export function measurePerfFunc any>(func: T, name?: string) { + const logger = usePluginLogger("perf") + return (...args: Parameters): ReturnType => { + const perf = startPerfTime(name ?? func.name) + + let result: ReturnType + try { + result = func(...args) + + if (isPromise(result)) { + //@ts-ignore Type system too stupid again. + return (async () => { + try { + return await result + } finally { + perf.stop(logger) + } + })() + } else { + perf.stop(logger) + return result + } + } catch (err) { + perf.stop(logger) + throw err + } + } +} diff --git a/libs/castmate-overlay-core/tsconfig.json b/libs/castmate-overlay-core/tsconfig.json index 4d4faa6f..934d023d 100644 --- a/libs/castmate-overlay-core/tsconfig.json +++ b/libs/castmate-overlay-core/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/libs/castmate-overlay-macros/tsconfig.json b/libs/castmate-overlay-macros/tsconfig.json index ae039036..cb4b1fd0 100644 --- a/libs/castmate-overlay-macros/tsconfig.json +++ b/libs/castmate-overlay-macros/tsconfig.json @@ -6,7 +6,7 @@ "preserveConstEnums": true, "outDir": "dist", "sourceMap": true, - "target": "ES6", + "target": "ES2022", "strictNullChecks": true, "esModuleInterop": true }, diff --git a/libs/castmate-overlay-widget-loader/tsconfig.json b/libs/castmate-overlay-widget-loader/tsconfig.json index f32a276b..13a97455 100644 --- a/libs/castmate-overlay-widget-loader/tsconfig.json +++ b/libs/castmate-overlay-widget-loader/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/libs/castmate-ui-core/tsconfig.json b/libs/castmate-ui-core/tsconfig.json index 4d4faa6f..934d023d 100644 --- a/libs/castmate-ui-core/tsconfig.json +++ b/libs/castmate-ui-core/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/libs/castmate-vite/tsconfig.json b/libs/castmate-vite/tsconfig.json index 75b88507..40f00a10 100644 --- a/libs/castmate-vite/tsconfig.json +++ b/libs/castmate-vite/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "module": "ESNext", "moduleResolution": "Node", - "target": "ES6", + "target": "ES2022", "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true, diff --git a/libs/castmate-ws-rpc/tsconfig.json b/libs/castmate-ws-rpc/tsconfig.json index 36c6976e..8ed3b62e 100644 --- a/libs/castmate-ws-rpc/tsconfig.json +++ b/libs/castmate-ws-rpc/tsconfig.json @@ -6,7 +6,7 @@ "preserveConstEnums": true, "outDir": "dist", "sourceMap": true, - "target": "ES6", + "target": "ES2022", "strictNullChecks": true }, "include": ["src/**/*"], diff --git a/package.json b/package.json index 9d987e65..1e398469 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "castmate-monorepo", - "version": "0.5.1", + "version": "0.5.2-beta", "description": "", "private": true, "type": "module", diff --git a/packages/castmate-obs-overlay/tsconfig.json b/packages/castmate-obs-overlay/tsconfig.json index 1b25bf17..2d457fea 100644 --- a/packages/castmate-obs-overlay/tsconfig.json +++ b/packages/castmate-obs-overlay/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/packages/castmate/package.json b/packages/castmate/package.json index c107ef0e..fd433164 100644 --- a/packages/castmate/package.json +++ b/packages/castmate/package.json @@ -1,6 +1,6 @@ { "name": "castmate", - "version": "0.5.1", + "version": "0.5.2-beta", "description": "CastMate", "author": "LordTocs", "scripts": { diff --git a/packages/castmate/tsconfig.json b/packages/castmate/tsconfig.json index ec465c84..b6f9d37d 100644 --- a/packages/castmate/tsconfig.json +++ b/packages/castmate/tsconfig.json @@ -3,7 +3,7 @@ "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugin-template/renderer/tsconfig.json b/plugin-template/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugin-template/renderer/tsconfig.json +++ b/plugin-template/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/discord/renderer/tsconfig.json b/plugins/discord/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/discord/renderer/tsconfig.json +++ b/plugins/discord/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/elgato/renderer/tsconfig.json b/plugins/elgato/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/elgato/renderer/tsconfig.json +++ b/plugins/elgato/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/govee/renderer/tsconfig.json b/plugins/govee/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/govee/renderer/tsconfig.json +++ b/plugins/govee/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/http/renderer/tsconfig.json b/plugins/http/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/http/renderer/tsconfig.json +++ b/plugins/http/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/input/renderer/tsconfig.json b/plugins/input/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/input/renderer/tsconfig.json +++ b/plugins/input/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/iot/renderer/tsconfig.json b/plugins/iot/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/iot/renderer/tsconfig.json +++ b/plugins/iot/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/lifx/renderer/tsconfig.json b/plugins/lifx/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/lifx/renderer/tsconfig.json +++ b/plugins/lifx/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/minecraft/renderer/tsconfig.json b/plugins/minecraft/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/minecraft/renderer/tsconfig.json +++ b/plugins/minecraft/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/obs/renderer/tsconfig.json b/plugins/obs/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/obs/renderer/tsconfig.json +++ b/plugins/obs/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/os/renderer/tsconfig.json b/plugins/os/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/os/renderer/tsconfig.json +++ b/plugins/os/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/overlays/overlay/tsconfig.json b/plugins/overlays/overlay/tsconfig.json index 9ef94822..acdc3196 100644 --- a/plugins/overlays/overlay/tsconfig.json +++ b/plugins/overlays/overlay/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/overlays/renderer/tsconfig.json b/plugins/overlays/renderer/tsconfig.json index 14019814..e4a5ab51 100644 --- a/plugins/overlays/renderer/tsconfig.json +++ b/plugins/overlays/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/philips-hue/renderer/tsconfig.json b/plugins/philips-hue/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/philips-hue/renderer/tsconfig.json +++ b/plugins/philips-hue/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/random/overlay/tsconfig.json b/plugins/random/overlay/tsconfig.json index 9ef94822..acdc3196 100644 --- a/plugins/random/overlay/tsconfig.json +++ b/plugins/random/overlay/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/random/renderer/tsconfig.json b/plugins/random/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/random/renderer/tsconfig.json +++ b/plugins/random/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/remote/renderer/tsconfig.json b/plugins/remote/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/remote/renderer/tsconfig.json +++ b/plugins/remote/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/sound/renderer/tsconfig.json b/plugins/sound/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/sound/renderer/tsconfig.json +++ b/plugins/sound/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/spellcast/renderer/tsconfig.json b/plugins/spellcast/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/spellcast/renderer/tsconfig.json +++ b/plugins/spellcast/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/stream-plans/renderer/tsconfig.json b/plugins/stream-plans/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/stream-plans/renderer/tsconfig.json +++ b/plugins/stream-plans/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/time/renderer/tsconfig.json b/plugins/time/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/time/renderer/tsconfig.json +++ b/plugins/time/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/tplink-kasa/renderer/tsconfig.json b/plugins/tplink-kasa/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/tplink-kasa/renderer/tsconfig.json +++ b/plugins/tplink-kasa/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/twinkly/renderer/tsconfig.json b/plugins/twinkly/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/twinkly/renderer/tsconfig.json +++ b/plugins/twinkly/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/twitch/main/src/ads.ts b/plugins/twitch/main/src/ads.ts index 4035cebd..4f151291 100644 --- a/plugins/twitch/main/src/ads.ts +++ b/plugins/twitch/main/src/ads.ts @@ -1,10 +1,22 @@ -import { Service, defineAction, defineState, defineTrigger, onProfilesChanged } from "castmate-core" +import { + Service, + defineAction, + defineState, + defineTrigger, + measurePerf, + measurePerfFunc, + onProfilesChanged, + startPerfTime, + usePluginLogger, +} from "castmate-core" import { TwitchAccount } from "./twitch-auth" import { CommercialLength } from "@twurple/api" import { onChannelAuth } from "./api-harness" import { Duration, Timer, getTimeRemaining, isTimerStarted } from "castmate-schema" export function setupAds() { + const logger = usePluginLogger() + defineAction({ id: "runAd", name: "Run Ad", @@ -77,7 +89,7 @@ export function setupAds() { required: true, }) - async function queryAdSchedule() { + const queryAdSchedule = measurePerfFunc(async function () { const schedule = await TwitchAccount.channel.apiClient.channels.getAdSchedule(TwitchAccount.channel.twitchId) nextAdDuration.value = schedule.duration @@ -94,7 +106,7 @@ export function setupAds() { //Adjust the schedule if necessary scheduleAdTriggers(scheduledAdTriggers) - } + }, "queryAdSchedule") interface ScheduledAdTrigger { advance: Duration diff --git a/plugins/twitch/main/src/channelpoints.ts b/plugins/twitch/main/src/channelpoints.ts index 4c17e38a..c183f965 100644 --- a/plugins/twitch/main/src/channelpoints.ts +++ b/plugins/twitch/main/src/channelpoints.ts @@ -393,25 +393,29 @@ export class ChannelPointReward extends Resource r.id == reward.config.twitchId) - await reward.initializeFromTwurple(twitchReward) - await reward.initializeReactivity() + try { + await reward.initializeFromTwurple(twitchReward) + await reward.initializeReactivity() + } catch (err) { + logger.error("Error Initializing Reward", reward.config.name, err) + } } } diff --git a/plugins/twitch/main/src/subscriptions.ts b/plugins/twitch/main/src/subscriptions.ts index 2298b0eb..0725a8ba 100644 --- a/plugins/twitch/main/src/subscriptions.ts +++ b/plugins/twitch/main/src/subscriptions.ts @@ -3,7 +3,7 @@ import { EventSubWsListener } from "@twurple/eventsub-ws" import { TwitchAccount } from "./twitch-auth" import { defineState, defineTrigger, usePluginLogger } from "castmate-core" import { Range } from "castmate-schema" -import { TwitchAPIService, onChannelAuth } from "./api-harness" +import { TwitchAPIService, onBotAuth, onChannelAuth } from "./api-harness" import { ViewerCache } from "./viewer-cache" import { TwitchViewer, TwitchViewerGroup } from "castmate-plugin-twitch-shared" import { inTwitchViewerGroup } from "./group" @@ -34,7 +34,7 @@ export function setupSubscriptions() { viewer: { type: TwitchViewer, required: true, default: "27082158" }, totalMonths: { type: Number, required: true, default: 5 }, streakMonths: { type: Number, required: true, default: 3 }, - durationMonths: { type: Number, required: true, default: 1 }, + //durationMonths: { type: Number, required: true, default: 1 }, message: { type: String, required: true, default: "" }, }, }, @@ -64,14 +64,14 @@ export function setupSubscriptions() { type: Object, properties: { subs: { type: Range, name: "Subs Gifted", required: true, default: { min: 1 } }, - group: { type: TwitchViewerGroup, name: "Viewer Group", required: true, default: {} }, + group: { type: TwitchViewerGroup, name: "Viewer Group", required: true }, }, }, context: { type: Object, properties: { gifter: { type: TwitchViewer, required: true, default: "27082158" }, - subs: { type: Number, required: true, default: 5 }, + subs: { type: Number, required: true, default: 2 }, }, }, async handle(config, context) { @@ -126,7 +126,7 @@ export function setupSubscriptions() { service.eventsub.onChannelSubscriptionMessage(channel.twitchId, async (event) => { logger.log( - "Sub Message Received: ", + "EventSub Sub Message Received: ", event.userDisplayName, event.userId, event.tier, @@ -135,7 +135,7 @@ export function setupSubscriptions() { event.streakMonths ) - let tier = 1 + /*let tier = 1 if (event.tier == "2000") { tier = 2 } else if (event.tier == "3000") { @@ -151,7 +151,7 @@ export function setupSubscriptions() { streakMonths: event.streakMonths ?? 1, durationMonths: event.durationMonths, message: event.messageText ?? "", - }) + })*/ }) service.eventsub.onChannelSubscriptionGift(channel.twitchId, async (event) => { @@ -172,4 +172,73 @@ export function setupSubscriptions() { updateSubscriberCount() }) + + onBotAuth((channel, service) => { + //Don't trust eventsub subscription messages. They're broken serverside and don't always trigger for first time subs. + service.chatClient.onSub(async (channel, user, subInfo, msg) => { + let tier = 1 + if (subInfo.plan == "2000") { + tier = 2 + } else if (subInfo.plan == "3000") { + tier = 3 + } + + logger.log( + "IRC Sub Message Received: ", + subInfo.displayName, + subInfo.userId, + subInfo.plan, + subInfo.months, + subInfo.streak + ) + + ViewerCache.getInstance() + .getResolvedViewer(subInfo.userId) + .then((viewer) => { + lastSubscriber.value = viewer + }) + + subscription({ + tier, + viewer: subInfo.userId, + totalMonths: subInfo.months, + streakMonths: subInfo.streak ?? 1, + //durationMonths: subInfo..durationMonths, + message: subInfo.message ?? "", + }) + }) + + service.chatClient.onResub(async (channel, user, subInfo, msg) => { + let tier = 1 + if (subInfo.plan == "2000") { + tier = 2 + } else if (subInfo.plan == "3000") { + tier = 3 + } + + logger.log( + "IRC ReSub Message Received: ", + subInfo.displayName, + subInfo.userId, + subInfo.plan, + subInfo.months, + subInfo.streak + ) + + ViewerCache.getInstance() + .getResolvedViewer(subInfo.userId) + .then((viewer) => { + lastSubscriber.value = viewer + }) + + subscription({ + tier, + viewer: subInfo.userId, + totalMonths: subInfo.months, + streakMonths: subInfo.streak ?? 1, + //durationMonths: subInfo..durationMonths, + message: subInfo.message ?? "", + }) + }) + }) } diff --git a/plugins/twitch/main/src/viewer-cache.ts b/plugins/twitch/main/src/viewer-cache.ts index 44fddf79..d4acfa2d 100644 --- a/plugins/twitch/main/src/viewer-cache.ts +++ b/plugins/twitch/main/src/viewer-cache.ts @@ -4,12 +4,15 @@ import { ReactiveRef, Service, defineRendererCallable, + measurePerf, + measurePerfFunc, onLoad, onUnload, reactiveRef, registerSchemaExpose, registerSchemaTemplate, registerSchemaUnexpose, + startPerfTime, template, usePluginLogger, } from "castmate-core" @@ -110,7 +113,9 @@ export function setupViewerCache() { }) onChannelAuth(async () => { + const perf = startPerfTime("Viewer Cache Init") await ViewerCache.getInstance().resetCache() + perf.stop(logger) }) } @@ -202,22 +207,25 @@ export const ViewerCache = Service( this.chatterQueryTimer = setTimeout(() => this.updateChatterList(), 60000) } + //@measurePerf private async updateChatterList() { - const newChatters = new Map() - - //TODO: Check if the bot account is active and has moderator privledges, that would give us a guilt free 800 queries - - // Each page can be 1000, so theoretically this will break everything if you have close to 800,000 concurrent viewers - // So.. for now we won't worry about it, but if we get some sort of huge event using it... Put some work in here? - const query = TwitchAccount.channel.apiClient.chat.getChattersPaginated(TwitchAccount.channel.twitchId) - for await (const chatter of query) { - const cached = this.getOrCreate(chatter.userId) - this.updateNameCache(cached, chatter.userDisplayName) - cached.lastSeen = Date.now() - newChatters.set(chatter.userId, cached) - } + return await measurePerfFunc(async () => { + const newChatters = new Map() + + //TODO: Check if the bot account is active and has moderator privledges, that would give us a guilt free 800 queries + + // Each page can be 1000, so theoretically this will break everything if you have close to 800,000 concurrent viewers + // So.. for now we won't worry about it, but if we get some sort of huge event using it... Put some work in here? + const query = TwitchAccount.channel.apiClient.chat.getChattersPaginated(TwitchAccount.channel.twitchId) + for await (const chatter of query) { + const cached = this.getOrCreate(chatter.userId) + this.updateNameCache(cached, chatter.userDisplayName) + cached.lastSeen = Date.now() + newChatters.set(chatter.userId, cached) + } - this.chatters = newChatters + this.chatters = newChatters + }, "updateChatterList")() } private get(userId: string) { @@ -502,53 +510,58 @@ export const ViewerCache = Service( } async getResolvedViewers(userIds: string[]): Promise { - const neededSubIds: string[] = [] - const neededColorIds: string[] = [] - const neededUserInfoIds: string[] = [] - const neededFollowerIds: string[] = [] + const perf = startPerfTime("Resolve Viewer") + try { + const neededSubIds: string[] = [] + const neededColorIds: string[] = [] + const neededUserInfoIds: string[] = [] + const neededFollowerIds: string[] = [] - const cachedUsers = userIds.map((id) => this.getOrCreate(id)) + const cachedUsers = userIds.map((id) => this.getOrCreate(id)) - for (const cached of cachedUsers) { - if (cached.subbed == null || (cached.subbed === true && cached.sub == null)) { - neededSubIds.push(cached.id) - } + for (const cached of cachedUsers) { + if (cached.subbed == null || (cached.subbed === true && cached.sub == null)) { + neededSubIds.push(cached.id) + } - if (cached.color == null) { - neededColorIds.push(cached.id) - } + if (cached.color == null) { + neededColorIds.push(cached.id) + } - if (cached.profilePicture == null || cached.description == null) { - neededUserInfoIds.push(cached.id) - } + if (cached.profilePicture == null || cached.description == null) { + neededUserInfoIds.push(cached.id) + } - if (cached.following == null) { - neededFollowerIds.push(cached.id) + if (cached.following == null) { + neededFollowerIds.push(cached.id) + } } - } - const queryPromises: Promise[] = [] + const queryPromises: Promise[] = [] - if (neededColorIds.length > 0) { - queryPromises.push(this.queryColor(...neededColorIds)) - } + if (neededColorIds.length > 0) { + queryPromises.push(this.queryColor(...neededColorIds)) + } - if (neededFollowerIds.length > 0) { - queryPromises.push(this.queryFollowing(...neededFollowerIds)) - } + if (neededFollowerIds.length > 0) { + queryPromises.push(this.queryFollowing(...neededFollowerIds)) + } - if (neededSubIds.length > 0) { - queryPromises.push(this.querySubInfo(...neededSubIds)) - } + if (neededSubIds.length > 0) { + queryPromises.push(this.querySubInfo(...neededSubIds)) + } - if (neededUserInfoIds.length > 0) { - queryPromises.push(this.queryUserInfo(...neededUserInfoIds)) - } + if (neededUserInfoIds.length > 0) { + queryPromises.push(this.queryUserInfo(...neededUserInfoIds)) + } - await Promise.all(queryPromises) + await Promise.all(queryPromises) - //Safe to cast here since we've resolved everything - return cachedUsers as TwitchViewer[] + //Safe to cast here since we've resolved everything + return cachedUsers as TwitchViewer[] + } finally { + perf.stop(logger) + } } async getDisplayDataByName(name: string) { diff --git a/plugins/twitch/overlay/tsconfig.json b/plugins/twitch/overlay/tsconfig.json index 9ef94822..acdc3196 100644 --- a/plugins/twitch/overlay/tsconfig.json +++ b/plugins/twitch/overlay/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/twitch/renderer/tsconfig.json b/plugins/twitch/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/twitch/renderer/tsconfig.json +++ b/plugins/twitch/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/variables/renderer/tsconfig.json b/plugins/variables/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/variables/renderer/tsconfig.json +++ b/plugins/variables/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/voicemod/renderer/tsconfig.json b/plugins/voicemod/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/voicemod/renderer/tsconfig.json +++ b/plugins/voicemod/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */ diff --git a/plugins/wyze/renderer/tsconfig.json b/plugins/wyze/renderer/tsconfig.json index 123eb7c9..aac47dd1 100644 --- a/plugins/wyze/renderer/tsconfig.json +++ b/plugins/wyze/renderer/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */