summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server-beta/src/json/decode.lua153
-rw-r--r--server-beta/src/json/encode.lua135
-rw-r--r--server-beta/src/json/init.lua6
-rw-r--r--server-beta/src/jsonrpc.lua15
-rw-r--r--server-beta/src/pub/brave.lua1
-rw-r--r--server-beta/src/pub/client.lua45
-rw-r--r--server-beta/src/pub/pub.lua39
-rw-r--r--server-beta/src/service.lua21
-rw-r--r--server-beta/src/task.lua7
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