diff --git a/include/ircd/m/room/aliases.h b/include/ircd/m/room/aliases.h index 1c99f7038..64754934c 100644 --- a/include/ircd/m/room/aliases.h +++ b/include/ircd/m/room/aliases.h @@ -13,11 +13,14 @@ /// Interface to the aliases /// -/// This interface focuses specifically on room aliases. These are aliases contained -/// in a room's state. +/// This interface focuses specifically on room aliases. These are aliases +/// contained in a room's state. There is also an aliases::cache which stores +/// the result of directory lookups as well as the contents found through this +/// interface in order to resolve aliases to room_ids. /// struct ircd::m::room::aliases { + struct cache; using closure_bool = std::function; static bool for_each(const m::room &, const string_view &server, const closure_bool &); @@ -35,3 +38,17 @@ struct ircd::m::room::aliases :room{room} {} }; + +struct ircd::m::room::aliases::cache +{ + using closure_bool = std::function; + + static bool for_each(const string_view &server, const closure_bool &); + static bool for_each(const closure_bool &); + static bool has(const alias &); + static bool get(std::nothrow_t, const alias &, const id::closure &); + static void get(const alias &, const id::closure &); + static id::buf get(const alias &); + static bool set(const alias &, const id &); + static bool del(const alias &); +}; diff --git a/ircd/m_room.cc b/ircd/m_room.cc index ea0f80362..98fd5cebc 100644 --- a/ircd/m_room.cc +++ b/ircd/m_room.cc @@ -2438,6 +2438,109 @@ ircd::m::room::aliases::for_each(const m::room &room, return call(room, server, closure); } +// +// room::aliases::cache +// + +bool +ircd::m::room::aliases::cache::del(const alias &a) +{ + using prototype = bool (const alias &); + + static mods::import call + { + "m_room_aliases", "ircd::m::room::aliases::cache::del" + }; + + return call(a); +} + +bool +ircd::m::room::aliases::cache::set(const alias &a, + const id &i) +{ + using prototype = bool (const alias &, const id &); + + static mods::import call + { + "m_room_aliases", "ircd::m::room::aliases::cache::set" + }; + + return call(a, i); +} + +ircd::m::room::id::buf +ircd::m::room::aliases::cache::get(const alias &a) +{ + id::buf ret; + get(a, [&ret](const id &room_id) + { + ret = room_id; + }); + + return ret; +} + +void +ircd::m::room::aliases::cache::get(const alias &a, + const id::closure &c) +{ + if(!get(std::nothrow, a, c)) + throw m::NOT_FOUND + { + "Cannot find room_id for %s", + string_view{a} + }; +} + +bool +ircd::m::room::aliases::cache::get(std::nothrow_t, + const alias &a, + const id::closure &c) +{ + using prototype = bool (std::nothrow_t, const alias &, const id::closure &); + + static mods::import call + { + "m_room_aliases", "ircd::m::room::aliases::cache::get" + }; + + return call(std::nothrow, a, c); +} + +bool +ircd::m::room::aliases::cache::has(const alias &a) +{ + using prototype = bool (const alias &); + + static mods::import call + { + "m_room_aliases", "ircd::m::room::aliases::cache::has" + }; + + return call(a); +} + +bool +ircd::m::room::aliases::cache::for_each(const closure_bool &c) +{ + return for_each(string_view{}, c); +} + +bool +ircd::m::room::aliases::cache::for_each(const string_view &s, + const closure_bool &c) +{ + using prototype = bool (const string_view &, const closure_bool &); + + static mods::import call + { + "m_room_aliases", "ircd::m::room::aliases::cache::for_each" + }; + + return call(s, c); +} + // // room::power // diff --git a/modules/m_room_aliases.cc b/modules/m_room_aliases.cc index 4cf65a95d..bdd983c66 100644 --- a/modules/m_room_aliases.cc +++ b/modules/m_room_aliases.cc @@ -29,7 +29,7 @@ alias_room }; // -// m::room::aliases impl +// m::room::aliases // bool @@ -75,6 +75,160 @@ ircd::m::room::aliases::for_each(const m::room &room, return ret; } +// +// m::room::aliases::cache +// + +bool +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::del(const alias &alias) +{ + char swapbuf[m::id::room_alias::buf::SIZE]; + const string_view &key + { + alias.swap(swapbuf) + }; + + const auto &event_idx + { + alias_room.get("ircd.room.alias", key) + }; + + if(!event_idx) + return false; + + const auto event_id + { + m::event_id(event_idx) + }; + + if(!event_id) + return false; + + const auto ret + { + redact(alias_room, m::me.user_id, event_id, "deleted") + }; + + return true; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::set(const alias &alias, + const id &id) +{ + char swapbuf[m::id::room_alias::buf::SIZE]; + const string_view &key + { + alias.swap(swapbuf) + }; + + const auto ret + { + send(alias_room, m::me.user_id, "ircd.room.alias", key, + { + { "room_id", id } + }) + }; + + return true; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::get(std::nothrow_t, + const alias &alias, + const id::closure &closure) +{ + char swapbuf[m::id::room_alias::buf::SIZE]; + const string_view &key + { + alias.swap(swapbuf) + }; + + const auto &event_idx + { + alias_room.get("ircd.room.alias", key) + }; + + if(!event_idx) + return false; + + bool ret{false}; + m::get(std::nothrow, event_idx, "content", [&closure, &ret] + (const json::object &content) + { + const json::string &room_id + { + content.get("room_id") + }; + + if(!empty(room_id)) + { + ret = true; + closure(room_id); + } + }); + + return ret; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::has(const alias &alias) +{ + char swapbuf[m::id::room_alias::buf::SIZE]; + const string_view &key + { + alias.swap(swapbuf) + }; + + return alias_room.has("ircd.room.alias", key); +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::for_each(const string_view &server, + const closure_bool &closure) +{ + const m::room::state state + { + alias_room + }; + + bool ret{true}; + const m::room::state::closure_bool reclosure{[&server, &closure, &ret] + (const string_view &type, const string_view &state_key, const m::event::idx &event_idx) + { + thread_local char swapbuf[m::id::room_alias::buf::SIZE]; + const alias &alias + { + m::id::unswap(state_key, swapbuf) + }; + + if(server && alias.host() != server) + return false; + + m::get(std::nothrow, event_idx, "content", [&closure, &ret, &alias] + (const json::object &content) + { + const json::string &room_id + { + content.get("room_id") + }; + + if(!empty(room_id)) + ret = closure(alias, room_id); + }); + + return ret; + }}; + + state.for_each("ircd.room.alias", server, reclosure); + return ret; +} + // // hook handlers //