elastic websocket.
Constructor options:
- ws: websocket object to use. auto-greated if omitted and url is derivable.
- scheme: scheme of the URL to use. ignored if url or ws is provided. default ws if omitted
- domain: domain of the URL to use. ignored if url or ws is provided. window.location.host is used if omitted
- path: path of the URL to use. ignored if url or ws is provided. default `` if omitted.
- url: url for websocket connection.
- ignored if ws is provided.
- derived from scheme, domain and path above if both ws and url are omitted
- scope: scope of this socket. default ``
- pingInterval: optional. interval between ping. default 60s, minimal 20s.
API (ews):
- pipe(scope): return a scoped ews object piped from this ews object.
- dispose(): permanently detach this ews object - unsupervise from its source and remove all handlers it ever installed on any raw websocket.
- a disposed ews can neither receive events nor be re-attached on reconnect. use this to safely discard a scoped ( piped ) ews, so late events from a stale session can never leak to its consumer.
- ws(): return the real websocket object used.
- ensure(): ensure connection. return Promise, resolves when connected
- disconnect(): disconnect websocket from server.
- return Promise when disconnected.
- connect(opt): reconnect websocket if disconnected. return a Promise which is resolved when connected.
- options:
- retry: automatically retry if set to true. default true.
- delay: delay ( in millisecond) before first connection attmpt. default 0
- now: reset current reconnection attempts and start a new attempt immediately
- cancel(): cancel connection. return Promise, resolves when connection canceled.
- reject lderror 1026 if no connection to cancel.
- status(): get connection status. return a integer with following possible values:
- 0: not connected
- 1: connecting
- 2: connected
- ping(opt): periodically ping remote server (heartbeat) to prevent disconnecting.
- opt is an object with following field:
- now: default false. if false, ping message is sent after ping interval;
otherwise it will be sent immediately.
- `interval: optional. interval of ping. default 60s, minimal 20s.
- unping(): stop ping.
API (from original WebSocket):
- send
- close
- addEventListener
- dispatchEvent
- removeEventListener
- on: (TBD) used by websocket-json-stream
Except original WebSocket events, we provide additional events as follows:
- offline: fired when the connection goes offline. Carries an info object with a src field indicating how the disconnection was detected:
- ws-close: detected via WebSocket close event. info also includes code, reason, and wasClean from the close event.
- network-offline: detected via browser's window offline event.
- close somehow may not yet fired when offline is fired, so this can be used to hint user about a dying socket.
Sharedb is bundled in this repo, in following files:
- dist/sharedb.min.js: standalone sharedb bundle, expose sharedb object.
- dist/sdb-client.min.js: client side sharedb wrapper
- dist/sdb-server.min.js: server side sharedb wrapper
prepare a ews object, and create a sdb-client once:
ws = new ews({url: ...});
sdb = new ews.sdb-client({ws: ws});
sdb.connect().then( ... );
sdb-client keeps its sharedb Connection - and thus all docs, along with
their pending / inflight ops - alive across disconnection. on reconnect it
binds a fresh scoped socket via sharedb's bindToSocket, then sharedb
resubscribes ( catching up by doc version ) and resends unacknowledged ops
( deduplicated by src / seq on server ) by itself. there is no need to
recreate sdb-client per reconnect; just call ensure() ( or connect() )
when the underlying ews is back.
a socket declared dead is disposed immediately ( see ews dispose() ), so
late events from a stale session - a half-open socket revived, a buffered
close, an orphan reply - can never reach sharedb.
APIs:
- connect(): ensure the underlying ews is connected, then create or rebind the sharedb connection. return Promise.
- ensure(): alias of connect().
- get({id, collection, create, watch}): fetch and subscribe a doc. return Promise resolving to the doc.
- getSnapshot({id, version, collection}): fetch a doc snapshot.
- disconnect() / cancel() / status(): delegate to the underlying ews.
Additionally, following events are available in sdb-client:
- close: socket is closed. the sharedb connection and its docs survive this - they resync after reconnect.
- error: fired when receiving error events from sharedb Doc or Connection.
- NOTE please always handle error event to keep your doc up to date.
use http and ws module to create a WebSocket server ( use express as example ):
sdbServer = require("@plotdb/ews/sdb-server")
app = express();
server = http.createServer(express());
wss = new ws.Server({ server: server });
ret = sdb-server({io: {postgres configuration ...} , wss})
wss.on("connection", function(ws, req) {
/* you can still use the created ws object */
var myws = new ews({ws});
...
});
If metadata(opt) function is provided, it will be called when commit hook is triggered with an object including following parameters:
- m: the metadata object from sharedb op.
- type: either readSnapshots or submit.
- collection: target collection.
- id: target doc id. This will be null if there are multiple doc ids - in this case, check snapshots instead.
- req: the express request object.
- session: shorthand for req.session from express-session.
- user: shorthand for session.user from passport.
edit the m field directly to inject necessary metadata. For example, add user id:
metadata = ({m, user, session, collection, id, snaptshos}) -> m.user = (if user? => user.key else 0)
If access is function provided, it will be called in following hooks:
access(opt) is called with an object containing following paramters:
- type: either readSnapshots or submit.
- collection: target collection.
- id: target doc id. This will be null if there are multiple doc ids - in this case, check snapshots instead.
- snapshots: array of snapshots. Only provided when called by readSnapshots hook.
- req: the express request object.
- session: shorthand for req.session from express-session.
- user: shorthand for session.user from passport.
access(opt) should return a Promise which only resolve when access is granted. By default the returned promise reject a lderror id 1012 error when access is denied.
Here is an example to prevent new document creation:
access = ({snapshots}) ->
if snapshots and !(snapshots.0.id) =>
return lderror.reject 1012
return Promise.resolve!
Please note that ShareDB logs rejected errors (by recognizing its stack attribute) and wrap errors in {code, message} format. Consider rejecting a plain lderror object as above example, @plotdb/ews will wrap/parse your lderror objects for you so you can receive a correct lderror object in frontend.
MIT