1 /**
  2  * Olives http://flams.github.com/olives
  3  * The MIT License (MIT)
  4  * Copyright (c) 2012-2014 Olivier Scherrer <pode.fr@gmail.com> - Olivier Wietrich <olivier.wietrich@gmail.com>
  5  */
  6 "use strict";
  7 
  8 /**
  9  * @class
 10  * SocketIOTransport allows for client-server eventing.
 11  * It's based on socket.io.
 12  */
 13 
 14 /**
 15  * Defines the SocketIOTransport
 16  * @private
 17  * @param {Object} $io socket.io's object
 18  * @returns
 19  */
 20 module.exports = function SocketIOTransportConstructor($socket) {
 21 
 22 	/**
 23 	 * @private
 24 	 * The socket.io's socket
 25 	 */
 26 	var _socket = null;
 27 
 28 	/**
 29 	 * Set the socket created by SocketIO
 30 	 * @param {Object} socket the socket.io socket
 31 	 * @returns true if it seems to be a socket.io socket
 32 	 */
 33 	this.setSocket = function setSocket(socket) {
 34 		if (socket && typeof socket.emit == "function") {
 35 			_socket = socket;
 36 			return true;
 37 		} else {
 38 			return false;
 39 		}
 40 	};
 41 
 42 	/**
 43 	 * Get the socket, for debugging purpose
 44 	 * @private
 45 	 * @returns {Object} the socket
 46 	 */
 47 	this.getSocket = function getSocket() {
 48 		return _socket;
 49 	};
 50 
 51 	/**
 52 	 * Subscribe to a socket event
 53 	 * @param {String} event the name of the event
 54 	 * @param {Function} func the function to execute when the event fires
 55 	 */
 56 	this.on = function on(event, func) {
 57 		return _socket.on(event, func);
 58 	};
 59 
 60 	/**
 61 	 * Subscribe to a socket event but disconnect as soon as it fires.
 62 	 * @param {String} event the name of the event
 63 	 * @param {Function} func the function to execute when the event fires
 64 	 */
 65 	this.once = function once(event, func) {
 66 		return _socket.once(event, func);
 67 	};
 68 
 69 	/**
 70 	 * Publish an event on the socket
 71 	 * @param {String} event the event to publish
 72 	 * @param data
 73 	 * @param {Function} callback is the function to be called for ack
 74 	 */
 75 	this.emit = function emit(event, data, callback) {
 76 		return _socket.emit(event, data, callback);
 77 	};
 78 
 79 	/**
 80 	 * Stop listening to events on a channel
 81 	 * @param {String} event the event to publish
 82 	 * @param data
 83 	 * @param {Function} callback is the function to be called for ack
 84 	 */
 85 	this.removeListener = function removeListener(event, data, callback) {
 86 		return _socket.removeListener(event, data, callback);
 87 	};
 88 
 89 	/**
 90 	 * Make a request on the node server
 91 	 * @param {String} channel watch the server's documentation to see available channels
 92 	 * @param data the request data, it could be anything
 93 	 * @param {Function} func the callback that will get the response.
 94 	 * @param {Object} scope the scope in which to execute the callback
 95 	 */
 96 	this.request = function request(channel, data, func, scope) {
 97 		if (typeof channel == "string" &&
 98 				typeof data != "undefined") {
 99 
100 			var reqData = {
101 					eventId: Date.now() + Math.floor(Math.random()*1e6),
102 					data: data
103 				},
104 				boundCallback = function () {
105 					if (func) {
106 						func.apply(scope || null, arguments);
107 					}
108 				};
109 
110 			this.once(reqData.eventId, boundCallback);
111 
112 			this.emit(channel, reqData);
113 
114 			return true;
115 		} else {
116 			return false;
117 		}
118 	};
119 
120 	/**
121 	 * Listen to an url and get notified on new data
122 	 * @param {String} channel watch the server's documentation to see available channels
123 	 * @param data the request data, it could be anything
124 	 * @param {Function} func the callback that will get the data
125 	 * @param {Object} scope the scope in which to execute the callback
126 	 * @returns
127 	 */
128 	this.listen = function listen(channel, data, func, scope) {
129 		if (typeof channel == "string" &&
130 				typeof data != "undefined" &&
131 				typeof func == "function") {
132 
133 			var reqData = {
134 					eventId: Date.now() + Math.floor(Math.random()*1e6),
135 					data: data,
136 					keepAlive: true
137 				},
138 				boundCallback = function () {
139 					if (func) {
140 						func.apply(scope || null, arguments);
141 					}
142 				},
143 				that = this;
144 
145 			this.on(reqData.eventId, boundCallback);
146 
147 			this.emit(channel, reqData);
148 
149 			return function stop() {
150 				that.emit("disconnect-" + reqData.eventId);
151 				that.removeListener(reqData.eventId, boundCallback);
152 			};
153 		} else {
154 			return false;
155 		}
156 	};
157 
158 	/**
159 	 * Sets the socket.io
160 	 */
161 	this.setSocket($socket);
162 };