I created a nifty one that we are using heavily in my company and in our products.
Not super documented but I think you will understand it.
Here you go:
local M = {}
local register = hash("register")
local unregister = hash("unregister")
local unregister_all = hash("unregister_all")
local debug_time = require "utils.debug_time"
local context = "msg_proxy"
local msg_id = {}
local msg_group = {}
local msg_both = {}
local long_storage_buffer = 50
local long_storage = {}
for i = 1,long_storage_buffer do
table.insert(long_storage, { fetched = true, msg = nil, msg_id = nil })
end
local key_ix = 0
--- Post message to all registered listeners
-- @param tbl Table to store for receivers
-- @return table with message_key
function M.create_long_message(tbl, message_id)
key_ix = key_ix%long_storage_buffer + 1
local buffer_tbl = long_storage[key_ix]
if buffer_tbl.fetched == false then
-- note: this must NOT use log instead of print because log uses long messages -> stack overflow
print("No script retrieved long message: [" .. key_ix .."] [" .. tostring(buffer_tbl.msg_id) .. "], will be overwritten by circular buffer")
end
buffer_tbl.msg = tbl
buffer_tbl.msg_id = message_id
buffer_tbl.fetched = false
return { message_key = key_ix }
end
function M.get_message(key, message_id)
if type(key) == "table" then key = message.message_key end
if type(message_id) == "string" then message_id = hash(message_id) end
local tbl = long_storage[key]
if message_id and tbl.msg_id ~= message_id then
print("found wrong message type in long message storage (requested:" .. tostring(message_id) ..", found:" .. tostring(tbl.msg_id) .. ")")
end
tbl.fetched = true
return tbl.msg
end
--- Post message to all registered listeners
-- @param message_id
-- @param message
-- @param group Optional
-- @param long Optional If message is too long to be sent by msg.post a table_storage key is sent instead.
function M.post(message_id, message, group, long)
if type(message_id) == "string" then message_id = hash(message_id) end
message = message or {}
if long then
message = M.create_long_message(message, message_id)
end
local lists
-- post to group
if group then
lists = msg_group[group]
if lists ~= nil then
for k,v in pairs(lists) do
msg.post(v,message_id,message)
end
end
-- post to both
local tbl = msg_both[message_id]
if tbl ~= nil then
local lists = tbl[group]
if lists ~= nil then
for k,v in pairs(lists) do
msg.post(v,message_id,message)
end
end
end
end
-- post to id_msg_id
lists = msg_id[message_id]
if lists then
for k,v in pairs(lists) do
msg.post(v,message_id,message)
end
end
end
function M.register(mi, group)
local sender = msg.url()
-- hash_to_hex(sender.socket) ..
local readable = hash_to_hex(sender.path) .. hash_to_hex(sender.fragment or hash(""))
if mi and group then
if type(mi) == "string" then mi = hash(mi) end
if msg_both[mi] == nil then msg_both[mi] = {} end
local tbl = msg_both[mi]
if tbl[group] == nil then tbl[group] = {} end
tbl[group][readable] = sender
elseif mi then
local str
if type(mi) == "string" then
str = mi
mi = hash(str)
end
if msg_id[mi] == nil then msg_id[mi] = {} end
if msg_id[mi][readable] then
log.w(string.format("Already registered message %s to %s",tostring(mi),tostring(sender)),context)
return
end
msg_id[mi][readable] = sender
elseif group then
if msg_group[group] == nil then msg_group[group] = {} end
msg_group[group][readable] = sender
end
end
function M.unregister(mi, group)
local sender = msg.url()
--hash_to_hex(sender.socket) ..
local readable = hash_to_hex(sender.path) .. hash_to_hex(sender.fragment or hash(""))
if mi and group then
if type(mi) == "string" then mi = hash(mi) end
local tbl = msg_both[mi]
if tbl == nil then
log.i("Cant unregister a message_id that doesn't exist: " .. mi, context)
elseif tbl[group] == nil then
log.i("Cant unregister a group that doesn't exist: " .. group, context)
else
tbl[group][readable] = nil
end
elseif mi then
if type(mi) == "string" then mi = hash(mi) end
if msg_id[mi] == nil then
log.i("Cant unregister a message_id that doesn't exist: " .. mi, context)
else
msg_id[mi][readable]=nil
end
elseif group then
if msg_group[group] == nil then
log.i("Cant unregister a group that doesn't exist: " .. group, context)
else
msg_group[group][readable]=nil
end
else
error("msg_proxy.script needs message_id or msg_group in message when registering")
end
end
function M.has_listener(message_id, group)
if type(message_id) == "string" then message_id = hash(message_id) end
local lists
if group then
lists = msg_group[group]
else
lists = msg_id[message_id]
end
if lists == nil or next(lists) == nil then return false end
return true
end
-- Lazy version of destroying all listeners for a script. Will parse through all tables.
-- Use M.unregister if performance is important
function M.destroy()
local sender = msg.url()
--hash_to_hex(sender.socket) ..
local readable = hash_to_hex(sender.path) .. hash_to_hex(sender.fragment or hash(""))
-- id
for k,v in pairs(msg_id) do
for kk,vv in pairs(v) do
if kk == readable then
msg_id[k][kk] = nil
end
end
end
-- group
for k,v in pairs(msg_group) do
for kk,vv in pairs(v) do
if kk == readable then
msg_id[k][kk] = nil
end
end
end
-- both
for k,v in pairs(msg_both) do
for kk,vv in pairs(v) do
for kkk,vvv in pairs(vv) do
if kkk == readable then
msg_both[k][kk][kkk] = nil
end
end
end
end
end
function M.final()
local sender = msg.url()
for k,tbl in pairs(msg_id) do
for kk,vv in pairs(tbl) do
if kk == sender then
tbl[kk] = nil
end
end
end
for k,tbl in pairs(msg_group) do
for kk,vv in pairs(tbl) do
if kk == sender then
tbl[kk] = nil
end
end
end
end
return M