102 lines
8.2 KiB
JavaScript
102 lines
8.2 KiB
JavaScript
import EventEmitter from 'events';
|
|
import { createHash } from 'crypto';
|
|
import { streamSSE } from 'hono/streaming';
|
|
import { ProductErrorCode } from './enums.js';
|
|
import { ProductError } from './errors.js';
|
|
import { logger } from '../commons/logger.js';
|
|
export class AbstractProduct extends EventEmitter {
|
|
async start(boss) {
|
|
try {
|
|
await this.onStart(boss);
|
|
}
|
|
catch (error) {
|
|
throw new ProductError(ProductErrorCode.START_FAILED, {
|
|
message: `Failed to start product ${this.id}: ${error.message}`,
|
|
originalError: error
|
|
});
|
|
}
|
|
}
|
|
async onStart(boss) {
|
|
// Optional hook for subclasses
|
|
}
|
|
async stop() {
|
|
try {
|
|
await this.onStop();
|
|
}
|
|
catch (error) {
|
|
throw new ProductError(ProductErrorCode.STOP_FAILED, {
|
|
message: `Failed to stop product ${this.id}: ${error.message}`,
|
|
originalError: error
|
|
});
|
|
}
|
|
}
|
|
async onStop() {
|
|
// Optional hook
|
|
}
|
|
async pause() {
|
|
// No-op for now as we removed pgboss
|
|
}
|
|
async resume() {
|
|
// No-op for now as we removed pgboss
|
|
}
|
|
async handleStream(c, options) {
|
|
const { data, userId, forceRefresh, fetcher, cacheChecker } = options;
|
|
const inputHash = this.generateHash(data);
|
|
return streamSSE(c, async (stream) => {
|
|
try {
|
|
await stream.writeSSE({
|
|
event: 'progress',
|
|
data: JSON.stringify({ stage: 'starting', percent: 0 })
|
|
});
|
|
if (!forceRefresh && cacheChecker) {
|
|
await stream.writeSSE({
|
|
event: 'progress',
|
|
data: JSON.stringify({ stage: 'checking_cache', percent: 10 })
|
|
});
|
|
const cached = await cacheChecker(inputHash);
|
|
if (cached) {
|
|
for (let i = 0; i < cached.length; i++) {
|
|
await stream.writeSSE({
|
|
event: 'result',
|
|
data: JSON.stringify(cached[i])
|
|
});
|
|
}
|
|
await stream.writeSSE({
|
|
event: 'complete',
|
|
data: JSON.stringify({ total: cached.length, cached: true })
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
await stream.writeSSE({
|
|
event: 'progress',
|
|
data: JSON.stringify({ stage: 'fetching_from_api', percent: 20 })
|
|
});
|
|
const results = await fetcher(data, userId);
|
|
for (let i = 0; i < results.length; i++) {
|
|
await stream.writeSSE({
|
|
event: 'result',
|
|
data: JSON.stringify(results[i])
|
|
});
|
|
}
|
|
await stream.writeSSE({
|
|
event: 'complete',
|
|
data: JSON.stringify({ total: results.length, cached: false })
|
|
});
|
|
}
|
|
catch (error) {
|
|
logger.error(error, `[${this.id}] Stream error`);
|
|
await stream.writeSSE({
|
|
event: 'error',
|
|
data: JSON.stringify({ error: error.message || 'Internal Server Error' })
|
|
});
|
|
}
|
|
});
|
|
}
|
|
// Helper for hashing
|
|
generateHash(params) {
|
|
const normalizedInput = JSON.stringify(params, Object.keys(params).sort());
|
|
return createHash('sha256').update(normalizedInput).digest('hex');
|
|
}
|
|
}
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RQcm9kdWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Byb2R1Y3RzL0Fic3RyYWN0UHJvZHVjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLFlBQVksTUFBTSxRQUFRLENBQUM7QUFDbEMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUNwQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFM0MsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQzlDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDM0MsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBZ0I5QyxNQUFNLE9BQWdCLGVBQWdDLFNBQVEsWUFBWTtJQU90RSxLQUFLLENBQUMsS0FBSyxDQUFDLElBQVU7UUFDbEIsSUFBSSxDQUFDO1lBQ0QsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzdCLENBQUM7UUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO1lBQ2xCLE1BQU0sSUFBSSxZQUFZLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxFQUFFO2dCQUNsRCxPQUFPLEVBQUUsMkJBQTJCLElBQUksQ0FBQyxFQUFFLEtBQUssS0FBSyxDQUFDLE9BQU8sRUFBRTtnQkFDL0QsYUFBYSxFQUFFLEtBQUs7YUFDdkIsQ0FBQyxDQUFDO1FBQ1AsQ0FBQztJQUNMLENBQUM7SUFFUyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQVU7UUFDOUIsK0JBQStCO0lBQ25DLENBQUM7SUFFRCxLQUFLLENBQUMsSUFBSTtRQUNOLElBQUksQ0FBQztZQUNELE1BQU0sSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ3hCLENBQUM7UUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO1lBQ2xCLE1BQU0sSUFBSSxZQUFZLENBQUMsZ0JBQWdCLENBQUMsV0FBVyxFQUFFO2dCQUNqRCxPQUFPLEVBQUUsMEJBQTBCLElBQUksQ0FBQyxFQUFFLEtBQUssS0FBSyxDQUFDLE9BQU8sRUFBRTtnQkFDOUQsYUFBYSxFQUFFLEtBQUs7YUFDdkIsQ0FBQyxDQUFDO1FBQ1AsQ0FBQztJQUNMLENBQUM7SUFFUyxLQUFLLENBQUMsTUFBTTtRQUNsQixnQkFBZ0I7SUFDcEIsQ0FBQztJQUVELEtBQUssQ0FBQyxLQUFLO1FBQ1AscUNBQXFDO0lBQ3pDLENBQUM7SUFFRCxLQUFLLENBQUMsTUFBTTtRQUNSLHFDQUFxQztJQUN6QyxDQUFDO0lBRVMsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFNLEVBQUUsT0FBc0I7UUFDdkQsTUFBTSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsR0FBRyxPQUFPLENBQUM7UUFFdEUsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUUxQyxPQUFPLFNBQVMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ2pDLElBQUksQ0FBQztnQkFDRCxNQUFNLE1BQU0sQ0FBQyxRQUFRLENBQUM7b0JBQ2xCLEtBQUssRUFBRSxVQUFVO29CQUNqQixJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxDQUFDO2lCQUMxRCxDQUFDLENBQUM7Z0JBRUgsSUFBSSxDQUFDLFlBQVksSUFBSSxZQUFZLEVBQUUsQ0FBQztvQkFDaEMsTUFBTSxNQUFNLENBQUMsUUFBUSxDQUFDO3dCQUNsQixLQUFLLEVBQUUsVUFBVTt3QkFDakIsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxLQUFLLEVBQUUsZ0JBQWdCLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRSxDQUFDO3FCQUNqRSxDQUFDLENBQUM7b0JBRUgsTUFBTSxNQUFNLEdBQUcsTUFBTSxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUM7b0JBQzdDLElBQUksTUFBTSxFQUFFLENBQUM7d0JBQ1QsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQzs0QkFDckMsTUFBTSxNQUFNLENBQUMsUUFBUSxDQUFDO2dDQUNsQixLQUFLLEVBQUUsUUFBUTtnQ0FDZixJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7NkJBQ2xDLENBQUMsQ0FBQzt3QkFDUCxDQUFDO3dCQUNELE1BQU0sTUFBTSxDQUFDLFFBQVEsQ0FBQzs0QkFDbEIsS0FBSyxFQUFFLFVBQVU7NEJBQ2pCLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDO3lCQUMvRCxDQUFDLENBQUM7d0JBQ0gsT0FBTztvQkFDWCxDQUFDO2dCQUNMLENBQUM7Z0JBRUQsTUFBTSxNQUFNLENBQUMsUUFBUSxDQUFDO29CQUNsQixLQUFLLEVBQUUsVUFBVTtvQkFDakIsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRSxDQUFDO2lCQUNwRSxDQUFDLENBQUM7Z0JBRUgsTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUU1QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO29CQUN0QyxNQUFNLE1BQU0sQ0FBQyxRQUFRLENBQUM7d0JBQ2xCLEtBQUssRUFBRSxRQUFRO3dCQUNmLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztxQkFDbkMsQ0FBQyxDQUFDO2dCQUNQLENBQUM7Z0JBRUQsTUFBTSxNQUFNLENBQUMsUUFBUSxDQUFDO29CQUNsQixLQUFLLEVBQUUsVUFBVTtvQkFDakIsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxLQUFLLEVBQUUsT0FBTyxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUM7aUJBQ2pFLENBQUMsQ0FBQztZQUVQLENBQUM7WUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO2dCQUNsQixNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxJQUFJLElBQUksQ0FBQyxFQUFFLGdCQUFnQixDQUFDLENBQUM7Z0JBQ2pELE1BQU0sTUFBTSxDQUFDLFFBQVEsQ0FBQztvQkFDbEIsS0FBSyxFQUFFLE9BQU87b0JBQ2QsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLE9BQU8sSUFBSSx1QkFBdUIsRUFBRSxDQUFDO2lCQUM1RSxDQUFDLENBQUM7WUFDUCxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQscUJBQXFCO0lBQ1gsWUFBWSxDQUFDLE1BQVc7UUFDOUIsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzNFLE9BQU8sVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDdEUsQ0FBQztDQUlKIn0=
|