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

sending programs over rednet

Started by dcleondc, 17 October 2012 - 11:29 PM
dcleondc #1
Posted 18 October 2012 - 01:29 AM
hey im on my server and i want to send a program to another computer over rednet. How do i do it?
lieudusty #2
Posted 18 October 2012 - 01:54 AM
Simple!
You will need to use fs or io to read the file then send it through rednet. Check the fs section of the wiki.
Kingdaro #3
Posted 18 October 2012 - 01:57 AM
I have a solution, though it's probably not the best way of doing it. (because of how the rednet string would be absolutely massive, lol. but I'm not sure if that actually matters.)

You would first take the program on the first computer that you want to send to the other and read it's contents with the fs library, then throw it in a table, serialize it, and send it.

local program
local recipient

-- keep going until the user has entered in a valid program
while true do
  print 'Program name?'
  program = read()

  if fs.exists(program) then
    break
  else
    print 'Program does not exist.'
  end
end

-- keep going until input is a valid number.
while true do
  print 'Recipient ID?'
  recipient = tonumber(read())

  if recipient then
    break
  else
    print 'Invalid number.'
  end
end

-- prepare data
local file = fs.open(program, 'r')
local data = textutils.serialize {
  cmd = 'getfile',
  program = program,
  content = file:readAll()
}
file:close()

-- send the data.
rednet.send(recipient, data)

Now on your computer receiving the program, you'll want to have this program open. It loops until it has valid data, then writes the data's content to the specified program name.

print 'Waiting for data...'

while true do
  local _, data = textutils.unserialize(rednet.receive())

  -- we have to be SUPER EXTRA CAREFUL so that we dont crash
  -- on bad data.
  if data and data.cmd and data.cmd == 'getfile' then
    -- write our received program! :P/>/>
    print 'Data received. Writing program.'
    local file = fs.open(data.program, 'w')
    file:write(data.content)
    file:close()
    print 'Done.'
    break
  end
end
ChunLing #4
Posted 18 October 2012 - 06:42 AM
There is no need to use textutils.un/serialize. The lua files are stored as text. You can simply send the entire thing as a single string in a rednet message. The receive file function looks like this:
local function rcvfl(flnm,sndrID)
    repeat cldt = {rednet.receive()} until cldt[1] == sndrID
    local flbdy = fs.open(flnm,"w") flbdy.write(cldt[3]) flbdy.close()
end
The send file function looks like this:
local function srvfl(flnm,rcvrID)
    local flbdy = fs.open(flnm,"r")
    rednet.send(rcvrID,flbdy.readAll()) flbdy.close()
end
In both cases, the argument "flnm" is the name of the file, and sndr/rcvrID the ID of the other computer.
If you needed to send a binary file over rednet, then you would need to turn the file into some kind of non-string representation using textutils (and decode it on the other end). But lua programs are stored entirely as text, so they fit fine into rednet messages.
remiX #5
Posted 18 October 2012 - 09:14 AM
Just go over the pastebin api file. I learnt how to do this from there mainly.
Kingdaro #6
Posted 18 October 2012 - 02:44 PM
There is no need to use textutils.un/serialize. The lua files are stored as text. You can simply send the entire thing as a single string in a rednet message. The receive file function looks like this:
local function rcvfl(flnm,sndrID)
	repeat cldt = {rednet.receive()} until cldt[1] == sndrID
	local flbdy = fs.open(flnm,"w") flbdy.write(cldt[3]) flbdy.close()
end
The send file function looks like this:
local function srvfl(flnm,rcvrID)
	local flbdy = fs.open(flnm,"r")
	rednet.send(rcvrID,flbdy.readAll()) flbdy.close()
end
In both cases, the argument "flnm" is the name of the file, and sndr/rcvrID the ID of the other computer.
If you needed to send a binary file over rednet, then you would need to turn the file into some kind of non-string representation using textutils (and decode it on the other end). But lua programs are stored entirely as text, so they fit fine into rednet messages.
The problem with this is that if the program doesn't know that it's a file that was sent to them by another computer that it's supposed to "download", it'll just pick up any old rednet broadcast and close before its ready, nor does it know the name/path of the file it's supposed to save it as. It's not enough to just check if the sender ID is correct because you might want to send a file from another computer.

I like to take these kinds of precautions, even in single player.

Though it is true that one could accomplish this sort of thing without serialization, I just find it easier and more convenient to do than doing something like using :match() to interpret incoming string commands.
ChunLing #7
Posted 18 October 2012 - 06:12 PM
Um…yes, the function I provided does provide the file path as one of the arguments, it won't work without that argument. And while it is true that, if you open a computer to receive a file from another computer, and then send a message that you do not mean to be the file, it will save the message as the file, there is absolutely no way to make this impossible in principle. The point of sending/receiving a file is that the receiver does not already know what the file is.

As for how using serialize avoids either of these problems, I'm open to learning. But I doubt it does.
Kingdaro #8
Posted 18 October 2012 - 06:19 PM
That's exactly what I did. In my serialized table, I provided an argument called "cmd" with the value "getfile", while the receiver checks for that cmd argument with the value "getfile" and will disregard the rednet signal otherwise.
ChunLing #9
Posted 18 October 2012 - 06:48 PM
Just to be clear, that doesn't actually have anything to do with using serialize. Serialize is just how you organized an additional layer of error checking. Which is fine, but it is not different in principle from simply checking to make sure that the message is from the correct sender. Or rather, the way in which it differs in principle is that it is far easier to 'spoof' than the sender ID.

I'm not trying to pick a fight here. It's just that what you claimed is potentially misleading. I provided the simplest functions that would get the job done in reasonably reliable manner. I realize that this differed from your approach of providing two essentially complete programs. I'm not saying that your approach is wrong, but I do believe that it can be helpful to provide the simple solution that confines itself to the direct query. The question was how to send/receive a text file (specifically, one containing a lua program). Information on how to prevent erroneous receipt may be useful, but is a slightly different issue.
Kingdaro #10
Posted 18 October 2012 - 08:56 PM
I agree, though it can't hurt to teach the OP a few safecheck techniques, or different ways of approaching the problem.
ChunLing #11
Posted 19 October 2012 - 03:00 AM
Eh…maybe it could? No, I think that teaching error catching is fine.
willifolts #12
Posted 07 March 2013 - 08:42 AM
I am having a little problem. I typed in your code EXACTLY into my computer, and lua is attempting to call nil on line 30. help?
Lyqyd #13
Posted 07 March 2013 - 08:45 AM
Whose code? What is line 30?
willifolts #14
Posted 08 March 2013 - 01:33 AM
I am using Kingdaro's code for his email system. I typed it up exactly into a program, and line 30:

content = file:readAll()
Is giving me an error. It is saying that a string is needed.
GravityScore #15
Posted 08 March 2013 - 01:37 AM
I am using Kingdaro's code for his email system. I typed it up exactly into a program, and line 30:

content = file:readAll()
Is giving me an error. It is saying that a string is needed.

It needs to be file.readAll(). Replace the : with a .

Also needs to be done in file:close(), again, the : should be a .
willifolts #16
Posted 08 March 2013 - 02:28 AM
Done, but its not still not working. This is the error I am getting: send:30: attempt to call nil
remiX #17
Posted 08 March 2013 - 02:53 AM
Post the code you're using, and don't say that you're just using Kingdaro's code because you would have made changes