1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | Object.defineProperty(exports, "__esModule", { value: true });
|
18 | exports.WebSocketConnectionSource = void 0;
|
19 | const tslib_1 = require("tslib");
|
20 | const common_1 = require("../../common");
|
21 | const socket_io_client_1 = require("socket.io-client");
|
22 | const endpoint_1 = require("../endpoint");
|
23 | const channel_1 = require("../../common/message-rpc/channel");
|
24 | const uint8_array_message_buffer_1 = require("../../common/message-rpc/uint8-array-message-buffer");
|
25 | const inversify_1 = require("inversify");
|
26 | const frontend_id_provider_1 = require("./frontend-id-provider");
|
27 | const frontend_application_config_provider_1 = require("../frontend-application-config-provider");
|
28 | const socket_write_buffer_1 = require("../../common/messaging/socket-write-buffer");
|
29 | const connection_management_1 = require("../../common/messaging/connection-management");
|
30 | let WebSocketConnectionSource = class WebSocketConnectionSource {
|
31 | constructor() {
|
32 | this.writeBuffer = new socket_write_buffer_1.SocketWriteBuffer();
|
33 | this.onConnectionDidOpenEmitter = new common_1.Emitter();
|
34 | this.onSocketDidOpenEmitter = new common_1.Emitter();
|
35 | this.onSocketDidCloseEmitter = new common_1.Emitter();
|
36 | this.onIncomingMessageActivityEmitter = new common_1.Emitter();
|
37 | }
|
38 | get socket() {
|
39 | return this._socket;
|
40 | }
|
41 | get onConnectionDidOpen() {
|
42 | return this.onConnectionDidOpenEmitter.event;
|
43 | }
|
44 | get onSocketDidOpen() {
|
45 | return this.onSocketDidOpenEmitter.event;
|
46 | }
|
47 | get onSocketDidClose() {
|
48 | return this.onSocketDidCloseEmitter.event;
|
49 | }
|
50 | get onIncomingMessageActivity() {
|
51 | return this.onIncomingMessageActivityEmitter.event;
|
52 | }
|
53 | openSocket() {
|
54 | const url = this.createWebSocketUrl(common_1.servicesPath);
|
55 | this._socket = this.createWebSocket(url);
|
56 | this._socket.on('connect', () => {
|
57 | this.onSocketDidOpenEmitter.fire();
|
58 | this.handleSocketConnected();
|
59 | });
|
60 | this._socket.on('disconnect', () => {
|
61 | this.onSocketDidCloseEmitter.fire();
|
62 | });
|
63 | this._socket.on('error', reason => {
|
64 | if (this.currentChannel) {
|
65 | this.currentChannel.onErrorEmitter.fire(reason);
|
66 | }
|
67 | ;
|
68 | });
|
69 | this._socket.connect();
|
70 | }
|
71 | negogiateReconnect() {
|
72 | const reconnectListener = (hasConnection) => {
|
73 | this._socket.off(connection_management_1.ConnectionManagementMessages.RECONNECT, reconnectListener);
|
74 | if (hasConnection) {
|
75 | console.info(`reconnect succeeded on ${this.socket.id}`);
|
76 | this.writeBuffer.flush(this.socket);
|
77 | }
|
78 | else {
|
79 | if (frontend_application_config_provider_1.FrontendApplicationConfigProvider.get().reloadOnReconnect) {
|
80 | window.location.reload();
|
81 | }
|
82 | else {
|
83 | console.info(`reconnect failed on ${this.socket.id}`);
|
84 | this.currentChannel.onCloseEmitter.fire({ reason: 'reconnecting channel' });
|
85 | this.currentChannel.close();
|
86 | this.writeBuffer.drain();
|
87 | this.socket.disconnect();
|
88 | this.socket.connect();
|
89 | this.negotiateInitialConnect();
|
90 | }
|
91 | }
|
92 | };
|
93 | this._socket.on(connection_management_1.ConnectionManagementMessages.RECONNECT, reconnectListener);
|
94 | console.info(`sending reconnect on ${this.socket.id}`);
|
95 | this._socket.emit(connection_management_1.ConnectionManagementMessages.RECONNECT, this.frontendIdProvider.getId());
|
96 | }
|
97 | negotiateInitialConnect() {
|
98 | const initialConnectListener = () => {
|
99 | console.info(`initial connect received on ${this.socket.id}`);
|
100 | this._socket.off(connection_management_1.ConnectionManagementMessages.INITIAL_CONNECT, initialConnectListener);
|
101 | this.connectNewChannel();
|
102 | };
|
103 | this._socket.on(connection_management_1.ConnectionManagementMessages.INITIAL_CONNECT, initialConnectListener);
|
104 | console.info(`sending initial connect on ${this.socket.id}`);
|
105 | this._socket.emit(connection_management_1.ConnectionManagementMessages.INITIAL_CONNECT, this.frontendIdProvider.getId());
|
106 | }
|
107 | handleSocketConnected() {
|
108 | if (this.currentChannel) {
|
109 | this.negogiateReconnect();
|
110 | }
|
111 | else {
|
112 | this.negotiateInitialConnect();
|
113 | }
|
114 | }
|
115 | connectNewChannel() {
|
116 | if (this.currentChannel) {
|
117 | this.currentChannel.close();
|
118 | this.currentChannel.onCloseEmitter.fire({ reason: 'reconnecting channel' });
|
119 | }
|
120 | this.writeBuffer.drain();
|
121 | this.currentChannel = this.createChannel();
|
122 | this.onConnectionDidOpenEmitter.fire(this.currentChannel);
|
123 | }
|
124 | createChannel() {
|
125 | const toDispose = new common_1.DisposableCollection();
|
126 |
|
127 | const messageHandler = (data) => {
|
128 | this.onIncomingMessageActivityEmitter.fire();
|
129 | if (this.currentChannel) {
|
130 |
|
131 |
|
132 | const buffer = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
133 | this.currentChannel.onMessageEmitter.fire(() => new uint8_array_message_buffer_1.Uint8ArrayReadBuffer(buffer));
|
134 | }
|
135 | ;
|
136 | };
|
137 | this._socket.on('message', messageHandler);
|
138 | toDispose.push(common_1.Disposable.create(() => {
|
139 | this.socket.off('message', messageHandler);
|
140 | }));
|
141 | const channel = new channel_1.ForwardingChannel('any', () => {
|
142 | toDispose.dispose();
|
143 | }, () => {
|
144 | const result = new uint8_array_message_buffer_1.Uint8ArrayWriteBuffer();
|
145 | result.onCommit(buffer => {
|
146 | if (this.socket.connected) {
|
147 | this.socket.send(buffer);
|
148 | }
|
149 | else {
|
150 | this.writeBuffer.buffer(buffer);
|
151 | }
|
152 | });
|
153 | return result;
|
154 | });
|
155 | return channel;
|
156 | }
|
157 | |
158 |
|
159 |
|
160 | createWebSocketUrl(path) {
|
161 |
|
162 |
|
163 | return this.createEndpoint(path).getWebSocketUrl().withPath(path).toString();
|
164 | }
|
165 | createHttpWebSocketUrl(path) {
|
166 | return this.createEndpoint(path).getRestUrl().toString();
|
167 | }
|
168 | createEndpoint(path) {
|
169 | return new endpoint_1.Endpoint({ path });
|
170 | }
|
171 | |
172 |
|
173 |
|
174 | createWebSocket(url) {
|
175 | return (0, socket_io_client_1.io)(url, {
|
176 | path: this.createSocketIoPath(url),
|
177 | reconnection: true,
|
178 | reconnectionDelay: 1000,
|
179 | reconnectionDelayMax: 10000,
|
180 | reconnectionAttempts: Infinity,
|
181 | extraHeaders: {
|
182 |
|
183 |
|
184 | 'fix-origin': window.location.origin
|
185 | }
|
186 | });
|
187 | }
|
188 | |
189 |
|
190 |
|
191 | createSocketIoPath(url) {
|
192 | if (location.protocol === endpoint_1.Endpoint.PROTO_FILE) {
|
193 | return '/socket.io';
|
194 | }
|
195 | let { pathname } = location;
|
196 | if (!pathname.endsWith('/')) {
|
197 | pathname += '/';
|
198 | }
|
199 | return pathname + 'socket.io';
|
200 | }
|
201 | };
|
202 | WebSocketConnectionSource.NO_CONNECTION = '<none>';
|
203 | (0, tslib_1.__decorate)([
|
204 | (0, inversify_1.inject)(frontend_id_provider_1.FrontendIdProvider),
|
205 | (0, tslib_1.__metadata)("design:type", Object)
|
206 | ], WebSocketConnectionSource.prototype, "frontendIdProvider", void 0);
|
207 | (0, tslib_1.__decorate)([
|
208 | (0, inversify_1.postConstruct)(),
|
209 | (0, tslib_1.__metadata)("design:type", Function),
|
210 | (0, tslib_1.__metadata)("design:paramtypes", []),
|
211 | (0, tslib_1.__metadata)("design:returntype", void 0)
|
212 | ], WebSocketConnectionSource.prototype, "openSocket", null);
|
213 | WebSocketConnectionSource = (0, tslib_1.__decorate)([
|
214 | (0, inversify_1.injectable)(),
|
215 | (0, tslib_1.__metadata)("design:paramtypes", [])
|
216 | ], WebSocketConnectionSource);
|
217 | exports.WebSocketConnectionSource = WebSocketConnectionSource;
|
218 |
|
\ | No newline at end of file |