A mod for minetest that listens on a socket and sends and receives chat messages to all clients connected to that socket. To install, add bridgesocket to secure.trusted_mods.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
5.7 KiB

local modpath = minetest.get_modpath(minetest.get_current_modname())
-- Handle mod security if needed
local ie, req_ie = _G, minetest.request_insecure_environment
if req_ie then ie = req_ie() end
if not ie then
error("The bridge socket mod requires access to insecure functions in order "..
"to work. Please add the bridgesocket mod to your secure.trusted_mods "..
"setting or disable the bridgesocket mod.")
end
-- The build of Lua that Minetest comes with only looks for libraries under
-- /usr/local/share and /usr/local/lib but LuaSocket is often installed under
-- /usr/share and /usr/lib.
if not rawget(_G, "jit") and package.config:sub(1, 1) == "/" then
ie.package.path = ie.package.path..
";/usr/share/lua/5.1/?.lua"..
";/usr/share/lua/5.1/?/init.lua"
ie.package.cpath = ie.package.cpath..
";/usr/lib/lua/5.1/?.so"..
";/usr/lib64/lua/5.1/?.so"
ie.package.cpath = "/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;"..ie.package.cpath
end
-- Temporarily set require so that LuaIRC can access it
local old_require = require
require = ie.require
-- Silence warnings about `module` in `ltn12`.
local old_module = rawget(_G, "module")
rawset(_G, "module", ie.module)
local socket = require("socket")
require = old_require
rawset(_G, "module", old_module)
serverSocket = assert(socket.bind('*', 8869))
serverSocket:settimeout(0)
set = {}
clients = {}
table.insert(set, serverSocket)
function add_client_socket(sock)
sock:settimeout(0)
io.write("Inserting client in set\n")
table.insert(set, sock)
table.insert(clients, { sock = sock, buffer = '' })
end
function remove_client_socket(sock)
sock:close()
io.write("Removing client from set\n")
for i, s in ipairs(set) do
if(sock == s) then
table.remove(set, i)
break
end
end
remove_client_by_sock(sock)
end
function remove_client_by_sock(sock)
for i, client in ipairs(clients) do
if client.sock == sock then
table.remove(clients, i)
return
end
end
end
function get_client_by_sock(sock)
for _, client in ipairs(clients) do
if client.sock == sock then
return client
end
end
return nil
end
function spansToText(spans)
local ret = ''
for _, span in ipairs(spans) do
if type(span) == 'string' then
ret = ret .. span
else
if span.color then
ret = ret .. minetest.get_color_escape_sequence(span.color)
end
if span.bgcolor then
ret = ret .. minetest.get_background_escape_sequence(span.bgcolor)
end
ret = ret .. span.text
if span.color then
ret = ret .. minetest.get_color_escape_sequence('#ffffffff')
end
if span.bgcolor then
ret = ret .. minetest.get_background_escape_sequence('#00000000')
end
end
end
return ret
end
function process_input(sock, data)
local client = get_client_by_sock(sock)
for i = 1, string.len(data) do
local c = string.byte(data, i)
if c == 0xff then
client.buffer = ''
elseif c == 0x00 then
local parsed, err = minetest.parse_json(client.buffer)
if err then
print('Could not parse json: '..client.buffer)
return
end
if parsed and parsed.type and parsed.type == 'chat' and parsed.spans then
minetest.chat_send_all(spansToText(parsed.spans))
end
else
if string.len(client.buffer) <= 65536 then
client.buffer = client.buffer .. string.char(c)
end
end
end
end
function server_iteration()
local readable, _, error = socket.select(set, nil, 0)
for _, input in ipairs(readable) do
-- is it a server socket?
if input == serverSocket then
local new = input:accept()
if new then
add_client_socket(new)
end
-- it is a client socket
else
local line, error, partial = input:receive(1024)
if partial and string.len(partial) > 0 then
process_input(input, partial)
end
if error ~= 'timeout' then
remove_client_socket(input)
end
end
end
end
minetest.register_globalstep(server_iteration)
function sendMessage(msg)
local json, err = minetest.write_json(msg)
if err then
print('Could not encode json')
return
end
local str = '\xff'..json..'\x00'
local writable, error = socket.skip(1, socket.select(nil, set, 0))
if not error then
for __, output in ipairs(writable) do
if output ~= input then
output:send(str .. "\n")
end
end
end
end
function join(player)
sendMessage({ type = 'join', player = player:get_player_name()})
end
function chat(name, message)
sendMessage({ type = 'chat', player = name, message = message })
end
function dead(player, reason)
local reasonData = { type = reason.type }
if reason.object then
local entity = reason.object:get_luaentity()
if entity then
reasonData.object = entity.name
end
end
sendMessage({ type = 'dead', player = player:get_player_name(), reason = reasonData })
end
function leave(player)
sendMessage({ type = 'leave', player = player:get_player_name() })
end
function shutdown()
sendMessage({ type = 'shutdown' })
end
minetest.register_on_joinplayer(join)
minetest.register_on_chat_message(chat)
minetest.register_on_dieplayer(dead)
minetest.register_on_leaveplayer(leave)
minetest.register_on_shutdown(shutdown)