UNPKG

9.76 kBJavaScriptView Raw
1"use strict";
2// *****************************************************************************
3// Copyright (C) 2018 TypeFox and others.
4//
5// This program and the accompanying materials are made available under the
6// terms of the Eclipse Public License v. 2.0 which is available at
7// http://www.eclipse.org/legal/epl-2.0.
8//
9// This Source Code may also be made available under the following Secondary
10// Licenses when the conditions for such availability set forth in the Eclipse
11// Public License v. 2.0 are satisfied: GNU General Public License, version 2
12// with the GNU Classpath Exception which is available at
13// https://www.gnu.org/software/classpath/license.html.
14//
15// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
16// *****************************************************************************
17var __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};
23var __metadata = (this && this.__metadata) || function (k, v) {
24 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25};
26var MessagingContribution_1;
27Object.defineProperty(exports, "__esModule", { value: true });
28exports.MessagingContribution = exports.MessagingContainer = void 0;
29const socket_io_1 = require("socket.io");
30const inversify_1 = require("inversify");
31const common_1 = require("../../common");
32const web_socket_channel_1 = require("../../common/messaging/web-socket-channel");
33const messaging_service_1 = require("./messaging-service");
34const connection_container_module_1 = require("./connection-container-module");
35const Route = require("route-parser");
36const ws_request_validators_1 = require("../ws-request-validators");
37const messaging_listeners_1 = require("./messaging-listeners");
38const channel_1 = require("../../common/message-rpc/channel");
39exports.MessagingContainer = Symbol('MessagingContainer');
40let 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; // 30 seconds
45 this.maxHttpBufferSize = 1e8; // 100 MB
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 // Accept every namespace by using /.*/
66 socketServer.of(/.*/).on('connection', async (socket) => {
67 const request = socket.request;
68 // Socket.io strips the `origin` header of the incoming request
69 // We provide a `fix-origin` header in the `WebSocketConnectionProvider`
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);
167MessagingContribution = MessagingContribution_1 = __decorate([
168 (0, inversify_1.injectable)()
169], MessagingContribution);
170exports.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 = {}));
208exports.MessagingContribution = MessagingContribution;
209//# sourceMappingURL=messaging-contribution.js.map
\No newline at end of file