local thread = require 'bee.thread' local utility = require 'utility' local await = require 'await' thread.newchannel 'taskpad' thread.newchannel 'waiter' local errLog = thread.channel 'errlog' local taskPad = thread.channel 'taskpad' local waiter = thread.channel 'waiter' local type = type local counter = utility.counter() local braveTemplate = [[ package.path = %q package.cpath = %q DEVELOP = %s DBGPORT = %d DBGWAIT = %s collectgarbage 'generational' log = require 'brave.log' xpcall(dofile, log.error, %q) local brave = require 'brave' brave.register(%d) ]] ---@class pub local m = {} m.type = 'pub' m.braves = {} m.ability = {} m.taskQueue = {} m.taskMap = {} --- 注册酒馆的功能 function m.on(name, callback) m.ability[name] = callback end --- 招募勇者,勇者会从公告板上领取任务,完成任务后到看板娘处交付任务 ---@param num integer function m.recruitBraves(num) for _ = 1, num do local id = #m.braves + 1 log.debug('Create brave:', id) m.braves[id] = { id = id, thread = thread.thread(braveTemplate:format( package.path, package.cpath, DEVELOP, DBGPORT or 11412, DBGWAIT or 'nil', (ROOT / 'debugger.lua'):string(), id )), taskMap = {}, currentTask = nil, memory = 0, } end end --- 给勇者推送任务 function m.pushTask(info) if info.removed then return false end taskPad:push(info.name, info.id, info.params) m.taskMap[info.id] = info return true end --- 从勇者处接收任务反馈 function m.popTask(brave, id, result) local info = m.taskMap[id] if not info then log.warn(('Brave pushed unknown task result: # %d => [%d]'):format(brave.id, id)) return end m.taskMap[id] = nil if not info.removed then info.removed = true if info.callback then xpcall(info.callback, log.error, result) end end end --- 从勇者处接收报告 function m.popReport(brave, name, params) local abil = m.ability[name] if not abil then log.warn(('Brave pushed unknown report: # %d => %q'):format(brave.id, name)) return end xpcall(abil, log.error, params, brave) end --- 发布任务 ---@param name string ---@param params any ---@return any ---@async function m.awaitTask(name, params) local info = { id = counter(), name = name, params = params, } if m.pushTask(info) then return await.wait(function (waker) info.callback = waker end) else return false end end --- 发布同步任务,如果任务进入了队列,会返回执行器 --- 通过 jumpQueue 可以插队 ---@param name string ---@param params any ---@param callback? function function m.task(name, params, callback) local info = { id = counter(), name = name, params = params, callback = callback, } return m.pushTask(info) end --- 接收反馈 function m.recieve(block) if block then local id, name, result = waiter:bpop() if type(name) == 'string' then m.popReport(m.braves[id], name, result) else m.popTask(m.braves[id], name, result) end else while true do local suc, id, name, result = waiter:pop() if not suc then break end if type(name) == 'string' then m.popReport(m.braves[id], name, result) else m.popTask(m.braves[id], name, result) end end end end --- 检查伤亡情况 function m.checkDead() while true do local suc, err = errLog:pop() if not suc then break end log.error('Brave is dead!: ' .. err) end end function m.step(block) m.checkDead() m.recieve(block) end return m