From d4081a4f5174331a3dc4533ac9951efe0c28e775 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Fri, 3 May 2024 18:21:06 +0100 Subject: [PATCH 1/5] Create timer helper --- .gitignore | 3 +- package-lock.json | 23 +++++++++++++ package.json | 1 + src/bot.ts | 12 ++++++- src/helpers/TimerHelper.ts | 67 ++++++++++++++++++++++++++++++++++++++ src/timers/GiveCurrency.ts | 9 +++++ 6 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 src/helpers/TimerHelper.ts create mode 100644 src/timers/GiveCurrency.ts diff --git a/.gitignore b/.gitignore index aecb458..9326cc8 100644 --- a/.gitignore +++ b/.gitignore @@ -108,4 +108,5 @@ config.json ormconfig.json gdrive-credentials.json data/ -*.db \ No newline at end of file +*.db +.temp/ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e93e59f..7f521cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@types/uuid": "^9.0.0", "body-parser": "^1.20.2", "clone-deep": "^4.0.1", + "cron": "^3.1.7", "discord.js": "^14.3.0", "dotenv": "^16.0.0", "express": "^4.18.2", @@ -1895,6 +1896,11 @@ "@types/node": "*" } }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==" + }, "node_modules/@types/mime": { "version": "3.0.4", "license": "MIT" @@ -3841,6 +3847,15 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/cron": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/cron/-/cron-3.1.7.tgz", + "integrity": "sha512-tlBg7ARsAMQLzgwqVxy8AZl/qlTc5nibqYwtNGoCrd+cV+ugI+tvZC1oT/8dFH8W455YrywGykx/KMmAqOr7Jw==", + "dependencies": { + "@types/luxon": "~3.4.0", + "luxon": "~3.4.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "license": "MIT", @@ -7700,6 +7715,14 @@ "node": ">=10" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/magic-bytes.js": { "version": "1.6.0", "license": "MIT" diff --git a/package.json b/package.json index 178f288..004cfb8 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "@types/uuid": "^9.0.0", "body-parser": "^1.20.2", "clone-deep": "^4.0.1", + "cron": "^3.1.7", "discord.js": "^14.3.0", "dotenv": "^16.0.0", "express": "^4.18.2", diff --git a/src/bot.ts b/src/bot.ts index 87008c5..f75bbff 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -4,6 +4,8 @@ import { IntentsBitField } from "discord.js"; import Registry from "./registry"; import { existsSync } from "fs"; import { ExecException, exec } from "child_process"; +import TimerHelper from "./helpers/TimerHelper"; +import GiveCurrency from "./timers/GiveCurrency"; dotenv.config(); @@ -56,4 +58,12 @@ if (!existsSync(`${process.env.DATA_DIR}/cards`) && process.env.GDRIVESYNC_AUTO }); } -client.start(); \ No newline at end of file +client.start(); + +const timerHelper = new TimerHelper(); + +const id = timerHelper.AddTimer('* * * * * *', 'Europe/London', GiveCurrency); + +console.log(`Timer Created: ${id}`); + +timerHelper.StartAllTimers(); \ No newline at end of file diff --git a/src/helpers/TimerHelper.ts b/src/helpers/TimerHelper.ts new file mode 100644 index 0000000..3d3f7e9 --- /dev/null +++ b/src/helpers/TimerHelper.ts @@ -0,0 +1,67 @@ +import { CronJob } from "cron"; +import { v4 } from "uuid"; + +interface Timer { + id: string; + job: CronJob; + context: Map; +} + +export default class TimerHelper { + private _timers: Timer[]; + + constructor() { + this._timers = []; + } + + public AddTimer( + cronTime: string, + timeZone: string, + onTick: ((context: Map) => void) | ((context: Map) => Promise)): string { + const context = new Map(); + + const job = new CronJob( + cronTime, + () => { + onTick(context); + }, + null, + false, + timeZone, + ); + + const id = v4(); + + this._timers.push({ + id, + job, + context, + }); + + return id; + } + + public StartAllTimers() { + this._timers.forEach(timer => timer.job.start()); + } + + public StopAllTimers() { + this._timers.forEach(timer => timer.job.stop()); + } + + public StartTimer(id: string) { + const timer = this._timers.find(x => x.id == id); + + if (!timer) return; + + timer.job.start(); + } + + public StopTimer(id: string) { + const timer = this._timers.find(x => x.id == id); + + if (!timer) return; + + timer.job.stop(); + } +} \ No newline at end of file diff --git a/src/timers/GiveCurrency.ts b/src/timers/GiveCurrency.ts new file mode 100644 index 0000000..d9e40fa --- /dev/null +++ b/src/timers/GiveCurrency.ts @@ -0,0 +1,9 @@ +export default function GiveCurrency(context: Map) { + let calledTimes = context.get('times') as number; + + if (!calledTimes) calledTimes = 1; + + console.log(`This has been called ${calledTimes} times!`); + + context.set('times', calledTimes + 1); +} \ No newline at end of file -- 2.43.4 From c1ca37283c1d4a29f21472c05d631a4601926c25 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Mon, 6 May 2024 17:09:59 +0100 Subject: [PATCH 2/5] Add give currency timer --- src/bot.ts | 10 +--------- src/client/client.ts | 11 ++++++++++- src/contracts/AppBaseEntity.ts | 6 ++++++ src/database/entities/app/User.ts | 4 ++-- src/helpers/TimerHelper.ts | 19 ++++++++++++++++--- src/registry.ts | 4 ++++ src/timers/GiveCurrency.ts | 17 ++++++++++++----- 7 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/bot.ts b/src/bot.ts index f75bbff..41ec193 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -58,12 +58,4 @@ if (!existsSync(`${process.env.DATA_DIR}/cards`) && process.env.GDRIVESYNC_AUTO }); } -client.start(); - -const timerHelper = new TimerHelper(); - -const id = timerHelper.AddTimer('* * * * * *', 'Europe/London', GiveCurrency); - -console.log(`Timer Created: ${id}`); - -timerHelper.StartAllTimers(); \ No newline at end of file +client.start(); \ No newline at end of file diff --git a/src/client/client.ts b/src/client/client.ts index c694950..2dd9a29 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -14,6 +14,8 @@ import Webhooks from "../webhooks"; import CardMetadataFunction from "../Functions/CardMetadataFunction"; import { SeriesMetadata } from "../contracts/SeriesMetadata"; import AppLogger from "./appLogger"; +import TimerHelper from "../helpers/TimerHelper"; +import GiveCurrency from "../timers/GiveCurrency"; export class CoreClient extends Client { private static _commandItems: ICommandItem[]; @@ -23,6 +25,7 @@ export class CoreClient extends Client { private _events: Events; private _util: Util; private _webhooks: Webhooks; + private _timerHelper: TimerHelper; public static ClaimId: string; public static Environment: Environment; @@ -59,6 +62,7 @@ export class CoreClient extends Client { this._events = new Events(); this._util = new Util(); this._webhooks = new Webhooks(); + this._timerHelper = new TimerHelper(); AppLogger.LogInfo("Client", `Environment: ${CoreClient.Environment}`); @@ -72,7 +76,12 @@ export class CoreClient extends Client { } await AppDataSource.initialize() - .then(() => AppLogger.LogInfo("Client", "App Data Source Initialised")) + .then(() => { + AppLogger.LogInfo("Client", "App Data Source Initialised"); + + const timerId = this._timerHelper.AddTimer("*/30 * * * * *", "Europe/London", GiveCurrency, false); + this._timerHelper.StartTimer(timerId); + }) .catch(err => { AppLogger.LogError("Client", "App Data Source Initialisation Failed"); AppLogger.LogError("Client", err); diff --git a/src/contracts/AppBaseEntity.ts b/src/contracts/AppBaseEntity.ts index b9ca565..3eb9684 100644 --- a/src/contracts/AppBaseEntity.ts +++ b/src/contracts/AppBaseEntity.ts @@ -27,6 +27,12 @@ export default class AppBaseEntity { await repository.save(entity); } + public static async SaveAll(target: EntityTarget, entities: DeepPartial[]): Promise { + const repository = AppDataSource.getRepository(target); + + await repository.save(entities); + } + public static async Remove(target: EntityTarget, entity: T): Promise { const repository = AppDataSource.getRepository(target); diff --git a/src/database/entities/app/User.ts b/src/database/entities/app/User.ts index 649c1c1..a909552 100644 --- a/src/database/entities/app/User.ts +++ b/src/database/entities/app/User.ts @@ -13,8 +13,8 @@ export default class User extends AppBaseEntity { @Column() Currency: number; - public UpdateCurrency(currency: number) { - this.Currency = currency; + public AddCurrency(amount: number) { + this.Currency += amount; } public RemoveCurrency(amount: number): boolean { diff --git a/src/helpers/TimerHelper.ts b/src/helpers/TimerHelper.ts index 3d3f7e9..c5b1071 100644 --- a/src/helpers/TimerHelper.ts +++ b/src/helpers/TimerHelper.ts @@ -5,6 +5,8 @@ interface Timer { id: string; job: CronJob; context: Map; + onTick: ((context: Map) => void) | ((context: Map) => Promise); + runOnStart: boolean; } export default class TimerHelper { @@ -17,7 +19,8 @@ export default class TimerHelper { public AddTimer( cronTime: string, timeZone: string, - onTick: ((context: Map) => void) | ((context: Map) => Promise)): string { + onTick: ((context: Map) => void) | ((context: Map) => Promise), + runOnStart: boolean = false): string { const context = new Map(); const job = new CronJob( @@ -36,13 +39,15 @@ export default class TimerHelper { id, job, context, + onTick, + runOnStart, }); return id; } public StartAllTimers() { - this._timers.forEach(timer => timer.job.start()); + this._timers.forEach(timer => this.StartJob(timer)); } public StopAllTimers() { @@ -54,7 +59,7 @@ export default class TimerHelper { if (!timer) return; - timer.job.start(); + this.StartJob(timer); } public StopTimer(id: string) { @@ -64,4 +69,12 @@ export default class TimerHelper { timer.job.stop(); } + + private StartJob(timer: Timer) { + timer.job.start(); + + if (timer.runOnStart) { + timer.onTick(timer.context); + } + } } \ No newline at end of file diff --git a/src/registry.ts b/src/registry.ts index bb68685..eee78f4 100644 --- a/src/registry.ts +++ b/src/registry.ts @@ -52,4 +52,8 @@ export default class Registry { CoreClient.RegisterButtonEvent("series", new SeriesEvent()); CoreClient.RegisterButtonEvent("trade", new TradeButtonEvent()); } + + public static RegisterTimers() { + + } } \ No newline at end of file diff --git a/src/timers/GiveCurrency.ts b/src/timers/GiveCurrency.ts index d9e40fa..9a0d28a 100644 --- a/src/timers/GiveCurrency.ts +++ b/src/timers/GiveCurrency.ts @@ -1,9 +1,16 @@ -export default function GiveCurrency(context: Map) { - let calledTimes = context.get('times') as number; +import AppLogger from "../client/appLogger"; +import User from "../database/entities/app/User"; - if (!calledTimes) calledTimes = 1; +export default async function GiveCurrency(context: Map) { + AppLogger.LogInfo("Timers/GiveCurrency", "Giving currency to every known user"); - console.log(`This has been called ${calledTimes} times!`); + const users = await User.FetchAll(User); - context.set('times', calledTimes + 1); + for (const user of users) { + user.AddCurrency(5); + } + + User.SaveAll(User, users); + + AppLogger.LogInfo("Timers/GiveCurrency", `Successfully gave +5 currency to ${users.length} users`); } \ No newline at end of file -- 2.43.4 From 25d099928f26e27bfda60323be11c509940904b8 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 15 May 2024 17:55:17 +0100 Subject: [PATCH 3/5] Fix requested changes --- src/bot.ts | 3 --- src/registry.ts | 8 -------- 2 files changed, 11 deletions(-) diff --git a/src/bot.ts b/src/bot.ts index 41ec193..e5e25a3 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -4,8 +4,6 @@ import { IntentsBitField } from "discord.js"; import Registry from "./registry"; import { existsSync } from "fs"; import { ExecException, exec } from "child_process"; -import TimerHelper from "./helpers/TimerHelper"; -import GiveCurrency from "./timers/GiveCurrency"; dotenv.config(); @@ -39,7 +37,6 @@ const client = new CoreClient([ ]); Registry.RegisterCommands(); -Registry.RegisterEvents(); Registry.RegisterButtonEvents(); if (!existsSync(`${process.env.DATA_DIR}/cards`) && process.env.GDRIVESYNC_AUTO && process.env.GDRIVESYNC_AUTO == "true") { diff --git a/src/registry.ts b/src/registry.ts index eee78f4..3ea5528 100644 --- a/src/registry.ts +++ b/src/registry.ts @@ -41,10 +41,6 @@ export default class Registry { CoreClient.RegisterCommand("droprarity", new Droprarity(), Environment.Test); } - public static RegisterEvents() { - - } - public static RegisterButtonEvents() { CoreClient.RegisterButtonEvent("claim", new Claim()); CoreClient.RegisterButtonEvent("inventory", new InventoryButtonEvent()); @@ -52,8 +48,4 @@ export default class Registry { CoreClient.RegisterButtonEvent("series", new SeriesEvent()); CoreClient.RegisterButtonEvent("trade", new TradeButtonEvent()); } - - public static RegisterTimers() { - - } } \ No newline at end of file -- 2.43.4 From 0504598518c3917af18f49bbc2cc5c42de3f6d70 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 15 May 2024 17:59:38 +0100 Subject: [PATCH 4/5] Remove duplicate function --- src/database/entities/app/User.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/database/entities/app/User.ts b/src/database/entities/app/User.ts index cf13160..a909552 100644 --- a/src/database/entities/app/User.ts +++ b/src/database/entities/app/User.ts @@ -17,10 +17,6 @@ export default class User extends AppBaseEntity { this.Currency += amount; } - public AddCurrency(amount: number) { - this.Currency += amount; - } - public RemoveCurrency(amount: number): boolean { if (this.Currency < amount) return false; -- 2.43.4 From 30c62bd94ddad82ce31cb1e4afd903b0c7b4df29 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 15 May 2024 18:06:19 +0100 Subject: [PATCH 5/5] Fix linting issues --- src/helpers/TimerHelper.ts | 9 +++++---- src/timers/GiveCurrency.ts | 2 +- src/type/primitive.ts | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 src/type/primitive.ts diff --git a/src/helpers/TimerHelper.ts b/src/helpers/TimerHelper.ts index c5b1071..535a6a7 100644 --- a/src/helpers/TimerHelper.ts +++ b/src/helpers/TimerHelper.ts @@ -1,11 +1,12 @@ import { CronJob } from "cron"; import { v4 } from "uuid"; +import { Primitive } from "../type/primitive"; interface Timer { id: string; job: CronJob; - context: Map; - onTick: ((context: Map) => void) | ((context: Map) => Promise); + context: Map; + onTick: ((context: Map) => void) | ((context: Map) => Promise); runOnStart: boolean; } @@ -19,9 +20,9 @@ export default class TimerHelper { public AddTimer( cronTime: string, timeZone: string, - onTick: ((context: Map) => void) | ((context: Map) => Promise), + onTick: ((context: Map) => void) | ((context: Map) => Promise), runOnStart: boolean = false): string { - const context = new Map(); + const context = new Map(); const job = new CronJob( cronTime, diff --git a/src/timers/GiveCurrency.ts b/src/timers/GiveCurrency.ts index 9a0d28a..ad1a21a 100644 --- a/src/timers/GiveCurrency.ts +++ b/src/timers/GiveCurrency.ts @@ -1,7 +1,7 @@ import AppLogger from "../client/appLogger"; import User from "../database/entities/app/User"; -export default async function GiveCurrency(context: Map) { +export default async function GiveCurrency() { AppLogger.LogInfo("Timers/GiveCurrency", "Giving currency to every known user"); const users = await User.FetchAll(User); diff --git a/src/type/primitive.ts b/src/type/primitive.ts new file mode 100644 index 0000000..b1e143b --- /dev/null +++ b/src/type/primitive.ts @@ -0,0 +1 @@ +export type Primitive = string | number | boolean; \ No newline at end of file -- 2.43.4