local sproto = require "sproto.sproto" local conn = require "conn" local sconn = require "sconn" local mt = {} local function new(client_pbin, server_pbin) local client_proto = sproto.new(client_pbin) local server_proto = sproto.new(server_pbin) local client = client_proto:host "package" -- local server = server_proto:host "package" local client_request = client:attach(server_proto) local raw = { v_session_index = 1, v_request_session = {}, v_response_handle = {}, v_out = {}, v_conn = false, v_client = client, v_client_request = client_request, } return setmetatable(raw, { __index = mt, }) end function mt:connect(host, port, stable) self.v_request_session = {} local conn_module = stable and sconn or conn local obj, err = conn_module.connect_host(host, port) if not obj then return false, err else self.v_conn = obj return true end end function mt:check_connected() return self.v_conn end local function dispatch(self, resp) local client = self.v_client local _type, v1, v2, v3 = client:dispatch(resp) if _type == "RESPONSE" then local session, response = v1, v2 local session_item = self.v_request_session[session] local handle = session_item.handle local tt = type(handle) if tt == "function" then handle(response) elseif tt == "thread" then local success, err = coroutine.resume(handle, response) if not success then error(err) end else error("error handle type:" .. tt .. " from msg:" .. tostring(session_item.name)) end self.v_request_session[session] = nil elseif _type == "REQUEST" then local name, request, response = v1, v2, v3 local handle = self.v_response_handle[name] local data = handle(request) if response then data = response(data) self.v_conn:send_msg(data) end else error("error dispatch type: " .. tostring(_type)) end end function mt:update() local success, err, status = self.v_conn:update() if success then local out = self.v_out local count = self.v_conn:recv_msg(out) for i = 1, count do local resp = out[i] local ok, oerr = xpcall(dispatch, debug.traceback, self, resp) if not ok then error("error dispatch: " .. oerr) end end end return success, err, status end local function request(self, name, t, session_index) local req = self.v_client_request(name, t, session_index) return self.v_conn:send_msg(req) end function mt:call(name, t, cb) local session_index = self.v_session_index self.v_session_index = session_index + 1 assert(self.v_request_session[session_index] == nil, session_index) local session_item = { name = name, handle = false, } self.v_request_session[session_index] = session_item if cb then session_item.handle = cb request(self, name, t, session_index) elseif coroutine.isyieldable() then session_item.handle = coroutine.running() request(self, name, t, session_index) return coroutine.yield() else assert(cb) end end function mt:invoke(name, t) return request(self, name, t) end function mt:register(name, cb) assert(cb) assert(self.v_response_handle[name] == nil) self.v_response_handle[name] = cb end function mt:close() if self.v_conn then self.v_conn:close() end self.v_conn = false end function mt:reconnect(cb) local conn_module = self.v_conn if conn_module.reconnect then local ok, err = conn_module:reconnect(function(success) cb(success) -- success 表示 是否重连成功 print("end reconnect", success) end) print("begin reconnect", ok, err) end end return new