1
0
mirror of https://github.com/kepler155c/opus synced 2025-07-03 10:32:50 +00:00
opus/sys/apps/network/snmp.lua
Kan18 f26f443b9d Increase discovery message interval, distribute messages
Previously on large server(s), there was an issue where because
chunkloaded computers all started up at once, so they all had the same
discovery message sending timer. This prevents that by starting each off
with a random offset. Also increases the interval for sending messages
from 15 s to 30 s, so that messages (which are the same, a lot of the
time) get sent less often.
2022-12-28 18:43:49 +04:00

227 lines
5.1 KiB
Lua

local Event = require('opus.event')
local GPS = require('opus.gps')
local Socket = require('opus.socket')
local Util = require('opus.util')
local device = _G.device
local kernel = _G.kernel
local network = _G.network
local os = _G.os
local turtle = _G.turtle
-- move this into gps api
local gpsRequested
local gpsLastPoint
local gpsLastRequestTime
local function snmpConnection(socket)
while true do
local msg = socket:read()
if not msg then
break
end
if msg.type == 'reboot' then
os.reboot()
elseif msg.type == 'shutdown' then
os.shutdown()
elseif msg.type == 'ping' then
socket:write('pong')
elseif msg.type == 'script' then
kernel.run(_ENV, {
chunk = msg.args,
title = 'script',
})
elseif msg.type == 'scriptEx' then
local s, m = pcall(function()
local env = kernel.makeEnv(_ENV)
local fn, m = load(msg.args, 'script', nil, env)
if not fn then
error(m)
end
return { fn() }
end)
if s then
socket:write(m)
else
socket:write({ s, m })
end
elseif msg.type == 'gps' then
if gpsRequested then
repeat
os.sleep(0)
until not gpsRequested
end
if gpsLastPoint and os.clock() - gpsLastRequestTime < .5 then
socket:write(gpsLastPoint)
else
gpsRequested = true
local pt = GPS.getPoint(2)
if pt then
socket:write(pt)
else
print('snmp: Unable to get GPS point')
end
gpsRequested = false
gpsLastPoint = pt
if pt then
gpsLastRequestTime = os.clock()
end
end
elseif msg.type == 'info' then
local info = {
id = os.getComputerID(),
label = os.getComputerLabel(),
uptime = math.floor(os.clock()),
}
if turtle then
info.fuel = turtle.getFuelLevel()
info.status = turtle.getStatus()
end
socket:write(info)
end
end
end
Event.addRoutine(function()
print('snmp: listening on port 161')
while true do
local socket = Socket.server(161)
Event.addRoutine(function()
print('snmp: connection from ' .. socket.dhost)
local s, m = pcall(snmpConnection, socket)
print('snmp: closing connection to ' .. socket.dhost)
if not s and m then
print('snmp error')
_G.printError(m)
end
end)
end
end)
device.wireless_modem.open(999)
print('discovery: listening on port 999')
Event.on('modem_message', function(_, _, sport, id, info, distance)
if sport == 999 and tonumber(id) and type(info) == 'table' then
if type(info.label) == 'string' and type(info.id) == 'number' then
if not network[id] then
network[id] = { }
end
Util.merge(network[id], info)
network[id].distance = type(distance) == 'number' and distance
network[id].timestamp = os.clock()
if not network[id].label then
network[id].label = 'unknown'
end
if not network[id].active then
network[id].active = true
os.queueEvent('network_attach', network[id])
end
else
print('discovery: Invalid alive message ' .. id)
end
end
end)
local info = {
id = os.getComputerID()
}
local infoTimer = os.clock()
local function getSlots()
return Util.reduce(turtle.getInventory(), function(acc, v)
if v.count > 0 then
acc[v.index .. ',' .. v.count] = v.key
end
return acc
end, { })
end
local function sendInfo()
if os.clock() - infoTimer >= 5 then -- don't flood
infoTimer = os.clock()
info.label = os.getComputerLabel()
info.uptime = math.floor(os.clock())
info.group = network.getGroup()
if turtle and turtle.getStatus then
info.fuel = turtle.getFuelLevel()
info.status = turtle.getStatus()
info.point = turtle.point
info.inv = getSlots()
info.slotIndex = turtle.getSelectedSlot()
end
if device.neuralInterface then
info.status = device.neuralInterface.status
if not info.status and device.neuralInterface.getMetaOwner then
pcall(function()
local meta = device.neuralInterface.getMetaOwner()
local states = {
isWet = 'Swimming',
isElytraFlying = 'Flying',
isBurning = 'Burning',
isDead = 'Deceased',
isOnLadder = 'Climbing',
isRiding = 'Riding',
isSneaking = 'Sneaking',
isSprinting = 'Running',
}
for k,v in pairs(states) do
if meta[k] then
info.status = v
break
end
end
info.status = info.status or 'health: ' ..
math.floor(meta.health / meta.maxHealth * 100)
end)
end
end
device.wireless_modem.transmit(999, os.getComputerID(), info)
end
end
local function cleanNetwork()
for _,c in pairs(_G.network) do
local elapsed = os.clock()-c.timestamp
if c.active and elapsed > 90 then
c.active = false
os.queueEvent('network_detach', c)
end
end
end
-- every 60 seconds, send out this computer's info
-- send with offset so that messages are evenly distributed and do not all come at once
Event.onTimeout(math.random() * 60, function()
sendInfo()
cleanNetwork()
Event.onInterval(60, function()
sendInfo()
cleanNetwork()
end)
end)
Event.on('turtle_response', function()
if turtle.getStatus() ~= info.status or
turtle.fuel ~= info.fuel then
sendInfo()
end
end)
-- send info early so that computers show soon after booting
Event.onTimeout(math.random() * 4 + 1, sendInfo)