2013-02-06 13:12:36 +00:00
require 'aasm'
2012-10-01 21:27:32 +00:00
module JamRuby
class Connection < ActiveRecord :: Base
2014-08-19 01:41:44 +00:00
include HtmlSanitize
2014-04-30 20:29:10 +00:00
# client_types
TYPE_CLIENT = 'client'
TYPE_BROWSER = 'browser'
2014-05-16 19:39:37 +00:00
TYPE_LATENCY_TESTER = 'latency_tester'
2012-11-30 15:23:43 +00:00
attr_accessor :joining_session
2012-11-04 03:02:11 +00:00
2012-10-07 18:02:26 +00:00
self . primary_key = 'id'
2012-10-21 01:55:49 +00:00
2012-10-02 05:02:02 +00:00
belongs_to :user , :class_name = > " JamRuby::User "
2014-05-06 21:17:26 +00:00
belongs_to :music_session , :class_name = > " JamRuby::ActiveMusicSession " , foreign_key : :music_session_id
2014-05-16 19:39:37 +00:00
has_one :latency_tester , class_name : 'JamRuby::LatencyTester' , foreign_key : :client_id , primary_key : :client_id
2014-02-08 03:05:16 +00:00
has_many :tracks , :class_name = > " JamRuby::Track " , :inverse_of = > :connection , :foreign_key = > 'connection_id' , :dependent = > :delete_all
2014-10-03 18:36:51 +00:00
has_many :video_sources , :class_name = > " JamRuby::VideoSource " , :inverse_of = > :connection , :foreign_key = > 'connection_id' , :dependent = > :delete_all
2012-11-04 03:02:11 +00:00
2014-10-06 21:44:30 +00:00
validates :as_musician , :inclusion = > { :in = > [ true , false , nil ] }
2014-05-16 19:39:37 +00:00
validates :client_type , :inclusion = > { :in = > [ TYPE_CLIENT , TYPE_BROWSER , TYPE_LATENCY_TESTER ] }
2014-06-09 20:43:16 +00:00
validates_numericality_of :last_jam_audio_latency , greater_than : 0 , :allow_nil = > true
2012-11-30 15:23:43 +00:00
validate :can_join_music_session , :if = > :joining_session?
2014-05-16 19:39:37 +00:00
validate :user_or_latency_tester_present
2012-11-30 15:23:43 +00:00
after_save :require_at_least_one_track_when_in_session , :if = > :joining_session?
2013-11-03 13:10:21 +00:00
after_create :did_create
2014-04-08 17:15:49 +00:00
after_save :report_add_participant
2012-11-30 15:23:43 +00:00
2013-02-11 06:02:25 +00:00
include AASM
IDLE_STATE = :idle
2013-02-06 13:12:36 +00:00
CONNECT_STATE = :connected
2013-02-11 06:02:25 +00:00
STALE_STATE = :stale
EXPIRED_STATE = :expired
2013-02-06 13:12:36 +00:00
aasm do
2013-02-11 06:02:25 +00:00
state IDLE_STATE , :initial = > true
2013-02-06 13:12:36 +00:00
state CONNECT_STATE
2013-02-11 06:02:25 +00:00
state STALE_STATE
state EXPIRED_STATE
2013-02-06 13:12:36 +00:00
event :connect do
2013-02-11 06:02:25 +00:00
transitions :from = > IDLE_STATE , :to = > CONNECT_STATE
transitions :from = > STALE_STATE , :to = > CONNECT_STATE
2013-02-06 13:12:36 +00:00
end
2013-02-11 06:02:25 +00:00
event :stale do
transitions :from = > CONNECT_STATE , :to = > STALE_STATE
transitions :from = > IDLE_STATE , :to = > STALE_STATE
2013-02-06 13:12:36 +00:00
end
event :expire , :after = > :did_expire do
2013-02-11 06:02:25 +00:00
transitions :from = > CONNECT_STATE , :to = > EXPIRED_STATE
transitions :from = > STALE_STATE , :to = > EXPIRED_STATE
transitions :from = > IDLE_STATE , :to = > EXPIRED_STATE
2013-02-06 13:12:36 +00:00
end
end
def state_message
case self . aasm_state . to_sym
when CONNECT_STATE
'Connected'
2013-02-11 06:02:25 +00:00
when STALE_STATE
'Stale'
2013-02-06 13:12:36 +00:00
else
'Idle'
end
end
2014-09-13 03:30:51 +00:00
def in_session?
! music_session_id . nil?
end
def in_scoring_timeout?
scoring_timeout > Time . now
end
2013-02-06 13:12:36 +00:00
def did_expire
self . destroy
end
2012-11-30 15:23:43 +00:00
def joining_session?
2014-03-03 22:13:23 +00:00
joining_session
2012-11-30 15:23:43 +00:00
end
def can_join_music_session
2014-05-01 03:01:43 +00:00
# puts "can_join_music_session: #{music_session_id} was #{music_session_id_was}" if music_session_id_changed?
if music_session_id_changed? and ! ( music_session_id_was . nil? or music_session_id_was . blank? )
errors . add ( :music_session , ValidationMessages :: CANT_JOIN_MULTIPLE_SESSIONS )
return false
end
2012-11-30 15:23:43 +00:00
if music_session . nil?
2013-11-03 20:55:55 +00:00
errors . add ( :music_session , ValidationMessages :: MUSIC_SESSION_MUST_BE_SPECIFIED )
2012-11-30 15:23:43 +00:00
return false
end
if as_musician
unless self . user . musician
2013-11-16 04:35:40 +00:00
errors . add ( :as_musician , ValidationMessages :: FAN_CAN_NOT_JOIN_AS_MUSICIAN )
2012-11-30 15:23:43 +00:00
return false
end
if music_session . musician_access
if music_session . approval_required
unless music_session . creator == user || music_session . invited_musicians . exists? ( user )
2013-11-03 20:55:55 +00:00
errors . add ( :approval_required , ValidationMessages :: INVITE_REQUIRED )
2012-11-30 15:23:43 +00:00
return false
end
end
else
unless music_session . creator == user || music_session . invited_musicians . exists? ( user )
2013-11-03 20:55:55 +00:00
errors . add ( :musician_access , ValidationMessages :: INVITE_REQUIRED )
2012-11-30 15:23:43 +00:00
return false
end
end
else
unless self . music_session . fan_access
# it's someone joining as a fan, and the only way a fan can join is if fan_access is true
2013-11-03 20:55:55 +00:00
errors . add ( :fan_access , ValidationMessages :: FANS_CAN_NOT_JOIN )
2012-11-30 15:23:43 +00:00
return false
end
end
2013-11-03 20:55:55 +00:00
if music_session . is_recording?
errors . add ( :music_session , ValidationMessages :: CANT_JOIN_RECORDING_SESSION )
end
2014-02-24 01:46:38 +00:00
2014-02-25 04:25:22 +00:00
# unless user.admin?
# num_sessions = Connection.where(:user_id => user_id)
# .where(["(music_session_id IS NOT NULL) AND (aasm_state != ?)",EXPIRED_STATE.to_s])
# .count
# if 0 < num_sessions
# errors.add(:music_session, ValidationMessages::CANT_JOIN_MULTIPLE_SESSIONS)
# return false;
# end
# end
2014-02-24 01:46:38 +00:00
2012-11-30 15:23:43 +00:00
return true
end
2012-10-02 05:02:02 +00:00
2012-10-21 01:55:49 +00:00
# decides if a given user can access this client with p2p messaging
# the answer is yes if the user is in the same music session
def access_p2p? ( user )
return self . music_session . users . exists? ( user )
end
2012-11-30 15:23:43 +00:00
2013-11-03 13:10:21 +00:00
def did_create
2014-05-17 19:55:26 +00:00
# self.user.update_lat_lng(self.ip_address) if self.user && self.ip_address
2013-11-03 13:10:21 +00:00
end
2014-03-09 13:38:46 +00:00
def report_add_participant
if self . music_session_id_changed? &&
self . music_session . present? &&
self . connected? &&
self . as_musician? &&
0 < ( count = self . music_session . connected_participant_count )
GoogleAnalyticsEvent . report_session_participant ( count )
end
true
end
2014-10-06 22:02:10 +00:00
def join_the_session ( music_session , as_musician , tracks , user , audio_latency , videos = nil )
2014-05-01 03:01:43 +00:00
self . music_session_id = music_session . id
2014-04-29 03:38:30 +00:00
self . as_musician = as_musician
self . joining_session = true
self . joined_session_at = Time . now
2014-05-01 03:01:43 +00:00
associate_tracks ( tracks ) unless tracks . nil?
2014-10-06 21:17:46 +00:00
associate_videos ( videos ) unless videos . nil?
2014-05-01 03:01:43 +00:00
self . save
2014-05-09 00:44:52 +00:00
# if user joins the session as a musician, update their addr and location
if as_musician
2014-07-22 19:36:45 +00:00
user . update_addr_loc ( self , User :: JAM_REASON_JOIN )
2014-08-01 01:16:38 +00:00
user . update_audio_latency ( self , audio_latency ) if audio_latency # try not to let a previously recorded value get nil'ed
2014-05-09 00:44:52 +00:00
end
2014-04-29 03:38:30 +00:00
end
2014-05-01 03:01:43 +00:00
def associate_tracks ( tracks )
unless tracks . nil?
self . tracks . clear ( )
tracks . each do | track |
t = Track . new
t . instrument = Instrument . find ( track [ " instrument_id " ] )
t . connection = self
t . sound = track [ " sound " ]
t . client_track_id = track [ " client_track_id " ]
t . save # todo what if it fails?
self . tracks << t
end
end
end
2014-10-06 21:17:46 +00:00
def associate_videos ( videos )
unless videos . nil?
2014-10-06 22:02:10 +00:00
self . video_sources . clear ( )
2014-10-06 21:17:46 +00:00
videos . each do | video |
v = VideoSource . new
v . connection = self
v . client_video_source_id = video [ " client_video_source_id " ]
v . save # todo what if it fails?
2014-10-06 22:02:10 +00:00
self . video_sources << v
2014-10-06 21:17:46 +00:00
end
end
end
2014-07-20 02:11:16 +00:00
def self . update_locidispids ( use_copied = true )
# using addr, we can rebuild locidispid
# this will set a connections's _locidispid = 0 if there are no geoiplocations/blocks that match their IP address, or if there are no JamIsps that match the IP address
# otherwise, locidispid will be updated to the correct new value.
# updates all connections's locidispids
table_suffix = use_copied ? '_copied' : ''
Connection . connection . execute ( " UPDATE connections SET locidispid = COALESCE((SELECT geolocs.locid as geolocid FROM geoipblocks #{ table_suffix } as geoblocks INNER JOIN geoiplocations #{ table_suffix } as geolocs ON geoblocks.locid = geolocs.locid WHERE geoblocks.geom && ST_MakePoint(addr, 0) AND addr BETWEEN geoblocks.beginip AND geoblocks.endip LIMIT 1) * 1000000::bigint +(SELECT coid FROM jamisp #{ table_suffix } as jisp WHERE geom && ST_MakePoint(addr, 0) AND addr BETWEEN beginip AND endip LIMIT 1), 0) " ) . check
end
def self . after_maxmind_import
update_locidispids
end
2012-11-04 03:02:11 +00:00
private
2014-04-29 03:38:30 +00:00
2012-11-04 03:02:11 +00:00
def require_at_least_one_track_when_in_session
2012-12-15 07:11:04 +00:00
if tracks . count == 0
2014-03-06 17:56:15 +00:00
errors . add ( :tracks , ValidationMessages :: SELECT_AT_LEAST_ONE )
2012-11-04 03:02:11 +00:00
end
end
2014-05-16 19:39:37 +00:00
def user_or_latency_tester_present
if user . nil? && client_type != TYPE_LATENCY_TESTER
2014-05-19 13:46:03 +00:00
puts client_type
2014-05-16 19:39:37 +00:00
errors . add ( :connection , ValidationMessages :: USER_OR_LATENCY_TESTER_PRESENT )
end
end
2012-10-01 21:27:32 +00:00
end
2013-02-06 13:12:36 +00:00
end