Created
June 24, 2025 17:33
-
-
Save nandordudas/2cc7961dd98d0c47371930fb39bd2ed5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { Alarms } from 'webextension-polyfill' | |
import { consola } from 'consola' | |
import { alarms } from 'webextension-polyfill' | |
interface ScheduledEmail { | |
readonly id: string | |
scheduledTime: number | |
status: 'pending' | 'sent' | 'failed' | |
readonly created: number | |
} | |
class DailyScheduler { | |
readonly #alarmName = 'daily-scheduler' | |
constructor() { | |
void this.#init() | |
} | |
async #init(): Promise<void> { | |
alarms.onAlarm.addListener(this.#handleAlarm) | |
await this.#createDailyAlarm() | |
} | |
async #createDailyAlarm(): Promise<void> { | |
await alarms.clear(this.#alarmName) | |
const now = new Date() | |
const eightAM = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 8, 0, 0) | |
if (eightAM <= now) | |
eightAM.setDate(eightAM.getDate() + 1) | |
alarms.create(this.#alarmName, { | |
// when: eightAM.getTime(), | |
delayInMinutes: 0.167 * 4.5, // 10 seconds = 0.167 minutes, original 24 hours = 1440 minutes | |
periodInMinutes: 0.167 * 4.5, | |
}) | |
consola.log('Daily scheduler set for 45 seconds interval') | |
// consola.log(`Daily scheduler set for: ${eightAM.toLocaleString()}`) | |
} | |
#handleAlarm = async (alarm: Alarms.Alarm): Promise<void> => { | |
if (alarm.name === this.#alarmName) | |
await this.#performDailyTasks() | |
} | |
async #performDailyTasks(): Promise<void> { | |
consola.log('π Daily scheduler running - fetching email configs') | |
const emails: ScheduledEmail[] = [] | |
const now = Date.now() | |
for (let i = 0; i < 5; ++i) { | |
const scheduledTime = now + Math.random() * 30_000 | |
emails.push({ | |
id: `email-${Date.now()}-${i}`, | |
scheduledTime, | |
status: 'pending', | |
created: now, | |
}) | |
} | |
const { scheduledEmails = [] } = await messenger.storage.local.get('scheduledEmails') as { | |
scheduledEmails: ScheduledEmail[] | |
} | |
scheduledEmails.push(...emails) | |
await messenger.storage.local.set({ scheduledEmails }) | |
consola.log(`π§ Scheduled ${emails.length} emails for the day`) | |
emails.forEach((email) => { | |
consola.log(` - Email ${email.id} scheduled for ${new Date(email.scheduledTime).toLocaleTimeString()}`) | |
}) | |
} | |
} | |
class FiveMinuteScheduler { | |
readonly #alarmName = 'five-minute-scheduler' | |
constructor() { | |
void this.#init() | |
} | |
async #init(): Promise<void> { | |
alarms.onAlarm.addListener(this.#handleAlarm) | |
await this.#createFiveMinuteAlarm() | |
} | |
async #createFiveMinuteAlarm(): Promise<void> { | |
await alarms.clear(this.#alarmName) | |
alarms.create(this.#alarmName, { | |
delayInMinutes: 0.033 * 2.5, // 2 seconds = 0.033 minutes, original 5 | |
periodInMinutes: 0.033 * 2.5, | |
}) | |
consola.log('Five-minute scheduler set for 5 seconds interval') | |
} | |
#handleAlarm = async (alarm: Alarms.Alarm): Promise<void> => { | |
if (alarm.name === this.#alarmName) | |
await this.#checkScheduledEmails() | |
} | |
async #checkScheduledEmails(): Promise<void> { | |
const { scheduledEmails = [] } = await messenger.storage.local.get('scheduledEmails') as { | |
scheduledEmails: ScheduledEmail[] | |
} | |
const now = Date.now() | |
const emailsToSend = scheduledEmails.filter((email: ScheduledEmail) => { | |
return email.status === 'pending' && email.scheduledTime <= now | |
}) | |
if (emailsToSend.length === 0) | |
return consola.log('β° Checking scheduled emails... none ready to send') | |
consola.log(`π€ Found ${emailsToSend.length} emails ready to send`) | |
for (const email of emailsToSend) { | |
email.status = 'sent' | |
consola.log(`β Sent email: ${email.id}`) | |
} | |
await messenger.storage.local.set({ scheduledEmails }) | |
consola.log(`π¬ Successfully sent ${emailsToSend.length} emails`) | |
} | |
} | |
class TestScheduler { | |
static readonly #symbol: unique symbol = Symbol.for('TestScheduler') | |
static create(): TestScheduler { | |
return new TestScheduler(this.#symbol) | |
} | |
readonly #dailyScheduler = new DailyScheduler() | |
readonly #fiveMinuteScheduler = new FiveMinuteScheduler() | |
protected constructor(symbol: symbol) { | |
if (symbol !== TestScheduler.#symbol) | |
throw new Error('Cannot create instance of TestScheduler') | |
consola.log('π Test Scheduler initialized') | |
consola.log(' - Daily scheduler: 10 seconds', this.#dailyScheduler) | |
consola.log(' - Email checker: 2 seconds', this.#fiveMinuteScheduler) | |
} | |
} | |
TestScheduler.create() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment