UNPKG

s3db.js

Version:

Use AWS S3, the world's most reliable document storage, as a database with this ORM.

134 lines (117 loc) 4.79 kB
import { createConsumer } from './consumers/index.js'; import tryFn from "../concerns/try-fn.js"; // Example configuration for SQS: // const plugin = new QueueConsumerPlugin({ // driver: 'sqs', // queues: { users: 'https://sqs.us-east-1.amazonaws.com/123456789012/my-queue' }, // region: 'us-east-1', // credentials: { accessKeyId: '...', secretAccessKey: '...' }, // poolingInterval: 1000, // maxMessages: 10, // }); // // Example configuration for RabbitMQ: // const plugin = new QueueConsumerPlugin({ // driver: 'rabbitmq', // queues: { users: 'users-queue' }, // amqpUrl: 'amqp://user:pass@localhost:5672', // prefetch: 10, // reconnectInterval: 2000, // }); export default class QueueConsumerPlugin { constructor(options = {}) { this.options = options; // New pattern: consumers = [{ driver, config, consumers: [{ queueUrl, resources, ... }] }] this.driversConfig = Array.isArray(options.consumers) ? options.consumers : []; this.consumers = []; } async setup(database) { this.database = database; for (const driverDef of this.driversConfig) { const { driver, config: driverConfig = {}, consumers: consumerDefs = [] } = driverDef; // Handle legacy format where config is mixed with driver definition if (consumerDefs.length === 0 && driverDef.resources) { // Legacy format: { driver: 'sqs', resources: 'users', config: {...} } const { resources, driver: defDriver, config: nestedConfig, ...directConfig } = driverDef; const resourceList = Array.isArray(resources) ? resources : [resources]; // Flatten config - prioritize nested config if it exists, otherwise use direct config const flatConfig = nestedConfig ? { ...directConfig, ...nestedConfig } : directConfig; for (const resource of resourceList) { const consumer = createConsumer(driver, { ...flatConfig, onMessage: (msg) => this._handleMessage(msg, resource), onError: (err, raw) => this._handleError(err, raw, resource) }); await consumer.start(); this.consumers.push(consumer); } } else { // New format: { driver: 'sqs', config: {...}, consumers: [{ resources: 'users', ... }] } for (const consumerDef of consumerDefs) { const { resources, ...consumerConfig } = consumerDef; const resourceList = Array.isArray(resources) ? resources : [resources]; for (const resource of resourceList) { const mergedConfig = { ...driverConfig, ...consumerConfig }; const consumer = createConsumer(driver, { ...mergedConfig, onMessage: (msg) => this._handleMessage(msg, resource), onError: (err, raw) => this._handleError(err, raw, resource) }); await consumer.start(); this.consumers.push(consumer); } } } } } async stop() { if (!Array.isArray(this.consumers)) this.consumers = []; for (const consumer of this.consumers) { if (consumer && typeof consumer.stop === 'function') { await consumer.stop(); } } this.consumers = []; } async _handleMessage(msg, configuredResource) { const opt = this.options; // Permitir resource/action/data tanto na raiz quanto em $body // Handle double nesting from SQS parsing let body = msg.$body || msg; if (body.$body && !body.resource && !body.action && !body.data) { // Double nested case - use the inner $body body = body.$body; } let resource = body.resource || msg.resource; let action = body.action || msg.action; let data = body.data || msg.data; if (!resource) { throw new Error('QueueConsumerPlugin: resource not found in message'); } if (!action) { throw new Error('QueueConsumerPlugin: action not found in message'); } const resourceObj = this.database.resources[resource]; if (!resourceObj) throw new Error(`QueueConsumerPlugin: resource '${resource}' not found`); let result; const [ok, err, res] = await tryFn(async () => { if (action === 'insert') { result = await resourceObj.insert(data); } else if (action === 'update') { const { id: updateId, ...updateAttributes } = data; result = await resourceObj.update(updateId, updateAttributes); } else if (action === 'delete') { result = await resourceObj.delete(data.id); } else { throw new Error(`QueueConsumerPlugin: unsupported action '${action}'`); } return result; }); if (!ok) { throw err; } return res; } _handleError(err, raw, resourceName) { } }