LuaATC: Improve error/print logging, log only to subscribed players

master
orwell96 2021-02-17 19:10:40 +01:00
parent d13a610c2e
commit 1e4156d0a4
3 changed files with 99 additions and 33 deletions

View File

@ -109,8 +109,9 @@ function ac.run_in_env(pos, evtdata, customfct_p)
atwarn("LuaAutomation component at",ph,": Not an existing environment: "..(nodetbl.env or "<nil>"))
return false
end
local env = atlatc.envs[nodetbl.env]
if not nodetbl.code or nodetbl.code=="" then
atwarn("LuaAutomation component at",ph,": No code to run! (insert -- to suppress warning)")
env:log("warning", "LuaAutomation component at",ph,": No code to run! (insert -- to suppress warning)")
return false
end
@ -141,14 +142,14 @@ function ac.run_in_env(pos, evtdata, customfct_p)
end
local datain=nodetbl.data or {}
local succ, dataout = atlatc.envs[nodetbl.env]:execute_code(datain, nodetbl.code, evtdata, customfct)
local succ, dataout = env:execute_code(datain, nodetbl.code, evtdata, customfct)
if succ then
atlatc.active.nodes[ph].data=atlatc.remove_invalid_data(dataout)
else
atlatc.active.nodes[ph].err=dataout
atwarn("LuaAutomation ATC interface rail at",ph,": LUA Error:",dataout)
env:log("error", "LuaATC component at",ph,": LUA Error:",dataout)
if meta then
meta:set_string("infotext", "LuaAutomation ATC interface rail, ERROR:"..dataout)
meta:set_string("infotext", "LuaATC component, ERROR:"..dataout)
end
--TODO temporary
--if customfct.atc_id then

View File

