diff --git a/web/app/assets/javascripts/JamServer.js b/web/app/assets/javascripts/JamServer.js index 626b4aa50..83b2ce23f 100644 --- a/web/app/assets/javascripts/JamServer.js +++ b/web/app/assets/javascripts/JamServer.js @@ -669,9 +669,9 @@ } if(!mode) { mode = 'client' - if (context.jamClient && context.jamClient.getOperatingMode) { + //if (context.jamClient && context.jamClient.getOperatingMode) { mode = context.jamClient.getOperatingMode() - } + //} isLatencyTesterMode = mode == 'server'; } @@ -937,7 +937,6 @@ async function connect(){ if (context.jamClient !== undefined && await context.jamClient.IsNativeClient()) { await context.jamClient.SendP2PMessage.connect(server.sendP2PMessage); - //if (context.jamClient.SendLogin) { await context.jamClient.SendLogin.connect(server.sendLogin); await context.jamClient.SendLogin.connect(server.sendLogout); diff --git a/web/app/assets/javascripts/asyncJamClient.js b/web/app/assets/javascripts/asyncJamClient.js index e94bdd7c3..1babfdd82 100644 --- a/web/app/assets/javascripts/asyncJamClient.js +++ b/web/app/assets/javascripts/asyncJamClient.js @@ -3,10 +3,24 @@ context.JK = context.JK || {}; + class Deferred { + constructor(request_id) { + var self = this; + this.request_id = request_id; + this.promise = new Promise(function (resolve, reject) { + self.reject = reject; + self.resolve = resolve; + }); + } + } + context.JK.AsyncJamClient = function (app) { const self = this; - let proxy, jkfrontendchannel; + let deferredQueue = []; + let jkfrontendchannel; let enumAppCounter = 1000; + let request_id = 1; + const JKFrontendMethods = Object.freeze({ UnknownJKAppMessage: enumAppCounter++, AbortRecording: enumAppCounter++, @@ -275,7 +289,7 @@ VST_ScanForMidiDevices: enumAppCounter++ }); - function setupWebSocket() { + function setupWebSocketConnection(){ const baseUrl = "ws://localhost:3060"; console.log("connecting to WebSocket server at " + baseUrl + "."); @@ -288,9 +302,9 @@ // Try to reconnect. if (!navigator.onLine) { - //alert("You are offline. Please connect to the Internet and try again."); + //alert("You are offline. Please connect to the Internet and try again."); } - } + } }; socket.onerror = function (error) { @@ -301,81 +315,80 @@ console.log("WebSocket connected, setting up QWebChannel."); new QWebChannel(socket, function (channel) { jkfrontendchannel = channel.objects.jkfrontendchannel; - console.log(">>>> jkfrontendchannel", jkfrontendchannel); if(jkfrontendchannel){ - jkfrontendchannel.sendText.connect(function (message) { - console.log("Received message: " + message); - }); - console.log("Connected to WebChannel, ready to send/receive messages!"); + let deferred; + try{ + jkfrontendchannel.sendText.connect(function (message) { + //console.log("Message received via QWebChannel: " + message); + let msg = JSON.parse(message) + let req_id = msg.request_id + let response = msg.response; + + deferred = deferredQueue.find(d => { + return d.request_id === req_id + }); + + if(deferred){ + deferred.resolve(response) + //remove this deferred object from queue + deferredQueue = deferredQueue.filter((d) => d.request_id !== deferred.request_id) + } + }); + //TODO: handle method does not exist + }catch(e){ + console.log("Error when receving message via QWebChannel"); + if(deferred){ + deferred.reject(e.message) + deferred = null + } + } } }); }; + } - function init() { - let request_id = 1; - - setupWebSocket(); - + function setupAsyncProxy(){ + let proxy; const handler = { - get(target, prop) { - return function () { - console.log('[asyncJamClient] calling method:', prop); - //console.log(Array.from(arguments)); + get(target, prop, receiver) { + const origMethod = target[prop]; + //console.log('[asyncJamClient] get:', target, prop); + + return function(...args){ + // let result = origMethod.apply(this, args); + // console.log(prop + JSON.stringify(args)+ ' -> ' + JSON.stringify(result)); + // return result; - let appMessage = new Object(); + let appMessage = new Object(); appMessage.request_id = ++request_id; - appMessage.arguments = Array.from(arguments) || []; + appMessage.arguments = Array.from(arguments) || []; + let method = JKFrontendMethods[prop]; + appMessage.method = method + + let deferred = new Deferred(appMessage.request_id) - let method = JKFrontendMethods[prop]; - - if(!method || !jkfrontendchannel) return - - appMessage.method = method - - console.log("[asyncJamClient] appMessage:", appMessage); + try { + //console.log('[asyncJamClient] diverting to backend:', prop, appMessage); + jkfrontendchannel.receiveText(JSON.stringify(appMessage)); + deferredQueue.push(deferred) + return deferred.promise; + } catch (e) { + console.log("Native app not connected"); + } - new Promise(function (resolve, reject) { - try { - jkfrontendchannel.receiveText( - JSON.stringify(appMessage), - function (resp) { - console.log("[asyncJamClient] response received:", resp); - resolve(resp); - } - ); - //TODO: handle 404 error - return null if method does not exist - } catch (e) { - console.log("[asyncJamClient] error: Native app not connected"); - reject(Error(e.message)); //TODO: reject with custom error object QWebChannelError(e.message, e.data) - } - }); - - return true; //return true to prevent raising undefined method error - }; - }, - }; - - //let jamClient = context.jamClient; + } + + } + } proxy = new Proxy(self, handler); - - // let proxy = new Proxy(obj, { - // get(target, prop){ - // let value = target[prop] - // console.log(`target: ${target} | prop: ${prop} | value: ${value}`); - // if (typeof value === 'function') { - // return value.bind(target); - // }else{ - // return value - // } - // } - // }) - + console.log("Connected to WebChannel, ready to send/receive messages!"); + return proxy; } - //this.initialize = initialize; - init(); - return proxy; + setupWebSocketConnection() + return setupAsyncProxy() + }; })(window, jQuery); diff --git a/web/app/assets/javascripts/dialog/shareDialog.js b/web/app/assets/javascripts/dialog/shareDialog.js index e17d61635..9e9522e89 100644 --- a/web/app/assets/javascripts/dialog/shareDialog.js +++ b/web/app/assets/javascripts/dialog/shareDialog.js @@ -452,7 +452,7 @@ registerEvents(false); } - function initialize(_facebookHelper) { + async function initialize(_facebookHelper) { facebookHelper = _facebookHelper; var dialogBindings = { @@ -467,7 +467,7 @@ facebookHelper.deferredLoginStatus().done(function(response) { handleFbStateChange(response); }); - if(context.jamClient.IsNativeClient()) { + if(await context.jamClient.IsNativeClient()) { $("#btn-share-copy").unbind('click').click(async function() { await context.jamClient.SaveToClipboard($("#link-contents").text()); return false; diff --git a/web/app/assets/javascripts/everywhere/everywhere.js b/web/app/assets/javascripts/everywhere/everywhere.js index 854a5966a..b21c8acca 100644 --- a/web/app/assets/javascripts/everywhere/everywhere.js +++ b/web/app/assets/javascripts/everywhere/everywhere.js @@ -214,6 +214,7 @@ } function initializeStun(app) { + stun = new context.JK.Stun(app); context.JK.StunInstance = stun; stun.initialize(); diff --git a/web/app/assets/javascripts/react-components/ConfigureOutputsDialog.js.jsx.coffee b/web/app/assets/javascripts/react-components/ConfigureOutputsDialog.js.jsx.coffee index 05b934ad3..0c9d36ad3 100644 --- a/web/app/assets/javascripts/react-components/ConfigureOutputsDialog.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/ConfigureOutputsDialog.js.jsx.coffee @@ -46,7 +46,7 @@ ConfigureTracksStore = @ConfigureTracksStore $output1 = $root.find('.output-1') $output2 = $root.find('.output-2') - if @state.configureTracks? && @state.configureTracks.trackAssignments.outputs.assigned.length == 2 + if @state.configureTracks? && @state.configureTracks.trackAssignments && @state.configureTracks.trackAssignments.outputs.assigned.length == 2 output1 = @state.configureTracks.trackAssignments.outputs.assigned[0].id output2 = @state.configureTracks.trackAssignments.outputs.assigned[1].id diff --git a/web/app/assets/javascripts/react-components/stores/ConfigureTracksStore.js.coffee b/web/app/assets/javascripts/react-components/stores/ConfigureTracksStore.js.coffee index 719f70436..0cce51904 100644 --- a/web/app/assets/javascripts/react-components/stores/ConfigureTracksStore.js.coffee +++ b/web/app/assets/javascripts/react-components/stores/ConfigureTracksStore.js.coffee @@ -503,19 +503,22 @@ void removeSearchPath(int typeId, QString pathToRemove); loadTrackInstruments: `async function(forceInputsToUnassign) { const result = []; - for (let inputsForTrack of Array.from(this.trackAssignments.inputs.assigned)) { + //following if guard was added after changing to asyncJamClient to prevent null errors as this.trackAssignments return null on the initial page load + if(this.trackAssignments){ + for (let inputsForTrack of Array.from(this.trackAssignments.inputs.assigned)) { - let clientInstrument = await context.jamClient.TrackGetInstrument(inputsForTrack.assignment); + let clientInstrument = await context.jamClient.TrackGetInstrument(inputsForTrack.assignment); - if (clientInstrument === 0) { - logger.debug('defaulting track instrument for assignment '+ this.trackNumber); - await context.jamClient.TrackSetInstrument(inputsForTrack.assignment, 50); - clientInstrument = 50; + if (clientInstrument === 0) { + logger.debug('defaulting track instrument for assignment '+ this.trackNumber); + await context.jamClient.TrackSetInstrument(inputsForTrack.assignment, 50); + clientInstrument = 50; + } + + const instrument = context.JK.client_to_server_instrument_map[clientInstrument]; + + result.push(inputsForTrack.instrument_id = instrument != null ? instrument.server_id : undefined); } - - const instrument = context.JK.client_to_server_instrument_map[clientInstrument]; - - result.push(inputsForTrack.instrument_id = instrument != null ? instrument.server_id : undefined); } return result; diff --git a/web/app/assets/javascripts/recordingManager.js b/web/app/assets/javascripts/recordingManager.js index 6d4424c9a..05321e442 100644 --- a/web/app/assets/javascripts/recordingManager.js +++ b/web/app/assets/javascripts/recordingManager.js @@ -166,6 +166,16 @@ return false; } + async function registerRecordingManagerCallbacks(){ + await context.jamClient.RegisterRecordingManagerCallbacks( + "JK.RecordingManagerCommandStart", + "JK.RecordingManagerCommandProgress", + "JK.RecordingManagerCommandStop", + "JK.RecordingManagerCommandsChanged", + "JK.RecordingManagerAsapCommandStatus" + ) + } + $fileManager.click(onClick) $convertCommand.click(onClick) $downloadCommand.click(onClick) @@ -178,13 +188,14 @@ context.JK.RecordingManagerCommandsChanged = onCommandsChanged; context.JK.RecordingManagerAsapCommandStatus = onAsapCommandStatus; - context.jamClient.RegisterRecordingManagerCallbacks( - "JK.RecordingManagerCommandStart", - "JK.RecordingManagerCommandProgress", - "JK.RecordingManagerCommandStop", - "JK.RecordingManagerCommandsChanged", - "JK.RecordingManagerAsapCommandStatus" - ) + // context.jamClient.RegisterRecordingManagerCallbacks( + // "JK.RecordingManagerCommandStart", + // "JK.RecordingManagerCommandProgress", + // "JK.RecordingManagerCommandStop", + // "JK.RecordingManagerCommandsChanged", + // "JK.RecordingManagerAsapCommandStatus" + // ) + registerRecordingManagerCallbacks() return this; } diff --git a/web/app/assets/javascripts/sessionModel.js b/web/app/assets/javascripts/sessionModel.js index ad5cb722b..5df08972a 100644 --- a/web/app/assets/javascripts/sessionModel.js +++ b/web/app/assets/javascripts/sessionModel.js @@ -687,11 +687,11 @@ }) } - function onWebsocketDisconnected(in_error) { + async function onWebsocketDisconnected(in_error) { // kill the streaming of the session immediately if(currentSessionId) { logger.debug("onWebsocketDisconnect: calling jamClient.LeaveSession for clientId=" + clientId); - client.LeaveSession({ sessionID: currentSessionId }); + await client.LeaveSession({ sessionID: currentSessionId }); } } diff --git a/web/app/assets/javascripts/stun.js b/web/app/assets/javascripts/stun.js index 6528ae4d6..a220f7437 100644 --- a/web/app/assets/javascripts/stun.js +++ b/web/app/assets/javascripts/stun.js @@ -16,16 +16,18 @@ var result = await context.jamClient.NetworkTestResult(); - if (udp_blocked === null || (result.remote_udp_blocked != udp_blocked)) { - // update the server + if(result){ + if (udp_blocked === null || (result.remote_udp_blocked != udp_blocked)) { + // update the server - if(result.remote_udp_blocked) logger.debug("NO STUN: " + JSON.stringify(result)); - else logger.debug("STUN capable: " + JSON.stringify(result)); + if(result.remote_udp_blocked) logger.debug("NO STUN: " + JSON.stringify(result)); + else logger.debug("STUN capable: " + JSON.stringify(result)); - udp_blocked = result.remote_udp_blocked; + udp_blocked = result.remote_udp_blocked; - if (changed) changed(result.remote_udp_blocked) - } + if (changed) changed(result.remote_udp_blocked) + } + } return udp_blocked; } diff --git a/web/app/assets/javascripts/utils.js b/web/app/assets/javascripts/utils.js index 020fa4dcc..4afb58220 100644 --- a/web/app/assets/javascripts/utils.js +++ b/web/app/assets/javascripts/utils.js @@ -1127,7 +1127,7 @@ if (!(window.jamClient)) { var p2pMessageFactory = new JK.FakeJamClientMessages(); //window.jamClient = new JK.FakeJamClient(app, p2pMessageFactory); //legacy jamClient calling directly the C++ backend functions - console.log("SETTING UP AsyncJamClient"); + console.log("Setting up AsyncJamClient..."); window.jamClient = new JK.AsyncJamClient(app); //new client that asynchronously connects backend via websocket await window.jamClient.SetFakeRecordingImpl(new JK.FakeJamClientRecordings(app, jamClient, p2pMessageFactory)); } diff --git a/web/app/assets/javascripts/webcam_viewer.js.coffee b/web/app/assets/javascripts/webcam_viewer.js.coffee index 9ab016687..becbb9c4f 100644 --- a/web/app/assets/javascripts/webcam_viewer.js.coffee +++ b/web/app/assets/javascripts/webcam_viewer.js.coffee @@ -33,8 +33,6 @@ BackendToFrontendFPS = { 5: 10 } -#_loadResolutions = `async function(){const resolutions = (this.client.FTUEGetCaptureResolution != null) ? this.client.FTUEGetCaptureResolution() : {};const selectControl = this.resolutionSelect;this.logger.debug('FOUND THESE RESOLUTIONS', resolutions); context._.each(resolutions, function(resolution, resolutionKey, obj) { const frontendResolution = BackendToFrontend[resolutionKey];if (!frontendResolution) { this.logger.error('unknown resolution!' + resolution); const value = `${resolutionKey}`; const option = $('