I'm trying to use websocket-rails to broadcast live routes as they come in to my site. However, I'm unable to get any messages to be published. I've read all of the help I could find, and I can't seem to get a solution.
Here is what the javascript I have in application.html.erb:
var route_name = window.location.pathname + window.location.search;
$.post("/realtimeroutes",
{ data: { route_name: route_name} },
function(response) {
}
);
This data is handed off to a rails controller method realtime_routes which looks like this:
def realtime_routes
puts '*** The Route Data is: ' + params[:data][:route_name]);
new_route = RouteCatcher.new(route_name: params[:data][:route_name]
if new_route.save
route = {route_name: params[:data][:route_name]}
puts '*** Right before the Message is sent ***'
WebsocketRails[:new_route].trigger('new', route)
puts '*** Right After the Message is sent ***'
render nothing: true
else
render nothing: true
end
end
To this point everything is fine. updates are happening in the DB and both the before and after messages are printing to the console, but there is no Websocket Message fired.
Next I have this javascript listening in realtime.html.erb:
var dispatcher = new WebSocketRails(window.location.host + '/websocket');
var channel = dispatcher.subscribe('new_route');
channel.bind('new', function(route) {
console.log('********** Inside Bind Event');
console.log('********** a new route '+ route.route_name +' arrived!');
});
Nothing is ever being received on the bind event and when I look in the Console on Chrome, I get:
'Uncaught ReferenceError: WebSocketRails is not defined'
So I'm absolutely stuck here as I've followed every bit of documentation I can find and really have no idea where to go. Any help with this is greatly appreciated.
UPDATE: That was an initialization error because the WebSocketRails was being rendered before the rest of the application js.
However, now I am getting the error:
WebSocket connection to 'ws://localhost:3000/websocket' failed: Error during WebSocket handshake: Unexpected response code: 301
After reading further about other people with the same error, it seems prudent to mention that I am using Puma on AWS elasticbeanstalk with SSL in production.
Related
Bottom line up front: The Paho MQTT client sucessfully connects to my Mosquitto broker, but immediately disconnects when I try to publish a message or when it receives a message from a topic it's subscribed to. I've tried changing Mosquitto's listening port and authentication settings, and using two different versions of Paho MQTT, and I still have the same problem.
Now let's get into detail.
Intro: I'm making a dashboard for some facial recognition devices that communicate through MQTT. I set up a Mosquitto broker and I've had no problems connecting to it and communicating with the devices using the Paho MQTT client for Python (I made a kind of server to sync the device's info to a database). Now I'm making the web interface, so I added a WebSockets listener to my mosquitto.conf and wrote a script using the Paho MQTT library for Javascript to connect to it, subscribe to topic sgdrf/out, send a simple JSON message to topic sgdrf/in to get the list of online devices, and process the response of the Python server once it arrives.
Problem and attempted solutions: I ran the Django server, loaded the web page and opened the JS console to find that the MQTT client successfully connected to the broker but immediately disconnected when it tried to publish the message to topic sgdrf/in. Here's each line of console output with their explanations:
The message produced by the onSuccess function, which indicates that the client successfully connected to the Mosquitto broker:
Conexión exitosa al broker MQTT.
In the onConnected function, I added console.log(uri) to see the URI used by the client to connect to the broker. I got:
ws://localhost:61613/
After printing uri to console, I made the client subscribe to sgdrf/out and then print 'subscribed' to console:
subscribed
Then I call get_online_devices(mqtt_client), a function which creates a simple JSON string and publishes it to the topic sgdrf/in. But first, it prints the strign to the console so that I can check it (just in case):
{"operator":"GetOnlineDevices","messageId":96792535859850080000,"info":{}}
Then, when the publish method is actually executed, is when I get this error (captured by the onConnectionLost function):
Pérdida de conexión con el broker MQTT: AMQJS0005E Internal error. Error Message: message is not defined, Stack trace: No Error Stack Available (código: 5)
I checked the Mosquitto log file and it only says when a new client was connected and then when it was disconnected because of a socket error (each time for every page reload). Tail of /var/log/mosquitto/mosquitto.log:
1614796149: New connection from 127.0.0.1 on port 61612.
1614796149: New client connected from 127.0.0.1 as mqttx_53195902 (p2, c1, k60, u'admin').
1614796182: Socket error on client sgdrf_dashboard_8499, disconnecting.
1614796325: New client connected from ::ffff:127.0.0.1 as sgdrf_dashboard_1597 (p2, c1, k60, u'admin').
1614796325: Socket error on client sgdrf_dashboard_1597, disconnecting.
1614796336: New client connected from ::ffff:127.0.0.1 as sgdrf_dashboard_6565 (p2, c1, k60, u'admin').
1614796336: Socket error on client sgdrf_dashboard_6565, disconnecting.
1614796931: New client connected from ::ffff:127.0.0.1 as sgdrf_dashboard_9773 (p2, c1, k60, u'admin').
1614796931: Socket error on client sgdrf_dashboard_9773, disconnecting.
1614797168: Saving in-memory database to /var/lib/mosquitto/mosquitto.db.
I tried changing the listening port in mosquitto.conf, and enabling and disabling authentication, but it changes nothing. And obviously I've had to restart Mosquito every time I changed the config file. I don't think the problem is Mosquitto.
I have the same problem whether I use Paho MQTT version 1.1.0 or 1.0.3.
As an experiment, I commented out the call to get_online_devices in my Javascript so that it doesn't try to publish anything, reloaded the page and there was no error, as expected. Then, I used MQTTX to send a JSON message to the sgdrf/out topic to which the MQTT JS client is subscribed to, and it immediately disconnected with the same error message.
Code: At the bottom of the page (index.html) I have the following code (the original code has Django template tags to fill in some values, so this is the actual code received by the browser):
<!-- Paho MQTT -->
<script src="/static/js/paho-mqtt-min.js"></script>
<!-- Scripts -->
<script src="/static/js/dashboard.js"></script>
<script>
function get_online_devices(mqtt_client) {
cmd = {
operator: "GetOnlineDevices",
messageId: generate_random_number_n_exp(20),
info: {}
};
payload_string = JSON.stringify(cmd);
console.log(payload_string)
mqtt_client.publish("sgdrf/in", payload_string);
}
function add_device_to_list(device) {
// Omitted for brevity. It's not being used yet.
}
let mqtt_client = make_mqtt_client("localhost", 61613);
let connection_options = make_connection_options(
"admin",
"CENSORED_PASSWORD"
);
mqtt_client.onConnected = function(reconnect, uri) {
console.log(uri)
mqtt_client.subscribe("sgdrf/out");
console.log('subscribed');
get_online_devices(mqtt_client);
};
mqtt_client.onConnectionLost = mqtt_client_on_connection_lost;
mqtt_client.onMessageDelivered = mqtt_client_on_message_delivered;
mqtt_client.onMessageArrived = function (msg) {
// Omitted for brevity. Checks if the payload is a
// JSON object with the right data and calls
// add_device_to_list for each item of a list in it.
};
$(document).ready(function() {
mqtt_client.connect(connection_options);
$("#reload-device-list-btn").click(function() {
get_online_devices(mqtt_client);
});
});
</script>
The dashboard.js files mentioned above just has some functions that I think will be useful for other pages, so I separated them to a file:
// dashboard.js
function generate_random_number_n_exp(n) {
return parseInt(Math.random() * Math.pow(10, n), 10)
}
function make_mqtt_client(host, port) {
let client_id = "sgdrf_dashboard_" + generate_random_number_n_exp(4);
return new Paho.Client(host, port, '/', client_id);
}
function make_connection_options(user, password) {
let connection_options = {
userName: user,
password: password,
onSuccess: mqtt_client_on_success,
onFailure: mqtt_client_on_failure,
};
return connection_options;
}
function mqtt_client_on_success() {
console.log('Conexión exitosa al broker MQTT.');
}
function mqtt_client_on_failure(error) {
console.log(
'Fallo de conexión con el broker MQTT: ' + error.errorMessage
+ ' (código: ' + error.errorCode + ')'
);
}
function mqtt_client_on_connection_lost (error) {
console.log('Pérdida de conexión con el broker MQTT: ' + error.errorMessage
+ ' (código: ' + error.errorCode + ')'
);
}
function mqtt_client_on_message_delivered(msg) {
let topic = message.destinationName;
let payload = message.payloadString;
console.log("Mensaje enviado a " + topic + ": " + payload);
}
function mqtt_client_on_message_arrived(msg) {
let topic = message.destinationName;
let payload = message.payloadString;
console.log("Mensaje recibido de " + topic + ": " + payload);
}
Here are the contents of my mosquitto.conf file:
per_listener_settings true
listener 61612
allow_anonymous false
password_file /home/s8a/Projects/sgdrf/config/pwdfile.txt
listener 61613
protocol websockets
allow_anonymous false
password_file /home/s8a/Projects/sgdrf/config/pwdfile.txt
It just sets up a TCP listener and a WebSockets listener, both disallow anonymous connections, and authenticate using a pwdfile. As I said before, I have enabled and disabled anonymous connections, and changed the port number to 9001 and back to 61613, and I still have the same error.
Conclusion: I don't know what to do and this project's deadline is next week.
I feel kinda stupid, because it was really a trivial typing mistake. The problem is that the onMessageDelivered and onMessageArrived functions have msg as argument, but I wrote messagein the function body for some reason. That's what the "message is not defined" error meant, message is literally not defined. Anyway I fixed that and now it sends and receives messages without problems.
...
More detailed story: What was not trivial is how I figured it out.
I decided to get my hands dirty and opened the non-minified version of paho-mqtt.js. I looked for "Invalid error" and found where the error constant is defined, and two places where it's used in a catch block. In both catch blocks I noticed that there was a ternary operator checking if (error.hasOwnProperty("stack") == "undefined") but the true and false clauses were inverted, which is why I was getting "No Error Stack Available".
So I inverted the clauses, and indeed I got a stack trace in the console (maybe I should file a bug report to the Paho dev team when I can). The stack trace had my mqtt_client_on_message_delivered function right at the top, so I read it again and suddenly everything made sense. Then I felt stupid for wasting an afternoon on this.
I'm following the instructions in the documentation site, but I got stuck in the echo example, the websocket is created correctly and it's connected to the server but when I send anything to the server I'm not getting any response (In the example says I should see an alert window with the same message that I send into the socket but I don't, although I've changed the alert for a console.log but still), what I'm doing wrong?
In settings.py:
INSTALLED_APPS = {
...
'channels',
'myapp',
...
}
...
# Channels settings
CHANNEL_LAYERS = {
"default": {
"BACKEND": "asgiref.inmemory.ChannelLayer",
"ROUTING": "myapp.routing.channel_routing",
},
}
In routing.py:
from channels.routing import route
from myapp.consumers import *
channel_routing = [
route("websocket.receive", ws_receive),
]
In consumers.py:
def ws_receive(message):
# ASGI WebSocket packet-received and send-packet message types
# both have a "text" key for their textual data.
message.reply_channel.send({
"text": message.content['text'],
})
In asgi.py
import os
from channels.asgi import get_channel_layer
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
channel_layer = get_channel_layer()
Then I run: python manage.py runserver, and in my browser I go to the server url and in the console I put the following:
socket = new WebSocket("ws://" + window.location.host + "/chat/");
socket.onmessage = function(e) {
alert(e.data);
}
socket.onopen = function() {
socket.send("hello world");
}
Again, at this point I should see an alert window (or the console.log message) but I get nothing.
The requests that I made have a status of pending (Although I read here and the first comment says it's normal)
And the server output looks like this:
Every time that I've tried to send something through the websocket in the browser, the server just print CONNECT but no log from the js console is showing.
Edit: I've tested websockets in my browser against echo.websocket.org and I got the answer as expected:
I changed to an older version of twisted and it fixed it. Hth
So, I have a node server, running expressjs io (uses socket.io), and I'm building a grid map that tracks coordinates in a database.
Only, I've run into a peculiar issue in that my sockets only listen sometimes.
At first there was no error message, and only by chance I let the page run and I got this error.
Uncaught TypeError: Cannot call method '0' of undefined UkPS99A_w96Ae0K570Nt?t=1395276358213&i=0:1
When I click on the file UkPS99A_w96Ae0K570Nt?t=1395276358213&i=0:1 I get this code:
io.j[0]("8::");
If I refresh the page, every few times it will suddenly work find for about 10 tile clicks, and then it stops working. My database is updating properly until the sockets basically die out.
Here is where I send the coordinates in my map:
io.emit("move", {x:this.x,y:this.y});
Server listening:
app.io.route('move', function(req) {
con.getConnection(function(err){
if (err) console.log("Get Connection Error.. "+err);
//removed query because redundant
req.io.emit("talk", {x:req.data.x,y:req.data.y});
});
});
and my socket script:
io.on("talk",function(data) {
console.log(data.x,data.y);
});
My script includes are at the bottom of the page in this order:
<script src="socket.io/socket.io.js"></script>
<script>io = io.connect();</script> <!-- open the socket so the other scripts can use it -->
<script src="../js/sock.js"></script>
<script src="../js/map.js"></script>
Is there something I'm doing wrong to that the socket seems to lose connection and throw some sort of error?
Update: I left the server running longer and a couple more error messages popped up in my console:
Uncaught TypeError: Cannot call method 'close' of null socket.io.js:1967
Uncaught TypeError: Cannot call method 'close' of null socket.io.js:1967
Uncaught TypeError: Cannot call method 'onClose' of null
More update: altered the connection line and added the proper CORS to my server.js
io = io.connect('http://sourceundead.com', {resource : 'socket.io'});
Still the same issue.
You seem to have a connection attrition as you never release them to the pool.
Assuming con is the (bad) name of your pool, instead of
app.io.route('move', function(req) {
con.getConnection(function(err){
if (err) console.log("Get Connection Error.. "+err);
//removed query because redundant
req.io.emit("talk", {x:req.data.x,y:req.data.y});
});
});
you should have something like
app.io.route('move', function(req) {
con.getConnection(function(err, connection){
if (err) console.log("Get Connection Error.. "+err);
//removed query because redundant
req.io.emit("talk", {x:req.data.x,y:req.data.y});
connection.release();
});
});
Be careful that using connections must be done with care to ensure they're always released, and it's a little tedious to do especially when handling errors as soon as you have a few queries to do when doing a task.
At some point you might want to use promises to make that easier. Here's a blog post about using bound promises to ease database querying in node.js.
I am trying to setup SignalR at my ASP.NET MVC site and a Javascript client.
This is my client:
#section scripts{
<script src="~/Scripts/jquery.signalR-2.0.2.min.js"></script>
<script type="text/javascript">
$(function () {
var connection = $.connection('/MY_ENDPOINT');
connection.received(function (data) {
$('#chatArea').append('>>' + data + "\r\n");
});
connection.start().done(function () {
$("#send").click(function () {
connection.send($('#msg').val());
$("#msg").val("");
});
});
connection.error(function (e) {
console.log(e);
});
});
</script>
}
Of course, I have the corresponding HTML elements chatArea and msg. In server, here is what I did:
Installed SignalR (latest version currently, 2.0.2) through NuGet.
Added app.MapSignalR("MY_ENDPOINT", new Microsoft.AspNet.SignalR.HubConfiguration()); in startup configuration, made sure it is called before registering auth methods.
I've subclassed PersistentConnection and overridden OnConnected and OnReceived methods.
However, when I run my app and navigate to the page, I can see that my endpoint's negotiate and connect methods are called, they both return OK (HTTP 200). I try to send anything using the webpage by clicking the "send" button, and at the server side I'm getting this error:
A first chance exception of type 'Newtonsoft.Json.JsonReaderException'
occurred in Newtonsoft.Json.dll
Additional information: Unexpected character encountered while
parsing value: a. Path '', line 0, position 0.
What could be the cause of this error?
UPDATE: I also have an iOS app with the SignalR-ObjC framework, and I can connect. However, when I try to send any data over it, I'm getting:
2014-03-06 19:39:39.853 Tanisalim[54987:70b] Websocket error: Error Domain=AFNetworkingErrorDomain Code=-1011 "Request failed: internal server error (500)" UserInfo=0xade84e0 {NSErrorFailingURLKey=http://10.211.55.3/api/socket/send?transport=longPolling&connectionData=(null)&connectionToken=xybYQ8ItTN0IWUbyrosuHy%2F3jN0krIyHLO6b6Gq8VdC3orwRRGkVSIgtYkNQINVLhRMW77cX%2BU2LiHxoe0eDE3ZumT7JrObJcQ%2FXyHiP25%2BQy%2BZizHEHbsPyBBomERoI, NSLocalizedDescription=Request failed: internal server error (500), NSUnderlyingError=0xade1290 "Request failed: unacceptable content-type: text/html"
Still, no server-side breakpoints are hit.
I followed the docs on the websocket-rails github wiki page, but couldn't overcome this difficulty, I get this error with chrome:
WebSocket connection to 'ws://0.0.0.0:3000/websocket' failed: Error during WebSocket handshake: Unexpected response code: 301
I installed the websocket-rails gem, generated the install, I set successfully config.middleware.delete Rack::Lock in development.rb; I'm using Rails 4.
I got in the view:
<script type="text/javascript">
var dispatcher = new WebSocketRails('0.0.0.0:3000/websocket');
</script>
I got in my chat_controller.rb:
class ChatController < WebsocketRails::BaseController
def initialize_session
puts "Session Initialized"
end
def user_connected
puts 'user connected'
end
end
in my events.rb:
WebsocketRails::EventMap.describe do
subscribe :client_connected, :to => ChatController, :with_method => :user_connected
end
As you can see, my goal is to display "Session Initialized", and "user connected", in my thin server console each time that someone goes on a page. Between, I run the server with bundle exec thin start, but I got a javascript error instead (websocket connection failed error 301).
Thanks to the members of the Websocket Rails IRC, I found out that in my route, I was appending the locale before every path, so it coudln't find it.
Check your routes.rb if someone hit that issue too !