added debug features to the lua and python jrpc servers.

Added doc of lua func item
This commit is contained in:
2025-12-31 13:38:19 +01:00
parent f54e09098a
commit 2e9c5e6c52
17 changed files with 129 additions and 54 deletions

View File

@@ -8,7 +8,7 @@ from interpreter.utils.eval import evaluate
class TestItemCheckValue(TestItem):
"""check item usage.
check usage:{check: {name: check my func output, steps: ['$(fn_echo) < 5']}}
check usage:{check: {name: check my func output, steps: ['$(pfn_echo) < 5']}}
"""
def __init__(self, dict_item, parent = None, status_queue=None, filename=""):
self._name = cst.TYPE_CHECK.item_name

View File

@@ -50,6 +50,7 @@ class TestItemLuaFunc(TestItem):
if success == TestValue.SUCCESS:
self.result.set(TestValue.SUCCESS)
res, reported_values = ret
print(res)
reported_values = {**reported_values, "returned": res}
self.result.reported = ret[1]
@@ -58,7 +59,7 @@ class TestItemLuaFunc(TestItem):
tm.print_debug(textwrap.indent(pprint.pformat(res), " |"))
# The result of the func test item is put in global dir and result
tm.setgd("fn_" + self._name, res)
tm.setgd("lfn_" + self._name, res)
self.result.value = res
else:

View File

@@ -58,7 +58,7 @@ class TestItemPyFunc(TestItem):
tm.print_debug(textwrap.indent(pprint.pformat(res), " |"))
# The result of the func test item is put in global dir and result
tm.setgd("fn_" + self._name, res)
tm.setgd("pfn_" + self._name, res)
self.result.value = res
else:

View File

@@ -38,7 +38,7 @@ Usage example (server):
Usage example (client):
clt = JsonRpcClient(port)
clt = JsonRpcClient(host, port)
clt.start()
result = clt.call('method_name', {'foo': 'bar'})
@@ -236,8 +236,9 @@ class JsonRpcBase(threading.Thread):
- `call()` raises `ETUMRuntimeError` if no active connection exists.
"""
def __init__(self, port, req_handler: Callable[[dict], Any]=None, timeout=10, dbg_out=None):
def __init__(self, host, port, req_handler: Callable[[dict], Any]=None, timeout=10, dbg_out=None):
super().__init__()
self._host = host
self._port = port
self._timeout = timeout
self._rpc = None
@@ -306,8 +307,8 @@ class JsonRpcSrv(JsonRpcBase):
The server will raise `ETUMRuntimeError` on accept/connect timeout.
"""
def __init__(self, port, req_handler = None, timeout=10):
super().__init__(port, req_handler, timeout)
def __init__(self, host, port, req_handler = None, timeout=10):
super().__init__(host, port, req_handler, timeout)
self.name = f"JsonRpcSvr_{port}"
def run(self):
@@ -318,12 +319,13 @@ class JsonRpcSrv(JsonRpcBase):
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Link of the socket at the configured port
sock.bind(("localhost", self._port))
sock.bind((self._host, self._port))
sock.settimeout(self._timeout)
# Listens incoming connections
sock.listen(1)
self.print_info(f"listening on {self._host}:{self._port}")
self.print_info("awaiting connection")
tslice = 0.2
@@ -331,6 +333,7 @@ class JsonRpcSrv(JsonRpcBase):
while True:
try:
conn, addr = sock.accept()
self.print_info("Client connected")
except socket.timeout:
if t >= 0:
sleep(tslice)
@@ -364,13 +367,13 @@ class JsonRpcClient(JsonRpcBase):
Typical usage::
clt = JsonRpcClient(port)
clt = JsonRpcClient(host, port)
clt.start()
resp = clt.call('method', {'a': 1})
"""
def __init__(self, port, req_handler = None, timeout=10):
super().__init__(port, req_handler, timeout)
def __init__(self, host, port, req_handler = None, timeout=10):
super().__init__(host, port, req_handler, timeout)
self.name = f"JsonRpcClt_{port}"
def run(self):
@@ -383,7 +386,7 @@ class JsonRpcClient(JsonRpcBase):
t = self._timeout
while True:
try:
sock.connect(("localhost", self._port))
sock.connect((self._host, self._port))
except OSError:
t -= tslice
if t >= 0:

View File

@@ -75,15 +75,20 @@ class LuaFuncExecEngine:
func_proc_path = os.path.join(tm.gd("testium_path"),"lua_func")
lua_env = tm.gd("lua_env", {})
params = [self._lpath, "main.lua", "--host", "127.0.0.1", "--port", f"{self._port}"]
if tm.debug_enabled():
params.append("--verbose")
self._process = subprocess.Popen(
[self._lpath, "main.lua", "--host", "127.0.0.1", "--port", f"{self._port}"], env=lua_env, cwd=func_proc_path
params, env=lua_env, cwd=func_proc_path
)
# Port was reserved until the sub-process is started. Now released.
if sock is not None:
sock.close()
self._rpc = JsonRpcClient(self._port, req_handler=self._req_handler)
self._rpc = JsonRpcClient("localhost", self._port, req_handler=self._req_handler)
self._rpc.start()
def join(self):

View File

@@ -78,15 +78,19 @@ class PyFuncExecEngine:
func_proc_path = tm.gd("testium_path")
params = [self._ppath, "-m", "py_func", "-p", f"{self._port}"]
if tm.debug_enabled():
params.append("-v")
self._process = subprocess.Popen(
[self._ppath, "-m", "py_func", "-p", f"{self._port}"], cwd=func_proc_path
params, cwd=func_proc_path
)
# Port was reserved until the sub-process is started. Now released.
if sock is not None:
sock.close()
self._rpc = JsonRpcClient(self._port, req_handler=self._req_handler)
self._rpc = JsonRpcClient("localhost", self._port, req_handler=self._req_handler)
self._rpc.start()
def join(self):

View File

@@ -27,7 +27,7 @@ local function _get_func_by_path(file_path, func_name)
local target_func = module[func_name]
if type(target_func) ~= "function" then
return nil, "Function '" .. func_name .. "' not found in " .. file_path
return nil, "Function '" .. func_name .. "' not found in '" .. file_path .. "'"
end
return target_func
@@ -52,9 +52,10 @@ function handle.func_call(params)
-- 3. Execute the function
if err == nil then
print(string.format("Function executed from '%s'", pfile))
utils.log("func_call function found '%s', '%s'", file, fname)
succ, ret = pcall(func, table.unpack(prms))
utils.log("func_call returned '%s'", tostring(ret))
utils.log("func_call returned '%s', '%s'", tostring(succ), tostring(ret))
if succ then
res = ret

View File

@@ -6,9 +6,9 @@ JSONRPC.__index = JSONRPC
function JSONRPC.new(sock)
local self = setmetatable({}, JSONRPC)
self.sock = sock -- Function to transmit string data to transport (TCP/Websocket)
self.methods = {} -- Methods the server provides to the client
self.pending = {} -- Requests sent to client waiting for response
self.sock = sock -- Function to transmit string data to transport (TCP/Websocket)
self.methods = {} -- Methods the server provides to the client
self.pending = {} -- Requests sent to client waiting for response
self.next_id = 1
self.sock:settimeout(0.2)
@@ -24,7 +24,7 @@ end
function JSONRPC:handle_message(raw_data)
utils.log("received: '%s'", raw_data)
local ok, msg = pcall(json.decode, raw_data)
if not ok then return self:_send_error(nil, -32700, "Parse error") end
if not ok then return self:_send_error(nil, "received message parse error in lua server") end
-- 1. Check if it's a Response (has 'result' or 'error' and 'id')
if (msg.id ~= nil) and (msg.result ~= nil or msg.error ~= nil) then
@@ -44,37 +44,27 @@ function JSONRPC:_handle_request(req)
local ok, ret
local res, err
if not method then
if req.id then self:_send_error(req.id, -32601, "Method not found") end
if req.id then self:_send_error(req.id, string.format("Method '%s' not registered in lua server")) end
return
end
utils.log("calling '%s'", method)
ok, ret = pcall(method, req.params)
utils.log("returned '%s', '%s'", tostring(ok), tostring(res))
ok, ret, err = pcall(method, req.params)
utils.log("Call returned ok='%s', ret='%s'", tostring(ok), tostring(ret))
-- Only send response if it's not a Notification (notifications have no ID)
if req.id then
if ok then
res, err = ret
res = ret
if res == nil then
self:_send_error(req.id, -32603, "Internal error: " .. tostring(err))
self:_send_error(req.id, tostring(err))
else
self:_send({ jsonrpc = "2.0", result = {returned = res}, id = req.id })
self:_send({ jsonrpc = "2.0", result = { returned_value = res }, id = req.id })
end
else
self:_send_error(req.id, -32603, "Internal error: " .. tostring(ret))
self:_send_error(req.id, tostring(err))
end
end
end
--- INTERNAL: Handle responses to requests WE sent
-- function JSONRPC:_handle_response(res)
-- local callback = self.pending[res.id]
-- if callback then
-- callback(res.error, res.result)
-- self.pending[res.id] = nil
-- end
-- end
--- Call a method on the client
function JSONRPC:call(method, params)
local id = self.next_id
@@ -109,10 +99,10 @@ function JSONRPC:_send(data)
return self.sock:send(j .. "\n")
end
function JSONRPC:_send_error(id, code, message)
function JSONRPC:_send_error(id, message)
self:_send({
jsonrpc = "2.0",
error = { code = code, message = message },
error = message,
id = id
})
end
@@ -137,4 +127,4 @@ function JSONRPC:loop()
end
end
return JSONRPC
return JSONRPC

View File

@@ -5,7 +5,7 @@ local config = {
host = "0.0.0.0",
port = 9000,
timeout = 60,
verbose = true,
verbose = false,
}
local function usage()

View File

@@ -22,15 +22,19 @@ def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--ip", type=str, help="Ip address or hostname to listen to",
default="localhost")
parser.add_argument("-p", "--port", type=int, help="port to listen to",
default="/etc/jsonrpc-echo.conf")
default=9000)
parser.add_argument("-v", "--verbose", action='store_true', help="port to listen to")
args = parser.parse_args()
thrd_api = _init_api(args.port)
thrd_api = _init_api(args.ip, args.port)
outstream = TcpStdOut()
stdio_redir.redirect(outstream)
# debug the server
# thrd_api.dbg_out = stdio_redir.ini_stdout
if args.verbose:
thrd_api.dbg_out = stdio_redir.ini_stdout
try:
while thrd_api.is_alive():
thrd_api.join(1)

View File

@@ -46,7 +46,7 @@ def func_exec(file: str, func_name: str, params: list, verbose: bool=True):
reported_values = {}
mod = func_module(file)
if verbose:
print("Function executed from {}".format(
print("Function executed from '{}'".format(
inspect.getabsfile(mod)))
# check of the FunctionItem descendants

View File

@@ -49,7 +49,7 @@ def _make_api(name):
for k in SUPPORTED_API:
setattr(thismodule, k, _make_api(k))
def _init_api(port):
def _init_api(host, port):
"""Start and initialize the remote function handler.
Starts a ``FuncHandler`` bound to ``port``, runs it and blocks until
@@ -63,7 +63,7 @@ def _init_api(port):
``_func_call_thread``.
"""
global _func_call_thread
_func_call_thread = FuncHandler(port)
_func_call_thread = FuncHandler(host, port)
_func_call_thread.start()
_func_call_thread.wait_ready()
return _func_call_thread