Advertisement
Guest User

rednet.lua

a guest
Mar 21st, 2018
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.12 KB | None | 0 0
  1.  
  2. CHANNEL_BROADCAST = 65535
  3. CHANNEL_REPEAT = 65533
  4.  
  5. local tReceivedMessages = {}
  6. local tReceivedMessageTimeouts = {}
  7. local tHostnames = {}
  8.  
  9. function open( sModem )
  10.     if type( sModem ) ~= "string" then
  11.         error( "bad argument #1 (expected string, got " .. type( sModem ) .. ")", 2 )
  12.     end
  13.     if peripheral.getType( sModem ) ~= "modem" then
  14.         error( "No such modem: "..sModem, 2 )
  15.     end
  16.     peripheral.call( sModem, "open", os.getComputerID() )
  17.     peripheral.call( sModem, "open", CHANNEL_BROADCAST )
  18. end
  19.  
  20. function close( sModem )
  21.     if sModem then
  22.         -- Close a specific modem
  23.         if type( sModem ) ~= "string" then
  24.             error( "bad argument #1 (expected string, got " .. type( sModem ) .. ")", 2 )
  25.         end
  26.         if peripheral.getType( sModem ) ~= "modem" then
  27.             error( "No such modem: "..sModem, 2 )
  28.         end
  29.         peripheral.call( sModem, "close", os.getComputerID() )
  30.         peripheral.call( sModem, "close", CHANNEL_BROADCAST )
  31.     else
  32.         -- Close all modems
  33.         for n,sModem in ipairs( peripheral.getNames() ) do
  34.             if isOpen( sModem ) then
  35.                 close( sModem )
  36.             end
  37.         end
  38.     end
  39. end
  40.  
  41. function isOpen( sModem )
  42.     if sModem then
  43.         -- Check if a specific modem is open
  44.         if type( sModem ) ~= "string" then
  45.             error( "bad argument #1 (expected string, got " .. type( sModem ) .. ")", 2 )
  46.         end
  47.         if peripheral.getType( sModem ) == "modem" then
  48.             return peripheral.call( sModem, "isOpen", os.getComputerID() ) and peripheral.call( sModem, "isOpen", CHANNEL_BROADCAST )
  49.         end
  50.     else
  51.         -- Check if any modem is open
  52.         for n,sModem in ipairs( peripheral.getNames() ) do
  53.             if isOpen( sModem ) then
  54.                 return true
  55.             end
  56.         end
  57.     end
  58.     return false
  59. end
  60.  
  61. function send( nRecipient, message, sProtocol )
  62.     if type( nRecipient ) ~= "number" then
  63.         error( "bad argument #1 (expected number, got " .. type( nRecipient ) .. ")", 2 )
  64.     end
  65.     if sProtocol ~= nil and type( sProtocol ) ~= "string" then
  66.         error( "bad argument #3 (expected string, got " .. type( sProtocol ) .. ")", 2 )
  67.     end
  68.     -- Generate a (probably) unique message ID
  69.     -- We could do other things to guarantee uniqueness, but we really don't need to
  70.     -- Store it to ensure we don't get our own messages back
  71.     local nMessageID = math.random( 1, 2147483647 )
  72.     tReceivedMessages[ nMessageID ] = true
  73.     tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = nMessageID
  74.  
  75.     -- Create the message
  76.     local nReplyChannel = os.getComputerID()
  77.     local tMessage = {
  78.         nMessageID = nMessageID,
  79.         nRecipient = nRecipient,
  80.         message = message,
  81.         sProtocol = sProtocol,
  82.     }
  83.  
  84.     if nRecipient == os.getComputerID() then
  85.         -- Loopback to ourselves
  86.         os.queueEvent( "rednet_message", nReplyChannel, message, sProtocol )
  87.  
  88.     else
  89.         -- Send on all open modems, to the target and to repeaters
  90.         local sent = false
  91.         for n,sModem in ipairs( peripheral.getNames() ) do
  92.             if isOpen( sModem ) then
  93.                 peripheral.call( sModem, "transmit", nRecipient, nReplyChannel, tMessage );
  94.                 peripheral.call( sModem, "transmit", CHANNEL_REPEAT, nReplyChannel, tMessage );
  95.                 sent = true
  96.             end
  97.         end
  98.     end
  99. end
  100.  
  101. function broadcast( message, sProtocol )
  102.     if sProtocol ~= nil and type( sProtocol ) ~= "string" then
  103.         error( "bad argument #2 (expected string, got " .. type( sProtocol ) .. ")", 2 )
  104.     end
  105.     send( CHANNEL_BROADCAST, message, sProtocol )
  106. end
  107.  
  108. function receive( sProtocolFilter, nTimeout )
  109.     -- The parameters used to be ( nTimeout ), detect this case for backwards compatibility
  110.     if type(sProtocolFilter) == "number" and nTimeout == nil then
  111.         sProtocolFilter, nTimeout = nil, sProtocolFilter
  112.     end
  113.     if sProtocolFilter ~= nil and type( sProtocolFilter ) ~= "string" then
  114.         error( "bad argument #1 (expected string, got " .. type( sProtocolFilter ) .. ")", 2 )
  115.     end
  116.     if nTimeout ~= nil and type( nTimeoutl ) ~= "number" then
  117.         error( "bad argument #2 (expected number, got " .. type( nTimeout ) .. ")", 2 )
  118.     end
  119.  
  120.     -- Start the timer
  121.     local timer = nil
  122.     local sFilter = nil
  123.     if nTimeout then
  124.         timer = os.startTimer( nTimeout )
  125.         sFilter = nil
  126.     else
  127.         sFilter = "rednet_message"
  128.     end
  129.  
  130.     -- Wait for events
  131.     while true do
  132.         local sEvent, p1, p2, p3 = os.pullEvent( sFilter )
  133.         if sEvent == "rednet_message" then
  134.             -- Return the first matching rednet_message
  135.             local nSenderID, message, sProtocol = p1, p2, p3
  136.             if sProtocolFilter == nil or sProtocol == sProtocolFilter then
  137.                 return nSenderID, message, sProtocol
  138.             end
  139.         elseif sEvent == "timer" then
  140.             -- Return nil if we timeout
  141.             if p1 == timer then
  142.                 return nil
  143.             end
  144.         end
  145.     end
  146. end
  147.  
  148. function host( sProtocol, sHostname )
  149.     if type( sProtocol ) ~= "string" then
  150.         error( "bad argument #1 (expected string, got " .. type( sProtocol ) .. ")", 2 )
  151.     end
  152.     if type( sHostname ) ~= "string" then
  153.         error( "bad argument #2 (expected string, got " .. type( sHostname ) .. ")", 2 )
  154.     end
  155.     if sHostname == "localhost" then
  156.         error( "Reserved hostname", 2 )
  157.     end
  158.     if tHostnames[ sProtocol ] ~= sHostname then
  159.         if lookup( sProtocol, sHostname ) ~= nil then
  160.             error( "Hostname in use", 2 )
  161.         end
  162.         tHostnames[ sProtocol ] = sHostname
  163.     end
  164. end
  165.  
  166. function unhost( sProtocol )
  167.     if type( sProtocol ) ~= "string" then
  168.         error( "bad argument #1 (expected string, got " .. type( sProtocol ) .. ")", 2 )
  169.     end
  170.     tHostnames[ sProtocol ] = nil
  171. end
  172.  
  173. function lookup( sProtocol, sHostname )
  174.     if type( sProtocol ) ~= "string" then
  175.         error( "bad argument #1 (expected string, got " .. type( sProtocol ) .. ")", 2 )
  176.     end
  177.     if sHostname ~= nil and type( sHostname ) ~= "string" then
  178.         error( "bad argument #2 (expected string, got " .. type( sHostname ) .. ")", 2 )
  179.     end
  180.  
  181.     -- Build list of host IDs
  182.     local tResults = nil
  183.     if sHostname == nil then
  184.         tResults = {}
  185.     end
  186.  
  187.     -- Check localhost first
  188.     if tHostnames[ sProtocol ] then
  189.         if sHostname == nil then
  190.             table.insert( tResults, os.getComputerID() )
  191.         elseif sHostname == "localhost" or sHostname == tHostnames[ sProtocol ] then
  192.             return os.getComputerID()
  193.         end
  194.     end
  195.  
  196.     if not isOpen() then
  197.         if tResults then
  198.             return table.unpack( tResults )
  199.         end
  200.         return nil
  201.     end
  202.  
  203.     -- Broadcast a lookup packet
  204.     broadcast( {
  205.         sType = "lookup",
  206.         sProtocol = sProtocol,
  207.         sHostname = sHostname,
  208.     }, "dns" )
  209.  
  210.     -- Start a timer
  211.     local timer = os.startTimer( 2 )
  212.  
  213.     -- Wait for events
  214.     while true do
  215.         local event, p1, p2, p3 = os.pullEvent()
  216.         if event == "rednet_message" then
  217.             -- Got a rednet message, check if it's the response to our request
  218.             local nSenderID, tMessage, sMessageProtocol = p1, p2, p3
  219.             if sMessageProtocol == "dns" and type(tMessage) == "table" and tMessage.sType == "lookup response" then
  220.                 if tMessage.sProtocol == sProtocol then
  221.                     if sHostname == nil then
  222.                         table.insert( tResults, nSenderID )
  223.                     elseif tMessage.sHostname == sHostname then
  224.                         return nSenderID
  225.                     end
  226.                 end
  227.             end
  228.         else
  229.             -- Got a timer event, check it's the end of our timeout
  230.             if p1 == timer then
  231.                 break
  232.             end
  233.         end
  234.     end
  235.     if tResults then
  236.         return table.unpack( tResults )
  237.     end
  238.     return nil
  239. end
  240.  
  241. local bRunning = false
  242. function run()
  243.     if bRunning then
  244.         error( "rednet is already running", 2 )
  245.     end
  246.     bRunning = true
  247.    
  248.     while bRunning do
  249.         local sEvent, p1, p2, p3, p4 = os.pullEventRaw()
  250.         if sEvent == "modem_message" then
  251.             -- Got a modem message, process it and add it to the rednet event queue
  252.             local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4
  253.             if isOpen( sModem ) and ( nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST ) then
  254.                 if type( tMessage ) == "table" and tMessage.nMessageID then
  255.                     if not tReceivedMessages[ tMessage.nMessageID ] then
  256.                         tReceivedMessages[ tMessage.nMessageID ] = true
  257.                         tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID
  258.                         os.queueEvent( "rednet_message", nReplyChannel, tMessage.message, tMessage.sProtocol )
  259.                     end
  260.                 end
  261.             end
  262.  
  263.         elseif sEvent == "rednet_message" then
  264.             -- Got a rednet message (queued from above), respond to dns lookup
  265.             local nSenderID, tMessage, sProtocol = p1, p2, p3
  266.             if sProtocol == "dns" and type(tMessage) == "table" and tMessage.sType == "lookup" then
  267.                 local sHostname = tHostnames[ tMessage.sProtocol ]
  268.                 if sHostname ~= nil and (tMessage.sHostname == nil or tMessage.sHostname == sHostname) then
  269.                     rednet.send( nSenderID, {
  270.                         sType = "lookup response",
  271.                         sHostname = sHostname,
  272.                         sProtocol = tMessage.sProtocol,
  273.                     }, "dns" )
  274.                 end
  275.             end
  276.  
  277.         elseif sEvent == "timer" then
  278.             -- Got a timer event, use it to clear the event queue
  279.             local nTimer = p1
  280.             local nMessage = tReceivedMessageTimeouts[ nTimer ]
  281.             if nMessage then
  282.                 tReceivedMessageTimeouts[ nTimer ] = nil
  283.                 tReceivedMessages[ nMessage ] = nil
  284.             end
  285.         end
  286.     end
  287. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement