summaryrefslogtreecommitdiff
path: root/script-beta/proto/proto.lua
diff options
context:
space:
mode:
Diffstat (limited to 'script-beta/proto/proto.lua')
-rw-r--r--script-beta/proto/proto.lua133
1 files changed, 133 insertions, 0 deletions
diff --git a/script-beta/proto/proto.lua b/script-beta/proto/proto.lua
new file mode 100644
index 00000000..f04653d5
--- /dev/null
+++ b/script-beta/proto/proto.lua
@@ -0,0 +1,133 @@
+local subprocess = require 'bee.subprocess'
+local util = require 'utility'
+local await = require 'await'
+local pub = require 'pub'
+local jsonrpc = require 'jsonrpc'
+local ErrorCodes = require 'define.ErrorCodes'
+
+local reqCounter = util.counter()
+
+local m = {}
+
+m.ability = {}
+m.waiting = {}
+
+function m.getMethodName(proto)
+ if proto.method:sub(1, 2) == '$/' then
+ return proto.method:sub(3), true
+ else
+ return proto.method, false
+ end
+end
+
+function m.on(method, callback)
+ m.ability[method] = callback
+end
+
+function m.response(id, res)
+ if id == nil then
+ log.error('Response id is nil!', util.dump(res))
+ return
+ end
+ -- res 可能是nil,为了转成json时保留nil,使用 container 容器
+ local data = util.container()
+ data.id = id
+ data.result = res
+ local buf = jsonrpc.encode(data)
+ log.debug('Response', id, #buf)
+ io.stdout:write(buf)
+end
+
+function m.responseErr(id, code, message)
+ if id == nil then
+ log.error('Response id is nil!', util.dump(message))
+ return
+ end
+ local buf = jsonrpc.encode {
+ id = id,
+ error = {
+ code = code,
+ message = message,
+ }
+ }
+ log.debug('ResponseErr', id, #buf)
+ io.stdout:write(buf)
+end
+
+function m.notify(name, params)
+ local buf = jsonrpc.encode {
+ method = name,
+ params = params,
+ }
+ log.debug('Notify', name, #buf)
+ io.stdout:write(buf)
+end
+
+function m.awaitRequest(name, params)
+ local id = reqCounter()
+ local buf = jsonrpc.encode {
+ id = id,
+ method = name,
+ params = params,
+ }
+ log.debug('Request', name, #buf)
+ io.stdout:write(buf)
+ return await.wait(function (waker)
+ m.waiting[id] = waker
+ end)
+end
+
+function m.doMethod(proto)
+ local method, optional = m.getMethodName(proto)
+ local abil = m.ability[method]
+ if not abil then
+ if not optional then
+ log.warn('Recieved unknown proto: ' .. method)
+ end
+ if proto.id then
+ m.responseErr(proto.id, ErrorCodes.MethodNotFound, method)
+ end
+ return
+ end
+ await.create(function ()
+ local clock = os.clock()
+ local ok, res = xpcall(abil, log.error, proto.params)
+ local passed = os.clock() - clock
+ if passed > 0.2 then
+ log.debug(('Method [%s] takes [%.3f]sec.'):format(method, passed))
+ end
+ if not proto.id then
+ return
+ end
+ if ok then
+ m.response(proto.id, res)
+ else
+ m.responseErr(proto.id, ErrorCodes.InternalError, res)
+ end
+ end)
+end
+
+function m.doResponse(proto)
+ local id = proto.id
+ local waker = m.waiting[id]
+ if not waker then
+ log.warn('Response id not found: ' .. util.dump(proto))
+ return
+ end
+ m.waiting[id] = nil
+ if proto.error then
+ log.warn(('Response error [%d]: %s'):format(proto.error.code, proto.error.message))
+ return
+ end
+ waker(proto.result)
+end
+
+function m.listen()
+ subprocess.filemode(io.stdin, 'b')
+ subprocess.filemode(io.stdout, 'b')
+ io.stdin:setvbuf 'no'
+ io.stdout:setvbuf 'no'
+ pub.task('loadProto')
+end
+
+return m