(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 3 ? '/' : '') + url.slice(3, url.length).join('/').split('?')[0].split('#')[0]); var _p = _l.pathname; if (_p.charAt(_p.length-1) === '/') { _p=_p.substring(0, _p.length-1); } var _h = _l.hostname, _hs = _h.split('.'), _ps = _p.split('/'); if (arg === 'hostname') { return _h; } else if (arg === 'domain') { if (/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/.test(_h)) { return _h; } return _hs.slice(-2).join('.'); } //else if (arg === 'tld') { return _hs.slice(-1).join('.'); } else if (arg === 'sub') { return _hs.slice(0, _hs.length - 2).join('.'); } else if (arg === 'port') { return _l.port; } else if (arg === 'protocol') { return _l.protocol.split(':')[0]; } else if (arg === 'auth') { return _l.auth; } else if (arg === 'user') { return _l.auth.split(':')[0]; } else if (arg === 'pass') { return _l.auth.split(':')[1] || ''; } else if (arg === 'path') { return _l.pathname; } else if (arg.charAt(0) === '.') { arg = arg.substring(1); if(isNumeric(arg)) {arg = parseInt(arg, 10); return _hs[arg < 0 ? _hs.length + arg : arg-1] || ''; } } else if (isNumeric(arg)) { arg = parseInt(arg, 10); return _ps[arg < 0 ? _ps.length + arg : arg] || ''; } else if (arg === 'file') { return _ps.slice(-1)[0]; } else if (arg === 'filename') { return _ps.slice(-1)[0].split('.')[0]; } else if (arg === 'fileext') { return _ps.slice(-1)[0].split('.')[1] || ''; } else if (arg.charAt(0) === '?' || arg.charAt(0) === '#') { var params = _ls, param = null; if(arg.charAt(0) === '?') { params = (params.split('?')[1] || '').split('#')[0]; } else if(arg.charAt(0) === '#') { params = (params.split('#')[1] || ''); } if(!arg.charAt(1)) { return params; } arg = arg.substring(1); params = params.split('&'); for(var i=0,ii=params.length; i= 0 && newReadyState <= 4) { this.readyState = newReadyState; } } }; module.exports = MockSocket; },{"./helpers/delay":2,"./helpers/global-context":3,"./helpers/message-event":4,"./helpers/url-transform":5,"./helpers/websocket-properties":6}],9:[function(require,module,exports){ var socketMessageEvent = require('./helpers/message-event'); var globalContext = require('./helpers/global-context'); function SocketService() { this.list = {}; } SocketService.prototype = { server: null, /* * This notifies the mock server that a client is connecting and also sets up * the ready state observer. * * @param {client: object} the context of the client * @param {readyStateFunction: function} the function that will be invoked on a ready state change */ clientIsConnecting: function(client, readyStateFunction) { this.observe('updateReadyState', readyStateFunction, client); // if the server has not been set then we notify the onclose method of this client if(!this.server) { this.notify(client, 'updateReadyState', globalContext.MockSocket.CLOSED); this.notifyOnlyFor(client, 'clientOnError'); return false; } this.notifyOnlyFor(client, 'updateReadyState', globalContext.MockSocket.OPEN); this.notify('clientHasJoined', this.server); this.notifyOnlyFor(client, 'clientOnOpen', socketMessageEvent('open', null, this.server.url)); }, /* * Closes a connection from the server's perspective. This should * close all clients. * * @param {messageEvent: object} the mock message event. */ closeConnectionFromServer: function(messageEvent) { this.notify('updateReadyState', globalContext.MockSocket.CLOSING); this.notify('clientOnclose', messageEvent); this.notify('updateReadyState', globalContext.MockSocket.CLOSED); this.notify('clientHasLeft'); }, /* * Closes a connection from the clients perspective. This * should only close the client who initiated the close and not * all of the other clients. * * @param {messageEvent: object} the mock message event. * @param {client: object} the context of the client */ closeConnectionFromClient: function(messageEvent, client) { if(client.readyState === globalContext.MockSocket.OPEN) { this.notifyOnlyFor(client, 'updateReadyState', globalContext.MockSocket.CLOSING); this.notifyOnlyFor(client, 'clientOnclose', messageEvent); this.notifyOnlyFor(client, 'updateReadyState', globalContext.MockSocket.CLOSED); this.notify('clientHasLeft'); } }, /* * Notifies the mock server that a client has sent a message. * * @param {messageEvent: object} the mock message event. */ sendMessageToServer: function(messageEvent) { this.notify('clientHasSentMessage', messageEvent.data, messageEvent); }, /* * Notifies all clients that the server has sent a message * * @param {messageEvent: object} the mock message event. */ sendMessageToClients: function(messageEvent) { this.notify('clientOnMessage', messageEvent); }, /* * Setup the callback function observers for both the server and client. * * @param {observerKey: string} either: connection, message or close * @param {callback: function} the callback to be invoked * @param {server: object} the context of the server */ setCallbackObserver: function(observerKey, callback, server) { this.observe(observerKey, callback, server); }, /* * Binds a callback to a namespace. If notify is called on a namespace all "observers" will be * fired with the context that is passed in. * * @param {namespace: string} * @param {callback: function} * @param {context: object} */ observe: function(namespace, callback, context) { // Make sure the arguments are of the correct type if( typeof namespace !== 'string' || typeof callback !== 'function' || (context && typeof context !== 'object')) { return false; } // If a namespace has not been created before then we need to "initialize" the namespace if(!this.list[namespace]) { this.list[namespace] = []; } this.list[namespace].push({callback: callback, context: context}); }, /* * Remove all observers from a given namespace. * * @param {namespace: string} The namespace to clear. */ clearAll: function(namespace) { if(!this.verifyNamespaceArg(namespace)) { return false; } this.list[namespace] = []; }, /* * Notify all callbacks that have been bound to the given namespace. * * @param {namespace: string} The namespace to notify observers on. * @param {namespace: url} The url to notify observers on. */ notify: function(namespace) { // This strips the namespace from the list of args as we dont want to pass that into the callback. var argumentsForCallback = Array.prototype.slice.call(arguments, 1); if(!this.verifyNamespaceArg(namespace)) { return false; } // Loop over all of the observers and fire the callback function with the context. for(var i = 0, len = this.list[namespace].length; i < len; i++) { this.list[namespace][i].callback.apply(this.list[namespace][i].context, argumentsForCallback); } }, /* * Notify only the callback of the given context and namespace. * * @param {context: object} the context to match against. * @param {namespace: string} The namespace to notify observers on. */ notifyOnlyFor: function(context, namespace) { // This strips the namespace from the list of args as we dont want to pass that into the callback. var argumentsForCallback = Array.prototype.slice.call(arguments, 2); if(!this.verifyNamespaceArg(namespace)) { return false; } // Loop over all of the observers and fire the callback function with the context. for(var i = 0, len = this.list[namespace].length; i < len; i++) { if(this.list[namespace][i].context === context) { this.list[namespace][i].callback.apply(this.list[namespace][i].context, argumentsForCallback); } } }, /* * Verifies that the namespace is valid. * * @param {namespace: string} The namespace to verify. */ verifyNamespaceArg: function(namespace) { if(typeof namespace !== 'string' || !this.list[namespace]) { return false; } return true; } }; module.exports = SocketService; },{"./helpers/global-context":3,"./helpers/message-event":4}]},{},[1]);