May 17

Rails 4, websockets , ActionCable , LiteCable and Anycable.

AnyCable description says:  

AnyCable allows you to use any WebSocket server (written in any language) as a replacement for your Ruby server (such as Faye, ActionCable, etc).
AnyCable uses ActionCable protocol, so you can use ActionCable JavaScript client without any monkey-patching.

That's what I needed. Since with the current configuration (Faye + PrivatePub) in the future under the load there would certainly be problems.

We had to consider other options. And this was the decision of AnyCable.

How it's works:




There are already two ready-made solutions for Rails 5 and for Sinatra. You can look here.

We use Rails 4, so we had to twist it a little. 

To do this, we take LiteCable, a websocket server written on Go anycable-go and link it all together.

In your app in bin directory create file with name 'anycable_rpc'.
This file contain start Anycable server:

#!/usr/bin/env ruby
# frozen_string_literal: true
require ::File.expand_path('../../config/environment', __FILE__)
Rails.application.eager_load!
Anycable::Server.start

Next in the initializers, we turn on LiteCable.

config/initializers/lite_cable_init.rb

# frozen_string_literal: true
require 'litecable'
require 'anycable'
require_relative '../../app/lite_cable_factory/connection.rb'

LiteCable.config.log_level = Logger::DEBUG

# Turn AnyCable compatibility mode
LiteCable.anycable!
Anycable.configure do |config|
  config.debug = true
  config.connection_factory = LiteCableFactory::Connection
  config.redis_url = ENV.fetch('REDIS_URL', 'redis://localhost:6379/5')
end

Here we configure the Any Cable server and show our Connection Factory.

app/lite_cable_factory/connection.rb

# frozen_string_literal: true
module LiteCableFactory
  class Connection < LiteCable::Connection::Base # :nodoc:
    identified_by :user, :user_id
    def connect
      @user = cookies["user"]
      @user_id = request.params["user_id"]
      reject_unauthorized_connection unless @user_id
      puts "User with ID: #{@user_id} connected"
    end
    def disconnect
      puts "#{@user} disconnected"
    end
  end
end

This is just an example of how we connect the user.
We also create channels subscribed to by users.

app/lite_cable_factory/channels/notifications_channel.rb

# frozen_string_literal: true
module LiteCable
  class NotificationsChannel < LiteCable::Channel::Base # :nodoc:
    identifier :notifications
    def subscribed
      reject unless params['user_id']
      stream_from "notifications_#{params['user_id']}"
    end
    def speak(data)
      LiteCable.broadcast "app_update_#{user_id}", message: data['message']
    end
  end
end

Run the application:

rails s
./bin/anycable_rpc
./bin/anycable-go -redis=redis://localhost:6379/5 -redis_channel=anycable -addr=localhost:3001 -log

-log - for logging to stdout
-addr - where websockets will be mount, ws://localhost:3001/cable

For another configuration options please visit anycable-go.

Если есть варианты лучше, чем это пожалуйста поделитесь в комментариях.


Share:

Comments

comments powered by HyperComments
Comment