Advertisement
osmarks

jnet

Mar 10th, 2019
229
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 2.77 KB | None | 0 0
  1. if not fs.exists ".jnet-ecc.0.lua" then
  2.     print "ECC not found. Downloading..."
  3.     local h = http.get "https://pastebin.com/raw/ykK4UMa6"
  4.     local f = fs.open(".jnet-ecc.0.lua", "w")
  5.     f.write(h.readAll())
  6.     h.close()
  7.     f.close()
  8.     print "Done!"
  9. end
  10. local ecc = dofile ".jnet-ecc.0.lua"
  11.  
  12. local CHANNEL = 62831
  13.  
  14. local modems = {}
  15.  
  16. local LOG_LEVEL = 3
  17.  
  18. local function log(level, ...)
  19.     if level <= LOG_LEVEL then
  20.         local out = {os.clock()}
  21.         for _, thing in pairs{...} do
  22.             if type(thing) == "string" then table.insert(out, thing)
  23.             else
  24.                 local ok, x = pcall(textutils.serialise, thing)
  25.                 if ok then table.insert(out, x)
  26.                 else table.insert(out, tostring(thing)) end
  27.             end
  28.         end
  29.         print(table.concat(out, " "))
  30.     end
  31. end
  32. local function log_debg(...) log(3, ...) end
  33. local function log_info(...) log(2, ...) end
  34. local function log_warn(...) log(1, ...) end
  35. local function log_fail(...) log(0, ...) end
  36.  
  37. local function hex_to_bytes(hex)
  38.     local out = {}
  39.     for i = 1, #hex, 2 do
  40.         local pair = hex:sub(i, i + 1)
  41.         table.insert(out, tonumber(pair, 16))
  42.     end
  43.     return out
  44. end
  45.  
  46. local function bytes_to_hex(key)
  47.     local out = ""
  48.     for _, v in pairs(key) do
  49.         out = out .. string.format("%.2x", v)
  50.     end
  51.     return out
  52. end
  53.  
  54. local private_key, public_key = settings.get "jnet.private_key"
  55. if not private_key then
  56.     log_warn "Private key for node not found. A keypair is being generated."
  57.     private_key, public_key = ecc.keypair()
  58.     settings.set("jnet.private_key", bytes_to_hex(private_key))
  59.     settings.save ".settings"
  60. else
  61.     private_key = hex_to_bytes(private_key)
  62.     public_key = ecc.publicKey(private_key)
  63. end
  64.  
  65. log_info("Public key is", bytes_to_hex(public_key))
  66.  
  67. -- Generate random 31-bit-or-so UUID. Why? Because CC's random function is mildly broken.
  68. local function generate_UUID()
  69.     if chaos then -- Use PotatOS Chaos service if available
  70.         return chaos.get_u32()
  71.     end
  72.     return math.random(0, 0x6FFFFFFF)
  73. end
  74.  
  75. local seen_UUIDs = {}
  76. local UUID_clear_timers = {}
  77.  
  78. local function add_modem(name)
  79.     local new = peripheral.wrap(name)
  80.     modems[name] = new
  81.     new.open(CHANNEL)
  82.     new.wireless = new.isWireless() -- cache wireless-ness
  83.     log_info("Added modem", name)
  84. end
  85.  
  86. local function log_UUID(UUID)
  87.     seen_UUIDs[UUID] = true
  88.     UUID_clear_timers[UUID] = os.startTimer(30)
  89. end
  90.  
  91. local function handle_packet(packet)
  92.     if packet.type == "data" and type(packet.UUID) == "number" and packet.data then
  93.         -- lazy rednet-style relaying
  94.         log_info("Received packet", packet)
  95.         os.queueEvent("jnet_packet", packet)
  96.         if not seen_UUIDs[packet.UUID] then
  97.             log_info("Retransmitting", packet.UUID)
  98.             for name, periph in pairs(modems) do
  99.                 periph.transmit(CHANNEL, CHANNEL, packet)
  100.                 log_debg("Transmitted on modem", name)
  101.             end
  102.             log_UUID(packet.UUID)
  103.         else
  104.             log_debg("Ignoring already-handled packet", packet.UUID)
  105.         end
  106.     else
  107.         log_info("Invalid packet", packet)
  108.     end
  109. end
  110.  
  111. local function listener()
  112.     peripheral.find("modem", add_modem)
  113.     while true do
  114.         local ev = {coroutine.yield()}
  115.         if ev[1] == "peripheral" then
  116.             local _, name = unpack(ev)
  117.             if peripheral.getType(name) == "modem" then
  118.                 add_modem(name)
  119.             end
  120.         elseif ev[1] == "peripheral_detach" then
  121.             local _, name = unpack(ev)
  122.             if peripheral.getType(name) == "modem" then modems[name] = nil end
  123.         elseif ev[1] == "modem_message" then
  124.             local _, side, channel, reply_channel, packet, distance = unpack(ev)
  125.             if channel == CHANNEL and type(packet) == "table" then
  126.                 handle_packet(packet)
  127.             end
  128.         elseif ev[1] == "timer" then
  129.             local timer = ev[2]
  130.             local UUID = UUID_clear_timers[timer]
  131.             if UUID then
  132.                 log_debg("Removing UUID", UUID, "from seen UUIDs.")
  133.                 seen_UUIDs[UUID] = nil
  134.                 UUID_clear_timers[timer] = nil
  135.             end
  136.         end
  137.     end
  138. end
  139.  
  140. local function send(data)
  141.     local UUID = generate_UUID()
  142.     log_UUID(UUID)
  143.     for name, periph in pairs(modems) do
  144.         periph.transmit(CHANNEL, CHANNEL, { UUID = UUID, data = data, type = "data" })
  145.     end
  146. end
  147.  
  148. local function recv()
  149.     local _, packet = os.pullEvent "jnet_packet"
  150.     return packet.data, packet
  151. end
  152.  
  153. local option = ...
  154. if option == "send" then
  155.     parallel.waitForAny(listener, function()
  156.         send(read())
  157.     end)
  158. elseif option == "recv" then
  159.     parallel.waitForAny(listener, function()
  160.         print(recv())
  161.     end)
  162. elseif option == "run" then
  163.     listener()
  164. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement