# The channel is the connection between the front end and the backend. require 'json' require 'volt/reactive/reactive_accessors' require 'volt/reactive/eventable' module Volt class Channel include ReactiveAccessors include Eventable reactive_accessor :connected, :status, :error, :reconnect_interval, :retry_count, :reconnect_in def initialize @socket = nil self.status = :opening self.connected = false self.error = nil self.retry_count = 0 @queue = [] connect! end def connected? connected end def connect! ` this.socket = new SockJS('/channel'); this.socket.onopen = function() { self.$opened(); }; this.socket.onmessage = function(message) { self['$message_received'](message.data); }; this.socket.onclose = function(error) { self.$closed(error); }; ` end def opened self.status = :open self.connected = true self.reconnect_interval = nil self.retry_count = 0 @queue.each do |message| send_message(message) end end def closed(error) self.status = :closed self.connected = false self.error = `error.reason` reconnect! end def reconnect! self.status = :reconnecting self.reconnect_interval ||= 0 self.reconnect_interval += (1000 + rand(5000)) self.retry_count += 1 interval = self.reconnect_interval self.reconnect_in = interval reconnect_tick end def message_received(message) message = JSON.parse(message) trigger!('message', *message) end def send_message(message) if status != :open @queue << message else # TODO: Temp: wrap message in an array, so we're sure its valid JSON message = JSON.dump([message]) ` this.socket.send(message); ` end end def close! self.status = :closed ` this.socket.close(); ` end private def reconnect_tick if reconnect_in >= 1000 self.reconnect_in -= 1000 ` setTimeout(function() { self['$reconnect_tick'](); }, 1000); ` else connect! end end end end