Advertisement
PaymentOption

Ports API

Oct 1st, 2012
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.60 KB | None | 0 0
  1. --==============================================================
  2. --
  3. --                                      Trystan Cannon
  4. -- Ports API for Lieu                   10/1/12
  5. --                                      ccnet.ddns.me
  6. --
  7. -- This API allows for the opening and closing of virtual ports
  8. -- that act as buffers between incoming rednet messages.
  9. --==============================================================
  10.  
  11. -- Opens all of the available ports in the port config file.
  12. function openAllPorts()
  13.     local tPorts = loadPorts()
  14.  
  15.     for nPortIndex, tPortTable in ipairs(tPorts) do
  16.         changePortStatus(tPortTable.nPort, true)
  17.     end
  18. end
  19.  
  20. -- Closes all of the available ports in the port config file.
  21. function closeAllPorts()
  22.     local tPorts = loadPorts()
  23.  
  24.     for nPortIndex, tPortTable in ipairs(tPorts) do
  25.         changePortStatus(tPortTable.nPort, false)
  26.     end
  27. end
  28.  
  29. -- Appends the status of a port, or adds a new port with the passed status to the config file.
  30. function changePortStatus(nPort, bOpen)
  31.     -- Function borrowed from: http://lua-users.org/wiki/SplitJoin
  32.     local function split(str, pat)
  33.        local t = {}  -- NOTE: use {n = 0} in Lua-5.0
  34.        local fpat = "(.-)" .. pat
  35.        local last_end = 1
  36.        local s, e, cap = str:find(fpat, 1)
  37.        while s do
  38.           if s ~= 1 or cap ~= "" then
  39.          table.insert(t,cap)
  40.           end
  41.           last_end = e+1
  42.           s, e, cap = str:find(fpat, last_end)
  43.        end
  44.        if last_end <= #str then
  45.           cap = str:sub(last_end)
  46.           table.insert(t, cap)
  47.        end
  48.        return t
  49.     end
  50.  
  51.     if not fs.isDir(".portConfig") then
  52.         local sNewState = "" -- The new state of the port to be appended to the config file.
  53.         if bOpen then
  54.             sNewState = "open"
  55.         else
  56.             sNewState = "closed"
  57.         end
  58.  
  59.         local tPorts = loadPorts()
  60.         local nPortID_InTable = nil -- If the port already exists in the port table, this will be its index in the table.
  61.         if #tPorts > 0 then
  62.             nPortID_InTable = checkIfPortExists(nPort, tPorts)
  63.         end
  64.  
  65.         -- Open the file, get its contents, then separate all of the lines in the file into a table.
  66.             local portConfigFile = fs.open(".portConfig", "r")
  67.             local sPortFileContents = portConfigFile.readAll()
  68.             portConfigFile.close()
  69.  
  70.             local tLines = split(sPortFileContents, '\n')
  71.         -- If the port already exists as an entry in the port table, open it via its current entry.
  72.         if nPortID_InTable then
  73.             -- Now that we have all of the lines split into a table, append our entry, then repackage the table into the file.
  74.             local nColonPosition = tostring(nPort):len() + 1 -- This is the position of the colon in the entry.
  75.             tLines[nPortID_InTable] = tLines[nPortID_InTable]:sub(1, nColonPosition) .. sNewState
  76.         -- If the port does not already exist, then add it to the table and repackage the file.
  77.         else
  78.             tLines[#tLines+1] = nPort .. ":" .. sNewState
  79.         end
  80.  
  81.         -- Repackage the table into the file.
  82.         portConfigFile = fs.open(".portConfig", "w")
  83.         for nLine = 1, #tLines do
  84.             portConfigFile.writeLine(tLines[nLine])
  85.         end
  86.         portConfigFile.close()
  87.  
  88.         return true
  89.     else
  90.         error("Port config file cannot be a directory.")
  91.     end
  92. end
  93.  
  94. -- Checks if the passed port exists in the port table.
  95. -- IF it does, then it returns the index of the passed port in the port table.
  96. -- ELSE, then it returns nil.
  97. function checkIfPortExists(nPort, tPorts)
  98.     for nPortIndex, tPortTable in ipairs(tPorts) do
  99.         if tPortTable.nPort == nPort then
  100.             return nPortIndex
  101.         end
  102.     end
  103.  
  104.     return nil
  105. end
  106.  
  107. -- Checks if the passed port is open in the most recently loaded ports table.
  108. -- IF the port is open, returns true.
  109. -- IF the port is not open OR the port doesn't exist, returns false.
  110. function checkIfPortIsOpen(nPort, tPorts)
  111.     for nPortIndex, tPortTable in ipairs(tPorts) do
  112.         if tPortTable.nPort == nPort then
  113.             if tPortTable.bOpen then
  114.                 return true
  115.             else
  116.                 return false
  117.             end
  118.         end
  119.     end
  120.  
  121.     return false
  122. end
  123.  
  124. -- Loads the ports and their states from the config file located at:
  125. -- /.portConfig
  126. -- RETURNS:
  127. --  A table containing the numbers and states of each port formatted as such:
  128. --      tPorts[n] = {nPort (number), bOpen (boolean)}
  129. function loadPorts()
  130.     -- Entries in the port config file should be formatted as such:
  131.     --  portNumber:open/closed
  132.  
  133.     if fs.exists(".portConfig") and not fs.isDir(".portConfig") then
  134.         -- Get the number of entries in the port config file (the number of lines).
  135.         local portConfigFile = io.open(".portConfig", "r")
  136.         local nLines = 0
  137.  
  138.         for sLine in portConfigFile:lines() do
  139.             nLines = nLines + 1
  140.         end
  141.         portConfigFile:close()
  142.  
  143.         -- Now, read all of the lines and parse them into a table.
  144.         --  tPorts[n] = {nPort (number), bOpen (boolean)}
  145.         local tPorts = {}
  146.         portConfigFile = fs.open(".portConfig", "r")
  147.  
  148.         local sCurrentEntry = "" -- The current entry, or line, being read from the config file.
  149.         local nStatePosition = 0 -- The position of the first number after the colon of the current entry in the string.
  150.  
  151.         local nCurrentEntry_Port = 0 -- The port number of the current entry.
  152.         local bCurrentEntry_Open = false -- Whether or not the current entry is to be set as open or closed.
  153.  
  154.         for nLine = 1, nLines do
  155.             -- Read the line out of the config file, then parse it.
  156.             sCurrentEntry = portConfigFile.readLine()
  157.             -- The line should be formatted: portNumber:open/closed.
  158.             -- Get the position of the psotion of the first character after the colon; this should be the position
  159.             -- of the first character of the state of this port.
  160.             nStatePosition = sCurrentEntry:find(":") + 1 -- Add one to the numnber returned so it is one AFTER the colon's position.
  161.             -- Now that we have the position of the state, read the port number and the state of the entry with
  162.             -- a conditional to monitor the boolean value entered into the table.
  163.             nCurrentEntry_Port = tonumber(sCurrentEntry:sub(1, nStatePosition - 2)) -- Get a substring from two BEFORE the position
  164.                                                                                     -- of the first character of the state to compensate
  165.                                                                                     -- for the colon.
  166.             bCurrentEntry_Open = sCurrentEntry:sub(nStatePosition, sCurrentEntry:len()) -- Get the state as "open" or "closed" and then
  167.                                                                                         -- check for the final value using a conditional.
  168.             -- If the current entry's state was "open", then set the boolean value to true.
  169.             if bCurrentEntry_Open == "open" then
  170.                 bCurrentEntry_Open = true
  171.             -- If the current entry's state was anything other than "open", then set the boolean value to false.
  172.             else
  173.                 bCurrentEntry_Open = false
  174.             end
  175.  
  176.             -- Finally, insert the newly read and parsed entry into the table.
  177.             table.insert(tPorts, {nPort = nCurrentEntry_Port, bOpen = bCurrentEntry_Open})
  178.         end
  179.  
  180.         -- Now that all of the ports have been read from the config file, go ahead and return the port table to the calling method.
  181.         portConfigFile.close()
  182.         return tPorts
  183.     else
  184.         return {}
  185.     end
  186. end
  187.  
  188. -- Finds and opens an exsistant modem;
  189. -- opens the modem if one is found: returns true
  190. -- returns false if there was no modem found.
  191. function openExistantModem()
  192.     local tSides = rs.getSides()
  193.  
  194.     for nSideIndex, sSide in ipairs(tSides) do
  195.         if peripheral.isPresent(sSide) and peripheral.getType(sSide) == "modem" then
  196.             rednet.open(sSide)
  197.             return true
  198.         end
  199.     end
  200.  
  201.     -- If no modem was found; the loop executed without returning, report
  202.     -- a lock of a modem, and therefore an error.
  203.     return false
  204. end
  205.  
  206. --=NETWORKING METHODS=========================================--
  207.  
  208. -- Uses redent.receive to wait for a message. If a message is received then
  209. -- check if the message contains the port number in the first line.
  210. -- If this method was called to listen for activity on port 5, then it would
  211. -- look like this:
  212.  
  213. -- Message sent: 5:Super awesome port API you got here, Trystan!
  214. -- The message would be parsed to the first digit: 5. Then, since the check passes,
  215. -- the message is parsed into this: Super awesome port API you got here, Trystan!
  216.  
  217. -- THIS ONLY OCCURS IF THE PORT IS OPEN!!!
  218. function receiveOnPort(nPort, nTimeOut)
  219.     local nSender, sMessage = rednet.receive(nTimeOut)
  220.  
  221.     if checkIfPortIsOpen(nPort, loadPorts()) then
  222.         if sMessage:sub(1, tostring(nPort):len()) == tostring(nPort) then
  223.             return nSender, sMessage:sub(tostring(nPort):len() + 2, sMessage:len()) -- Plus two to compensate for the colon.
  224.         else
  225.             return nil, nil
  226.         end
  227.     else
  228.         return nil, nil
  229.     end
  230. end
  231.  
  232. -- Sends a message to the receiver on the the given port.
  233. -- Does this by concatenating the port with a colon to the message, then
  234. -- sending that newly formed string as a message to the tonumber(receiver).
  235. function sendToPort(nReceiver, nPort, sMessage)
  236.     rednet.send(tonumber(nReceiver), nPort .. ":" .. sMessage)
  237. end
  238. --============================================================--
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement