put stuff in same folder
npm install socket.io-client@0.9 bluebird
then run siotest.js
Should first error and then connect
// socket.io-1.2.1 | |
// (from http://socket.io/download/) | |
io = require('socket.io-client').connect; | |
/** | |
* sails.io.js | |
* ------------------------------------------------------------------------ | |
* JavaScript Client (SDK) for communicating with Sails. | |
* | |
* Note that this script is completely optional, but it is handy if you're | |
* using WebSockets from the browser to talk to your Sails server. | |
* | |
* For tips and documentation, visit: | |
* http://sailsjs.org/#!documentation/reference/BrowserSDK/BrowserSDK.html | |
* ------------------------------------------------------------------------ | |
* | |
* This file allows you to send and receive socket.io messages to & from Sails | |
* by simulating a REST client interface on top of socket.io. It models its API | |
* after the $.ajax pattern from jQuery you might already be familiar with. | |
* | |
* So if you're switching from using AJAX to sockets, instead of: | |
* `$.post( url, [data], [cb] )` | |
* | |
* You would use: | |
* `socket.post( url, [data], [cb] )` | |
*/ | |
(function() { | |
// Save the URL that this script was fetched from for use below. | |
// (skip this if this SDK is being used outside of the DOM, i.e. in a Node process) | |
var urlThisScriptWasFetchedFrom = (function() { | |
if ( | |
typeof window !== 'object' || | |
typeof window.document !== 'object' || | |
typeof window.document.getElementsByTagName !== 'function' | |
) { | |
return ''; | |
} | |
// Return the URL of the last script loaded (i.e. this one) | |
// (this must run before nextTick; see http://stackoverflow.com/a/2976714/486547) | |
var allScriptsCurrentlyInDOM = window.document.getElementsByTagName('script'); | |
var thisScript = allScriptsCurrentlyInDOM[allScriptsCurrentlyInDOM.length - 1]; | |
return thisScript.src; | |
})(); | |
// Constants | |
var CONNECTION_METADATA_PARAMS = { | |
version: '__sails_io_sdk_version', | |
platform: '__sails_io_sdk_platform', | |
language: '__sails_io_sdk_language' | |
}; | |
// Current version of this SDK (sailsDK?!?!) and other metadata | |
// that will be sent along w/ the initial connection request. | |
var SDK_INFO = { | |
version: '0.11.0', // TODO: pull this automatically from package.json during build. | |
platform: typeof module === 'undefined' ? 'browser' : 'node', | |
language: 'javascript' | |
}; | |
SDK_INFO.versionString = | |
CONNECTION_METADATA_PARAMS.version + '=' + SDK_INFO.version + '&' + | |
CONNECTION_METADATA_PARAMS.platform + '=' + SDK_INFO.platform + '&' + | |
CONNECTION_METADATA_PARAMS.language + '=' + SDK_INFO.language; | |
// In case you're wrapping the socket.io client to prevent pollution of the | |
// global namespace, you can pass in your own `io` to replace the global one. | |
// But we still grab access to the global one if it's available here: | |
var _io = (typeof io !== 'undefined') ? io : null; | |
/** | |
* Augment the `io` object passed in with methods for talking and listening | |
* to one or more Sails backend(s). Automatically connects a socket and | |
* exposes it on `io.socket`. If a socket tries to make requests before it | |
* is connected, the sails.io.js client will queue it up. | |
* | |
* @param {SocketIO} io | |
*/ | |
function SailsIOClient(io) { | |
// Prefer the passed-in `io` instance, but also use the global one if we've got it. | |
if (!io) { | |
io = _io; | |
} | |
// If the socket.io client is not available, none of this will work. | |
if (!io) throw new Error('`sails.io.js` requires a socket.io client, but `io` was not passed in.'); | |
////////////////////////////////////////////////////////////// | |
///// /////////////////////////// | |
///// PRIVATE METHODS/CONSTRUCTORS /////////////////////////// | |
///// /////////////////////////// | |
////////////////////////////////////////////////////////////// | |
/** | |
* A little logger for this library to use internally. | |
* Basically just a wrapper around `console.log` with | |
* support for feature-detection. | |
* | |
* @api private | |
* @factory | |
*/ | |
function LoggerFactory(options) { | |
options = options || { | |
prefix: true | |
}; | |
// If `console.log` is not accessible, `log` is a noop. | |
if ( | |
typeof console !== 'object' || | |
typeof console.log !== 'function' || | |
typeof console.log.bind !== 'function' | |
) { | |
return function noop() {}; | |
} | |
return function log() { | |
var args = Array.prototype.slice.call(arguments); | |
// All logs are disabled when `io.sails.environment = 'production'`. | |
if (io.sails.environment === 'production') return; | |
// Add prefix to log messages (unless disabled) | |
var PREFIX = ''; | |
if (options.prefix) { | |
args.unshift(PREFIX); | |
} | |
// Call wrapped logger | |
console.log | |
.bind(console) | |
.apply(this, args); | |
}; | |
} | |
// Create a private logger instance | |
var consolog = LoggerFactory(); | |
consolog.noPrefix = LoggerFactory({ | |
prefix: false | |
}); | |
/** | |
* What is the `requestQueue`? | |
* | |
* The request queue is used to simplify app-level connection logic-- | |
* i.e. so you don't have to wait for the socket to be connected | |
* to start trying to synchronize data. | |
* | |
* @api private | |
* @param {SailsSocket} socket | |
*/ | |
function runRequestQueue (socket) { | |
var queue = socket.requestQueue; | |
if (!queue) return; | |
for (var i in queue) { | |
// Double-check that `queue[i]` will not | |
// inadvertently discover extra properties attached to the Object | |
// and/or Array prototype by other libraries/frameworks/tools. | |
// (e.g. Ember does this. See https://github.com/balderdashy/sails.io.js/pull/5) | |
var isSafeToDereference = ({}).hasOwnProperty.call(queue, i); | |
if (isSafeToDereference) { | |
// Emit the request. | |
_emitFrom(socket, queue[i]); | |
} | |
} | |
// Now empty the queue to remove it as a source of additional complexity. | |
queue = null; | |
} | |
/** | |
* Send a JSONP request. | |
* | |
* @param {Object} opts [optional] | |
* @param {Function} cb | |
* @return {XMLHttpRequest} | |
*/ | |
function jsonp(opts, cb) { | |
opts = opts || {}; | |
if (typeof window === 'undefined') { | |
// TODO: refactor node usage to live in here | |
return cb(); | |
} | |
var scriptEl = document.createElement('script'); | |
window._sailsIoJSConnect = function(response) { | |
scriptEl.parentNode.removeChild(scriptEl); | |
cb(response); | |
}; | |
scriptEl.src = opts.url; | |
document.getElementsByTagName('head')[0].appendChild(scriptEl); | |
} | |
/** | |
* The JWR (JSON WebSocket Response) received from a Sails server. | |
* | |
* @api public | |
* @param {Object} responseCtx | |
* => :body | |
* => :statusCode | |
* => :headers | |
* | |
* @constructor | |
*/ | |
function JWR(responseCtx) { | |
this.body = responseCtx.body || responseCtx; | |
this.headers = responseCtx.headers || {}; | |
this.statusCode = responseCtx.statusCode || 200; | |
if (this.statusCode < 200 || this.statusCode >= 400) { | |
this.error = this.body || this.statusCode; | |
} | |
} | |
JWR.prototype.toString = function() { | |
return '[ResponseFromSails]' + ' -- ' + | |
'Status: ' + this.statusCode + ' -- ' + | |
'Headers: ' + this.headers + ' -- ' + | |
'Body: ' + this.body; | |
}; | |
JWR.prototype.toPOJO = function() { | |
return { | |
body: this.body, | |
headers: this.headers, | |
statusCode: this.statusCode | |
}; | |
}; | |
JWR.prototype.pipe = function() { | |
// TODO: look at substack's stuff | |
return new Error('Client-side streaming support not implemented yet.'); | |
}; | |
/** | |
* @api private | |
* @param {SailsSocket} socket [description] | |
* @param {Object} requestCtx [description] | |
*/ | |
function _emitFrom(socket, requestCtx) { | |
if (!socket._raw) { | |
throw new Error('Failed to emit from socket- raw SIO socket is missing.'); | |
} | |
// Since callback is embedded in requestCtx, | |
// retrieve it and delete the key before continuing. | |
var cb = requestCtx.cb; | |
delete requestCtx.cb; | |
// Name of the appropriate socket.io listener on the server | |
// ( === the request method or "verb", e.g. 'get', 'post', 'put', etc. ) | |
var sailsEndpoint = requestCtx.method; | |
socket._raw.emit(sailsEndpoint, requestCtx, function serverResponded(responseCtx) { | |
// Send back (emulatedHTTPBody, jsonWebSocketResponse) | |
if (cb && responseCtx) { | |
cb(responseCtx.body, new JWR(responseCtx)); | |
} | |
}); | |
} | |
////////////////////////////////////////////////////////////// | |
///// </PRIVATE METHODS/CONSTRUCTORS> //////////////////////// | |
////////////////////////////////////////////////////////////// | |
// Version note: | |
// | |
// `io.SocketNamespace.prototype` doesn't exist in sio 1.0. | |
// | |
// Rather than adding methods to the prototype for the Socket instance that is returned | |
// when the browser connects with `io.connect()`, we create our own constructor, `SailsSocket`. | |
// This makes our solution more future-proof and helps us work better w/ the Socket.io team | |
// when changes are rolled out in the future. To get a `SailsSocket`, you can run: | |
// ``` | |
// io.sails.connect(); | |
// ``` | |
/** | |
* SailsSocket | |
* | |
* A wrapper for an underlying Socket instance that communicates directly | |
* to the Socket.io server running inside of Sails. | |
* | |
* If no `socket` option is provied, SailsSocket will function as a mock. It will queue socket | |
* requests and event handler bindings, replaying them when the raw underlying socket actually | |
* connects. This is handy when we don't necessarily have the valid configuration to know | |
* WHICH SERVER to talk to yet, etc. It is also used by `io.socket` for your convenience. | |
* | |
* @constructor | |
*/ | |
function SailsSocket (opts){ | |
var self = this; | |
opts = opts||{}; | |
// Absorb opts | |
self.useCORSRouteToGetCookie = opts.useCORSRouteToGetCookie; | |
self.url = opts.url; | |
self.multiplex = opts.multiplex; | |
self.transports = opts.transports; | |
// Set up "eventQueue" to hold event handlers which have not been set on the actual raw socket yet. | |
self.eventQueue = {}; | |
// Listen for special `parseError` event sent from sockets hook on the backend | |
// if an error occurs but a valid callback was not received from the client | |
// (i.e. so the server had no other way to send back the error information) | |
self.on('sails:parseError', function (err){ | |
consolog('Sails encountered an error parsing a socket message sent from this client, and did not have access to a callback function to respond with.'); | |
consolog('Error details:',err); | |
}); | |
// TODO: | |
// Listen for a special private message on any connected that allows the server | |
// to set the environment (giving us 100% certainty that we guessed right) | |
// However, note that the `console.log`s called before and after connection | |
// are still forced to rely on our existing heuristics (to disable, tack #production | |
// onto the URL used to fetch this file.) | |
} | |
/** | |
* Start connecting this socket. | |
* | |
* @api private | |
*/ | |
SailsSocket.prototype._connect = function (){ | |
var self = this; | |
// Apply `io.sails` config as defaults | |
// (now that at least one tick has elapsed) | |
self.useCORSRouteToGetCookie = self.useCORSRouteToGetCookie||io.sails.useCORSRouteToGetCookie; | |
self.url = self.url||io.sails.url; | |
self.transports = self.transports || io.sails.transports; | |
// Ensure URL has no trailing slash | |
self.url = self.url ? self.url.replace(/(\/)$/, '') : undefined; | |
// Mix the current SDK version into the query string in | |
// the connection request to the server: | |
if (typeof self.query !== 'string') self.query = SDK_INFO.versionString; | |
else self.query += '&' + SDK_INFO.versionString; | |
// Determine whether this is a cross-origin socket by examining the | |
// hostname and port on the `window.location` object. | |
var isXOrigin = (function (){ | |
// If `window` doesn't exist (i.e. being used from node.js), then it's | |
// always "cross-domain". | |
if (typeof window === 'undefined' || typeof window.location === 'undefined') { | |
return false; | |
} | |
// If `self.url` (aka "target") is falsy, then we don't need to worry about it. | |
if (typeof self.url !== 'string') { return false; } | |
// Get information about the "target" (`self.url`) | |
var targetProtocol = (function (){ | |
try { | |
targetProtocol = self.url.match(/^([a-z]+:\/\/)/i)[1].toLowerCase(); | |
} | |
catch (e) {} | |
targetProtocol = targetProtocol || 'http://'; | |
return targetProtocol; | |
})(); | |
var isTargetSSL = !!self.url.match('^https'); | |
var targetPort = (function (){ | |
try { | |
return self.url.match(/^[a-z]+:\/\/[^:]*:([0-9]*)/i)[1]; | |
} | |
catch (e){} | |
return isTargetSSL ? '443' : '80'; | |
})(); | |
var targetAfterProtocol = self.url.replace(/^([a-z]+:\/\/)/i, ''); | |
// If target protocol is different than the actual protocol, | |
// then we'll consider this cross-origin. | |
if (targetProtocol.replace(/[:\/]/g, '') !== window.location.protocol.replace(/[:\/]/g,'')) { | |
return true; | |
} | |
// If target hostname is different than actual hostname, we'll consider this cross-origin. | |
var hasSameHostname = targetAfterProtocol.search(window.location.hostname) !== 0; | |
if (!hasSameHostname) { | |
return true; | |
} | |
// If no actual port is explicitly set on the `window.location` object, | |
// we'll assume either 80 or 443. | |
var isLocationSSL = window.location.protocol.match(/https/i); | |
var locationPort = (window.location.port+'') || (isLocationSSL ? '443' : '80'); | |
// Finally, if ports don't match, we'll consider this cross-origin. | |
if (targetPort !== locationPort) { | |
return true; | |
} | |
// Otherwise, it's the same origin. | |
return false; | |
})(); | |
// Prepare to start connecting the socket | |
(function selfInvoking (cb){ | |
// If this is an attempt at a cross-origin or cross-port | |
// socket connection, send a JSONP request first to ensure | |
// that a valid cookie is available. This can be disabled | |
// by setting `io.sails.useCORSRouteToGetCookie` to false. | |
// | |
// Otherwise, skip the stuff below. | |
if (!(self.useCORSRouteToGetCookie && isXOrigin)) { | |
return cb(); | |
} | |
// Figure out the x-origin CORS route | |
// (Sails provides a default) | |
var xOriginCookieURL = self.url; | |
if (typeof self.useCORSRouteToGetCookie === 'string') { | |
xOriginCookieURL += self.useCORSRouteToGetCookie; | |
} | |
else { | |
xOriginCookieURL += '/__getcookie'; | |
} | |
// Make the AJAX request (CORS) | |
if (typeof window !== 'undefined') { | |
jsonp({ | |
url: xOriginCookieURL, | |
method: 'GET' | |
}, cb); | |
return; | |
} | |
// If there's no `window` object, we must be running in Node.js | |
// so just require the request module and send the HTTP request that | |
// way. | |
var mikealsReq = require('request'); | |
mikealsReq.get(xOriginCookieURL, function(err, httpResponse, body) { | |
if (err) { | |
consolog( | |
'Failed to connect socket (failed to get cookie)', | |
'Error:', err | |
); | |
return; | |
} | |
cb(); | |
}); | |
})(function goAheadAndActuallyConnect() { | |
// Now that we're ready to connect, create a raw underlying Socket | |
// using Socket.io and save it as `_raw` (this will start it connecting) | |
self._raw = io(self.url, self); | |
// Replay event bindings from the eager socket | |
self.replay(); | |
/** | |
* 'connect' event is triggered when the socket establishes a connection | |
* successfully. | |
*/ | |
self.on('connect', function socketConnected() { | |
consolog.noPrefix( | |
'\n' + | |
'\n' + | |
// ' |> ' + '\n' + | |
// ' \\___/ '+️ | |
// '\n'+ | |
' |> Now connected to Sails.' + '\n' + | |
'\\___/ For help, see: http://bit.ly/1DmTvgK' + '\n' + | |
' (using '+io.sails.sdk.platform+' SDK @v'+io.sails.sdk.version+')'+ '\n' + | |
'\n'+ | |
'\n'+ | |
// '\n'+ | |
'' | |
// ' ⚓︎ (development mode)' | |
// 'e.g. to send a GET request to Sails via WebSockets, run:'+ '\n' + | |
// '`io.socket.get("/foo", function serverRespondedWith (body, jwr) { console.log(body); })`'+ '\n' + | |
); | |
}); | |
self.on('disconnect', function() { | |
self.connectionLostTimestamp = (new Date()).getTime(); | |
consolog('===================================='); | |
consolog('Socket was disconnected from Sails.'); | |
consolog('Usually, this is due to one of the following reasons:' + '\n' + | |
' -> the server ' + (self.url ? self.url + ' ' : '') + 'was taken down' + '\n' + | |
' -> your browser lost internet connectivity'); | |
consolog('===================================='); | |
}); | |
self.on('reconnecting', function(numAttempts) { | |
consolog( | |
'\n'+ | |
' Socket is trying to reconnect to Sails...\n'+ | |
'_-|>_- (attempt #' + numAttempts + ')'+'\n'+ | |
'\n' | |
); | |
}); | |
self.on('reconnect', function(transport, numAttempts) { | |
var msSinceConnectionLost = ((new Date()).getTime() - self.connectionLostTimestamp); | |
var numSecsOffline = (msSinceConnectionLost / 1000); | |
consolog( | |
'\n'+ | |
' |> Socket reconnected successfully after'+'\n'+ | |
'\\___/ being offline for ~' + numSecsOffline + ' seconds.'+'\n'+ | |
'\n' | |
); | |
}); | |
// 'error' event is triggered if connection can not be established. | |
// (usually because of a failed authorization, which is in turn | |
// usually due to a missing or invalid cookie) | |
self.on('error', function failedToConnect(err) { | |
// TODO: | |
// handle failed connections due to failed authorization | |
// in a smarter way (probably can listen for a different event) | |
// A bug in Socket.io 0.9.x causes `connect_failed` | |
// and `reconnect_failed` not to fire. | |
// Check out the discussion in github issues for details: | |
// https://github.com/LearnBoost/socket.io/issues/652 | |
// io.socket.on('connect_failed', function () { | |
// consolog('io.socket emitted `connect_failed`'); | |
// }); | |
// io.socket.on('reconnect_failed', function () { | |
// consolog('io.socket emitted `reconnect_failed`'); | |
// }); | |
consolog( | |
'Failed to connect socket (probably due to failed authorization on server)', | |
'Error:', err | |
); | |
}); | |
}); | |
}; | |
/** | |
* Disconnect the underlying socket. | |
* | |
* @api public | |
*/ | |
SailsSocket.prototype.disconnect = function (){ | |
if (!this._raw) { | |
throw new Error('Cannot disconnect- socket is already disconnected'); | |
} | |
return this._raw.disconnect(); | |
}; | |
/** | |
* isConnected | |
* | |
* @api private | |
* @return {Boolean} whether the socket is connected and able to | |
* communicate w/ the server. | |
*/ | |
SailsSocket.prototype.isConnected = function () { | |
if (!this._raw) { | |
return false; | |
} | |
return !!this._raw.socket.connected; | |
}; | |
/** | |
* [replay description] | |
* @return {[type]} [description] | |
*/ | |
SailsSocket.prototype.replay = function (){ | |
var self = this; | |
// Pass events and a reference to the request queue | |
// off to the self._raw for consumption | |
for (var evName in self.eventQueue) { | |
for (var i in self.eventQueue[evName]) { | |
self._raw.on(evName, self.eventQueue[evName][i]); | |
} | |
} | |
// Bind a one-time function to run the request queue | |
// when the self._raw connects. | |
if ( !self.isConnected() ) { | |
var alreadyRanRequestQueue = false; | |
self._raw.on('connect', function whenRawSocketConnects() { | |
if (alreadyRanRequestQueue) return; | |
runRequestQueue(self); | |
alreadyRanRequestQueue = true; | |
}); | |
} | |
// Or run it immediately if self._raw is already connected | |
else { | |
runRequestQueue(self); | |
} | |
return self; | |
}; | |
/** | |
* Chainable method to bind an event to the socket. | |
* | |
* @param {String} evName [event name] | |
* @param {Function} fn [event handler function] | |
* @return {SailsSocket} | |
*/ | |
SailsSocket.prototype.on = function (evName, fn){ | |
// Bind the event to the raw underlying socket if possible. | |
if (this._raw) { | |
this._raw.on(evName, fn); | |
return this; | |
} | |
// Otherwise queue the event binding. | |
if (!this.eventQueue[evName]) { | |
this.eventQueue[evName] = [fn]; | |
} | |
else { | |
this.eventQueue[evName].push(fn); | |
} | |
return this; | |
}; | |
/** | |
* Chainable method to unbind an event from the socket. | |
* | |
* @param {String} evName [event name] | |
* @param {Function} fn [event handler function] | |
* @return {SailsSocket} | |
*/ | |
SailsSocket.prototype.off = function (evName, fn){ | |
// Bind the event to the raw underlying socket if possible. | |
if (this._raw) { | |
this._raw.off(evName, fn); | |
return this; | |
} | |
// Otherwise queue the event binding. | |
if (this.eventQueue[evName] && this.eventQueue[evName].indexOf(fn) > -1) { | |
this.eventQueue[evName].splice(this.eventQueue[evName].indexOf(fn), 1); | |
} | |
return this; | |
}; | |
/** | |
* Chainable method to unbind all events from the socket. | |
* | |
* @return {SailsSocket} | |
*/ | |
SailsSocket.prototype.removeAllListeners = function (){ | |
// Bind the event to the raw underlying socket if possible. | |
if (this._raw) { | |
this._raw.removeAllListeners(); | |
return this; | |
} | |
// Otherwise queue the event binding. | |
this.eventQueue = {}; | |
return this; | |
}; | |
/** | |
* Simulate a GET request to sails | |
* e.g. | |
* `socket.get('/user/3', Stats.populate)` | |
* | |
* @api public | |
* @param {String} url :: destination URL | |
* @param {Object} params :: parameters to send with the request [optional] | |
* @param {Function} cb :: callback function to call when finished [optional] | |
*/ | |
SailsSocket.prototype.get = function(url, data, cb) { | |
// `data` is optional | |
if (typeof data === 'function') { | |
cb = data; | |
data = {}; | |
} | |
return this.request({ | |
method: 'get', | |
params: data, | |
url: url | |
}, cb); | |
}; | |
/** | |
* Simulate a POST request to sails | |
* e.g. | |
* `socket.post('/event', newMeeting, $spinner.hide)` | |
* | |
* @api public | |
* @param {String} url :: destination URL | |
* @param {Object} params :: parameters to send with the request [optional] | |
* @param {Function} cb :: callback function to call when finished [optional] | |
*/ | |
SailsSocket.prototype.post = function(url, data, cb) { | |
// `data` is optional | |
if (typeof data === 'function') { | |
cb = data; | |
data = {}; | |
} | |
return this.request({ | |
method: 'post', | |
data: data, | |
url: url | |
}, cb); | |
}; | |
/** | |
* Simulate a PUT request to sails | |
* e.g. | |
* `socket.post('/event/3', changedFields, $spinner.hide)` | |
* | |
* @api public | |
* @param {String} url :: destination URL | |
* @param {Object} params :: parameters to send with the request [optional] | |
* @param {Function} cb :: callback function to call when finished [optional] | |
*/ | |
SailsSocket.prototype.put = function(url, data, cb) { | |
// `data` is optional | |
if (typeof data === 'function') { | |
cb = data; | |
data = {}; | |
} | |
return this.request({ | |
method: 'put', | |
params: data, | |
url: url | |
}, cb); | |
}; | |
/** | |
* Simulate a DELETE request to sails | |
* e.g. | |
* `socket.delete('/event', $spinner.hide)` | |
* | |
* @api public | |
* @param {String} url :: destination URL | |
* @param {Object} params :: parameters to send with the request [optional] | |
* @param {Function} cb :: callback function to call when finished [optional] | |
*/ | |
SailsSocket.prototype['delete'] = function(url, data, cb) { | |
// `data` is optional | |
if (typeof data === 'function') { | |
cb = data; | |
data = {}; | |
} | |
return this.request({ | |
method: 'delete', | |
params: data, | |
url: url | |
}, cb); | |
}; | |
/** | |
* Simulate an HTTP request to sails | |
* e.g. | |
* ``` | |
* socket.request({ | |
* url:'/user', | |
* params: {}, | |
* method: 'POST', | |
* headers: {} | |
* }, function (responseBody, JWR) { | |
* // ... | |
* }); | |
* ``` | |
* | |
* @api public | |
* @option {String} url :: destination URL | |
* @option {Object} params :: parameters to send with the request [optional] | |
* @option {Object} headers:: headers to send with the request [optional] | |
* @option {Function} cb :: callback function to call when finished [optional] | |
* @option {String} method :: HTTP request method [optional] | |
*/ | |
SailsSocket.prototype.request = function(options, cb) { | |
var usage = | |
'Usage:\n'+ | |
'socket.request( options, [fnToCallWhenComplete] )\n\n'+ | |
'options.url :: e.g. "/foo/bar"'+'\n'+ | |
'options.method :: e.g. "get", "post", "put", or "delete", etc.'+'\n'+ | |
'options.params :: e.g. { emailAddress: "mike@sailsjs.org" }'+'\n'+ | |
'options.headers :: e.g. { "x-my-custom-header": "some string" }'; | |
// Old usage: | |
// var usage = 'Usage:\n socket.'+(options.method||'request')+'('+ | |
// ' destinationURL, [dataToSend], [fnToCallWhenComplete] )'; | |
// Validate options and callback | |
if (typeof options !== 'object' || typeof options.url !== 'string') { | |
throw new Error('Invalid or missing URL!\n' + usage); | |
} | |
if (options.method && typeof options.method !== 'string') { | |
throw new Error('Invalid `method` provided (should be a string like "post" or "put")\n' + usage); | |
} | |
if (options.headers && typeof options.headers !== 'object') { | |
throw new Error('Invalid `headers` provided (should be an object with string values)\n' + usage); | |
} | |
if (options.params && typeof options.params !== 'object') { | |
throw new Error('Invalid `params` provided (should be an object with string values)\n' + usage); | |
} | |
if (cb && typeof cb !== 'function') { | |
throw new Error('Invalid callback function!\n' + usage); | |
} | |
// Build a simulated request object | |
// (and sanitize/marshal options along the way) | |
var requestCtx = { | |
method: options.method.toLowerCase() || 'get', | |
headers: options.headers || {}, | |
data: options.params || options.data || {}, | |
// Remove trailing slashes and spaces to make packets smaller. | |
url: options.url.replace(/^(.+)\/*\s*$/, '$1'), | |
cb: cb | |
}; | |
// If this socket is not connected yet, queue up this request | |
// instead of sending it. | |
// (so it can be replayed when the socket comes online.) | |
if ( ! this.isConnected() ) { | |
// If no queue array exists for this socket yet, create it. | |
this.requestQueue = this.requestQueue || []; | |
this.requestQueue.push(requestCtx); | |
return; | |
} | |
// Otherwise, our socket is ok! | |
// Send the request. | |
_emitFrom(this, requestCtx); | |
}; | |
/** | |
* Socket.prototype._request | |
* | |
* Simulate HTTP over Socket.io. | |
* | |
* @api private | |
* @param {[type]} options [description] | |
* @param {Function} cb [description] | |
*/ | |
SailsSocket.prototype._request = function(options, cb) { | |
throw new Error('`_request()` was a private API deprecated as of v0.11 of the sails.io.js client. Use `.request()` instead.'); | |
}; | |
// Set a `sails` object that may be used for configuration before the | |
// first socket connects (i.e. to prevent auto-connect) | |
io.sails = { | |
// Whether to automatically connect a socket and save it as `io.socket`. | |
autoConnect: true, | |
// The route (path) to hit to get a x-origin (CORS) cookie | |
// (or true to use the default: '/__getcookie') | |
useCORSRouteToGetCookie: true, | |
// The environment we're running in. | |
// (logs are not displayed when this is set to 'production') | |
// | |
// Defaults to development unless this script was fetched from a URL | |
// that ends in `*.min.js` or '#production' (may also be manually overridden.) | |
// | |
environment: urlThisScriptWasFetchedFrom.match(/(\#production|\.min\.js)/g) ? 'production' : 'development', | |
// The version of this sails.io.js client SDK | |
sdk: SDK_INFO, | |
// Transports to use when communicating with the server, in the order they will be tried | |
transports: ['polling', 'websocket'] | |
}; | |
/** | |
* Add `io.sails.connect` function as a wrapper for the built-in `io()` aka `io.connect()` | |
* method, returning a SailsSocket. This special function respects the configured io.sails | |
* connection URL, as well as sending other identifying information (most importantly, the | |
* current version of this SDK). | |
* | |
* @param {String} url [optional] | |
* @param {Object} opts [optional] | |
* @return {Socket} | |
*/ | |
io.sails.connect = function(url, opts) { | |
opts = opts || {}; | |
// If explicit connection url is specified, save it to options | |
opts.url = url || opts.url || undefined; | |
// Instantiate and return a new SailsSocket- and try to connect immediately. | |
var socket = new SailsSocket(opts); | |
socket._connect(); | |
return socket; | |
}; | |
// io.socket | |
// | |
// The eager instance of Socket which will automatically try to connect | |
// using the host that this js file was served from. | |
// | |
// This can be disabled or configured by setting properties on `io.sails.*` within the | |
// first cycle of the event loop. | |
// | |
// Build `io.socket` so it exists | |
// (this does not start the connection process) | |
io.socket = new SailsSocket(); | |
// In the mean time, this eager socket will be queue events bound by the user | |
// before the first cycle of the event loop (using `.on()`), which will later | |
// be rebound on the raw underlying socket. | |
// If configured to do so, start auto-connecting after the first cycle of the event loop | |
// has completed (to allow time for this behavior to be configured/disabled | |
// by specifying properties on `io.sails`) | |
setTimeout(function() { | |
// If autoConnect is disabled, delete the eager socket (io.socket) and bail out. | |
if (!io.sails.autoConnect) { | |
delete io.socket; | |
return; | |
} | |
// consolog('Eagerly auto-connecting socket to Sails... (requests will be queued in the mean-time)'); | |
io.socket._connect(); | |
}, 0); // </setTimeout> | |
// Return the `io` object. | |
return io; | |
} | |
// Add CommonJS support to allow this client SDK to be used from Node.js. | |
if (typeof module === 'object' && typeof module.exports !== 'undefined') { | |
module.exports = SailsIOClient; | |
return SailsIOClient; | |
} | |
// Otherwise, try to instantiate the client: | |
// In case you're wrapping the socket.io client to prevent pollution of the | |
// global namespace, you can replace the global `io` with your own `io` here: | |
return SailsIOClient(); | |
})(); |
global.navigator = false; | |
var Promise = require("bluebird"); | |
var fs = require("fs"); | |
var io = require("socket.io-client"); | |
var sio = require("./sails.io.js"); | |
var clientio = sio(); | |
clientio.sails.url = "https://beam.pro"; | |
var socket = clientio.socket; | |
Promise.promisifyAll(socket); | |
socket.on("connect", function () { | |
console.log("connected"); | |
socket.postAsync("/api/v1/users/login", {username: "<username>", password: "<password>"}) | |
.then(function (data) { | |
// Login response | |
return socket.getAsync("/api/v1/channels/search", {scope: "names", query: "MindlessPuppetz"}); | |
}).then(function (data) { | |
// Search response | |
var id = (JSON.parse(data.body)[0]).id; | |
// console.log(JSON.parse(data.body)[0]) | |
socket.on("channel:" + id + ":status", function (status) { | |
console.log("Status changed", status); | |
}); | |
return socket.putAsync("/api/v1/live", {slug: "channel:" + id + ":status"}); | |
}).then(function (data) { | |
// Register response | |
console.log(data); | |
}).catch(function (err) { | |
console.log("ERROR", err); | |
}); | |
}); |