This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Neander_King's profile picture

Executing a string as a Command

Started by Neander_King, 22 July 2015 - 06:30 PM
Neander_King #1
Posted 22 July 2015 - 08:30 PM
For a little background, I am making yet another wireless turtle remote control program, and I want to be able to have the vast majority of the code exist solely on the pocket computer "remote" and have a turtle with a program that only listens for commands on a specific protocol, sends a response, and executes the received command. However, I don't know how to, or if it's possible, to execute a string as if it were a command. For example, I wrote this code which should take the two strings, concatenate them, and execute the result.

local main_cmd="turtle.dig"
local direction="Down"
local params="()"
shell.run(main_cmd..direction..params)
To be more straightforward, I want a way to use a string like "turtle.digDown()" and make the turtle execute that.
MKlegoman357 #2
Posted 22 July 2015 - 09:12 PM
Well, you could loadstring the 'command' (which is Lua code) and run that. But I'd suggest not to if you're playing on a server, because somebody might send a virus that your program will run unknowingly. If the functions you want to run are simply turtle.dig or turtle.forward, then I'd suggest not having the client send the code a turtle should execute but rather a command telling what to execute. So you'd simply send something like "MOVE_FORWARD" and then the turtle would interpret that as a turtle.forward:


local trusted_id = 5 --# the id of the sending computer

while true do
  local id, message = rednet.receive()

  if id == trusted_id then
    if message = "MOVE_FORWARD" then
      turtle.forward()
    end
  end
end

You could even take this design further by putting all the commands in a table and simplifying everything:


local trusted_id = 5 --# the id of the sending computer
local commands = {} --# a table holding all the commands as keys and their respective functions as values

command["MOVE_FORWARD"] = function () --# make a function with some logic inside
  if not turtle.detect() then
    turtle.forward()
  end
end

command["MOVE_BACK"] = turtle.back --# or simply assign one of the functions directly

while true do
  local id, message = rednet.receive()

  if id == trusted_id then
    local command = commands[message] --# get the command from the table

    if command then --# if there is a command
      command() --# execute it
    end
  end
end

Of course, you may actually need to send custom code to the turtle, but from your example I figured you want to run pretty straight forward commands.
Neander_King #3
Posted 22 July 2015 - 09:24 PM
Thank you so much for the extra effort to explain the security aspect. I will definitely take your advice and store the commands on the turtle despite their simple nature.
H4X0RZ #4
Posted 22 July 2015 - 09:57 PM
Well, you could loadstring the 'command' (which is Lua code) and run that. But I'd suggest not to if you're playing on a server, because somebody might send a virus that your program will run unknowingly. If the functions you want to run are simply turtle.dig or turtle.forward, then I'd suggest not having the client send the code a turtle should execute but rather a command telling what to execute. So you'd simply send something like "MOVE_FORWARD" and then the turtle would interpret that as a turtle.forward:


local trusted_id = 5 --# the id of the sending computer

while true do
  local id, message = rednet.receive()

  if id == trusted_id then
	if message = "MOVE_FORWARD" then
	  turtle.forward()
	end
  end
end

You could even take this design further by putting all the commands in a table and simplifying everything:


local trusted_id = 5 --# the id of the sending computer
local commands = {} --# a table holding all the commands as keys and their respective functions as values

command["MOVE_FORWARD"] = function () --# make a function with some logic inside
  if not turtle.detect() then
	turtle.forward()
  end
end

command["MOVE_BACK"] = turtle.back --# or simply assign one of the functions directly

while true do
  local id, message = rednet.receive()

  if id == trusted_id then
	local command = commands[message] --# get the command from the table

	if command then --# if there is a command
	  command() --# execute it
	end
  end
end

Of course, you may actually need to send custom code to the turtle, but from your example I figured you want to run pretty straight forward commands.

Instead of using IDs (= rednet) it would be a bit more secure to use the modem API and a "random" channel. If you want to go even further, you could use Diffie Hellman to find a private, random channel.
But, well ,this random channel could still be "bruteforced" as in using ~500 computers listening to all channels.
Edited on 22 July 2015 - 07:58 PM
HPWebcamAble #5
Posted 23 July 2015 - 07:26 AM
Instead of using IDs (= rednet) it would be a bit more secure to use the modem API and a "random" channel. If you want to go even further, you could use Diffie Hellman to find a private, random channel.
But, well ,this random channel could still be "bruteforced" as in using ~500 computers listening to all channels.

Err, wouldn't you only need one? Just open every channel and wait for a message?

Plus, someone would have to know about your program, its flaw, and have a motive to infiltrate it.


