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

File rollout server

Started by albrat, 11 July 2013 - 11:29 AM
albrat #1
Posted 11 July 2013 - 01:29 PM
I have been working on a file updating system to roll out on my computers…

I have not got a HTTP server connection so programs have to be hand typed on a computer then transfered using a disk drive (which had to be placed and removed every time as the computers are stand alone).

This system is intended to be automatic.

here is a pastebin link to the fileserver code

http://pastebin.com/Z0Ls2rbX

edit : To use the fileserver – you MUST create two folders ( - mkdir server / mkdir client - )
edit : Just to avoid confusion these two folders must be made on your file server


This is the pastebin for the client code

http://pastebin.com/rGuCZh8N

edit : my fileserver is id 1.. change your fileserver id in the file to match your fileservers id in your client code.

the client code runs the update, then after the final command "bt.eol" - end of list - it then runs a set of shell commands to delete itself, rename the update of itself to its own name, calls the startup file and exits with the error "File updates finished" you can even update the program that is running the updates!!

I built a file structure to be \\server\\ files and \\client\\ files

This currently only supports a client and server profile but expanding to more clients would be pretty easy.


My plands to use this on a multiplayer server mean that any computer can be installed as a client. (I have to write a server update script still. But it is basically the same but with "update_server" instead of "update_client" then it will pull the server update files from the server folder.)

I hope some people can find a use for this. (it helps to distribute new code easily)

