-- Salt's ComputerCraft Storage Network Script
--
-- For information on this script, physical in-world setup, and configuration,
-- see: https://git.desu.ltd/salt/mc-scripts/src/branch/master/storage-net

-- Default configuration values. Override in config.lua. DO NOT CHANGE HERE
mode                = "ConfigureMe"     -- The mode of function for this node
networkid           = 0                 -- Unique ID for this network
port_broadcast      = 42914             -- Port for M->S traffic
port_return         = 42915             -- Port for S->M traffic
packet_magic        = "ccstoragenet"    -- Just a random string

-- This loads config.lua. See masterconfig.lua and slaveconfig.lua for example
-- configurations.
require "config"

-- Startup diagnostics
print("Salt's CC Storage Net")
print("Computer " .. os.getComputerID() .. " configured as " .. mode)

-- Common globals
modem = peripheral.find("modem") or error("No modem attached", 0)
-- Master globals
-- Slave globals

-- Common functions
function c_mainLoop(loopfunc)
    -- Loops a thing forever
    while true do
        loopfunc()
        sleep(0.10)
    end
end
function c_waitForMessage()
    -- Waits for a message on the modem, timing out after 1 second
    local timeout = os.startTimer(1)
    local event, side, channel, replyChannel, message, distance = os.pullEvent()
    if (event == "modem_message") then
        if
            (message["magic"] ~= packet_magic) or       -- Magic is required per packet spec
            (not message["type"])                       -- Message type is required
            then
            print("Discarded nonconformant message")
            return nil
        end
        return message
    end
    return nil
end
function c_sendMessage(message)
    -- Sends a message, either to the master or all slaves depending on mode
    local msg = {
        magic           = packet_magic,
        networkid       = networkid,
        sourceid        = os.getComputerID(),
        --destid is optional
    }
    -- Override basic message object with args
    for k,v in pairs(message) do
        msg[k] = v
    end
    print("Transmitting message: " .. textutils.serialize(msg))
    -- Transmit on different ports depending on mode
    if (mode == "master") then
        modem.transmit(port_broadcast, port_return, msg)
    elseif (mode == "slave") then
        modem.transmit(port_return, port_broadcast, msg)
    end
end
-- Master functions
function m_loop()
    -- The main loop of the master server
    -- Listen for packets on the return net
    msg = c_waitForMessage()
    if not msg then return end
    sleep(1)
end
-- Slave functions
function s_loop()
    -- The main loop of any slave nodes
    -- Listen for packets from the master
    msg = c_waitForMessage()
    if not msg then
        print(".")
        return
    end
    if (msg[type] == "ping") then
        -- Respond to pings with pongs
        print("Received ping")
        c_sendMessage({type="pong"})
    end
    sleep(1)
end

-- Application entrypoint
function main ()
    if (mode == "master") then
        print("Beginning initialization as master...")
        modem.open(port_return)

        print("Pinging for slaves...")
        c_sendMessage({type="ping"})
        sleep(3)
        local msg = true
        while msg ~= nil do
            msg = c_waitForMessage()
            if (msg and msg[type] == "pong") then
                print("Received pong from " .. msg["sourceid"])
            end
        end
        print("Entering main loop")
        c_mainLoop(m_loop)
    elseif (mode == "slave") then
        print("Beginning initialization as slave...")
        modem.open(port_broadcast)

        print("Entering main loop")
        c_mainLoop(s_loop)
    else
        error("Invalid mode: " .. mode .. ", please configure this node appropriately", 0)
    end
    modem.closeAll()
end

main()