Advertisement
Tag365

98_serverfilesystem.lua

Feb 14th, 2016
1,884
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.28 KB | None | 0 0
  1. ------------------------------
  2. -- Server Filesystem Script --
  3. ------------------------------
  4. -- Configuration --
  5. local timeoutPeriod = 10
  6. local useTunnelOverModem = true
  7. local autoMountServerFS = true
  8. local activateServerFSModule = true
  9. local virtualizeServerFSComponent = true
  10. local throwSoftErrors = false
  11.  
  12. -- Modules
  13. local computer = require("computer")
  14. local component = require("component")
  15. local serialization = require("serialization")
  16. local event = require("event")
  17. local filesystem = require("filesystem")
  18.  
  19. -- Set up the server filesystem component --
  20. local serverFS = {
  21.     type = "filesystem",
  22.     address = "0000-remoteFS"
  23. }
  24. local functionList = {
  25.     "spaceTotal", "spaceUsed", "spaceFree", "getLabel", "setLabel", "isReadOnly",
  26.     "exists", "isDirectory", "size", "lastModified", "list",
  27.     "rename", "remove", "makeDirectory",
  28.     "open", "close", "read", "write", "seek",
  29. }
  30. local functionHelp = {
  31.     spaceUsed = "function():number -- The currently used capacity of the file system, in bytes.",
  32.     spaceFree = "function():number -- The current amount of free space on the file system, in bytes.",
  33.     open = "function(path:string[, mode:string='r']):number -- Opens a new file descriptor and returns its handle.",
  34.     seek = "function(handle:number, whence:string, offset:number):number -- Seeks in an open file descriptor with the specified handle. Returns the new pointer position.",
  35.     makeDirectory = "function(path:string):boolean -- Creates a directory at the specified absolute path in the file system. Creates parent directories, if necessary.",
  36.     exists = "function(path:string):boolean -- Returns whether an object exists at the specified absolute path in the file system.",
  37.     isReadOnly = "function():boolean -- Returns whether the file system is read-only.",
  38.     write = "function(handle:number, value:string):boolean -- Writes the specified data to an open file descriptor with the specified handle.",
  39.     spaceTotal = "function():number -- The overall capacity of the file system, in bytes.",
  40.     isDirectory = "function(path:string):boolean -- Returns whether the object at the specified absolute path in the file system is a directory.",
  41.     rename = "function(from:string, to:string):boolean -- Renames/moves an object from the first specified absolute path in the file system to the second.",
  42.     list = "function(path:string):table -- Returns a list of names of objects in the directory at the specified absolute path in the file system.",
  43.     lastModified = "function(path:string):number -- Returns the (real world) timestamp of when the object at the specified absolute path in the file system was modified.",
  44.     getLabel = "function():string -- Get the current label of the file system.",
  45.     remove = "function(path:string):boolean -- Removes the object at the specified absolute path in the file system.",
  46.     close = "function(handle:number) -- Closes an open file descriptor with the specified handle.",
  47.     size = "function(path:string):number -- Returns the size of the object at the specified absolute path in the file system.",
  48.     read = "function(handle:number, count:number):string or nil -- Reads up to the specified amount of data from an open file descriptor with the specified handle. Returns nil when EOF is reached.",
  49.     setLabel = "function(value:string):string -- Sets the label of the file system. Returns the new value, which may be truncated.",
  50. }
  51.  
  52. -- Build the serverFS component module --
  53. local lastCall = computer.uptime()
  54. for key, value in ipairs(functionList) do
  55.     serverFS[value] = setmetatable({}, {
  56.         __call = function(self, ...)
  57.             if computer.uptime() - lastCall < .7 then
  58.                 os.sleep(.7 - (computer.uptime() - lastCall))
  59.             end
  60.             lastCall = computer.uptime()
  61.             local foundModem, modem = pcall(component.getPrimary, "modem")
  62.             local foundTunnel, tunnel = pcall(component.getPrimary, "tunnel")
  63.            
  64.             -- If the function errored then the modem has not been found and is just an error message.
  65.             if not foundModem then modem = nil end
  66.             if not foundTunnel then tunnel = nil end
  67.            
  68.             -- Try to find a tunnel or modem to use if no primary component is set.
  69.             if not (modem or tunnel) then
  70.                 for address, componentType in component.list() do
  71.                     if componentType == "modem" and not modem then
  72.                         modem = component.proxy(address)
  73.                     elseif componentType == "tunnel" and not tunnel then
  74.                         tunnel = component.proxy(address)
  75.                     end
  76.                 end
  77.             end
  78.            
  79.             -- Determine if we want to use the modem or tunnel.
  80.             if (tunnel and modem and useTunnelOverModem) or (tunnel and (not modem)) then
  81.                 -- Use the tunnel
  82.                 tunnel.send(serialization.serialize({value, ...}))
  83.                 while true do
  84.                     local messageRecieved, address, from, port, _, message = event.pull(timeoutPeriod, "modem_message")
  85.                     if not messageRecieved then
  86.                         return false, "The request timed out. The server may not be online or is handling too many requests."
  87.                     end
  88.                     if address == tunnel.address then
  89.                         local args = serialization.unserialize(message)
  90.                         if args[1] == true then
  91.                             table.remove(args, 1)
  92.                         else
  93.                             if throwSoftErrors then
  94.                                 return false, args[2]
  95.                             else
  96.                                 error(args[1], 2)
  97.                             end
  98.                         end
  99.                         for key, value in pairs(args) do
  100.                             if tonumber(value) then
  101.                                 args[key] = tonumber(value)
  102.                             elseif value == "true" then
  103.                                 args[key] = true
  104.                             elseif value == "false" then
  105.                                 args[key] = false
  106.                             end
  107.                         end
  108.                         return table.unpack(args)
  109.                     end
  110.                 end
  111.             elseif (modem) then
  112.                 -- Use the modem
  113.                 local isOpenBeforeThisRequest = modem.isOpen(280)
  114.                 modem.open(280)
  115.                 modem.broadcast(300, serialization.serialize({value, ...}))
  116.                 while true do
  117.                     local messageRecieved, _, from, port, _, message = event.pull(timeoutPeriod, "modem_message")
  118.                     if not messageRecieved then
  119.                         return false, "The request timed out. The server may not be online or is handling too many requests."
  120.                     end
  121.                     if port == 280 then
  122.                         local args = serialization.unserialize(message)
  123.                         if args[1] == true then
  124.                             table.remove(args, 1)
  125.                         else
  126.                             if throwSoftErrors then
  127.                                 return false, args[2]
  128.                             else
  129.                                 error(args[1], 2)
  130.                             end
  131.                         end
  132.                         for key, value in pairs(args) do
  133.                             if tonumber(value) then
  134.                                 args[key] = tonumber(value)
  135.                             elseif value == "true" then
  136.                                 args[key] = true
  137.                             elseif value == "false" then
  138.                                 args[key] = false
  139.                             end
  140.                         end
  141.                         return table.unpack(args)
  142.                     end
  143.                 end
  144.                 if not isOpenBeforeThisRequest then -- Close it again if it was closed before we called this request
  145.                     modem.close(280)
  146.                 end
  147.             else
  148.                 -- No primary tunnel or modem found.
  149.                 if throwSoftErrors then
  150.                     return false, "No tunnel or modem found. Please insert a tunnel or modem component, then try again."
  151.                 else
  152.                     error("No tunnel or modem found. Please insert a tunnel or modem component, then try again.", 2)
  153.                 end
  154.             end
  155.         end,
  156.         __tostring = functionHelp[value] or "function()",
  157.     })
  158. end
  159.  
  160. -- Mount this filesystem --
  161. if autoMountServerFS then
  162.     local success, errorMessage = filesystem.mount(serverFS, "srv")
  163.     if not success then
  164.         io.stderr:write("Failed to mount server: "..tostring(errorMessage).."\n")
  165.     end
  166. end
  167.  
  168. -- Add this to the loaded modules --
  169. if activateServerFSModule then
  170.     package.loaded["serverFS"] = serverFS
  171. end
  172.  
  173. -- Insert the virtual serverFS component to the component API --
  174. if virtualizeServerFSComponent then
  175.     pcall(function()
  176.         local component = require("component")
  177.         local serverFS = serverFS
  178.         if not serverFS then
  179.             serverFS = require("serverFS")
  180.         end
  181.  
  182.         local oldDoc = component.doc
  183.         local oldList = component.list
  184.         local oldProxy = component.proxy
  185.         local oldInvoke = component.invoke
  186.         local oldMethods = component.methods
  187.         local oldType = component.type
  188.  
  189.         local sfsAddress = serverFS.address
  190.  
  191.         function component.doc(address, method)
  192.             if address == sfsAddress then
  193.                 return tostring(serverFS[method])
  194.             end
  195.             return oldDoc
  196.         end
  197.         function component.list(filter, exact)
  198.             if type(filter) == "string" then
  199.                 if (exact and filter == "filesystem") or (not exact and filter:find(("filesystem"):sub(1, #filter))) then
  200.                     local realItems = {}
  201.                     for x, y in oldList(filter, exact or false) do
  202.                         realItems[x] = y
  203.                     end
  204.                     realItems[sfsAddress] = serverFS.type
  205.                     local ilterator = function()
  206.                         for x, y in pairs(realItems) do
  207.                             coroutine.yield(x, y)
  208.                         end
  209.                     end
  210.                     return coroutine.wrap(ilterator)
  211.                 end
  212.                 return oldList(filter, exact)
  213.             end
  214.             return oldList(filter, exact)
  215.         end
  216.         function component.proxy(address)
  217.             if address == sfsAddress then
  218.                 return serverFS
  219.             end
  220.             return oldProxy(address)
  221.         end
  222.         function component.invoke(address, funct, ...)
  223.             if address == sfsAddress then
  224.                 return serverFS[funct](...)
  225.             end
  226.             return oldInvoke(address, funct, ...)
  227.         end
  228.         function component.methods(address)
  229.             if address == sfsAddress then
  230.                 local functions = {}
  231.                 for key, value in pairs(serverFS) do
  232.                     if type(value) == "function" then
  233.                         functions[key] = false
  234.                     end
  235.                 end
  236.                 return functions
  237.             end
  238.             return oldMethods(address)
  239.         end
  240.         function component.type(address)
  241.             if address == sfsAddress then
  242.                 return "filesystem"
  243.             end
  244.             return oldType(address)
  245.         end
  246.     end)
  247. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement