0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-15 14:31:11 +01:00
construct/modules/m_event_append.cc

221 lines
4.9 KiB
C++
Raw Normal View History

// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// 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.
ircd::mapi::header
IRCD_MODULE
{
"Matrix Event Library :Streaming tools"
};
namespace ircd::m
{
extern log::log event_append_log;
}
decltype(ircd::m::event_append_log)
ircd::m::event_append_log
{
"m.event.append"
};
IRCD_MODULE_EXPORT
ircd::m::event::append::append(json::stack::array &array,
const event &event_,
const opts &opts)
:boolean{[&]
{
json::stack::object object
{
array
};
const bool ret
{
append
{
object, event_, opts
}
};
return ret;
}}
{
}
IRCD_MODULE_EXPORT
ircd::m::event::append::append(json::stack::object &object,
const event &event,
const opts &opts)
:boolean{[&]
{
const bool has_event_idx
{
opts.event_idx && *opts.event_idx
};
const bool has_client_txnid
{
opts.client_txnid && *opts.client_txnid
};
const bool has_user
{
opts.user_id && opts.user_room
};
const bool sender_is_user
{
has_user && json::get<"sender"_>(event) == *opts.user_id
};
const auto txnid_idx
{
!has_client_txnid && sender_is_user && opts.query_txnid?
opts.user_room->get(std::nothrow, "ircd.client.txnid", event.event_id):
0UL
};
#if defined(RB_DEBUG) && 0
if(!has_client_txnid && !txnid_idx && sender_is_user && opts.query_txnid)
log::dwarning
{
log, "Could not find transaction_id for %s from %s in %s",
string_view{event.event_id},
json::get<"sender"_>(event),
json::get<"room_id"_>(event)
};
#endif
if(has_event_idx && !defined(json::get<"state_key"_>(event)) && m::redacted(*opts.event_idx))
{
log::debug
{
log, "Not sending event '%s' because redacted.",
string_view{event.event_id},
};
return false;
}
if(!json::get<"state_key"_>(event) && has_user)
{
const m::user::ignores ignores{*opts.user_id};
if(ignores.enforce("events") && ignores.has(json::get<"sender"_>(event)))
{
log::debug
{
log, "Not sending event '%s' because '%s' is ignored by '%s'",
string_view{event.event_id},
json::get<"sender"_>(event),
string_view{*opts.user_id}
};
return false;
}
}
if(!json::get<"event_id"_>(event))
{
auto _event(event);
json::get<"event_id"_>(_event) = event.event_id;
object.append(_event);
}
else object.append(event);
if(json::get<"state_key"_>(event) && has_event_idx)
{
const auto prev_idx
{
room::state::prev(*opts.event_idx)
};
if(prev_idx)
m::get(std::nothrow, prev_idx, "content", [&object]
(const json::object &content)
{
json::stack::member
{
object, "prev_content", content
};
});
}
json::stack::object unsigned_
{
object, "unsigned"
};
const json::value age
{
// When the opts give an explicit age, use it.
opts.age != std::numeric_limits<long>::min()?
opts.age:
// If we have depth information, craft a value based on the
// distance to the head depth; if this is 0 in riot the event will
// "stick" at the bottom of the timeline. This may be advantageous
// in the future but for now we make sure the result is non-zero.
json::get<"depth"_>(event) >= 0 && opts.room_depth && *opts.room_depth >= 0L?
(*opts.room_depth + 1 - json::get<"depth"_>(event)) + 1:
// We don't have depth information, so we use the origin_server_ts.
// It is bad if it conflicts with other appends in the room which
// did have depth information.
!opts.room_depth && json::get<"origin_server_ts"_>(event)?
ircd::time<milliseconds>() - json::get<"origin_server_ts"_>(event):
// Finally, this special value will eliminate the age altogether
// during serialization.
json::undefined_number
};
json::stack::member
{
unsigned_, "age", age
};
if(has_client_txnid)
json::stack::member
{
unsigned_, "transaction_id", *opts.client_txnid
};
if(txnid_idx)
m::get(std::nothrow, txnid_idx, "content", [&unsigned_]
(const json::object &content)
{
json::stack::member
{
unsigned_, "transaction_id", unquote(content.get("transaction_id"))
};
});
#ifdef IRCD_M_EVENT_APPEND_DEBUG
log::debug
{
event_append_log, "%s %s idx:%lu in %s depth:%ld txnid:%s idx:%lu age:%ld %s,%s",
opts.user_id? string_view{*opts.user_id} : string_view{},
string_view{event.event_id},
opts.event_idx? *opts.event_idx : 0UL,
json::get<"room_id"_>(event),
json::get<"depth"_>(event),
has_client_txnid? *opts.client_txnid : string_view{},
txnid_idx,
int64_t(age),
json::get<"type"_>(event),
json::get<"state_key"_>(event),
};
#endif
return true;
}}
{
}