1740 lines
136 KiB
JavaScript
1740 lines
136 KiB
JavaScript
|
/* eslint-disable */
|
|||
|
|
|||
|
/**
|
|||
|
* To use sails.io.js in an AMD environment (e.g. with require.js),
|
|||
|
* replace this file with the sails.io.js file from the root of:
|
|||
|
* https://github.com/balderdashy/sails.io.js
|
|||
|
* and download a standalone copy of socket.io-client from:
|
|||
|
* https://github.com/socketio/socket.io-client
|
|||
|
* then follow the instructions at:
|
|||
|
* https://github.com/balderdashy/sails.io.js#requirejsamd-usage
|
|||
|
*/
|
|||
|
|
|||
|
// socket.io-client version 2.0.3
|
|||
|
// https://github.com/socketio/socket.io-client
|
|||
|
|
|||
|
!function(a,b){"object"==typeof exports&&"object"==typeof module?module.exports=b():"function"==typeof define&&define.amd?define([],b):"object"==typeof exports?exports.io=b():a.io=b()}(this,function(){return function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={exports:{},id:d,loaded:!1};return a[d].call(e.exports,e,e.exports,b),e.loaded=!0,e.exports}var c={};return b.m=a,b.c=c,b.p="",b(0)}([function(a,b,c){"use strict";function d(a,b){"object"===("undefined"==typeof a?"undefined":e(a))&&(b=a,a=void 0),b=b||{};var c,d=f(a),g=d.source,k=d.id,l=d.path,m=j[k]&&l in j[k].nsps,n=b.forceNew||b["force new connection"]||!1===b.multiplex||m;return n?(i("ignoring socket cache for %s",g),c=h(g,b)):(j[k]||(i("new io instance for %s",g),j[k]=h(g,b)),c=j[k]),d.query&&!b.query&&(b.query=d.query),c.socket(d.path,b)}var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a},f=c(1),g=c(7),h=c(13),i=c(3)("socket.io-client");a.exports=b=d;var j=b.managers={};b.protocol=g.protocol,b.connect=d,b.Manager=c(13),b.Socket=c(39)},function(a,b,c){(function(b){"use strict";function d(a,c){var d=a;c=c||b.location,null==a&&(a=c.protocol+"//"+c.host),"string"==typeof a&&("/"===a.charAt(0)&&(a="/"===a.charAt(1)?c.protocol+a:c.host+a),/^(https?|wss?):\/\//.test(a)||(f("protocol-less url %s",a),a="undefined"!=typeof c?c.protocol+"//"+a:"https://"+a),f("parse %s",a),d=e(a)),d.port||(/^(http|ws)$/.test(d.protocol)?d.port="80":/^(http|ws)s$/.test(d.protocol)&&(d.port="443")),d.path=d.path||"/";var g=d.host.indexOf(":")!==-1,h=g?"["+d.host+"]":d.host;return d.id=d.protocol+"://"+h+":"+d.port,d.href=d.protocol+"://"+h+(c&&c.port===d.port?"":":"+d.port),d}var e=c(2),f=c(3)("socket.io-client:url");a.exports=d}).call(b,function(){return this}())},function(a,b){var c=/^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,d=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];a.exports=function(a){var b=a,e=a.indexOf("["),f=a.indexOf("]");e!=-1&&f!=-1&&(a=a.substring(0,e)+a.substring(e,f).replace(/:/g,";")+a.substring(f,a.length));for(var g=c.exec(a||""),h={},i=14;i--;)h[d[i]]=g[i]||"";return e!=-1&&f!=-1&&(h.source=b,h.host=h.host.substring(1,h.host.length-1).replace(/;/g,":"),h.authority=h.authority.replace("[","").replace("]","").replace(/;/g,":"),h.ipv6uri=!0),h}},function(a,b,c){(function(d){function e(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type)||"undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function f(a){var c=this.useColors;if(a[0]=(c?"%c":"")+this.namespace+(c?" %c":" ")+a[0]+(c?"%c ":" ")+"+"+b.humanize(this.diff),c){var d="color: "+this.color;a.splice(1,0,d,"color: inherit");var e=0,f=0;a[0].replace(/%[a-zA-Z%]/g,function(a){"%%"!==a&&(e++,"%c"===a&&(f=e))}),a.splice(f,0,d)}}function g(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function h(a){try{null==a?b.storage.removeItem("debug"):b.storage.debug=a}catch(c){}}function i(){var a;try{a=b.storage.debug}catch(c){}return!a&&"undefined"!=typeof d&&"env"in d&&(a=d.env.DEBUG),a}function j(){try{return window.localStorage}catch(a){}}b=a.exports=c(5),b.log=g,b.formatArgs=f,b.save=h,b.load=i,b.useColors=e,b.storage="undefined"!=typeof chrome&
|
|||
|
return new(b[["Active"].concat("Object").join("X")])("Microsoft.XMLHTTP")}catch(g){}}}).call(b,function(){return this}())},function(a,b){try{a.exports="undefined"!=typeof XMLHttpRequest&&"withCredentials"in new XMLHttpRequest}catch(c){a.exports=!1}},function(a,b,c){(function(b){function d(){}function e(a){if(i.call(this,a),this.requestTimeout=a.requestTimeout,this.extraHeaders=a.extraHeaders,b.location){var c="https:"===location.protocol,d=location.port;d||(d=c?443:80),this.xd=a.hostname!==b.location.hostname||d!==a.port,this.xs=a.secure!==c}}function f(a){this.method=a.method||"GET",this.uri=a.uri,this.xd=!!a.xd,this.xs=!!a.xs,this.async=!1!==a.async,this.data=void 0!==a.data?a.data:null,this.agent=a.agent,this.isBinary=a.isBinary,this.supportsBinary=a.supportsBinary,this.enablesXDR=a.enablesXDR,this.requestTimeout=a.requestTimeout,this.pfx=a.pfx,this.key=a.key,this.passphrase=a.passphrase,this.cert=a.cert,this.ca=a.ca,this.ciphers=a.ciphers,this.rejectUnauthorized=a.rejectUnauthorized,this.extraHeaders=a.extraHeaders,this.create()}function g(){for(var a in f.requests)f.requests.hasOwnProperty(a)&&f.requests[a].abort()}var h=c(18),i=c(21),j=c(8),k=c(32),l=c(3)("engine.io-client:polling-xhr");a.exports=e,a.exports.Request=f,k(e,i),e.prototype.supportsBinary=!0,e.prototype.request=function(a){return a=a||{},a.uri=this.uri(),a.xd=this.xd,a.xs=this.xs,a.agent=this.agent||!1,a.supportsBinary=this.supportsBinary,a.enablesXDR=this.enablesXDR,a.pfx=this.pfx,a.key=this.key,a.passphrase=this.passphrase,a.cert=this.cert,a.ca=this.ca,a.ciphers=this.ciphers,a.rejectUnauthorized=this.rejectUnauthorized,a.requestTimeout=this.requestTimeout,a.extraHeaders=this.extraHeaders,new f(a)},e.prototype.doWrite=function(a,b){var c="string"!=typeof a&&void 0!==a,d=this.request({method:"POST",data:a,isBinary:c}),e=this;d.on("success",b),d.on("error",function(a){e.onError("xhr post error",a)}),this.sendXhr=d},e.prototype.doPoll=function(){l("xhr poll");var a=this.request(),b=this;a.on("data",function(a){b.onData(a)}),a.on("error",function(a){b.onError("xhr poll error",a)}),this.pollXhr=a},j(f.prototype),f.prototype.create=function(){var a={agent:this.agent,xdomain:this.xd,xscheme:this.xs,enablesXDR:this.enablesXDR};a.pfx=this.pfx,a.key=this.key,a.passphrase=this.passphrase,a.cert=this.cert,a.ca=this.ca,a.ciphers=this.ciphers,a.rejectUnauthorized=this.rejectUnauthorized;var c=this.xhr=new h(a),d=this;try{l("xhr open %s: %s",this.method,this.uri),c.open(this.method,this.uri,this.async);try{if(this.extraHeaders){c.setDisableHeaderCheck&&c.setDisableHeaderCheck(!0);for(var e in this.extraHeaders)this.extraHeaders.hasOwnProperty(e)&&c.setRequestHeader(e,this.extraHeaders[e])}}catch(g){}if("POST"===this.method)try{this.isBinary?c.setRequestHeader("Content-type","application/octet-stream"):c.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(g){}try{c.setRequestHeader("Accept","*/*")}catch(g){}"withCredentials"in c&&(c.withCredentials=!0),this.requestTimeout&&(c.timeout=this.requestTimeout),this.hasXDR()?(c.onload=function(){d.onLoad()},c.onerror=function(){d.onError(c.responseText)}):c.onreadystatechange=function(){if(2===c.readyState){var a;try{a=c.getResponseHeader("Content-Type")}catch(b){}"application/octet-stream"===a&&(c.responseType="arraybuffer")}4===c.readyState&&(200===c.status||1223===c.status?d.onLoad():setTimeout(function(){d.onError(c.status)},0))},l("xhr data %s",this.data),c.send(this.data)}catch(g){return void setTimeout(function(){d.onError(g)},0)}b.document&&(this.index=f.requestsCount++,f.requests[this.index]=this)},f.prototype.onSuccess=function(){this.emit("success"),this.cleanup()},f.prototype.onData=function(a){this.emit("data",a),this.onSuccess()},f.prototype.onError=function(a){this.emit("error",a),this.cleanup(!0)},f.prototype.cleanup=function(a){if("undefined"!=typeof this.xhr&&null!==this.xhr){if(this.hasXDR()?this.xhr.onload=this.xhr.onerror=d:this.xhr.onreadystatechange=d,a)try{this.xhr.abort()}catch(c){}b.document&&delete f.requests[this.index],this.xhr=null}},f.prototype.onLoad=function(){var a;try{var b;
|
|||
|
|
|||
|
//////////////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// ███████╗ █████╗ ██╗██╗ ███████╗ ██╗ ██████╗ ██╗███████╗ //
|
|||
|
// ██╔════╝██╔══██╗██║██║ ██╔════╝ ██║██╔═══██╗ ██║██╔════╝ //
|
|||
|
// ███████╗███████║██║██║ ███████╗ ██║██║ ██║ ██║███████╗ //
|
|||
|
// ╚════██║██╔══██║██║██║ ╚════██║ ██║██║ ██║ ██ ██║╚════██║ //
|
|||
|
// ███████║██║ ██║██║███████╗███████║██╗██║╚██████╔╝██╗╚█████╔╝███████║ //
|
|||
|
// ╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═════╝ ╚═╝ ╚════╝ ╚══════╝ //
|
|||
|
// //
|
|||
|
// ╦╔═╗╦ ╦╔═╗╔═╗╔═╗╦═╗╦╔═╗╔╦╗ ╔═╗╦ ╦╔═╗╔╗╔╔╦╗ ╔═╗╔╦╗╦╔═ //
|
|||
|
// ║╠═╣╚╗╔╝╠═╣╚═╗║ ╠╦╝║╠═╝ ║ ║ ║ ║║╣ ║║║ ║ ╚═╗ ║║╠╩╗ //
|
|||
|
// ╚╝╩ ╩ ╚╝ ╩ ╩╚═╝╚═╝╩╚═╩╩ ╩ ╚═╝╩═╝╩╚═╝╝╚╝ ╩ ╚═╝═╩╝╩ ╩ //
|
|||
|
// ┌─┐┌─┐┬─┐ ┌┐┌┌─┐┌┬┐┌─┐ ┬┌─┐ ┌─┐┌┐┌┌┬┐ ┌┬┐┬ ┬┌─┐ ┌┐ ┬─┐┌─┐┬ ┬┌─┐┌─┐┬─┐ //
|
|||
|
// ├┤ │ │├┬┘ ││││ │ ││├┤ │└─┐ ├─┤│││ ││ │ ├─┤├┤ ├┴┐├┬┘│ ││││└─┐├┤ ├┬┘ //
|
|||
|
// └ └─┘┴└─ ┘└┘└─┘─┴┘└─┘o└┘└─┘ ┴ ┴┘└┘─┴┘ ┴ ┴ ┴└─┘ └─┘┴└─└─┘└┴┘└─┘└─┘┴└─ //
|
|||
|
// //
|
|||
|
//////////////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
/**
|
|||
|
* sails.io.js
|
|||
|
* v1.2.1
|
|||
|
* ------------------------------------------------------------------------
|
|||
|
* 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.com/documentation/reference/web-sockets/socket-client
|
|||
|
* ------------------------------------------------------------------------
|
|||
|
*
|
|||
|
* 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() {
|
|||
|
|
|||
|
|
|||
|
// ██████╗ ██████╗ ███╗ ██╗███████╗████████╗ █████╗ ███╗ ██╗████████╗███████╗
|
|||
|
// ██╔════╝██╔═══██╗████╗ ██║██╔════╝╚══██╔══╝██╔══██╗████╗ ██║╚══██╔══╝██╔════╝
|
|||
|
// ██║ ██║ ██║██╔██╗ ██║███████╗ ██║ ███████║██╔██╗ ██║ ██║ ███████╗
|
|||
|
// ██║ ██║ ██║██║╚██╗██║╚════██║ ██║ ██╔══██║██║╚██╗██║ ██║ ╚════██║
|
|||
|
// ╚██████╗╚██████╔╝██║ ╚████║███████║ ██║ ██║ ██║██║ ╚████║ ██║ ███████║
|
|||
|
// ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* Constant containing the names of all available options
|
|||
|
* for individual sockets.
|
|||
|
*
|
|||
|
* @type {Array}
|
|||
|
*/
|
|||
|
var SOCKET_OPTIONS = [
|
|||
|
'useCORSRouteToGetCookie',
|
|||
|
'url',
|
|||
|
'multiplex',
|
|||
|
'transports',
|
|||
|
'query',
|
|||
|
'path',
|
|||
|
'headers',
|
|||
|
'initialConnectionHeaders',
|
|||
|
'reconnection',
|
|||
|
'reconnectionAttempts',
|
|||
|
'reconnectionDelay',
|
|||
|
'reconnectionDelayMax',
|
|||
|
'rejectUnauthorized',
|
|||
|
'randomizationFactor',
|
|||
|
'timeout'
|
|||
|
];
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* Constant containing the names of properties on `io.sails` which
|
|||
|
* may be configured using HTML attributes on the script tag which
|
|||
|
* loaded this file.
|
|||
|
*
|
|||
|
* @type {Array}
|
|||
|
*
|
|||
|
* (this is unused if loading from node.js)
|
|||
|
*/
|
|||
|
var CONFIGURABLE_VIA_HTML_ATTR = [
|
|||
|
'autoConnect',
|
|||
|
'reconnection',
|
|||
|
'environment',
|
|||
|
'headers',
|
|||
|
'url',
|
|||
|
'transports',
|
|||
|
'path'
|
|||
|
];
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* Constant containing the names of querystring
|
|||
|
* parameters sent when connecting any SailsSocket.
|
|||
|
*
|
|||
|
* @type {Dictionary}
|
|||
|
*/
|
|||
|
var CONNECTION_METADATA_PARAMS = {
|
|||
|
version: '__sails_io_sdk_version',
|
|||
|
platform: '__sails_io_sdk_platform',
|
|||
|
language: '__sails_io_sdk_language'
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* Constant containing metadata about the platform, language, and
|
|||
|
* current version of this SDK.
|
|||
|
*
|
|||
|
* @type {Dictionary}
|
|||
|
*/
|
|||
|
var SDK_INFO = {
|
|||
|
version: '1.2.1', // <-- pulled automatically from package.json, do not change!
|
|||
|
language: 'javascript',
|
|||
|
platform: (function (){
|
|||
|
if (typeof module === 'object' && typeof module.exports !== 'undefined') {
|
|||
|
return 'node';
|
|||
|
}
|
|||
|
else {
|
|||
|
return 'browser';
|
|||
|
}
|
|||
|
})()
|
|||
|
};
|
|||
|
|
|||
|
// Build `versionString` (a querystring snippet) by
|
|||
|
// combining SDK_INFO and CONNECTION_METADATA_PARAMS.
|
|||
|
SDK_INFO.versionString =
|
|||
|
CONNECTION_METADATA_PARAMS.version + '=' + SDK_INFO.version + '&' +
|
|||
|
CONNECTION_METADATA_PARAMS.platform + '=' + SDK_INFO.platform + '&' +
|
|||
|
CONNECTION_METADATA_PARAMS.language + '=' + SDK_INFO.language;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// █████╗ ██████╗ ███████╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗████████╗███╗ ███╗██╗
|
|||
|
// ██╔══██╗██╔══██╗██╔════╝██╔═══██╗██╔══██╗██╔══██╗ ██║ ██║╚══██╔══╝████╗ ████║██║
|
|||
|
// ███████║██████╔╝███████╗██║ ██║██████╔╝██████╔╝ ███████║ ██║ ██╔████╔██║██║
|
|||
|
// ██╔══██║██╔══██╗╚════██║██║ ██║██╔══██╗██╔══██╗ ██╔══██║ ██║ ██║╚██╔╝██║██║
|
|||
|
// ██║ ██║██████╔╝███████║╚██████╔╝██║ ██║██████╔╝ ██║ ██║ ██║ ██║ ╚═╝ ██║███████╗
|
|||
|
// ╚═╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝
|
|||
|
//
|
|||
|
// █████╗ ████████╗████████╗██████╗ ██╗██████╗ ██╗ ██╗████████╗███████╗███████╗
|
|||
|
// ██╔══██╗╚══██╔══╝╚══██╔══╝██╔══██╗██║██╔══██╗██║ ██║╚══██╔══╝██╔════╝██╔════╝
|
|||
|
// ███████║ ██║ ██║ ██████╔╝██║██████╔╝██║ ██║ ██║ █████╗ ███████╗
|
|||
|
// ██╔══██║ ██║ ██║ ██╔══██╗██║██╔══██╗██║ ██║ ██║ ██╔══╝ ╚════██║
|
|||
|
// ██║ ██║ ██║ ██║ ██║ ██║██║██████╔╝╚██████╔╝ ██║ ███████╗███████║
|
|||
|
// ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚═════╝ ╚═════╝ ╚═╝ ╚══════╝╚══════╝
|
|||
|
//
|
|||
|
// ███████╗██████╗ ██████╗ ███╗ ███╗ ██╗███████╗ ██████╗██████╗ ██╗██████╗ ████████╗██╗
|
|||
|
// ██╔════╝██╔══██╗██╔═══██╗████╗ ████║ ██╔╝██╔════╝██╔════╝██╔══██╗██║██╔══██╗╚══██╔══╝╚██╗
|
|||
|
// █████╗ ██████╔╝██║ ██║██╔████╔██║ ██╔╝ ███████╗██║ ██████╔╝██║██████╔╝ ██║ ╚██╗
|
|||
|
// ██╔══╝ ██╔══██╗██║ ██║██║╚██╔╝██║ ╚██╗ ╚════██║██║ ██╔══██╗██║██╔═══╝ ██║ ██╔╝
|
|||
|
// ██║ ██║ ██║╚██████╔╝██║ ╚═╝ ██║ ╚██╗███████║╚██████╗██║ ██║██║██║ ██║ ██╔╝
|
|||
|
// ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═╝
|
|||
|
//
|
|||
|
//
|
|||
|
// If available, grab the DOM element for the script tag which imported this file.
|
|||
|
// (skip this if this SDK is being used outside of the DOM, i.e. in a Node process)
|
|||
|
//
|
|||
|
// This is used below to parse client-side sails.io.js configuration encoded as
|
|||
|
// HTML attributes, as well as grabbing hold of the URL from whence the SDK was fetched.
|
|||
|
var thisScriptTag = (function() {
|
|||
|
if (
|
|||
|
typeof window !== 'object' ||
|
|||
|
typeof window.document !== 'object' ||
|
|||
|
typeof window.document.getElementsByTagName !== 'function'
|
|||
|
) {
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
// 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');
|
|||
|
return allScriptsCurrentlyInDOM[allScriptsCurrentlyInDOM.length - 1];
|
|||
|
})();
|
|||
|
|
|||
|
|
|||
|
// Variables to contain src URL and other script tag config (for use below).
|
|||
|
var urlThisScriptWasFetchedFrom = '';
|
|||
|
var scriptTagConfig = {};
|
|||
|
|
|||
|
|
|||
|
if (thisScriptTag) {
|
|||
|
// Save the URL that this script was fetched from.
|
|||
|
urlThisScriptWasFetchedFrom = thisScriptTag.src;
|
|||
|
|
|||
|
// Now parse the most common client-side configuration settings
|
|||
|
// from the script tag where they may be encoded as HTML attributes.
|
|||
|
//
|
|||
|
// Any configuration which may be provided as an HTML attribute may
|
|||
|
// also be provided prefixed with `data-`. This is for folks who
|
|||
|
// need to support browsers that have issues with nonstandard
|
|||
|
// HTML attributes (or if the idea of using nonstandard HTML attributes
|
|||
|
// just creeps you out)
|
|||
|
//
|
|||
|
// If a `data-` prefixed attr is provided, it takes precedence.
|
|||
|
// (this is so that if you are already using one of these HTML
|
|||
|
// attrs for some reason, you can keep it as-is and override
|
|||
|
// it using `data-`. If you are using the `data-` prefixed version
|
|||
|
// for some other purpose... well, in that case you'll just have to
|
|||
|
// configure programmatically using `io.sails` instead.)
|
|||
|
CONFIGURABLE_VIA_HTML_ATTR.forEach(function (configKey){
|
|||
|
|
|||
|
scriptTagConfig[configKey] = (function (){
|
|||
|
|
|||
|
// Support 'data-' prefixed or normal attributes.
|
|||
|
// (prefixed versions take precedence if provided)
|
|||
|
var htmlAttrVal = thisScriptTag.getAttribute( 'data-'+configKey );
|
|||
|
if (!htmlAttrVal) {
|
|||
|
htmlAttrVal = thisScriptTag.getAttribute( configKey );
|
|||
|
}
|
|||
|
|
|||
|
// The HTML attribute value should always be a string or `null`.
|
|||
|
// We'll try to parse it as JSON and use that, but worst case fall back
|
|||
|
// to the default situation of it being a string.
|
|||
|
if (typeof htmlAttrVal === 'string') {
|
|||
|
try { return JSON.parse(htmlAttrVal); } catch (e) { return htmlAttrVal; }
|
|||
|
}
|
|||
|
// If `null` was returned from getAttribute(), it means that the HTML attribute
|
|||
|
// was not specified, so we treat it as undefined (which will cause the property
|
|||
|
// to be removed below)
|
|||
|
else if (htmlAttrVal === null) {
|
|||
|
return undefined;
|
|||
|
}
|
|||
|
// Any other contingency shouldn't be possible:
|
|||
|
// - if no quotes are used in the HTML attribute, it still comes in as a string.
|
|||
|
// - if no RHS is provided for the attribute, it still comes in as "" (empty string)
|
|||
|
// (but we still handle this with an explicit error just in case--for debugging and support purposes)
|
|||
|
else throw new Error('sails.io.js :: Unexpected/invalid script tag configuration for `'+configKey+'`: `'+htmlAttrVal+'` (a `'+typeof htmlAttrVal+'`). Should be a string.');
|
|||
|
})();
|
|||
|
|
|||
|
if (scriptTagConfig[configKey] === undefined){
|
|||
|
delete scriptTagConfig[configKey];
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Now that they've been parsed, do an extremely lean version of
|
|||
|
// logical type validation/coercion of provided values.
|
|||
|
//////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// `autoConnect`
|
|||
|
if (typeof scriptTagConfig.autoConnect !== 'undefined') {
|
|||
|
if (scriptTagConfig.autoConnect === '') {
|
|||
|
// Special case for empty string. It means `true` (see above).
|
|||
|
scriptTagConfig.autoConnect = true;
|
|||
|
}
|
|||
|
else if (typeof scriptTagConfig.autoConnect !== 'boolean') {
|
|||
|
throw new Error('sails.io.js :: Unexpected/invalid configuration for `autoConnect` provided in script tag: `'+scriptTagConfig.autoConnect+'` (a `'+typeof scriptTagConfig.autoConnect+'`). Should be a boolean.');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// `environment`
|
|||
|
if (typeof scriptTagConfig.environment !== 'undefined') {
|
|||
|
if (typeof scriptTagConfig.environment !== 'string') {
|
|||
|
throw new Error('sails.io.js :: Unexpected/invalid configuration for `environment` provided in script tag: `'+scriptTagConfig.environment+'` (a `'+typeof scriptTagConfig.environment+'`). Should be a string.');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// `headers`
|
|||
|
if (typeof scriptTagConfig.headers !== 'undefined') {
|
|||
|
if (typeof scriptTagConfig.headers !== 'object' || Array.isArray(scriptTagConfig.headers)) {
|
|||
|
throw new Error('sails.io.js :: Unexpected/invalid configuration for `headers` provided in script tag: `'+scriptTagConfig.headers+'` (a `'+typeof scriptTagConfig.headers+'`). Should be a JSON-compatible dictionary (i.e. `{}`). Don\'t forget those double quotes (""), even on key names! Use single quotes (\'\') to wrap the HTML attribute value; e.g. `headers=\'{"X-Auth": "foo"}\'`');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// `url`
|
|||
|
if (typeof scriptTagConfig.url !== 'undefined') {
|
|||
|
if (typeof scriptTagConfig.url !== 'string') {
|
|||
|
throw new Error('sails.io.js :: Unexpected/invalid configuration for `url` provided in script tag: `'+scriptTagConfig.url+'` (a `'+typeof scriptTagConfig.url+'`). Should be a string.');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// OTHER `io.sails` options are NOT CURRENTLY SUPPORTED VIA HTML ATTRIBUTES.
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Grab a reference to the global socket.io client (if one is available).
|
|||
|
// This is used via closure below to determine which `io` to use when the
|
|||
|
// socket.io client instance (`io`) is augmented to become the Sails client
|
|||
|
// SDK instance (still `io`).
|
|||
|
var _existingGlobalSocketIO = (typeof io !== 'undefined') ? io : undefined;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//////////////////////////////////////////////////////////////
|
|||
|
/////
|
|||
|
///// NOW FOR BUNCHES OF:
|
|||
|
///// - PRIVATE FUNCTION DEFINITIONS
|
|||
|
///// - CONSTRUCTORS
|
|||
|
///// - AND METHODS
|
|||
|
/////
|
|||
|
//////////////////////////////////////////////////////////////
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// ███████╗ █████╗ ██╗██╗ ███████╗ ██╗ ██████╗ ██████╗██╗ ██╗███████╗███╗ ██╗████████╗
|
|||
|
// ██╔════╝██╔══██╗██║██║ ██╔════╝ ██║██╔═══██╗ ██╔════╝██║ ██║██╔════╝████╗ ██║╚══██╔══╝
|
|||
|
// ███████╗███████║██║██║ ███████╗█████╗██║██║ ██║█████╗██║ ██║ ██║█████╗ ██╔██╗ ██║ ██║
|
|||
|
// ╚════██║██╔══██║██║██║ ╚════██║╚════╝██║██║ ██║╚════╝██║ ██║ ██║██╔══╝ ██║╚██╗██║ ██║
|
|||
|
// ███████║██║ ██║██║███████╗███████║ ██║╚██████╔╝ ╚██████╗███████╗██║███████╗██║ ╚████║ ██║
|
|||
|
// ╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝ ╚═╝ ╚═════╝ ╚═════╝╚══════╝╚═╝╚══════╝╚═╝ ╚═══╝ ╚═╝
|
|||
|
//
|
|||
|
|
|||
|
/**
|
|||
|
* SailsIOClient()
|
|||
|
*
|
|||
|
* Augment the provided Socket.io client object (`io`) with methods for
|
|||
|
* talking and listening to one or more Sails backend(s). If no `io` was
|
|||
|
* provided (i.e. in a browser setting), then attempt to use the global.
|
|||
|
*
|
|||
|
* This absorbs implicit `io.sails` configuration, sets a timer for
|
|||
|
* automatically connecting a socket (if `io.sails.autoConnect` is enabled)
|
|||
|
* and returns the augmented `io`.
|
|||
|
*
|
|||
|
* Note:
|
|||
|
* The automatically-connected socket is exposed as `io.socket`. If this
|
|||
|
* socket attempts to bind event listeners or send requests before it is
|
|||
|
* connected, it will be queued up and replayed when the connection is
|
|||
|
* successfully opened.
|
|||
|
*
|
|||
|
* @param {SocketIO} io
|
|||
|
* @returns {SailsIOClient} [also called `io`]
|
|||
|
*/
|
|||
|
|
|||
|
function SailsIOClient(_providedSocketIO) {
|
|||
|
|
|||
|
// First, determine which `io` we're augmenting.
|
|||
|
//
|
|||
|
// Prefer the passed-in `io` instance, but fall back to the
|
|||
|
// global one if we've got it.
|
|||
|
var io;
|
|||
|
if (_providedSocketIO) {
|
|||
|
io = _providedSocketIO;
|
|||
|
}
|
|||
|
else {
|
|||
|
io = _existingGlobalSocketIO;
|
|||
|
}
|
|||
|
// (note that for readability, we deliberately do not short circuit or use the tertiary operator above)
|
|||
|
|
|||
|
|
|||
|
// If a socket.io client (`io`) is not available, none of this will work.
|
|||
|
if (!io) {
|
|||
|
// If node:
|
|||
|
if (SDK_INFO.platform === 'node') {
|
|||
|
throw new Error('No socket.io client available. When requiring `sails.io.js` from Node.js, a socket.io client (`io`) must be passed in; e.g.:\n```\nvar io = require(\'sails.io.js\')( require(\'socket.io-client\') )\n```\n(see https://github.com/balderdashy/sails.io.js/tree/master/test for more examples)');
|
|||
|
}
|
|||
|
// Otherwise, this is a web browser:
|
|||
|
else {
|
|||
|
throw new Error('The Sails socket SDK depends on the socket.io client, but the socket.io global (`io`) was not available when `sails.io.js` loaded. Normally, the socket.io client code is bundled with sails.io.js, so something is a little off. Please check to be sure this version of `sails.io.js` has the minified Socket.io client at the top of the file.');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// If the chosen socket.io client (`io`) has ALREADY BEEN AUGMENTED by this SDK,
|
|||
|
// (i.e. if it already has a `.sails` property) then throw an error.
|
|||
|
if (io.sails) {
|
|||
|
// If node:
|
|||
|
if (SDK_INFO.platform === 'node') {
|
|||
|
throw new Error('The provided socket.io client (`io`) has already been augmented into a Sails socket SDK instance (it has `io.sails`).');
|
|||
|
}
|
|||
|
// Otherwise, this is a web browser:
|
|||
|
else {
|
|||
|
throw new Error('The socket.io client (`io`) has already been augmented into a Sails socket SDK instance. Usually, this means you are bringing `sails.io.js` onto the page more than once.');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* 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);
|
|||
|
};
|
|||
|
}//</LoggerFactory>
|
|||
|
|
|||
|
// 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) {
|
|||
|
// Get the arguments that were originally made to the "request" method
|
|||
|
var requestArgs = queue[i];
|
|||
|
// Call the request method again in the context of the socket, with the original args
|
|||
|
socket.request.apply(socket, requestArgs);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Now empty the queue to remove it as a source of additional complexity.
|
|||
|
socket.requestQueue = null;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* Send a JSONP request.
|
|||
|
*
|
|||
|
* @param {Object} opts [optional]
|
|||
|
* @param {Function} cb
|
|||
|
* @return {XMLHttpRequest}
|
|||
|
*/
|
|||
|
|
|||
|
function jsonp(opts, cb) {
|
|||
|
opts = opts || {};
|
|||
|
|
|||
|
if (typeof window === 'undefined') {
|
|||
|
// FUTURE: refactor node usage to live in here
|
|||
|
return cb();
|
|||
|
}
|
|||
|
|
|||
|
var scriptEl = document.createElement('script');
|
|||
|
window._sailsIoJSConnect = function(response) {
|
|||
|
// In rare circumstances our script may have been vaporised.
|
|||
|
// Remove it, but only if it still exists
|
|||
|
// https://github.com/balderdashy/sails.io.js/issues/92
|
|||
|
if (scriptEl && scriptEl.parentNode) {
|
|||
|
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;
|
|||
|
this.headers = responseCtx.headers || {};
|
|||
|
this.statusCode = (typeof responseCtx.statusCode === 'undefined') ? 200 : responseCtx.statusCode;
|
|||
|
// FUTURE: Replace this typeof short-circuit with an assertion (statusCode should always be set)
|
|||
|
|
|||
|
if (this.statusCode < 200 || this.statusCode >= 400) {
|
|||
|
// Determine the appropriate error message.
|
|||
|
var msg;
|
|||
|
if (this.statusCode === 0) {
|
|||
|
msg = 'The socket request failed.';
|
|||
|
}
|
|||
|
else {
|
|||
|
msg = 'Server responded with a ' + this.statusCode + ' status code';
|
|||
|
msg += ':\n```\n' + JSON.stringify(this.body, null, 2) + '\n```';
|
|||
|
// (^^Note that we should always be able to rely on socket.io to give us
|
|||
|
// non-circular data here, so we don't have to worry about wrapping the
|
|||
|
// above in a try...catch)
|
|||
|
}
|
|||
|
|
|||
|
// Now build and attach Error instance.
|
|||
|
this.error = new Error(msg);
|
|||
|
}
|
|||
|
}
|
|||
|
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() {
|
|||
|
// FUTURE: 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 && !requestCtx.calledCb) {
|
|||
|
cb(responseCtx.body, new JWR(responseCtx));
|
|||
|
// Set flag indicating that callback was called, to avoid duplicate calls.
|
|||
|
requestCtx.calledCb = true;
|
|||
|
// Remove the callback from the list.
|
|||
|
socket._responseCbs.splice(socket._responseCbs.indexOf(cb), 1);
|
|||
|
// Remove the context from the list.
|
|||
|
socket._requestCtxs.splice(socket._requestCtxs.indexOf(requestCtx), 1);
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// ███████╗ █████╗ ██╗██╗ ███████╗███████╗ ██████╗ ██████╗██╗ ██╗███████╗████████╗
|
|||
|
// ██╔════╝██╔══██╗██║██║ ██╔════╝██╔════╝██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝
|
|||
|
// ███████╗███████║██║██║ ███████╗███████╗██║ ██║██║ █████╔╝ █████╗ ██║
|
|||
|
// ╚════██║██╔══██║██║██║ ╚════██║╚════██║██║ ██║██║ ██╔═██╗ ██╔══╝ ██║
|
|||
|
// ███████║██║ ██║██║███████╗███████║███████║╚██████╔╝╚██████╗██║ ██╗███████╗ ██║
|
|||
|
// ╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═╝
|
|||
|
//
|
|||
|
|
|||
|
/**
|
|||
|
* 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
|
|||
|
* @api private
|
|||
|
*
|
|||
|
* ----------------------------------------------------------------------
|
|||
|
* Note: This constructor should not be used directly. To obtain a `SailsSocket`
|
|||
|
* instance of your very own, run:
|
|||
|
* ```
|
|||
|
* var mySocket = io.sails.connect();
|
|||
|
* ```
|
|||
|
* ----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
function SailsSocket (opts){
|
|||
|
var self = this;
|
|||
|
opts = opts||{};
|
|||
|
|
|||
|
// Initialize private properties
|
|||
|
self._isConnecting = false;
|
|||
|
self._mightBeAboutToAutoConnect = false;
|
|||
|
|
|||
|
// Set up connection options so that they can only be changed when socket is disconnected.
|
|||
|
var _opts = {};
|
|||
|
SOCKET_OPTIONS.forEach(function(option) {
|
|||
|
// Okay to change global headers while socket is connected
|
|||
|
if (option == 'headers') {return;}
|
|||
|
Object.defineProperty(self, option, {
|
|||
|
get: function() {
|
|||
|
if (option == 'url') {
|
|||
|
return _opts[option] || (self._raw && self._raw.io && self._raw.io.uri);
|
|||
|
}
|
|||
|
return _opts[option];
|
|||
|
},
|
|||
|
set: function(value) {
|
|||
|
// Don't allow value to be changed while socket is connected
|
|||
|
if (self.isConnected() && io.sails.strict !== false && value != _opts[option]) {
|
|||
|
throw new Error('Cannot change value of `' + option + '` while socket is connected.');
|
|||
|
}
|
|||
|
// If socket is attempting to reconnect, stop it.
|
|||
|
if (self._raw && self._raw.io && self._raw.io.reconnecting && !self._raw.io.skipReconnect) {
|
|||
|
self._raw.io.skipReconnect = true;
|
|||
|
consolog('Stopping reconnect; use .reconnect() to connect socket after changing options.');
|
|||
|
}
|
|||
|
_opts[option] = value;
|
|||
|
}
|
|||
|
});
|
|||
|
});
|
|||
|
|
|||
|
// Absorb opts into SailsSocket instance
|
|||
|
// See http://sailsjs.com/documentation/reference/web-sockets/socket-client/sails-socket/properties
|
|||
|
// for description of options
|
|||
|
SOCKET_OPTIONS.forEach(function(option) {
|
|||
|
self[option] = opts[option];
|
|||
|
});
|
|||
|
|
|||
|
// 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);
|
|||
|
});
|
|||
|
|
|||
|
// FUTURE:
|
|||
|
// 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.)
|
|||
|
|
|||
|
}//</SailsSocket>
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* `SailsSocket.prototype._connect()`
|
|||
|
*
|
|||
|
* Begin connecting this socket to the server.
|
|||
|
*
|
|||
|
* @api private
|
|||
|
*/
|
|||
|
SailsSocket.prototype._connect = function (){
|
|||
|
var self = this;
|
|||
|
|
|||
|
self._isConnecting = true;
|
|||
|
|
|||
|
// Apply `io.sails` config as defaults
|
|||
|
// (now that at least one tick has elapsed)
|
|||
|
// See http://sailsjs.com/documentation/reference/web-sockets/socket-client/sails-socket/properties
|
|||
|
// for description of options and default values
|
|||
|
SOCKET_OPTIONS.forEach(function(option) {
|
|||
|
if ('undefined' == typeof self[option]) {
|
|||
|
self[option] = io.sails[option];
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
// Headers that will be sent with the initial request to /socket.io (Node.js only)
|
|||
|
self.extraHeaders = self.initialConnectionHeaders || {};
|
|||
|
|
|||
|
// For browser usage (currently works with "polling" transport only)
|
|||
|
self.transportOptions = self.transportOptions || {};
|
|||
|
self.transports.forEach(function(transport) {
|
|||
|
self.transportOptions[transport] = self.transportOptions[transport] || {};
|
|||
|
self.transportOptions[transport].extraHeaders = self.initialConnectionHeaders || {};
|
|||
|
});
|
|||
|
|
|||
|
// Log a warning if non-Node.js platform attempts to use `initialConnectionHeaders` for anything other than `polling`.
|
|||
|
if (self.initialConnectionHeaders && SDK_INFO.platform !== 'node' && self.transports.indexOf('polling') === -1 || self.transports.length > 1) {
|
|||
|
if (typeof console === 'object' && typeof console.warn === 'function') {
|
|||
|
console.warn('When running in browser, `initialConnectionHeaders` option is only available for the `polling` transport.');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 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') {
|
|||
|
// (If provided as a string, trim leading question mark,
|
|||
|
// just in case one was provided.)
|
|||
|
self.query = self.query.replace(/^\?/, '');
|
|||
|
self.query += '&' + SDK_INFO.versionString;
|
|||
|
}
|
|||
|
else if (self.query && typeof self.query === 'object') {
|
|||
|
throw new Error('`query` setting does not currently support configuration as a dictionary (`{}`). Instead, it must be specified as a string like `foo=89&bar=hi`');
|
|||
|
}
|
|||
|
else if (!self.query) {
|
|||
|
self.query = SDK_INFO.versionString;
|
|||
|
}
|
|||
|
else {
|
|||
|
throw new Error('Unexpected data type provided for `query` setting: '+self.query);
|
|||
|
}
|
|||
|
|
|||
|
// Determine whether this is a cross-origin socket by examining the
|
|||
|
// hostname and port on the `window.location` object. If it's cross-origin,
|
|||
|
// we'll attempt to get a cookie for the domain so that a Sails session can
|
|||
|
// be established.
|
|||
|
var isXOrigin = (function (){
|
|||
|
|
|||
|
// If `window` doesn't exist (i.e. being used from Node.js), then
|
|||
|
// we won't bother attempting to get a cookie. If you're using sockets
|
|||
|
// from Node.js and find you need to share a session between multiple
|
|||
|
// socket connections, you'll need to make an HTTP request to the /__getcookie
|
|||
|
// endpoint of the Sails server (or any endpoint that returns a set-cookie header)
|
|||
|
// and then use the cookie value in the `initialConnectionHeaders` option to
|
|||
|
// io.sails.connect()
|
|||
|
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 via a browswe, 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)
|
|||
|
jsonp({
|
|||
|
url: xOriginCookieURL,
|
|||
|
method: 'GET'
|
|||
|
}, 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);
|
|||
|
|
|||
|
// If the low-level transport throws an error _while connecting_, then set the _isConnecting flag
|
|||
|
// to false (since we're no longer connecting with any chance of success anyway).
|
|||
|
// Also, in this case (and in dev mode only) log a helpful message.
|
|||
|
self._raw.io.engine.transport.on('error', function(err){
|
|||
|
if (!self._isConnecting) { return; }
|
|||
|
|
|||
|
self._isConnecting = false;
|
|||
|
|
|||
|
// Track this timestamp for use in reconnection messages
|
|||
|
// (only relevant if reconnection is enabled.)
|
|||
|
self.connectionErrorTimestamp = (new Date()).getTime();
|
|||
|
|
|||
|
// Development-only message:
|
|||
|
consolog('====================================');
|
|||
|
consolog('The socket was unable to connect.');
|
|||
|
consolog('The server may be offline, or the');
|
|||
|
consolog('socket may have failed authorization');
|
|||
|
consolog('based on its origin or other factors.');
|
|||
|
consolog('You may want to check the values of');
|
|||
|
consolog('`sails.config.sockets.onlyAllowOrigins`');
|
|||
|
consolog('or (more rarely) `sails.config.sockets.beforeConnect`');
|
|||
|
consolog('in your app.');
|
|||
|
consolog('More info: https://sailsjs.com/config/sockets');
|
|||
|
consolog('For help: https://sailsjs.com/support');
|
|||
|
consolog('');
|
|||
|
consolog('Technical details:');
|
|||
|
consolog(err);
|
|||
|
consolog('====================================');
|
|||
|
});
|
|||
|
|
|||
|
// 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() {
|
|||
|
self._isConnecting = false;
|
|||
|
consolog.noPrefix(
|
|||
|
'\n' +
|
|||
|
'\n' +
|
|||
|
// ' |> ' + '\n' +
|
|||
|
// ' \\___/ '+️
|
|||
|
// '\n'+
|
|||
|
' |> Now connected to '+(self.url ? self.url : 'Sails')+'.' + '\n' +
|
|||
|
'\\___/ For help, see: http://bit.ly/2q0QDpf' + '\n' +
|
|||
|
' (using sails.io.js '+io.sails.sdk.platform+' SDK @v'+io.sails.sdk.version+')'+ '\n' +
|
|||
|
' Connected at: '+(new Date())+'\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() {
|
|||
|
|
|||
|
// Get a timestamp of when the disconnect was detected.
|
|||
|
self.connectionLostTimestamp = (new Date()).getTime();
|
|||
|
|
|||
|
// Get a shallow clone of the internal array of response callbacks, in case any of the callbacks mutate it.
|
|||
|
var responseCbs = [].concat(self._responseCbs || []);
|
|||
|
// Wipe the internal array of response callbacks before executing them, in case a callback happens to add
|
|||
|
// a new request to the queue.
|
|||
|
self._responseCbs = [];
|
|||
|
|
|||
|
// Do the same for the internal request context list.
|
|||
|
var requestCtxs = [].concat(self._requestCtxs || []);
|
|||
|
self._requestCtxs = [];
|
|||
|
|
|||
|
// Loop through the callbacks for all in-progress requests, and call them each with an error indicating the disconnect.
|
|||
|
if (responseCbs.length) {
|
|||
|
responseCbs.forEach(function(responseCb) {
|
|||
|
responseCb(new Error('The socket disconnected before the request completed.'), {
|
|||
|
body: null,
|
|||
|
statusCode: 0,
|
|||
|
headers: {}
|
|||
|
});
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
// If there is a list of request contexts, indicate that their callbacks have been
|
|||
|
// called and then wipe the list. This prevents errors in the edge case of a response
|
|||
|
// somehow coming back after the socket reconnects.
|
|||
|
if (requestCtxs.length) {
|
|||
|
requestCtxs.forEach(function(requestCtx) {
|
|||
|
requestCtx.calledCb = true;
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
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 '+(self.url ? self.url : 'Sails')+'...\n'+
|
|||
|
'_-|>_- (attempt #' + numAttempts + ')'+'\n'+
|
|||
|
'\n'
|
|||
|
);
|
|||
|
});
|
|||
|
|
|||
|
self.on('reconnect', function(transport, numAttempts) {
|
|||
|
if (!self._isConnecting) {
|
|||
|
self.on('connect', runRequestQueue.bind(self, self));
|
|||
|
}
|
|||
|
|
|||
|
var msSinceLastOffline;
|
|||
|
var numSecsOffline;
|
|||
|
if (self.connectionLostTimestamp){
|
|||
|
msSinceLastOffline = ((new Date()).getTime() - self.connectionLostTimestamp);
|
|||
|
numSecsOffline = (msSinceLastOffline / 1000);
|
|||
|
}
|
|||
|
else if (self.connectionErrorTimestamp) {
|
|||
|
msSinceLastOffline = ((new Date()).getTime() - self.connectionErrorTimestamp);
|
|||
|
numSecsOffline = (msSinceLastOffline / 1000);
|
|||
|
}
|
|||
|
else {
|
|||
|
msSinceLastOffline = '???';
|
|||
|
numSecsOffline = '???';
|
|||
|
}
|
|||
|
|
|||
|
consolog(
|
|||
|
'\n'+
|
|||
|
' |> Socket reconnected successfully after'+'\n'+
|
|||
|
'\\___/ being offline at least ' + 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) {
|
|||
|
self._isConnecting = false;
|
|||
|
////////////////////////////////////////////////////////////////////////////////////
|
|||
|
// Note:
|
|||
|
// In the future, we could provide a separate event for when a socket cannot connect
|
|||
|
// due to a failed `beforeConnect` (aka "authorization" if you're old school).
|
|||
|
// this could probably be implemented by emitting a special event from the server.
|
|||
|
////////////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
consolog(
|
|||
|
'Failed to connect socket (possibly due to failed `beforeConnect` on server)',
|
|||
|
'Error:', err
|
|||
|
);
|
|||
|
});
|
|||
|
});
|
|||
|
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Reconnect the underlying socket.
|
|||
|
*
|
|||
|
* @api public
|
|||
|
*/
|
|||
|
SailsSocket.prototype.reconnect = function (){
|
|||
|
if (this._isConnecting) {
|
|||
|
throw new Error('Cannot connect- socket is already connecting');
|
|||
|
}
|
|||
|
if (this.isConnected()) {
|
|||
|
throw new Error('Cannot connect- socket is already connected');
|
|||
|
}
|
|||
|
return this._connect();
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Disconnect the underlying socket.
|
|||
|
*
|
|||
|
* @api public
|
|||
|
*/
|
|||
|
SailsSocket.prototype.disconnect = function (){
|
|||
|
this._isConnecting = false;
|
|||
|
if (!this.isConnected()) {
|
|||
|
throw new Error('Cannot disconnect- socket is already disconnected');
|
|||
|
}
|
|||
|
return this._raw.disconnect();
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* isConnected
|
|||
|
*
|
|||
|
* @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.connected;
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* isConnecting
|
|||
|
*
|
|||
|
* @return {Boolean} whether the socket is in the process of connecting
|
|||
|
* to the server.
|
|||
|
*/
|
|||
|
|
|||
|
SailsSocket.prototype.isConnecting = function () {
|
|||
|
return this._isConnecting;
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* isConnecting
|
|||
|
*
|
|||
|
* @return {Boolean} flag that is `true` after a SailsSocket instance is
|
|||
|
* initialized but before one tick of the event loop
|
|||
|
* has passed (so that it hasn't attempted to connect
|
|||
|
* yet, if autoConnect ends up being configured `true`)
|
|||
|
*/
|
|||
|
SailsSocket.prototype.mightBeAboutToAutoConnect = function() {
|
|||
|
return this._mightBeAboutToAutoConnect;
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* [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() ) {
|
|||
|
self._raw.once('connect', runRequestQueue.bind(self, self));
|
|||
|
}
|
|||
|
// 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} data :: 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} data :: 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} data :: 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 PATCH request to sails
|
|||
|
* e.g.
|
|||
|
* `socket.patch('/event/3', changedFields, $spinner.hide)`
|
|||
|
*
|
|||
|
* @api public
|
|||
|
* @param {String} url :: destination URL
|
|||
|
* @param {Object} data :: parameters to send with the request [optional]
|
|||
|
* @param {Function} cb :: callback function to call when finished [optional]
|
|||
|
*/
|
|||
|
|
|||
|
SailsSocket.prototype.patch = function(url, data, cb) {
|
|||
|
|
|||
|
// `data` is optional
|
|||
|
if (typeof data === 'function') {
|
|||
|
cb = data;
|
|||
|
data = {};
|
|||
|
}
|
|||
|
|
|||
|
return this.request({
|
|||
|
method: 'patch',
|
|||
|
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} data :: 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@example.com" }'+'\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 cb !== 'undefined' && typeof cb !== 'function') {
|
|||
|
throw new Error('Invalid callback function!\n' + usage);
|
|||
|
}
|
|||
|
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 a dictionary with string values)\n' + usage);
|
|||
|
}
|
|||
|
if (options.params && typeof options.params !== 'object') {
|
|||
|
throw new Error('Invalid `params` provided (should be a dictionary with JSON-serializable values)\n' + usage);
|
|||
|
}
|
|||
|
if (options.data && typeof options.data !== 'object') {
|
|||
|
throw new Error('Invalid `data` provided (should be a dictionary with JSON-serializable values)\n' + usage);
|
|||
|
}
|
|||
|
|
|||
|
// Accept either `params` or `data` for backwards compatibility (but not both!)
|
|||
|
if (options.data && options.params) {
|
|||
|
throw new Error('Cannot specify both `params` and `data`! They are aliases of each other.\n' + usage);
|
|||
|
}
|
|||
|
else if (options.data) {
|
|||
|
options.params = options.data;
|
|||
|
delete options.data;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// 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([options, cb]);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Otherwise, our socket is connected, so continue prepping
|
|||
|
// the request.
|
|||
|
|
|||
|
// Default headers to an empty object
|
|||
|
options.headers = options.headers || {};
|
|||
|
|
|||
|
// Build a simulated request object
|
|||
|
// (and sanitize/marshal options along the way)
|
|||
|
var requestCtx = {
|
|||
|
|
|||
|
method: (options.method || 'get').toLowerCase(),
|
|||
|
|
|||
|
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
|
|||
|
};
|
|||
|
|
|||
|
// Get a reference to the callback list, or create a new one.
|
|||
|
this._responseCbs = this._responseCbs || [];
|
|||
|
|
|||
|
// Get a reference to the request context list, or create a new one.
|
|||
|
this._requestCtxs = this._requestCtxs || [];
|
|||
|
|
|||
|
// Add this callback to the list. If the socket disconnects, we'll call
|
|||
|
// each cb in the list with an error and reset the list. Otherwise the
|
|||
|
// cb will be removed from the list when the server responds.
|
|||
|
// Also add the request context to the list. It will be removed once
|
|||
|
// the response comes back, or if the socket disconnects.
|
|||
|
if (cb) {
|
|||
|
this._responseCbs.push(cb);
|
|||
|
this._requestCtxs.push(requestCtx);
|
|||
|
}
|
|||
|
|
|||
|
// Merge global headers in, if there are any.
|
|||
|
if (this.headers && 'object' === typeof this.headers) {
|
|||
|
for (var header in this.headers) {
|
|||
|
if (!options.headers.hasOwnProperty(header)) {
|
|||
|
options.headers[header] = this.headers[header];
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 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 an `io.sails` object that may be used for configuration before the
|
|||
|
// first socket connects (i.e. to allow auto-connect behavior to be
|
|||
|
// prevented by setting `io.sails.autoConnect` in an inline script
|
|||
|
// directly after the script tag which loaded this file).
|
|||
|
|
|||
|
|
|||
|
// ┌─┐┌─┐┌┬┐ ┬ ┬┌─┐ ╔╦╗╔═╗╔═╗╔═╗╦ ╦╦ ╔╦╗╔═╗ ┌─┐┌─┐┬─┐ ┬┌─┐ ┌─┐┌─┐┬┬ ┌─┐
|
|||
|
// └─┐├┤ │ │ │├─┘ ║║║╣ ╠╣ ╠═╣║ ║║ ║ ╚═╗ ├┤ │ │├┬┘ ││ │ └─┐├─┤││ └─┐
|
|||
|
// └─┘└─┘ ┴ └─┘┴ ═╩╝╚═╝╚ ╩ ╩╚═╝╩═╝╩ ╚═╝ └ └─┘┴└─ ┴└─┘o└─┘┴ ┴┴┴─┘└─┘
|
|||
|
io.sails = {
|
|||
|
|
|||
|
// Whether to automatically connect a socket and save it as `io.socket`.
|
|||
|
autoConnect: true,
|
|||
|
|
|||
|
// Whether to automatically try to reconnect after connection is lost
|
|||
|
reconnection: false,
|
|||
|
|
|||
|
// 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', or if the conventional
|
|||
|
// `SAILS_LOCALS` global is set with an `_environment` of "production"
|
|||
|
// or "staging". (This setting may also be manually overridden.)
|
|||
|
environment: (
|
|||
|
urlThisScriptWasFetchedFrom.match(/(\#production|\.min\.js)/g) ||
|
|||
|
(
|
|||
|
typeof window === 'object' && window &&
|
|||
|
typeof window.SAILS_LOCALS === 'object' && window.SAILS_LOCALS &&
|
|||
|
(window.SAILS_LOCALS._environment === 'staging' || window.SAILS_LOCALS._environment === 'production')
|
|||
|
)
|
|||
|
)? '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: ['websocket']
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// ┌─┐─┐ ┬┌┬┐┌─┐┌┐┌┌┬┐ ┬┌─┐ ┌─┐┌─┐┬┬ ┌─┐ ┌┬┐┌─┐┌─┐┌─┐┬ ┬┬ ┌┬┐┌─┐
|
|||
|
// ├┤ ┌┴┬┘ │ ├┤ │││ ││ ││ │ └─┐├─┤││ └─┐ ││├┤ ├┤ ├─┤│ ││ │ └─┐
|
|||
|
// └─┘┴ └─ ┴ └─┘┘└┘─┴┘ ┴└─┘o└─┘┴ ┴┴┴─┘└─┘ ─┴┘└─┘└ ┴ ┴└─┘┴─┘┴ └─┘
|
|||
|
// ┬ ┬┬┌┬┐┬ ┬ ┌┬┐┬ ┬┌─┐ ╦ ╦╔╦╗╔╦╗╦ ╔═╗╔╦╗╔╦╗╦═╗╦╔╗ ╦ ╦╔╦╗╔═╗╔═╗
|
|||
|
// ││││ │ ├─┤ │ ├─┤├┤ ╠═╣ ║ ║║║║ ╠═╣ ║ ║ ╠╦╝║╠╩╗║ ║ ║ ║╣ ╚═╗
|
|||
|
// └┴┘┴ ┴ ┴ ┴ ┴ ┴ ┴└─┘ ╩ ╩ ╩ ╩ ╩╩═╝ ╩ ╩ ╩ ╩ ╩╚═╩╚═╝╚═╝ ╩ ╚═╝╚═╝
|
|||
|
// ┌─┐┬─┐┌─┐┌┬┐ ┌┬┐┬ ┬┌─┐ ┌─┐┌─┐┬─┐┬┌─┐┌┬┐ ┌┬┐┌─┐┌─┐
|
|||
|
// ├┤ ├┬┘│ ││││ │ ├─┤├┤ └─┐│ ├┬┘│├─┘ │ │ ├─┤│ ┬
|
|||
|
// └ ┴└─└─┘┴ ┴ ┴ ┴ ┴└─┘ └─┘└─┘┴└─┴┴ ┴ ┴ ┴ ┴└─┘
|
|||
|
//
|
|||
|
// Now fold in config provided as HTML attributes on the script tag:
|
|||
|
// (note that if `io.sails.*` is changed after this script, those changes
|
|||
|
// will still take precedence)
|
|||
|
CONFIGURABLE_VIA_HTML_ATTR.forEach(function (configKey){
|
|||
|
if (typeof scriptTagConfig[configKey] !== 'undefined') {
|
|||
|
io.sails[configKey] = scriptTagConfig[configKey];
|
|||
|
}
|
|||
|
});
|
|||
|
//////////////////////////////////////////////////////////////////////////////
|
|||
|
// Note that the new HTML attribute configuration style may eventually
|
|||
|
// completely replace the original approach of setting `io.sails` properties,
|
|||
|
// since the new strategy is easier to reason about. Also, it would allow us
|
|||
|
// to remove the timeout below someday.
|
|||
|
//////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// ┬┌─┐ ┌─┐┌─┐┬┬ ┌─┐ ╔═╗╔═╗╔╗╔╔╗╔╔═╗╔═╗╔╦╗ / \
|
|||
|
// ││ │ └─┐├─┤││ └─┐ ║ ║ ║║║║║║║║╣ ║ ║ / /
|
|||
|
// ┴└─┘o└─┘┴ ┴┴┴─┘└─┘o╚═╝╚═╝╝╚╝╝╚╝╚═╝╚═╝ ╩ \ /
|
|||
|
|
|||
|
/**
|
|||
|
* 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) {
|
|||
|
|
|||
|
// Make URL optional
|
|||
|
if ('object' === typeof url) {
|
|||
|
opts = url;
|
|||
|
url = null;
|
|||
|
}
|
|||
|
|
|||
|
// Default opts to empty object
|
|||
|
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
|
|||
|
// (note that this DOES NOT start the connection process)
|
|||
|
io.socket = new SailsSocket();
|
|||
|
//
|
|||
|
// This socket is not connected yet, and has not even _started_ connecting.
|
|||
|
//
|
|||
|
// But 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`)
|
|||
|
|
|||
|
// Indicate that the autoConnect timer has started.
|
|||
|
io.socket._mightBeAboutToAutoConnect = true;
|
|||
|
|
|||
|
setTimeout(function() {
|
|||
|
|
|||
|
// Indicate that the autoConect timer fired.
|
|||
|
io.socket._mightBeAboutToAutoConnect = false;
|
|||
|
|
|||
|
// If autoConnect is disabled, delete the eager socket (io.socket) and bail out.
|
|||
|
if (io.sails.autoConnect === false || io.sails.autoconnect === false) {
|
|||
|
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;
|
|||
|
} //</SailsIOClient>
|
|||
|
|
|||
|
//
|
|||
|
/////////////////////////////////////////////////////////////////////////////////
|
|||
|
///// </bunches of private function definitions, constructors, and methods>
|
|||
|
/////////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// ███████╗██╗ ██╗██████╗ ██████╗ ███████╗███████╗ ███████╗██████╗ ██╗ ██╗
|
|||
|
// ██╔════╝╚██╗██╔╝██╔══██╗██╔═══██╗██╔════╝██╔════╝ ██╔════╝██╔══██╗██║ ██╔╝
|
|||
|
// █████╗ ╚███╔╝ ██████╔╝██║ ██║███████╗█████╗ ███████╗██║ ██║█████╔╝
|
|||
|
// ██╔══╝ ██╔██╗ ██╔═══╝ ██║ ██║╚════██║██╔══╝ ╚════██║██║ ██║██╔═██╗
|
|||
|
// ███████╗██╔╝ ██╗██║ ╚██████╔╝███████║███████╗ ███████║██████╔╝██║ ██╗
|
|||
|
// ╚══════╝╚═╝ ╚═╝╚═╝ ╚═════╝ ╚══════╝╚══════╝ ╚══════╝╚═════╝ ╚═╝ ╚═╝
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
// Add CommonJS support to allow this client SDK to be used from Node.js.
|
|||
|
if (SDK_INFO.platform === 'node') {
|
|||
|
module.exports = SailsIOClient;
|
|||
|
}
|
|||
|
// Add AMD support, registering this client SDK as an anonymous module.
|
|||
|
else if (typeof define === 'function' && define.amd) {
|
|||
|
define([], function() {
|
|||
|
return SailsIOClient;
|
|||
|
});
|
|||
|
}
|
|||
|
else {
|
|||
|
// Otherwise, try to instantiate the client using the global `io`:
|
|||
|
SailsIOClient();
|
|||
|
|
|||
|
// Note:
|
|||
|
// If you are modifying this file manually to wrap an existing socket.io client
|
|||
|
// (e.g. to prevent pollution of the global namespace), you can replace the global
|
|||
|
// `io` with your own `io` instance above.
|
|||
|
}
|
|||
|
|
|||
|
})();
|
|||
|
;
|
|||
|
|
|||
|
/* eslint-enable */
|