Ari
Ari

Reputation: 3679

Sending anonymous functions through socket.io?

I want to create a client-side function that can receive and execute arbitrary commands using client-side variables. I will be sending these functions from my server by using socket.io to send a JSON object containing an anonymous function which will be my command. It looks something like the following:

//client side

socket.on('executecommand', function(data){
    var a = "foo";
    data.execute(a); //should produce "foo"
});

//server side

socket.emit('executecommand', {'execute': function(param){
    console.log(param);
}});

Yet, when I tried it out, the client side received an empty json object (data == {}), then threw an exception because data contained no method execute. What is going wrong here?

Upvotes: 6

Views: 5286

Answers (3)

bigOmega  ツ
bigOmega ツ

Reputation: 371

Here's how I did this eventually.

Have the functions in a common place (const.js here) and send the key.

// const.js
const FNS = {
  timer: { exec: t => console.log(`You have ${t} seconds!`) },
}

// server
const FNS_KEYS = Object.keys(CONST.FNS).reduce((m,k) => (m[k]=k,m), {})
socket.emit('execute', FNS_KEYS.timer)

// client
socket.on('execute', key => CONST.FNS[key]?.exec(30))

Upvotes: 0

Jonathan Lonowski
Jonathan Lonowski

Reputation: 123533

JSON doesn't support the inclusion of function definitions/expressions.

What you can do instead is to define a commands object with the functions you need and just pass a commandName:

// client-side

var commands = {
    log: function (param) {
        console.log(param);
    }
};

socket.on('executecommand', function(data){
    var a = 'foo';
    commands[data.commandName](a);
});
// server-side

socket.emit('executecommand', { commandName: 'log' });

You can also use fn.apply() to pass arguments and check the commandName matches a command with in:

// client-side
var commands = { /* ... */ };

socket.on('executecommand', function(data){
    if (data.commandName in commands) {
        commands[data.commandName].apply(null, data.arguments || []);
    } else {
        console.error('Unrecognized command', data.commandName);
    }
});
// server-side

socket.emit('executecommand', {
    commandName: 'log',
    arguments: [ 'foo' ]
});

Upvotes: 10

Daniel
Daniel

Reputation: 1692

You can't send literal JavaScript functions and expect it to work. You'll need to stringify the function first (i.e put it within a set of quotes), then eval the string on the client side.

Upvotes: 4

Related Questions