在node.js中运行websocket-rails javascript客户端

我试图从我的web服务器从websocket检索数据。 远程主机上的websocket服务器运行websocket-rails。 从Websocket-rails github项目页面( https://github.com/websocket-rails )我使用javascript客户端代码将一个web套接字客户端放在一个html文件中。 也就是说,我将github上的/ lib / assets / javascripts / websocket_rails中的所有CoffeeScript文件的内容复制到一个单独的文件中,然后用js2coffee.org进行编译(可能是更好的解决scheme,但是我可能是更好的解决scheme现在注意到)。 然后添加几行连接到远程Web套接字并订阅频道。 (通道部分实际上是为什么我使用WebSocket-rails客户端,而不是一个“正常”的Web套接字连接,因为我不知道如何通过一个“正常的”websocket连接连接后订阅一个通道)。

到现在为止还挺好。 当使用浏览器和下面的代码时,我可以从远程主机上的websocket连接到一个通道,并将消息发送到控制台。

<!DOCTYPE html> <meta charset="utf-8" /> <title>WebSocket Test</title> <script language="javascript" type="text/javascript"> (function() { var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; this.WebSocketRails = (function() { function WebSocketRails(url, use_websockets) { this.url = url; this.use_websockets = use_websockets != null ? use_websockets : true; this.connection_stale = __bind(this.connection_stale, this); this.pong = __bind(this.pong, this); this.supports_websockets = __bind(this.supports_websockets, this); this.dispatch_channel = __bind(this.dispatch_channel, this); this.unsubscribe = __bind(this.unsubscribe, this); this.subscribe_private = __bind(this.subscribe_private, this); this.subscribe = __bind(this.subscribe, this); this.dispatch = __bind(this.dispatch, this); this.trigger_event = __bind(this.trigger_event, this); this.trigger = __bind(this.trigger, this); this.unbind = __bind(this.unbind, this); this.bind = __bind(this.bind, this); this.connection_established = __bind(this.connection_established, this); this.new_message = __bind(this.new_message, this); this.reconnect = __bind(this.reconnect, this); this.callbacks = {}; this.channels = {}; this.queue = {}; this.connect(); } WebSocketRails.prototype.connect = function() { this.state = 'connecting'; if (!(this.supports_websockets() && this.use_websockets)) { this._conn = new WebSocketRails.HttpConnection(this.url, this); } else { this._conn = new WebSocketRails.WebSocketConnection(this.url, this); } return this._conn.new_message = this.new_message; }; WebSocketRails.prototype.disconnect = function() { if (this._conn) { this._conn.close(); delete this._conn._conn; delete this._conn; } return this.state = 'disconnected'; }; WebSocketRails.prototype.reconnect = function() { var event, id, old_connection_id, _ref, _ref1; old_connection_id = (_ref = this._conn) != null ? _ref.connection_id : void 0; this.disconnect(); this.connect(); _ref1 = this.queue; for (id in _ref1) { event = _ref1[id]; if (event.connection_id === old_connection_id && !event.is_result()) { this.trigger_event(event); } } return this.reconnect_channels(); }; WebSocketRails.prototype.new_message = function(data) { var event, socket_message, _i, _len, _ref, _results; _results = []; for (_i = 0, _len = data.length; _i < _len; _i++) { socket_message = data[_i]; event = new WebSocketRails.Event(socket_message); if (event.is_result()) { if ((_ref = this.queue[event.id]) != null) { _ref.run_callbacks(event.success, event.data); } delete this.queue[event.id]; } else if (event.is_channel()) { this.dispatch_channel(event); } else if (event.is_ping()) { this.pong(); } else { this.dispatch(event); } if (this.state === 'connecting' && event.name === 'client_connected') { _results.push(this.connection_established(event.data)); } else { _results.push(void 0); } } return _results; }; WebSocketRails.prototype.connection_established = function(data) { this.state = 'connected'; this._conn.setConnectionId(data.connection_id); this._conn.flush_queue(); if (this.on_open != null) { return this.on_open(data); } }; WebSocketRails.prototype.bind = function(event_name, callback) { var _base; if ((_base = this.callbacks)[event_name] == null) { _base[event_name] = []; } return this.callbacks[event_name].push(callback); }; WebSocketRails.prototype.unbind = function(event_name) { return delete this.callbacks[event_name]; }; WebSocketRails.prototype.trigger = function(event_name, data, success_callback, failure_callback) { var event, _ref; event = new WebSocketRails.Event([event_name, data, (_ref = this._conn) != null ? _ref.connection_id : void 0], success_callback, failure_callback); return this.trigger_event(event); }; WebSocketRails.prototype.trigger_event = function(event) { var _base, _name; if ((_base = this.queue)[_name = event.id] == null) { _base[_name] = event; } if (this._conn) { this._conn.trigger(event); } return event; }; WebSocketRails.prototype.dispatch = function(event) { var callback, _i, _len, _ref, _results; if (this.callbacks[event.name] == null) { return; } _ref = this.callbacks[event.name]; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { callback = _ref[_i]; _results.push(callback(event.data)); } return _results; }; WebSocketRails.prototype.subscribe = function(channel_name, success_callback, failure_callback) { var channel; if (this.channels[channel_name] == null) { channel = new WebSocketRails.Channel(channel_name, this, false, success_callback, failure_callback); this.channels[channel_name] = channel; return channel; } else { return this.channels[channel_name]; } }; WebSocketRails.prototype.subscribe_private = function(channel_name, success_callback, failure_callback) { var channel; if (this.channels[channel_name] == null) { channel = new WebSocketRails.Channel(channel_name, this, true, success_callback, failure_callback); this.channels[channel_name] = channel; return channel; } else { return this.channels[channel_name]; } }; WebSocketRails.prototype.unsubscribe = function(channel_name) { if (this.channels[channel_name] == null) { return; } this.channels[channel_name].destroy(); return delete this.channels[channel_name]; }; WebSocketRails.prototype.dispatch_channel = function(event) { if (this.channels[event.channel] == null) { return; } return this.channels[event.channel].dispatch(event.name, event.data); }; WebSocketRails.prototype.supports_websockets = function() { return typeof WebSocket === "function" || typeof WebSocket === "object"; }; WebSocketRails.prototype.pong = function() { var pong, _ref; pong = new WebSocketRails.Event(['websocket_rails.pong', {}, (_ref = this._conn) != null ? _ref.connection_id : void 0]); return this._conn.trigger(pong); }; WebSocketRails.prototype.connection_stale = function() { return this.state !== 'connected'; }; WebSocketRails.prototype.reconnect_channels = function() { var callbacks, channel, name, _ref, _results; _ref = this.channels; _results = []; for (name in _ref) { channel = _ref[name]; callbacks = channel._callbacks; channel.destroy(); delete this.channels[name]; channel = channel.is_private ? this.subscribe_private(name) : this.subscribe(name); channel._callbacks = callbacks; _results.push(channel); } return _results; }; return WebSocketRails; })(); /* The Event object stores all the relevant event information. */ WebSocketRails.Event = (function() { function Event(data, success_callback, failure_callback) { var attr; this.success_callback = success_callback; this.failure_callback = failure_callback; this.name = data[0]; attr = data[1]; if (attr != null) { this.id = attr['id'] != null ? attr['id'] : ((1 + Math.random()) * 0x10000) | 0; this.channel = attr.channel != null ? attr.channel : void 0; this.data = attr.data != null ? attr.data : attr; this.token = attr.token != null ? attr.token : void 0; this.connection_id = data[2]; if (attr.success != null) { this.result = true; this.success = attr.success; } } } Event.prototype.is_channel = function() { return this.channel != null; }; Event.prototype.is_result = function() { return typeof this.result !== 'undefined'; }; Event.prototype.is_ping = function() { return this.name === 'websocket_rails.ping'; }; Event.prototype.serialize = function() { return JSON.stringify([this.name, this.attributes()]); }; Event.prototype.attributes = function() { return { id: this.id, channel: this.channel, data: this.data, token: this.token }; }; Event.prototype.run_callbacks = function(success, result) { this.success = success; this.result = result; if (this.success === true) { return typeof this.success_callback === "function" ? this.success_callback(this.result) : void 0; } else { return typeof this.failure_callback === "function" ? this.failure_callback(this.result) : void 0; } }; return Event; })(); /* Abstract Interface for the WebSocketRails client. */ WebSocketRails.AbstractConnection = (function() { function AbstractConnection(url, dispatcher) { this.dispatcher = dispatcher; this.message_queue = []; } AbstractConnection.prototype.close = function() {}; AbstractConnection.prototype.trigger = function(event) { if (this.dispatcher.state !== 'connected') { return this.message_queue.push(event); } else { return this.send_event(event); } }; AbstractConnection.prototype.send_event = function(event) { if (this.connection_id != null) { return event.connection_id = this.connection_id; } }; AbstractConnection.prototype.on_close = function(event) { var close_event; if (this.dispatcher && this.dispatcher._conn === this) { close_event = new WebSocketRails.Event(['connection_closed', event]); this.dispatcher.state = 'disconnected'; return this.dispatcher.dispatch(close_event); } }; AbstractConnection.prototype.on_error = function(event) { var error_event; if (this.dispatcher && this.dispatcher._conn === this) { error_event = new WebSocketRails.Event(['connection_error', event]); this.dispatcher.state = 'disconnected'; return this.dispatcher.dispatch(error_event); } }; AbstractConnection.prototype.on_message = function(event_data) { if (this.dispatcher && this.dispatcher._conn === this) { return this.dispatcher.new_message(event_data); } }; AbstractConnection.prototype.setConnectionId = function(connection_id) { this.connection_id = connection_id; }; AbstractConnection.prototype.flush_queue = function() { var event, _i, _len, _ref; _ref = this.message_queue; for (_i = 0, _len = _ref.length; _i < _len; _i++) { event = _ref[_i]; this.trigger(event); } return this.message_queue = []; }; return AbstractConnection; })(); /* HTTP Interface for the WebSocketRails client. */ WebSocketRails.HttpConnection = (function(_super) { __extends(HttpConnection, _super); HttpConnection.prototype.connection_type = 'http'; HttpConnection.prototype._httpFactories = function() { return [ function() { return new XDomainRequest(); }, function() { return new XMLHttpRequest(); }, function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, function() { return new ActiveXObject("Msxml3.XMLHTTP"); }, function() { return new ActiveXObject("Microsoft.XMLHTTP"); } ]; }; function HttpConnection(url, dispatcher) { var e; this.dispatcher = dispatcher; HttpConnection.__super__.constructor.apply(this, arguments); this._url = "http://" + url; this._conn = this._createXMLHttpObject(); this.last_pos = 0; try { this._conn.onreadystatechange = (function(_this) { return function() { return _this._parse_stream(); }; })(this); this._conn.addEventListener("load", this.on_close, false); } catch (_error) { e = _error; this._conn.onprogress = (function(_this) { return function() { return _this._parse_stream(); }; })(this); this._conn.onload = this.on_close; this._conn.readyState = 3; } this._conn.open("GET", this._url, true); this._conn.send(); } HttpConnection.prototype.close = function() { return this._conn.abort(); }; HttpConnection.prototype.send_event = function(event) { HttpConnection.__super__.send_event.apply(this, arguments); return this._post_data(event.serialize()); }; HttpConnection.prototype._post_data = function(payload) { return $.ajax(this._url, { type: 'POST', data: { client_id: this.connection_id, data: payload }, success: function() {} }); }; HttpConnection.prototype._createXMLHttpObject = function() { var e, factories, factory, xmlhttp, _i, _len; xmlhttp = false; factories = this._httpFactories(); for (_i = 0, _len = factories.length; _i < _len; _i++) { factory = factories[_i]; try { xmlhttp = factory(); } catch (_error) { e = _error; continue; } break; } return xmlhttp; }; HttpConnection.prototype._parse_stream = function() { var data, e, event_data; if (this._conn.readyState === 3) { data = this._conn.responseText.substring(this.last_pos); this.last_pos = this._conn.responseText.length; data = data.replace(/\]\]\[\[/g, "],["); try { event_data = JSON.parse(data); return this.on_message(event_data); } catch (_error) { e = _error; } } }; return HttpConnection; })(WebSocketRails.AbstractConnection); /* WebSocket Interface for the WebSocketRails client. */ WebSocketRails.WebSocketConnection = (function(_super) { __extends(WebSocketConnection, _super); WebSocketConnection.prototype.connection_type = 'websocket'; function WebSocketConnection(url, dispatcher) { this.url = url; this.dispatcher = dispatcher; WebSocketConnection.__super__.constructor.apply(this, arguments); if (this.url.match(/^wss?:\/\//)) { console.log("WARNING: Using connection urls with protocol specified is depricated"); } else if (window.location.protocol === 'https:') { this.url = "wss://" + this.url; } else { this.url = "wss://" + this.url; } this._conn = new WebSocket(this.url); this._conn.onmessage = (function(_this) { return function(event) { var event_data; event_data = JSON.parse(event.data); return _this.on_message(event_data); }; })(this); this._conn.onclose = (function(_this) { return function(event) { return _this.on_close(event); }; })(this); this._conn.onerror = (function(_this) { return function(event) { return _this.on_error(event); }; })(this); } WebSocketConnection.prototype.close = function() { return this._conn.close(); }; WebSocketConnection.prototype.send_event = function(event) { WebSocketConnection.__super__.send_event.apply(this, arguments); return this._conn.send(event.serialize()); }; return WebSocketConnection; })(WebSocketRails.AbstractConnection); /* The channel object is returned when you subscribe to a channel. For instance: var dispatcher = new WebSocketRails('localhost:3000/websocket'); var awesome_channel = dispatcher.subscribe('awesome_channel'); awesome_channel.bind('event', function(data) { console.log('channel event!'); }); awesome_channel.trigger('awesome_event', awesome_object); If you want to unbind an event, you can use the unbind function : awesome_channel.unbind('event') */ WebSocketRails.Channel = (function() { function Channel(name, _dispatcher, is_private, on_success, on_failure) { var event, event_name, _ref; this.name = name; this._dispatcher = _dispatcher; this.is_private = is_private != null ? is_private : false; this.on_success = on_success; this.on_failure = on_failure; this._failure_launcher = __bind(this._failure_launcher, this); this._success_launcher = __bind(this._success_launcher, this); this._callbacks = {}; this._token = void 0; this._queue = []; if (this.is_private) { event_name = 'websocket_rails.subscribe_private'; } else { event_name = 'websocket_rails.subscribe'; } this.connection_id = (_ref = this._dispatcher._conn) != null ? _ref.connection_id : void 0; event = new WebSocketRails.Event([ event_name, { data: { channel: this.name } }, this.connection_id ], this._success_launcher, this._failure_launcher); this._dispatcher.trigger_event(event); } Channel.prototype.destroy = function() { var event, event_name, _ref; if (this.connection_id === ((_ref = this._dispatcher._conn) != null ? _ref.connection_id : void 0)) { event_name = 'websocket_rails.unsubscribe'; event = new WebSocketRails.Event([ event_name, { data: { channel: this.name } }, this.connection_id ]); this._dispatcher.trigger_event(event); } return this._callbacks = {}; }; Channel.prototype.bind = function(event_name, callback) { var _base; if ((_base = this._callbacks)[event_name] == null) { _base[event_name] = []; } return this._callbacks[event_name].push(callback); }; Channel.prototype.unbind = function(event_name) { return delete this._callbacks[event_name]; }; Channel.prototype.trigger = function(event_name, message) { var event; event = new WebSocketRails.Event([ event_name, { channel: this.name, data: message, token: this._token }, this.connection_id ]); if (!this._token) { return this._queue.push(event); } else { return this._dispatcher.trigger_event(event); } }; Channel.prototype.dispatch = function(event_name, message) { var callback, _i, _len, _ref, _ref1, _results; if (event_name === 'websocket_rails.channel_token') { this.connection_id = (_ref = this._dispatcher._conn) != null ? _ref.connection_id : void 0; this._token = message['token']; return this.flush_queue(); } else { if (this._callbacks[event_name] == null) { return; } _ref1 = this._callbacks[event_name]; _results = []; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { callback = _ref1[_i]; _results.push(callback(message)); } return _results; } }; Channel.prototype._success_launcher = function(data) { if (this.on_success != null) { return this.on_success(data); } }; Channel.prototype._failure_launcher = function(data) { if (this.on_failure != null) { return this.on_failure(data); } }; Channel.prototype.flush_queue = function() { var event, _i, _len, _ref; _ref = this._queue; for (_i = 0, _len = _ref.length; _i < _len; _i++) { event = _ref[_i]; this._dispatcher.trigger_event(event); } return this._queue = []; }; return Channel; })(); }).call(this); //// Below is the code I added, the rest is compiled coffeeScript from the WebSocket-Rails github repository testWebSocket = function() { var channelTicker, websocket; websocket = new WebSocketRails(wsUri); websocket.on_open = function(data) { console.log("Socket opened on " + wsUri + " :)"); }; channelTicker = websocket.subscribe("ticker"); channelTicker.bind("ticker.new", function(data) { console.log(data); }); }; wsUri = "ws.remotehost.com:3456/websocket"; testWebSocket(); </script> <h2>WebSocket Test</h2> <p>all output in console</p> 

所以在这之后我想,很好,让我们弄清楚如何使用服务器打开web套接字连接并将所有输出存储在mysql数据库中。 但是,这是有点难,然后我期望…我试图node.js运行我的web服务器上的HTML文件的JavaScript。 这是行不通的。 它会抛出一个错误:

 WebSocketRails.Event = (function() { ^ ReferenceError: WebSocketRails is not defined at Object.<anonymous> (/Users/user/Desktop/tmp/wsBrowserClient.js:242:1) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) at startup (node.js:119:16) at node.js:906:3 

据我现在了解,浏览器和node.js中运行js之间的巨大差异是有或没有一个DOM。 浏览器将variables赋值给window对象,但是node.js不能这样做。

所以我必须改变JavaScript代码为“node.js”的JavaScript,但无法find我必须开始。 我最好的猜测将是线

  this.WebSocketRails = (function() { 

但是我应该改变它呢? 希望有人能帮我一把。 如果有人能告诉我如何订阅一个“普通”webwocket的频道,然后使用为节点js编写的web套接字客户端,当然这也可以。

或者一种“只是”运行代码,因为它现在是另一种方法的服务器端,这也有帮助。

要清楚,我是一个在JavaScript的noob。 知道一个或两个关于PHP的事情,但是在这里帮不了我多less…

非常感谢您的帮助!