fastify-rabbitmq 0.0.1-alpha.0 → 0.0.1-alpha.2
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/README.md +143 -58
- package/dist/index.d.ts +13 -19
- package/dist/index.js +34 -80
- package/package.json +12 -6
- package/index.ts +0 -165
- package/tsconfig.json +0 -29
package/README.md
CHANGED
|
@@ -1,93 +1,178 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# Fastify RabbitMq
|
|
2
|
+
|
|
3
|
+
A Fastify RabbitMQ Plugin Developed in Pure TypeScript.
|
|
4
|
+
It uses the [node-amqp-connection-manager](https://github.com/jwalton/node-amqp-connection-manager) plugin as a wrapper.
|
|
5
|
+
|
|
6
|
+
This comes right from the README on ```node-amqp-connection-manager```:
|
|
7
|
+
|
|
8
|
+
> Features
|
|
9
|
+
> * Automatically reconnect when your amqplib broker dies in a fire.
|
|
10
|
+
> * Round-robin connections between multiple brokers in a cluster.
|
|
11
|
+
> * If messages are sent while the broker is unavailable, queues messages in memory until we reconnect.
|
|
12
|
+
> * Supports both promises and callbacks (using promise-breaker)
|
|
13
|
+
> * Very un-opinionated library—a thin wrapper around amqplib.
|
|
14
|
+
|
|
15
|
+
## Notice
|
|
16
|
+
|
|
17
|
+
This NPM package is still going **active development** so things will break. Review the issues list for on going development work and if you want to help out, submit a PR.
|
|
18
|
+
|
|
19
|
+
Help Wanted:
|
|
20
|
+
* Documentation
|
|
21
|
+
* GitHub Workflows
|
|
22
|
+
* Unit Testing using Jest
|
|
23
|
+
|
|
24
|
+
## Table of Contents
|
|
25
|
+
|
|
26
|
+
1. [Notice](#notice)
|
|
27
|
+
2. [Install](#install)
|
|
28
|
+
2. [Basic Usage](#basic-usage)
|
|
29
|
+
3. [Full Documentation](#full-documentation)
|
|
30
|
+
1. [Options](#options)
|
|
31
|
+
4. [Acknowledgements](#acknowledgements)
|
|
32
|
+
5. [License](#license)
|
|
3
33
|
|
|
4
34
|
## Install
|
|
5
35
|
```
|
|
6
|
-
npm i fastify-rabbitmq
|
|
36
|
+
npm i fastify-rabbitmq amqplib
|
|
37
|
+
npm i --save-dev @types/amqplib
|
|
7
38
|
```
|
|
8
39
|
|
|
9
|
-
## Usage
|
|
10
|
-
Register as a plugin.
|
|
40
|
+
## Basic Usage
|
|
41
|
+
Register this as a plugin.
|
|
42
|
+
Make sure it is loaded before any ***routes*** are loaded.
|
|
43
|
+
|
|
44
|
+
### Quick Setup on the Server Side
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
export default fp<any>(async (fastify: FastifyInstance, options: FastifyPluginOptions) => {
|
|
48
|
+
|
|
49
|
+
fastify.register(fastifyRabbit, {
|
|
50
|
+
urLs: ['amqp://localhost']
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
fastify.ready().then(async () => {
|
|
54
|
+
fastify.log.debug('[rabbitmq] Started RabbitMQ')
|
|
55
|
+
fastify.rabbitmq.channel = fastify.rabbitmq.createChannel({
|
|
56
|
+
json: true,
|
|
57
|
+
setup: function (channel: ConfirmChannel) {
|
|
58
|
+
return Promise.all([
|
|
59
|
+
channel.assertQueue('server', {durable: true}),
|
|
60
|
+
channel.prefetch(1),
|
|
61
|
+
channel.consume('server', async (message) => {
|
|
62
|
+
fastify.log.debug(JSON.stringify(data))
|
|
63
|
+
fastify.rabbitmq.channel?.ack(message);
|
|
64
|
+
})
|
|
65
|
+
]);
|
|
66
|
+
},
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Within server instance can also call the same queue as long as it has access to the ``fastify.rabbitmq`` decorator.
|
|
74
|
+
Traditionally, a separate app is running and is the client sending messages to the client.
|
|
75
|
+
|
|
76
|
+
### Quick Setup on the Client Side
|
|
11
77
|
|
|
12
|
-
|
|
13
|
-
* fastify.rabbitmq.directMessage
|
|
78
|
+
First set up your plugin to register the plugin.
|
|
14
79
|
|
|
15
|
-
```
|
|
80
|
+
```typescript
|
|
81
|
+
import {ConfirmChannel} from "amqplib";
|
|
82
|
+
import {
|
|
83
|
+
FastifyInstance,
|
|
84
|
+
FastifyPluginOptions,
|
|
85
|
+
} from 'fastify';
|
|
86
|
+
import fp from "fastify-plugin";
|
|
16
87
|
import fastifyRabbit from "fastify-rabbitmq"
|
|
17
88
|
|
|
18
|
-
fastify
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
89
|
+
export default fp<any>(async (fastify: FastifyInstance, options: FastifyPluginOptions) => {
|
|
90
|
+
|
|
91
|
+
fastify.register(fastifyRabbit, {
|
|
92
|
+
urLs: ['amqp://localhost']
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
fastify.ready().then(async () => {
|
|
96
|
+
|
|
97
|
+
fastify.rabbitmq.channel = fastify.rabbitmq.createChannel({
|
|
98
|
+
json: true,
|
|
99
|
+
setup: function (channel: ConfirmChannel) {
|
|
100
|
+
return channel.assertQueue('client', { durable: true });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
})
|
|
105
|
+
|
|
23
106
|
})
|
|
24
107
|
```
|
|
25
108
|
|
|
26
|
-
|
|
109
|
+
Now in your routes or anywhere the fastify.rabbitmq can be accessed:
|
|
27
110
|
|
|
28
111
|
```typescript
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
consumeMessageFn: (message: ConsumeMessage, channel: Channel) => void;
|
|
38
|
-
confirmChannel?: boolean
|
|
39
|
-
}
|
|
112
|
+
fastify.get('/rabbitmq', {}, async (request, reply) => {
|
|
113
|
+
try {
|
|
114
|
+
fastify.rabbitmq.channel?.sendToQueue('server', { foo: 'bar'})
|
|
115
|
+
return reply.code(200).send({ result: true});
|
|
116
|
+
} catch (error) {
|
|
117
|
+
return reply.send(404);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
40
120
|
```
|
|
41
|
-
### `queue` (required)
|
|
42
|
-
|
|
43
|
-
The RabbitMQ queue to create.
|
|
44
121
|
|
|
45
|
-
|
|
122
|
+
## Full Documentation
|
|
46
123
|
|
|
47
|
-
|
|
124
|
+
### Options
|
|
48
125
|
|
|
49
126
|
```typescript
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
...data
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
const {body} = await got.post(`http://localhost:3000/foo`, options)
|
|
127
|
+
export interface FastifyRabbitMQOptions extends AmqpConnectionManagerOptions {
|
|
128
|
+
logLevel?: 'trace' | 'debug' | 'info' | 'warn' | 'error'
|
|
129
|
+
namespace?: string
|
|
130
|
+
urLs: ConnectionUrl | ConnectionUrl[] | undefined | null
|
|
58
131
|
}
|
|
59
132
|
```
|
|
60
|
-
|
|
133
|
+
#### FastifyRabbitMQOptions
|
|
61
134
|
|
|
62
|
-
|
|
135
|
+
##### `logLevel`
|
|
63
136
|
|
|
64
|
-
|
|
65
|
-
The name can be the same as the queue.
|
|
137
|
+
Set the log level for Fastify RabbitMQ plugin. This is usefull for development work. The default value is ```silent```
|
|
66
138
|
|
|
67
|
-
|
|
139
|
+
##### `namespace`
|
|
68
140
|
|
|
69
|
-
|
|
141
|
+
If you need more than one "connection" to a different set and/or array of RabbitMQ servers,
|
|
142
|
+
either on network or cloud, each registration of the plugin needs it to be in its own namespace.
|
|
143
|
+
If not provided, your application will fail to load.
|
|
70
144
|
|
|
71
|
-
|
|
145
|
+
##### `urLs`
|
|
72
146
|
|
|
73
|
-
|
|
147
|
+
This needs to be an array of the RabbitMQ host:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
fastify.register(fastifyRabbit, {
|
|
151
|
+
urLs: ['amqp://localhost']
|
|
152
|
+
})
|
|
153
|
+
```
|
|
74
154
|
|
|
75
|
-
|
|
155
|
+
This is not needed
|
|
156
|
+
if you use AmqpConnectionManagerOptions [findServers](https://github.com/jwalton/node-amqp-connection-manager#connecturls-options)
|
|
157
|
+
which overrides the urls value if it's set.
|
|
158
|
+
If you need
|
|
159
|
+
to pass in credentials to the RabbitMQ or vHost for the connection review the [connection options](#amqpconnectionmanageroptions).
|
|
76
160
|
|
|
77
|
-
|
|
161
|
+
Please review the options [here](https://github.com/jwalton/node-amqp-connection-manager/blob/master/src/AmqpConnectionManager.ts#L26C13-L26C34).
|
|
162
|
+
(Note:
|
|
163
|
+
This URL might bring you to the wrong line
|
|
164
|
+
if the file has been changed on the ```node-amqp-connection-manager``` package.)
|
|
78
165
|
|
|
79
|
-
|
|
166
|
+
#### ```AmqpConnectionManagerOptions```
|
|
80
167
|
|
|
81
|
-
|
|
168
|
+
See [Connection Options](https://github.com/jwalton/node-amqp-connection-manager#connecturls-options) for 'node-amqp-connection-manager' for detailed options that can be passed in.
|
|
82
169
|
|
|
83
|
-
|
|
170
|
+
## Acknowledgements
|
|
84
171
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
172
|
+
- [node-amqp-connection-manager](https://github.com/jwalton/node-amqp-connection-manager)
|
|
173
|
+
- [fastify](https://fastify.dev/)
|
|
174
|
+
- ...and of course my Wife and Baby Girl.
|
|
88
175
|
|
|
89
|
-
|
|
176
|
+
## License
|
|
90
177
|
|
|
91
|
-
|
|
92
|
-
it's ```false``` but mark this ture in order for you to mark your queue
|
|
93
|
-
always confirm that it received data from a remote RabbitMQ.
|
|
178
|
+
Licensed under [MIT](./LICENSE).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,33 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Channel, ConfirmChannel } from 'amqplib';
|
|
2
|
+
import { ChannelWrapper } from 'amqp-connection-manager';
|
|
3
|
+
import type { AmqpConnectionManager, AmqpConnectionManagerOptions, ConnectionUrl } from 'amqp-connection-manager';
|
|
4
|
+
import { FastifyInstance } from 'fastify';
|
|
3
5
|
import FastifyRabbitMQOptions = fastifyRabbitMQ.FastifyRabbitMQOptions;
|
|
6
|
+
import FastifyRabbitMQObject = fastifyRabbitMQ.FastifyRabbitMQObject;
|
|
4
7
|
declare module 'fastify' {
|
|
5
8
|
interface FastifyInstance {
|
|
6
|
-
rabbitmq:
|
|
9
|
+
rabbitmq: FastifyRabbitMQObject & fastifyRabbitMQ.FastifyRabbitMQNestedObject;
|
|
7
10
|
}
|
|
8
11
|
}
|
|
9
|
-
type fastifyRabbitMQPlugin = FastifyPluginCallback<NonNullable<fastifyRabbitMQ.FastifyRabbitMQOptions>>;
|
|
10
12
|
declare namespace fastifyRabbitMQ {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
directMessage(sendQueue: string, message: any): void;
|
|
13
|
+
interface FastifyRabbitMQObject extends AmqpConnectionManager {
|
|
14
|
+
channel?: ChannelWrapper;
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
+
interface FastifyRabbitMQNestedObject {
|
|
16
17
|
[namespace: string]: FastifyRabbitMQObject;
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
+
interface FastifyRabbitMQOptions extends AmqpConnectionManagerOptions {
|
|
20
|
+
logLevel?: 'trace' | 'debug' | 'info' | 'warn' | 'error';
|
|
19
21
|
namespace?: string;
|
|
20
|
-
|
|
21
|
-
host?: string;
|
|
22
|
-
port?: string;
|
|
23
|
-
username?: string;
|
|
24
|
-
password?: string;
|
|
25
|
-
preProcessMessageFn?: (message: any) => string;
|
|
26
|
-
consumeMessageFn: (message: ConsumeMessage, channel: Channel) => void;
|
|
27
|
-
confirmChannel?: boolean;
|
|
22
|
+
urLs: ConnectionUrl | ConnectionUrl[] | undefined | null;
|
|
28
23
|
}
|
|
29
|
-
export const fastifyRabbitMQPlugin: fastifyRabbitMQPlugin;
|
|
30
|
-
export { fastifyRabbitMQPlugin as default };
|
|
31
24
|
}
|
|
32
25
|
declare const fastifyRabbit: (fastify: FastifyInstance, options: FastifyRabbitMQOptions) => Promise<void>;
|
|
26
|
+
export { Channel, ConfirmChannel };
|
|
33
27
|
export default fastifyRabbit;
|
package/dist/index.js
CHANGED
|
@@ -7,107 +7,61 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
+
import amqp from 'amqp-connection-manager';
|
|
10
11
|
import fp from 'fastify-plugin';
|
|
11
|
-
import amqp from 'amqplib';
|
|
12
12
|
/**
|
|
13
13
|
* decorateFastifyInstance
|
|
14
14
|
* @since 0.0.1
|
|
15
15
|
* @param fastify
|
|
16
16
|
* @param options
|
|
17
|
-
* @param
|
|
17
|
+
* @param connection
|
|
18
18
|
*/
|
|
19
|
-
const decorateFastifyInstance = (fastify, options,
|
|
20
|
-
const { namespace } = options;
|
|
21
|
-
|
|
19
|
+
const decorateFastifyInstance = (fastify, options, connection) => {
|
|
20
|
+
const { logLevel = 'silent', namespace = '' } = options;
|
|
21
|
+
// override log level
|
|
22
|
+
const logger = fastify.log.child({}, { level: logLevel });
|
|
23
|
+
if (namespace !== '') {
|
|
24
|
+
logger.debug('[fastify-rabbitmq] Namespace: %s', namespace);
|
|
25
|
+
}
|
|
26
|
+
if (namespace !== '') {
|
|
22
27
|
if (typeof fastify.rabbitmq === 'undefined') {
|
|
23
|
-
fastify.decorate('rabbitmq',
|
|
28
|
+
fastify.decorate('rabbitmq', connection);
|
|
24
29
|
}
|
|
25
|
-
if (
|
|
26
|
-
throw Error('Connection name already registered: ' + namespace);
|
|
30
|
+
if (fastify.rabbitmq[namespace] != null) {
|
|
31
|
+
throw Error('[fastify-rabbitmq] Connection name already registered: ' + namespace);
|
|
27
32
|
}
|
|
33
|
+
logger.trace('[fastify-rabbitmq] Decorate Fastify with Namespace: %', namespace);
|
|
34
|
+
fastify.rabbitmq[namespace] = connection;
|
|
28
35
|
}
|
|
29
36
|
else {
|
|
30
37
|
if (typeof fastify.rabbitmq !== 'undefined') {
|
|
31
|
-
throw Error('fastify-rabbitmq
|
|
38
|
+
throw Error('[fastify-rabbitmq] Already registered');
|
|
32
39
|
}
|
|
33
40
|
}
|
|
34
41
|
if (typeof fastify.rabbitmq === 'undefined') {
|
|
35
|
-
|
|
42
|
+
logger.trace('[fastify-rabbitmq] Decorate Fastify');
|
|
43
|
+
fastify.decorate('rabbitmq', connection);
|
|
36
44
|
}
|
|
37
45
|
};
|
|
38
46
|
const fastifyRabbit = fp((fastify, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
39
|
-
const {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* Process the incoming message from another queue. This is required.
|
|
55
|
-
* @since 0.0.1
|
|
56
|
-
* @param msg {ConsumeMessage} Data from RabbitMQ. It's in a string format; however, you need to interpret the data.
|
|
57
|
-
* @param channel {Channel} What channel did it comes from and the properties of that channel.
|
|
58
|
-
*/
|
|
59
|
-
function consumeRabbitMessage(msg, channel) {
|
|
60
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
-
if (typeof consumeMessageFn === 'function') {
|
|
62
|
-
consumeMessageFn(msg, channel);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* preProcessMessage
|
|
68
|
-
* If the parameter preProcessMessageFn is passed, it will use that function to process the data.
|
|
69
|
-
* @since 0.0.1
|
|
70
|
-
* @param message {any} The data you want to send, however it must be a string.
|
|
71
|
-
*/
|
|
72
|
-
function preProcessMessage(message) {
|
|
73
|
-
if (typeof preProcessMessageFn === 'function') {
|
|
74
|
-
return preProcessMessageFn(message);
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
return message;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
const channel = yield getRabbitChannel(confirmChannel);
|
|
81
|
-
yield (channel === null || channel === void 0 ? void 0 : channel.assertQueue(queue, { durable: false }).then(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
82
|
-
return yield channel.consume(queue, (msg) => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
|
-
yield consumeRabbitMessage(msg, channel);
|
|
84
|
-
}), {
|
|
85
|
-
noAck: true
|
|
86
|
-
});
|
|
87
|
-
})));
|
|
88
|
-
/**
|
|
89
|
-
* publishMessage
|
|
90
|
-
* @since 0.0.1
|
|
91
|
-
* @param sendQueue {string} The target queue.
|
|
92
|
-
* @param message {any} You can publish anything as long as it goes out over as a string.
|
|
93
|
-
*/
|
|
94
|
-
function publishMessage(sendQueue, message) {
|
|
95
|
-
channel === null || channel === void 0 ? void 0 : channel.publish('', sendQueue, Buffer.from(preProcessMessage(message)));
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* directMessage
|
|
99
|
-
* @since 0.0.1
|
|
100
|
-
* @param sendQueue {string} The target queue and directed to that queue. No one else can take it.
|
|
101
|
-
* @param message {any} You can publish anything as long as it goes out over as a string.
|
|
102
|
-
*/
|
|
103
|
-
function directMessage(sendQueue, message) {
|
|
104
|
-
channel === null || channel === void 0 ? void 0 : channel.sendToQueue(sendQueue, Buffer.from(preProcessMessage(message)), {
|
|
105
|
-
replyTo: queue
|
|
106
|
-
});
|
|
107
|
-
}
|
|
47
|
+
const { logLevel = 'silent', urLs, heartbeatIntervalInSeconds, reconnectTimeInSeconds, findServers, connectionOptions } = options;
|
|
48
|
+
// override log level
|
|
49
|
+
const logger = fastify.log.child({}, { level: logLevel });
|
|
50
|
+
const connection = amqp.connect(urLs, {
|
|
51
|
+
heartbeatIntervalInSeconds,
|
|
52
|
+
reconnectTimeInSeconds,
|
|
53
|
+
findServers,
|
|
54
|
+
connectionOptions
|
|
55
|
+
});
|
|
56
|
+
connection.on('connect', function () {
|
|
57
|
+
logger.debug('[fastify-rabbitmq] Connection to RabbitMQ Successful');
|
|
58
|
+
});
|
|
59
|
+
connection.on('disconnect', function () {
|
|
60
|
+
logger.debug('[fastify-rabbitmq] Connection to RabbitMQ Disconnected');
|
|
61
|
+
});
|
|
108
62
|
/**
|
|
109
63
|
* Decorate Fastify
|
|
110
64
|
*/
|
|
111
|
-
decorateFastifyInstance(fastify, options,
|
|
65
|
+
decorateFastifyInstance(fastify, options, connection);
|
|
112
66
|
}));
|
|
113
67
|
export default fastifyRabbit;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify-rabbitmq",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.2",
|
|
4
4
|
"description": "A Fastify RabbitMQ Plugin Developed in Pure TypeScript using the AMQPLIB",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"build:watch": "tsc -w",
|
|
11
11
|
"lint": "ts-standard",
|
|
12
12
|
"lint:fix": "ts-standard --fix",
|
|
13
|
-
"test": "
|
|
13
|
+
"test": "jest",
|
|
14
14
|
"update": "npx npm-check-updates -u && npm install"
|
|
15
15
|
},
|
|
16
16
|
"repository": {
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
"url": "git+https://github.com/Bugs5382/fastify-rabbitmq.git"
|
|
19
19
|
},
|
|
20
20
|
"keywords": [
|
|
21
|
+
"amqp-connection-manager",
|
|
22
|
+
"amqplib",
|
|
21
23
|
"typescript",
|
|
22
24
|
"rabbitmq",
|
|
23
25
|
"fastify",
|
|
@@ -30,17 +32,21 @@
|
|
|
30
32
|
},
|
|
31
33
|
"homepage": "https://github.com/Bugs5382/fastify-rabbitmq#readme",
|
|
32
34
|
"dependencies": {
|
|
33
|
-
"
|
|
35
|
+
"amqp-connection-manager": "^4.1.14",
|
|
34
36
|
"fastify-plugin": "^4.5.1"
|
|
35
37
|
},
|
|
36
38
|
"devDependencies": {
|
|
37
39
|
"@types/amqplib": "^0.10.1",
|
|
38
|
-
"@types/
|
|
40
|
+
"@types/jest": "^29.5.3",
|
|
41
|
+
"@types/node": "^20.4.10",
|
|
39
42
|
"fastify": "^4.21.0",
|
|
40
|
-
"
|
|
43
|
+
"jest": "^29.6.2",
|
|
44
|
+
"npm-check-updates": "^16.11.1",
|
|
41
45
|
"pre-commit": "^1.2.2",
|
|
42
|
-
"
|
|
46
|
+
"ts-jest": "^29.1.1",
|
|
47
|
+
"ts-node": "^10.9.1",
|
|
43
48
|
"ts-standard": "^12.0.2",
|
|
49
|
+
"tsd": "^0.28.1",
|
|
44
50
|
"typescript": "^5.1.6"
|
|
45
51
|
},
|
|
46
52
|
"pre-commit": []
|
package/index.ts
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import {FastifyInstance, FastifyPluginCallback} from 'fastify'
|
|
2
|
-
import fp from 'fastify-plugin'
|
|
3
|
-
import amqp, {Channel, ConsumeMessage} from 'amqplib'
|
|
4
|
-
|
|
5
|
-
import FastifyRabbitMQOptions = fastifyRabbitMQ.FastifyRabbitMQOptions;
|
|
6
|
-
|
|
7
|
-
declare module 'fastify' {
|
|
8
|
-
interface FastifyInstance {
|
|
9
|
-
rabbitmq: fastifyRabbitMQ.FastifyRabbitMQObject & fastifyRabbitMQ.FastifyRabbitMQNestedObject;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type fastifyRabbitMQPlugin = FastifyPluginCallback<
|
|
15
|
-
NonNullable<fastifyRabbitMQ.FastifyRabbitMQOptions>
|
|
16
|
-
>;
|
|
17
|
-
|
|
18
|
-
declare namespace fastifyRabbitMQ {
|
|
19
|
-
|
|
20
|
-
export interface FastifyRabbitMQObject {
|
|
21
|
-
publishMessage (sendQueue: string, message: any): void
|
|
22
|
-
directMessage (sendQueue: string, message: any): void
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface FastifyRabbitMQNestedObject {
|
|
26
|
-
[namespace: string]: FastifyRabbitMQObject;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface FastifyRabbitMQOptions {
|
|
30
|
-
namespace?: string
|
|
31
|
-
queue: string
|
|
32
|
-
host?: string
|
|
33
|
-
port?: string
|
|
34
|
-
username?: string
|
|
35
|
-
password?: string
|
|
36
|
-
preProcessMessageFn?: (message: any) => string;
|
|
37
|
-
consumeMessageFn: (message: ConsumeMessage, channel: Channel) => void;
|
|
38
|
-
confirmChannel?: boolean
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export const fastifyRabbitMQPlugin: fastifyRabbitMQPlugin
|
|
42
|
-
export { fastifyRabbitMQPlugin as default }
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* decorateFastifyInstance
|
|
48
|
-
* @since 0.0.1
|
|
49
|
-
* @param fastify
|
|
50
|
-
* @param options
|
|
51
|
-
* @param functions
|
|
52
|
-
*/
|
|
53
|
-
const decorateFastifyInstance = (fastify: FastifyInstance, options: FastifyRabbitMQOptions, functions: any): void => {
|
|
54
|
-
const { namespace } = options
|
|
55
|
-
|
|
56
|
-
if (namespace) {
|
|
57
|
-
if (typeof fastify.rabbitmq === 'undefined') {
|
|
58
|
-
fastify.decorate('rabbitmq', {...functions})
|
|
59
|
-
}
|
|
60
|
-
if (typeof fastify.rabbitmq[namespace] !== 'undefined') {
|
|
61
|
-
throw Error('Connection name already registered: ' + namespace)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
} else {
|
|
65
|
-
if (typeof fastify.rabbitmq !== 'undefined') {
|
|
66
|
-
throw Error('fastify-rabbitmq has already registered')
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (typeof fastify.rabbitmq === 'undefined') {
|
|
71
|
-
fastify.decorate('rabbitmq', {...functions})
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const fastifyRabbit = fp(async (fastify: FastifyInstance, options: FastifyRabbitMQOptions): Promise<void> => {
|
|
77
|
-
const {
|
|
78
|
-
queue,
|
|
79
|
-
host = 'localhost',
|
|
80
|
-
port = '5672',
|
|
81
|
-
username = 'guest',
|
|
82
|
-
password = 'guest',
|
|
83
|
-
confirmChannel = false,
|
|
84
|
-
consumeMessageFn,
|
|
85
|
-
preProcessMessageFn
|
|
86
|
-
} = options
|
|
87
|
-
|
|
88
|
-
const RABBITMQ_FULL_URL = `amqp://${username}:${password}@${host}:${port}`
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* getRabbitChannel
|
|
92
|
-
* @since 0.0.1
|
|
93
|
-
* @param confirmChannel {boolean} Set this to true if you want the channel to always ask for a confirmation that it was sent and received by the other side.
|
|
94
|
-
*/
|
|
95
|
-
async function getRabbitChannel (confirmChannel: boolean): Promise<Channel> {
|
|
96
|
-
const conn = await amqp.connect(RABBITMQ_FULL_URL)
|
|
97
|
-
return confirmChannel ? await conn.createConfirmChannel() : await conn.createChannel()
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* consumeRabbitMessage
|
|
102
|
-
* Process the incoming message from another queue. This is required.
|
|
103
|
-
* @since 0.0.1
|
|
104
|
-
* @param msg {ConsumeMessage} Data from RabbitMQ. It's in a string format; however, you need to interpret the data.
|
|
105
|
-
* @param channel {Channel} What channel did it comes from and the properties of that channel.
|
|
106
|
-
*/
|
|
107
|
-
async function consumeRabbitMessage (msg: ConsumeMessage, channel: Channel): Promise<void> {
|
|
108
|
-
if (typeof consumeMessageFn === 'function') {
|
|
109
|
-
consumeMessageFn(msg, channel)
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* preProcessMessage
|
|
115
|
-
* If the parameter preProcessMessageFn is passed, it will use that function to process the data.
|
|
116
|
-
* @since 0.0.1
|
|
117
|
-
* @param message {any} The data you want to send, however it must be a string.
|
|
118
|
-
*/
|
|
119
|
-
function preProcessMessage(message: any): string {
|
|
120
|
-
if (typeof preProcessMessageFn === 'function') {
|
|
121
|
-
return preProcessMessageFn(message)
|
|
122
|
-
} else {
|
|
123
|
-
return message
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const channel = await getRabbitChannel(confirmChannel)
|
|
128
|
-
|
|
129
|
-
await channel?.assertQueue(queue, { durable: false }).then(async () => {
|
|
130
|
-
return await channel.consume(queue, async (msg:amqp.ConsumeMessage | null): Promise<void> => {
|
|
131
|
-
await consumeRabbitMessage(<ConsumeMessage>msg, channel)
|
|
132
|
-
}, {
|
|
133
|
-
noAck: true
|
|
134
|
-
})
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* publishMessage
|
|
139
|
-
* @since 0.0.1
|
|
140
|
-
* @param sendQueue {string} The target queue.
|
|
141
|
-
* @param message {any} You can publish anything as long as it goes out over as a string.
|
|
142
|
-
*/
|
|
143
|
-
function publishMessage (sendQueue: string, message: any): void {
|
|
144
|
-
channel?.publish('', sendQueue, Buffer.from(preProcessMessage(message)))
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* directMessage
|
|
149
|
-
* @since 0.0.1
|
|
150
|
-
* @param sendQueue {string} The target queue and directed to that queue. No one else can take it.
|
|
151
|
-
* @param message {any} You can publish anything as long as it goes out over as a string.
|
|
152
|
-
*/
|
|
153
|
-
function directMessage (sendQueue: string, message: any): void {
|
|
154
|
-
channel?.sendToQueue(sendQueue, Buffer.from(preProcessMessage(message)), {
|
|
155
|
-
replyTo: queue
|
|
156
|
-
})
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Decorate Fastify
|
|
161
|
-
*/
|
|
162
|
-
decorateFastifyInstance(fastify, options, {publishMessage, directMessage})
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
export default fastifyRabbit
|
package/tsconfig.json
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"files": ["index.ts"],
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"target": "es2015",
|
|
5
|
-
"module": "es2015",
|
|
6
|
-
"moduleResolution": "node",
|
|
7
|
-
"declaration": true,
|
|
8
|
-
"outDir": "./dist",
|
|
9
|
-
"noEmit": false,
|
|
10
|
-
"strict": true,
|
|
11
|
-
"noImplicitAny": true,
|
|
12
|
-
"strictNullChecks": true,
|
|
13
|
-
"strictFunctionTypes": true,
|
|
14
|
-
"strictBindCallApply": true,
|
|
15
|
-
"strictPropertyInitialization": true,
|
|
16
|
-
"noImplicitThis": true,
|
|
17
|
-
"alwaysStrict": true,
|
|
18
|
-
"noUnusedLocals": true,
|
|
19
|
-
"noUnusedParameters": true,
|
|
20
|
-
"noImplicitReturns": true,
|
|
21
|
-
"noFallthroughCasesInSwitch": true,
|
|
22
|
-
"noUncheckedIndexedAccess": true,
|
|
23
|
-
"noImplicitOverride": true,
|
|
24
|
-
"noPropertyAccessFromIndexSignature": true,
|
|
25
|
-
"esModuleInterop": true,
|
|
26
|
-
"forceConsistentCasingInFileNames": true,
|
|
27
|
-
"skipLibCheck": true
|
|
28
|
-
}
|
|
29
|
-
}
|