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 => nil}) access_music_session(music_session, user) client_ids = music_session.get_connection_ids(as_musician: true, exclude_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 from the server # no access check as with user_publish_to_session # client_msg should be a well-structure message (jam-pb message) def server_publish_to_session(music_session, client_msg, sender = {:client_id => nil}) # gather up client_ids in the session client_ids = music_session.get_connection_ids(as_musician: true, exclude_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 AND fans/listeners from the server # client_msg should be a well-structure message (jam-pb message) def server_publish_to_everyone_in_session(music_session, client_msg, sender = {:client_id => nil}) # gather up client_ids in the session client_ids = music_session.get_connection_ids(exclude_client_id: sender[:client_id]) publish_to_session(music_session.id, client_ids, client_msg.to_s, sender) end # sends a message to a client with no checking of permissions (RAW USAGE) # this method deliberately has no database interactivity/active_record objects def publish_to_client(client_id, client_msg, sender = {:client_id => ""}) EM.schedule do sender_client_id = sender[:client_id] @@log.debug "publishing to client:#{client_id} from client:#{sender_client_id}" # put it on the topic exchange for clients self.class.client_exchange.publish(client_msg, :routing_key => "client.#{client_id}") end end # sends a message to a session with no checking of permissions (RAW USAGE) # this method deliberately has no database interactivity/active_record objects def publish_to_session(music_session_id, client_ids, client_msg, sender = {:client_id => nil}) 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:#{music_session_id} / client:#{client_id} from client:#{sender_client_id}" # put it on the topic exchange for clients self.class.client_exchange.publish(client_msg, :routing_key => "client.#{client_id}") end end end # sends a message to a user with no checking of permissions (RAW USAGE) # this method deliberately has no database interactivity/active_record objects def publish_to_user(user_id, user_msg) @@log.warn "EM not running in publish_to_user" unless EM.reactor_running? EM.schedule do @@log.debug "publishing to user:#{user_id} from server" # put it on the topic exchange for users self.class.user_exchange.publish(user_msg, :routing_key => "user.#{user_id}") end end # sends a message to a list of friends with no checking of permissions (RAW USAGE) # this method deliberately has no database interactivity/active_record objects def publish_to_friends(friend_ids, user_msg, from_user_id) EM.schedule do friend_ids.each do |friend_id| @@log.debug "publishing to friend:#{friend_id} from user/band #{from_user_id}" # put it on the topic exchange for users self.class.user_exchange.publish(user_msg, :routing_key => "user.#{friend_id}") end end end end