I have a Sinatra app that uses Websockets.
My app works when I run it with ruby app.rb, but doesn't when I'm trying to run it with shotgun app.rb.
This is in my sending_out.erb:
<script>
$(document).ready(function(){
connection = new WebSocket('ws://' + window.location.host + window.location.pathname);
connection.onopen = function(){
$("#msgs").append('Connection opened'+"<br>")
};
connection.onmessage = function(e){
$("#msgs").append(e.data+"<br>");
};
connection.onclose = function() {
$("#msgs").append('Connection closes from view'+"<br>");
};
$("form").submit(function(){
connection.send( $("input").val() );
});
});
</script>
And this is in my app.rb:
require 'sinatra-websocket'
set :sockets, []
get '/sending_out' do
request.websocket do |connection|
connection.onopen do
connection.send("Hello World!")
settings.sockets << connection
connection.send("opened")
connection.send("went")
end
connection.onmessage do |msg|
EM.next_tick { settings.sockets.each{|s| s.send(msg) } }
end
connection.onclose do
warn("websocket closed")
settings.sockets.delete(ws)
end
end
end
It must show
Connection opened
Hello World!
opened
went
when I go to the page. But it only shows
Connection closes from view
with Shotgun.
And in the console it says WebSocket connection to 'ws://127.0.0.1:9393/sending_out' failed: Error during WebSocket handshake: Unexpected response code: 500.
Is there an issue running Websockets with Shotgun?
The main feature of Shotgun is that it automatically reloads your whole code every request and I think that could be also the problem you are facing.
Shotgun should be used just for development.
For production purposes you have plenty of other options available:
Puma
Rainbows
Unicorn
Thin
others
Comparison of ruby servers can be found on https://www.digitalocean.com/community/tutorials/a-comparison-of-rack-web-servers-for-ruby-web-applications
Related
Actually my question is not about console only. I haven't found any libraries for testing LiteCable, and I try to implement some. The problem I faced now, is when I call in console something like (exactly same as official example):
LiteCable.broadcast "chat_#{chat_id}", user: user, message: data["message"], sid: sid
It returns nil. I've tried to put byebug in the code, and when I call this method with absolutely same parameters there, I got pretty big sheet with some unreadable parameters. And the main problem is I don't see messages I try to send from console.
Can someone explain why is that and how can I implement sending requests from console? The point is I working on api-only application, and try to cover this functionality with proper tests. Thank you very much in advance!
P.S: the project is on pure ruby, without rails
Since you don't have the entire code, I am unable to get a clear sense of your setup. The default broadcast_adapter for LiteCable is memory, so if you were to broadcast from your console, processes outside your console will not receive such streams. If you use the anycable adapter which I believe queues broadcasts in redis, then you should be able to broadcast from your console provided you have the correct connection.
Here is a simple implementation of a WS client and a server using LiteCable without Rails
# ~/app/server.rb
# A simple WS server that evaluates math expression literally using ruby eval
# Run this server with ruby server.rb
require "rack"
require "rack/handler/puma"
require "lite_cable"
require "lite_cable/server"
class CalculatorConnection < LiteCable::Connection::Base
identified_by :token
def connect
self.token = request.params["token"]
$stdout.puts "Session #{token} is connected to the server"
end
def disconnect
$stdout.puts "Session #{token} disconnected from the server"
end
end
class CalculatorChannel < LiteCable::Channel::Base
identifier :calculator
def subscribed
stream_from "calculator"
end
def evaluate(payload)
$stdout.puts "Data received from the client"
LiteCable.broadcast "calculator", result: eval(payload['expression'])
end
end
app = Rack::Builder.new
app.map "/cable" do
use LiteCable::Server::Middleware, connection_class: CalculatorConnection
run(proc { |_| [200, {"Content-Type" => "text/plain"}, ["OK"]] })
end
Rack::Handler::Puma.run app
// ~/app/client.js
// A client that talks to the WS server.
// To run, Open chrome console and paste this code
let socket = null;
(function init() {
socket = new WebSocket("ws://0.0.0.0:9292/cable?token=abc123");
socket.onopen = function (e) {
console.info("[connected] : Connection established to the server");
};
socket.onmessage = function (e) {
console.info("[message] : Message from the server", e.data);
};
socket.onerror = function (e) {
console.error("[error] : Error establishing connection", e.message);
};
})();
// subscribe to the calculator channel
socket.send(
JSON.stringify({
command: "subscribe",
identifier: JSON.stringify({
channel: "calculator",
}),
})
);
// call the evaluate method on the Calculator channel
socket.send(
JSON.stringify({
command: "message",
identifier: JSON.stringify({
channel: "calculator",
}),
data: JSON.stringify({
expression: "150 * 4 - 3 / (2 + 2)",
action: "evaluate",
}),
})
);
There's nothing special going on here just a simple rack app that uses Puma which adds support for rack socket hijacking. This should guide you in the right direction. Make sure you keep both your server and chrome console open to see the output. Try sending additional message to the server to see the output.
If you are looking at implementing a WebSocket client in ruby instead of js using LiteCable, check the client socket class in the LiteCable repo
I have an Electron app which tries to connect to a device over a web socket. The connection is encrypted (i.e. wss) but the SSL certificate is self signed and thus, untrusted.
Connecting inside Chrome is ok and it works. However inside Electron I run into problems. Without putting any certificate-error handlers on the BrowserWindow or on the app I receive the following error in the console output:
WebSocket connection to 'wss://some_ip:50443/' failed: Error in connection establishment: net::ERR_CERT_AUTHORITY_INVALID
Then shortly after:
User is closing WAMP connection.... unreachable
In my code, to make the connection I run the following.
const connection = new autobahn.Connection({
realm: 'some_realm',
url: 'wss://some_ip:50443'
});
connection.onopen = (session, details) => {
console.log('* User is opening WAMP connection....', session, details);
};
connection.onclose = (reason, details) => {
console.log('* User is closing WAMP connection....', reason, details);
return true;
};
connection.open();
// alternatively, this also displays the same error
const socket = new WebSocket(`wss://some_ip:50443`);
socket.onopen = function (event) {
console.log(event);
};
socket.onclose = function (event) {
console.log(event);
};
NOTE: Autobahn is a Websocket library for connecting using the WAMP protocol to a socket server of some sort. (in my case, the device) The underlying protocol is wss. Underneath the code above, a native JS new WebSocket() is being called. In other words:
As I mentioned, I've tested this code in the browser window and it works. I've also built a smaller application to try and isolate the issue. Still no luck.
I have tried adding the following code to my main.js process script:
app.commandLine.appendSwitch('ignore-certificate-errors');
and
win.webContents.on('certificate-error', (event, url, error, certificate, callback) => {
// On certificate error we disable default behaviour (stop loading the page)
// and we then say "it is all fine - true" to the callback
event.preventDefault();
callback(true);
});
and
app.on('certificate-error', (event, webContents, link, error, certificate, callback) => {
// On certificate error we disable default behaviour (stop loading the page)
// and we then say "it is all fine - true" to the callback
event.preventDefault();
callback(true);
});
This changed the error to:
WebSocket connection to 'wss://some_ip:50443/' failed: WebSocket opening handshake was canceled
My understanding is that the 'certificate-error' handlers above should escape any SSL certificate errors and allow the application to proceed. However, they're not.
I've also tried adding the following to main.js:
win = new BrowserWindow({
webPreferences: {
nodeIntegration: true,
webSecurity: false
}
});
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = '1';
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
With Election, how do I properly deal with a certificate from an untrusted authority? i.e. a self signed cert.
Any help would be much appreciated.
I had the same problem , all i added was your line:
app.commandLine.appendSwitch('ignore-certificate-errors');
I use socket.io, but i think its the same principal.
I do however connect to the https protocol and not wss directly.
This is what my connection looks like on the page:
socket = io.connect(
'https://yoursocketserver:yourport', {
'socketpath',
secure: false,
transports: ['websocket']
});
That seems to have done the trick.
Thank you for the help :) i hope this answer helps you too.
I am using websockets in my laravel project. I have opened a port by PHP that is 8000 and it is working fine. I am connecting to the port by following in in view file:
function WebSocketInit()
{
if ("WebSocket" in window)
{
// Let us open a web socket
ws = new ReconnectingWebSocket("ws://xxx.xxx.xxx.xxx:8000");
}
else
{
// The browser doesn't support WebSocket
alert("WebSocket NOT supported by your Browser!");
}
}
WebSocketInit();
ws.onopen = function(){
console.log( "Connected." );
};
ws.onclose = function(){
ws.refresh();
console.log( "Disconnected." );
};
It connects well first time but if I refresh my page then it disconnects and do not re-connect most of the time. Sometimes, it connects but takes few seconds. Any help will be appreciated.
Thanks in advance!
I'm trying to implement autobahn 0.9.5 on my SPA project using DurandalJS.
var ab = require('autobahn');
live = new ab.Connection(
{
url: 'ws://localhost:8080',
realm: 'realm1'
});
live.onopen = function(session, details)
{
console.log('Autobahn open successfully!', session);
};
live.onclose = function(reason, details)
{
console.log('Autobahn connection lost', reason + ' - ' + details);
};
live.open();
i received an error on firefox and chrome browser
Firefox:
InvalidAccessError: A parameter or an operation is not supported by the underlying object
websocket.close(code, reason);
Chrome:
WebSocket connection to 'ws://localhost:8080/' failed: Error during WebSocket handshake: Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received
I have no idea what happened..
BEFORE I STARTED WITH - autobahn 0.9.5
I have write simple test on test.html to see if everything setup in backend is correct.
But on this test i currently used autobahn 0.8.2
test.html
<script src="http://autobahn.s3.amazonaws.com/js/autobahn.min.js"></script>
<script>
var conn = new ab.Session(
// Websocket host
'ws://localhost:8080',
// Callback on connection established
function() {
// Once connect, subscribe to channel
conn.subscribe('3', function(topic, data) {
console.log(topic, data);
});
},
// Callback on connection close
function() {
console.warn('WebSocket connection closed');
},
// Additional AB parameters
{'skipSubprotocolCheck': true}
);
</script>
This test working perfectly as what i need, but after I try to implement it inside real project, I can't make autobahn 0.8.2 loaded using requireJS, It keep give me an error ab not defined.
I don't really understand what is happening, according of autobahn getting started, it should work.
and here is how I define it on main.js (requirejs paths and shim config)
requirejs.config({
paths: {
'autobahn' : 'https://autobahn.s3.amazonaws.com/autobahnjs/latest/autobahn.min',
'when' : 'https://cdnjs.cloudflare.com/ajax/libs/when/2.7.1/when'
},
shim: {
'autobahn': {
deps: ['when']
}
}
});
Hopefully somebody can help me, I really love to make it working !
Any help will be greatly appreciated!
Thanks
Probably late, but for further reference.
This is probably not a complete answer to SO question.
First of all, everything should be written either for AutobahnJS v0.8.2 (which supports WAMPv1) or for AutobahnJS v0.9.5 (WAMPv2).
Check API documentation.
WAMP v1
AutobahnJS v0.8.2 API - http://autobahn.ws/js/reference_wampv1.html
it loads from http://autobahn.s3.amazonaws.com/js/autobahn.js
global variable for autobahn is ab
connecting with var conn = new ab.Session(wuri, onOpenCallback, onCloseCallback, options);
WAMP v2
AutobahnJS v0.9.5 API - http://autobahn.ws/js/reference.html
it loads from https://autobahn.s3.amazonaws.com/autobahnjs/latest/autobahn.min.jgz
global variable for autobahn is autobahn
connecting with new autobahn.Connection({url: wuri, realm: yourRealm});
I'm going crazy trying to figure out what's wrong with my system that it is unable to send websocket messages. I've tried a ton of things:
Chrome 32, firefox 27, ie 10
various websocket server libraries: ws, websocket, nodejs-websocket
running the server on windows and centos
reinstalling node.js (to version 0.10.26)
reinstalling firefox
Turning off my firewall
The behavior is always the same: both client and server say they get a connection, but when the client tries to send a message, the other one simply doesn't get it. Sometimes i get "Error: read ECONNRESET" on the server - but not all the time. About 50% of the time it just fails silently. Eventually the connection closes.
If I add code to send a message from the server on connection, it always gets "Error: read ECONNRESET".
What does work?
the exact same code and setup on my laptop
any websocket code online, for example this: http://www.websocket.org/echo.html
So what could cause just my local websocket connection to silently drop messages?
Server:
var
ws = require('websocket').server
var http = require('http')
var server = http.createServer(function(request, response) {
console.log("connection received for "+request.url)
response.writeHead(404)
response.end()
})
server.listen(8080, function() {
console.log("now listening")
})
wsServer = new ws({httpServer:server, autoAcceptConnections: false})
wsServer.on('request', function(request) {
console.log("got request")
var connection = request.accept('a', request.origin)
console.log("got connection")
connection.on('message', function(message) {
console.log("got message: "+message)
})
connection.on("close", function() {
console.log("closed")
})
connection.on('error', function(e) {
console.log('Error: '+e)
})
})
Output:
got connection
closed
Client:
<script>
var ws = new WebSocket('ws://localhost:8080/', 'a')
ws.onopen = function() {
console.log('open')
ws.send('something2')
}
ws.onerror = function(e) {
console.log(e)
}
ws.onmessage = function(m) {
console.log(m)
}
ws.onclose = function() {
console.log('closed')
}
</script>
Output
open
closed
This is driving me crazy.