From 68479481cf3f395c41c9b5f9c20617e92303ff5c Mon Sep 17 00:00:00 2001 From: danielgrippi Date: Tue, 15 Mar 2011 18:20:16 -0700 Subject: [PATCH] made websockets far less dumb. don't render partials for people not connected. --- app/controllers/sockets_controller.rb | 1 + features/support/env.rb | 21 +--------------- lib/diaspora/web_socket.rb | 10 ++++++++ spec/controllers/sockets_controller_spec.rb | 21 +++++++++++----- spec/integration/receiving_spec.rb | 1 + spec/lib/diaspora/web_socket_spec.rb | 28 +++++++++++++++++++++ spec/support/fake_redis.rb | 3 +++ 7 files changed, 59 insertions(+), 26 deletions(-) diff --git a/app/controllers/sockets_controller.rb b/app/controllers/sockets_controller.rb index aa87ec320..705b70132 100644 --- a/app/controllers/sockets_controller.rb +++ b/app/controllers/sockets_controller.rb @@ -12,6 +12,7 @@ class SocketsController < ApplicationController end def outgoing(user, object, opts={}) + return unless Diaspora::WebSocket.is_connected?(user.id) @_request = ActionDispatch::Request.new({}) Diaspora::WebSocket.queue_to_user(user.id, action_hash(user, object, opts)) end diff --git a/features/support/env.rb b/features/support/env.rb index 86d2f253b..1257f607d 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -41,6 +41,7 @@ Cucumber::Rails::World.use_transactional_fixtures = false require File.join(File.dirname(__FILE__), "database_cleaner_patches") +require File.join(File.dirname(__FILE__), "..", "..", "spec", "support", "fake_redis") require File.join(File.dirname(__FILE__), "..", "..", "spec", "helper_methods") include HelperMethods @@ -57,26 +58,6 @@ module Resque end end -module Diaspora::WebSocket - def self.redis - FakeRedis.new - end -end - -class FakeRedis - def rpop(*args) - true - end - - def llen(*args) - true - end - - def lpush(*args) - true - end -end - Before('@localserver') do TestServerFixture.start_if_needed CapybaraSettings.instance.save diff --git a/lib/diaspora/web_socket.rb b/lib/diaspora/web_socket.rb index 9b8778bf4..1010c3c89 100644 --- a/lib/diaspora/web_socket.rb +++ b/lib/diaspora/web_socket.rb @@ -4,6 +4,9 @@ module Diaspora module WebSocket + + REDIS_CONNECTION_SET = 'ws-uids' + def self.redis @redis ||= Resque.redis end @@ -32,6 +35,8 @@ module Diaspora self.ensure_channel(uid) @channels[uid][0].subscribe{ |msg| ws.send msg } @channels[uid][1] += 1 + + redis.sadd(REDIS_CONNECTION_SET, uid) end def self.ensure_channel(uid) @@ -44,8 +49,13 @@ module Diaspora @channels[uid][1] -= 1 if @channels[uid][1] <= 0 @channels.delete(uid) + redis.srem(REDIS_CONNECTION_SET, uid) end end + + def self.is_connected?(uid) + redis.sismember(REDIS_CONNECTION_SET, uid) + end end module Socketable diff --git a/spec/controllers/sockets_controller_spec.rb b/spec/controllers/sockets_controller_spec.rb index b6878504e..1cb0fa4c1 100644 --- a/spec/controllers/sockets_controller_spec.rb +++ b/spec/controllers/sockets_controller_spec.rb @@ -15,15 +15,11 @@ describe SocketsController do before do @user = alice @controller = SocketsController.new + @aspect = @user.aspects.first + @message = @user.post :status_message, :text => "post through user for victory", :to => @aspect.id end describe 'actionhash' do - before do - @aspect = @user.aspects.first - @message = @user.post :status_message, :text => "post through user for victory", :to => @aspect.id - @fixture_name = File.dirname(__FILE__) + '/../fixtures/button.png' - end - it 'actionhashes posts' do json = @controller.action_hash(@user, @message) json.include?(@message.text).should be_true @@ -37,4 +33,17 @@ describe SocketsController do json.include?("html\":null").should be_true end end + describe '#outgoing' do + it 'calls queue_to_user' do + Diaspora::WebSocket.should_receive(:is_connected?).with(@user.id).and_return(true) + Diaspora::WebSocket.should_receive(:queue_to_user).with(@user.id, anything) + @controller.outgoing(@user, @message) + end + + it 'does not call queue_to_user if the user is not connected' do + Diaspora::WebSocket.should_receive(:is_connected?).with(@user.id).and_return(false) + Diaspora::WebSocket.should_not_receive(:queue_to_user) + @controller.outgoing(@user, @message) + end + end end diff --git a/spec/integration/receiving_spec.rb b/spec/integration/receiving_spec.rb index 0593b256d..e8be6b4ab 100644 --- a/spec/integration/receiving_spec.rb +++ b/spec/integration/receiving_spec.rb @@ -28,6 +28,7 @@ describe 'a user receives a post' do contact = @user1.contact_for(@user2.person) @user1.add_contact_to_aspect(contact, @user1.aspects.create(:name => "villains")) status = @user2.build_post(:status_message, :text => "Users do things", :to => @aspect2.id) + Diaspora::WebSocket.stub!(:is_connected?).and_return(true) Diaspora::WebSocket.should_receive(:queue_to_user).exactly(:once) zord = Postzord::Receiver.new(@user1, :object => status, :person => @user2.person) zord.receive_object diff --git a/spec/lib/diaspora/web_socket_spec.rb b/spec/lib/diaspora/web_socket_spec.rb index 2f4bb3604..551b874d0 100644 --- a/spec/lib/diaspora/web_socket_spec.rb +++ b/spec/lib/diaspora/web_socket_spec.rb @@ -21,6 +21,33 @@ describe Diaspora::WebSocket do Diaspora::WebSocket.queue_to_user("me", "Socket!") end end + + describe '.subscribe' do + it 'adds the uid to the uid redis set' do + Diaspora::WebSocket.stub!(:length) + Diaspora::WebSocket.initialize_channels + @mock_redis.should_receive(:sadd).with(Diaspora::WebSocket::REDIS_CONNECTION_SET, alice.id) + Diaspora::WebSocket.subscribe(alice.id, mock()) + end + end + + describe '.unsubscribe' do + it 'removes the uid to the uid redis set' do + Diaspora::WebSocket.stub!(:length) + Diaspora::WebSocket.initialize_channels + @mock_redis.stub!(:sadd) + Diaspora::WebSocket.subscribe(alice.id, mock()) + @mock_redis.should_receive(:srem).with(Diaspora::WebSocket::REDIS_CONNECTION_SET, alice.id) + Diaspora::WebSocket.unsubscribe(alice.id, mock()) + end + end + + describe '.is_connected?' do + it 'calls sismember' do + @mock_redis.should_receive(:sismember).with(Diaspora::WebSocket::REDIS_CONNECTION_SET, alice.id) + Diaspora::WebSocket.is_connected?(alice.id) + end + end end describe Diaspora::Socketable do @@ -32,6 +59,7 @@ describe Diaspora::Socketable do end it 'sockets to a user' do + Diaspora::WebSocket.should_receive(:is_connected?).with(@user.id).and_return(true) Diaspora::WebSocket.should_receive(:queue_to_user) @post.socket_to_user(@user, :aspect_ids => @aspect.id) end diff --git a/spec/support/fake_redis.rb b/spec/support/fake_redis.rb index 97dda9585..c180a8665 100644 --- a/spec/support/fake_redis.rb +++ b/spec/support/fake_redis.rb @@ -14,4 +14,7 @@ class FakeRedis def lpush(*args) true end + def sismember(*args) + false + end end