mirror of
https://github.com/matrix-construct/construct
synced 2025-01-14 16:46:50 +01:00
modules/m_presence: Move federation send hook here; complete functionality.
This commit is contained in:
parent
c760eb0a12
commit
9973c80916
2 changed files with 116 additions and 37 deletions
|
@ -255,36 +255,3 @@ put__presence_status(client &client,
|
||||||
client, http::OK
|
client, http::OK
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
handle_my_presence_changed(const m::event &event,
|
|
||||||
m::vm::eval &eval)
|
|
||||||
{
|
|
||||||
if(!my(event))
|
|
||||||
return;
|
|
||||||
|
|
||||||
const m::user::id &user_id
|
|
||||||
{
|
|
||||||
json::get<"sender"_>(event)
|
|
||||||
};
|
|
||||||
|
|
||||||
if(!my(user_id))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// The event has to be an ircd.presence in the user's room, not just a
|
|
||||||
// random ircd.presence typed event in some other room...
|
|
||||||
const m::user::room user_room{user_id};
|
|
||||||
if(json::get<"room_id"_>(event) != user_room.room_id)
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const m::hookfn<m::vm::eval &>
|
|
||||||
my_presence_changed
|
|
||||||
{
|
|
||||||
handle_my_presence_changed,
|
|
||||||
{
|
|
||||||
{ "_site", "vm.effect" },
|
|
||||||
{ "type", "ircd.presence" },
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
using namespace ircd;
|
using namespace ircd;
|
||||||
|
|
||||||
|
static void handle_ircd_presence(const m::event &, m::vm::eval &);
|
||||||
static void handle_edu_m_presence_object(const m::event &, const m::presence &edu);
|
static void handle_edu_m_presence_object(const m::event &, const m::presence &edu);
|
||||||
static void handle_edu_m_presence(const m::event &, m::vm::eval &);
|
static void handle_edu_m_presence(const m::event &, m::vm::eval &);
|
||||||
|
|
||||||
|
@ -19,6 +20,12 @@ IRCD_MODULE
|
||||||
"Matrix Presence"
|
"Matrix Presence"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Coarse enabler for incoming federation presence events. If this is
|
||||||
|
/// disabled then all presence coming over the federation is ignored. Note
|
||||||
|
/// that there are other ways to degrade or ignore presence in various
|
||||||
|
/// other subsystems like sync without losing the data; however presence
|
||||||
|
/// data over the federation is considerable and tiny deployments which
|
||||||
|
/// won't /sync presence to clients should probably quench it here too.
|
||||||
conf::item<bool>
|
conf::item<bool>
|
||||||
federation_incoming
|
federation_incoming
|
||||||
{
|
{
|
||||||
|
@ -26,15 +33,22 @@ federation_incoming
|
||||||
{ "default", true },
|
{ "default", true },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Coarse enabler to send presence events over the federation.
|
||||||
|
conf::item<bool>
|
||||||
|
federation_send
|
||||||
|
{
|
||||||
|
{ "name", "ircd.m.presence.federation.send" },
|
||||||
|
{ "default", false },
|
||||||
|
};
|
||||||
|
|
||||||
log::log
|
log::log
|
||||||
presence_log
|
presence_log
|
||||||
{
|
{
|
||||||
"m.presence"
|
"m.presence"
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const string_view
|
/// This hook processes incoming m.presence events from the federation and
|
||||||
valid_states[];
|
/// turns them into ircd.presence events in the user's room.
|
||||||
|
|
||||||
const m::hookfn<m::vm::eval &>
|
const m::hookfn<m::vm::eval &>
|
||||||
_m_presence_eval
|
_m_presence_eval
|
||||||
{
|
{
|
||||||
|
@ -45,6 +59,9 @@ _m_presence_eval
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern const string_view
|
||||||
|
valid_states[];
|
||||||
|
|
||||||
void
|
void
|
||||||
handle_edu_m_presence(const m::event &event,
|
handle_edu_m_presence(const m::event &event,
|
||||||
m::vm::eval &eval)
|
m::vm::eval &eval)
|
||||||
|
@ -53,7 +70,7 @@ try
|
||||||
if(!federation_incoming)
|
if(!federation_incoming)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(m::my_host(at<"origin"_>(event)))
|
if(my(event))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const json::object &content
|
const json::object &content
|
||||||
|
@ -204,6 +221,101 @@ catch(const m::error &e)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This hook processes ircd.presence events generated internally from local
|
||||||
|
/// users and converts them to m.presence over the federation.
|
||||||
|
const m::hookfn<m::vm::eval &>
|
||||||
|
_ircd_presence_eval
|
||||||
|
{
|
||||||
|
handle_ircd_presence,
|
||||||
|
{
|
||||||
|
{ "_site", "vm.effect" },
|
||||||
|
{ "type", "ircd.presence" },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_ircd_presence(const m::event &event,
|
||||||
|
m::vm::eval &eval)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!federation_send)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const m::user::id &user_id
|
||||||
|
{
|
||||||
|
json::get<"sender"_>(event)
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!my(user_id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The event has to be an ircd.presence in the user's room, not just a
|
||||||
|
// random ircd.presence typed event in some other room...
|
||||||
|
if(!m::user::room::is(json::get<"room_id"_>(event), user_id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get the spec EDU data from our PDU's content
|
||||||
|
const m::edu::m_presence edu
|
||||||
|
{
|
||||||
|
json::get<"content"_>(event)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if the user_id in the content is legitimate. This should have
|
||||||
|
// been checked on any input side, but nevertheless we'll ignore any
|
||||||
|
// discrepancies here for now.
|
||||||
|
if(unlikely(json::get<"user_id"_>(edu) != user_id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The matrix EDU format requires us to wrap this data in an array
|
||||||
|
// called "push" so we copy content into this stack buffer :/
|
||||||
|
char buf[512];
|
||||||
|
json::stack out{buf};
|
||||||
|
{
|
||||||
|
json::stack::array push{out};
|
||||||
|
push.append(edu);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that "sender" is intercepted by the federation sender and not
|
||||||
|
// actually sent over the wire.
|
||||||
|
json::iov edu_event, content;
|
||||||
|
const json::iov::push pushed[]
|
||||||
|
{
|
||||||
|
{ edu_event, { "type", "m.presence" }},
|
||||||
|
{ edu_event, { "sender", user_id }},
|
||||||
|
{ content, { "push", out.completed() }},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setup for a core injection of an EDU.
|
||||||
|
m::vm::copts opts;
|
||||||
|
opts.prop_mask.reset(); // Clear all PDU properties
|
||||||
|
opts.conforming = false; // EDU's are not event::conforms checked
|
||||||
|
opts.notify_clients = false; // Client /sync already saw the ircd.presence
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
m::vm::eval
|
||||||
|
{
|
||||||
|
edu_event, content, opts
|
||||||
|
};
|
||||||
|
|
||||||
|
log::info
|
||||||
|
{
|
||||||
|
presence_log, "%s is %s and %s %zd seconds ago",
|
||||||
|
string_view{user_id},
|
||||||
|
json::get<"currently_active"_>(edu)? "active"_sv : "inactive"_sv,
|
||||||
|
json::get<"presence"_>(edu),
|
||||||
|
json::get<"last_active_ago"_>(edu) / 1000L,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch(const std::exception &e)
|
||||||
|
{
|
||||||
|
log::error
|
||||||
|
{
|
||||||
|
presence_log, "Presence from our %s to federation :%s",
|
||||||
|
string_view{json::get<"sender"_>(event)},
|
||||||
|
e.what(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IRCD_MODULE_EXPORT
|
IRCD_MODULE_EXPORT
|
||||||
ircd::m::presence::get(const std::nothrow_t,
|
ircd::m::presence::get(const std::nothrow_t,
|
||||||
|
|
Loading…
Reference in a new issue