lib/pusher-client/socket.rb in pusher-client-0.2.1 vs lib/pusher-client/socket.rb in pusher-client-0.2.2

- old
+ new

@@ -1,43 +1,47 @@ require 'json' +require 'hmac-sha2' +require 'digest/md5' module PusherClient class Socket - + # Mimick the JavaScript client - CLIENT_ID = 'js' - VERSION = '1.7.1' + CLIENT_ID = 'pusher-ruby-client' + VERSION = '0.2.2' + PROTOCOL = '5' attr_accessor :encrypted, :secure attr_reader :path, :connected, :channels, :global_channel, :socket_id def initialize(application_key, options={}) - raise ArgumentError if (!application_key.is_a?(String) || application_key.size < 1) - @path = "/app/#{application_key}?client=#{CLIENT_ID}&version=#{VERSION}" + @path = "/app/#{application_key}?client=#{CLIENT_ID}&version=#{VERSION}&protocol=#{PROTOCOL}" @key = application_key + @secret = options[:secret] @socket_id = nil @channels = Channels.new @global_channel = Channel.new('pusher_global_channel') @global_channel.global = true @secure = false @connected = false @encrypted = options[:encrypted] || false bind('pusher:connection_established') do |data| + socket = JSON.parse(data) @connected = true - @socket_id = data['socket_id'] + @socket_id = socket['socket_id'] subscribe_all end bind('pusher:connection_disconnected') do |data| @channels.channels.each { |c| c.disconnect } end bind('pusher:error') do |data| - PusherClient.logger.fatal("Pusher : error : #{data.message}") + PusherClient.logger.fatal("Pusher : error : #{data.inspect}") end end def connect(async = false) if @encrypted || @secure @@ -46,11 +50,12 @@ url = "ws://#{HOST}:#{WS_PORT}#{@path}" end PusherClient.logger.debug("Pusher : connecting : #{url}") @connection_thread = Thread.new { - @connection = WebSocket.new(url) + options = {:ssl => @encrypted || @secure} + @connection = WebSocket.new(url, options) PusherClient.logger.debug "Websocket connected" loop do msg = @connection.receive[0] params = parser(msg) next if (params['socket_id'] && params['socket_id'] == self.socket_id) @@ -75,17 +80,16 @@ else PusherClient.logger.warn "Disconnect attempted... not connected" end end - def subscribe(channel_name) + def subscribe(channel_name, user_id = nil) + @user_data = {:user_id => user_id}.to_json unless user_id.nil? + channel = @channels << channel_name if @connected - send_event('pusher:subscribe', { - 'channel' => channel.name - }) - channel.acknowledge_subscription(nil) + authorize(channel, method(:authorize_callback)) end return channel end def unsubscribe(channel_name) @@ -110,16 +114,58 @@ @channels << channel_name end end def subscribe_all - @channels.channels.clone.each{ |k,v| + @channels.channels.clone.each{ |k,v| subscribe(k) } end - + + #auth for private and presence + def authorize(channel, callback) + if is_private_channel(channel.name) + auth_data = get_private_auth(channel) + elsif is_presence_channel(channel.name) + auth_data = get_presence_auth(channel) + channel_data = @user_data + end + # could both be nil if didn't require auth + callback.call(channel, auth_data, channel_data) + end + + def authorize_callback(channel, auth_data, channel_data) + send_event('pusher:subscribe', { + 'channel' => channel.name, + 'auth' => auth_data, + 'channel_data' => channel_data + }) + channel.acknowledge_subscription(nil) + end + + def is_private_channel(channel_name) + channel_name.match(/^private-/) + end + + def is_presence_channel(channel_name) + channel_name.match(/^presence-/) + end + + def get_private_auth(channel) + string_to_sign = @socket_id + ':' + channel.name + signature = HMAC::SHA256.hexdigest(@secret, string_to_sign) + return "#{@key}:#{signature}" + end + + def get_presence_auth(channel) + string_to_sign = @socket_id + ':' + channel.name + ':' + @user_data + signature = HMAC::SHA256.hexdigest(@secret, string_to_sign) + return "#{@key}:#{signature}" + end + + # For compatibility with JavaScript client API - alias :subscribeAll :subscribe_all + alias :subscribeAll :subscribe_all def send_event(event_name, data) payload = {'event' => event_name, 'data' => data}.to_json @connection.send(payload) PusherClient.logger.debug("Pusher : sending event : #{payload}")