From 4d8a7a9bc1e29681244db15a6cb283e7e4feeff7 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 11 Jan 2015 15:42:12 -0600 Subject: [PATCH] * wip --- ruby/lib/jam_ruby/models/jam_track_right.rb | 4 +- .../javascripts/download_jamtrack.js.coffee | 233 ++++++++++++++++-- web/app/assets/javascripts/utils.js | 4 + web/app/controllers/spikes_controller.rb | 2 + .../_download_jamtrack_templates.html.slim | 28 +++ 5 files changed, 249 insertions(+), 22 deletions(-) diff --git a/ruby/lib/jam_ruby/models/jam_track_right.rb b/ruby/lib/jam_ruby/models/jam_track_right.rb index affee58a5..3e82185ed 100644 --- a/ruby/lib/jam_ruby/models/jam_track_right.rb +++ b/ruby/lib/jam_ruby/models/jam_track_right.rb @@ -123,8 +123,6 @@ module JamRuby state = nil if signed state = 'SIGNED' - elsif error_count > 0 - state = 'ERROR' elsif signing_started_at if Time.now - signing_started_at > APP_CONFIG.signing_job_run_max_time state = 'SIGNING_TIMEOUT' @@ -137,6 +135,8 @@ module JamRuby else state = 'QUEUED' end + elsif error_count > 0 + state = 'ERROR' else state = 'QUIET' # needs to be poked to go build end diff --git a/web/app/assets/javascripts/download_jamtrack.js.coffee b/web/app/assets/javascripts/download_jamtrack.js.coffee index 937574403..f8605475e 100644 --- a/web/app/assets/javascripts/download_jamtrack.js.coffee +++ b/web/app/assets/javascripts/download_jamtrack.js.coffee @@ -9,46 +9,239 @@ context.JK ||= {}; # The JamTrack exists on the server, but not on disk, so we will download it (downloading state) # The JamTrack is on the disk, but does not yet have keys, so we will fetch them (keying) +context.JK.DownloadJamTracks = {} context.JK.DownloadJamTrack = class DownloadJamTrack - constructor: (@app) -> + constructor: (@app, jamTrackId, jamTrackRightId) -> @EVENTS = context.JK.EVENTS @rest = context.JK.Rest() - @jamTrackId = null + @logger = context.JK.logger + @jamTrackId = jamTrackId + @jamTrackRightId = jamTrackRightId + @attemptedEnqueue = false + @errorMessage = null + @transitionTimer = null + @downloadTimer = null + @trackDetail = null + @errorSupportMsg = "Press RETRY, or if you have already retried, please contact support@jamkazam.com." @states = { - synchronized: 'synchronized', - packaging: 'packaging', - downloading: 'downloading', - keying: 'keying', - initial: 'initial' + no_client: { name: 'no-client', show: @showNoClient }, + synchronized: { name: 'synchronized', show: @showSynchronized }, + packaging: { name: 'packaging', show: @showPackaging }, + downloading: { name: 'downloading', show: @showDownloading }, + keying: { name: 'keying', show: @showKeying }, + initial: { name: 'initial', show: @showInitial }, + errored: { name: 'errored', show: @showError } } @state = @states.initial - init: (jamTrackId) => - @jamTrackId = jamTrackId - @root = $($('#template-download-jamtrack').html()) + context.JK.DownloadJamTracks[@jamTrackId] = this + # after you've created the DownloadJamTrack widget, call synchronize which will begin ensuring that the jamtrack # is downloaded and ready to open - synchronize: () => + init: () => + @root = $($('#template-download-jamtrack').html()) + + # populate in template and visual transition functions + for state, data of @states + data.template = $("#template-download-jamtrack-state-#{data.name}") + + # check if we are in a browser or client + if !gon.isNativeClient + @states.no_client.show() + else + @states.initial.show() + this.synchronize() + @attemptedEnqueue = false + this.checkState() + + + showPackaging: () => + @logger.debug("showing #{@states.name}") + + showDownloading: () => + @logger.debug("showing #{@states.name}") + # while downloading, we don't run the transition timer, because the download API is guaranteed to call success, or failure, eventually + this.clearTransitionTimer() + context.jamClient.StartFileDownload(context.JK.makeAbsolute('/api/jamtracks/download/' + @jamTrackId), this.makeDownloadProgressCallback(), this.makeDownloadSuccessCallback(), this.makeDownloadFailureCallback(), true) + + showKeying: () => + @logger.debug("showing #{@states.name}") + this.clearTransitionTimer() + context.jamClient.requestJamTrackKeys() + this.expectKeyed() + + showInitial: () => + @logger.debug("showing #{@states.name}") + context.JK.SubscriptionUtils.subscribe('jam_track_right', @jamTrackRightId).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, this.onJamTrackRightEvent) + + showError: () => + @logger.debug("showing #{@states.name}") + clearTransitionTimer() + context.JK.SubscriptionUtils.unsubscribe('jam_track_right', @jamTrackRightId) + + showSynchronized: () => + @logger.debug("showing #{@states.name}") + clearTransitionTimer() + context.JK.SubscriptionUtils.unsubscribe('jam_track_right', @jamTrackRightId) + + showNoClient: () => + @logger.debug("showing #{@states.name}") + + downloadCheck: () => + @logger.debug "downloadcheck" + + # sets an interval timer for every 3 seconds, waiting for the status to change + expectKeyed: () => + + expectDownload: () => + unless @downloadTimer? + return + + # every 10 seconds, wake up and check the server and see if we missed a state transition + this.clearDownloadTimer() + @downloadTimer = setTimeout(this.downloadCheck, 10000) + + clearDownloadTimer: () => + if @downloadTimer? + clearTimeout(@downloadTimer) + @downloadTimer = null + + + transitionCheck: () => this.checkState() + # this should be called every time something changes statefully, to restart a 12 second timer to hit the server for update. + # if everything is moving snappily, we won't have to query the server much, because we are also getting subscription events + # about any changes to the status of the jam track. But, we could miss a message or there could be a path in the server where + # we don't get an event, so that's why, after 12 seconds, we'll still go to the server and check. + # exception: this should not be runngi + expectTransition: () => + unless @transitionTimer? + return + + # every 12 seconds, wake up and check the server and see if we missed a state transition + this.clearTransitionTimer() + @transitionTimer = setTimeout(this.transitionCheck, 12000) + + clearTransitionTimer: () => + if @transitionTimer? + clearTimeout(@transitionTimer) + @transitionTimer = null + transition: (newState) => - + if newState == @state + @logger.debug("DownloadJamTrack: ignoring state change #{@state}") + return + + @logger.debug("DownloadJamTrack: state change: #{@state} => #{newState}") + @state = newState + + @states[newState].show() checkState: () => - isPlayable = context.jamClient.JamTrackIsPlayable() + # check for the success state against the local state of the client... if it's playable, then we should be OK + @trackDetail = context.jamClient.JamTrackGetTrackDetail(@jamTrackId) - if isPlayable - this.transition(@states.synchronized) - else + switch @trackDetail.key_state + when 'pending' + this.transition(@states.keying) + when 'not authorized' + this.transition(@states.keying) + when 'ready' + this.transition(@states.synchronized) + when 'unknown' + @rest.getJamTrackRight({id: @jamTrackId}) + .done(this.processJamTrackRight) + .fail(this.processJamTrackRightFail) - @rest.getJamTrackRight({id: @jamTrackId}) - .done(this.processJamTrackRight) - .fail(@app.ajaxError) + processSigningState: (signingState) => + switch signingState + when 'QUIET' + if @attemptedEnqueue + # this means we've already tried to poke the server. something is wrong + @errorMessage = "The server has not begun building your JamTrack. #{@errorSupportMsg}" + this.transition(@states.errored) + else + + this.expectTransition() + + @rest.enqueueJamTrack({id: @jamTrackId}) + .done(this.processEnqueueJamTrack) + .fail(this.processEnqueueJamTrackFail) + when 'QUEUED' + # when it's queued, there is nothing to do except wait. + this.expectTransition() + this.transition(@states.packaging) + when 'QUEUED_TIMEOUT' + @errorMessage = "The server took too long to begin processing your JamTrack. #{@errorSupportMsg}" + this.transition(@states.errored) + when 'SIGNING' + this.expectTransition() + when 'SIGNING_TIMEOUT' + @errorMessage = "The server took too long to create your JamTrack. #{@errorSupportMsg}" + this.transition(@states.errored) + when 'SIGNED' + this.transition(@states.downloading) + when 'ERROR' + if @attemptedEnqueue + # this means we've already tried to poke the server. something is wrong + @errorMessage = "The server failed to create your package. #{@errorSupportMsg}" + this.transition(@states.errored) + else + this.expectTransition() + + @rest.enqueueJamTrack({id: @jamTrackId}) + .done(this.processEnqueueJamTrack) + .fail(this.processEnqueueJamTrackFail) + + + + processJamTrackRightFail: () => + @errorMessage = "Unable to check with the server on the status of your JamTrack. #{@errorSupportMsg}" + this.transition(@states.errored) + + processEnqueueJamTrack: (enqueueResponse) => + this.expectTransition() # the act of enqueuing should send down events to the client. we wait... + + processEnqueueJamTrackFail: () => + @errorMessage = "Unable to ask the server to build your JamTrack. #{@errorSupportMsg}" + this.transition(@states.errored) processJamTrackRight: (myJamTrack) => - if response.signing_state + this.processSigningState(myJamTrack.signing_state) + onJamTrackRightEvent: (e, data) => + @logger.debug("DownloadJamTrack: subscription notification received: type:" + data.type) + this.expectTransition() + this.processSigningState(data.body.signing_state) + + downloadProgressCallback: (bytesReceived, bytesTotal, downloadSpeedMegSec, timeRemaining) => + bytesReceived = Number(bytesReceived) + bytesTotal = Number(bytesTotal) + # bytesTotal from Qt is not trust worthy; trust server's answer instead + #progressWidth = ((bytesReceived / updateSize) * 100).toString() + "%"; + # $('#progress-bar').width(progressWidth) + + downloadSuccessCallback: (updateLocation) => + # is the package loadable yet? + this.transition(@states.keying) + + downloadFailureCallback: (errorMsg) => + @errorMessage = errorMessage + this.transition(@states.errored) + + # makes a function name for the backend + makeDownloadProgressCallback: () => + "JK.DownloadJamTracks['#{@jamTrackId}'].downloadProgressCallback" + + # makes a function name for the backend + makeDownloadSuccessCallback: () => + "JK.DownloadJamTracks['#{@jamTrackId}'].downloadSuccessCallback" + + # makes a function name for the backend + makeDownloadFailureCallback: () => + "JK.DownloadJamTracks['#{@jamTrackId}'].downloadFailureCallback" diff --git a/web/app/assets/javascripts/utils.js b/web/app/assets/javascripts/utils.js index 052b7d20e..f4ac9cee0 100644 --- a/web/app/assets/javascripts/utils.js +++ b/web/app/assets/javascripts/utils.js @@ -910,6 +910,10 @@ return null; } + context.JK.makeAbsolute = function(path) { + return window.location.protocol + '//' + window.location.host + path; + } + context.JK.popExternalLinks = function ($parent) { if(!$parent) $parent = $('body'); diff --git a/web/app/controllers/spikes_controller.rb b/web/app/controllers/spikes_controller.rb index b07987b4d..e0e43129f 100644 --- a/web/app/controllers/spikes_controller.rb +++ b/web/app/controllers/spikes_controller.rb @@ -33,6 +33,8 @@ class SpikesController < ApplicationController def subscription + #Notification.send_reload(MessageFactory::ALL_NATIVE_CLIENTS) + Notification.send_subscription_message('test', '1', '{"msg": "oh hai 1"}') Notification.send_subscription_message('test', '2', '{"msg": "oh hai 2"}') render text: 'oh hai' diff --git a/web/app/views/clients/_download_jamtrack_templates.html.slim b/web/app/views/clients/_download_jamtrack_templates.html.slim index bf5831cb4..abbbaf955 100644 --- a/web/app/views/clients/_download_jamtrack_templates.html.slim +++ b/web/app/views/clients/_download_jamtrack_templates.html.slim @@ -1,2 +1,30 @@ script type="text/template" id='template-download-jamtrack' .download-jamtrack + + +script type="text/template" id="template-download-jamtrack-state-no-client" + .state-no-client + | To download this JamTrack, launch the JamKazam application and open it while in a session. + +script type="text/template" id="template-download-jamtrack-state-synchronized" + .state-success + | This JamTrack is on your system and ready to play. + +script type="text/template" id="template-download-jamtrack-state-packaging" + .state-packaging + | Your JamTrack is currently being created on the JamKazam server. + +script type="text/template" id="template-download-jamtrack-state-downloading" + .state-downloading + | Your JamTrack is currently being downloaded. + +script type="text/template" id="template-download-jamtrack-state-keying" + .state-keying + | Your JamTrack is being authenticated. + +script type="text/template" id="template-download-jamtrack-state-initial" + .state-initial + | Initializing... +script type="text/template" id="template-download-jamtrack-state-errored" + .state-errored + .msg \ No newline at end of file