From f8ae5b70c0bdb39e6a64e94f01758ed6daea24fb Mon Sep 17 00:00:00 2001 From: Huskydog9988 <39809509+Huskydog9988@users.noreply.github.com> Date: Wed, 12 Mar 2025 18:34:36 -0400 Subject: [PATCH] automate twitch credential refresh --- nuxt.config.ts | 2 ++ server/internal/metadata/igdb.ts | 16 +++++++++++++--- server/internal/metadata/index.ts | 13 +++++++++++++ server/tasks/metadata/refreshCredentials.ts | 12 ++++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 server/tasks/metadata/refreshCredentials.ts diff --git a/nuxt.config.ts b/nuxt.config.ts index acda755..8e32a02 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -29,6 +29,8 @@ export default defineNuxtConfig({ scheduledTasks: { "0 * * * *": ["cleanup:invitations"], + // every two hours, check if creds need updating + "0 */2 * * *": ["metadata:refreshCredentials"], }, }, diff --git a/server/internal/metadata/igdb.ts b/server/internal/metadata/igdb.ts index 67823b2..f91930f 100644 --- a/server/internal/metadata/igdb.ts +++ b/server/internal/metadata/igdb.ts @@ -132,6 +132,7 @@ export class IGDBProvider implements MetadataProvider { private client_id: string; private client_secret: string; private access_token: string; + private access_token_expire: moment.Moment; constructor() { const client_id = process.env.IGDB_CLIENT_ID; @@ -148,6 +149,7 @@ export class IGDBProvider implements MetadataProvider { this.client_secret = client_secret; this.access_token = ""; + this.access_token_expire = moment(); this.authWithTwitch(); } @@ -167,9 +169,17 @@ export class IGDBProvider implements MetadataProvider { console.log(inspect(response.data)); this.access_token = response.data.access_token; - // TODO: handle token expiration, time in seconds is provided, on a long running server - // this WILL be an issue. Can use node timers, or maybe nuxt tasks? problem is - // that idk if tasks can be variable like twitch wants, expires_in is variable + this.access_token_expire = moment().add( + response.data.expires_in, + "seconds" + ); + } + + public async refreshCredentials() { + const futureTime = moment().add(1, "day"); + + // if the token expires before this future time (aka soon), refresh + if (this.access_token_expire.isBefore(futureTime)) this.authWithTwitch(); } private async request( diff --git a/server/internal/metadata/index.ts b/server/internal/metadata/index.ts index f986d8f..0b33fc3 100644 --- a/server/internal/metadata/index.ts +++ b/server/internal/metadata/index.ts @@ -51,6 +51,8 @@ export abstract class MetadataProvider { abstract fetchDeveloper( params: _FetchDeveloperMetadataParams ): Promise; + + abstract refreshCredentials?: () => void; } export class MetadataHandler { @@ -253,6 +255,17 @@ export class MetadataHandler { `No metadata provider found a ${databaseName} for "${query}"` ); } + + /** + * Refresh creds for all providers that need it + */ + public refreshCredentials() { + for (const provider of this.providers.values()) { + if (provider.refreshCredentials) { + provider.refreshCredentials(); + } + } + } } export const metadataHandler = new MetadataHandler(); diff --git a/server/tasks/metadata/refreshCredentials.ts b/server/tasks/metadata/refreshCredentials.ts new file mode 100644 index 0000000..fa654f5 --- /dev/null +++ b/server/tasks/metadata/refreshCredentials.ts @@ -0,0 +1,12 @@ +import { metadataHandler } from "~/server/plugins/metadata"; + +export default defineTask({ + meta: { + name: "metadata:refreshCredentials", + description: "Refresh credentials for metadata providers", + }, + run({ payload, context }) { + metadataHandler.refreshCredentials(); + return { result: "Success" }; + }, +});