I am trying to make a Chat web application based on Rails using "private_pub" gem which works perfectly on my localhost server. Now my site is hosted on DigitalOcean and i want to push chat code on the server to see how real-time chat app will work.
This is my private_pub.yml file
development:
server: "http://localhost:9292/faye"
secret_token: "secret"
test:
server: "http://localhost:9292/faye"
secret_token: "secret"
staging:
server: <%= ENV["FAYE_URL"] %>
secret_token:"secret_key"
signature_expiration: 3600 # one hour
production:
server: <%= ENV["FAYE_URL"] %>
secret_token: "secret_key"
signature_expiration: 3600 # one hour
My question is What should i have to do to make it work on any Linux server ( Here Digital Ocean for me). I am using Nginx server on DigitalOcean.
What should be the value for FAYE_URL in private_pub.yml file?
rackup private_pub.ru -s thin -E production
Do i have to run rack command on my server terminal? Or is there any other way to host Faye on a different server then?
I don't know Digital Ocean's servers.
I have worked with a Google Cloud Engine virtual machine with OS Ubuntu 14.04.
Here's how I configured my pub/sub app that uses Faye with a dns resolver in HTTPS on Nginx web server with Passenger.
Faye Server
I set up the Faye server, as a Rack application, to start automatically at boot through the 'Thin' web server.
Script to start/stop Thin with params: thin-configuration-file, faye-rackup-server-script.
/home/user/apps/myapp/config/thin.sh
#!/bin/sh
set -e
TIMEOUT=${TIMEOUT-60}
APP_ROOT=/home/user/apps/myapp
PID=$APP_ROOT/tmp/pids/thin.pid
CMD="cd $APP_ROOT; thin -C $APP_ROOT/config/thin.yml -R $APP_ROOT/faye.ru"
AS_USER=user
set -u
startme() {
run "$CMD start"
}
stopme() {
run "thin stop"
}
run () {
if [ "$(id -un)" = "$AS_USER" ]; then
eval $1
else
su -c "$1" - $AS_USER
fi
}
case "$1" in
start) startme ;;
stop) stopme ;;
restart) stopme; startme ;;
*) echo "usage: $0 start|stop|restart" >&2
exit 1
;
esac
so I set the execution permissions for the script thin.sh
chmod ugo+x /home/user/apps/myappconfig/thin.sh
-rwxr-xr-x 1 user user ... thin.sh*
then I defined the script thin.sh as a service
cd /etc/init.d
sudo ln -s /home/user/apps/myapp/config/thin.sh thin
lrwxrwxrwx 1 root root ... thin -> /home/user/apps/myapp/config/thin.sh*
and finally I configured the boot on startup
sudo update-rc.d thin defaults
I have defined the parameters necessary for the script thin.sh (as params in $CMD in config/thin.sh)
First the thin web server configuration file
/home/user/apps/myapp/config/thin.yml
chdir: "/home/user/apps/myapp"
environment: production
address: 127.0.0.1
port: 9292
timeout: 30
wait: 30
max_conns: 1024
log: /home/user/apps/myapp/log/thin.log
pid: /home/user/apps/myapp/tmp/pids/thin.pid
max_persistent_conns: 100
require: []
threadpool_size: 20
daemonize: true
ssl: true
ssl-key-file: "/etc/ssl/private/example_com.key"
ssl-cert-file: "/etc/ssl/certs/example_com.crt"
#ssl-disable-verify: true
and then the Faye server startup script (via rackup)
/home/user/apps/myapp/faye.ru
require 'eventmachine'
require 'rack'
require 'thin'
require 'faye'
# set FAYE_TOKEN you prefer for faye authentication
require File.expand_path('../config/initializers/faye_token.rb', __FILE__)
Faye::WebSocket.load_adapter('thin')
#define authentication extension
class ServerAuth
def incoming(message, callback)
if message['channel'] !~ %r{^/meta/}
if !message['ext'].nil?
if message['ext']['auth_token'] != FAYE_TOKEN
message['error'] = 'Invalid authentication token'
end
end
end
if message['channel'] =~ %r{/meta/subscribe}
...
end
callback.call(message)
end
end
faye_server = Faye::RackAdapter.new(:mount => '/faye', :timeout => 30)
faye_server.add_extension(ServerAuth.new)
run faye_server
at this point the automatic start of faye server is set.
At boot '/etc/init.d/thin' service start 'thin server' with config/thin.yml executnig rackup script 'faye.ru'.
Faye client
I parametrized the urls for faye client
/home/user/apps/myapp/config/initializers/urls.rb
FAYE_MOUNTPOINT_URL='https://example.com/faye'
FAYE_JSCLIENT_URL='https://example.com/faye/client.js'
I included faye client javascripts in
/home/user/apps/myapp/app/views/layouts/application.html.erb
so then they are charged when you access the app
<!DOCTYPE html>
<html lang="it">
<head>
<%= javascript_include_tag FAYE_JSCLIENT_URL %>
</head>
...
The Faye client is created when you access the page where there are your chat rooms (as channel).
The right place is
/home/user/apps/myapp/app/assets/javascript/application.js
...
var faye = null;
$(document).ready(function(){
// https
faye = new Faye.Client('<%= FAYE_MOUNTPOINT_URL %>');
faye.disable('autodisconnect');
// divs with '.subscribe' class contain channels name
$('.subscribe').each(function() {
// subscribe each channel
faye.subscribe('/'+$(this).text(), function (data) {
// here I process 'data' to refresh page with new content using jquery
// I'm using hidden div
// when I receive notification I clone hidden div, then I fill some fields and I exhibit the new cloned div
...
msg = $('#message_template').clone();
msg.html(data.message.content);
msg.css('visibility','visible');
});
});
});
Sending a new message from client to server Faye:
(creating a new Message model with a call remote: true (ajax))
called by create.js rensponse triggerd by controller_message#create as ajax response renderer
/home/user/apps/myapp/app/helpers/application_helper.rb
def broadcast(channel, <your_params>)
# prepare 'data' as json format
data = { your_key: your_params.as_json }
message = { channel: '/' + channel.name, data: data, ext: { auth_token: FAYE_TOKEN } }
# https
uri = URI.parse(FAYE_MOUNTPOINT_URL)
Net::HTTP.post_form(uri, message: message.to_json, use_ssl: true)
end
That's all
For a better comprehension, I enclose Nginx configuration file
worker_processes 1;
error_log logs/err.log debug;
events {
worker_connections 1024;
}
http {
upstream faye {
server unix:/tmp/faye.0.sock;
server unix:/tmp/faye.1.sock;
}
passenger_root /home/user/.rvm/gems/ruby-2.3.0/gems/passenger-5.1.11;
server {
listen 80;
server_name example.com;
return 301 https://example.com/$request_uri;
}
server {
listen 443 ssl default_server;
server_name example.com;
ssl_certificate /etc/ssl/certs/example_com.crt;
ssl_certificate_key /etc/ssl/private/example_com.key;
ssl on;
passenger_enabled on;
passenger_app_root /home/user/apps/myapp;
passenger_ruby /home/user/.rvm/gems/ruby-2.3.0/wrappers/ruby;
location / {
root /home/user/apps/myapp/public;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location /faye {
proxy_pass https://127.0.0.1:9292/faye;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
}
}