Though I agree its better to store functions locally and wait for a message to run them, rather than sending code around.
MKlegoman357 #6
Posted 23 July 2015 - 08:30 AM
Err, wouldn't you only need one? Just open every channel and wait for a message?

The maximum number of channels you can open on a single modem is 128, so you'd need a bunch of computers and modems to sniff all 65535 channels.
jerimo #7
Posted 23 July 2015 - 04:29 PM
Err, wouldn't you only need one? Just open every channel and wait for a message?

The maximum number of channels you can open on a single modem is 128, so you'd need a bunch of computers and modems to sniff all 65535 channels.
If the only commands you use are the turtle API calls, you could pass your input into it this way
turtle[input]()
Which would run any turtle cmand you sent it, without the need for expansive if statements
MKlegoman357 #8
Posted 23 July 2015 - 06:17 PM
If the only commands you use are the turtle API calls, you could pass your input into it this way
turtle[input]()
Which would run any turtle cmand you sent it, without the need for expansive if statements

My example code does pretty much the same thing, except rather than calling functions of the turtle API directly, letting you create your own commands and functions.
Dragon53535 #9
Posted 24 July 2015 - 08:59 AM
My example code does pretty much the same thing, except rather than calling functions of the turtle API directly, letting you create your own commands and functions.
True, however it is quite the simplest to just

if turtle[cmd] then turtle[cmd]() end
Of course you could expand that to ALSO allow extra functions, by combining the both ideas.

if turtle[cmd] then
  turtle[cmd]()
elseif tbl[cmd] then
  tbl[cmd]()
end
jerimo #10
Posted 24 July 2015 - 10:42 PM
If the only commands you use are the turtle API calls, you could pass your input into it this way
turtle[input]()
Which would run any turtle cmand you sent it, without the need for expansive if statements

My example code does pretty much the same thing, except rather than calling functions of the turtle API directly, letting you create your own commands and functions.
True, but as dragon pointed out its easier that way, and another perk is that if say the turtle API gets updated and gets new functions, the program still works with zero change, as you dint need to add an if statement into it.
If you wanted to add.more APIs you could also do

Function run(APIName, funcName)
if _G[APIName][funcName] then
_G[APIName][funcName]()
End
End
Which would allow you to use any function in any loaded API
Edited on 24 July 2015 - 08:42 PM
H4X0RZ #11
Posted 25 July 2015 - 02:24 AM
If the only commands you use are the turtle API calls, you could pass your input into it this way
turtle[input]()
Which would run any turtle cmand you sent it, without the need for expansive if statements

My example code does pretty much the same thing, except rather than calling functions of the turtle API directly, letting you create your own commands and functions.
True, but as dragon pointed out its easier that way, and another perk is that if say the turtle API gets updated and gets new functions, the program still works with zero change, as you dint need to add an if statement into it.
If you wanted to add.more APIs you could also do

Function run(APIName, funcName)
if _G[APIName][funcName] then
_G[APIName][funcName]()
End
End
Which would allow you to use any function in any loaded API
If you go this far, you should also add support for functions which are saved directly in _G.
Bomb Bloke #12
Posted 25 July 2015 - 03:39 AM
True, but as dragon pointed out its easier that way,

I wouldn't say it's "easier" - and I wouldn't say Dragon said that, either.

I mean, yeah, the code ends up shorter on the turtle's side, but as a result you need to send a lot more data over rednet to get the job done. Would you rather you just sent a "go forward" command and the turtle went forward, or would you rather that you had to send a "go forward" command, check on the result, send another command to make the turtle dig / attack if the movement failed, send another "go forward" command, etc, etc, etc…?

It's "easier" to handle such things locally, on the turtle itself. Granted, having both options (which is what Dragon is suggesting) is better again, but if I were going to choose between the two methods, I'd do the same as MKlegoman357.
Edited on 25 July 2015 - 01:40 AM
jerimo #13
Posted 25 July 2015 - 07:27 AM
True, but as dragon pointed out its easier that way,

I wouldn't say it's "easier" - and I wouldn't say Dragon said that, either.

I mean, yeah, the code ends up shorter on the turtle's side, but as a result you need to send a lot more data over rednet to get the job done. Would you rather you just sent a "go forward" command and the turtle went forward, or would you rather that you had to send a "go forward" command, check on the result, send another command to make the turtle dig / attack if the movement failed, send another "go forward" command, etc, etc, etc…?

It's "easier" to handle such things locally, on the turtle itself. Granted, having both options (which is what Dragon is suggesting) is better again, but if I were going to choose between the two methods, I'd do the same as MKlegoman357.
Why not just have a proper turtle API loaded up instead and use that? I've rarely if ever keptnthe standard turtle API I always end up replacing it as my needs and base hardware developed such as GPS and the such, which would render the if once again much more complex for no reason