diff --git a/plugins/mod_shard.lua b/plugins/mod_shard.lua index 8ca4b90..67d5616 100644 --- a/plugins/mod_shard.lua +++ b/plugins/mod_shard.lua @@ -41,14 +41,36 @@ local function get_local_rooms(host) return rooms; end +local function is_persistent_room(jid) + local node, host, _ = jid_split(jid); + local bare = node..'@'..host; + + if hosts[host] and hosts[host].muc.rooms[bare] then + return hosts[host].muc.rooms[bare]._data.persistent; + end + return false; +end + +local function check_redis_info(room) + local rhost = redis_mucs.get_room_host(room); + + if rhost ~= shard_name then + module:log("info", "clean wrong shard info for room[%s]", room); + redis_mucs.clean_room_host(room, rhost); + redis_mucs.set_room_host(room, shard_name); + end +end + local function handle_room_event(event) local to = event.stanza.attr.to; local node, host, _ = jid_split(to); - local rhost; + local rhost, bare; if node then - if hosts[host].muc.rooms[node] then - module:log("debug", "room[%s] is hosted here. Nothing to do", node); + bare = node..'@'..host; + if not is_persistent_room(bare) and hosts[host].muc.rooms[bare] then + module:log("debug", "room[%s] is hosted here. Nothing to do", bare); + check_redis_info(bare); return nil; end module:log("debug", "looking up target room shard for %s", to); @@ -65,7 +87,14 @@ local function handle_room_event(event) end if not rhost then - module:log("debug", "room not found. Nothing to do"); + assert(bare); + if is_persistent_room(bare) then + module:log("info", + "restore missing info for persistent room[%s]", bare); + redis_mucs.set_room_host(bare, shard_name); + else + module:log("debug", "room not found. Nothing to do"); + end return nil; end @@ -128,6 +157,21 @@ local function handle_event (event) return stop_process_local; end +local function handle_shard_error(event) + local server_id = event.shard + local stanza = event.stanza + local jid = stanza.attr.to; + local _, host, _ = jid_split(jid); + + if hosts[host].muc then + module:log("debug", + "to MUC %s detected, clean conference %s", host, jid); + redis_mucs.clean_room_host(jid, server_id) + else + redis_sessions.clean_host(jid, server_id) + end +end + module:hook("iq/bare", handle_event, 1000); module:hook("iq/full", handle_event, 1000); module:hook("iq/host", handle_event, 1000); @@ -137,4 +181,5 @@ module:hook("message/host", handle_event, 1000); module:hook("presence/bare", handle_event, 1000); module:hook("presence/full", handle_event, 1000); module:hook("presence/host", handle_event, 1000); +module:hook_global("shard/error", handle_shard_error); module:log("debug", "hooked at %s", module:get_host()); diff --git a/plugins/mod_shard_client.lua b/plugins/mod_shard_client.lua index bef1383..cc7efa2 100644 --- a/plugins/mod_shard_client.lua +++ b/plugins/mod_shard_client.lua @@ -199,12 +199,12 @@ local function handle_send(event) conn, err = connect(shard); if not conn then module:log("error", "couldn't connect to "..shard..": "..err); + module:fire_event("shard/error", {shard = shard, stanza = stanza}); return; end conns[shard] = conn; queue[shard] = {}; end - if stanza.attr.via then local via = ut.string.explode(';', stanza.attr.via); module:log("debug", "via:%s", ut.table.tostring(via)); diff --git a/plugins/mod_sipwise_redis_mucs.lua b/plugins/mod_sipwise_redis_mucs.lua index 54a20bc..3fec312 100644 --- a/plugins/mod_sipwise_redis_mucs.lua +++ b/plugins/mod_sipwise_redis_mucs.lua @@ -33,35 +33,16 @@ end local function muc_created(event) local room = event.room; - local node, host, _ = jid.split(room.jid) + redis_mucs.set_room_host(room.jid, redis_config.server_id); module:log("debug", "muc-room-created %s", room.jid); - - if not test_connection() then client_connect() end - -- TODO: check that there is no other "room.jid" value? - if redis_client:set(room.jid, redis_config.server_id) then - module:log("debug", "save [%s]=%s", room.jid, redis_config.server_id); - end - if redis_client:sadd(host, redis_config.server_id..":"..node) > 0 then - module:log("debug", "append [%s]=>%s:%s", host, - redis_config.server_id, node); - end end local function muc_destroyed(event) local room = event.room; - local node, host, _ = jid.split(room.jid) + redis_mucs.clean_room_host(room.jid, redis_config.server_id); module:log("debug", "muc-room-destroyed %s", room.jid); - - if not test_connection() then client_connect() end - if redis_client:del(room.jid) > 0 then - module:log("debug", "remove [%s]=%s", room.jid, redis_config.server_id); - end - if redis_client:srem(host, redis_config.server_id..":"..node) > 0 then - module:log("debug", "remove [%s]=>%s:%s", host, - redis_config.server_id, node); - end end local function split_key(key) @@ -85,8 +66,23 @@ function redis_mucs.get_rooms(host) return res; end +function redis_mucs.set_room_host(room_jid, server_id) + local node, host, _ = jid.split(room_jid); + local bare_jid = node.."@"..host; + + if not test_connection() then client_connect() end + -- TODO: check that there is no other "bare_jid" value? + if redis_client:set(bare_jid, server_id) then + module:log("debug", "save [%s]=%s", bare_jid, server_id); + end + if redis_client:sadd(host, server_id..":"..node) > 0 then + module:log("debug", "append [%s]=>%s:%s", host, + server_id, node); + end +end + function redis_mucs.get_room_host(room_jid) - local node, domain = jid.split(room_jid); + local node, domain, _ = jid.split(room_jid); local bare_jid = node.."@"..domain; module:log("debug", "search room:%s host", bare_jid); @@ -94,6 +90,19 @@ function redis_mucs.get_room_host(room_jid) return redis_client:get(bare_jid); end +function redis_mucs.clean_room_host(room_jid, server_id) + local node, host, _ = jid.split(room_jid); + local bare_jid = node.."@"..host; + + if not test_connection() then client_connect() end + if redis_client:del(bare_jid) > 0 then + module:log("debug", "remove [%s]=%s", bare_jid, server_id); + end + if redis_client:srem(host, server_id..":"..node) > 0 then + module:log("debug", "remove [%s]=>%s:%s", host, server_id, node); + end +end + function module.load() redis_config = module:get_option("redis_sessions_auth", redis_config); end diff --git a/plugins/mod_sipwise_redis_sessions.lua b/plugins/mod_sipwise_redis_sessions.lua index d627014..5e2dd76 100644 --- a/plugins/mod_sipwise_redis_sessions.lua +++ b/plugins/mod_sipwise_redis_sessions.lua @@ -12,7 +12,8 @@ local array = require "util.array"; local redis = require 'redis'; local redis_config = { port = 6739, host = "127.0.0.1", - server_id = "0", redis_db = "2" + server_id = "0", redis_db = "2", + clean_local_sessions = true, }; local redis_client; @@ -48,17 +49,23 @@ local function resource_bind(event) redis_client:sadd(bare_jid, redis_config.server_id..":"..resource); end -local function resource_unbind(event) - local session, _ = event.session, event.error; - local node, domain, resource = jid.split(session.full_jid); - local full_jid, bare_jid = session.full_jid, node.."@"..domain; +local function remove_resource(full_jid) + local node, domain, resource = jid.split(full_jid); + local bare_jid = node.."@"..domain; - module:log("debug", "resource-unbind from %s", session.host); - module:log("debug", "remove [%s]=%s", full_jid, redis_config.server_id); if not test_connection() then client_connect() end redis_client:del(full_jid); - module:log("debug", "remove [%s]=>%s:%s", bare_jid, redis_config.server_id, resource); + module:log("debug", "remove [%s]=%s", full_jid, redis_config.server_id); redis_client:srem(bare_jid, redis_config.server_id..":"..resource); + module:log("debug", "remove [%s]=>%s:%s", bare_jid, + redis_config.server_id, resource); +end + +local function resource_unbind(event) + local session, _ = event.session, event.error; + + module:log("debug", "resource-unbind from %s", session.host); + remove_resource(session.full_jid); end local function split_key(key) @@ -66,6 +73,23 @@ local function split_key(key) return t[1], t[2]; end +local function clean_local_sessions(host) + if not test_connection() then client_connect() end + local l = redis_client:keys('*@'..host); + for _, bare_jid in ipairs(l) do + local resources = redis_client:smembers(bare_jid); + module:log("debug", "clean previous sessions for %s on %s", + bare_jid, redis_config.server_id); + for _, resource in ipairs(resources) do + local server, old_resource = split_key(resource); + if server == redis_config.server_id then + module:log("debug", "remove old resource %s", old_resource); + remove_resource(bare_jid..'/'..old_resource); + end + end + end +end + function redis_sessions.get_hosts(j) local node, domain = jid.split(j); local bare_jid = node.."@"..domain; @@ -85,12 +109,32 @@ function redis_sessions.get_hosts(j) return res; end +function redis_sessions.clean_host(j, server_id) + local bare_jid = jid.bare(j); + module:log("debug", "clean jid %s from %s", bare_jid, server_id); + if not test_connection() then client_connect() end + local l = redis_client:smembers(bare_jid); + for _,v in pairs(l) do + local h, _ = split_key(v); + if h == server_id then + redis_client:srem(bare_jid, v); + redis_client:del(v); + module:log("debug", "removed %s from %s", v, bare_jid); + end + end +end + function module.load() redis_config = module:get_option("redis_sessions_auth", redis_config); end function module.add_host(module) - module:hook("resource-bind", resource_bind, 200); - module:hook("resource-unbind", resource_unbind, 200); - module:log("debug", "hooked at %s", module:get_host()); + local host = module:get_host(); + + if module:get_host_type() ~= "component" then + module:hook("resource-bind", resource_bind, 200); + module:hook("resource-unbind", resource_unbind, 200); + clean_local_sessions(host); + module:log("debug", "hooked at %s", host); + end end