548 lines
18 KiB
CoffeeScript
548 lines
18 KiB
CoffeeScript
$ = jQuery
|
|
context = window
|
|
logger = context.JK.logger
|
|
rest = context.JK.Rest()
|
|
EVENTS = context.JK.EVENTS
|
|
|
|
|
|
JamTrackActions = @JamTrackActions
|
|
|
|
@JamTrackStore = Reflux.createStore(
|
|
{
|
|
listenables: [JamTrackActions, JamTrackMixdownActions]
|
|
jamTrack: null
|
|
previous: null
|
|
requestedSearch: null
|
|
requestedFilter: null
|
|
subscriptions: {}
|
|
enqueuedMixdowns: {}
|
|
|
|
init: ->
|
|
# Register with the app store to get @app
|
|
this.listenTo(context.AppStore, this.onAppInit)
|
|
|
|
onAppInit: (app) ->
|
|
@app = app
|
|
|
|
getState: () ->
|
|
@state
|
|
|
|
pickMyPackage: () ->
|
|
|
|
return unless @jamTrack?
|
|
|
|
|
|
for mixdown in @jamTrack.mixdowns
|
|
|
|
myPackage = null
|
|
for mixdown_package in mixdown.packages
|
|
if mixdown_package.file_type == 'ogg' && mixdown_package.encrypt_type == 'jkz' && mixdown_package.sample_rate == @sampleRate
|
|
myPackage = mixdown_package
|
|
break
|
|
|
|
mixdown.myPackage = myPackage
|
|
|
|
subscriptionKey: (mixdown_package) ->
|
|
"mixdown-#{mixdown_package.id}"
|
|
|
|
subscribe: (mixdown_package) ->
|
|
key = @subscriptionKey(mixdown_package)
|
|
|
|
if !@watchedMixdowns[key]?
|
|
# we need to register
|
|
context.JK.SubscriptionUtils.subscribe('mixdown', mixdown_package.id).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, this.onMixdownSubscriptionEvent)
|
|
@watchedMixdowns[key] = {type:'mixdown', id: mixdown_package.id}
|
|
|
|
unsubscribe: (mixdown_package) ->
|
|
key = @subscriptionKey(mixdown_package)
|
|
if @watchedMixdowns[key]?
|
|
context.JK.SubscriptionUtils.unsubscribe('mixdown', mixdown_package.id)
|
|
delete @watchedMixdowns[key]
|
|
|
|
manageWatchedMixdowns: () ->
|
|
|
|
if @jamTrack?
|
|
for mixdown in @jamTrack.mixdowns
|
|
if mixdown.myPackage
|
|
if mixdown.myPackage.signing_state == 'SIGNED'
|
|
@unsubscribe(mixdown.myPackage)
|
|
else
|
|
@subscribe(mixdown.myPackage)
|
|
|
|
else
|
|
for key, subscription of @watchedMixdowns
|
|
logger.debug("unsubscribing bulk", key, subscription)
|
|
context.JK.SubscriptionUtils.unsubscribe(subscription.type, subscription.id)
|
|
|
|
# we cleared them all out; clear out storage
|
|
@watchedMixdowns = {}
|
|
|
|
onMixdownSubscriptionEvent: (e, data) ->
|
|
logger.debug("JamTrackStore: subscription notification received: type:" + data.type, data)
|
|
|
|
return unless @jamTrack?
|
|
|
|
mixdown_package_id = data.id
|
|
|
|
for mixdown in @jamTrack.mixdowns
|
|
for mixdown_package in mixdown.packages
|
|
if mixdown_package.id == mixdown_package_id
|
|
mixdown_package.signing_state = data.body.signing_state
|
|
mixdown_package.packaging_steps = data.body.packaging_steps
|
|
mixdown_package.current_packaging_step = data.body.current_packaging_step
|
|
logger.debug("updated package with subscription notification event")
|
|
|
|
if mixdown_package.signing_state == 'SIGNING_TIMEOUT' || mixdown_package.signing_state == 'QUEUED_TIMEOUT' || mixdown_package.signing_state == 'QUIET_TIMEOUT' || mixdown_package.signing_state == 'ERROR'
|
|
@reportError(mixdown)
|
|
|
|
@changed()
|
|
break
|
|
|
|
# this drives the state engine required to get a Mixdown from 'available on the server' to
|
|
manageMixdownSynchronization: () ->
|
|
|
|
@jamTrack.activeMixdown = null if @jamTrack
|
|
|
|
# let's see if we have a mixdown active?
|
|
|
|
if !@jamTrack?.last_mixdown_id?
|
|
logger.debug("JamTrackStore: no mixdown active")
|
|
@clearMixdownTimers()
|
|
return
|
|
|
|
for mixdown in @jamTrack.mixdowns
|
|
if mixdown.id == @jamTrack.last_mixdown_id
|
|
@jamTrack.activeMixdown = mixdown
|
|
logger.debug("JamTrackStore: mixdown active:", mixdown)
|
|
break
|
|
|
|
if @jamTrack.activeMixdown?
|
|
|
|
# if we don't have this on the server yet, don't engage the rest of this logic...
|
|
return if @jamTrack.activeMixdown?.myPackage?.signing_state != 'SIGNED'
|
|
|
|
fqId = "#{@jamTrack.id}_#{@jamTrack.activeMixdown.id}-#{@sampleRate}"
|
|
@trackDetail = context.jamClient.JamTrackGetTrackDetail (fqId)
|
|
|
|
logger.debug("JamTrackStore: JamTrackGetTrackDetail(#{fqId}).key_state: " + @trackDetail.key_state, @trackDetail)
|
|
|
|
# first check if the version is not the same; if so, invalidate.
|
|
|
|
if @trackDetail.version? && @jamTrack.activeMixdown.myPackage?
|
|
if @jamTrack.activeMixdown.myPackage.version != @trackDetail.version
|
|
logger.info("JamTrackStore: JamTrack Mixdown on disk is different version (stored: #{@trackDetail.version}, server: #{@jamTrack.activeMixdown.myPackage.version}. Invalidating")
|
|
context.jamClient.InvalidateJamTrack(fqId)
|
|
@trackDetail = context.jamClient.JamTrackGetTrackDetail (fqId)
|
|
|
|
if @trackDetail.version?
|
|
logger.error("after invalidating package, the version is still wrong!")
|
|
throw "after invalidating package, the version is still wrong!"
|
|
|
|
if @jamTrack.activeMixdown.client_state == 'cant_open'
|
|
logger.debug(" skipping state check because of earlier 'cant_open'. user should hit retry. ")
|
|
return
|
|
|
|
if @jamTrack.activeMixdown.client_state == 'download_fail'
|
|
logger.debug("skipping state check because of earlier 'download_fail'. user should hit retry. ")
|
|
return
|
|
|
|
if @jamTrack.activeMixdown.client_state == 'downloading'
|
|
logger.debug("skipping state check because we are downloading")
|
|
|
|
switch @trackDetail.key_state
|
|
when 'pending'
|
|
@attemptKeying()
|
|
when 'not authorized'
|
|
# TODO: if not authorized, do we need to re-initiate a keying attempt?
|
|
@attemptKeying()
|
|
when 'ready'
|
|
if @jamTrack.activeMixdown.client_state != 'ready'
|
|
|
|
@clearMixdownTimers()
|
|
@jamTrack.activeMixdown.client_state = 'ready'
|
|
|
|
# now load it:
|
|
# JamTrackPlay means 'load'
|
|
logger.debug("JamTrackStore: loading mixdown")
|
|
context.jamClient.JamTrackStopPlay();
|
|
result = context.jamClient.JamTrackPlay(fqId);
|
|
if !result
|
|
@jamTrack.activeMixdown.client_state = 'cant_open'
|
|
@reportError(@jamTrack.activeMixdown)
|
|
@app.notify(
|
|
{
|
|
title: "Mixdown Can Not Open",
|
|
text: "Unable to open your JamTrack Mixdown. Please contact support@jamkazam.com"
|
|
}
|
|
, null, true)
|
|
|
|
when 'unknown'
|
|
# we need to check if @keyCheckTimeout exists; because if it does, we don't want to download while keying.
|
|
# 'unknown' is tricky here because the file probably is actually on disk, but the bridge API can say unknown until you've tried to key at least once
|
|
if @jamTrack.activeMixdown.client_state != 'downloading' && !@keyCheckTimeout?
|
|
@jamTrack.activeMixdown.client_state = 'downloading'
|
|
logger.debug("JamTrackStore: initiating download of mixdown")
|
|
context.jamClient.JamTrackDownload(@jamTrack.id, @jamTrack.activeMixdown.id, context.JK.currentUserId,
|
|
this.makeDownloadProgressCallback(),
|
|
this.makeDownloadSuccessCallback(),
|
|
this.makeDownloadFailureCallback())
|
|
else
|
|
logger.debug("JamTrackStore: already downloading")
|
|
|
|
attemptKeying: () ->
|
|
if @keyCheckTimeout?
|
|
logger.debug("JamTrackStore: attemptKeying: skipping because already keying")
|
|
return
|
|
else if @jamTrack.activeMixdown.client_state == 'keying_timeout'
|
|
# if we have timed out keying, we shouldn't automatically retry
|
|
logger.debug("JamTrackStore: attempKeying: skipping because we have timed out before and user hasn't requested RETRY")
|
|
return
|
|
else
|
|
@keyCheckTimeout = setTimeout(@onKeyCheckTimeout, 10000)
|
|
@keyCheckoutInterval = setInterval(@checkOnKeying, 1000)
|
|
@jamTrack.activeMixdown.client_state = 'keying'
|
|
logger.debug("JamTrackStore: initiating keying requested")
|
|
context.jamClient.JamTrackKeysRequest()
|
|
|
|
onKeyCheckTimeout: () ->
|
|
@keyCheckTimeout = null
|
|
clearInterval(@keyCheckoutInterval)
|
|
@keyCheckoutInterval = null
|
|
|
|
if @jamTrack?.activeMixdown?
|
|
@jamTrack.activeMixdown.client_state = 'keying_timeout'
|
|
@reportError(@jamTrack.activeMixdown)
|
|
|
|
@changed()
|
|
|
|
checkOnKeying: () ->
|
|
@manageMixdownSynchronization()
|
|
|
|
# if we exit keying state, we can clear our timers and poke state
|
|
if @jamTrack.activeMixdown.client_state != 'keying'
|
|
@clearMixdownTimers()
|
|
@changed()
|
|
|
|
|
|
# clear out any timer/watcher stuff
|
|
clearMixdownTimers: () ->
|
|
logger.debug("JamTrackStore: clearing mixdown timers", @keyCheckTimeout, @keyCheckoutInterval)
|
|
clearTimeout(@keyCheckTimeout) if @keyCheckTimeout?
|
|
clearInterval(@keyCheckoutInterval) if @keyCheckoutInterval?
|
|
@keyCheckTimeout = null
|
|
@keyCheckoutInterval = null
|
|
|
|
changed: () ->
|
|
|
|
@pickMyPackage()
|
|
@manageWatchedMixdowns()
|
|
@manageMixdownSynchronization()
|
|
|
|
@state = {
|
|
jamTrack: @jamTrack,
|
|
opened: @previous == null && @jamTrack != null,
|
|
closed: @previous != null && @jamTrack == null,
|
|
fullTrackActivated: @previousMixdown != null && @jamTrack?.activeMixdown == null}
|
|
@previous = @jamTrack
|
|
@previousMixdown = @jamTrack?.activeMixdown
|
|
this.trigger(@state)
|
|
|
|
|
|
onOpen: (jamTrack) ->
|
|
if @jamTrack?
|
|
@app.notify({text: 'Unable to open JamTrack because another one is already open.'})
|
|
return
|
|
|
|
@enqueuedMixdowns = {}
|
|
@jamTrack = jamTrack
|
|
|
|
# we can cache this because you can't switch gear while in a session (and possible change sample rate!)
|
|
sampleRate = context.jamClient.GetSampleRate()
|
|
@sampleRate = if sampleRate == 48 then 48 else 44
|
|
|
|
@changed()
|
|
|
|
onClose: () ->
|
|
@jamTrack = null
|
|
@changed()
|
|
|
|
onRequestSearch:(searchType, searchData) ->
|
|
@requestedSearch = {searchType: searchType, searchData: searchData}
|
|
window.location.href = '/client#/jamtrack/search'
|
|
|
|
# needed by the JamTrackSearchScreen
|
|
checkRequestedSearch:() ->
|
|
requested = @requestedSearch
|
|
@requestedSearch = null
|
|
requested
|
|
|
|
onRequestFilter:(genre, instrument) ->
|
|
@requestedFilter = {genre: genre, instrument:instrument}
|
|
window.location.href = '/client#/jamtrack/filter'
|
|
|
|
# needed by the JamTrackSearchScreen
|
|
checkRequestedFilter:() ->
|
|
requested = @requestedFilter
|
|
@requestedFilter = null
|
|
requested
|
|
|
|
onCreateMixdown: (mixdown, done, fail) ->
|
|
|
|
volumeSettings = context.jamClient.GetJamTrackSettings();
|
|
|
|
track_settings = []
|
|
|
|
for track in volumeSettings.tracks
|
|
track_settings.push({id: track.id, pan: track.pan, vol: track.vol_l, mute: track.mute})
|
|
|
|
mixdown.settings.tracks = track_settings
|
|
|
|
logger.debug("creating mixdown", mixdown)
|
|
|
|
rest.createMixdown(mixdown)
|
|
.done((created) =>
|
|
|
|
@addMixdown(created)
|
|
|
|
logger.debug("created mixdown", created)
|
|
|
|
@onEnqueueMixdown({id: created.id}, done, fail)
|
|
)
|
|
.fail((jqxhr) =>
|
|
fail(jqxhr)
|
|
)
|
|
|
|
|
|
onEditMixdown: (mixdown) ->
|
|
logger.debug("editing mixdown", mixdown)
|
|
|
|
rest.editMixdown(mixdown)
|
|
.done((updatedMixdown) =>
|
|
logger.debug("edited mixdown")
|
|
@updateMixdown(updatedMixdown)
|
|
).fail((jqxhr) =>
|
|
@app.layout.notify({title:'Unable to Edit Custom Mix', text: 'The server was unable to edit this mix.'})
|
|
)
|
|
|
|
onDeleteMixdown: (mixdown) ->
|
|
logger.debug("deleting mixdown", mixdown)
|
|
|
|
rest.deleteMixdown(mixdown)
|
|
.done(() =>
|
|
logger.debug("deleted mixdown")
|
|
|
|
@deleteMixdown(mixdown)
|
|
)
|
|
.fail((jqxhr) =>
|
|
@app.layout.notify({title:'Unable to Deleted Custom Mix', text: 'The server was unable to delete this mix.'})
|
|
)
|
|
|
|
onOpenMixdown: (mixdown) ->
|
|
logger.debug("opening mixdown", mixdown)
|
|
|
|
# check if it's already available in the backend or not
|
|
rest.markMixdownActive({id: @jamTrack.id, mixdown_id: mixdown.id})
|
|
.done((edited) =>
|
|
logger.debug("marked mixdown as active")
|
|
@jamTrack = edited
|
|
|
|
# unload any currently loaded JamTrack
|
|
context.jamClient.JamTrackStopPlay();
|
|
|
|
@changed()
|
|
|
|
SessionActions.mixdownActive(mixdown)
|
|
)
|
|
.fail((jqxhr) =>
|
|
@app.layout.notify({title:'Unable to Edit Mixdown', text: 'Unable to mark this mixdown as active.'})
|
|
)
|
|
|
|
onActivateNoMixdown: (jamTrack) ->
|
|
logger.debug("activating no mixdown")
|
|
|
|
rest.markMixdownActive({id: @jamTrack.id, mixdown_id: null})
|
|
.done((edited) =>
|
|
logger.debug("marked JamTrack as active")
|
|
|
|
@jamTrack = edited
|
|
@changed()
|
|
|
|
SessionActions.mixdownActive({id:null})
|
|
)
|
|
.fail((jqxhr) =>
|
|
@app.layout.notify({title:'Unable to Edit Mixdown', text: 'Unable to mark this mixdown as active.'})
|
|
)
|
|
|
|
|
|
onCloseMixdown: (mixdown) ->
|
|
logger.debug("closing mixdown", mixdown)
|
|
|
|
onEnqueueMixdown: (mixdown, done, fail) ->
|
|
logger.debug("enqueuing mixdown", mixdown)
|
|
|
|
package_settings = {file_type: 'ogg', encrypt_type: 'jkz', sample_rate: @sampleRate}
|
|
package_settings.id = mixdown.id
|
|
|
|
rest.enqueueMixdown(package_settings)
|
|
.done((enqueued) =>
|
|
|
|
@enqueuedMixdowns[mixdown.id] = {}
|
|
|
|
logger.debug("enqueued mixdown package", package_settings)
|
|
@addOrUpdatePackage(enqueued)
|
|
done(enqueued) if done
|
|
)
|
|
.fail((jqxhr) =>
|
|
@app.layout.notify({title:'Unable to Create Custom Mix', text: 'Click the error icon to retry.'})
|
|
fail(jqxhr) if fail?
|
|
)
|
|
|
|
onDownloadMixdown: (mixdown) ->
|
|
logger.debug("download mixdown", mixdown)
|
|
|
|
onRefreshMixdown: (mixdown) ->
|
|
logger.debug("refresh mixdown", mixdown)
|
|
|
|
addMixdown: (mixdown) ->
|
|
if @jamTrack?
|
|
logger.debug("adding mixdown to JamTrackStore", mixdown)
|
|
@jamTrack.mixdowns.splice(0, 0, mixdown)
|
|
@changed()
|
|
else
|
|
logger.warn("no jamtrack to add mixdown to in JamTrackStore", mixdown)
|
|
|
|
deleteMixdown: (mixdown) ->
|
|
if @jamTrack?
|
|
logger.debug("deleting mixdown from JamTrackStore", mixdown)
|
|
index = null
|
|
for matchMixdown, i in @jamTrack.mixdowns
|
|
if mixdown.id == matchMixdown.id
|
|
index = i
|
|
if index?
|
|
@jamTrack.mixdowns.splice(index, 1)
|
|
|
|
if @jamTrack.activeMixdown?.id == mixdown.id
|
|
@onActivateNoMixdown(@jamTrack)
|
|
|
|
@changed()
|
|
else
|
|
logger.warn("unable to find mixdown to delete in JamTrackStore", mixdown)
|
|
else
|
|
logger.warn("no jamtrack to delete mixdown for in JamTrackStore", mixdown)
|
|
|
|
updateMixdown: (mixdown) ->
|
|
if @jamTrack?
|
|
logger.debug("editing mixdown from JamTrackStore", mixdown)
|
|
index = null
|
|
for matchMixdown, i in @jamTrack.mixdowns
|
|
if mixdown.id == matchMixdown.id
|
|
index = i
|
|
if index?
|
|
@jamTrack.mixdowns[index] = mixdown
|
|
|
|
@changed()
|
|
else
|
|
logger.warn("unable to find mixdown to edit in JamTrackStore", mixdown)
|
|
else
|
|
logger.warn("no jamtrack to edit mixdown for in JamTrackStore", mixdown)
|
|
|
|
addOrUpdatePackage: (mixdown_package) ->
|
|
if @jamTrack?
|
|
added = false
|
|
index = null
|
|
for mixdown in @jamTrack.mixdowns
|
|
existing = false
|
|
if mixdown_package.jam_track_mixdown_id == mixdown.id
|
|
for possiblePackage, i in mixdown.packages
|
|
if possiblePackage.id == mixdown_package.id
|
|
existing = true
|
|
index = i
|
|
break
|
|
|
|
if existing
|
|
mixdown.packages[index] = mixdown_package
|
|
logger.debug("replacing mixdown package in JamTrackStore", mixdown_package)
|
|
else
|
|
mixdown.packages.splice(0, 0, mixdown_package)
|
|
logger.debug("adding mixdown package in JamTrackStore")
|
|
|
|
added = true
|
|
@changed()
|
|
break
|
|
|
|
if !added
|
|
logger.debug("couldn't find the mixdown associated with package in JamTrackStore", mixdown_package)
|
|
else
|
|
logger.warn("no mixdown to add package to in JamTrackStore", mixdown_package)
|
|
|
|
|
|
updateDownloadProgress: () ->
|
|
|
|
if @bytesReceived? and @bytesTotal?
|
|
progress = "#{Math.round(@bytesReceived/@bytesTotal * 100)}%"
|
|
else
|
|
progress = '0%'
|
|
|
|
#@root.find('.state-downloading .progress').text(progress)
|
|
|
|
downloadProgressCallback: (bytesReceived, bytesTotal) ->
|
|
logger.debug("download #{bytesReceived}/#{bytesTotal}")
|
|
|
|
@bytesReceived = Number(bytesReceived)
|
|
@bytesTotal = Number(bytesTotal)
|
|
|
|
# the reason this timeout is set is because, without it,
|
|
# we observe that the client will hang. So, if you remove this timeout, make sure to test with real client
|
|
setTimeout(this.updateDownloadProgress, 100)
|
|
|
|
downloadSuccessCallback: (updateLocation) ->
|
|
# is the package loadable yet?
|
|
logger.debug("JamTrackStore: download complete - on to keying")
|
|
@attemptKeying()
|
|
@changed()
|
|
|
|
downloadFailureCallback: (errorMsg) ->
|
|
|
|
logger.debug("mixdown download failed", errorMsg);
|
|
|
|
if @jamTrack?.activeMixdown?
|
|
@jamTrack.activeMixdown.client_state = 'download_fail'
|
|
@reportError(@jamTrack.activeMixdown)
|
|
@changed()
|
|
|
|
# makes a function name for the backend
|
|
makeDownloadProgressCallback: () ->
|
|
"JamTrackStore.downloadProgressCallback"
|
|
|
|
# makes a function name for the backend
|
|
makeDownloadSuccessCallback: () ->
|
|
"JamTrackStore.downloadSuccessCallback"
|
|
|
|
# makes a function name for the backend
|
|
makeDownloadFailureCallback: () ->
|
|
"JamTrackStore.downloadFailureCallback"
|
|
|
|
|
|
reportError: (mixdown) ->
|
|
|
|
enqueued = @enqueuedMixdowns[mixdown?.id]
|
|
|
|
# don't double-report
|
|
if !enqueued? || enqueued.marked
|
|
return
|
|
|
|
enqueued.marked = true
|
|
data = {
|
|
value: 1,
|
|
user_id: context.JK.currentUserId,
|
|
user_name: context.JK.currentUserName,
|
|
result: "signing state: #{mixdown.myPackage?.signing_state}, client state: #{mixdown.client_state}",
|
|
mixdown: mixdown.id,
|
|
package: mixdown.myPackage?.id
|
|
detail: mixdown.myPackage?.error_reason
|
|
}
|
|
rest.createAlert("Mixdown Sync failed for #{context.JK.currentUserName}", data)
|
|
|
|
context.stats.write('web.mixdown.error', data)
|
|
}
|
|
) |