diff options
Diffstat (limited to 'server-beta/src')
-rw-r--r-- | server-beta/src/json/decode.lua | 153 | ||||
-rw-r--r-- | server-beta/src/json/encode.lua | 135 | ||||
-rw-r--r-- | server-beta/src/json/init.lua | 6 | ||||
-rw-r--r-- | server-beta/src/jsonrpc.lua | 15 | ||||
-rw-r--r-- | server-beta/src/pub/brave.lua | 1 | ||||
-rw-r--r-- | server-beta/src/pub/client.lua | 45 | ||||
-rw-r--r-- | server-beta/src/pub/pub.lua | 39 | ||||
-rw-r--r-- | server-beta/src/service.lua | 21 | ||||
-rw-r--r-- | server-beta/src/task.lua | 7 |
9 files changed, 379 insertions, 43 deletions
diff --git a/server-beta/src/json/decode.lua b/server-beta/src/json/decode.lua new file mode 100644 index 00000000..9129d92f --- /dev/null +++ b/server-beta/src/json/decode.lua @@ -0,0 +1,153 @@ +local lpeg = require 'lpeglabel' +local tablePack = table.pack +local rawset = rawset +local tointeger = math.tointeger +local tonumber = tonumber +local setmetatable = setmetatable +local stringChar = string.char +local error = error + +_ENV = nil + +local SaveSort +local P = lpeg.P +local S = lpeg.S +local R = lpeg.R +local V = lpeg.V +local C = lpeg.C +local Ct = lpeg.Ct +local Cc = lpeg.Cc +local Cp = lpeg.Cp +local Cs = lpeg.Cs + +local EscMap = { + ['t'] = '\t', + ['r'] = '\r', + ['n'] = '\n', + ['"'] = '"', + ['\\'] = '\\', +} +local BoolMap = { + ['true'] = true, + ['false'] = false, +} + +local hashmt = { + __pairs = function (self) + local i = 1 + local function next() + i = i + 1 + local k = self[i] + if k == nil then + return + end + local v = self[k] + if v == nil then + return next() + end + return k, v + end + return next + end, + __newindex = function (self, k, v) + local i = 2 + while self[i] do + i = i + 1 + end + rawset(self, i, k) + rawset(self, k, v) + end, +} + +----------------------------------------------------------------------------- +-- JSON4Lua: JSON encoding / decoding support for the Lua language. +-- json Module. +-- Author: Craig Mason-Jones +-- Homepage: http://github.com/craigmj/json4lua/ +-- Version: 1.0.0 +-- This module is released under the MIT License (MIT). +-- Please see LICENCE.txt for details. +-- +local function Utf8(str) + local n = tonumber(str, 16) + -- math.floor(x/2^y) == lazy right shift + -- a % 2^b == bitwise_and(a, (2^b)-1) + -- 64 = 2^6 + -- 4096 = 2^12 (or 2^6 * 2^6) + local x + if n < 0x80 then + x = stringChar(n % 0x80) + elseif n < 0x800 then + -- [110x xxxx] [10xx xxxx] + x = stringChar(0xC0 + ((n // 64) % 0x20), 0x80 + (n % 0x40)) + else + -- [1110 xxxx] [10xx xxxx] [10xx xxxx] + x = stringChar(0xE0 + ((n // 4096) % 0x10), 0x80 + ((n // 64) % 0x40), 0x80 + (n % 0x40)) + end + return x +end + +local function HashTable(patt) + return C(patt) / function (_, ...) + local hash = tablePack(...) + local n = hash.n + hash.n = nil + if SaveSort then + local max = n // 2 + for i = 1, max do + local key, value = hash[2*i-1], hash[2*i] + hash[key] = value + hash[i+1] = key + end + hash[1] = nil + for i = max+2, max*2 do + hash[i] = nil + end + return setmetatable(hash, hashmt) + else + local max = n // 2 + for i = 1, max do + local a = 2*i-1 + local b = 2*i + local key, value = hash[a], hash[b] + hash[key] = value + hash[a] = nil + hash[b] = nil + end + return hash + end + end +end + +local Token = P +{ + V'Value' * Cp(), + Nl = P'\r\n' + S'\r\n', + Sp = S' \t', + Spnl = (V'Sp' + V'Nl')^0, + Bool = C(P'true' + P'false') / BoolMap, + Int = C('0' + (P'-'^-1 * R'19' * R'09'^0)) / tointeger, + Float = C(P'-'^-1 * ('0' + R'19' * R'09'^0) * '.' * R'09'^0) / tonumber, + Null = P'null' * Cc(nil), + String = '"' * Cs(V'Char'^0) * '"', + Char = V'Esc' + V'Utf8' + (1 - P'"' - P'\t' - V'Nl'), + Esc = P'\\' * C(S'tnr"\\') / EscMap, + Utf8 = P'\\u' * C(P(4)) / Utf8, + Hash = V'Spnl' * '{' * V'Spnl' * HashTable((V'Object' + P',' * V'Spnl')^0) * V'Spnl' * P'}' * V'Spnl', + Array = V'Spnl' * '[' * V'Spnl' * Ct((V'Value' * V'Spnl' + P',' * V'Spnl')^0) * V'Spnl' * P']' * V'Spnl', + Object = V'Spnl' * V'Key' * V'Spnl' * V'Value' * V'Spnl', + Key = V'String' * V'Spnl' * ':', + Value = V'Hash' + V'Array' + V'Bool' + V'Null' + V'String' + V'Float' + V'Int', +} + +return function (str, save_sort_) + SaveSort = save_sort_ + local table, res, pos = Token:match(str) + if not table then + if not pos or pos <= #str then + pos = pos or 1 + error(('没匹配完[%s][%s]\n%s'):format(pos, res, str:sub(pos, pos+100))) + end + end + return table +end diff --git a/server-beta/src/json/encode.lua b/server-beta/src/json/encode.lua new file mode 100644 index 00000000..492c5a58 --- /dev/null +++ b/server-beta/src/json/encode.lua @@ -0,0 +1,135 @@ +local rep = string.rep +local gsub = string.gsub +local sort = table.sort +local find = string.find +local tostring = tostring +local getmetatable = debug.getmetatable +local type = type +local next = next +local pairs = pairs +local tableConcat = table.concat + +_ENV = nil + +local index +local lines +local n = -1 +local tabs = {} + +local esc_map = { + ['\\'] = '\\\\', + ['\r'] = '\\r', + ['\n'] = '\\n', + ['\t'] = '\\t', + ['"'] = '\\"', +} + +local function encode(data, key) + n = n + 1 + if not tabs[n] then + tabs[n] = rep(' ', n) + end + local tp = type(data) + if tp == 'table' then + if not data[1] and next(data) then + -- 认为这个是哈希表 + if key then + index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": {\r\n' + else + index=index+1;lines[index] = tabs[n] .. '{\r\n' + end + local meta = getmetatable(data) + local sep + if meta and meta.__pairs then + for k, v in meta.__pairs(data), data do + if encode(v, k) then + index=index+1;lines[index] = ',\r\n' + sep = true + end + end + else + local list = {} + local i = 0 + for k in next, data do + i=i+1;list[i] = k + end + sort(list) + for j = 1, i do + local k = list[j] + if encode(data[k], k) then + index=index+1;lines[index] = ',\r\n' + sep = true + end + end + end + if sep then + lines[index] = '\r\n' + end + index=index+1;lines[index] = tabs[n] .. '}' + else + -- 认为这个是数组 + if key then + index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": [\r\n' + else + index=index+1;lines[index] = tabs[n] .. '[\r\n' + end + local sep + for k, v in pairs(data) do + if encode(v) then + index=index+1;lines[index] = ',\r\n' + sep = true + end + end + if sep then + lines[index] = '\r\n' + end + index=index+1;lines[index] = tabs[n] .. ']' + end + elseif tp == 'number' then + data = tostring(data) + -- 判断 inf -inf -nan(ind) 1.#INF -1.#INF -1.#IND + if find(data, '%a') then + data = '0' + end + if key then + index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": ' .. data + else + index=index+1;lines[index] = tabs[n] .. data + end + elseif tp == 'boolean' then + if key then + index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": ' .. tostring(data) + else + index=index+1;lines[index] = tabs[n] .. tostring(data) + end + elseif tp == 'nil' then + if key then + index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": null' + else + index=index+1;lines[index] = tabs[n] .. 'null' + end + elseif tp == 'string' then + local str = gsub(data, '[\\\r\n\t"]', esc_map) + if key then + index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": "' .. str .. '"' + else + index=index+1;lines[index] = tabs[n] .. '"' .. str .. '"' + end + else + n = n - 1 + return false + end + n = n - 1 + return true +end + +local function json(t) + lines = {} + index = 0 + + encode(t) + + return tableConcat(lines) +end + +return json diff --git a/server-beta/src/json/init.lua b/server-beta/src/json/init.lua new file mode 100644 index 00000000..c28e7aed --- /dev/null +++ b/server-beta/src/json/init.lua @@ -0,0 +1,6 @@ +local api = { + decode = require 'json.decode', + encode = require 'json.encode', +} + +return api diff --git a/server-beta/src/jsonrpc.lua b/server-beta/src/jsonrpc.lua new file mode 100644 index 00000000..f92b12a1 --- /dev/null +++ b/server-beta/src/jsonrpc.lua @@ -0,0 +1,15 @@ +local json = require 'json' +local ioWrite = io.write +local osClock = os.clock + +_ENV = nil + +local TIMEOUT = 600.0 +local ID = 0 +local Cache = {} + +---@class jsonrpc +local m = {} +m.type = 'jsonrpc' + +return m diff --git a/server-beta/src/pub/brave.lua b/server-beta/src/pub/brave.lua index 5e4f85ad..c9fd0afe 100644 --- a/server-beta/src/pub/brave.lua +++ b/server-beta/src/pub/brave.lua @@ -1,5 +1,6 @@ local thread = require 'bee.thread' +---@class pub_brave local m = {} m.type = 'pub.brave' diff --git a/server-beta/src/pub/client.lua b/server-beta/src/pub/client.lua index 1212adf2..5ac24684 100644 --- a/server-beta/src/pub/client.lua +++ b/server-beta/src/pub/client.lua @@ -1,4 +1,6 @@ local thread = require 'bee.thread' +local utility = require 'utility' +local task = require 'task' local braveTemplate = [[ package.path = %q @@ -14,6 +16,7 @@ m.type = 'pub.client' m.braves = {} --- 招募勇者,勇者会从公告板上领取任务,完成任务后到看板娘处交付任务 +---@param num integer function m:recruitBraves(num) for _ = 1, num do local id = #self.braves + 1 @@ -21,6 +24,7 @@ function m:recruitBraves(num) thread.newchannel('taskpad' .. id) thread.newchannel('waiter' .. id) self.braves[id] = { + id = id, taskpad = thread.channel('taskpad' .. id), waiter = thread.channel('waiter' .. id), thread = thread.thread(braveTemplate:format( @@ -28,13 +32,50 @@ function m:recruitBraves(num) package.cpath, id )), + taskList = {}, + counter = utility.counter(), + currentTask = nil, } end end ---- 发布任务 -function m:task() +--- 勇者是否有空 +function m:isIdle(brave) + return brave.currentTask == nil and not next(brave.taskList) +end + +--- 给勇者推送任务 +function m:pushTask(brave, name, ...) + local taskID = brave.counter() + local co = coroutine.running() + brave.taskpad:push(name, taskID, ...) + brave.taskList[taskID] = co + return coroutine.yield(co) +end + +--- 从勇者处接收任务反馈 +function m:popTask(brave, id, ...) + local co = brave.taskList[id] + if not co then + log.warn(('Brave pushed unknown task result: [%d] => [%d]'):format(brave.id, id)) + return + end + brave.taskList[id] = nil + coroutine.resume(co, ...) +end +--- 发布任务 +---@parma name string +function m:task(name, ...) + local _, main = coroutine.running() + if main then + error('不能在主协程中发布任务') + end + for _, brave in ipairs(self.braves) do + if self:isIdle(brave) then + return self:pushTask(brave, name, ...) + end + end end return m diff --git a/server-beta/src/pub/pub.lua b/server-beta/src/pub/pub.lua deleted file mode 100644 index 0fd7945f..00000000 --- a/server-beta/src/pub/pub.lua +++ /dev/null @@ -1,39 +0,0 @@ -local thread = require 'bee.thread' -local taskpad = require 'pub.taskpad' -local waiter = require 'pub.waiter' -local brave = require 'pub.brave' - ----@class pub -local m = {} -m.type = 'pub' - ---- 委托人招募勇者,勇者会从公告板上领取任务,完成任务后到看板娘处交付任务 -function m:recruitBraves(num) - if self.mode ~= 'client' then - error('只有委托人可以招募勇者') - end - for _ = 1, num do - local n = #self.braves + 1 - self.braves[n] = brave(n) - end -end - ---- 委托人发布任务 -function m:task() - -end - ---- 注册成为委托人 -function m:registerClient() - self.mode = 'client' - self.braves = {} -end - ---- 注册成为勇者 -function m:registerBrave(id) - self.mode = 'brave' - self.taskpad = thread.channel('taskpad' .. id) - self.waiter = thread.channel('waiter' .. id) -end - -return m diff --git a/server-beta/src/service.lua b/server-beta/src/service.lua index 06e2de51..0aaf5a23 100644 --- a/server-beta/src/service.lua +++ b/server-beta/src/service.lua @@ -1,11 +1,28 @@ -local client = require 'pub.client' -local thread = require 'bee.thread' +local client = require 'pub.client' +local subprocess = require 'bee.subprocess' +local thread = require 'bee.thread' +local task = require 'task' +local utility = require 'utility' local m = {} m.type = 'service' +function m:listenProto() + subprocess.filemode(io.stdin, 'b') + subprocess.filemode(io.stdout, 'b') + io.stdin:setvbuf 'no' + io.stdout:setvbuf 'no' + coroutine.wrap(function () + while true do + local proto = client:task('loadProto') + log.debug('proto:', utility.dump(proto)) + end + end) +end + function m:start() client:recruitBraves(4) + self:listenProto() end return m diff --git a/server-beta/src/task.lua b/server-beta/src/task.lua new file mode 100644 index 00000000..fa44b7c6 --- /dev/null +++ b/server-beta/src/task.lua @@ -0,0 +1,7 @@ +local thread = require 'bee.thread' + +---@class task +local m = {} +m.type = 'task' + +return m |