Increase server to client com message limit.

Long sscsm com messages are now split over multiple chat messages.
This commit is contained in:
luk3yx 2020-02-14 21:17:46 +13:00
parent b2b23654d4
commit 7ed12d0419
4 changed files with 76 additions and 8 deletions

View File

@ -83,7 +83,8 @@ change in a future release.
- `sscsm.com_send(player_or_name, channel, msg)`: Sends `msg`
(a JSON-compatible object) to `player_or_name` on the SSCSM com channel
`channel`. Channel names should be `modname` or `modname:name` to prevent
conflicts.
conflicts. *Although the limit for server-to-client messages is 128MB, I
strongly recommend not sending large messages when not necessary.*
- `sscsm.com_send_all(channel, msg)`: Sends `msg` to all clients that are
running SSCSMs.
- `sscsm.register_on_com_receive(channel, function(name, msg))`: Registers a

View File

@ -202,6 +202,7 @@ local function validate_channel(channel)
end
end
local msgids = {}
function sscsm.com_send(pname, channel, msg)
if minetest.is_player(pname) then
pname = pname:get_player_name()
@ -212,8 +213,34 @@ function sscsm.com_send(pname, channel, msg)
else
msg = assert(minetest.write_json(msg))
end
minetest.chat_send_player(pname, '\001SSCSM_COM\001' .. channel .. '\001'
.. msg)
-- Short messages can be sent all at once
local prefix = '\001SSCSM_COM\001' .. channel .. '\001'
if #msg < 65300 then
minetest.chat_send_player(pname, prefix .. msg)
return
end
-- You should never send messages over 128MB to clients
assert(#msg < 134217728)
-- Otherwise split the message into multiple chunks
prefix = prefix .. '\001'
local id = #msgids + 1
local i = 0
msgids[id] = true
local total_msgs = math.ceil(#msg / 65000)
repeat
i = i + 1
minetest.chat_send_player(pname, prefix .. id .. '\001' .. i ..
'\001' .. total_msgs .. '\001' .. msg:sub(1, 65000))
msg = msg:sub(65001)
until msg == ""
-- Allow the ID to be reused on the next globalstep.
minetest.after(0, function()
msgids[id] = nil
end)
end
local registered_on_receive = {}
@ -272,7 +299,7 @@ function sscsm.com_send_all(channel, msg)
end
-- Testing
minetest.after(1, function()
minetest.after(0, function()
-- Check if any other SSCSMs have been registered.
local c = 0
for k, v in pairs(sscsm.registered_csms) do

View File

@ -212,6 +212,30 @@ function sscsm.register_on_com_receive(channel, func)
table.insert(registered_on_receive[channel], func)
end
-- Load split messages
local incoming_messages = {}
local function load_split_message(chan, msg)
print('Got split message chunk')
local id, i, l, pkt = msg:match('^\1([^\1]+)\1([^\1]+)\1([^\1]+)\1(.*)$')
id, i, l = tonumber(id), tonumber(i), tonumber(l)
if not incoming_messages[id] then
incoming_messages[id] = {}
end
local msgs = incoming_messages[id]
msgs[i] = pkt
-- Return true if all the messages have been received
if #msgs < l then return end
for i = 1, l do
if not msgs[i] then
return
end
end
incoming_messages[id] = nil
return table.concat(msgs, '')
end
-- Detect messages and handle them
minetest.register_on_receiving_chat_message(function(message)
local chan, msg = message:match('^\001SSCSM_COM\001([^\001]*)\001(.*)$')
@ -222,7 +246,16 @@ minetest.register_on_receiving_chat_message(function(message)
if not callbacks then return end
-- Load the message
if msg:sub(1, 1) == '\002' then
local prefix = msg:sub(1, 1)
if prefix == '\001' then
msg = load_split_message(chan, msg)
if not msg then
return true
end
prefix = msg:sub(1, 1)
end
if prefix == '\002' then
msg = msg:sub(2)
else
msg = minetest.parse_json(msg)
@ -230,7 +263,10 @@ minetest.register_on_receiving_chat_message(function(message)
-- Run callbacks
for _, func in ipairs(callbacks) do
func(msg)
local ok, msg = pcall(func, msg)
if not ok then
minetest.log('error', '[SSCSM] ' .. tostring(msg))
end
end
return true
end)

View File

@ -89,6 +89,10 @@ sscsm.every(60, function(param1)
end, 123)
sscsm.register_on_com_receive('sscsm:testing', function(msg)
print('Got ' .. minetest.serialize(msg):sub(8) .. ' from the server')
sscsm.com_send('sscsm:testing', msg)
if #msg > 400 then
print('Got large message of length ' .. #msg .. ' from the server')
else
sscsm.com_send('sscsm:testing', msg)
print('Got ' .. minetest.serialize(msg):sub(8) .. ' from the server')
end
end)