117 lines
2.6 KiB
TypeScript
117 lines
2.6 KiB
TypeScript
export type EventType = "message" | "heartbeat" | "cron" | "hook" | "webhook";
|
|
|
|
export type HookType = "startup" | "agent_begin" | "agent_stop" | "shutdown";
|
|
|
|
export interface MessagePayload {
|
|
prompt: { text: string; channelId: string; userId: string; guildId: string | null };
|
|
}
|
|
|
|
export interface HeartbeatPayload {
|
|
instruction: string;
|
|
checkName: string;
|
|
}
|
|
|
|
export interface CronPayload {
|
|
instruction: string;
|
|
jobName: string;
|
|
}
|
|
|
|
export interface HookPayload {
|
|
hookType: HookType;
|
|
instruction?: string;
|
|
}
|
|
|
|
export type EventPayload = MessagePayload | HeartbeatPayload | CronPayload | HookPayload;
|
|
|
|
export interface Event {
|
|
id: number;
|
|
type: EventType;
|
|
payload: EventPayload;
|
|
timestamp: Date;
|
|
source: string;
|
|
}
|
|
|
|
export class EventQueue {
|
|
private queue: Event[] = [];
|
|
private nextId = 1;
|
|
private maxDepth: number;
|
|
private handler: ((event: Event) => Promise<void>) | null = null;
|
|
private processing = false;
|
|
private drainResolvers: Array<() => void> = [];
|
|
|
|
constructor(maxDepth: number) {
|
|
this.maxDepth = maxDepth;
|
|
}
|
|
|
|
enqueue(event: Omit<Event, "id" | "timestamp">): Event | null {
|
|
if (this.queue.length >= this.maxDepth) {
|
|
return null;
|
|
}
|
|
|
|
const fullEvent: Event = {
|
|
...event,
|
|
id: this.nextId++,
|
|
timestamp: new Date(),
|
|
};
|
|
|
|
this.queue.push(fullEvent);
|
|
this.processNext();
|
|
return fullEvent;
|
|
}
|
|
|
|
dequeue(): Event | undefined {
|
|
return this.queue.shift();
|
|
}
|
|
|
|
size(): number {
|
|
return this.queue.length;
|
|
}
|
|
|
|
onEvent(handler: (event: Event) => Promise<void>): void {
|
|
this.handler = handler;
|
|
this.processNext();
|
|
}
|
|
|
|
drain(): Promise<void> {
|
|
if (this.queue.length === 0 && !this.processing) {
|
|
return Promise.resolve();
|
|
}
|
|
return new Promise<void>((resolve) => {
|
|
this.drainResolvers.push(resolve);
|
|
});
|
|
}
|
|
|
|
private processNext(): void {
|
|
if (this.processing || !this.handler || this.queue.length === 0) {
|
|
return;
|
|
}
|
|
|
|
this.processing = true;
|
|
const event = this.queue.shift()!;
|
|
|
|
this.handler(event)
|
|
.then(() => {
|
|
this.processing = false;
|
|
if (this.queue.length === 0) {
|
|
const resolvers = this.drainResolvers.splice(0);
|
|
for (const resolve of resolvers) {
|
|
resolve();
|
|
}
|
|
} else {
|
|
this.processNext();
|
|
}
|
|
})
|
|
.catch(() => {
|
|
this.processing = false;
|
|
if (this.queue.length === 0) {
|
|
const resolvers = this.drainResolvers.splice(0);
|
|
for (const resolve of resolvers) {
|
|
resolve();
|
|
}
|
|
} else {
|
|
this.processNext();
|
|
}
|
|
});
|
|
}
|
|
}
|