@ -43,12 +43,78 @@ core.register_chatcommand("env_create", {
privs = {atlatc=true},
func = function(name, param)
if not param or param=="" then return false, "Name required!" end
if string.find(param, "[^a-zA-Z0-9-_]") then return false, "Invalid name (only common characters)" end
if atlatc.envs[param] then return false, "Environment already exists!" end
atlatc.envs[param] = atlatc.env_new(param)
atlatc.envs[param].subscribers = {name}
return true, "Created environment '"..param.."'. Use '/env_setup "..param.."' to define global initialization code, or start building LuaATC components!"
end,
})
core.register_chatcommand("env_subscribe", {
params = "<environment name>",
description = "Subscribe to the log of an Advtrains LuaATC environment",
privs = {atlatc=true},
func = function(name, param)
local env=atlatc.envs[param]
if not env then return false,"Invalid environment name!" end
for _,pname in ipairs(env.subscribers) do
if pname==name then
return false, "Already subscribed!"
end
end
table.insert(env.subscribers, name)
return true, "Subscribed to environment '"..param.."'."
end,
})
core.register_chatcommand("env_unsubscribe", {
params = "<environment name>",
description = "Unubscribe to the log of an Advtrains LuaATC environment",
privs = {atlatc=true},
func = function(name, param)
local env=atlatc.envs[param]
if not env then return false,"Invalid environment name!" end
for index,pname in ipairs(env.subscribers) do
if pname==name then
table.remove(env.subscribers, index)
return true, "Successfully unsubscribed!"
end
end
return false, "Not subscribed to environment '"..param.."'."
end,
})
core.register_chatcommand("env_subscriptions", {
params = "[environment name]",
description = "List Advtrains LuaATC environments you are subscribed to (no parameters) or subscribers of an environment (giving an env name).",
privs = {atlatc=true},
func = function(name, param)
if not param or param=="" then
local none=true
for envname, env in pairs(atlatc.envs) do
for _,pname in ipairs(env.subscribers) do
if pname==name then
none=false
minetest.chat_send_player(name, envname)
end
end
end
if none then
return false, "Not subscribed to any!"
end
return true
end
local env=atlatc.envs[param]
if not env then return false,"Invalid environment name!" end
local none=true
for index,pname in ipairs(env.subscribers) do
none=false
minetest.chat_send_player(name, pname)
end
if none then
return false, "No subscribers!"
end
return true
end,
})
minetest.register_on_player_receive_fields(function(player, formname, fields)

View File

@ -33,12 +33,12 @@ local env_proto={
self.sdata=data.sdata and atlatc.remove_invalid_data(data.sdata) or {}
self.fdata={}
self.init_code=data.init_code or ""
self.step_code=data.step_code or ""
self.subscribers=data.subscribers or {}
end,
save = function(self)
-- throw any function values out of the sdata table
self.sdata = atlatc.remove_invalid_data(self.sdata)
return {sdata = self.sdata, init_code=self.init_code, step_code=self.step_code}
return {sdata = self.sdata, init_code=self.init_code, subscribers=self.subscribers}
end,
}
@ -50,14 +50,6 @@ local safe_globals = {
"tonumber", "tostring", "type", "unpack", "_VERSION"
}
--print is actually minetest.chat_send_all()
--using advtrains.print_concat_table because it's cool
local function safe_print(t, ...)
local str=advtrains.print_concat_table({t, ...})
minetest.log("action", "[atlatc] "..str)
minetest.chat_send_all(str)
end
local function safe_date(f, t)
if not f then
-- fall back to old behavior
@ -95,7 +87,6 @@ local mp=minetest.get_modpath("advtrains_luaautomation")
local static_env = {
--core LUA functions
print = safe_print,
string = {
byte = string.byte,
char = string.char,
@ -252,7 +243,6 @@ for _, name in pairs(safe_globals) do
static_env[name] = _G[name]
end
--The environment all code calls get is a table that has set static_env as metatable.
--In general, every variable is local to a single code chunk, but kept persistent over code re-runs. Data is also saved, but functions and userdata and circular references are removed
--Init code and step code's environments are not saved
@ -265,6 +255,14 @@ local proxy_env={}
-- returns: true, fenv if successful; nil, error if error
function env_proto:execute_code(localenv, code, evtdata, customfct)
-- create us a print function specific for this environment
if not self.safe_print_func then
local myenv = self
self.safe_print_func = function(...)
myenv:log("info", ...)
end
end
local metatbl ={
__index = function(t, i)
if i=="S" then
@ -277,6 +275,8 @@ function env_proto:execute_code(localenv, code, evtdata, customfct)
return customfct[i]
elseif localenv and localenv[i] then
return localenv[i]
elseif i=="print" then
return self.safe_print_func
end
return static_env[i]
end,
@ -306,35 +306,39 @@ function env_proto:run_initcode()
if self.init_code and self.init_code~="" then
local old_fdata=self.fdata
self.fdata = {}
atprint("[atlatc]Running initialization code for environment '"..self.name.."'")
--atprint("[atlatc]Running initialization code for environment '"..self.name.."'")
local succ, err = self:execute_code({}, self.init_code, {type="init", init=true})
if not succ then
atwarn("[atlatc]Executing InitCode for '"..self.name.."' failed:"..err)
self:log("error", "Executing InitCode for '"..self.name.."' failed:"..err)
self.init_err=err
if old_fdata then
self.fdata=old_fdata
atwarn("[atlatc]The 'F' table has been restored to the previous state.")
self:log("warning", "The 'F' table has been restored to the previous state.")
end
end
end
end
function env_proto:run_stepcode()
if self.step_code and self.step_code~="" then
local succ, err = self:execute_code({}, self.step_code, nil, {})
if not succ then
--TODO
end
-- log to environment subscribers. severity can be "error", "warning" or "info" (used by internal print)
function env_proto:log(severity, ...)
local text=advtrains.print_concat_table({"[atlatc "..self.name.." "..severity.."]", ...})
minetest.log("action", text)
for _, pname in ipairs(self.subscribers) do
minetest.chat_send_player(pname, text)
end
end
-- env.subscribers table may be directly altered by callers.
--- class interface
function atlatc.env_new(name)
local newenv={
name=name,
init_code="",
step_code="",
sdata={}
sdata={},
subscribers={},
}
setmetatable(newenv, {__index=env_proto})
return newenv
@ -351,11 +355,6 @@ function atlatc.run_initcode()
env:run_initcode()
end
end
function atlatc.run_stepcode()
for envname, env in pairs(atlatc.envs) do
env:run_stepcode()
end
end