1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119 | 1x
1x
1x
1x
1x
12x
12x
12x
12x
12x
12x
12x
12x
12x
12x
12x
3x
2x
2x
3x
3x
3x
3x
3x
4x
4x
4x
4x
2x
2x
2x
2x
2x
1x
1x
1x
1x
2x
1x
1x
1x
| import { loadPackage } from '@nestjs/common/utils/load-package.util';
import { Observable } from 'rxjs';
import {
CONNECT_EVENT,
DISCONNECTED_RMQ_MESSAGE,
DISCONNECT_EVENT,
NO_PATTERN_MESSAGE,
RQM_DEFAULT_IS_GLOBAL_PREFETCH_COUNT,
RQM_DEFAULT_PREFETCH_COUNT,
RQM_DEFAULT_QUEUE,
RQM_DEFAULT_QUEUE_OPTIONS,
RQM_DEFAULT_URL,
} from '../constants';
import { CustomTransportStrategy, RmqOptions } from '../interfaces';
import { MicroserviceOptions } from '../interfaces/microservice-configuration.interface';
import { Server } from './server';
let rqmPackage: any = {};
export class ServerRMQ extends Server implements CustomTransportStrategy {
private server: any = null;
private channel: any = null;
private readonly urls: string[];
private readonly queue: string;
private readonly prefetchCount: number;
private readonly queueOptions: any;
private readonly isGlobalPrefetchCount: boolean;
constructor(private readonly options: MicroserviceOptions) {
super();
this.urls = this.getOptionsProp<RmqOptions>(this.options, 'urls') || [
RQM_DEFAULT_URL,
];
this.queue =
this.getOptionsProp<RmqOptions>(this.options, 'queue') ||
RQM_DEFAULT_QUEUE;
this.prefetchCount =
this.getOptionsProp<RmqOptions>(this.options, 'prefetchCount') ||
RQM_DEFAULT_PREFETCH_COUNT;
this.isGlobalPrefetchCount =
this.getOptionsProp<RmqOptions>(this.options, 'isGlobalPrefetchCount') ||
RQM_DEFAULT_IS_GLOBAL_PREFETCH_COUNT;
this.queueOptions =
this.getOptionsProp<RmqOptions>(this.options, 'queueOptions') ||
RQM_DEFAULT_QUEUE_OPTIONS;
loadPackage('amqplib', ServerRMQ.name);
rqmPackage = loadPackage('amqp-connection-manager', ServerRMQ.name);
}
public async listen(callback: () => void): Promise<void> {
await this.start(callback);
}
public close(): void {
this.channel && this.channel.close();
this.server && this.server.close();
}
public async start(callback?: () => void) {
this.server = this.createClient();
this.server.on(CONNECT_EVENT, _ => {
this.channel = this.server.createChannel({
json: false,
setup: channel => this.setupChannel(channel, callback),
});
});
this.server.on(DISCONNECT_EVENT, err => {
this.logger.error(DISCONNECTED_RMQ_MESSAGE);
});
}
public createClient<T = any>(): T {
return rqmPackage.connect(this.urls);
}
public async setupChannel(channel: any, callback: Function) {
await channel.assertQueue(this.queue, this.queueOptions);
await channel.prefetch(this.prefetchCount, this.isGlobalPrefetchCount);
channel.consume(this.queue, msg => this.handleMessage(msg), {
noAck: true,
});
callback();
}
public async handleMessage(message: any): Promise<void> {
const { content, properties } = message;
const packet = JSON.parse(content.toString());
const pattern = JSON.stringify(packet.pattern);
const handler = this.getHandlerByPattern(pattern);
if (!handler) {
const status = 'error';
return this.sendMessage(
{ status, err: NO_PATTERN_MESSAGE },
properties.replyTo,
properties.correlationId,
);
}
const response$ = this.transformToObservable(
await handler(packet.data),
) as Observable<any>;
const publish = data =>
this.sendMessage(data, properties.replyTo, properties.correlationId);
response$ && this.send(response$, publish);
}
public sendMessage<T = any>(
message: T,
replyTo: any,
correlationId: string,
): void {
const buffer = Buffer.from(JSON.stringify(message));
this.channel.sendToQueue(replyTo, buffer, { correlationId });
}
}
|