mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-06-24 22:23:21 +00:00
![SquidDev](/assets/img/avatar_default.png)
We now use illuaminate[1]'s linting facilities to check the rom and bios.lua for a couple of common bugs and other problems. Right now this doesn't detect any especially important bugs, though it has caught lots of small things (unused variables, some noisy code). In the future, the linter will grow in scope and features, which should allow us to be stricter and catch most issues. As a fun aside, we started off with ~150 bugs, and illuaminate was able to fix all but 30 of them, which is pretty neat. [1]: https://github.com/SquidDev/illuaminate
265 lines
8.5 KiB
Lua
265 lines
8.5 KiB
Lua
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
|
|
|
CHANNEL_BROADCAST = 65535
|
|
CHANNEL_REPEAT = 65533
|
|
|
|
local tReceivedMessages = {}
|
|
local tReceivedMessageTimeouts = {}
|
|
local tHostnames = {}
|
|
|
|
function open( sModem )
|
|
expect(1, sModem, "string")
|
|
if peripheral.getType( sModem ) ~= "modem" then
|
|
error( "No such modem: "..sModem, 2 )
|
|
end
|
|
peripheral.call( sModem, "open", os.getComputerID() )
|
|
peripheral.call( sModem, "open", CHANNEL_BROADCAST )
|
|
end
|
|
|
|
function close( sModem )
|
|
expect(1, sModem, "string", "nil")
|
|
if sModem then
|
|
-- Close a specific modem
|
|
if peripheral.getType( sModem ) ~= "modem" then
|
|
error( "No such modem: "..sModem, 2 )
|
|
end
|
|
peripheral.call( sModem, "close", os.getComputerID() )
|
|
peripheral.call( sModem, "close", CHANNEL_BROADCAST )
|
|
else
|
|
-- Close all modems
|
|
for _,sModem in ipairs( peripheral.getNames() ) do
|
|
if isOpen( sModem ) then
|
|
close( sModem )
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function isOpen( sModem )
|
|
expect(1, sModem, "string", "nil")
|
|
if sModem then
|
|
-- Check if a specific modem is open
|
|
if peripheral.getType( sModem ) == "modem" then
|
|
return peripheral.call( sModem, "isOpen", os.getComputerID() ) and peripheral.call( sModem, "isOpen", CHANNEL_BROADCAST )
|
|
end
|
|
else
|
|
-- Check if any modem is open
|
|
for _,sModem in ipairs( peripheral.getNames() ) do
|
|
if isOpen( sModem ) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function send( nRecipient, message, sProtocol )
|
|
expect(1, nRecipient, "number")
|
|
expect(3, sProtocol, "string", "nil")
|
|
-- Generate a (probably) unique message ID
|
|
-- We could do other things to guarantee uniqueness, but we really don't need to
|
|
-- Store it to ensure we don't get our own messages back
|
|
local nMessageID = math.random( 1, 2147483647 )
|
|
tReceivedMessages[ nMessageID ] = true
|
|
tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = nMessageID
|
|
|
|
-- Create the message
|
|
local nReplyChannel = os.getComputerID()
|
|
local tMessage = {
|
|
nMessageID = nMessageID,
|
|
nRecipient = nRecipient,
|
|
message = message,
|
|
sProtocol = sProtocol,
|
|
}
|
|
|
|
local sent = false
|
|
if nRecipient == os.getComputerID() then
|
|
-- Loopback to ourselves
|
|
os.queueEvent( "rednet_message", nReplyChannel, message, sProtocol )
|
|
sent = true
|
|
else
|
|
-- Send on all open modems, to the target and to repeaters
|
|
for _,sModem in ipairs( peripheral.getNames() ) do
|
|
if isOpen( sModem ) then
|
|
peripheral.call( sModem, "transmit", nRecipient, nReplyChannel, tMessage )
|
|
peripheral.call( sModem, "transmit", CHANNEL_REPEAT, nReplyChannel, tMessage )
|
|
sent = true
|
|
end
|
|
end
|
|
end
|
|
|
|
return sent
|
|
end
|
|
|
|
function broadcast( message, sProtocol )
|
|
expect(2, sProtocol, "string", "nil")
|
|
send( CHANNEL_BROADCAST, message, sProtocol )
|
|
end
|
|
|
|
function receive( sProtocolFilter, nTimeout )
|
|
-- The parameters used to be ( nTimeout ), detect this case for backwards compatibility
|
|
if type(sProtocolFilter) == "number" and nTimeout == nil then
|
|
sProtocolFilter, nTimeout = nil, sProtocolFilter
|
|
end
|
|
expect(1, sProtocolFilter, "string", "nil")
|
|
expect(2, nTimeout, "number", "nil")
|
|
|
|
-- Start the timer
|
|
local timer = nil
|
|
local sFilter = nil
|
|
if nTimeout then
|
|
timer = os.startTimer( nTimeout )
|
|
sFilter = nil
|
|
else
|
|
sFilter = "rednet_message"
|
|
end
|
|
|
|
-- Wait for events
|
|
while true do
|
|
local sEvent, p1, p2, p3 = os.pullEvent( sFilter )
|
|
if sEvent == "rednet_message" then
|
|
-- Return the first matching rednet_message
|
|
local nSenderID, message, sProtocol = p1, p2, p3
|
|
if sProtocolFilter == nil or sProtocol == sProtocolFilter then
|
|
return nSenderID, message, sProtocol
|
|
end
|
|
elseif sEvent == "timer" then
|
|
-- Return nil if we timeout
|
|
if p1 == timer then
|
|
return nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function host( sProtocol, sHostname )
|
|
expect(1, sProtocol, "string")
|
|
expect(2, sHostname, "string")
|
|
if sHostname == "localhost" then
|
|
error( "Reserved hostname", 2 )
|
|
end
|
|
if tHostnames[ sProtocol ] ~= sHostname then
|
|
if lookup( sProtocol, sHostname ) ~= nil then
|
|
error( "Hostname in use", 2 )
|
|
end
|
|
tHostnames[ sProtocol ] = sHostname
|
|
end
|
|
end
|
|
|
|
function unhost( sProtocol )
|
|
expect(1, sProtocol, "string")
|
|
tHostnames[ sProtocol ] = nil
|
|
end
|
|
|
|
function lookup( sProtocol, sHostname )
|
|
expect(1, sProtocol, "string")
|
|
expect(2, sHostname, "string", "nil")
|
|
|
|
-- Build list of host IDs
|
|
local tResults = nil
|
|
if sHostname == nil then
|
|
tResults = {}
|
|
end
|
|
|
|
-- Check localhost first
|
|
if tHostnames[ sProtocol ] then
|
|
if sHostname == nil then
|
|
table.insert( tResults, os.getComputerID() )
|
|
elseif sHostname == "localhost" or sHostname == tHostnames[ sProtocol ] then
|
|
return os.getComputerID()
|
|
end
|
|
end
|
|
|
|
if not isOpen() then
|
|
if tResults then
|
|
return table.unpack( tResults )
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- Broadcast a lookup packet
|
|
broadcast( {
|
|
sType = "lookup",
|
|
sProtocol = sProtocol,
|
|
sHostname = sHostname,
|
|
}, "dns" )
|
|
|
|
-- Start a timer
|
|
local timer = os.startTimer( 2 )
|
|
|
|
-- Wait for events
|
|
while true do
|
|
local event, p1, p2, p3 = os.pullEvent()
|
|
if event == "rednet_message" then
|
|
-- Got a rednet message, check if it's the response to our request
|
|
local nSenderID, tMessage, sMessageProtocol = p1, p2, p3
|
|
if sMessageProtocol == "dns" and type(tMessage) == "table" and tMessage.sType == "lookup response" then
|
|
if tMessage.sProtocol == sProtocol then
|
|
if sHostname == nil then
|
|
table.insert( tResults, nSenderID )
|
|
elseif tMessage.sHostname == sHostname then
|
|
return nSenderID
|
|
end
|
|
end
|
|
end
|
|
else
|
|
-- Got a timer event, check it's the end of our timeout
|
|
if p1 == timer then
|
|
break
|
|
end
|
|
end
|
|
end
|
|
if tResults then
|
|
return table.unpack( tResults )
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local bRunning = false
|
|
function run()
|
|
if bRunning then
|
|
error( "rednet is already running", 2 )
|
|
end
|
|
bRunning = true
|
|
|
|
while bRunning do
|
|
local sEvent, p1, p2, p3, p4 = os.pullEventRaw()
|
|
if sEvent == "modem_message" then
|
|
-- Got a modem message, process it and add it to the rednet event queue
|
|
local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4
|
|
if isOpen( sModem ) and ( nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST ) then
|
|
if type( tMessage ) == "table" and tMessage.nMessageID then
|
|
if not tReceivedMessages[ tMessage.nMessageID ] then
|
|
tReceivedMessages[ tMessage.nMessageID ] = true
|
|
tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID
|
|
os.queueEvent( "rednet_message", nReplyChannel, tMessage.message, tMessage.sProtocol )
|
|
end
|
|
end
|
|
end
|
|
|
|
elseif sEvent == "rednet_message" then
|
|
-- Got a rednet message (queued from above), respond to dns lookup
|
|
local nSenderID, tMessage, sProtocol = p1, p2, p3
|
|
if sProtocol == "dns" and type(tMessage) == "table" and tMessage.sType == "lookup" then
|
|
local sHostname = tHostnames[ tMessage.sProtocol ]
|
|
if sHostname ~= nil and (tMessage.sHostname == nil or tMessage.sHostname == sHostname) then
|
|
rednet.send( nSenderID, {
|
|
sType = "lookup response",
|
|
sHostname = sHostname,
|
|
sProtocol = tMessage.sProtocol,
|
|
}, "dns" )
|
|
end
|
|
end
|
|
|
|
elseif sEvent == "timer" then
|
|
-- Got a timer event, use it to clear the event queue
|
|
local nTimer = p1
|
|
local nMessage = tReceivedMessageTimeouts[ nTimer ]
|
|
if nMessage then
|
|
tReceivedMessageTimeouts[ nTimer ] = nil
|
|
tReceivedMessages[ nMessage ] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|