I added a chat functionality in my existing RoR app with the websocket-rails (https://github.com/websocket-rails/websocket-rails) gem and I'm testing it in production mode on Heroku.
It works fine in localhost, but when I sent it to Heroku it is not receiving any further messages from the Server after the connection.
The connection works:
var WEBSOCKET_URL = 'myapponheroku.herokuapp.com/websocket'
var dispatcher = new WebSocketRails(WEBSOCKET_URL);
dispatcher.on_open = function(data) {
console.log('Connection has been established: ', data);
};
And I see the feedback message.
But the first task is to ask the server for active rooms in my chat. I noticed nothing is returning. I put some feedback messages in the server's action that should do the first tasks and none of them are reached. The feedback I implemented is a simple pair of functions that just returns a object and prints it to the console:
Javascript
dispatcher.bind('feedback',function(data){
console.log(data);
});
Ruby
def feedback data
send_message :feedback, {data: data}
end
It is never triggered. Any ideas? Is the a special configuration I must do on Heroku to allow it to work?
#update
Same error on my live server hosted on AWS.
Connection is established, but nothing is returned from server to client.
#update2
I wrote some code so the app would write some files when connection is established and when it asks for open rooms, right at the beginning, and the files were not created. The actions are not even being called.
Related
Background and Setup
I have a Google Cloud Platform (GCP) Pub/Sub topic called "test", for which I've published a few messages from the GCP Cloud Console. I'm using a Ruby on Rails app to subscribe to this topic. From the Receiving Messages section in their OVERVIEW.md documentation, I've placed that code snippet (reproduced here with brevity) in an initializer file config/initializers/pubsub.rb
require "google/cloud/pubsub"
pubsub = Google::Cloud::PubSub.new
sub = pubsub.subscription "test"
subscriber = sub.listen threads: { callback: 16 } do |received_message|
puts "Data: #{received_message.message.data}, published at #{received_message.message.published_at}"
received_message.acknowledge!
end
subscriber.start
sleep
To test that the app can receive messages, I start Rails Console and confirm that the message has arrived. Eureka!
Data: test message I typed from GCP Cloud Console, published at 2021-04-30 16:36:42 -0400
The Problem
Rails Console cannot receive any input. By starting the subscription listener in an initializer, I've effectively rendered Rails Console inoperable.
How can I start the subscription listener in the app without breaking the rest of the app (what is the Rails way for this scenario)?
I've recently deployed a Rails app, and have heard back from a few users that it doesn't work in their work environments. It's clear that Websockets are blocked for them.
I've hunted through the Rails documentation on this but can't find any information on how to go about detecting if this has happened. My best guess would be to send an AJAX request out for an ActionCable broadcast, and when that broadcast is not received after a certain timeout, to conclude that Websockets must be blocked.
Are there any easy answers here, perhaps already part of the Rails API, to determine Websocket connectivity?
I have a workaround that isn't great, but is better than anything else I've seen. Rails provides no interface, but you can get down to the native WebSocket and handle the error.
consumer.subscriptions.create("ChatChannel", { ... });
consumer.connection.webSocket.onerror = function () {
console.log('Websocket connection error!');
// Error handling goes here. Fallback to polling, perhaps.
};
ActionCable will keep trying to reconnect, and this only grabs the first failure, but that's enough to cover many cases.
There is a rejected handler you can use. This should fire when the subscription is rejected by the server.
The below coffeescript example is from the official rails docs.
App.cable.subscriptions.create "AppearanceChannel",
# Called when the subscription is ready for use on the server.
connected: ->
// Do something
# Called when the subscription is rejected by the server.
rejected: ->
// Do something
Whenever an action cable connection fails it writes to the browser console failed: WebSocket is closed before the connection is established
You can leverage this to know if there was a connection error:
def action_cable_connection_errored?
page.driver.browser.manage.logs.get(:browser)
.map(&:message)
.join
.match('failed: WebSocket is closed before the connection is established')
end
Im unable to connect to my Node server using Socket.io. I have been following these two tutorials http://www.appcoda.com/socket-io-chat-app/ and http://socket.io/get-started/chat/ but I cant seem to figure out where i'm going wrong. My goal is to connect my Node server to an ios app in Xcode. Here is the server file:
//require HTTP module/create server
var app = require ('http').createServer();
//Port Number
app.listen(3000)
//Run Server
var io = require('socket.io')(app);{
console.log('Listening on *:3000');
};
//Connection
io.on('connection', function(socket){
console.log('a user connected');
socket.on('disconnect', function(){
console.log('user disconnected');
});
});
When I run the server via terminal, i get Listening on *:3000 as the output
(According to the tutorial) I then import the Socket.io Source folder and create the SocketIOManager.swift file as well as edit my AppDelegate.swift file
According to both tutorials I'm suppose to read a user connected when I open the simulator and user disconnected when i close it. However i get nothing in terminal. And i'm not sure what this means because i'm not getting any errors in Xcode.
Also when I run the server and open a browser i get the following:
I'm not sure if the browser issue relates or not but im putting it out there. Im only trying trying to connect my server to the app. I am looking forward to the a user connected message because that will verify a connection. If there is another way to test for a connection kindly let me know. Frankly, if there is a more simplified way to connect my server to the app, that would be greatly appreciated. I am open to any additional questions and of course comments.
Thank you in advance!
EDIT
I have SocketIOManager.sharedInstance.establishConnection() in my viewcontroller as is but I still cannot establish a connection. Can anyone shed some light?
I'm trying to send an Apple push notification from a Go appengine site. I'm using the apns2 library as follows:
cert, err := certificate.FromPemFile(pemFile, "")
if err != nil {
log.Fatalf("cert error: %v", err)
}
client := apns2.NewClient(cert).Development()
n := &apns2.Notification{...}
if res, err := client.Push(n); err != nil { ... }
On a local development server, it works fine; but in production I'm seeing:
Post https://api.development.push.apple.com/3/device/995aa87050518ca346f7254f3484d7d5c731ee93c35e3c359db9ddf95d035003:
dial tcp: lookup api.development.push.apple.com on [::1]:53: dial udp [::1]:53: socket: operation not permitted
It looks like appengine expects you to use its own urlfetch library when sending outbound requests, so I tried setting the underlying HTTPClient to use that:
client.HTTPClient = urlfetch.Client(ctx)
However, the response from the Apple server is now
##?HTTP/2 client preface string missing or corrupt. Hex dump for received bytes: 504f5354202f332f6465766963652f393935616138373035
I believe the problem is that Apple push notifications require HTTP/2, but urlfetch only implements HTTP/1.1.
How do I solve this problem? Is there a way for an appengine app to send an HTTP/2 request?
This would require going through the App Engine Sockets API. The documentation states:
Libraries that can accept a net.Conn should work without modification.
You can get a net.Conn from the appengine/socket package and pass it to a lib that will accept one, but in the case of apns2 it doesn't allow you to do this. However another user has submitted a pull request to the apns2 project that adds a distinct GAEClient which can use App Engine sockets.
As of right now it looks like the commits still have not been pulled into the master branch, however you could still merge these updates manually into your own source tree as a workaround for now.
I dont know much about go appengine, but whatever it looks from the code, your client := apns2.NewClient(cert).Development() line seems to be defective, i think for production, you dont need development cert, you need to have distribution cert. So check that is there any option available for it. Also, is certificates from apple's dev site are generated by you or by go appengine. If you have manually created that, then you have to create 2 types of certificates, one for developement and one for distribution/production, and when app is running in production mode, you need to use that certificates.
so i'm building an iOS app and i've started building a REST API w/ nodejs, express, & mongodb. I'm currently adding instant messaging and notifications to my app so i've been reading up on websockets(socket.io). After tons of reading, I honestly cannot wrap my head around the concept and how to integrate into my API.
For example, I have this API route:
// create new message
app.post('/newmessage', function (req, res, next) {
if (!req.body.message ) {
res.json({success: false, msg: 'You must type a message.'});
console.log('message: ' + req.body.message);
} else {
var newMessage = new Message({
fromUser: ObjectID(req.params.id),
toUser: ObjectID(req.params.id),
message: String,
});
// save new message
newMessage.save(function(err) {
if (err) {
res.json({success: false, msg: 'message was unsuccessful.'});
} else {
res.json({success: true, msg: 'message sent!'});
console.log(newMessage.createdAt);
console.log(newMessage.updatedAt);
}
});
}
});
How would I integrate socket.io into this specific call? Would I create a Socket.js file and export from there? Backend isn't my thing at all, so I apologize if this is a poor question. Thanks!
The general architecture for using a webSocket or socket.io connection for instant messaging or server-push notifications is as follows:
Each client makes a webSocket or socket.io connection to the server.
The server is listening for those incoming connections and uses some sort of cookie on the initial connection to identify which user is connecting.
The server then holds those connections open for the duration of the user session and listens for incoming messages on them.
At any time, if the server wishes to send a notification to the client, it can find the connection belonging to the desired client and send a message on that connection.
The client will be listening for incoming messages and will receive that message and can then process it.
For instant messaging, a client would send a message to the server that essentially says "send this message to Bob" (where Bob is some user ID for some other user on the system). The server would receive that message from the other client and would then find Bob's connection and send the message to Bob on that connection.
I would recommend using socket.io as it offers a number of useful features on top of webSockets and there should be socket.io libraries for all platforms you would be using. The socket.io documentation includes a demo app that does chat which will give you some idea how things work with socket.io.