Files
opus-apps/milo/plugins/remote.lua
Kan18 2f67fb2ef8 Try to update Milo for 1.19
Removes Milo trying to access damage on items (`nil` because of The
Flattening). We might also need to reimplement showing durability in the
item's display name - I got a little too carried away with removing
mentions of "damage". Also renames nbtHash to nbt to be consistent with
new CC:T naming. I tried not to touch anything related to MiloRemote for
now, and there are probably still many bugs remaining that need to be
ironed out. Most of the basic functionality works now, though.
2022-12-24 15:39:14 +04:00

202 lines
4.3 KiB
Lua

local Event = require('opus.event')
local itemDB = require('core.itemDB')
local Milo = require('milo')
local Socket = require('opus.socket')
local device = _G.device
local context = Milo:getContext()
local function getNameSafe(v)
local name
local s, m = pcall(function()
name = v.getName()
end)
if not s then
_G._syslog(m)
end
return name
end
local function getManipulatorForUser(user)
for _,v in pairs(device) do
if v.type == 'manipulator' and v.getName and getNameSafe(v) == user then
return v
end
end
end
local function compactList(list)
local c = { }
for k,v in pairs(list) do
c[k]= table.concat({ v.has_recipe and 1 or 0, v.count, v.displayName }, ':')
end
return c
end
local function client(socket)
_G._syslog('REMOTE: connection from ' .. socket.dhost)
local user = socket:read(2)
if not user then
return
end
local manipulator = getManipulatorForUser(user)
if not manipulator then
_G._syslog('REMOTE: Manipulator with introspection module bound with user not found. Closing connection.')
socket:write({
msg = 'Manipulator not found'
})
socket:close()
return
end
_G._syslog('REMOTE: all good')
socket:write({
data = 'ok',
})
local function makeNode(devType)
local devName = user .. ':' .. devType
local adapter = device[devName]
if adapter then
return {
adapter = adapter,
name = devName,
}
end
end
repeat
local data = socket:read()
if not data then
break
end
socket.co = coroutine.running()
if data.request == 'scan' then -- full scan of all inventories
local items = Milo:mergeResources(Milo:listItems(true))
socket:write({
type = 'list',
list = compactList(items),
})
elseif data.request == 'list' then
local items = Milo:mergeResources(Milo:listItems())
socket:write({
type = 'list',
list = compactList(items),
})
elseif data.request == 'deposit' then
local function deposit()
local node = makeNode(data.source or 'inventory')
if node then
local slot = node.adapter.getItemDetail(data.slot)
if slot then
if context.storage:import(node, data.slot, slot.count, slot) > 0 then
local item = Milo:getItem(slot)
if item then
-- TODO: This generates multile messages for the same item
-- use a callback system using a UID for the message
socket:write({
type = 'received',
key = item.key,
count = item.count,
})
end
end
end
end
end
Milo:queueRequest({ }, deposit)
elseif data.request == 'transfer' then
local count = data.count
if count == 'stack' then
count = itemDB:getMaxCount(data.item)
elseif count == 'all' then
local item = Milo:getItem(data.item)
count = item and item.count or 0
end
local function transfer(request)
local target = makeNode('inventory')
if target then
local amount = context.storage:export(
target,
nil,
request.requested,
data.item)
local item = Milo:listItems()[request.key]
socket:write({
type = 'transfer',
key = request.key,
requested = request.requested,
current = item and item.count or 0,
count = amount,
craft = request.craft,
})
end
end
local request = Milo:makeRequest(data.item, count, transfer)
if (request.craft + request.count == 0) or
(request.craft > 0 and request.count == 0) then
socket:write({
type = 'transfer',
key = request.key,
requested = request.requested,
count = request.current,
craft = request.craft,
})
end
else
for _,v in pairs(context.plugins.remoteHandler or { }) do
if v.messages and v.messages[data.request] then
v.callback(user, data, socket)
end
end
end
until not socket.connected
_G._syslog('REMOTE: disconnected from ' .. socket.dhost)
end
local handler
local function listen()
if device.wireless_modem then
handler = Event.addRoutine(function()
_G._syslog('REMOTE: listening on port 4242')
while true do
local socket = Socket.server(4242)
Event.addRoutine(function()
client(socket)
socket:close()
end)
end
end)
end
end
Event.on({ 'device_attach', 'device_detach' }, function(_, name)
if name == 'wireless_modem' then
if handler then
handler:terminate()
handler = nil
_G._syslog('REMOTE: wireless modem disconnected')
else
listen()
end
end
end)
listen()