MagicMirror² v2.12.0 is available! For more information about this release, check out this topic.

How to send a function as payload of socket notification?



  • Hello,

    When I receive a socket notification in my node_helper.js file I want to sent a socket notification with an object containing a function as value of one of its keys. Like this:

    const NodeHelper = require('node_helper');
    const someFunction = require('./someFunction');
    
    module.exports = NodeHelper.create({
      start: function () {
        console.log('Start node helper');
      },
    
      socketNotificationReceived: function (notification) {
        if (notification === 'FOO') {
          this.sendSocketNotification('FOO', { bar: someFunction });
        }
      },
    });
    

    However, when I receive this notification inside my main module file the function is not present in the payload:

      socketNotificationReceived: function (notification, payload) {
        if (notification === 'FOO') {
          console.log(payload.bar); // This logs 'undefined'
        }
      },
    

    Any other values (object, arrays, etc) I pass in the payload are received correctly.

    Does somebody know why the function I pass with the payload is undefined when I receive the socket notification in my main module file?



  • @ngnijland I think u have to send the entire function in the packet. It can’t contain the address of anything on the other side



  • @sdetweil thanks for your reply!

    I don’t think I completely understand you. What do you mean with “send the entire function”? Do you mean I can’t import a reference? And should write out the function in the node_helper.js file?


  • Module Developer

    @ngnijland
    Impossible in the current MM legacy structure.
    those processes are separated and can not share function.

    2 reasons;

    • The function itself cannot be transferred through socket (JSON doesn’t allow it)
    • If the function depends on some dependencies, it will lose them.

    Anyway, if the function itself is somehow simple and has no dependency, there could be some trick.

    var originalPayload = {
      "something": "hello, world",
      "someFunc" : (value) => {
        console.log(value)
        return value
      }
    }
    
    originalPayload.someFunc("Original Execution.")
    
    
    let replacer = (key, value) => {
      if (typeof value == "function") {
        return "__FUNC__" + value.toString()
      }
      return value
    }
    
    // Encode function in payload object
    var encodedPayload = JSON.stringify(originalPayload, replacer, 2)
    console.log("----")
    console.log(encodedPayload)
    console.log("----")
    // encodedPayload will have;
    // {
    //   "something": "hello, world",
    //   "someFunc": "__FUNC__(value) => {\n console.log(value)\n return value\n  }"
    // }
    
    // Now you can transfer this string as payload of socketNotification.
    // this.sendSocketNotification("SOME_EVENT", encodedPayload)
    // ...
    
    // Let's assume you got a payload through socketNotification
    var receivedPayload = encodedPayload
    
    let reviver = (key, value) => {
      if (typeof value === 'string' && value.indexOf('__FUNC__') === 0) {
        value = value.slice(8)
        let functionTemplate = `(${value})`
        return eval(functionTemplate)
      }
      return value
    }
    
    var revivedPayload = JSON.parse(receivedPayload, reviver)
    revivedPayload.someFunc("Function is revived.")
    

    CAUTION
    If the function requires dependencies (node modules, injected Object, references out of scope, …) those will be lost and it will cause an error.



  • @Sean
    Ah ofcourse, thanks for the explanation!

    My function does not have dependencies. I’ll use good old eval to fix this!

    My use case is that I need to use a different function based on the language setting of the mirror. These functions live in a separate folder and I import them in the node_helper.js file (together with some other arrays and objects I need based on language). For now I’ll use this solution, maybe in the future I build in a build step in my module so I can import the files directly into my main module file.

    https://github.com/ngnijland/MMM-text-clock/pull/2