How to handle await/promise of async websocket object?



  • Hey,
    I want to set up a WebSocket client in my quasar app. I want to connect to just one local WebSocket server, which is hosted by a local C++ asio http&websocket server of mine. The port of that server can change, so I created a global variable (which is defined in index.template.html, so it does not get renamed by the build process). That global variable is written by a JS inject and then holds the port of the server. That on the other hand means, that I don’t have the necessary server port upon app start, but only ever so slightly later.

    So I thought I might solve this by using promises, but I am JS/vue.js noob and got confused in the process.

    I set up

    quasar new boot websocket
    

    and set it in the config

    module.exports = function (ctx) {
      return {
        boot: [
          'i18n',
          'axios',
          'websocket'
        ]}
    }
    

    For now the websocket.js is rather simple, because I dont get it to return an object only if it is able to create one:
    I want this to provide a websocket object, as soon as I can create one

    import wsClient from '../statics/JS_WS.js'
    import Vue from 'vue'
    
    Vue.prototype.$ws = wsClient
    
    //tried something along those lines, but failed:
    export default async ({ Vue }) => {
    
      Vue.prototype.$ws = wsClient
      return new Promise((resolve) => {
        if (wsClient !== null) {
          resolve()
        }
      })
    }
    

    The JS_WS.js is quite simple and relies on the global webserver port variable. It has a send and close method, but for the initialization those are the lines:
    I want this to read the port and create the websocket client object, as soon as the port is available

    var wsClient = null
    var wsAddress
    var WSServerMessage
    
    function InitWS() {
        if (globInit && globInit !== null) { //this is the global websocket port variable
            var globObj = JSON.parse(globInit)
            SetWSAddress("ws://localhost:" + globObj.localPort + "/templateHttp")
            ConnectWS()
        }
    }
    
    function SetWSAddress(address) {
        wsAddress = address
        wsClient = new WebSocket(wsAddress);
    }
    
    function ConnectWS() {
        try {
            console.log("Opening JS_WS to: " + wsAddress);
    
            wsClient.onopen = function () {
                wsClient.send("Initializing JS_WS");
            };
        }
        catch (e) {
            console.log(e)
        }
    }
    
    //the builder kept complaining that I dont have a default export, so I tried creating one - didn't work
    export default async () => {
        return new Promise((resolve) => {        
            if (globInit && globInit !== null) {
                resolve()
            }
        })
    }
    

    On app start (atm in MyLayout.vue) I try to set up a listener:
    I want this to set the listener for the websocket client, as soon as the client exists

    mounted() {
          let wsPromise = this.$ws;
          wsPromise.then(
            this.$ws.onmessage = function(e) {
              this.MessageFromWSServer = e.data;
              document.getElementById(
                "ID_MessageFromWSServer"
              ).innerHTML = this.MessageFromWSServer;
            }
          );
        });
      }
    

    At the moment I fail with the line: “Cannot read property ‘then’ of undefined” which had got to be the call in the .vue

    Where to start to unmess this this mess? I tried using vuex first, that was even more confusing to me.
    Any help appreciated!

    Thanks



  • @MKramer said in How to handle await/promise of async websocket object?:

    The port of that server can change, so I created a global variable (which is defined in index.template.html, so it does not get renamed by the build process)

    I’m afraid I don’t understand. What do you mean with getting renamed by the build process?

    Why is your port number not available upon app start? Does it change over time or something?

    Of course, the frontend somehow needs to know what port number the backend is running on and so on. But normally, it doesn’t need to wait for it… it should know value right away, for example using an environment variable.
    Why do you need it to be asynchonous?



  • @chyde90 said in How to handle await/promise of async websocket object?:

    @MKramer said in How to handle await/promise of async websocket object?:

    The port of that server can change, so I created a global variable (which is defined in index.template.html, so it does not get renamed by the build process)

    I’m afraid I don’t understand. What do you mean with getting renamed by the build process?

    If you have a look at the .js files, that “quasar build” generates you can see, that all the function and variable names are scrambled (not readable anymore). Except for the index.template.html, because that is where quasar is included so the rest is sort of ‘out of quasar terratory’.

    That means that I can not call a js function with javascript-injection (from outside of that app) after the build process, because all the names have changed.
    That is important for me, because my local webserver needs to run on many different machines locally. It may well be, that the port that I want to take is already taken, in which case I just take another port to start my server on. But the quasar app can not not know about it and needs to be notified, which port to use.

    Why is your port number not available upon app start? Does it change over time or something?

    It does not change over time though, I just need to check each time I start. To clarify: My server is local in a C++ app and that C++ app has an embedded browser, in which the quasar app is loaded (think about steam or blizzard launcher which is sort of the same)

    Of course, the frontend somehow needs to know what port number the backend is running on and so on. But normally, it doesn’t need to wait for it… it should know value right away, for example using an environment variable.

    My C++ server and my quasar client do not share any common enviroment. For communication between them, I set up that server.

    Why do you need it to be asynchonous?

    Because the only way to tell the quasar app about the port is a javascript injection from the server side. But for js-injection the app needs to be up and running, or else the js function that I want to call has not been loaded yet.
    Unfortunately I can’t just load the page with an URL parameter, because I load it from a virtual file system where the URL is part of the hash to identify the index file…

    So on start we go:
    Server/browser app starts > finds and occupies a port > loads quasar app from virtual file system in embedded browser > quasar app loads > quasar app tries to initialize the websocket client, is missing a port > js-injection from the server comes through > port is known in quasar

    I placed a button on the webpage to manually set the websocket and then it works all fine. But of course I don’t want a connect button on each page loaded, I want it to be automatic.

    Cheers


Log in to reply