Advertisement
LDDestroier

Disknet (computercraft)

Aug 25th, 2020
1,663
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.63 KB | None | 0 0
  1. local disknet = {}
  2.  
  3. local tArg = {...}
  4.  
  5. disknet.mainPath = "disk/DISKNET"   -- path of shared file
  6. local limitChannelsToModem = false  -- if true, can only use number channels from 1 to 65535
  7. local checkDelay = 0.05             -- amount of time (seconds) between checking the file -- if 0, checks super fast so don't do that
  8. local maximumBufferSize = 64        -- largest amount of messages per channel buffered
  9.  
  10. local isUsingTweaked = false
  11. if _HOST then
  12.     if _HOST:find("CCEmuX") or _HOST:find("CC:Tweaked") then
  13.         isUsingTweaked = true
  14.     end
  15. end
  16.  
  17. local openChannels = {}
  18. local yourID = os.getComputerID()
  19. local uniqueID = math.random(1, 2^31 - 1) -- prevents receiving your own messages
  20. local msgCheckList = {} -- makes sure duplicate messages aren't received
  21. local ageToToss = 0.005 -- amount of time before a message is removed
  22.  
  23. --  used for synching times between different emulators
  24. disknet._timeMod = 0
  25.  
  26. -- do not think for one second that os.epoch("utc") would be a proper substitute
  27. local getTime = function()
  28.     return (os.time() + (-1 + os.day()) * 24) + disknet._timeMod
  29. end
  30.  
  31. local function serialize(tbl)
  32.     local output = "{"
  33.     local noKlist = {}
  34.     local cc = table.concat
  35.     for i = 1, #tbl do
  36.         if type(tbl[i]) == "table" then
  37.             output = output .. serialize(tbl[i])
  38.         elseif type(tbl[i]) == "string" then
  39.             output = cc({output, "\"", tbl[i], "\""})
  40.         else
  41.             output = output .. tbl[i]
  42.         end
  43.         noKlist[i] = true
  44.         output = output .. ","
  45.     end
  46.     for k,v in pairs(tbl) do
  47.         if not noKlist[k] then
  48.             if type(k) == "number" or type(k) == "table" then
  49.                 output = cc({output, "[", k, "]="})
  50.             else
  51.                 output = cc({output, k, "="})
  52.             end
  53.             if type(v) == "table" then
  54.                 output = output .. serialize(v)
  55.             elseif type(v) == "string" then
  56.                 output = cc({output, "\"", v, "\""})
  57.             else
  58.                 output = output .. v
  59.             end
  60.             output = output .. ","
  61.         end
  62.     end
  63.     return output:sub(1, -2):gsub("\n", "\\n") .. "}"
  64. end
  65.  
  66. local readFile = function(path)
  67.     local file = fs.open(path, "r")
  68.     local contents = file.readAll()
  69.     file.close()
  70.     return contents
  71. end
  72.  
  73. local writeFile = function(path, contents)
  74.     local file = fs.open(path, "w")
  75.     file.write(contents)
  76.     file.close()
  77. end
  78.  
  79. -- if 'limitChannelsToModem', then will make sure that channel is a number between 0 and 65535
  80. local checkValidChannel = function(channel)
  81.     if limitChannelsToModem then
  82.         if type(channel) == "number" then
  83.             if channel < 0 or channel > 65535 then
  84.                 return false, "channel must be between 0 and 65535"
  85.             else
  86.                 return true
  87.             end
  88.         else
  89.             return false, "channel must be number"
  90.         end
  91.     else
  92.         if type(channel) == "string" or type(channel) == "number" then
  93.             return true
  94.         else
  95.             return false, "channel must be castable to string"
  96.         end
  97.     end
  98. end
  99.  
  100. disknet.isOpen = function(channel)
  101.     local valid, grr = checkValidChannel(channel)
  102.     if valid then
  103.         for i = 1, #openChannels do
  104.             if openChannels[i] == channel then
  105.                 return true
  106.             end
  107.         end
  108.         return false
  109.     else
  110.         error(grr)
  111.     end
  112. end
  113.  
  114. disknet.open = function(channel)
  115.     local valid, grr = checkValidChannel(channel)
  116.     if valid then
  117.         openChannels[#openChannels + 1] = channel
  118.         return true
  119.     else
  120.         error(grr)
  121.     end
  122. end
  123.  
  124. disknet.close = function(channel)
  125.     local valid, grr = checkValidChannel(channel)
  126.     if valid then
  127.         for i = 1, #openChannels do
  128.             if openChannels[i] == channel then
  129.                 table.remove(openChannels, i)
  130.                 return true
  131.             end
  132.         end
  133.         return false
  134.     else
  135.         error(grr)
  136.     end
  137. end
  138.  
  139. disknet.closeAll = function()
  140.     openChannels = {}
  141. end
  142.  
  143. disknet.send = function(channel, message, recipient)
  144.     local valid, grr = checkValidChannel(channel)
  145.     if valid then
  146.         if not fs.exists(fs.combine(disknet.mainPath, tostring(channel))) then
  147.             fs.open(fs.combine(disknet.mainPath, tostring(channel)), "w").close()
  148.         end
  149.         local contents = textutils.unserialize(readFile(fs.combine(disknet.mainPath, tostring(channel))))
  150.         local cTime = getTime()
  151.         if disknet.isOpen(channel) then
  152.             local file = fs.open(fs.combine(disknet.mainPath, tostring(channel)), "w")
  153.             if contents then
  154.                 contents[#contents + 1] = {
  155.                     time = cTime,
  156.                     id = yourID,
  157.                     uniqueID = uniqueID,
  158.                     messageID = math.random(1, 2^31 - 1),
  159.                     channel = channel,
  160.                     recipient = recipient,
  161.                     message = message,
  162.                 }
  163.                 for i = #contents, 1, -1 do
  164.                     if cTime - (contents[i].time or 0) > ageToToss then
  165.                         table.remove(contents, i)
  166.                     end
  167.                 end
  168.                 if #contents > maximumBufferSize then
  169.                     table.remove(contents, 1)
  170.                 end
  171.                 file.write(serialize(contents))
  172.             else
  173.                 file.write(serialize({{
  174.                     time = cTime,
  175.                     id = yourID,
  176.                     uniqueID = uniqueID,
  177.                     messageID = math.random(1, 2^31 - 1),
  178.                     channel = channel,
  179.                     message = message,
  180.                 }}):gsub("\n[ ]*", ""))
  181.             end
  182.             file.close()
  183.             return true
  184.         else
  185.             return false
  186.         end
  187.     else
  188.         error(grr)
  189.     end
  190. end
  191.  
  192. local fList, pList, sList = {}, {}, {}
  193.  
  194. local loadFList = function()
  195.     fList, pList = {}, {}
  196.     if channel then
  197.         fList = {fs.open(fs.combine(disknet.mainPath, tostring(channel)), "r")}
  198.         pList = {fs.combine(disknet.mainPath, tostring(channel))}
  199.     else
  200.         for i = 1, #openChannels do
  201.             fList[i] = fs.open(fs.combine(disknet.mainPath, tostring(openChannels[i])), "r")
  202.             pList[i] = fs.combine(disknet.mainPath, tostring(openChannels[i]))
  203.         end
  204.     end
  205. end
  206.  
  207. disknet.receive = function(channel, senderFilter)
  208.     local valid, grr = checkValidChannel(channel)
  209.     if valid or not channel then
  210.  
  211.         local output, contents
  212.         local doRewrite = false
  213.  
  214.         local good, goddamnit = pcall(function()
  215.             local cTime = getTime()
  216.             local goWithIt = false
  217.             while true do
  218.                 loadFList()
  219.                 for i = 1, #fList do
  220.                     contents = fList[i].readAll()
  221.                     if contents ~= "" then
  222.                         contents = textutils.unserialize(contents)
  223.                         if type(contents) == "table" then
  224.                             if contents[1] then
  225.                                 if not output then
  226.                                     for look = 1, #contents do
  227.                                         if (contents[look].uniqueID ~= uniqueID) and (not msgCheckList[contents[look].messageID]) then  -- make sure you're not receiving messages that you sent
  228.                                             if (not contents[look].recipient) or contents[look].recipient == yourID then                -- make sure that messages intended for others aren't picked up
  229.                                                 if (not channel) or channel == contents[look].channel then                              -- make sure that messages are the same channel as the filter, if any
  230.                                                     if (not senderFilter) or senderFilter == contents[look].id then                     -- make sure that the sender is the same as the id filter, if any
  231.                                                         if (not isUsingTweaked) and math.abs(contents[look].time - getTime()) >= ageToToss then     -- if using something besides CC:Tweaked/CCEmuX, adjust your time.
  232.                                                             disknet._timeMod = contents[look].time - getTime()
  233.                                                             cTime = getTime()
  234.                                                             goWithIt = true
  235.                                                         end
  236.                                                         if cTime - (contents[look].time or 0) <= ageToToss or goWithIt then                     -- make sure the message isn't too old
  237.                                                             msgCheckList[contents[look].messageID] = true
  238.                                                             output = {}
  239.                                                             for k,v in pairs(contents[look]) do
  240.                                                                 output[k] = v
  241.                                                             end
  242.                                                             break
  243.                                                         end
  244.                                                     end
  245.                                                 end
  246.                                             end
  247.                                         end
  248.                                     end
  249.                                 end
  250.  
  251.                                 -- delete old msesages
  252.                                 doRewrite = false
  253.                                 for t = #contents, 1, -1 do
  254.                                     if cTime - (contents[t].time or 0) > ageToToss or cTime - (contents[t].time or 0) < -1 then
  255.                                         msgCheckList[contents[t].messageID] = nil
  256.                                         table.remove(contents, t)
  257.                                         doRewrite = true
  258.                                     end
  259.                                 end
  260.                                 if doRewrite then
  261.                                     writeFile(pList[i], serialize(contents))
  262.                                 end
  263.                                 if output then
  264.                                     break
  265.                                 end
  266.                             end
  267.                         end
  268.                     end
  269.                 end
  270.                 if output then
  271.                     break
  272.                 else
  273.                     if checkDelay > 0 then
  274.                         sleep(checkDelay)
  275.                     else
  276.                         os.queueEvent("")
  277.                         os.pullEvent("")
  278.                     end
  279.                 end
  280.                 for i = 1, #fList do
  281.                     fList[i].close()
  282.                 end
  283.                 fList, pList = {}, {}
  284.             end
  285.         end)
  286.  
  287.         if good then
  288.             if contents then
  289.                 return output.message, output.channel, output.id, output.time + disknet._timeMod
  290.             else
  291.                 return nil
  292.             end
  293.         else
  294.             for i = 1, #fList do
  295.                 fList[i].close()
  296.             end
  297.             error(goddamnit, 0)
  298.         end
  299.     else
  300.         error(grr)
  301.     end
  302. end
  303.  
  304. -- not really needed if going between CCEmuX and another emulator, but may be needed between two separate CCEmuX daemons
  305. disknet.receive_TS = function(...)
  306.     local message, channel, id, time = disknet.receive(...)
  307.     if time then
  308.         disknet._timeMod = time - getTime()
  309.     end
  310.     return message, channel, id, time
  311. end
  312.  
  313. return disknet
  314.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement