150 lines
4.1 KiB
TypeScript
150 lines
4.1 KiB
TypeScript
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
export interface IFaxBoxConfig {
|
|
id: string;
|
|
enabled: boolean;
|
|
maxMessages?: number;
|
|
}
|
|
|
|
export interface IFaxMessage {
|
|
id: string;
|
|
boxId: string;
|
|
callerNumber?: string;
|
|
timestamp: number;
|
|
fileName: string;
|
|
completionCode?: number | null;
|
|
completionLabel?: string | null;
|
|
pageCount?: number;
|
|
bitRate?: number;
|
|
}
|
|
|
|
export class FaxBoxManager {
|
|
private boxes = new Map<string, IFaxBoxConfig>();
|
|
private readonly basePath: string;
|
|
private readonly log: (msg: string) => void;
|
|
|
|
constructor(log: (msg: string) => void) {
|
|
this.basePath = path.join(process.cwd(), '.nogit', 'fax', 'inboxes');
|
|
this.log = log;
|
|
}
|
|
|
|
init(faxBoxConfigs: IFaxBoxConfig[]): void {
|
|
this.boxes.clear();
|
|
|
|
for (const cfg of faxBoxConfigs) {
|
|
cfg.enabled ??= true;
|
|
cfg.maxMessages ??= 50;
|
|
this.boxes.set(cfg.id, cfg);
|
|
}
|
|
|
|
fs.mkdirSync(this.basePath, { recursive: true });
|
|
this.log(`[faxbox] initialized ${this.boxes.size} fax box(es)`);
|
|
}
|
|
|
|
getBox(boxId: string): IFaxBoxConfig | null {
|
|
return this.boxes.get(boxId) ?? null;
|
|
}
|
|
|
|
getBoxDir(boxId: string): string {
|
|
return path.join(this.basePath, boxId);
|
|
}
|
|
|
|
addMessage(
|
|
boxId: string,
|
|
info: {
|
|
callerNumber?: string;
|
|
fileName: string;
|
|
completionCode?: number | null;
|
|
completionLabel?: string | null;
|
|
pageCount?: number;
|
|
bitRate?: number;
|
|
},
|
|
): void {
|
|
const msg: IFaxMessage = {
|
|
id: crypto.randomUUID(),
|
|
boxId,
|
|
callerNumber: info.callerNumber,
|
|
timestamp: Date.now(),
|
|
fileName: path.basename(info.fileName),
|
|
completionCode: info.completionCode ?? null,
|
|
completionLabel: info.completionLabel ?? null,
|
|
pageCount: info.pageCount,
|
|
bitRate: info.bitRate,
|
|
};
|
|
this.saveMessage(msg);
|
|
}
|
|
|
|
saveMessage(msg: IFaxMessage): void {
|
|
const boxDir = this.getBoxDir(msg.boxId);
|
|
fs.mkdirSync(boxDir, { recursive: true });
|
|
|
|
const messages = this.loadMessages(msg.boxId);
|
|
messages.unshift(msg);
|
|
|
|
const box = this.boxes.get(msg.boxId);
|
|
const maxMessages = box?.maxMessages ?? 50;
|
|
while (messages.length > maxMessages) {
|
|
const old = messages.pop()!;
|
|
const oldPath = path.join(boxDir, old.fileName);
|
|
try {
|
|
if (fs.existsSync(oldPath)) fs.unlinkSync(oldPath);
|
|
} catch {}
|
|
}
|
|
|
|
this.writeMessages(msg.boxId, messages);
|
|
this.log(`[faxbox] saved fax ${msg.id} in box "${msg.boxId}" (${msg.fileName})`);
|
|
}
|
|
|
|
getMessages(boxId: string): IFaxMessage[] {
|
|
return this.loadMessages(boxId);
|
|
}
|
|
|
|
getMessage(boxId: string, messageId: string): IFaxMessage | null {
|
|
return this.loadMessages(boxId).find((m) => m.id === messageId) ?? null;
|
|
}
|
|
|
|
getMessageFilePath(boxId: string, messageId: string): string | null {
|
|
const msg = this.getMessage(boxId, messageId);
|
|
if (!msg) return null;
|
|
const filePath = path.join(this.getBoxDir(boxId), msg.fileName);
|
|
return fs.existsSync(filePath) ? filePath : null;
|
|
}
|
|
|
|
deleteMessage(boxId: string, messageId: string): boolean {
|
|
const messages = this.loadMessages(boxId);
|
|
const idx = messages.findIndex((m) => m.id === messageId);
|
|
if (idx === -1) return false;
|
|
|
|
const msg = messages[idx];
|
|
const filePath = path.join(this.getBoxDir(boxId), msg.fileName);
|
|
try {
|
|
if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
|
|
} catch {}
|
|
|
|
messages.splice(idx, 1);
|
|
this.writeMessages(boxId, messages);
|
|
return true;
|
|
}
|
|
|
|
private messagesPath(boxId: string): string {
|
|
return path.join(this.getBoxDir(boxId), 'messages.json');
|
|
}
|
|
|
|
private loadMessages(boxId: string): IFaxMessage[] {
|
|
const filePath = this.messagesPath(boxId);
|
|
try {
|
|
if (!fs.existsSync(filePath)) return [];
|
|
return JSON.parse(fs.readFileSync(filePath, 'utf8')) as IFaxMessage[];
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
private writeMessages(boxId: string, messages: IFaxMessage[]): void {
|
|
const boxDir = this.getBoxDir(boxId);
|
|
fs.mkdirSync(boxDir, { recursive: true });
|
|
fs.writeFileSync(this.messagesPath(boxId), JSON.stringify(messages, null, 2), 'utf8');
|
|
}
|
|
}
|