1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
18 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
19 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
20 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
21 | return c > 3 && r && Object.defineProperty(target, key, r), r;
|
22 | };
|
23 | var __metadata = (this && this.__metadata) || function (k, v) {
|
24 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
25 | };
|
26 | var MessagingContribution_1;
|
27 | Object.defineProperty(exports, "__esModule", { value: true });
|
28 | exports.MessagingContribution = exports.MessagingContainer = void 0;
|
29 | const socket_io_1 = require("socket.io");
|
30 | const inversify_1 = require("inversify");
|
31 | const common_1 = require("../../common");
|
32 | const web_socket_channel_1 = require("../../common/messaging/web-socket-channel");
|
33 | const messaging_service_1 = require("./messaging-service");
|
34 | const connection_container_module_1 = require("./connection-container-module");
|
35 | const Route = require("route-parser");
|
36 | const ws_request_validators_1 = require("../ws-request-validators");
|
37 | const messaging_listeners_1 = require("./messaging-listeners");
|
38 | const channel_1 = require("../../common/message-rpc/channel");
|
39 | exports.MessagingContainer = Symbol('MessagingContainer');
|
40 | let MessagingContribution = MessagingContribution_1 = class MessagingContribution {
|
41 | constructor() {
|
42 | this.wsHandlers = new MessagingContribution_1.ConnectionHandlers();
|
43 | this.channelHandlers = new MessagingContribution_1.ConnectionHandlers();
|
44 | this.checkAliveTimeout = 30000;
|
45 | this.maxHttpBufferSize = 1e8;
|
46 | }
|
47 | init() {
|
48 | this.ws(web_socket_channel_1.WebSocketChannel.wsPath, (_, socket) => this.handleChannels(socket));
|
49 | for (const contribution of this.contributions.getContributions()) {
|
50 | contribution.configure(this);
|
51 | }
|
52 | }
|
53 | wsChannel(spec, callback) {
|
54 | this.channelHandlers.push(spec, (params, channel) => callback(params, channel));
|
55 | }
|
56 | ws(spec, callback) {
|
57 | this.wsHandlers.push(spec, callback);
|
58 | }
|
59 | onStart(server) {
|
60 | const socketServer = new socket_io_1.Server(server, {
|
61 | pingInterval: this.checkAliveTimeout,
|
62 | pingTimeout: this.checkAliveTimeout * 2,
|
63 | maxHttpBufferSize: this.maxHttpBufferSize
|
64 | });
|
65 |
|
66 | socketServer.of(/.*/).on('connection', async (socket) => {
|
67 | const request = socket.request;
|
68 |
|
69 |
|
70 | request.headers.origin = request.headers['fix-origin'];
|
71 | if (await this.allowConnect(socket.request)) {
|
72 | this.handleConnection(socket);
|
73 | this.messagingListener.onDidWebSocketUpgrade(socket.request, socket);
|
74 | }
|
75 | else {
|
76 | socket.disconnect(true);
|
77 | }
|
78 | });
|
79 | }
|
80 | handleConnection(socket) {
|
81 | const pathname = socket.nsp.name;
|
82 | if (pathname && !this.wsHandlers.route(pathname, socket)) {
|
83 | console.error('Cannot find a ws handler for the path: ' + pathname);
|
84 | }
|
85 | }
|
86 | async allowConnect(request) {
|
87 | try {
|
88 | return this.wsRequestValidator.allowWsUpgrade(request);
|
89 | }
|
90 | catch (e) {
|
91 | return false;
|
92 | }
|
93 | }
|
94 | handleChannels(socket) {
|
95 | const socketChannel = new web_socket_channel_1.WebSocketChannel(this.toIWebSocket(socket));
|
96 | const multiplexer = new channel_1.ChannelMultiplexer(socketChannel);
|
97 | const channelHandlers = this.getConnectionChannelHandlers(socket);
|
98 | multiplexer.onDidOpenChannel(event => {
|
99 | if (channelHandlers.route(event.id, event.channel)) {
|
100 | console.debug(`Opening channel for service path '${event.id}'.`);
|
101 | event.channel.onClose(() => console.debug(`Closing channel on service path '${event.id}'.`));
|
102 | }
|
103 | });
|
104 | }
|
105 | toIWebSocket(socket) {
|
106 | return {
|
107 | close: () => {
|
108 | socket.removeAllListeners('disconnect');
|
109 | socket.removeAllListeners('error');
|
110 | socket.removeAllListeners('message');
|
111 | socket.disconnect();
|
112 | },
|
113 | isConnected: () => socket.connected,
|
114 | onClose: cb => socket.on('disconnect', reason => cb(reason)),
|
115 | onError: cb => socket.on('error', error => cb(error)),
|
116 | onMessage: cb => socket.on('message', data => cb(data)),
|
117 | send: message => socket.emit('message', message)
|
118 | };
|
119 | }
|
120 | createSocketContainer(socket) {
|
121 | const connectionContainer = this.container.createChild();
|
122 | connectionContainer.bind(socket_io_1.Socket).toConstantValue(socket);
|
123 | return connectionContainer;
|
124 | }
|
125 | getConnectionChannelHandlers(socket) {
|
126 | const connectionContainer = this.createSocketContainer(socket);
|
127 | (0, common_1.bindContributionProvider)(connectionContainer, common_1.ConnectionHandler);
|
128 | connectionContainer.load(...this.connectionModules.getContributions());
|
129 | const connectionChannelHandlers = new MessagingContribution_1.ConnectionHandlers(this.channelHandlers);
|
130 | const connectionHandlers = connectionContainer.getNamed(common_1.ContributionProvider, common_1.ConnectionHandler);
|
131 | for (const connectionHandler of connectionHandlers.getContributions(true)) {
|
132 | connectionChannelHandlers.push(connectionHandler.path, (_, channel) => {
|
133 | connectionHandler.onConnection(channel);
|
134 | });
|
135 | }
|
136 | return connectionChannelHandlers;
|
137 | }
|
138 | };
|
139 | __decorate([
|
140 | (0, inversify_1.inject)(exports.MessagingContainer),
|
141 | __metadata("design:type", Object)
|
142 | ], MessagingContribution.prototype, "container", void 0);
|
143 | __decorate([
|
144 | (0, inversify_1.inject)(common_1.ContributionProvider),
|
145 | (0, inversify_1.named)(connection_container_module_1.ConnectionContainerModule),
|
146 | __metadata("design:type", Object)
|
147 | ], MessagingContribution.prototype, "connectionModules", void 0);
|
148 | __decorate([
|
149 | (0, inversify_1.inject)(common_1.ContributionProvider),
|
150 | (0, inversify_1.named)(messaging_service_1.MessagingService.Contribution),
|
151 | __metadata("design:type", Object)
|
152 | ], MessagingContribution.prototype, "contributions", void 0);
|
153 | __decorate([
|
154 | (0, inversify_1.inject)(ws_request_validators_1.WsRequestValidator),
|
155 | __metadata("design:type", ws_request_validators_1.WsRequestValidator)
|
156 | ], MessagingContribution.prototype, "wsRequestValidator", void 0);
|
157 | __decorate([
|
158 | (0, inversify_1.inject)(messaging_listeners_1.MessagingListener),
|
159 | __metadata("design:type", messaging_listeners_1.MessagingListener)
|
160 | ], MessagingContribution.prototype, "messagingListener", void 0);
|
161 | __decorate([
|
162 | (0, inversify_1.postConstruct)(),
|
163 | __metadata("design:type", Function),
|
164 | __metadata("design:paramtypes", []),
|
165 | __metadata("design:returntype", void 0)
|
166 | ], MessagingContribution.prototype, "init", null);
|
167 | MessagingContribution = MessagingContribution_1 = __decorate([
|
168 | (0, inversify_1.injectable)()
|
169 | ], MessagingContribution);
|
170 | exports.MessagingContribution = MessagingContribution;
|
171 | (function (MessagingContribution) {
|
172 | class ConnectionHandlers {
|
173 | constructor(parent) {
|
174 | this.parent = parent;
|
175 | this.handlers = [];
|
176 | }
|
177 | push(spec, callback) {
|
178 | const route = new Route(spec);
|
179 | this.handlers.push((path, channel) => {
|
180 | const params = route.match(path);
|
181 | if (!params) {
|
182 | return false;
|
183 | }
|
184 | callback(params, channel);
|
185 | return route.reverse(params);
|
186 | });
|
187 | }
|
188 | route(path, connection) {
|
189 | for (const handler of this.handlers) {
|
190 | try {
|
191 | const result = handler(path, connection);
|
192 | if (result) {
|
193 | return result;
|
194 | }
|
195 | }
|
196 | catch (e) {
|
197 | console.error(e);
|
198 | }
|
199 | }
|
200 | if (this.parent) {
|
201 | return this.parent.route(path, connection);
|
202 | }
|
203 | return false;
|
204 | }
|
205 | }
|
206 | MessagingContribution.ConnectionHandlers = ConnectionHandlers;
|
207 | })(MessagingContribution = exports.MessagingContribution || (exports.MessagingContribution = {}));
|
208 | exports.MessagingContribution = MessagingContribution;
|
209 |
|
\ | No newline at end of file |