diff --git a/pb/src/client_container.proto b/pb/src/client_container.proto index 0169de05e..9e16de1f4 100644 --- a/pb/src/client_container.proto +++ b/pb/src/client_container.proto @@ -42,6 +42,7 @@ message ClientMessage { RECORDING_STARTED = 210; RECORDING_ENDED = 215; RECORDING_MASTER_MIX_COMPLETE = 220; + DOWNLOAD_AVAILABLE = 221; // band notifications BAND_INVITATION = 225; @@ -109,6 +110,7 @@ message ClientMessage { optional RecordingStarted recording_started = 210; optional RecordingEnded recording_ended = 215; optional RecordingMasterMixComplete recording_master_mix_complete = 220; + optional DownloadAvailable download_available = 221; // band notifications optional BandInvitation band_invitation = 225; @@ -330,6 +332,10 @@ message RecordingMasterMixComplete { optional string created_at = 4; } +message DownloadAvailable { + +} + message BandInvitation { optional string band_invitation_id = 1; optional string band_id = 2; diff --git a/ruby/lib/jam_ruby/message_factory.rb b/ruby/lib/jam_ruby/message_factory.rb index 7bdcb0881..24b8ddcff 100644 --- a/ruby/lib/jam_ruby/message_factory.rb +++ b/ruby/lib/jam_ruby/message_factory.rb @@ -70,6 +70,16 @@ module JamRuby ) end + def download_available + download_available = Jampb::DownloadAvailable.new + + return Jampb::ClientMessage.new( + :type => ClientMessage::Type::DOWNLOAD_AVAILABLE, + :route_to => CLIENT_TARGET, + :download_available => download_available + ) + end + # create a music session login message def login_music_session(music_session) login_music_session = Jampb::LoginMusicSession.new(:music_session => music_session) diff --git a/ruby/lib/jam_ruby/models/notification.rb b/ruby/lib/jam_ruby/models/notification.rb index 220b9bfd9..127b761ac 100644 --- a/ruby/lib/jam_ruby/models/notification.rb +++ b/ruby/lib/jam_ruby/models/notification.rb @@ -740,6 +740,13 @@ module JamRuby @@mq_router.server_publish_to_session(music_session, msg, sender = {:client_id => client_id}) end + + + def send_download_available(user_id) + msg = @@message_factory.download_available + + @@mq_router.publish_to_user(user_id, msg) + end end end end \ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/recorded_track_observer.rb b/ruby/lib/jam_ruby/models/recorded_track_observer.rb index c8392f4cb..8ad806704 100644 --- a/ruby/lib/jam_ruby/models/recorded_track_observer.rb +++ b/ruby/lib/jam_ruby/models/recorded_track_observer.rb @@ -5,6 +5,8 @@ module JamRuby observe JamRuby::RecordedTrack def before_validation(recorded_track) + + # if we see that a part was just uploaded entirely, validate that we can find the part that was just uploaded if recorded_track.is_part_uploading_was && !recorded_track.is_part_uploading begin aws_part = recorded_track.s3_manager.multiple_upload_find_part(recorded_track.url, recorded_track.upload_id, recorded_track.next_part_to_upload - 1) @@ -22,10 +24,13 @@ module JamRuby end - # if we detect that this just became fully uploaded + # if we detect that this just became fully uploaded -- if so, tell s3 to put the parts together if !recorded_track.fully_uploaded_was && recorded_track.fully_uploaded + + multipart_success = false begin recorded_track.s3_manager.multipart_upload_complete(recorded_track.url, recorded_track.upload_id) + multipart_success = true rescue SocketError => e raise # this should cause a 500 error, which is what we want. The client will retry later. rescue Exception => e @@ -34,6 +39,11 @@ module JamRuby recorded_track.errors.add(:upload_id, ValidationMessages::BAD_UPLOAD) end + # tell all users that a download is available, except for the user who just uploaded + recorded_track.recording.users.each do |user| + Notification.send_download_available(recorded_track.user_id) unless user == recorded_track.user + end + end end @@ -41,6 +51,7 @@ module JamRuby end + # here we tick upload failure counts, or revert the state of the model, as needed def after_rollback(recorded_track) # if fully uploaded, don't increment failures if recorded_track.fully_uploaded diff --git a/web/app/assets/javascripts/AAB_message_factory.js b/web/app/assets/javascripts/AAB_message_factory.js index e45d11c86..b6820a8b1 100644 --- a/web/app/assets/javascripts/AAB_message_factory.js +++ b/web/app/assets/javascripts/AAB_message_factory.js @@ -42,6 +42,7 @@ RECORDING_STARTED : "RECORDING_STARTED", RECORDING_ENDED : "RECORDING_ENDED", RECORDING_MASTER_MIX_COMPLETE : "RECORDING_MASTER_MIX_COMPLETE", + DOWNLOAD_AVAILABLE : "DOWNLOAD_AVAILABLE", // band notifications BAND_INVITATION : "BAND_INVITATION", diff --git a/web/app/assets/javascripts/fakeJamClient.js b/web/app/assets/javascripts/fakeJamClient.js index b48d10242..96ee3781c 100644 --- a/web/app/assets/javascripts/fakeJamClient.js +++ b/web/app/assets/javascripts/fakeJamClient.js @@ -569,6 +569,7 @@ return {success: true} } function CloseRecording() {} + function OnDownloadAvailable() {} // Javascript Bridge seems to camel-case @@ -700,6 +701,7 @@ this.GetLocalRecordingState = GetLocalRecordingState; this.OpenRecording = OpenRecording; this.CloseRecording = CloseRecording; + this.OnDownloadAvailable = OnDownloadAvailable; // fake calls; not a part of the actual jam client this.RegisterP2PMessageCallbacks = RegisterP2PMessageCallbacks; diff --git a/web/app/assets/javascripts/jamkazam.js b/web/app/assets/javascripts/jamkazam.js index dd5fef42b..d9ec02fba 100644 --- a/web/app/assets/javascripts/jamkazam.js +++ b/web/app/assets/javascripts/jamkazam.js @@ -130,6 +130,13 @@ } } + /** + * This occurs when a new download from a recording has become available + */ + function downloadAvailable() { + context.jamClient.OnDownloadAvailable(); + } + /** * Called whenever the websocket closes; this gives us a chance to cleanup things that should be stopped/cleared * @param in_error did the socket close abnormally? @@ -172,6 +179,12 @@ context.JK.JamServer.registerMessageCallback(context.JK.MessageType.SERVER_BAD_STATE_RECOVERED, serverBadStateRecovered); } + function registerDownloadAvailable() { + logger.debug("register for download_available"); + context.JK.JamServer.registerMessageCallback(context.JK.MessageType.DOWNLOAD_AVAILABLE, downloadAvailable); + } + + function registerSocketClosed() { logger.debug("register for socket closed"); context.JK.JamServer.registerOnSocketClosed(socketClosed); @@ -346,6 +359,7 @@ registerBadStateRecovered(); registerBadStateError(); registerSocketClosed(); + registerDownloadAvailable(); context.JK.FaderHelpers.initialize(); context.window.onunload = this.unloadFunction; } diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 58b91c470..4245dbee8 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -590,7 +590,7 @@ var recordedTracks = sessionModel.recordedTracks(); - console.log("recorded tracks=%o local media=%o", recordedTracks, localMediaMixers); + console.log("recorded tracks=%o local_media=%o", recordedTracks, localMediaMixers); if(recordedTracks && localMediaMixers.length == 0) { // if we are the creator, then rather than raise an error, tell the server the recording is over. diff --git a/web/spec/features/recordings_spec.rb b/web/spec/features/recordings_spec.rb index 1d9748797..4a54e45e0 100644 --- a/web/spec/features/recordings_spec.rb +++ b/web/spec/features/recordings_spec.rb @@ -153,8 +153,8 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature claim_recording(name, desc) music_session = MusicSession.first() recording = music_session.recordings.first() - #puts recording.claimed_recordings.inspect claimed_recording = recording.claimed_recordings.where(:user_id => user.id).first + puts recording.claimed_recordings.inspect unless claimed_recording claimed_recording.name.should == name claimed_recording.description.should == desc claimed_recording.is_public.should be_true @@ -183,8 +183,8 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature claim_recording("my recording", '') music_session = MusicSession.first() recording = music_session.recordings.first() - #puts recording.claimed_recordings.inspect claimed_recording = recording.claimed_recordings.where(:user_id => user.id).first + puts recording.claimed_recordings.inspect unless claimed_recording claimed_recording.name.should == "my recording" claimed_recording.description.should == '' claimed_recording.is_public.should be_true