diff --git a/include/ircd/m/user.h b/include/ircd/m/user.h index a95a02047..ed62aa6ae 100644 --- a/include/ircd/m/user.h +++ b/include/ircd/m/user.h @@ -33,3 +33,4 @@ namespace ircd::m #include "user/room_tags.h" #include "user/filter.h" #include "user/ignores.h" +#include "user/highlight.h" diff --git a/include/ircd/m/user/highlight.h b/include/ircd/m/user/highlight.h new file mode 100644 index 000000000..3ee841038 --- /dev/null +++ b/include/ircd/m/user/highlight.h @@ -0,0 +1,31 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2019 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_M_USER_HIGHLIGHT_H + +/// Interface to user highlighting and counting. +struct ircd::m::user::highlight +{ + m::user user; + + bool has(const event &) const; + bool has(const event::idx &) const; + + size_t count_between(const m::room &, const event::idx_range &) const; + size_t count_to(const m::room &, const event::idx &) const; + size_t count(const m::room &) const; + size_t count() const; + + highlight(const m::user &user) + noexcept + :user{user} + {} +}; diff --git a/include/ircd/m/user/user.h b/include/ircd/m/user/user.h index 25df0d97b..72b56b98b 100644 --- a/include/ircd/m/user/user.h +++ b/include/ircd/m/user/user.h @@ -23,6 +23,7 @@ struct ircd::m::user struct room_tags; struct filter; struct ignores; + struct highlight; using id = m::id::user; using closure = std::function; diff --git a/modules/client/sync/rooms/unread_notifications.cc b/modules/client/sync/rooms/unread_notifications.cc index 5e8654224..eea59536b 100644 --- a/modules/client/sync/rooms/unread_notifications.cc +++ b/modules/client/sync/rooms/unread_notifications.cc @@ -146,17 +146,20 @@ ircd::m::sync::_notification_count(const room &room, } long -ircd::m::sync::_highlight_count(const room &r, - const user &u, +ircd::m::sync::_highlight_count(const room &room, + const user &user, const event::idx &a, const event::idx &b) { - using proto = size_t (const user &, const room &, const event::idx &, const event::idx &); - - static mods::import count + const m::user::highlight highlight { - "m_user", "highlighted_count__between" + user }; - return count(u, r, a, a < b? b : a); + const m::event::idx_range range + { + a, a < b? b : a + }; + + return highlight.count_between(room, range); } diff --git a/modules/m_user.cc b/modules/m_user.cc index 3d899355f..eb2e1306b 100644 --- a/modules/m_user.cc +++ b/modules/m_user.cc @@ -44,87 +44,50 @@ user_create(const m::user::id &user_id, return user; } -extern "C" bool -highlighted_event(const event &event, - const user &user) +/////////////////////////////////////////////////////////////////////////////// +// +// m/user/highlight.h +// + +size_t +IRCD_MODULE_EXPORT +ircd::m::user::highlight::count() +const { - if(json::get<"type"_>(event) != "m.room.message") - return false; - - const json::object &content + const m::user::rooms rooms { - json::get<"content"_>(event) + user }; - const string_view &formatted_body + size_t ret(0); + rooms.for_each("join", m::user::rooms::closure_bool{[this, &ret] + (const m::room &room, const string_view &) { - content.get("formatted_body") - }; - - if(has(formatted_body, user.user_id)) + ret += this->count(room); return true; - - const string_view &body - { - content.get("body") - }; - - return has(body, user.user_id); -} - -extern "C" size_t -highlighted_count__between(const user &user, - const room &room, - const event::idx &a, - const event::idx &b) -{ - static const event::fetch::opts fopts - { - event::keys::include - { - "type", "content", - } - }; - - room::messages it - { - room, &fopts - }; - - assert(a <= b); - it.seek_idx(a); - - if(!it && !exists(room)) - throw m::NOT_FOUND - { - "Cannot find room '%s' to count highlights for '%s'", - string_view{room.room_id}, - string_view{user.user_id} - }; - else if(!it) - throw m::NOT_FOUND - { - "Event @ idx:%lu or idx:%lu not found in '%s' to count highlights for '%s'", - a, - b, - string_view{room.room_id}, - string_view{user.user_id}, - }; - - size_t ret{0}; - for(++it; it && it.event_idx() < b; ++it) - { - const event &event{*it}; - ret += highlighted_event(event, user); - } + }}); return ret; } -extern "C" size_t -highlighted_count__since(const user &user, - const room &room, - const event::idx ¤t) +size_t +IRCD_MODULE_EXPORT +ircd::m::user::highlight::count(const m::room &room) +const +{ + const auto ¤t + { + head_idx(room) + }; + + return count_to(room, current); +} + +size_t +IRCD_MODULE_EXPORT +ircd::m::user::highlight::count_to(const m::room &room, + const event::idx ¤t) +const { event::id::buf last_read_buf; const event::id last_read @@ -140,17 +103,100 @@ highlighted_count__since(const user &user, index(last_read) }; - return highlighted_count__between(user, room, a, current); -} - -extern "C" size_t -highlighted_count(const user &user, - const room &room) -{ - const auto ¤t + const event::idx_range range { - head_idx(room) + a, current }; - return highlighted_count__since(user, room, current); + return count_between(room, range); +} + +size_t +IRCD_MODULE_EXPORT +ircd::m::user::highlight::count_between(const m::room &room, + const event::idx_range &range) +const +{ + static const event::fetch::opts fopts + { + event::keys::include { "type", "content" }, + }; + + m::room::messages it + { + room, &fopts + }; + + assert(range.first <= range.second); + it.seek_idx(range.first); + + if(!it && !exists(room)) + throw m::NOT_FOUND + { + "Cannot find room '%s' to count highlights for '%s'", + string_view{room.room_id}, + string_view{user.user_id} + }; + else if(!it) + throw m::NOT_FOUND + { + "Event @ idx:%lu or idx:%lu not found in '%s' to count highlights for '%s'", + range.first, + range.second, + string_view{room.room_id}, + string_view{user.user_id}, + }; + + size_t ret{0}; + for(++it; it && it.event_idx() < b; ++it) + { + const event &event{*it}; + ret += has(event); + } + + return ret; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::user::highlight::has(const event::idx &event_idx) +const +{ + const event::fetch event + { + event_idx, std::nothrow + }; + + return event.valid? + has(event): + false; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::user::highlight::has(const event &event) +const +{ + if(json::get<"type"_>(event) != "m.room.message") + return false; + + const json::object &content + { + json::get<"content"_>(event) + }; + + const string_view &formatted_body + { + content.get("formatted_body") + }; + + if(ircd::has(formatted_body, user.user_id)) + return true; + + const string_view &body + { + content.get("body") + }; + + return ircd::has(body, user.user_id); }