(some of my files are 100's of lines of code, which would have meant a long rednet send message, hence I split by line) - not sure on the limits of a rednet message.
rhyleymaster #2
Posted 11 July 2013 - 01:45 PM
Not bad! (- the fact it floods rednet.)
Lyqyd #3
Posted 11 July 2013 - 02:09 PM
Send the whole file at once, don't send individual lines.
TheOddByte #4
Posted 12 July 2013 - 06:34 AM
As Lyqyd said don't send on line at a time…
I don't know how you are doing it but..
Here's how I would do it


repeat
filename = read()
until fs.exists(filename)

file = fs.open(filename,"r")
code = file.readAll()
file.close()

rID = 1337
rednet.send(rID,code)
This was just an example of how to send the full code directly
albrat #5
Posted 12 July 2013 - 07:05 AM
Fileserv - Updated code to send the whole file at once.
Spoiler

--[[  Fileserver - Senders call for a file update on the machine.
-- This machine responds with the files from within the
-- File server folder.
--]]
-- Local Vars
local serverdir = "\\server\\"
local clientdir = "\\client\\"

-- setup rednet
local sModemSide = nil
for n,sSide in ipairs(rs.getSides()) do
  if peripheral.getType(sSide) == "modem" then
	sModemSide = sSide
	break
  end
end
if sModemSide == nil then
  print("No wireless modem attached")
  return
end
rednet.open(sModemSide)
-- end setup rednet

--	 *************
--	 * Functions *
--	 *************
-- Sending file function
local function sendFile(filename, computerID, filedir)
local file = filedir .. filename
if not fs.exists(file) or fs.isDir(file) then
  print("File can't be sent!")
  print("It is either non existant or is a directory!")
  return false
end

computerID = tonumber(computerID)

local sr = fs.open(file, "r")
print("Connecting")

while true do
  rednet.send(computerID, "bt.con")
  os.startTimer(1)
  local e,p1,p2,p3 = os.pullEvent()
  if e == "rednet_message" then
   local id,msg = p1,p2
   if msg == "bt.acc" then
	print("connected!")
	break
   end
  end
end

sleep(0.8)
rednet.send(computerID, "bt.fn:" .. filename)

sleep(0.5)

print("Sending...")
local data
--while true do
  data = textutils.serialize(sr.readAll())
  print (data)
--  if data == nil then
--   break
--  end
  rednet.send(computerID, "bt.file:" .. data)
  sleep(0.8)
--end
rednet.send(computerID, "bt.done")
print("File sent!")
end

-- Check if folder exists --
function FolderExists(strFolderName)
local fileHandle = fs.isDir(strFolderName)
if fileHandle == false then
  return false
else
  return true
end
end
-- function get Dir listing
function Dirlist(folder)
local list = fs.list(folder)
return list
end
-- Sending of Programs funct
local args = {}
function Sendprogs( list, directory, cmpId, ... )
  args = ( ... )
  if type(list) ~= "table" then
	return false
  else
	for i = 1,#list do
  err = sendFile(list[i], cmpId)
end
  end

end
-- one time grab of the directory on boot up
-- Main program
while true do
id,msg = "",""
id, msg = rednet.receive(0.8)
if msg == "update_client" then
  list = Dirlist(clientdir)
  print("Client update starting")
  for i = 1,#list do
   sendFile(list[i], id, clientdir)
  end
elseif msg == "update_server" then
  list = Dirlist(serverdir)
  print("Server update starting")
  for i = 1,#list do
   sendFile(list[i], id, serverdir)
  end
end
rednet.send(id, "bt.eol")
end
--[[

err = Sendprogs( list, filedir, cmpId )
--]]
-- EOF.

Updated code for the fileupdate program.

Spoiler

-- File Updater Program
-- Varibles
local filesrv = 1  -- Your update server ID.
local cmptype = "client"
-- setup rednet
local sModemSide = nil
for n,sSide in ipairs(rs.getSides()) do
  if peripheral.getType(sSide) == "modem" then
	sModemSide = sSide
	break
  end
end
if sModemSide == nil then
  print("No wireless modem attached")
  return
end
rednet.open(sModemSide)
-- end setup rednet

-- *************
-- * Functions *
-- *************
-- Receive File.
local function receiveFile()
shell.run("id")
print("Waiting for a bt connection...")
rednet.send(filesrv,"update_client")

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

  if msg == "bt.eol" then printError("Finished file update") shell.run("delete fileupdate") shell.run("rename fileupdater fileupdate") shell.run("startup") error() end
   if msg == "bt.con" then
	print("Connected to " .. id .. "!")
	local remoteID = id
	rednet.send(id, "bt.acc")
  
	local fileName
  
	print("Getting the file name...")
  
	local id,msg = "",""
	while true do
	 id,msg = rednet.receive()
	
	 if id == remoteID and string.sub(msg, 1, #"bt.fn:") == "bt.fn:" then
	  fileName = string.sub(msg, #"bt.fn:" + 1)
	  break
	 end
	end

	if fs.exists(fileName) then
	 print("File already exists, Deleting old file... " .. fileName)
	 fs.delete(fileName)
	end
  
	print("Receiving file: " .. fileName)
  
	local file = fs.open(fileName, "w")

	local id,msg

	while true do
	 id,msg = rednet.receive()
	 if id == remoteID then
	  if string.sub(msg, 1, #"bt.file:") == "bt.file:" then
	   local subbedData = textutils.unserialize(string.sub(msg, #"bt.file:" + 1))
	
	   if term.isColor() then
		term.setTextColor(colors.lightBlue)
	   end
	  
	   file.writeLine(subbedData)
	  elseif msg == "bt.done" then
	   file.flush()
	   file.close()
	
	   if term.isColor() then
		term.setTextColor(colors.white)
	   end
	   print("Received file!")
	
	   break
	  end
	 end
	end
   end
end
end
-- Main Program
print("updating files")
receiveFile()

In the fileserv file, I changed the io.open to fs.open and file.read() to textutils.serialize(file.readAll()) ..
then commented out the while loop and check for data == nil / loop break command, as I removed the loop to receive sections of data.

In the fileupdate program I changed the local subbedData = string.sub(msg, #"bt.file:" + 1) to "local subbedData = textutils.unserialize(string.sub(msg, #"bt.file:" + 1))" voila works to copy and write the new files. 1 send instead of each line sending. ( much faster ).