mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Merge pull request #9371 from meteor/extract-socket-stream-client
Extract ClientStream into its own package.
This commit is contained in:
25
packages/ddp-client/.npm/package/npm-shrinkwrap.json
generated
25
packages/ddp-client/.npm/package/npm-shrinkwrap.json
generated
@@ -1,35 +1,10 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
"faye-websocket": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz",
|
||||
"integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg="
|
||||
},
|
||||
"http-parser-js": {
|
||||
"version": "0.4.6",
|
||||
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.6.tgz",
|
||||
"integrity": "sha1-GVJz9YcExFLWcQdr4gEyndNB3FU="
|
||||
},
|
||||
"lolex": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lolex/-/lolex-1.4.0.tgz",
|
||||
"integrity": "sha1-LycSsbwYDendzF06epbvPAuxYq0="
|
||||
},
|
||||
"permessage-deflate": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/permessage-deflate/-/permessage-deflate-0.1.6.tgz",
|
||||
"integrity": "sha1-WB8c7fvUQPrEfQd3vohjM4a5kt4="
|
||||
},
|
||||
"websocket-driver": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz",
|
||||
"integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs="
|
||||
},
|
||||
"websocket-extensions": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.2.tgz",
|
||||
"integrity": "sha1-Dhh4HeYpoYMIzhSBZQ9n/6JpOl0="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
export { DDP } from '../common/namespace.js';
|
||||
|
||||
if (false) {
|
||||
// This is used inside livedata_connection, but this is what gets
|
||||
// it included in the client bundle
|
||||
import './stream_client_sockjs';
|
||||
}
|
||||
|
||||
import '../common/livedata_connection';
|
||||
|
||||
// Initialize the default server connection and put it on Meteor.connection
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
||||
// In the client and server entry points, we make sure the
|
||||
// bundler loads the correct thing. Here, we just need to
|
||||
// make sure that we require the right one.
|
||||
export default function getClientStreamClass() {
|
||||
// The static analyzer of the bundler specifically looks
|
||||
// for static calls to 'require', so it won't treat the
|
||||
// below calls as a request to include that module.
|
||||
//
|
||||
// That means stream_client_nodejs won't be included on
|
||||
// the client, as desired.
|
||||
const modulePath = Meteor.isClient
|
||||
? '../client/stream_client_sockjs'
|
||||
: '../server/stream_client_nodejs';
|
||||
|
||||
return require(modulePath).default;
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import { Random } from 'meteor/random';
|
||||
import { Hook } from 'meteor/callback-hook';
|
||||
import { MongoID } from 'meteor/mongo-id';
|
||||
import { DDP } from './namespace.js';
|
||||
import getClientStreamClass from './getClientStreamClass.js';
|
||||
import MethodInvoker from './MethodInvoker.js';
|
||||
import {
|
||||
hasOwn,
|
||||
@@ -83,8 +82,10 @@ export class Connection {
|
||||
if (typeof url === 'object') {
|
||||
self._stream = url;
|
||||
} else {
|
||||
self._stream = new (getClientStreamClass())(url, {
|
||||
const { ClientStream } = require("meteor/socket-stream-client");
|
||||
self._stream = new ClientStream(url, {
|
||||
retry: options.retry,
|
||||
ConnectionError: DDP.ConnectionError,
|
||||
headers: options.headers,
|
||||
_sockjsOptions: options._sockjsOptions,
|
||||
// Used to keep some tests quiet, or for other cases in which
|
||||
|
||||
@@ -5,9 +5,7 @@ Package.describe({
|
||||
});
|
||||
|
||||
Npm.depends({
|
||||
'faye-websocket': '0.11.1',
|
||||
lolex: '1.4.0',
|
||||
'permessage-deflate': '0.1.6'
|
||||
lolex: '1.4.0'
|
||||
});
|
||||
|
||||
Package.onUse((api) => {
|
||||
@@ -22,6 +20,7 @@ Package.onUse((api) => {
|
||||
'callback-hook',
|
||||
'ddp-common',
|
||||
'reload',
|
||||
'socket-stream-client',
|
||||
|
||||
// we depend on _diffObjects, _applyChanges,
|
||||
'diff-sequence',
|
||||
@@ -73,6 +72,4 @@ Package.onTest((api) => {
|
||||
api.addFiles('test/livedata_tests.js');
|
||||
api.addFiles('test/livedata_test_service.js');
|
||||
api.addFiles('test/random_stream_tests.js');
|
||||
api.addFiles('test/stream_tests.js', 'client');
|
||||
api.addFiles('test/stream_client_tests.js', 'server');
|
||||
});
|
||||
|
||||
@@ -1,7 +1 @@
|
||||
export { DDP } from '../common/namespace.js';
|
||||
|
||||
if (false) {
|
||||
// This is used inside livedata_connection, but this is what gets
|
||||
// it included in the server bundle
|
||||
import './stream_client_nodejs';
|
||||
}
|
||||
|
||||
1
packages/socket-stream-client/.npm/package/.gitignore
vendored
Normal file
1
packages/socket-stream-client/.npm/package/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
7
packages/socket-stream-client/.npm/package/README
Normal file
7
packages/socket-stream-client/.npm/package/README
Normal file
@@ -0,0 +1,7 @@
|
||||
This directory and the files immediately inside it are automatically generated
|
||||
when you change this package's NPM dependencies. Commit the files in this
|
||||
directory (npm-shrinkwrap.json, .gitignore, and this README) to source control
|
||||
so that others run the same versions of sub-dependencies.
|
||||
|
||||
You should NOT check in the node_modules directory that Meteor automatically
|
||||
creates; if you are using git, the .gitignore file tells git to ignore it.
|
||||
30
packages/socket-stream-client/.npm/package/npm-shrinkwrap.json
generated
Normal file
30
packages/socket-stream-client/.npm/package/npm-shrinkwrap.json
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
"faye-websocket": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz",
|
||||
"integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg="
|
||||
},
|
||||
"http-parser-js": {
|
||||
"version": "0.4.9",
|
||||
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.9.tgz",
|
||||
"integrity": "sha1-6hoE+2St/wJC6ZdPKX3Uw8rSceE="
|
||||
},
|
||||
"permessage-deflate": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/permessage-deflate/-/permessage-deflate-0.1.6.tgz",
|
||||
"integrity": "sha1-WB8c7fvUQPrEfQd3vohjM4a5kt4="
|
||||
},
|
||||
"websocket-driver": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz",
|
||||
"integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs="
|
||||
},
|
||||
"websocket-extensions": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",
|
||||
"integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
8
packages/socket-stream-client/README.md
Normal file
8
packages/socket-stream-client/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# socket-stream-client
|
||||
[Source code of released version](https://github.com/meteor/meteor/tree/master/packages/socket-stream-client) | [Source code of development version](https://github.com/meteor/meteor/tree/devel/packages/socket-stream-client)
|
||||
***
|
||||
|
||||
This package provides the `ClientStream` abstraction used by the
|
||||
[`ddp-client`](https://github.com/meteor/meteor/tree/devel/packages/ddp-client)
|
||||
package.
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { DDP } from '../common/namespace.js';
|
||||
import {
|
||||
toSockjsUrl,
|
||||
toWebsocketUrl,
|
||||
} from '../common/urlHelpers.js';
|
||||
import StreamClientCommon from '../common/stream_client_common.js';
|
||||
} from "./urls.js";
|
||||
|
||||
export default class ClientStream extends StreamClientCommon {
|
||||
import { StreamClientCommon } from "./common.js";
|
||||
|
||||
export class ClientStream extends StreamClientCommon {
|
||||
// @param url {String} URL to Meteor app
|
||||
// "http://subdomain.meteor.com/" or "/" or
|
||||
// "ddp+sockjs://foo-**.meteor.com/sockjs"
|
||||
constructor(url, options) {
|
||||
super();
|
||||
|
||||
this.options = {
|
||||
retry: true,
|
||||
...options
|
||||
};
|
||||
super(options);
|
||||
|
||||
this._initCommon(this.options);
|
||||
|
||||
@@ -114,8 +108,8 @@ export default class ClientStream extends StreamClientCommon {
|
||||
}
|
||||
|
||||
_heartbeat_timeout() {
|
||||
Meteor._debug('Connection timeout. No sockjs heartbeat received.');
|
||||
this._lostConnection(new DDP.ConnectionError('Heartbeat timed out'));
|
||||
console.log('Connection timeout. No sockjs heartbeat received.');
|
||||
this._lostConnection(new this.ConnectionError("Heartbeat timed out"));
|
||||
}
|
||||
|
||||
_heartbeat_received() {
|
||||
@@ -186,11 +180,11 @@ export default class ClientStream extends StreamClientCommon {
|
||||
this.socket.onclose = () => {
|
||||
this._lostConnection();
|
||||
};
|
||||
this.socket.onerror = () => {
|
||||
this.socket.onerror = (...args) => {
|
||||
// XXX is this ever called?
|
||||
Meteor._debug(
|
||||
console.log(
|
||||
'stream error',
|
||||
Array.from(arguments),
|
||||
args,
|
||||
new Date().toDateString()
|
||||
);
|
||||
};
|
||||
@@ -201,7 +195,9 @@ export default class ClientStream extends StreamClientCommon {
|
||||
|
||||
if (this.connectionTimer) clearTimeout(this.connectionTimer);
|
||||
this.connectionTimer = setTimeout(() => {
|
||||
this._lostConnection(new DDP.ConnectionError('DDP connection timed out'));
|
||||
this._lostConnection(
|
||||
new this.ConnectionError("DDP connection timed out")
|
||||
);
|
||||
}, this.CONNECT_TIMEOUT);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
import { toSockjsUrl } from '../common/urlHelpers.js';
|
||||
import getClientStreamClass from '../common/getClientStreamClass.js';
|
||||
|
||||
const ClientStream = getClientStreamClass();
|
||||
import { toSockjsUrl } from "./urls.js";
|
||||
import { ClientStream } from "meteor/socket-stream-client";
|
||||
|
||||
Tinytest.add('stream - status', function(test) {
|
||||
// Very basic test. Just see that it runs and returns something. Not a
|
||||
@@ -1,11 +1,18 @@
|
||||
import { Random } from 'meteor/random';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { Retry } from 'meteor/retry';
|
||||
|
||||
import { DDP } from './namespace.js';
|
||||
const forcedReconnectError = new Error("forced reconnect");
|
||||
|
||||
export class StreamClientCommon {
|
||||
constructor(options) {
|
||||
this.options = {
|
||||
retry: true,
|
||||
...(options || null),
|
||||
};
|
||||
|
||||
this.ConnectionError =
|
||||
options && options.ConnectionError || Error;
|
||||
}
|
||||
|
||||
export default class StreamClientCommon {
|
||||
// Register for callbacks.
|
||||
on(name, callback) {
|
||||
if (name !== 'message' && name !== 'reset' && name !== 'disconnect')
|
||||
@@ -43,11 +50,14 @@ export default class StreamClientCommon {
|
||||
retryCount: 0
|
||||
};
|
||||
|
||||
this.statusListeners =
|
||||
typeof Tracker !== 'undefined' && new Tracker.Dependency();
|
||||
if (Package.tracker) {
|
||||
this.statusListeners = new Package.tracker.Tracker.Dependency();
|
||||
}
|
||||
|
||||
this.statusChanged = () => {
|
||||
if (this.statusListeners) this.statusListeners.changed();
|
||||
if (this.statusListeners) {
|
||||
this.statusListeners.changed();
|
||||
}
|
||||
};
|
||||
|
||||
//// Retry logic
|
||||
@@ -69,9 +79,8 @@ export default class StreamClientCommon {
|
||||
|
||||
if (this.currentStatus.connected) {
|
||||
if (options._force || options.url) {
|
||||
// force reconnect.
|
||||
this._lostConnection(new DDP.ForcedReconnectError());
|
||||
} // else, noop.
|
||||
this._lostConnection(forcedReconnectError);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -131,10 +140,8 @@ export default class StreamClientCommon {
|
||||
|
||||
_retryLater(maybeError) {
|
||||
var timeout = 0;
|
||||
if (
|
||||
this.options.retry ||
|
||||
(maybeError && maybeError.errorType === 'DDP.ForcedReconnectError')
|
||||
) {
|
||||
if (this.options.retry ||
|
||||
maybeError === forcedReconnectError) {
|
||||
timeout = this._retry.retryLater(
|
||||
this.currentStatus.retryCount,
|
||||
this._retryNow.bind(this)
|
||||
@@ -164,7 +171,9 @@ export default class StreamClientCommon {
|
||||
|
||||
// Get current status. Reactive.
|
||||
status() {
|
||||
if (this.statusListeners) this.statusListeners.depend();
|
||||
if (this.statusListeners) {
|
||||
this.statusListeners.depend();
|
||||
}
|
||||
return this.currentStatus;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { DDP } from '../common/namespace.js';
|
||||
import { toWebsocketUrl } from '../common/urlHelpers.js';
|
||||
import StreamClientCommon from '../common/stream_client_common.js';
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import { toWebsocketUrl } from "./urls.js";
|
||||
import { StreamClientCommon } from "./common.js";
|
||||
|
||||
// @param endpoint {String} URL to Meteor app
|
||||
// "http://subdomain.meteor.com/" or "/" or
|
||||
@@ -14,14 +13,9 @@ import StreamClientCommon from '../common/stream_client_common.js';
|
||||
// We don't do any heartbeating. (The logic that did this in sockjs was removed,
|
||||
// because it used a built-in sockjs mechanism. We could do it with WebSocket
|
||||
// ping frames or with DDP-level messages.)
|
||||
export default class ClientStream extends StreamClientCommon {
|
||||
export class ClientStream extends StreamClientCommon {
|
||||
constructor(endpoint, options) {
|
||||
super();
|
||||
|
||||
this.options = {
|
||||
retry: true,
|
||||
...(options || null),
|
||||
};
|
||||
super(options);
|
||||
|
||||
this.client = null; // created in _launchConnection
|
||||
this.endpoint = endpoint;
|
||||
@@ -155,7 +149,7 @@ export default class ClientStream extends StreamClientCommon {
|
||||
|
||||
this._clearConnectionTimer();
|
||||
this.connectionTimer = Meteor.setTimeout(() => {
|
||||
this._lostConnection(new DDP.ConnectionError('DDP connection timed out'));
|
||||
this._lostConnection(new this.ConnectionError('DDP connection timed out'));
|
||||
}, this.CONNECT_TIMEOUT);
|
||||
|
||||
this.client.on(
|
||||
@@ -182,7 +176,7 @@ export default class ClientStream extends StreamClientCommon {
|
||||
|
||||
// Faye's 'error' object is not a JS error (and among other things,
|
||||
// doesn't stringify well). Convert it to one.
|
||||
this._lostConnection(new DDP.ConnectionError(error.message));
|
||||
this._lostConnection(new this.ConnectionError(error.message));
|
||||
});
|
||||
|
||||
clientOnIfCurrent('close', 'stream close callback', () => {
|
||||
30
packages/socket-stream-client/package.js
Normal file
30
packages/socket-stream-client/package.js
Normal file
@@ -0,0 +1,30 @@
|
||||
Package.describe({
|
||||
name: "socket-stream-client",
|
||||
version: "0.1.0",
|
||||
summary: "Provides the ClientStream abstraction used by ddp-client",
|
||||
documentation: "README.md"
|
||||
});
|
||||
|
||||
Npm.depends({
|
||||
"faye-websocket": "0.11.1",
|
||||
"permessage-deflate": "0.1.6"
|
||||
});
|
||||
|
||||
Package.onUse(function(api) {
|
||||
api.use("ecmascript");
|
||||
api.use("retry"); // TODO Try to remove this.
|
||||
api.mainModule("browser.js", "client", { lazy: true });
|
||||
api.mainModule("node.js", "server", { lazy: true });
|
||||
});
|
||||
|
||||
Package.onTest(function(api) {
|
||||
api.use("underscore");
|
||||
api.use("ecmascript");
|
||||
api.use("tinytest");
|
||||
api.use("test-helpers");
|
||||
api.use("tracker");
|
||||
api.use("http");
|
||||
api.use("socket-stream-client");
|
||||
api.mainModule("client-tests.js", "client");
|
||||
api.mainModule("server-tests.js", "server");
|
||||
});
|
||||
@@ -1,6 +1,5 @@
|
||||
import ClientStream from '../server/stream_client_nodejs.js';
|
||||
|
||||
var Fiber = Npm.require('fibers');
|
||||
import { ClientStream } from "meteor/socket-stream-client";
|
||||
import Fiber from "fibers";
|
||||
|
||||
testAsyncMulti('stream client - callbacks run in a fiber', [
|
||||
function(test, expect) {
|
||||
@@ -1,5 +1,3 @@
|
||||
import { Random } from 'meteor/random';
|
||||
|
||||
// @param url {String} URL to Meteor app, eg:
|
||||
// "/" or "madewith.meteor.com" or "https://foo.meteor.com"
|
||||
// or "ddp+sockjs://ddp--****-foo.meteor.com/sockjs"
|
||||
@@ -30,7 +28,7 @@ function translateUrl(url, newSchemeBase, subPath) {
|
||||
// In the host (ONLY!), change '*' characters into random digits. This
|
||||
// allows different stream connections to connect to different hostnames
|
||||
// and avoid browser per-hostname connection limits.
|
||||
host = host.replace(/\*/g, () => Math.floor(Random.fraction() * 10));
|
||||
host = host.replace(/\*/g, () => Math.floor(Math.random() * 10));
|
||||
|
||||
return newScheme + '://' + host + rest;
|
||||
} else if (httpUrlMatch) {
|
||||
@@ -65,6 +63,5 @@ export function toSockjsUrl(url) {
|
||||
}
|
||||
|
||||
export function toWebsocketUrl(url) {
|
||||
var ret = translateUrl(url, 'ws', 'websocket');
|
||||
return ret;
|
||||
return translateUrl(url, 'ws', 'websocket');
|
||||
}
|
||||
Reference in New Issue
Block a user