mongodb-livedata-server 0.1.3 → 0.1.5
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 +2 -2
- package/dist/livedata_server.d.ts +4 -4
- package/dist/livedata_server.js +11 -11
- package/dist/meteor/binary-heap/max_heap.d.ts +31 -31
- package/dist/meteor/binary-heap/max_heap.js +186 -186
- package/dist/meteor/binary-heap/min_heap.d.ts +6 -6
- package/dist/meteor/binary-heap/min_heap.js +17 -17
- package/dist/meteor/binary-heap/min_max_heap.d.ts +11 -11
- package/dist/meteor/binary-heap/min_max_heap.js +48 -48
- package/dist/meteor/callback-hook/hook.d.ts +11 -11
- package/dist/meteor/callback-hook/hook.js +78 -78
- package/dist/meteor/ddp/crossbar.d.ts +15 -15
- package/dist/meteor/ddp/crossbar.js +136 -136
- package/dist/meteor/ddp/heartbeat.d.ts +19 -19
- package/dist/meteor/ddp/heartbeat.js +77 -77
- package/dist/meteor/ddp/livedata_server.d.ts +141 -142
- package/dist/meteor/ddp/livedata_server.js +403 -403
- package/dist/meteor/ddp/method-invocation.d.ts +35 -35
- package/dist/meteor/ddp/method-invocation.js +72 -72
- package/dist/meteor/ddp/random-stream.d.ts +8 -8
- package/dist/meteor/ddp/random-stream.js +100 -100
- package/dist/meteor/ddp/session-collection-view.d.ts +20 -20
- package/dist/meteor/ddp/session-collection-view.js +106 -106
- package/dist/meteor/ddp/session-document-view.d.ts +8 -8
- package/dist/meteor/ddp/session-document-view.js +82 -82
- package/dist/meteor/ddp/session.d.ts +75 -75
- package/dist/meteor/ddp/session.js +590 -590
- package/dist/meteor/ddp/stream_server.d.ts +20 -21
- package/dist/meteor/ddp/stream_server.js +181 -181
- package/dist/meteor/ddp/subscription.d.ts +94 -94
- package/dist/meteor/ddp/subscription.js +370 -370
- package/dist/meteor/ddp/utils.d.ts +8 -8
- package/dist/meteor/ddp/utils.js +104 -104
- package/dist/meteor/ddp/writefence.d.ts +20 -20
- package/dist/meteor/ddp/writefence.js +111 -111
- package/dist/meteor/diff-sequence/diff.d.ts +17 -17
- package/dist/meteor/diff-sequence/diff.js +257 -257
- package/dist/meteor/ejson/ejson.d.ts +82 -82
- package/dist/meteor/ejson/ejson.js +568 -569
- package/dist/meteor/ejson/stringify.d.ts +2 -2
- package/dist/meteor/ejson/stringify.js +119 -119
- package/dist/meteor/ejson/utils.d.ts +12 -12
- package/dist/meteor/ejson/utils.js +42 -42
- package/dist/meteor/mongo/caching_change_observer.d.ts +16 -16
- package/dist/meteor/mongo/caching_change_observer.js +63 -63
- package/dist/meteor/mongo/doc_fetcher.d.ts +7 -7
- package/dist/meteor/mongo/doc_fetcher.js +53 -53
- package/dist/meteor/mongo/geojson_utils.d.ts +3 -3
- package/dist/meteor/mongo/geojson_utils.js +40 -41
- package/dist/meteor/mongo/live_connection.d.ts +28 -28
- package/dist/meteor/mongo/live_connection.js +264 -264
- package/dist/meteor/mongo/live_cursor.d.ts +25 -25
- package/dist/meteor/mongo/live_cursor.js +60 -60
- package/dist/meteor/mongo/minimongo_common.d.ts +84 -84
- package/dist/meteor/mongo/minimongo_common.js +1998 -1998
- package/dist/meteor/mongo/minimongo_matcher.d.ts +23 -23
- package/dist/meteor/mongo/minimongo_matcher.js +283 -283
- package/dist/meteor/mongo/minimongo_sorter.d.ts +16 -16
- package/dist/meteor/mongo/minimongo_sorter.js +268 -268
- package/dist/meteor/mongo/observe_driver_utils.d.ts +9 -9
- package/dist/meteor/mongo/observe_driver_utils.js +72 -73
- package/dist/meteor/mongo/observe_multiplexer.d.ts +46 -46
- package/dist/meteor/mongo/observe_multiplexer.js +203 -203
- package/dist/meteor/mongo/oplog-observe-driver.d.ts +68 -68
- package/dist/meteor/mongo/oplog-observe-driver.js +918 -918
- package/dist/meteor/mongo/oplog_tailing.d.ts +35 -35
- package/dist/meteor/mongo/oplog_tailing.js +352 -352
- package/dist/meteor/mongo/oplog_v2_converter.d.ts +1 -1
- package/dist/meteor/mongo/oplog_v2_converter.js +125 -126
- package/dist/meteor/mongo/polling_observe_driver.d.ts +30 -30
- package/dist/meteor/mongo/polling_observe_driver.js +216 -221
- package/dist/meteor/mongo/synchronous-cursor.d.ts +17 -17
- package/dist/meteor/mongo/synchronous-cursor.js +261 -261
- package/dist/meteor/mongo/synchronous-queue.d.ts +13 -13
- package/dist/meteor/mongo/synchronous-queue.js +110 -110
- package/dist/meteor/ordered-dict/ordered_dict.d.ts +31 -31
- package/dist/meteor/ordered-dict/ordered_dict.js +198 -198
- package/dist/meteor/random/AbstractRandomGenerator.d.ts +42 -42
- package/dist/meteor/random/AbstractRandomGenerator.js +92 -92
- package/dist/meteor/random/AleaRandomGenerator.d.ts +13 -13
- package/dist/meteor/random/AleaRandomGenerator.js +90 -90
- package/dist/meteor/random/NodeRandomGenerator.d.ts +16 -16
- package/dist/meteor/random/NodeRandomGenerator.js +42 -42
- package/dist/meteor/random/createAleaGenerator.d.ts +2 -2
- package/dist/meteor/random/createAleaGenerator.js +32 -32
- package/dist/meteor/random/createRandom.d.ts +1 -1
- package/dist/meteor/random/createRandom.js +22 -22
- package/dist/meteor/random/main.d.ts +1 -1
- package/dist/meteor/random/main.js +12 -12
- package/dist/meteor/types.d.ts +1 -1
- package/dist/meteor/types.js +2 -2
- package/package.json +5 -5
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
private
|
|
13
|
-
private
|
|
14
|
-
private
|
|
15
|
-
private
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
1
|
+
import { Server } from "http";
|
|
2
|
+
import sockjs from "sockjs";
|
|
3
|
+
import { DDPSession } from "./session";
|
|
4
|
+
export interface StreamServerSocket extends sockjs.Connection {
|
|
5
|
+
setWebsocketTimeout: Function;
|
|
6
|
+
_session?: any;
|
|
7
|
+
_meteorSession?: DDPSession;
|
|
8
|
+
send: Function;
|
|
9
|
+
}
|
|
10
|
+
export declare class StreamServer {
|
|
11
|
+
private httpServer;
|
|
12
|
+
private registration_callbacks;
|
|
13
|
+
private open_sockets;
|
|
14
|
+
private prefix;
|
|
15
|
+
private server;
|
|
16
|
+
constructor(httpServer: Server);
|
|
17
|
+
register(callback: (socket: StreamServerSocket) => void): void;
|
|
18
|
+
all_sockets(): StreamServerSocket[];
|
|
19
|
+
_redirectWebsocketEndpoint(): void;
|
|
20
|
+
}
|
|
@@ -1,181 +1,181 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.StreamServer = void 0;
|
|
7
|
-
const permessage_deflate_1 = __importDefault(require("permessage-deflate"));
|
|
8
|
-
const sockjs_1 = __importDefault(require("sockjs"));
|
|
9
|
-
const url_1 = __importDefault(require("url"));
|
|
10
|
-
// By default, we use the permessage-deflate extension with default
|
|
11
|
-
// configuration.
|
|
12
|
-
class StreamServer {
|
|
13
|
-
constructor(httpServer) {
|
|
14
|
-
this.httpServer = httpServer;
|
|
15
|
-
this.registration_callbacks = [];
|
|
16
|
-
this.open_sockets = [];
|
|
17
|
-
// Because we are installing directly onto WebApp.httpServer instead of using
|
|
18
|
-
// WebApp.app, we have to process the path prefix ourselves.
|
|
19
|
-
this.prefix = '/sockjs';
|
|
20
|
-
//RoutePolicy.declare(this.prefix + '/', 'network');
|
|
21
|
-
// set up sockjs
|
|
22
|
-
const serverOptions = {
|
|
23
|
-
prefix: this.prefix,
|
|
24
|
-
log: function () { },
|
|
25
|
-
// this is the default, but we code it explicitly because we depend
|
|
26
|
-
// on it in stream_client:HEARTBEAT_TIMEOUT
|
|
27
|
-
heartbeat_delay: 45000,
|
|
28
|
-
// The default disconnect_delay is 5 seconds, but if the server ends up CPU
|
|
29
|
-
// bound for that much time, SockJS might not notice that the user has
|
|
30
|
-
// reconnected because the timer (of disconnect_delay ms) can fire before
|
|
31
|
-
// SockJS processes the new connection. Eventually we'll fix this by not
|
|
32
|
-
// combining CPU-heavy processing with SockJS termination (eg a proxy which
|
|
33
|
-
// converts to Unix sockets) but for now, raise the delay.
|
|
34
|
-
disconnect_delay: 60 * 1000,
|
|
35
|
-
// Set the USE_JSESSIONID environment variable to enable setting the
|
|
36
|
-
// JSESSIONID cookie. This is useful for setting up proxies with
|
|
37
|
-
// session affinity.
|
|
38
|
-
jsessionid: !!process.env.USE_JSESSIONID,
|
|
39
|
-
websocket: true,
|
|
40
|
-
faye_server_options: null
|
|
41
|
-
};
|
|
42
|
-
// If you know your server environment (eg, proxies) will prevent websockets
|
|
43
|
-
// from ever working, set $DISABLE_WEBSOCKETS and SockJS clients (ie,
|
|
44
|
-
// browsers) will not waste time attempting to use them.
|
|
45
|
-
// (Your server will still have a /websocket endpoint.)
|
|
46
|
-
if (process.env.DISABLE_WEBSOCKETS) {
|
|
47
|
-
serverOptions.websocket = false;
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
serverOptions.faye_server_options = {
|
|
51
|
-
extensions: [permessage_deflate_1.default.configure({ maxWindowBits: 11, memLevel: 4 })]
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
this.server = sockjs_1.default.createServer(serverOptions);
|
|
55
|
-
// Install the sockjs handlers, but we want to keep around our own particular
|
|
56
|
-
// request handler that adjusts idle timeouts while we have an outstanding
|
|
57
|
-
// request. This compensates for the fact that sockjs removes all listeners
|
|
58
|
-
// for "request" to add its own.
|
|
59
|
-
httpServer.removeListener('request', _timeoutAdjustmentRequestCallback);
|
|
60
|
-
this.server.installHandlers(httpServer);
|
|
61
|
-
httpServer.addListener('request', _timeoutAdjustmentRequestCallback);
|
|
62
|
-
// Support the /websocket endpoint
|
|
63
|
-
this._redirectWebsocketEndpoint();
|
|
64
|
-
this.server.on('connection', (socket) => {
|
|
65
|
-
// sockjs sometimes passes us null instead of a socket object
|
|
66
|
-
// so we need to guard against that. see:
|
|
67
|
-
// https://github.com/sockjs/sockjs-node/issues/121
|
|
68
|
-
// https://github.com/meteor/meteor/issues/10468
|
|
69
|
-
if (!socket)
|
|
70
|
-
return;
|
|
71
|
-
// We want to make sure that if a client connects to us and does the initial
|
|
72
|
-
// Websocket handshake but never gets to the DDP handshake, that we
|
|
73
|
-
// eventually kill the socket. Once the DDP handshake happens, DDP
|
|
74
|
-
// heartbeating will work. And before the Websocket handshake, the timeouts
|
|
75
|
-
// we set at the server level in webapp_server.js will work. But
|
|
76
|
-
// faye-websocket calls setTimeout(0) on any socket it takes over, so there
|
|
77
|
-
// is an "in between" state where this doesn't happen. We work around this
|
|
78
|
-
// by explicitly setting the socket timeout to a relatively large time here,
|
|
79
|
-
// and setting it back to zero when we set up the heartbeat in
|
|
80
|
-
// livedata_server.js.
|
|
81
|
-
socket.setWebsocketTimeout = function (timeout) {
|
|
82
|
-
if ((socket.protocol === 'websocket' ||
|
|
83
|
-
socket.protocol === 'websocket-raw')
|
|
84
|
-
&& socket._session.recv) {
|
|
85
|
-
socket._session.recv.connection.setTimeout(timeout);
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
socket.setWebsocketTimeout(45 * 1000);
|
|
89
|
-
socket.send = (data) => {
|
|
90
|
-
socket.write(data);
|
|
91
|
-
};
|
|
92
|
-
socket.on('close', () => {
|
|
93
|
-
this.open_sockets = this.open_sockets.filter(s => s !== socket);
|
|
94
|
-
});
|
|
95
|
-
this.open_sockets.push(socket);
|
|
96
|
-
// only to send a message after connection on tests, useful for
|
|
97
|
-
// socket-stream-client/server-tests.js
|
|
98
|
-
if (process.env.TEST_METADATA && process.env.TEST_METADATA !== "{}") {
|
|
99
|
-
socket.send(JSON.stringify({ testMessageOnConnect: true }));
|
|
100
|
-
}
|
|
101
|
-
// call all our callbacks when we get a new socket. they will do the
|
|
102
|
-
// work of setting up handlers and such for specific messages.
|
|
103
|
-
for (const callback of this.registration_callbacks) {
|
|
104
|
-
callback(socket);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
;
|
|
109
|
-
// call my callback when a new socket connects.
|
|
110
|
-
// also call it for all current connections.
|
|
111
|
-
register(callback) {
|
|
112
|
-
var self = this;
|
|
113
|
-
self.registration_callbacks.push(callback);
|
|
114
|
-
for (const socket of self.all_sockets()) {
|
|
115
|
-
callback(socket);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
// get a list of all sockets
|
|
119
|
-
all_sockets() {
|
|
120
|
-
return Object.values(this.open_sockets);
|
|
121
|
-
}
|
|
122
|
-
// Redirect /websocket to /sockjs/websocket in order to not expose
|
|
123
|
-
// sockjs to clients that want to use raw websockets
|
|
124
|
-
_redirectWebsocketEndpoint() {
|
|
125
|
-
var self = this;
|
|
126
|
-
// Unfortunately we can't use a connect middleware here since
|
|
127
|
-
// sockjs installs itself prior to all existing listeners
|
|
128
|
-
// (meaning prior to any connect middlewares) so we need to take
|
|
129
|
-
// an approach similar to overshadowListeners in
|
|
130
|
-
// https://github.com/sockjs/sockjs-node/blob/cf820c55af6a9953e16558555a31decea554f70e/src/utils.coffee
|
|
131
|
-
['request', 'upgrade'].forEach((event) => {
|
|
132
|
-
var oldHttpServerListeners = this.httpServer.listeners(event).slice(0);
|
|
133
|
-
this.httpServer.removeAllListeners(event);
|
|
134
|
-
// request and upgrade have different arguments passed but
|
|
135
|
-
// we only care about the first one which is always request
|
|
136
|
-
var newListener = function (request /*, moreArguments */) {
|
|
137
|
-
// Store arguments for use within the closure below
|
|
138
|
-
var args = arguments;
|
|
139
|
-
// Rewrite /websocket and /websocket/ urls to /sockjs/websocket while
|
|
140
|
-
// preserving query string.
|
|
141
|
-
var parsedUrl = url_1.default.parse(request.url);
|
|
142
|
-
if (parsedUrl.pathname === '/websocket' ||
|
|
143
|
-
parsedUrl.pathname === '/websocket/') {
|
|
144
|
-
parsedUrl.pathname = self.prefix + '/websocket';
|
|
145
|
-
request.url = url_1.default.format(parsedUrl);
|
|
146
|
-
}
|
|
147
|
-
for (const oldListener of oldHttpServerListeners) {
|
|
148
|
-
oldListener.apply(this.httpServer, args);
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
this.httpServer.addListener(event, newListener);
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
exports.StreamServer = StreamServer;
|
|
156
|
-
const SHORT_SOCKET_TIMEOUT = 5 * 1000;
|
|
157
|
-
const LONG_SOCKET_TIMEOUT = 120 * 1000;
|
|
158
|
-
// When we have a request pending, we want the socket timeout to be long, to
|
|
159
|
-
// give ourselves a while to serve it, and to allow sockjs long polls to
|
|
160
|
-
// complete. On the other hand, we want to close idle sockets relatively
|
|
161
|
-
// quickly, so that we can shut down relatively promptly but cleanly, without
|
|
162
|
-
// cutting off anyone's response.
|
|
163
|
-
function _timeoutAdjustmentRequestCallback(req, res) {
|
|
164
|
-
// this is really just req.socket.setTimeout(LONG_SOCKET_TIMEOUT);
|
|
165
|
-
req.setTimeout(LONG_SOCKET_TIMEOUT);
|
|
166
|
-
// Insert our new finish listener to run BEFORE the existing one which removes
|
|
167
|
-
// the response from the socket.
|
|
168
|
-
var finishListeners = res.listeners('finish');
|
|
169
|
-
// XXX Apparently in Node 0.12 this event was called 'prefinish'.
|
|
170
|
-
// https://github.com/joyent/node/commit/7c9b6070
|
|
171
|
-
// But it has switched back to 'finish' in Node v4:
|
|
172
|
-
// https://github.com/nodejs/node/pull/1411
|
|
173
|
-
res.removeAllListeners('finish');
|
|
174
|
-
res.on('finish', function () {
|
|
175
|
-
res.setTimeout(SHORT_SOCKET_TIMEOUT);
|
|
176
|
-
});
|
|
177
|
-
for (const l of finishListeners) {
|
|
178
|
-
res.on('finish', l);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
;
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.StreamServer = void 0;
|
|
7
|
+
const permessage_deflate_1 = __importDefault(require("permessage-deflate"));
|
|
8
|
+
const sockjs_1 = __importDefault(require("sockjs"));
|
|
9
|
+
const url_1 = __importDefault(require("url"));
|
|
10
|
+
// By default, we use the permessage-deflate extension with default
|
|
11
|
+
// configuration.
|
|
12
|
+
class StreamServer {
|
|
13
|
+
constructor(httpServer) {
|
|
14
|
+
this.httpServer = httpServer;
|
|
15
|
+
this.registration_callbacks = [];
|
|
16
|
+
this.open_sockets = [];
|
|
17
|
+
// Because we are installing directly onto WebApp.httpServer instead of using
|
|
18
|
+
// WebApp.app, we have to process the path prefix ourselves.
|
|
19
|
+
this.prefix = '/sockjs';
|
|
20
|
+
//RoutePolicy.declare(this.prefix + '/', 'network');
|
|
21
|
+
// set up sockjs
|
|
22
|
+
const serverOptions = {
|
|
23
|
+
prefix: this.prefix,
|
|
24
|
+
log: function () { },
|
|
25
|
+
// this is the default, but we code it explicitly because we depend
|
|
26
|
+
// on it in stream_client:HEARTBEAT_TIMEOUT
|
|
27
|
+
heartbeat_delay: 45000,
|
|
28
|
+
// The default disconnect_delay is 5 seconds, but if the server ends up CPU
|
|
29
|
+
// bound for that much time, SockJS might not notice that the user has
|
|
30
|
+
// reconnected because the timer (of disconnect_delay ms) can fire before
|
|
31
|
+
// SockJS processes the new connection. Eventually we'll fix this by not
|
|
32
|
+
// combining CPU-heavy processing with SockJS termination (eg a proxy which
|
|
33
|
+
// converts to Unix sockets) but for now, raise the delay.
|
|
34
|
+
disconnect_delay: 60 * 1000,
|
|
35
|
+
// Set the USE_JSESSIONID environment variable to enable setting the
|
|
36
|
+
// JSESSIONID cookie. This is useful for setting up proxies with
|
|
37
|
+
// session affinity.
|
|
38
|
+
jsessionid: !!process.env.USE_JSESSIONID,
|
|
39
|
+
websocket: true,
|
|
40
|
+
faye_server_options: null
|
|
41
|
+
};
|
|
42
|
+
// If you know your server environment (eg, proxies) will prevent websockets
|
|
43
|
+
// from ever working, set $DISABLE_WEBSOCKETS and SockJS clients (ie,
|
|
44
|
+
// browsers) will not waste time attempting to use them.
|
|
45
|
+
// (Your server will still have a /websocket endpoint.)
|
|
46
|
+
if (process.env.DISABLE_WEBSOCKETS) {
|
|
47
|
+
serverOptions.websocket = false;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
serverOptions.faye_server_options = {
|
|
51
|
+
extensions: [permessage_deflate_1.default.configure({ maxWindowBits: 11, memLevel: 4 })]
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
this.server = sockjs_1.default.createServer(serverOptions);
|
|
55
|
+
// Install the sockjs handlers, but we want to keep around our own particular
|
|
56
|
+
// request handler that adjusts idle timeouts while we have an outstanding
|
|
57
|
+
// request. This compensates for the fact that sockjs removes all listeners
|
|
58
|
+
// for "request" to add its own.
|
|
59
|
+
httpServer.removeListener('request', _timeoutAdjustmentRequestCallback);
|
|
60
|
+
this.server.installHandlers(httpServer);
|
|
61
|
+
httpServer.addListener('request', _timeoutAdjustmentRequestCallback);
|
|
62
|
+
// Support the /websocket endpoint
|
|
63
|
+
this._redirectWebsocketEndpoint();
|
|
64
|
+
this.server.on('connection', (socket) => {
|
|
65
|
+
// sockjs sometimes passes us null instead of a socket object
|
|
66
|
+
// so we need to guard against that. see:
|
|
67
|
+
// https://github.com/sockjs/sockjs-node/issues/121
|
|
68
|
+
// https://github.com/meteor/meteor/issues/10468
|
|
69
|
+
if (!socket)
|
|
70
|
+
return;
|
|
71
|
+
// We want to make sure that if a client connects to us and does the initial
|
|
72
|
+
// Websocket handshake but never gets to the DDP handshake, that we
|
|
73
|
+
// eventually kill the socket. Once the DDP handshake happens, DDP
|
|
74
|
+
// heartbeating will work. And before the Websocket handshake, the timeouts
|
|
75
|
+
// we set at the server level in webapp_server.js will work. But
|
|
76
|
+
// faye-websocket calls setTimeout(0) on any socket it takes over, so there
|
|
77
|
+
// is an "in between" state where this doesn't happen. We work around this
|
|
78
|
+
// by explicitly setting the socket timeout to a relatively large time here,
|
|
79
|
+
// and setting it back to zero when we set up the heartbeat in
|
|
80
|
+
// livedata_server.js.
|
|
81
|
+
socket.setWebsocketTimeout = function (timeout) {
|
|
82
|
+
if ((socket.protocol === 'websocket' ||
|
|
83
|
+
socket.protocol === 'websocket-raw')
|
|
84
|
+
&& socket._session.recv) {
|
|
85
|
+
socket._session.recv.connection.setTimeout(timeout);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
socket.setWebsocketTimeout(45 * 1000);
|
|
89
|
+
socket.send = (data) => {
|
|
90
|
+
socket.write(data);
|
|
91
|
+
};
|
|
92
|
+
socket.on('close', () => {
|
|
93
|
+
this.open_sockets = this.open_sockets.filter(s => s !== socket);
|
|
94
|
+
});
|
|
95
|
+
this.open_sockets.push(socket);
|
|
96
|
+
// only to send a message after connection on tests, useful for
|
|
97
|
+
// socket-stream-client/server-tests.js
|
|
98
|
+
if (process.env.TEST_METADATA && process.env.TEST_METADATA !== "{}") {
|
|
99
|
+
socket.send(JSON.stringify({ testMessageOnConnect: true }));
|
|
100
|
+
}
|
|
101
|
+
// call all our callbacks when we get a new socket. they will do the
|
|
102
|
+
// work of setting up handlers and such for specific messages.
|
|
103
|
+
for (const callback of this.registration_callbacks) {
|
|
104
|
+
callback(socket);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
;
|
|
109
|
+
// call my callback when a new socket connects.
|
|
110
|
+
// also call it for all current connections.
|
|
111
|
+
register(callback) {
|
|
112
|
+
var self = this;
|
|
113
|
+
self.registration_callbacks.push(callback);
|
|
114
|
+
for (const socket of self.all_sockets()) {
|
|
115
|
+
callback(socket);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// get a list of all sockets
|
|
119
|
+
all_sockets() {
|
|
120
|
+
return Object.values(this.open_sockets);
|
|
121
|
+
}
|
|
122
|
+
// Redirect /websocket to /sockjs/websocket in order to not expose
|
|
123
|
+
// sockjs to clients that want to use raw websockets
|
|
124
|
+
_redirectWebsocketEndpoint() {
|
|
125
|
+
var self = this;
|
|
126
|
+
// Unfortunately we can't use a connect middleware here since
|
|
127
|
+
// sockjs installs itself prior to all existing listeners
|
|
128
|
+
// (meaning prior to any connect middlewares) so we need to take
|
|
129
|
+
// an approach similar to overshadowListeners in
|
|
130
|
+
// https://github.com/sockjs/sockjs-node/blob/cf820c55af6a9953e16558555a31decea554f70e/src/utils.coffee
|
|
131
|
+
['request', 'upgrade'].forEach((event) => {
|
|
132
|
+
var oldHttpServerListeners = this.httpServer.listeners(event).slice(0);
|
|
133
|
+
this.httpServer.removeAllListeners(event);
|
|
134
|
+
// request and upgrade have different arguments passed but
|
|
135
|
+
// we only care about the first one which is always request
|
|
136
|
+
var newListener = function (request /*, moreArguments */) {
|
|
137
|
+
// Store arguments for use within the closure below
|
|
138
|
+
var args = arguments;
|
|
139
|
+
// Rewrite /websocket and /websocket/ urls to /sockjs/websocket while
|
|
140
|
+
// preserving query string.
|
|
141
|
+
var parsedUrl = url_1.default.parse(request.url);
|
|
142
|
+
if (parsedUrl.pathname === '/websocket' ||
|
|
143
|
+
parsedUrl.pathname === '/websocket/') {
|
|
144
|
+
parsedUrl.pathname = self.prefix + '/websocket';
|
|
145
|
+
request.url = url_1.default.format(parsedUrl);
|
|
146
|
+
}
|
|
147
|
+
for (const oldListener of oldHttpServerListeners) {
|
|
148
|
+
oldListener.apply(this.httpServer, args);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
this.httpServer.addListener(event, newListener);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
exports.StreamServer = StreamServer;
|
|
156
|
+
const SHORT_SOCKET_TIMEOUT = 5 * 1000;
|
|
157
|
+
const LONG_SOCKET_TIMEOUT = 120 * 1000;
|
|
158
|
+
// When we have a request pending, we want the socket timeout to be long, to
|
|
159
|
+
// give ourselves a while to serve it, and to allow sockjs long polls to
|
|
160
|
+
// complete. On the other hand, we want to close idle sockets relatively
|
|
161
|
+
// quickly, so that we can shut down relatively promptly but cleanly, without
|
|
162
|
+
// cutting off anyone's response.
|
|
163
|
+
function _timeoutAdjustmentRequestCallback(req, res) {
|
|
164
|
+
// this is really just req.socket.setTimeout(LONG_SOCKET_TIMEOUT);
|
|
165
|
+
req.setTimeout(LONG_SOCKET_TIMEOUT);
|
|
166
|
+
// Insert our new finish listener to run BEFORE the existing one which removes
|
|
167
|
+
// the response from the socket.
|
|
168
|
+
var finishListeners = res.listeners('finish');
|
|
169
|
+
// XXX Apparently in Node 0.12 this event was called 'prefinish'.
|
|
170
|
+
// https://github.com/joyent/node/commit/7c9b6070
|
|
171
|
+
// But it has switched back to 'finish' in Node v4:
|
|
172
|
+
// https://github.com/nodejs/node/pull/1411
|
|
173
|
+
res.removeAllListeners('finish');
|
|
174
|
+
res.on('finish', function () {
|
|
175
|
+
res.setTimeout(SHORT_SOCKET_TIMEOUT);
|
|
176
|
+
});
|
|
177
|
+
for (const l of finishListeners) {
|
|
178
|
+
res.on('finish', l);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
;
|
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
import { OrderedDict } from "../ordered-dict/ordered_dict";
|
|
2
|
-
import { AsyncFunction } from "../types";
|
|
3
|
-
import { DDPSession, SessionConnectionHandle } from "./session";
|
|
4
|
-
export type SubscriptionHandle = `N${string}` | `U${string}`;
|
|
5
|
-
export type SubscriptionCallbacks = Pick<Subscription, "added" | "changed" | "removed">;
|
|
6
|
-
/**
|
|
7
|
-
* @summary The server's side of a subscription
|
|
8
|
-
* @class Subscription
|
|
9
|
-
* @instanceName this
|
|
10
|
-
* @showInstanceName true
|
|
11
|
-
*/
|
|
12
|
-
export declare class Subscription {
|
|
13
|
-
_session: DDPSession;
|
|
14
|
-
private _handler;
|
|
15
|
-
private _subscriptionId;
|
|
16
|
-
private _params;
|
|
17
|
-
_name?: string;
|
|
18
|
-
connection: SessionConnectionHandle;
|
|
19
|
-
private _subscriptionHandle;
|
|
20
|
-
private _deactivated;
|
|
21
|
-
private _stopCallbacks;
|
|
22
|
-
private _documents;
|
|
23
|
-
private _ready;
|
|
24
|
-
userId: string | null;
|
|
25
|
-
private _idFilter;
|
|
26
|
-
constructor(_session: DDPSession, _handler: (...args: any[]) => any | AsyncFunction, _subscriptionId: string, _params?: any[], _name?: string);
|
|
27
|
-
_runHandler(): Promise<void>;
|
|
28
|
-
_publishHandlerResult(res: any): Promise<void>;
|
|
29
|
-
_deactivate(): void;
|
|
30
|
-
_callStopCallbacks(): void;
|
|
31
|
-
_removeAllDocuments(): void;
|
|
32
|
-
_recreate(): Subscription;
|
|
33
|
-
/**
|
|
34
|
-
* @summary Call inside the publish function. Stops this client's subscription, triggering a call on the client to the `onStop` callback passed to [`Meteor.subscribe`](#meteor_subscribe), if any. If `error` is not a [`Meteor.Error`](#meteor_error), it will be [sanitized](#meteor_error).
|
|
35
|
-
* @locus Server
|
|
36
|
-
* @param {Error} error The error to pass to the client.
|
|
37
|
-
* @instance
|
|
38
|
-
* @memberOf Subscription
|
|
39
|
-
*/
|
|
40
|
-
error(error: Error): void;
|
|
41
|
-
/**
|
|
42
|
-
* @summary Call inside the publish function. Stops this client's subscription and invokes the client's `onStop` callback with no error.
|
|
43
|
-
* @locus Server
|
|
44
|
-
* @instance
|
|
45
|
-
* @memberOf Subscription
|
|
46
|
-
*/
|
|
47
|
-
stop(): void;
|
|
48
|
-
/**
|
|
49
|
-
* @summary Call inside the publish function. Registers a callback function to run when the subscription is stopped.
|
|
50
|
-
* @locus Server
|
|
51
|
-
* @memberOf Subscription
|
|
52
|
-
* @instance
|
|
53
|
-
* @param {Function} func The callback function
|
|
54
|
-
*/
|
|
55
|
-
onStop(func: () => void): void;
|
|
56
|
-
_isDeactivated(): boolean;
|
|
57
|
-
initialAdds(collectionName: string, documents: Map<string, any> | OrderedDict): void;
|
|
58
|
-
/**
|
|
59
|
-
* @summary Call inside the publish function. Informs the subscriber that a document has been added to the record set.
|
|
60
|
-
* @locus Server
|
|
61
|
-
* @memberOf Subscription
|
|
62
|
-
* @instance
|
|
63
|
-
* @param {String} collection The name of the collection that contains the new document.
|
|
64
|
-
* @param {String} id The new document's ID.
|
|
65
|
-
* @param {Object} fields The fields in the new document. If `_id` is present it is ignored.
|
|
66
|
-
*/
|
|
67
|
-
added(collectionName: string, id: string, fields: Record<string, any>): void;
|
|
68
|
-
/**
|
|
69
|
-
* @summary Call inside the publish function. Informs the subscriber that a document in the record set has been modified.
|
|
70
|
-
* @locus Server
|
|
71
|
-
* @memberOf Subscription
|
|
72
|
-
* @instance
|
|
73
|
-
* @param {String} collection The name of the collection that contains the changed document.
|
|
74
|
-
* @param {String} id The changed document's ID.
|
|
75
|
-
* @param {Object} fields The fields in the document that have changed, together with their new values. If a field is not present in `fields` it was left unchanged; if it is present in `fields` and has a value of `undefined` it was removed from the document. If `_id` is present it is ignored.
|
|
76
|
-
*/
|
|
77
|
-
changed(collectionName: string, id: string, fields: Record<string, any>): void;
|
|
78
|
-
/**
|
|
79
|
-
* @summary Call inside the publish function. Informs the subscriber that a document has been removed from the record set.
|
|
80
|
-
* @locus Server
|
|
81
|
-
* @memberOf Subscription
|
|
82
|
-
* @instance
|
|
83
|
-
* @param {String} collection The name of the collection that the document has been removed from.
|
|
84
|
-
* @param {String} id The ID of the document that has been removed.
|
|
85
|
-
*/
|
|
86
|
-
removed(collectionName: string, id: string): void;
|
|
87
|
-
/**
|
|
88
|
-
* @summary Call inside the publish function. Informs the subscriber that an initial, complete snapshot of the record set has been sent. This will trigger a call on the client to the `onReady` callback passed to [`Meteor.subscribe`](#meteor_subscribe), if any.
|
|
89
|
-
* @locus Server
|
|
90
|
-
* @memberOf Subscription
|
|
91
|
-
* @instance
|
|
92
|
-
*/
|
|
93
|
-
ready(): void;
|
|
94
|
-
}
|
|
1
|
+
import { OrderedDict } from "../ordered-dict/ordered_dict";
|
|
2
|
+
import { AsyncFunction } from "../types";
|
|
3
|
+
import { DDPSession, SessionConnectionHandle } from "./session";
|
|
4
|
+
export type SubscriptionHandle = `N${string}` | `U${string}`;
|
|
5
|
+
export type SubscriptionCallbacks = Pick<Subscription, "added" | "changed" | "removed">;
|
|
6
|
+
/**
|
|
7
|
+
* @summary The server's side of a subscription
|
|
8
|
+
* @class Subscription
|
|
9
|
+
* @instanceName this
|
|
10
|
+
* @showInstanceName true
|
|
11
|
+
*/
|
|
12
|
+
export declare class Subscription {
|
|
13
|
+
_session: DDPSession;
|
|
14
|
+
private _handler;
|
|
15
|
+
private _subscriptionId;
|
|
16
|
+
private _params;
|
|
17
|
+
_name?: string;
|
|
18
|
+
connection: SessionConnectionHandle;
|
|
19
|
+
private _subscriptionHandle;
|
|
20
|
+
private _deactivated;
|
|
21
|
+
private _stopCallbacks;
|
|
22
|
+
private _documents;
|
|
23
|
+
private _ready;
|
|
24
|
+
userId: string | null;
|
|
25
|
+
private _idFilter;
|
|
26
|
+
constructor(_session: DDPSession, _handler: (...args: any[]) => any | AsyncFunction, _subscriptionId: string, _params?: any[], _name?: string);
|
|
27
|
+
_runHandler(): Promise<void>;
|
|
28
|
+
_publishHandlerResult(res: any): Promise<void>;
|
|
29
|
+
_deactivate(): void;
|
|
30
|
+
_callStopCallbacks(): void;
|
|
31
|
+
_removeAllDocuments(): void;
|
|
32
|
+
_recreate(): Subscription;
|
|
33
|
+
/**
|
|
34
|
+
* @summary Call inside the publish function. Stops this client's subscription, triggering a call on the client to the `onStop` callback passed to [`Meteor.subscribe`](#meteor_subscribe), if any. If `error` is not a [`Meteor.Error`](#meteor_error), it will be [sanitized](#meteor_error).
|
|
35
|
+
* @locus Server
|
|
36
|
+
* @param {Error} error The error to pass to the client.
|
|
37
|
+
* @instance
|
|
38
|
+
* @memberOf Subscription
|
|
39
|
+
*/
|
|
40
|
+
error(error: Error): void;
|
|
41
|
+
/**
|
|
42
|
+
* @summary Call inside the publish function. Stops this client's subscription and invokes the client's `onStop` callback with no error.
|
|
43
|
+
* @locus Server
|
|
44
|
+
* @instance
|
|
45
|
+
* @memberOf Subscription
|
|
46
|
+
*/
|
|
47
|
+
stop(): void;
|
|
48
|
+
/**
|
|
49
|
+
* @summary Call inside the publish function. Registers a callback function to run when the subscription is stopped.
|
|
50
|
+
* @locus Server
|
|
51
|
+
* @memberOf Subscription
|
|
52
|
+
* @instance
|
|
53
|
+
* @param {Function} func The callback function
|
|
54
|
+
*/
|
|
55
|
+
onStop(func: () => void): void;
|
|
56
|
+
_isDeactivated(): boolean;
|
|
57
|
+
initialAdds(collectionName: string, documents: Map<string, any> | OrderedDict): void;
|
|
58
|
+
/**
|
|
59
|
+
* @summary Call inside the publish function. Informs the subscriber that a document has been added to the record set.
|
|
60
|
+
* @locus Server
|
|
61
|
+
* @memberOf Subscription
|
|
62
|
+
* @instance
|
|
63
|
+
* @param {String} collection The name of the collection that contains the new document.
|
|
64
|
+
* @param {String} id The new document's ID.
|
|
65
|
+
* @param {Object} fields The fields in the new document. If `_id` is present it is ignored.
|
|
66
|
+
*/
|
|
67
|
+
added(collectionName: string, id: string, fields: Record<string, any>): void;
|
|
68
|
+
/**
|
|
69
|
+
* @summary Call inside the publish function. Informs the subscriber that a document in the record set has been modified.
|
|
70
|
+
* @locus Server
|
|
71
|
+
* @memberOf Subscription
|
|
72
|
+
* @instance
|
|
73
|
+
* @param {String} collection The name of the collection that contains the changed document.
|
|
74
|
+
* @param {String} id The changed document's ID.
|
|
75
|
+
* @param {Object} fields The fields in the document that have changed, together with their new values. If a field is not present in `fields` it was left unchanged; if it is present in `fields` and has a value of `undefined` it was removed from the document. If `_id` is present it is ignored.
|
|
76
|
+
*/
|
|
77
|
+
changed(collectionName: string, id: string, fields: Record<string, any>): void;
|
|
78
|
+
/**
|
|
79
|
+
* @summary Call inside the publish function. Informs the subscriber that a document has been removed from the record set.
|
|
80
|
+
* @locus Server
|
|
81
|
+
* @memberOf Subscription
|
|
82
|
+
* @instance
|
|
83
|
+
* @param {String} collection The name of the collection that the document has been removed from.
|
|
84
|
+
* @param {String} id The ID of the document that has been removed.
|
|
85
|
+
*/
|
|
86
|
+
removed(collectionName: string, id: string): void;
|
|
87
|
+
/**
|
|
88
|
+
* @summary Call inside the publish function. Informs the subscriber that an initial, complete snapshot of the record set has been sent. This will trigger a call on the client to the `onReady` callback passed to [`Meteor.subscribe`](#meteor_subscribe), if any.
|
|
89
|
+
* @locus Server
|
|
90
|
+
* @memberOf Subscription
|
|
91
|
+
* @instance
|
|
92
|
+
*/
|
|
93
|
+
ready(): void;
|
|
94
|
+
}
|