local os_execute = os.execute function set_insecure_environment(env) env = env or _G os_execute = env.os.execute local socket local original_require = rawget(_G, "require") rawset(_G, "require", env.require) pcall(function() socket = env.require"socket" end) rawset(_G, "require", original_require) build_bridge = (socket and build_socket_bridge) or build_file_bridge set_insecure_environment = nil end local ping_timeout = 5 function build_socket_bridge(name, logs) local server = socket.tcp() server:bind("*", 0) server:settimeout(5) local ip, port = server:getsockname() local logs=logs or minetest.get_worldpath().."/bridges/"..name.."/logs.txt" minetest.mkdir(minetest.get_worldpath().."/bridges/"..name) modlib.file.create_if_not_exists(logs, "") minetest.register_on_shutdown(function() server:close() end) local self = { info={name=name, server=server, ip=ip, port=port}, serve=function() end } function self.start(process) os_execute(process:format("", tostring(port), logs)) self.client = server:accept() self.start=nil end function self.write(line) self.client:send(line.."\n") end function self.listen(line_consumer) local status, err_msg=server:listen() if status ~= 1 then minetest.request_shutdown("adv_chat: "..name..": socket error: "..err_msg) end minetest.register_globalstep(function() local available = socket.select({self.client}, nil, 0) if next(available) then local line, error = self.client:receive("*l") if not error then if modlib.text.starts_with(line, "[KIL]") then minetest.request_shutdown("adv_chat: "..name..": process terminated: "..line:sub(6)) else line_consumer(line) end elseif error=="closed" then minetest.request_shutdown("adv_chat: "..name..": socket closed") end end end) end return self end function build_file_bridge(name, input, output, logs) modlib.file.process_bridge_build(name, input, output, logs) local self self = { info={name=name, ref=modlib.file.process_bridges[name]}, serve=function() return modlib.file.process_bridge_serve(name) end, write=function(line) return modlib.file.process_bridge_write(name, line) end, listen=function(line_consumer) function consumer(line) if modlib.text.starts_with(line, "[PIN]") then self.last_ping = minetest.get_gametime() elseif modlib.text.starts_with(line, "[KIL]") then minetest.request_shutdown("adv_chat: "..name..": process terminated: "..line:sub(6)) else return line_consumer(line) end end return modlib.file.process_bridge_listen(name, consumer) end } self.start=function(process) modlib.file.process_bridge_start(name, process, os_execute) self.last_ping = minetest.get_gametime() minetest.register_globalstep(function() self.last_ping = self.last_ping or minetest.get_gametime() if minetest.get_gametime()-self.last_ping > ping_timeout then minetest.request_shutdown("adv_chat: "..name..": process crashed (no ping during last "..ping_timeout.."s)") end end) self.start = nil end return self end