@opra/rabbitmq 1.15.1 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/rabbitmq-adapter.js +50 -52
- package/esm/rabbitmq-adapter.js +50 -52
- package/package.json +4 -3
- package/types/rabbitmq-adapter.d.ts +8 -5
- package/types/rabbitmq-context.d.ts +5 -5
package/cjs/rabbitmq-adapter.js
CHANGED
|
@@ -6,7 +6,7 @@ const node_zlib_1 = tslib_1.__importDefault(require("node:zlib"));
|
|
|
6
6
|
const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
|
|
7
7
|
const common_1 = require("@opra/common");
|
|
8
8
|
const core_1 = require("@opra/core");
|
|
9
|
-
const
|
|
9
|
+
const amqp_connection_manager_1 = require("amqp-connection-manager");
|
|
10
10
|
const content_type_1 = require("content-type");
|
|
11
11
|
const iconv_lite_1 = tslib_1.__importDefault(require("iconv-lite"));
|
|
12
12
|
const util_1 = require("util");
|
|
@@ -34,7 +34,6 @@ class RabbitmqAdapter extends core_1.PlatformAdapter {
|
|
|
34
34
|
constructor(document, config) {
|
|
35
35
|
super(config);
|
|
36
36
|
this._controllerInstances = new Map();
|
|
37
|
-
this._connections = [];
|
|
38
37
|
this._status = 'idle';
|
|
39
38
|
this.protocol = 'rpc';
|
|
40
39
|
this.platform = RabbitmqAdapter.PlatformName;
|
|
@@ -102,55 +101,54 @@ class RabbitmqAdapter extends core_1.PlatformAdapter {
|
|
|
102
101
|
handlerArgs.push(args);
|
|
103
102
|
}
|
|
104
103
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
: connectionOptions) +
|
|
113
|
-
')',
|
|
114
|
-
// @ts-ignore
|
|
115
|
-
e);
|
|
116
|
-
});
|
|
117
|
-
this._connections.push(connection);
|
|
118
|
-
const hostname = typeof connectionOptions === 'object'
|
|
119
|
-
? connectionOptions.hostname
|
|
120
|
-
: connectionOptions;
|
|
121
|
-
this.logger?.info?.(`Connected to ${hostname}`);
|
|
122
|
-
/** Subscribe to channels */
|
|
123
|
-
for (const args of handlerArgs) {
|
|
124
|
-
/** Create channel per operation */
|
|
125
|
-
const channel = await connection.createChannel();
|
|
126
|
-
for (const topic of args.topics) {
|
|
127
|
-
const opts = this._config.queues?.[topic];
|
|
128
|
-
if (opts)
|
|
129
|
-
await channel.assertQueue(topic, opts);
|
|
104
|
+
const connectionOptions = typeof this._config.connection === 'string'
|
|
105
|
+
? {
|
|
106
|
+
urls: [this._config.connection],
|
|
107
|
+
}
|
|
108
|
+
: Array.isArray(this._config.connection)
|
|
109
|
+
? {
|
|
110
|
+
urls: this._config.connection,
|
|
130
111
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
112
|
+
: this._config.connection;
|
|
113
|
+
this._client = new amqp_connection_manager_1.AmqpConnectionManagerClass(connectionOptions.urls, connectionOptions);
|
|
114
|
+
this._client.connect().catch(e => {
|
|
115
|
+
e.message =
|
|
116
|
+
'Unable to connect to RabbitMQ server at ' +
|
|
117
|
+
connectionOptions.urls +
|
|
118
|
+
'. ' +
|
|
119
|
+
e.message;
|
|
120
|
+
throw e;
|
|
121
|
+
});
|
|
122
|
+
this.logger?.info?.(`Connected RabbitMQ at ${connectionOptions.urls}`);
|
|
123
|
+
for (const args of handlerArgs) {
|
|
124
|
+
/** Create channel per operation */
|
|
125
|
+
this._client.createChannel({
|
|
126
|
+
setup: async (channel) => {
|
|
127
|
+
for (const topic of args.topics) {
|
|
128
|
+
const opts = this._config.queues?.[topic];
|
|
129
|
+
await channel.assertQueue(topic, opts);
|
|
130
|
+
await channel
|
|
131
|
+
.consume(topic, async (msg) => {
|
|
132
|
+
if (!msg)
|
|
133
|
+
return;
|
|
134
|
+
await this.emitAsync('message', msg, topic).catch(noOp);
|
|
135
|
+
try {
|
|
136
|
+
await args.handler(channel, topic, msg);
|
|
137
|
+
}
|
|
138
|
+
catch (e) {
|
|
139
|
+
this._emitError(e);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
/** Consume options */
|
|
143
|
+
args.operationConfig.consumer)
|
|
144
|
+
.catch(e => {
|
|
142
145
|
this._emitError(e);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
throw e;
|
|
150
|
-
});
|
|
151
|
-
this.logger?.info?.(`Subscribed to topic${args.topics.length > 1 ? 's' : ''} "${args.topics}"`);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
146
|
+
throw e;
|
|
147
|
+
});
|
|
148
|
+
this.logger?.info?.(`Subscribed to topic${args.topics.length > 1 ? 's' : ''} "${args.topics}"`);
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
});
|
|
154
152
|
}
|
|
155
153
|
this._status = 'started';
|
|
156
154
|
}
|
|
@@ -163,8 +161,8 @@ class RabbitmqAdapter extends core_1.PlatformAdapter {
|
|
|
163
161
|
* Closes all connections and stops the service
|
|
164
162
|
*/
|
|
165
163
|
async close() {
|
|
166
|
-
await
|
|
167
|
-
this.
|
|
164
|
+
await this._client?.close();
|
|
165
|
+
this._client = undefined;
|
|
168
166
|
this._controllerInstances.clear();
|
|
169
167
|
this._status = 'idle';
|
|
170
168
|
}
|
|
@@ -187,7 +185,7 @@ class RabbitmqAdapter extends core_1.PlatformAdapter {
|
|
|
187
185
|
return;
|
|
188
186
|
const operationConfig = {
|
|
189
187
|
consumer: {
|
|
190
|
-
noAck:
|
|
188
|
+
noAck: true,
|
|
191
189
|
},
|
|
192
190
|
};
|
|
193
191
|
if (this._config.defaults) {
|
package/esm/rabbitmq-adapter.js
CHANGED
|
@@ -2,7 +2,7 @@ import zlib from 'node:zlib';
|
|
|
2
2
|
import typeIs from '@browsery/type-is';
|
|
3
3
|
import { OpraException, RPC_CONTROLLER_METADATA, RpcApi, } from '@opra/common';
|
|
4
4
|
import { kAssetCache, PlatformAdapter } from '@opra/core';
|
|
5
|
-
import
|
|
5
|
+
import { AmqpConnectionManagerClass, } from 'amqp-connection-manager';
|
|
6
6
|
import { parse as parseContentType } from 'content-type';
|
|
7
7
|
import iconv from 'iconv-lite';
|
|
8
8
|
import { promisify } from 'util';
|
|
@@ -30,7 +30,6 @@ export class RabbitmqAdapter extends PlatformAdapter {
|
|
|
30
30
|
constructor(document, config) {
|
|
31
31
|
super(config);
|
|
32
32
|
this._controllerInstances = new Map();
|
|
33
|
-
this._connections = [];
|
|
34
33
|
this._status = 'idle';
|
|
35
34
|
this.protocol = 'rpc';
|
|
36
35
|
this.platform = RabbitmqAdapter.PlatformName;
|
|
@@ -98,55 +97,54 @@ export class RabbitmqAdapter extends PlatformAdapter {
|
|
|
98
97
|
handlerArgs.push(args);
|
|
99
98
|
}
|
|
100
99
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
: connectionOptions) +
|
|
109
|
-
')',
|
|
110
|
-
// @ts-ignore
|
|
111
|
-
e);
|
|
112
|
-
});
|
|
113
|
-
this._connections.push(connection);
|
|
114
|
-
const hostname = typeof connectionOptions === 'object'
|
|
115
|
-
? connectionOptions.hostname
|
|
116
|
-
: connectionOptions;
|
|
117
|
-
this.logger?.info?.(`Connected to ${hostname}`);
|
|
118
|
-
/** Subscribe to channels */
|
|
119
|
-
for (const args of handlerArgs) {
|
|
120
|
-
/** Create channel per operation */
|
|
121
|
-
const channel = await connection.createChannel();
|
|
122
|
-
for (const topic of args.topics) {
|
|
123
|
-
const opts = this._config.queues?.[topic];
|
|
124
|
-
if (opts)
|
|
125
|
-
await channel.assertQueue(topic, opts);
|
|
100
|
+
const connectionOptions = typeof this._config.connection === 'string'
|
|
101
|
+
? {
|
|
102
|
+
urls: [this._config.connection],
|
|
103
|
+
}
|
|
104
|
+
: Array.isArray(this._config.connection)
|
|
105
|
+
? {
|
|
106
|
+
urls: this._config.connection,
|
|
126
107
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
108
|
+
: this._config.connection;
|
|
109
|
+
this._client = new AmqpConnectionManagerClass(connectionOptions.urls, connectionOptions);
|
|
110
|
+
this._client.connect().catch(e => {
|
|
111
|
+
e.message =
|
|
112
|
+
'Unable to connect to RabbitMQ server at ' +
|
|
113
|
+
connectionOptions.urls +
|
|
114
|
+
'. ' +
|
|
115
|
+
e.message;
|
|
116
|
+
throw e;
|
|
117
|
+
});
|
|
118
|
+
this.logger?.info?.(`Connected RabbitMQ at ${connectionOptions.urls}`);
|
|
119
|
+
for (const args of handlerArgs) {
|
|
120
|
+
/** Create channel per operation */
|
|
121
|
+
this._client.createChannel({
|
|
122
|
+
setup: async (channel) => {
|
|
123
|
+
for (const topic of args.topics) {
|
|
124
|
+
const opts = this._config.queues?.[topic];
|
|
125
|
+
await channel.assertQueue(topic, opts);
|
|
126
|
+
await channel
|
|
127
|
+
.consume(topic, async (msg) => {
|
|
128
|
+
if (!msg)
|
|
129
|
+
return;
|
|
130
|
+
await this.emitAsync('message', msg, topic).catch(noOp);
|
|
131
|
+
try {
|
|
132
|
+
await args.handler(channel, topic, msg);
|
|
133
|
+
}
|
|
134
|
+
catch (e) {
|
|
135
|
+
this._emitError(e);
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
/** Consume options */
|
|
139
|
+
args.operationConfig.consumer)
|
|
140
|
+
.catch(e => {
|
|
138
141
|
this._emitError(e);
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
throw e;
|
|
146
|
-
});
|
|
147
|
-
this.logger?.info?.(`Subscribed to topic${args.topics.length > 1 ? 's' : ''} "${args.topics}"`);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
142
|
+
throw e;
|
|
143
|
+
});
|
|
144
|
+
this.logger?.info?.(`Subscribed to topic${args.topics.length > 1 ? 's' : ''} "${args.topics}"`);
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
});
|
|
150
148
|
}
|
|
151
149
|
this._status = 'started';
|
|
152
150
|
}
|
|
@@ -159,8 +157,8 @@ export class RabbitmqAdapter extends PlatformAdapter {
|
|
|
159
157
|
* Closes all connections and stops the service
|
|
160
158
|
*/
|
|
161
159
|
async close() {
|
|
162
|
-
await
|
|
163
|
-
this.
|
|
160
|
+
await this._client?.close();
|
|
161
|
+
this._client = undefined;
|
|
164
162
|
this._controllerInstances.clear();
|
|
165
163
|
this._status = 'idle';
|
|
166
164
|
}
|
|
@@ -183,7 +181,7 @@ export class RabbitmqAdapter extends PlatformAdapter {
|
|
|
183
181
|
return;
|
|
184
182
|
const operationConfig = {
|
|
185
183
|
consumer: {
|
|
186
|
-
noAck:
|
|
184
|
+
noAck: true,
|
|
187
185
|
},
|
|
188
186
|
};
|
|
189
187
|
if (this._config.defaults) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opra/rabbitmq",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.1",
|
|
4
4
|
"description": "Opra RabbitMQ package",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
"valgen": "^5.15.0"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
|
-
"@opra/common": "^1.
|
|
17
|
-
"@opra/core": "^1.
|
|
16
|
+
"@opra/common": "^1.16.1",
|
|
17
|
+
"@opra/core": "^1.16.1",
|
|
18
|
+
"amqp-connection-manager": "^4.1.14",
|
|
18
19
|
"amqplib": "^0.10.7"
|
|
19
20
|
},
|
|
20
21
|
"type": "module",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ApiDocument, OpraException, OpraSchema, RpcApi, RpcController, RpcOperation } from '@opra/common';
|
|
2
2
|
import { PlatformAdapter } from '@opra/core';
|
|
3
|
-
import
|
|
3
|
+
import { type AmqpConnectionManager, type AmqpConnectionManagerOptions, type ChannelWrapper, type ConnectionUrl } from 'amqp-connection-manager';
|
|
4
|
+
import amqplib from 'amqplib';
|
|
4
5
|
import { ConsumeMessage } from 'amqplib/properties';
|
|
5
6
|
import { RabbitmqContext } from './rabbitmq-context.js';
|
|
6
7
|
export interface OperationConfig {
|
|
@@ -12,7 +13,7 @@ interface HandlerArguments {
|
|
|
12
13
|
instance: any;
|
|
13
14
|
operation: RpcOperation;
|
|
14
15
|
operationConfig: OperationConfig;
|
|
15
|
-
handler: (channel:
|
|
16
|
+
handler: (channel: ChannelWrapper, queue: string, msg: ConsumeMessage | null) => void | Promise<void>;
|
|
16
17
|
topics: string[];
|
|
17
18
|
}
|
|
18
19
|
/**
|
|
@@ -23,7 +24,7 @@ export declare class RabbitmqAdapter extends PlatformAdapter<RabbitmqAdapter.Eve
|
|
|
23
24
|
static readonly PlatformName = "rabbitmq";
|
|
24
25
|
protected _config: RabbitmqAdapter.Config;
|
|
25
26
|
protected _controllerInstances: Map<RpcController, any>;
|
|
26
|
-
protected
|
|
27
|
+
protected _client?: AmqpConnectionManager;
|
|
27
28
|
protected _status: RabbitmqAdapter.Status;
|
|
28
29
|
readonly protocol: OpraSchema.Transport;
|
|
29
30
|
readonly platform = "rabbitmq";
|
|
@@ -71,9 +72,11 @@ export declare class RabbitmqAdapter extends PlatformAdapter<RabbitmqAdapter.Eve
|
|
|
71
72
|
export declare namespace RabbitmqAdapter {
|
|
72
73
|
type NextCallback = () => Promise<any>;
|
|
73
74
|
type Status = 'idle' | 'starting' | 'started';
|
|
74
|
-
|
|
75
|
+
interface ConnectionOptions extends AmqpConnectionManagerOptions {
|
|
76
|
+
urls?: ConnectionUrl[];
|
|
77
|
+
}
|
|
75
78
|
interface Config extends PlatformAdapter.Options {
|
|
76
|
-
connection:
|
|
79
|
+
connection: string | string[] | ConnectionOptions;
|
|
77
80
|
queues?: Record<string, amqplib.Options.AssertQueue>;
|
|
78
81
|
defaults?: {
|
|
79
82
|
consumer?: amqplib.Options.Consume;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OpraSchema, RpcController, RpcOperation } from '@opra/common';
|
|
2
2
|
import { ExecutionContext } from '@opra/core';
|
|
3
|
-
import type {
|
|
3
|
+
import type { ChannelWrapper } from 'amqp-connection-manager';
|
|
4
4
|
import type { ConsumeMessage } from 'amqplib/properties';
|
|
5
5
|
import type { AsyncEventEmitter } from 'node-events-async';
|
|
6
6
|
import type { RabbitmqAdapter } from './rabbitmq-adapter';
|
|
@@ -18,7 +18,7 @@ export declare class RabbitmqContext extends ExecutionContext implements AsyncEv
|
|
|
18
18
|
readonly operation?: RpcOperation;
|
|
19
19
|
readonly operationHandler?: Function;
|
|
20
20
|
readonly queue: string;
|
|
21
|
-
readonly channel:
|
|
21
|
+
readonly channel: ChannelWrapper;
|
|
22
22
|
readonly message: ConsumeMessage;
|
|
23
23
|
readonly content: any;
|
|
24
24
|
readonly headers: Record<string, any>;
|
|
@@ -27,15 +27,15 @@ export declare class RabbitmqContext extends ExecutionContext implements AsyncEv
|
|
|
27
27
|
* @param init the context options
|
|
28
28
|
*/
|
|
29
29
|
constructor(init: RabbitmqContext.Initiator);
|
|
30
|
-
get properties(): import("amqplib").MessageProperties;
|
|
31
|
-
get fields(): import("amqplib").ConsumeMessageFields;
|
|
30
|
+
get properties(): import("amqplib/properties").MessageProperties;
|
|
31
|
+
get fields(): import("amqplib/properties").ConsumeMessageFields;
|
|
32
32
|
ack(): void;
|
|
33
33
|
nack(): void;
|
|
34
34
|
}
|
|
35
35
|
export declare namespace RabbitmqContext {
|
|
36
36
|
interface Initiator extends Omit<ExecutionContext.Initiator, 'document' | 'protocol' | 'documentNode'> {
|
|
37
37
|
adapter: RabbitmqAdapter;
|
|
38
|
-
channel:
|
|
38
|
+
channel: ChannelWrapper;
|
|
39
39
|
controller?: RpcController;
|
|
40
40
|
controllerInstance?: any;
|
|
41
41
|
operation?: RpcOperation;
|