From 6128621ce6c8b8de14afe0b5ce93c9b169003b54 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 15 Oct 2012 21:09:57 -0500 Subject: [PATCH] * VRFS-19 - jam-ruby looks to have client messaging integrated, but need to see if it works when used in jam-web --- Gemfile | 1 + lib/jam_ruby.rb | 1 + lib/jam_ruby/connection_cleaner.rb | 6 +++ lib/jam_ruby/errors/permission_error.rb | 3 ++ lib/jam_ruby/mq_router.rb | 58 +++++++++++++++++++++++++ spec/jam_ruby/mq_router_spec.rb | 48 ++++++++++++++++++++ 6 files changed, 117 insertions(+) create mode 100644 lib/jam_ruby/connection_cleaner.rb create mode 100644 lib/jam_ruby/errors/permission_error.rb create mode 100644 lib/jam_ruby/mq_router.rb create mode 100644 spec/jam_ruby/mq_router_spec.rb diff --git a/Gemfile b/Gemfile index 061aa233e..0dd3006c9 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ gem 'activerecord', '3.2.7' gem 'uuidtools', '2.1.2' gem 'bcrypt-ruby', '3.0.1' gem 'ruby-protocol-buffers', '1.2.2' +gem 'eventmachine' group :test do gem 'jam_db', :path=> "#{workspace}/jam-db/target/ruby_package" diff --git a/lib/jam_ruby.rb b/lib/jam_ruby.rb index 94d641d67..ad68d6f08 100644 --- a/lib/jam_ruby.rb +++ b/lib/jam_ruby.rb @@ -2,6 +2,7 @@ require "pg" require "active_record" require "jampb" require 'uuidtools' +require "jam_ruby/mq_router" require "jam_ruby/version" require "jam_ruby/message_factory" require "jam_ruby/models/music_session_client" diff --git a/lib/jam_ruby/connection_cleaner.rb b/lib/jam_ruby/connection_cleaner.rb new file mode 100644 index 000000000..21522929d --- /dev/null +++ b/lib/jam_ruby/connection_cleaner.rb @@ -0,0 +1,6 @@ +class ConnectionCleaner + + def clean(connection, topic) + + end +end \ No newline at end of file diff --git a/lib/jam_ruby/errors/permission_error.rb b/lib/jam_ruby/errors/permission_error.rb new file mode 100644 index 000000000..80c4b1ff6 --- /dev/null +++ b/lib/jam_ruby/errors/permission_error.rb @@ -0,0 +1,3 @@ +class PermissionError < Exception + +end \ No newline at end of file diff --git a/lib/jam_ruby/mq_router.rb b/lib/jam_ruby/mq_router.rb new file mode 100644 index 000000000..b0f86b07d --- /dev/null +++ b/lib/jam_ruby/mq_router.rb @@ -0,0 +1,58 @@ +require 'eventmachine' + +class MQRouter + + # monostate pattern: + # You can initialize MQRouter instances as you want, + # but ultimately there are internal static state variables to represent global MQ exchange connections + + class << self + attr_accessor :client_exchange, :user_exchange + @@log = Logging.logger[MQRouter] + end + + def access_music_session(music_session, user) + + if music_session.nil? + raise ArgumentError, 'specified session not found' + end + + if !music_session.access? user + raise PermissionError, 'not allowed to join the specified session' + end + + return music_session + end + + # sends a message to a session on behalf of a user + # if this is originating in the context of a client, it should be specified as :client_id => "value" + # client_msg should be a well-structure message (jam-pb message) + def user_publish_to_session(music_session, user, client_msg, sender = {:client_id => "" }) + access_music_session(music_session, user) + + # gather up client_ids in the session + client_ids = music_session.music_session_clients.map {|client| client.client_id }.reject {|client_id| client_id == sender[:client_id] } + + publish_to_session(music_session.id, client_ids, client_msg.to_s, sender) + end + + + # sends a message to a session with no checking of permissions + # this method deliberately has no database interactivity/active_record objects + def publish_to_session(music_session_id, client_ids, client_msg, sender = {:client_id => "" }) + + EM.schedule do + sender_client_id = sender[:client_id] + + # iterate over each person in the session, and send a p2p message + client_ids.each do |client_id| + + @@log.debug "publishing to session:client #{music_session_id}:#{client_id} from client_id #{sender_client_id}" + # put it on the topic exchange for clients + self.class.client_exchange.publish(client_msg, :routing_key => "clients.#{music_session_id}") + end + end + end + + +end \ No newline at end of file diff --git a/spec/jam_ruby/mq_router_spec.rb b/spec/jam_ruby/mq_router_spec.rb new file mode 100644 index 000000000..76394847f --- /dev/null +++ b/spec/jam_ruby/mq_router_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +describe MQRouter do + + before do + @mq_router = MQRouter.new() + end + + it "user_publish_to_session works (but faking MQ)" do + + user1 = FactoryGirl.create(:user) # in the jam session + user2 = FactoryGirl.create(:user) # in the jam session + + music_session = FactoryGirl.create(:music_session, :creator => user1) + + music_session_member1 = FactoryGirl.create(:music_session_client, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1") + music_session_member2 = FactoryGirl.create(:music_session_client, :user => user2, :music_session => music_session, :ip_address => "2.2.2.2", :client_id => "2") + + @mq_router.should_receive(:publish_to_session).with(music_session.id, [music_session_member2.client_id], "a message", :client_id => music_session_member1.client_id) + + @mq_router.user_publish_to_session(music_session, user1, "a message" ,:client_id => music_session_member1.client_id) + end + + it "user_publish_to_session works (checking exchange callbacks)" do + + user1 = FactoryGirl.create(:user) # in the jam session + user2 = FactoryGirl.create(:user) # in the jam session + + music_session = FactoryGirl.create(:music_session, :creator => user1) + + music_session_member1 = FactoryGirl.create(:music_session_client, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1") + music_session_member2 = FactoryGirl.create(:music_session_client, :user => user2, :music_session => music_session, :ip_address => "2.2.2.2", :client_id => "2") + + EM.run do + + # mock up exchange + MQRouter.client_exchange = double("client_exchange") + + MQRouter.client_exchange.should_receive(:publish).with("a message", :routing_key => "clients.#{music_session.id}") + + @mq_router.user_publish_to_session(music_session, user1, "a message", :client_id => music_session_member1.client_id) + + EM.stop + + end + end + +end