BananeMan

Untitled

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