All files / rebaser/src/dm ve.dm.TransportServer.js

100% Statements 26/26
50% Branches 2/4
100% Functions 7/7
100% Lines 25/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70                            1x 1x     1x                     1x 1x 1x 1x 1x                         4x 4x 4x 4x       1x 1x 1x 1x 4x 4x   1x 1x 1x 1x 1x 1x 1x      
/*!
 * VisualEditor DataModel transport server class.
 *
 * @copyright See AUTHORS.txt
 */
 
'use strict';
 
/**
 * Transport server for Socket IO transport
 *
 * @constructor
 * @param {ve.dm.ProtocolServer} protocolServer The protocol server
 */
ve.dm.TransportServer = function VeDmTransportServer( protocolServer ) {
	this.protocolServer = protocolServer;
};
 
OO.initClass( ve.dm.TransportServer );
 
/**
 * Generic connection handler
 *
 * This just creates a namespace handler for the docName, if one does not already exist
 *
 * @param {Function} getRoom One-argument function taking docName, returning the corresponding room
 * @param {Object} socket The io socket
 * @return {Promise}
 */
ve.dm.TransportServer.prototype.onConnection = function ( getRoom, socket ) {
	const server = this.protocolServer,
		docName = socket.handshake.query.docName,
		authorId = +socket.handshake.query.authorId || null,
		token = socket.handshake.query.token || null;
 
	/**
	 * Ensure the doc is loaded when calling f
	 *
	 * @param {Function} f A method of server
	 * @param {Object} context Connection context object passed to f as first argument
	 * @return {Function} Function returning a promise resolving with f's return value
	 */
	function ensureLoadedWrap( f, context ) {
		// In theory, some protection is needed to ensure the document cannot unload
		// between the ensureLoaded promise resolving and f running. In practice,
		// this should not happen if the unloading is not too aggressive.
		return function () {
			const args = Array.prototype.slice.call( arguments );
			args.splice( 0, 0, context );
			return server.ensureLoaded( docName ).then( () => f.apply( server, args ) );
		};
	}
 
	socket.join( docName );
	return server.ensureLoaded( docName ).then( () => {
		const context = server.authenticate( docName, authorId, token );
		context.broadcast = function () {
			const room = getRoom( docName );
			room.emit.apply( room, arguments );
		};
		context.sendAuthor = socket.emit.bind( socket );
		context.connectionId = socket.client.conn.remoteAddress + ' ' + socket.handshake.url;
		socket.on( 'submitChange', ensureLoadedWrap( server.onSubmitChange, context ) );
		socket.on( 'changeAuthor', ensureLoadedWrap( server.onChangeAuthor, context ) );
		socket.on( 'disconnect', ensureLoadedWrap( server.onDisconnect, context ) );
		socket.on( 'logEvent', ensureLoadedWrap( server.onLogEvent, context ) );
		server.welcomeClient( context );
	} );
};