mirror of
https://github.com/matrix-construct/construct
synced 2024-12-25 23:14:13 +01:00
ircd:Ⓜ️ Split event definitions.
This commit is contained in:
parent
91beed59bd
commit
6f1ff08841
14 changed files with 2331 additions and 2269 deletions
|
@ -60,10 +60,35 @@ libircd_matrix_la_SOURCES += dbs.cc
|
|||
libircd_matrix_la_SOURCES += self.cc
|
||||
libircd_matrix_la_SOURCES += matrix.cc
|
||||
libircd_matrix_la_SOURCES += event.cc
|
||||
libircd_matrix_la_SOURCES += event_cached.cc
|
||||
libircd_matrix_la_SOURCES += event_conforms.cc
|
||||
libircd_matrix_la_SOURCES += event_fetch.cc
|
||||
libircd_matrix_la_SOURCES += event_get.cc
|
||||
libircd_matrix_la_SOURCES += event_id.cc
|
||||
libircd_matrix_la_SOURCES += event_index.cc
|
||||
libircd_matrix_la_SOURCES += event_prefetch.cc
|
||||
libircd_matrix_la_SOURCES += event_prev.cc
|
||||
libircd_matrix_la_SOURCES += event_refs.cc
|
||||
libircd_matrix_la_SOURCES += room.cc
|
||||
libircd_matrix_la_SOURCES += room_aliases.cc
|
||||
libircd_matrix_la_SOURCES += room_auth.cc
|
||||
libircd_matrix_la_SOURCES += room_bootstrap.cc
|
||||
libircd_matrix_la_SOURCES += room_create.cc
|
||||
libircd_matrix_la_SOURCES += room_events.cc
|
||||
libircd_matrix_la_SOURCES += room_head.cc
|
||||
libircd_matrix_la_SOURCES += room_history_visibility.cc
|
||||
libircd_matrix_la_SOURCES += user.cc
|
||||
libircd_matrix_la_SOURCES += user_account_data.cc
|
||||
libircd_matrix_la_SOURCES += user_events.cc
|
||||
libircd_matrix_la_SOURCES += user_rooms.cc
|
||||
libircd_matrix_la_SOURCES += user_filter.cc
|
||||
libircd_matrix_la_SOURCES += user_highlight.cc
|
||||
libircd_matrix_la_SOURCES += user_mitsein.cc
|
||||
libircd_matrix_la_SOURCES += user_profile.cc
|
||||
libircd_matrix_la_SOURCES += user_register.cc
|
||||
libircd_matrix_la_SOURCES += user_room_account_data.cc
|
||||
libircd_matrix_la_SOURCES += user_room_tags.cc
|
||||
libircd_matrix_la_SOURCES += breadcrumb_rooms.cc
|
||||
libircd_matrix_la_SOURCES += create.cc
|
||||
libircd_matrix_la_SOURCES += device.cc
|
||||
libircd_matrix_la_SOURCES += display_name.cc
|
||||
libircd_matrix_la_SOURCES += event_append.cc
|
||||
|
@ -82,26 +107,10 @@ libircd_matrix_la_SOURCES += node.cc
|
|||
libircd_matrix_la_SOURCES += presence.cc
|
||||
libircd_matrix_la_SOURCES += pretty.cc
|
||||
libircd_matrix_la_SOURCES += receipt.cc
|
||||
libircd_matrix_la_SOURCES += room_aliases.cc
|
||||
libircd_matrix_la_SOURCES += room_auth.cc
|
||||
libircd_matrix_la_SOURCES += room_bootstrap.cc
|
||||
libircd_matrix_la_SOURCES += room_events.cc
|
||||
libircd_matrix_la_SOURCES += room_head.cc
|
||||
libircd_matrix_la_SOURCES += room_history_visibility.cc
|
||||
libircd_matrix_la_SOURCES += rooms.cc
|
||||
libircd_matrix_la_SOURCES += room_server_acl.cc
|
||||
libircd_matrix_la_SOURCES += rooms_summary.cc
|
||||
libircd_matrix_la_SOURCES += typing.cc
|
||||
libircd_matrix_la_SOURCES += user_account_data.cc
|
||||
libircd_matrix_la_SOURCES += user_events.cc
|
||||
libircd_matrix_la_SOURCES += user_filter.cc
|
||||
libircd_matrix_la_SOURCES += user_highlight.cc
|
||||
libircd_matrix_la_SOURCES += user_mitsein.cc
|
||||
libircd_matrix_la_SOURCES += user_profile.cc
|
||||
libircd_matrix_la_SOURCES += user_register.cc
|
||||
libircd_matrix_la_SOURCES += user_room_account_data.cc
|
||||
libircd_matrix_la_SOURCES += user_rooms.cc
|
||||
libircd_matrix_la_SOURCES += user_room_tags.cc
|
||||
libircd_matrix_la_SOURCES += users.cc
|
||||
libircd_matrix_la_SOURCES += users_servers.cc
|
||||
libircd_matrix_la_SOURCES += conf.cc
|
||||
|
|
2260
matrix/event.cc
2260
matrix/event.cc
File diff suppressed because it is too large
Load diff
104
matrix/event_cached.cc
Normal file
104
matrix/event_cached.cc
Normal file
|
@ -0,0 +1,104 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 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.
|
||||
|
||||
bool
|
||||
ircd::m::cached(const id::event &event_id)
|
||||
{
|
||||
return cached(event_id, event::fetch::default_opts);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::cached(const id::event &event_id,
|
||||
const event::fetch::opts &opts)
|
||||
{
|
||||
if(!db::cached(dbs::event_idx, event_id, opts.gopts))
|
||||
return false;
|
||||
|
||||
const event::idx event_idx
|
||||
{
|
||||
index(event_id, std::nothrow)
|
||||
};
|
||||
|
||||
return event_idx?
|
||||
cached(event_idx, opts.gopts):
|
||||
false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::cached(const event::idx &event_idx)
|
||||
{
|
||||
return cached(event_idx, event::fetch::default_opts);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::cached(const event::idx &event_idx,
|
||||
const event::fetch::opts &opts)
|
||||
{
|
||||
const byte_view<string_view> &key
|
||||
{
|
||||
event_idx
|
||||
};
|
||||
|
||||
if(event::fetch::should_seek_json(opts))
|
||||
return db::cached(dbs::event_json, key, opts.gopts);
|
||||
|
||||
const auto &selection
|
||||
{
|
||||
opts.keys
|
||||
};
|
||||
|
||||
const auto result
|
||||
{
|
||||
cached_keys(event_idx, opts)
|
||||
};
|
||||
|
||||
for(size_t i(0); i < selection.size(); ++i)
|
||||
{
|
||||
auto &column
|
||||
{
|
||||
dbs::event_column.at(i)
|
||||
};
|
||||
|
||||
if(column && selection.test(i) && !result.test(i))
|
||||
{
|
||||
if(!db::has(column, key, opts.gopts))
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ircd::m::event::keys::selection
|
||||
ircd::m::cached_keys(const event::idx &event_idx,
|
||||
const event::fetch::opts &opts)
|
||||
{
|
||||
const byte_view<string_view> &key
|
||||
{
|
||||
event_idx
|
||||
};
|
||||
|
||||
event::keys::selection ret(0);
|
||||
const event::keys::selection &selection(opts.keys);
|
||||
for(size_t i(0); i < selection.size(); ++i)
|
||||
{
|
||||
auto &column
|
||||
{
|
||||
dbs::event_column.at(i)
|
||||
};
|
||||
|
||||
if(column && db::cached(column, key, opts.gopts))
|
||||
ret.set(i);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
423
matrix/event_conforms.cc
Normal file
423
matrix/event_conforms.cc
Normal file
|
@ -0,0 +1,423 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 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.
|
||||
|
||||
namespace ircd::m::vm
|
||||
{
|
||||
extern m::hookfn<eval &> conform_check_event_id;
|
||||
extern m::hookfn<eval &> conform_check_origin;
|
||||
extern m::hookfn<eval &> conform_check_size;
|
||||
extern m::hookfn<eval &> conform_report;
|
||||
}
|
||||
|
||||
/// Check if event_id is sufficient for the room version.
|
||||
decltype(ircd::m::vm::conform_check_event_id)
|
||||
ircd::m::vm::conform_check_event_id
|
||||
{
|
||||
{
|
||||
{ "_site", "vm.conform" }
|
||||
},
|
||||
[](const m::event &event, eval &eval)
|
||||
{
|
||||
// Don't care about EDU's on this hook
|
||||
if(!event.event_id)
|
||||
return;
|
||||
|
||||
// Conditions for when we don't care if the event_id conforms. This
|
||||
// hook only cares if the event_id is sufficient for the version, and
|
||||
// we don't care about the early matrix versions with mxids here.
|
||||
const bool unaffected
|
||||
{
|
||||
!eval.room_version
|
||||
|| eval.room_version == "0"
|
||||
|| eval.room_version == "1"
|
||||
|| eval.room_version == "2"
|
||||
};
|
||||
|
||||
if(eval.room_version == "3")
|
||||
if(!event::id::v3::is(event.event_id))
|
||||
throw error
|
||||
{
|
||||
fault::INVALID, "Event ID %s is not sufficient for version 3 room.",
|
||||
string_view{event.event_id}
|
||||
};
|
||||
|
||||
// note: we check v4 format for all other room versions, including "4"
|
||||
if(!unaffected && eval.room_version != "3")
|
||||
if(!event::id::v4::is(event.event_id))
|
||||
throw error
|
||||
{
|
||||
fault::INVALID, "Event ID %s in a version %s room is not a version 4 Event ID.",
|
||||
string_view{event.event_id},
|
||||
eval.room_version,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Check if an eval with a copts structure (indicating this server is
|
||||
/// creating the event) has an origin set to !my_host().
|
||||
decltype(ircd::m::vm::conform_check_origin)
|
||||
ircd::m::vm::conform_check_origin
|
||||
{
|
||||
{
|
||||
{ "_site", "vm.conform" }
|
||||
},
|
||||
[](const m::event &event, eval &eval)
|
||||
{
|
||||
if(eval.opts && !eval.opts->conforming)
|
||||
return;
|
||||
|
||||
if(unlikely(eval.copts && !my_host(at<"origin"_>(event))))
|
||||
throw error
|
||||
{
|
||||
fault::INVALID, "Issuing event for origin: %s", at<"origin"_>(event)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Check if an event originating from this server exceeds maximum size.
|
||||
decltype(ircd::m::vm::conform_check_size)
|
||||
ircd::m::vm::conform_check_size
|
||||
{
|
||||
{
|
||||
{ "_site", "vm.conform" },
|
||||
{ "origin", my_host() }
|
||||
},
|
||||
[](const m::event &event, eval &eval)
|
||||
{
|
||||
const size_t &event_size
|
||||
{
|
||||
serialized(event)
|
||||
};
|
||||
|
||||
if(event_size > size_t(event::max_size))
|
||||
throw m::BAD_JSON
|
||||
{
|
||||
"Event is %zu bytes which is larger than the maximum %zu bytes",
|
||||
event_size,
|
||||
size_t(event::max_size)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Check if an event originating from this server exceeds maximum size.
|
||||
decltype(ircd::m::vm::conform_report)
|
||||
ircd::m::vm::conform_report
|
||||
{
|
||||
{
|
||||
{ "_site", "vm.conform" }
|
||||
},
|
||||
[](const m::event &event, eval &eval)
|
||||
{
|
||||
assert(eval.opts);
|
||||
auto &opts(*eval.opts);
|
||||
|
||||
// When opts.conformed is set the report is already generated
|
||||
if(opts.conformed)
|
||||
{
|
||||
eval.report = opts.report;
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate the report here.
|
||||
eval.report = event::conforms
|
||||
{
|
||||
event, opts.non_conform.report
|
||||
};
|
||||
|
||||
// When opts.conforming is false a bad report is not an error.
|
||||
if(!opts.conforming)
|
||||
return;
|
||||
|
||||
// Otherwise this will kill the eval
|
||||
if(!eval.report.clean())
|
||||
throw error
|
||||
{
|
||||
fault::INVALID, "Non-conforming event: %s", string(eval.report)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
namespace ircd::m
|
||||
{
|
||||
constexpr size_t event_conforms_num{num_of<event::conforms::code>()};
|
||||
extern const std::array<string_view, event_conforms_num> event_conforms_reflects;
|
||||
}
|
||||
|
||||
decltype(ircd::m::event_conforms_reflects)
|
||||
ircd::m::event_conforms_reflects
|
||||
{
|
||||
"INVALID_OR_MISSING_EVENT_ID",
|
||||
"INVALID_OR_MISSING_ROOM_ID",
|
||||
"INVALID_OR_MISSING_SENDER_ID",
|
||||
"MISSING_TYPE",
|
||||
"MISSING_ORIGIN",
|
||||
"INVALID_ORIGIN",
|
||||
"INVALID_OR_MISSING_REDACTS_ID",
|
||||
"MISSING_CONTENT_MEMBERSHIP",
|
||||
"INVALID_CONTENT_MEMBERSHIP",
|
||||
"MISSING_MEMBER_STATE_KEY",
|
||||
"INVALID_MEMBER_STATE_KEY",
|
||||
"MISSING_PREV_EVENTS",
|
||||
"MISSING_AUTH_EVENTS",
|
||||
"DEPTH_NEGATIVE",
|
||||
"DEPTH_ZERO",
|
||||
"MISSING_SIGNATURES",
|
||||
"MISSING_ORIGIN_SIGNATURE",
|
||||
"MISMATCH_ORIGIN_SENDER",
|
||||
"MISMATCH_CREATE_SENDER",
|
||||
"MISMATCH_ALIASES_STATE_KEY",
|
||||
"SELF_REDACTS",
|
||||
"SELF_PREV_EVENT",
|
||||
"SELF_AUTH_EVENT",
|
||||
"DUP_PREV_EVENT",
|
||||
"DUP_AUTH_EVENT",
|
||||
"MISMATCH_EVENT_ID",
|
||||
};
|
||||
|
||||
std::ostream &
|
||||
ircd::m::operator<<(std::ostream &s, const event::conforms &conforms)
|
||||
{
|
||||
thread_local char buf[1024];
|
||||
s << conforms.string(buf);
|
||||
return s;
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::m::reflect(const event::conforms::code &code)
|
||||
try
|
||||
{
|
||||
return event_conforms_reflects.at(code);
|
||||
}
|
||||
catch(const std::out_of_range &e)
|
||||
{
|
||||
return "??????"_sv;
|
||||
}
|
||||
|
||||
ircd::m::event::conforms::code
|
||||
ircd::m::event::conforms::reflect(const string_view &name)
|
||||
{
|
||||
const auto it
|
||||
{
|
||||
std::find(begin(event_conforms_reflects), end(event_conforms_reflects), name)
|
||||
};
|
||||
|
||||
if(it == end(event_conforms_reflects))
|
||||
throw std::out_of_range
|
||||
{
|
||||
"There is no event::conforms code by that name."
|
||||
};
|
||||
|
||||
return code(std::distance(begin(event_conforms_reflects), it));
|
||||
}
|
||||
|
||||
ircd::m::event::conforms::conforms(const event &e,
|
||||
const uint64_t &skip)
|
||||
:conforms{e}
|
||||
{
|
||||
report &= ~skip;
|
||||
}
|
||||
|
||||
ircd::m::event::conforms::conforms(const event &e)
|
||||
:report{0}
|
||||
{
|
||||
if(!e.event_id)
|
||||
set(INVALID_OR_MISSING_EVENT_ID);
|
||||
|
||||
if(defined(json::get<"event_id"_>(e)))
|
||||
if(!valid(m::id::EVENT, json::get<"event_id"_>(e)))
|
||||
set(INVALID_OR_MISSING_EVENT_ID);
|
||||
|
||||
if(!has(INVALID_OR_MISSING_EVENT_ID))
|
||||
if(!m::check_id(e))
|
||||
set(MISMATCH_EVENT_ID);
|
||||
|
||||
if(!valid(m::id::ROOM, json::get<"room_id"_>(e)))
|
||||
set(INVALID_OR_MISSING_ROOM_ID);
|
||||
|
||||
if(!valid(m::id::USER, json::get<"sender"_>(e)))
|
||||
set(INVALID_OR_MISSING_SENDER_ID);
|
||||
|
||||
if(empty(json::get<"type"_>(e)))
|
||||
set(MISSING_TYPE);
|
||||
|
||||
if(empty(json::get<"origin"_>(e)))
|
||||
set(MISSING_ORIGIN);
|
||||
|
||||
//TODO: XXX
|
||||
if((false))
|
||||
set(INVALID_ORIGIN);
|
||||
|
||||
if(empty(json::get<"signatures"_>(e)))
|
||||
set(MISSING_SIGNATURES);
|
||||
|
||||
if(empty(json::object{json::get<"signatures"_>(e).get(json::get<"origin"_>(e))}))
|
||||
set(MISSING_ORIGIN_SIGNATURE);
|
||||
|
||||
if(!has(INVALID_OR_MISSING_SENDER_ID))
|
||||
if(json::get<"origin"_>(e) != m::id::user{json::get<"sender"_>(e)}.host())
|
||||
set(MISMATCH_ORIGIN_SENDER);
|
||||
|
||||
if(json::get<"type"_>(e) == "m.room.create")
|
||||
if(m::room::id(json::get<"room_id"_>(e)).host() != m::user::id(json::get<"sender"_>(e)).host())
|
||||
set(MISMATCH_CREATE_SENDER);
|
||||
|
||||
if(json::get<"type"_>(e) == "m.room.aliases")
|
||||
if(m::user::id(json::get<"sender"_>(e)).host() != json::get<"state_key"_>(e))
|
||||
set(MISMATCH_ALIASES_STATE_KEY);
|
||||
|
||||
if(json::get<"type"_>(e) == "m.room.redaction")
|
||||
if(!valid(m::id::EVENT, json::get<"redacts"_>(e)))
|
||||
set(INVALID_OR_MISSING_REDACTS_ID);
|
||||
|
||||
if(json::get<"redacts"_>(e))
|
||||
if(json::get<"redacts"_>(e) == e.event_id)
|
||||
set(SELF_REDACTS);
|
||||
|
||||
if(json::get<"type"_>(e) == "m.room.member")
|
||||
if(empty(unquote(json::get<"content"_>(e).get("membership"))))
|
||||
set(MISSING_CONTENT_MEMBERSHIP);
|
||||
|
||||
if(json::get<"type"_>(e) == "m.room.member")
|
||||
if(!all_of<std::islower>(unquote(json::get<"content"_>(e).get("membership"))))
|
||||
set(INVALID_CONTENT_MEMBERSHIP);
|
||||
|
||||
if(json::get<"type"_>(e) == "m.room.member")
|
||||
if(empty(json::get<"state_key"_>(e)))
|
||||
set(MISSING_MEMBER_STATE_KEY);
|
||||
|
||||
if(json::get<"type"_>(e) == "m.room.member")
|
||||
if(!valid(m::id::USER, json::get<"state_key"_>(e)))
|
||||
set(INVALID_MEMBER_STATE_KEY);
|
||||
|
||||
if(json::get<"type"_>(e) != "m.room.create")
|
||||
if(empty(json::get<"prev_events"_>(e)))
|
||||
set(MISSING_PREV_EVENTS);
|
||||
|
||||
if(json::get<"type"_>(e) != "m.room.create")
|
||||
if(empty(json::get<"auth_events"_>(e)))
|
||||
set(MISSING_AUTH_EVENTS);
|
||||
|
||||
if(json::get<"depth"_>(e) != json::undefined_number && json::get<"depth"_>(e) < 0)
|
||||
set(DEPTH_NEGATIVE);
|
||||
|
||||
if(json::get<"type"_>(e) != "m.room.create")
|
||||
if(json::get<"depth"_>(e) == 0)
|
||||
set(DEPTH_ZERO);
|
||||
|
||||
const event::prev prev{e};
|
||||
if(json::get<"event_id"_>(e))
|
||||
{
|
||||
for(size_t i(0); i < prev.auth_events_count(); ++i)
|
||||
if(prev.auth_event(i) == json::get<"event_id"_>(e))
|
||||
set(SELF_AUTH_EVENT);
|
||||
|
||||
for(size_t i(0); i < prev.prev_events_count(); ++i)
|
||||
if(prev.prev_event(i) == json::get<"event_id"_>(e))
|
||||
set(SELF_PREV_EVENT);
|
||||
}
|
||||
|
||||
for(size_t i(0); i < prev.auth_events_count(); ++i)
|
||||
{
|
||||
const auto &[event_id, ref_hash]
|
||||
{
|
||||
prev.auth_events(i)
|
||||
};
|
||||
|
||||
for(size_t j(0); j < prev.auth_events_count(); ++j)
|
||||
if(i != j)
|
||||
if(event_id == prev.auth_event(j))
|
||||
set(DUP_AUTH_EVENT);
|
||||
}
|
||||
|
||||
for(size_t i(0); i < prev.prev_events_count(); ++i)
|
||||
{
|
||||
const auto &[event_id, ref_hash]
|
||||
{
|
||||
prev.prev_events(i)
|
||||
};
|
||||
|
||||
for(size_t j(0); j < prev.prev_events_count(); ++j)
|
||||
if(i != j)
|
||||
if(event_id == prev.prev_event(j))
|
||||
set(DUP_PREV_EVENT);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ircd::m::event::conforms::operator|=(const code &code)
|
||||
&
|
||||
{
|
||||
set(code);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::m::event::conforms::del(const code &code)
|
||||
{
|
||||
report &= ~(1UL << code);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::m::event::conforms::set(const code &code)
|
||||
{
|
||||
report |= (1UL << code);
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::m::event::conforms::string(const mutable_buffer &out)
|
||||
const
|
||||
{
|
||||
mutable_buffer buf{out};
|
||||
for(uint64_t i(0); i < num_of<code>(); ++i)
|
||||
{
|
||||
if(!has(code(i)))
|
||||
continue;
|
||||
|
||||
if(begin(buf) != begin(out))
|
||||
consume(buf, copy(buf, " "_sv));
|
||||
|
||||
consume(buf, copy(buf, m::reflect(code(i))));
|
||||
}
|
||||
|
||||
return { data(out), begin(buf) };
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::conforms::has(const code &code)
|
||||
const
|
||||
{
|
||||
return report & (1UL << code);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::conforms::has(const uint &code)
|
||||
const
|
||||
{
|
||||
return (report & (1UL << code)) == code;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::conforms::operator!()
|
||||
const
|
||||
{
|
||||
return clean();
|
||||
}
|
||||
|
||||
ircd::m::event::conforms::operator bool()
|
||||
const
|
||||
{
|
||||
return !clean();
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::conforms::clean()
|
||||
const
|
||||
{
|
||||
return report == 0;
|
||||
}
|
402
matrix/event_fetch.cc
Normal file
402
matrix/event_fetch.cc
Normal file
|
@ -0,0 +1,402 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 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.
|
||||
|
||||
//
|
||||
// seek
|
||||
//
|
||||
|
||||
void
|
||||
ircd::m::seek(event::fetch &fetch,
|
||||
const event::id &event_id)
|
||||
{
|
||||
if(!seek(fetch, event_id, std::nothrow))
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"%s not found in database", event_id
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::seek(event::fetch &fetch,
|
||||
const event::id &event_id,
|
||||
std::nothrow_t)
|
||||
{
|
||||
const auto &event_idx
|
||||
{
|
||||
index(event_id, std::nothrow)
|
||||
};
|
||||
|
||||
return seek(fetch, event_idx, event_id, std::nothrow);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::m::seek(event::fetch &fetch,
|
||||
const event::idx &event_idx)
|
||||
{
|
||||
if(!seek(fetch, event_idx, std::nothrow))
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"%lu not found in database", event_idx
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::seek(event::fetch &fetch,
|
||||
const event::idx &event_idx,
|
||||
std::nothrow_t)
|
||||
{
|
||||
return seek(fetch, event_idx, m::event::id{}, std::nothrow);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::seek(event::fetch &fetch,
|
||||
const event::idx &event_idx,
|
||||
const event::id &event_id,
|
||||
std::nothrow_t)
|
||||
{
|
||||
fetch.event_idx = event_idx;
|
||||
fetch.event_id_buf = event_id?
|
||||
event::id::buf{event_id}:
|
||||
event::id::buf{};
|
||||
|
||||
if(!event_idx)
|
||||
{
|
||||
fetch.valid = false;
|
||||
return fetch.valid;
|
||||
}
|
||||
|
||||
const string_view &key
|
||||
{
|
||||
byte_view<string_view>(event_idx)
|
||||
};
|
||||
|
||||
auto &event
|
||||
{
|
||||
static_cast<m::event &>(fetch)
|
||||
};
|
||||
|
||||
assert(fetch.fopts);
|
||||
const auto &opts(*fetch.fopts);
|
||||
if(!fetch.should_seek_json(opts))
|
||||
if((fetch.valid = db::seek(fetch.row, key, opts.gopts)))
|
||||
if((fetch.valid = fetch.assign_from_row(key)))
|
||||
return fetch.valid;
|
||||
|
||||
if((fetch.valid = fetch._json.load(key, opts.gopts)))
|
||||
fetch.valid = fetch.assign_from_json(key);
|
||||
|
||||
return fetch.valid;
|
||||
}
|
||||
|
||||
//
|
||||
// event::fetch
|
||||
//
|
||||
|
||||
decltype(ircd::m::event::fetch::default_opts)
|
||||
ircd::m::event::fetch::default_opts
|
||||
{};
|
||||
|
||||
//
|
||||
// event::fetch::fetch
|
||||
//
|
||||
|
||||
/// Seek to event_id and populate this event from database.
|
||||
/// Throws if event not in database.
|
||||
ircd::m::event::fetch::fetch(const event::id &event_id,
|
||||
const opts &opts)
|
||||
:fetch
|
||||
{
|
||||
index(event_id), event_id, std::nothrow, opts
|
||||
}
|
||||
{
|
||||
if(!valid)
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"%s not found in database", string_view{event_id}
|
||||
};
|
||||
}
|
||||
|
||||
/// Seek to event_id and populate this event from database.
|
||||
/// Event is not populated if not found in database.
|
||||
ircd::m::event::fetch::fetch(const event::id &event_id,
|
||||
std::nothrow_t,
|
||||
const opts &opts)
|
||||
:fetch
|
||||
{
|
||||
index(event_id, std::nothrow), event_id, std::nothrow, opts
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
/// Seek to event_idx and populate this event from database.
|
||||
/// Throws if event not in database.
|
||||
ircd::m::event::fetch::fetch(const event::idx &event_idx,
|
||||
const opts &opts)
|
||||
:fetch
|
||||
{
|
||||
event_idx, std::nothrow, opts
|
||||
}
|
||||
{
|
||||
if(!valid)
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"idx %zu not found in database", event_idx
|
||||
};
|
||||
}
|
||||
|
||||
ircd::m::event::fetch::fetch(const event::idx &event_idx,
|
||||
std::nothrow_t,
|
||||
const opts &opts)
|
||||
:fetch
|
||||
{
|
||||
event_idx, m::event::id{}, std::nothrow, opts
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
/// Seek to event_idx and populate this event from database.
|
||||
/// Event is not populated if not found in database.
|
||||
ircd::m::event::fetch::fetch(const event::idx &event_idx,
|
||||
const event::id &event_id,
|
||||
std::nothrow_t,
|
||||
const opts &opts)
|
||||
:fopts
|
||||
{
|
||||
&opts
|
||||
}
|
||||
,event_idx
|
||||
{
|
||||
event_idx
|
||||
}
|
||||
,_json
|
||||
{
|
||||
dbs::event_json,
|
||||
event_idx && should_seek_json(opts)?
|
||||
key(&event_idx):
|
||||
string_view{},
|
||||
opts.gopts
|
||||
}
|
||||
,row
|
||||
{
|
||||
*dbs::events,
|
||||
event_idx && !_json.valid(key(&event_idx))?
|
||||
key(&event_idx):
|
||||
string_view{},
|
||||
event_idx && !_json.valid(key(&event_idx))?
|
||||
event::keys{opts.keys}:
|
||||
event::keys{event::keys::include{}},
|
||||
cell,
|
||||
opts.gopts
|
||||
}
|
||||
,valid
|
||||
{
|
||||
false
|
||||
}
|
||||
,event_id_buf
|
||||
{
|
||||
event_id?
|
||||
event::id::buf{event_id}:
|
||||
event::id::buf{}
|
||||
}
|
||||
{
|
||||
valid =
|
||||
event_idx && _json.valid(key(&event_idx))?
|
||||
assign_from_json(key(&event_idx)):
|
||||
event_idx?
|
||||
assign_from_row(key(&event_idx)):
|
||||
false;
|
||||
}
|
||||
|
||||
/// Seekless constructor.
|
||||
ircd::m::event::fetch::fetch(const opts &opts)
|
||||
:fopts
|
||||
{
|
||||
&opts
|
||||
}
|
||||
,_json
|
||||
{
|
||||
dbs::event_json,
|
||||
string_view{},
|
||||
opts.gopts
|
||||
}
|
||||
,row
|
||||
{
|
||||
*dbs::events,
|
||||
string_view{},
|
||||
!should_seek_json(opts)?
|
||||
event::keys{opts.keys}:
|
||||
event::keys{event::keys::include{}},
|
||||
cell,
|
||||
opts.gopts
|
||||
}
|
||||
,valid
|
||||
{
|
||||
false
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::fetch::assign_from_json(const string_view &key)
|
||||
try
|
||||
{
|
||||
auto &event
|
||||
{
|
||||
static_cast<m::event &>(*this)
|
||||
};
|
||||
|
||||
assert(_json.valid(key));
|
||||
const json::object source
|
||||
{
|
||||
_json.val()
|
||||
};
|
||||
|
||||
assert(!empty(source));
|
||||
const bool source_event_id
|
||||
{
|
||||
!event_id_buf && source.has("event_id")
|
||||
};
|
||||
|
||||
const auto event_id
|
||||
{
|
||||
source_event_id?
|
||||
id(json::string(source.at("event_id"))):
|
||||
event_id_buf?
|
||||
id(event_id_buf):
|
||||
m::event_id(event_idx, event_id_buf, std::nothrow)
|
||||
};
|
||||
|
||||
assert(fopts);
|
||||
assert(event_id);
|
||||
event =
|
||||
{
|
||||
source, event_id, event::keys{fopts->keys}
|
||||
};
|
||||
|
||||
assert(data(event.source) == data(source));
|
||||
assert(event.event_id == event_id);
|
||||
return true;
|
||||
}
|
||||
catch(const json::parse_error &e)
|
||||
{
|
||||
const ctx::exception_handler eh;
|
||||
|
||||
const auto event_id
|
||||
{
|
||||
event_id_buf?
|
||||
id(event_id_buf):
|
||||
m::event_id(event_idx, event_id_buf, std::nothrow)
|
||||
};
|
||||
|
||||
log::critical
|
||||
{
|
||||
m::log, "Fetching event:%lu %s JSON from local database :%s",
|
||||
event_idx,
|
||||
string_view{event_id},
|
||||
e.what(),
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::fetch::assign_from_row(const string_view &key)
|
||||
try
|
||||
{
|
||||
auto &event
|
||||
{
|
||||
static_cast<m::event &>(*this)
|
||||
};
|
||||
|
||||
if(!row.valid(key))
|
||||
return false;
|
||||
|
||||
event.source = {};
|
||||
assign(event, row, key);
|
||||
const auto event_id
|
||||
{
|
||||
!empty(json::get<"event_id"_>(event))?
|
||||
id{json::get<"event_id"_>(event)}:
|
||||
event_id_buf?
|
||||
id{event_id_buf}:
|
||||
m::event_id(event_idx, event_id_buf, std::nothrow)
|
||||
};
|
||||
|
||||
assert(event_id);
|
||||
event.event_id = event_id;
|
||||
return true;
|
||||
}
|
||||
catch(const json::parse_error &e)
|
||||
{
|
||||
const ctx::exception_handler eh;
|
||||
|
||||
const auto event_id
|
||||
{
|
||||
event_id_buf?
|
||||
id(event_id_buf):
|
||||
m::event_id(event_idx, event_id_buf, std::nothrow)
|
||||
};
|
||||
|
||||
log::critical
|
||||
{
|
||||
m::log, "Fetching event:%lu %s JSON from local database :%s",
|
||||
event_idx,
|
||||
string_view{event_id},
|
||||
e.what(),
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::fetch::should_seek_json(const opts &opts)
|
||||
{
|
||||
// User always wants to make the event_json query regardless
|
||||
// of their keys selection.
|
||||
if(opts.query_json_force)
|
||||
return true;
|
||||
|
||||
// If and only if selected keys have direct columns we can return
|
||||
// false to seek direct columns. If any other keys are selected we
|
||||
/// must perform the event_json query instead.
|
||||
for(size_t i(0); i < opts.keys.size(); ++i)
|
||||
if(opts.keys.test(i))
|
||||
if(!dbs::event_column.at(i))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::m::event::fetch::key(const event::idx *const &event_idx)
|
||||
{
|
||||
assert(event_idx);
|
||||
return byte_view<string_view>(*event_idx);
|
||||
}
|
||||
|
||||
//
|
||||
// event::fetch::opts
|
||||
//
|
||||
|
||||
ircd::m::event::fetch::opts::opts(const db::gopts &gopts,
|
||||
const event::keys::selection &keys)
|
||||
:opts
|
||||
{
|
||||
keys, gopts
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
ircd::m::event::fetch::opts::opts(const event::keys::selection &keys,
|
||||
const db::gopts &gopts)
|
||||
:keys{keys}
|
||||
,gopts{gopts}
|
||||
{
|
||||
}
|
229
matrix/event_get.cc
Normal file
229
matrix/event_get.cc
Normal file
|
@ -0,0 +1,229 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 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.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// event/get.h
|
||||
//
|
||||
|
||||
std::string
|
||||
ircd::m::get(const event::id &event_id,
|
||||
const string_view &key)
|
||||
{
|
||||
std::string ret;
|
||||
get(event_id, key, [&ret]
|
||||
(const string_view &value)
|
||||
{
|
||||
ret = value;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string
|
||||
ircd::m::get(const event::idx &event_idx,
|
||||
const string_view &key)
|
||||
{
|
||||
std::string ret;
|
||||
get(event_idx, key, [&ret]
|
||||
(const string_view &value)
|
||||
{
|
||||
ret = value;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string
|
||||
ircd::m::get(std::nothrow_t,
|
||||
const event::id &event_id,
|
||||
const string_view &key)
|
||||
{
|
||||
std::string ret;
|
||||
get(std::nothrow, event_id, key, [&ret]
|
||||
(const string_view &value)
|
||||
{
|
||||
ret = value;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string
|
||||
ircd::m::get(std::nothrow_t,
|
||||
const event::idx &event_idx,
|
||||
const string_view &key)
|
||||
{
|
||||
std::string ret;
|
||||
get(std::nothrow, event_idx, key, [&ret]
|
||||
(const string_view &value)
|
||||
{
|
||||
ret = value;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ircd::const_buffer
|
||||
ircd::m::get(const event::id &event_id,
|
||||
const string_view &key,
|
||||
const mutable_buffer &out)
|
||||
{
|
||||
const auto &ret
|
||||
{
|
||||
get(std::nothrow, index(event_id), key, out)
|
||||
};
|
||||
|
||||
if(!ret)
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"%s for %s not found in database",
|
||||
key,
|
||||
string_view{event_id}
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ircd::const_buffer
|
||||
ircd::m::get(const event::idx &event_idx,
|
||||
const string_view &key,
|
||||
const mutable_buffer &out)
|
||||
{
|
||||
const const_buffer ret
|
||||
{
|
||||
get(std::nothrow, event_idx, key, out)
|
||||
};
|
||||
|
||||
if(!ret)
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"%s for event_idx[%lu] not found in database",
|
||||
key,
|
||||
event_idx
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ircd::const_buffer
|
||||
ircd::m::get(std::nothrow_t,
|
||||
const event::id &event_id,
|
||||
const string_view &key,
|
||||
const mutable_buffer &buf)
|
||||
{
|
||||
return get(std::nothrow, index(event_id, std::nothrow), key, buf);
|
||||
}
|
||||
|
||||
ircd::const_buffer
|
||||
ircd::m::get(std::nothrow_t,
|
||||
const event::idx &event_idx,
|
||||
const string_view &key,
|
||||
const mutable_buffer &buf)
|
||||
{
|
||||
const_buffer ret;
|
||||
get(std::nothrow, event_idx, key, [&buf, &ret]
|
||||
(const string_view &value)
|
||||
{
|
||||
ret = { data(buf), copy(buf, value) };
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
ircd::m::get(const event::id &event_id,
|
||||
const string_view &key,
|
||||
const event::fetch::view_closure &closure)
|
||||
{
|
||||
if(!get(std::nothrow, index(event_id), key, closure))
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"%s for %s not found in database",
|
||||
key,
|
||||
string_view{event_id}
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
ircd::m::get(const event::idx &event_idx,
|
||||
const string_view &key,
|
||||
const event::fetch::view_closure &closure)
|
||||
{
|
||||
if(!get(std::nothrow, event_idx, key, closure))
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"%s for event_idx[%lu] not found in database",
|
||||
key,
|
||||
event_idx
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::get(std::nothrow_t,
|
||||
const event::id &event_id,
|
||||
const string_view &key,
|
||||
const event::fetch::view_closure &closure)
|
||||
{
|
||||
return get(std::nothrow, index(event_id, std::nothrow), key, closure);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::get(std::nothrow_t,
|
||||
const event::idx &event_idx,
|
||||
const string_view &key,
|
||||
const event::fetch::view_closure &closure)
|
||||
{
|
||||
if(!event_idx)
|
||||
return false;
|
||||
|
||||
const auto &column_idx
|
||||
{
|
||||
json::indexof<event>(key)
|
||||
};
|
||||
|
||||
auto &column
|
||||
{
|
||||
dbs::event_column.at(column_idx)
|
||||
};
|
||||
|
||||
const string_view &column_key
|
||||
{
|
||||
byte_view<string_view>{event_idx}
|
||||
};
|
||||
|
||||
if(column)
|
||||
return column(column_key, std::nothrow, closure);
|
||||
|
||||
// If the event property being sought doesn't have its own column we
|
||||
// fall back to fetching the full JSON and closing over the property.
|
||||
bool ret{false};
|
||||
dbs::event_json(column_key, std::nothrow, [&closure, &key, &ret]
|
||||
(const json::object &event)
|
||||
{
|
||||
string_view value
|
||||
{
|
||||
event[key]
|
||||
};
|
||||
|
||||
if(!value)
|
||||
return;
|
||||
|
||||
// The user expects an unquoted string to their closure, the same as
|
||||
// if this value was found in its own column.
|
||||
if(json::type(value) == json::STRING)
|
||||
value = json::string(value);
|
||||
|
||||
ret = true;
|
||||
closure(value);
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -59,3 +59,102 @@ ircd::m::event::horizon::rebuild()
|
|||
txn();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::horizon::has(const event::id &event_id)
|
||||
{
|
||||
char buf[m::dbs::EVENT_HORIZON_KEY_MAX_SIZE];
|
||||
const string_view &key
|
||||
{
|
||||
m::dbs::event_horizon_key(buf, event_id, 0UL)
|
||||
};
|
||||
|
||||
auto it
|
||||
{
|
||||
m::dbs::event_horizon.begin(key)
|
||||
};
|
||||
|
||||
return bool(it);
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::event::horizon::count()
|
||||
const
|
||||
{
|
||||
size_t ret(0);
|
||||
for_each([&ret]
|
||||
(const auto &, const auto &)
|
||||
{
|
||||
++ret;
|
||||
return true;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::horizon::has(const event::idx &event_idx)
|
||||
const
|
||||
{
|
||||
return !for_each([&event_idx]
|
||||
(const auto &, const auto &_event_idx)
|
||||
{
|
||||
// false to break; true to continue.
|
||||
return _event_idx == event_idx? false : true;
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::horizon::for_each(const closure_bool &closure)
|
||||
const
|
||||
{
|
||||
if(!this->event_id)
|
||||
return for_every(closure);
|
||||
|
||||
char buf[m::dbs::EVENT_HORIZON_KEY_MAX_SIZE];
|
||||
const string_view &key
|
||||
{
|
||||
m::dbs::event_horizon_key(buf, event_id, 0UL)
|
||||
};
|
||||
|
||||
for(auto it(m::dbs::event_horizon.begin(key)); it; ++it)
|
||||
{
|
||||
const auto &event_idx
|
||||
{
|
||||
std::get<0>(m::dbs::event_horizon_key(it->first))
|
||||
};
|
||||
|
||||
if(!closure(event_id, event_idx))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::horizon::for_every(const closure_bool &closure)
|
||||
{
|
||||
db::column &column{dbs::event_horizon};
|
||||
for(auto it(column.begin()); it; ++it)
|
||||
{
|
||||
const auto &parts
|
||||
{
|
||||
split(it->first, "\0"_sv)
|
||||
};
|
||||
|
||||
const auto &event_id
|
||||
{
|
||||
parts.first
|
||||
};
|
||||
|
||||
const auto &event_idx
|
||||
{
|
||||
byte_view<event::idx>(parts.second)
|
||||
};
|
||||
|
||||
if(!closure(event_id, event_idx))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
66
matrix/event_id.cc
Normal file
66
matrix/event_id.cc
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 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::m::event::id::buf
|
||||
ircd::m::event_id(const event::idx &event_idx)
|
||||
{
|
||||
event::id::buf ret;
|
||||
event_id(event_idx, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ircd::m::event::id::buf
|
||||
ircd::m::event_id(const event::idx &event_idx,
|
||||
std::nothrow_t)
|
||||
{
|
||||
event::id::buf ret;
|
||||
event_id(event_idx, ret, std::nothrow);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ircd::m::event::id
|
||||
ircd::m::event_id(const event::idx &event_idx,
|
||||
event::id::buf &buf)
|
||||
{
|
||||
const event::id ret
|
||||
{
|
||||
event_id(event_idx, buf, std::nothrow)
|
||||
};
|
||||
|
||||
if(!ret)
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"Cannot find event ID from idx[%lu]", event_idx
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ircd::m::event::id
|
||||
ircd::m::event_id(const event::idx &event_idx,
|
||||
event::id::buf &buf,
|
||||
std::nothrow_t)
|
||||
{
|
||||
event_id(event_idx, std::nothrow, [&buf]
|
||||
(const event::id &eid)
|
||||
{
|
||||
buf = eid;
|
||||
});
|
||||
|
||||
return buf? event::id{buf} : event::id{};
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event_id(const event::idx &event_idx,
|
||||
std::nothrow_t,
|
||||
const event::id::closure &closure)
|
||||
{
|
||||
return get(std::nothrow, event_idx, "event_id", closure);
|
||||
}
|
89
matrix/event_index.cc
Normal file
89
matrix/event_index.cc
Normal file
|
@ -0,0 +1,89 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 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::m::event::idx
|
||||
ircd::m::index(const event &event)
|
||||
try
|
||||
{
|
||||
return index(event.event_id);
|
||||
}
|
||||
catch(const json::not_found &)
|
||||
{
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"Cannot find index for event without an event_id."
|
||||
};
|
||||
}
|
||||
|
||||
ircd::m::event::idx
|
||||
ircd::m::index(const event &event,
|
||||
std::nothrow_t)
|
||||
{
|
||||
return index(event.event_id, std::nothrow);
|
||||
}
|
||||
|
||||
ircd::m::event::idx
|
||||
ircd::m::index(const event::id &event_id)
|
||||
{
|
||||
assert(event_id);
|
||||
const auto ret
|
||||
{
|
||||
index(event_id, std::nothrow)
|
||||
};
|
||||
|
||||
if(!ret)
|
||||
throw m::NOT_FOUND
|
||||
{
|
||||
"no index found for %s",
|
||||
string_view{event_id}
|
||||
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ircd::m::event::idx
|
||||
ircd::m::index(const event::id &event_id,
|
||||
std::nothrow_t)
|
||||
{
|
||||
event::idx ret{0};
|
||||
index(event_id, std::nothrow, [&ret]
|
||||
(const event::idx &event_idx)
|
||||
{
|
||||
ret = event_idx;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::index(const event::id &event_id,
|
||||
std::nothrow_t,
|
||||
const event::closure_idx &closure)
|
||||
{
|
||||
auto &column
|
||||
{
|
||||
dbs::event_idx
|
||||
};
|
||||
|
||||
if(!event_id)
|
||||
return false;
|
||||
|
||||
return column(event_id, std::nothrow, [&closure]
|
||||
(const string_view &value)
|
||||
{
|
||||
const event::idx &event_idx
|
||||
{
|
||||
byte_view<event::idx>(value)
|
||||
};
|
||||
|
||||
closure(event_idx);
|
||||
});
|
||||
}
|
76
matrix/event_prefetch.cc
Normal file
76
matrix/event_prefetch.cc
Normal file
|
@ -0,0 +1,76 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 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.
|
||||
|
||||
bool
|
||||
ircd::m::prefetch(const event::id &event_id,
|
||||
const event::fetch::opts &opts)
|
||||
{
|
||||
return prefetch(index(event_id), opts);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::prefetch(const event::id &event_id,
|
||||
const string_view &key)
|
||||
{
|
||||
return prefetch(index(event_id), key);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::prefetch(const event::idx &event_idx,
|
||||
const event::fetch::opts &opts)
|
||||
{
|
||||
if(event::fetch::should_seek_json(opts))
|
||||
{
|
||||
if(!event_idx)
|
||||
return false;
|
||||
|
||||
return db::prefetch(dbs::event_json, byte_view<string_view>{event_idx});
|
||||
}
|
||||
|
||||
const event::keys keys
|
||||
{
|
||||
opts.keys
|
||||
};
|
||||
|
||||
const vector_view<const string_view> cols
|
||||
{
|
||||
keys
|
||||
};
|
||||
|
||||
bool ret{false};
|
||||
for(const auto &col : cols)
|
||||
if(col)
|
||||
ret |= prefetch(event_idx, col);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::prefetch(const event::idx &event_idx,
|
||||
const string_view &key)
|
||||
{
|
||||
const auto &column_idx
|
||||
{
|
||||
json::indexof<event>(key)
|
||||
};
|
||||
|
||||
if(column_idx >= dbs::event_column.size())
|
||||
return prefetch(event_idx, event::fetch::default_opts);
|
||||
|
||||
auto &column
|
||||
{
|
||||
dbs::event_column.at(column_idx)
|
||||
};
|
||||
|
||||
if(!event_idx)
|
||||
return false;
|
||||
|
||||
return db::prefetch(column, byte_view<string_view>{event_idx});
|
||||
}
|
207
matrix/event_prev.cc
Normal file
207
matrix/event_prev.cc
Normal file
|
@ -0,0 +1,207 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 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.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// event/prev.h
|
||||
//
|
||||
|
||||
size_t
|
||||
ircd::m::event::prev::prev_events_exist()
|
||||
const
|
||||
{
|
||||
size_t ret(0);
|
||||
for(size_t i(0); i < prev_events_count(); ++i)
|
||||
ret += prev_event_exists(i);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::event::prev::auth_events_exist()
|
||||
const
|
||||
{
|
||||
size_t ret(0);
|
||||
for(size_t i(0); i < auth_events_count(); ++i)
|
||||
ret += auth_event_exists(i);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::prev::prev_event_exists(const size_t &idx)
|
||||
const
|
||||
{
|
||||
return m::exists(prev_event(idx));
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::prev::auth_event_exists(const size_t &idx)
|
||||
const
|
||||
{
|
||||
return m::exists(auth_event(idx));
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::prev::prev_events_has(const event::id &event_id)
|
||||
const
|
||||
{
|
||||
for(size_t i(0); i < prev_events_count(); ++i)
|
||||
if(prev_event(i) == event_id)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::prev::auth_events_has(const event::id &event_id)
|
||||
const
|
||||
{
|
||||
for(size_t i(0); i < auth_events_count(); ++i)
|
||||
if(auth_event(i) == event_id)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::event::prev::prev_events_count()
|
||||
const
|
||||
{
|
||||
return json::get<"prev_events"_>(*this).count();
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::event::prev::auth_events_count()
|
||||
const
|
||||
{
|
||||
return json::get<"auth_events"_>(*this).count();
|
||||
}
|
||||
|
||||
ircd::m::event::id
|
||||
ircd::m::event::prev::auth_event(const size_t &idx)
|
||||
const
|
||||
{
|
||||
return std::get<0>(auth_events(idx));
|
||||
}
|
||||
|
||||
ircd::m::event::id
|
||||
ircd::m::event::prev::prev_event(const size_t &idx)
|
||||
const
|
||||
{
|
||||
return std::get<0>(prev_events(idx));
|
||||
}
|
||||
|
||||
std::tuple<ircd::m::event::id, ircd::json::object>
|
||||
ircd::m::event::prev::auth_events(const size_t &idx)
|
||||
const
|
||||
{
|
||||
const string_view &prev_
|
||||
{
|
||||
json::at<"auth_events"_>(*this).at(idx)
|
||||
};
|
||||
|
||||
switch(json::type(prev_))
|
||||
{
|
||||
// v1 event format
|
||||
case json::ARRAY:
|
||||
{
|
||||
const json::array &prev(prev_);
|
||||
const json::string &prev_id(prev.at(0));
|
||||
return {prev_id, prev[1]};
|
||||
}
|
||||
|
||||
// v3/v4 event format
|
||||
case json::STRING:
|
||||
{
|
||||
const json::string &prev_id(prev_);
|
||||
return {prev_id, string_view{}};
|
||||
}
|
||||
|
||||
default: throw m::INVALID_MXID
|
||||
{
|
||||
"auth_events[%zu] is invalid", idx
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<ircd::m::event::id, ircd::json::object>
|
||||
ircd::m::event::prev::prev_events(const size_t &idx)
|
||||
const
|
||||
{
|
||||
const string_view &prev_
|
||||
{
|
||||
json::at<"prev_events"_>(*this).at(idx)
|
||||
};
|
||||
|
||||
switch(json::type(prev_))
|
||||
{
|
||||
// v1 event format
|
||||
case json::ARRAY:
|
||||
{
|
||||
const json::array &prev(prev_);
|
||||
const json::string &prev_id(prev.at(0));
|
||||
return {prev_id, prev[1]};
|
||||
}
|
||||
|
||||
// v3/v4 event format
|
||||
case json::STRING:
|
||||
{
|
||||
const json::string &prev_id(prev_);
|
||||
return {prev_id, string_view{}};
|
||||
}
|
||||
|
||||
default: throw m::INVALID_MXID
|
||||
{
|
||||
"prev_events[%zu] is invalid", idx
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::for_each(const event::prev &prev,
|
||||
const event::id::closure_bool &closure)
|
||||
{
|
||||
return json::until(prev, [&closure]
|
||||
(const auto &key, const json::array &prevs)
|
||||
{
|
||||
for(const string_view &prev_ : prevs)
|
||||
{
|
||||
switch(json::type(prev_))
|
||||
{
|
||||
// v1 event format
|
||||
case json::ARRAY:
|
||||
{
|
||||
const json::array &prev(prev_);
|
||||
const json::string &prev_id(prev.at(0));
|
||||
if(!closure(prev_id))
|
||||
return false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// v3/v4 event format
|
||||
case json::STRING:
|
||||
{
|
||||
const json::string &prev(prev_);
|
||||
if(!closure(prev))
|
||||
return false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
242
matrix/event_refs.cc
Normal file
242
matrix/event_refs.cc
Normal file
|
@ -0,0 +1,242 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 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.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// event/refs.h
|
||||
//
|
||||
|
||||
void
|
||||
ircd::m::event::refs::rebuild()
|
||||
{
|
||||
static const size_t pool_size{96};
|
||||
static const size_t log_interval{8192};
|
||||
|
||||
db::txn txn
|
||||
{
|
||||
*m::dbs::events
|
||||
};
|
||||
|
||||
auto &column
|
||||
{
|
||||
dbs::event_json
|
||||
};
|
||||
|
||||
auto it
|
||||
{
|
||||
column.begin()
|
||||
};
|
||||
|
||||
ctx::dock dock;
|
||||
ctx::pool pool;
|
||||
pool.min(pool_size);
|
||||
|
||||
size_t i(0), j(0);
|
||||
const ctx::uninterruptible::nothrow ui;
|
||||
for(; it; ++it)
|
||||
{
|
||||
if(ctx::interruption_requested())
|
||||
break;
|
||||
|
||||
const m::event::idx event_idx
|
||||
{
|
||||
byte_view<m::event::idx>(it->first)
|
||||
};
|
||||
|
||||
std::string event{it->second};
|
||||
pool([&txn, &dock, &i, &j, event(std::move(event)), event_idx]
|
||||
{
|
||||
m::dbs::write_opts wopts;
|
||||
wopts.event_idx = event_idx;
|
||||
wopts.appendix.reset();
|
||||
wopts.appendix.set(dbs::appendix::EVENT_REFS);
|
||||
m::dbs::write(txn, json::object{event}, wopts);
|
||||
|
||||
if(++j % log_interval == 0) log::info
|
||||
{
|
||||
m::log, "Refs builder @%zu:%zu of %lu (@idx: %lu)",
|
||||
i,
|
||||
j,
|
||||
m::vm::sequence::retired,
|
||||
event_idx
|
||||
};
|
||||
|
||||
if(j >= i)
|
||||
dock.notify_one();
|
||||
});
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
dock.wait([&i, &j]
|
||||
{
|
||||
return i == j;
|
||||
});
|
||||
|
||||
txn();
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::refs::prefetch()
|
||||
const
|
||||
{
|
||||
return prefetch(dbs::ref(-1));
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::refs::prefetch(const dbs::ref &type)
|
||||
const
|
||||
{
|
||||
if(unlikely(!idx))
|
||||
return false;
|
||||
|
||||
// Allow -1 to iterate through all types by starting
|
||||
// the iteration at type value 0 and then ignoring the
|
||||
// type as a loop continue condition.
|
||||
const bool all_type
|
||||
{
|
||||
type == dbs::ref(uint8_t(-1))
|
||||
};
|
||||
|
||||
const auto &_type
|
||||
{
|
||||
all_type? dbs::ref::NEXT : type
|
||||
};
|
||||
|
||||
static_assert(uint8_t(dbs::ref::NEXT) == 0);
|
||||
char buf[dbs::EVENT_REFS_KEY_MAX_SIZE];
|
||||
const string_view key
|
||||
{
|
||||
dbs::event_refs_key(buf, idx, _type, 0)
|
||||
};
|
||||
|
||||
return db::prefetch(dbs::event_refs, key);
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::event::refs::count()
|
||||
const
|
||||
{
|
||||
return count(dbs::ref(-1));
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::event::refs::count(const dbs::ref &type)
|
||||
const
|
||||
{
|
||||
size_t ret(0);
|
||||
for_each(type, [&ret]
|
||||
(const event::idx &, const dbs::ref &)
|
||||
{
|
||||
++ret;
|
||||
return true;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::refs::has(const event::idx &idx)
|
||||
const
|
||||
{
|
||||
return has(dbs::ref(-1), idx);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::refs::has(const dbs::ref &type)
|
||||
const
|
||||
{
|
||||
return !for_each(type, [&type]
|
||||
(const event::idx &, const dbs::ref &ref)
|
||||
{
|
||||
assert(ref == type);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::refs::has(const dbs::ref &type,
|
||||
const event::idx &idx)
|
||||
const
|
||||
{
|
||||
return !for_each(type, [&idx]
|
||||
(const event::idx &ref, const dbs::ref &)
|
||||
{
|
||||
return ref != idx; // true to continue, false to break
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::refs::for_each(const closure_bool &closure)
|
||||
const
|
||||
{
|
||||
return for_each(dbs::ref(-1), closure);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::event::refs::for_each(const dbs::ref &type,
|
||||
const closure_bool &closure)
|
||||
const
|
||||
{
|
||||
if(!idx)
|
||||
return true;
|
||||
|
||||
// Allow -1 to iterate through all types by starting
|
||||
// the iteration at type value 0 and then ignoring the
|
||||
// type as a loop continue condition.
|
||||
const bool all_type
|
||||
{
|
||||
type == dbs::ref(uint8_t(-1))
|
||||
};
|
||||
|
||||
const auto &_type
|
||||
{
|
||||
all_type? dbs::ref::NEXT : type
|
||||
};
|
||||
|
||||
static_assert(uint8_t(dbs::ref::NEXT) == 0);
|
||||
char buf[dbs::EVENT_REFS_KEY_MAX_SIZE];
|
||||
const string_view key
|
||||
{
|
||||
dbs::event_refs_key(buf, idx, _type, 0)
|
||||
};
|
||||
|
||||
auto it
|
||||
{
|
||||
dbs::event_refs.begin(key)
|
||||
};
|
||||
|
||||
for(; it; ++it)
|
||||
{
|
||||
const auto parts
|
||||
{
|
||||
dbs::event_refs_key(it->first)
|
||||
};
|
||||
|
||||
const auto &type
|
||||
{
|
||||
std::get<0>(parts)
|
||||
};
|
||||
|
||||
if(!all_type && type != _type)
|
||||
break;
|
||||
|
||||
const auto &ref
|
||||
{
|
||||
std::get<1>(parts)
|
||||
};
|
||||
|
||||
assert(idx != ref);
|
||||
if(!closure(ref, type))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
360
matrix/pretty.cc
360
matrix/pretty.cc
|
@ -136,3 +136,363 @@ ircd::m::pretty_stateline(std::ostream &out,
|
|||
out << std::endl;
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::pretty(const event &event)
|
||||
{
|
||||
std::string ret;
|
||||
std::stringstream s;
|
||||
pubsetbuf(s, ret, 4096);
|
||||
pretty(s, event);
|
||||
resizebuf(s, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::pretty(std::ostream &s,
|
||||
const event &event)
|
||||
{
|
||||
const auto out{[&s]
|
||||
(const string_view &key, auto&& val)
|
||||
{
|
||||
if(defined(json::value(val)))
|
||||
s << std::setw(16) << std::right << key << " :" << val << std::endl;
|
||||
}};
|
||||
|
||||
const string_view top_keys[]
|
||||
{
|
||||
"event_id",
|
||||
"room_id",
|
||||
"sender",
|
||||
"origin",
|
||||
"depth",
|
||||
"type",
|
||||
"state_key",
|
||||
"redacts",
|
||||
};
|
||||
|
||||
json::for_each(event, top_keys, out);
|
||||
|
||||
const auto &ts{json::get<"origin_server_ts"_>(event)};
|
||||
{
|
||||
thread_local char buf[128];
|
||||
s << std::setw(16) << std::right << "origin_server_ts" << " :"
|
||||
<< timef(buf, ts / 1000L, ircd::localtime)
|
||||
<< " (" << ts << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
const json::object &contents{json::get<"content"_>(event)};
|
||||
if(!contents.empty())
|
||||
s << std::setw(16) << std::right << "content" << " :"
|
||||
<< size(contents) << " keys; "
|
||||
<< size(string_view{contents}) << " bytes."
|
||||
<< std::endl;
|
||||
|
||||
const auto &hashes{json::get<"hashes"_>(event)};
|
||||
for(const auto &hash : hashes)
|
||||
{
|
||||
s << std::setw(16) << std::right << "[hash]" << " :"
|
||||
<< hash.first
|
||||
<< " "
|
||||
<< json::string(hash.second)
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
const auto &signatures{json::get<"signatures"_>(event)};
|
||||
for(const auto &signature : signatures)
|
||||
{
|
||||
s << std::setw(16) << std::right << "[signature]" << " :"
|
||||
<< signature.first << " ";
|
||||
|
||||
for(const auto &key : json::object{signature.second})
|
||||
s << key.first << " ";
|
||||
|
||||
s << std::endl;
|
||||
}
|
||||
|
||||
const m::event::prev prev
|
||||
{
|
||||
event
|
||||
};
|
||||
|
||||
pretty(s, prev);
|
||||
|
||||
if(!contents.empty())
|
||||
for(const json::object::member &content : contents)
|
||||
s << std::setw(16) << std::right << "[content]" << " :"
|
||||
<< std::setw(7) << std::left << reflect(json::type(content.second)) << " "
|
||||
<< std::setw(5) << std::right << size(string_view{content.second}) << " bytes "
|
||||
<< ':' << content.first
|
||||
<< std::endl;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::pretty_oneline(const event &event,
|
||||
const int &fmt)
|
||||
{
|
||||
std::string ret;
|
||||
std::stringstream s;
|
||||
pubsetbuf(s, ret, 4096);
|
||||
pretty_oneline(s, event, fmt);
|
||||
resizebuf(s, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::pretty_oneline(std::ostream &s,
|
||||
const event &event,
|
||||
const int &fmt)
|
||||
{
|
||||
thread_local char sdbuf[48];
|
||||
|
||||
if(defined(json::get<"room_id"_>(event)))
|
||||
s << json::get<"room_id"_>(event) << ' ';
|
||||
else
|
||||
s << "* ";
|
||||
|
||||
if(event.event_id && event.event_id.version() != "1")
|
||||
s << event.event_id << ' ';
|
||||
else if(!event.event_id)
|
||||
s << m::event::id::v4{sdbuf, event} << ' ';
|
||||
|
||||
if(json::get<"origin_server_ts"_>(event) != json::undefined_number)
|
||||
s << smalldate(sdbuf, json::get<"origin_server_ts"_>(event) / 1000L) << ' ';
|
||||
else
|
||||
s << "* ";
|
||||
|
||||
if(json::get<"depth"_>(event) != json::undefined_number)
|
||||
s << json::get<"depth"_>(event) << ' ';
|
||||
else
|
||||
s << "* ";
|
||||
|
||||
const m::event::prev prev(event);
|
||||
for(size_t i(0); i < prev.auth_events_count(); ++i)
|
||||
s << 'A';
|
||||
|
||||
for(size_t i(0); i < prev.prev_events_count(); ++i)
|
||||
s << 'P';
|
||||
|
||||
if(prev.auth_events_count() || prev.prev_events_count())
|
||||
s << ' ';
|
||||
|
||||
if(event.event_id && event.event_id.version() == "1")
|
||||
s << event.event_id << ' ';
|
||||
|
||||
if(fmt >= 2)
|
||||
{
|
||||
const auto &hashes{json::get<"hashes"_>(event)};
|
||||
s << "[ ";
|
||||
for(const auto &hash : hashes)
|
||||
s << hash.first << ' ';
|
||||
s << "] ";
|
||||
|
||||
const auto &signatures{json::get<"signatures"_>(event)};
|
||||
s << "[ ";
|
||||
for(const auto &signature : signatures)
|
||||
{
|
||||
s << signature.first << "[ ";
|
||||
for(const auto &key : json::object{signature.second})
|
||||
s << key.first << ' ';
|
||||
|
||||
s << "] ";
|
||||
}
|
||||
s << "] ";
|
||||
}
|
||||
|
||||
if(defined(json::get<"type"_>(event)))
|
||||
s << json::get<"type"_>(event) << ' ';
|
||||
else
|
||||
s << "* ";
|
||||
|
||||
const auto &state_key
|
||||
{
|
||||
json::get<"state_key"_>(event)
|
||||
};
|
||||
|
||||
if(defined(state_key) && empty(state_key))
|
||||
s << "\"\"" << ' ';
|
||||
else if(defined(state_key))
|
||||
s << state_key << ' ';
|
||||
else
|
||||
s << "*" << ' ';
|
||||
|
||||
const string_view &membership
|
||||
{
|
||||
json::get<"type"_>(event) == "m.room.member"?
|
||||
m::membership(event):
|
||||
"*"_sv
|
||||
};
|
||||
|
||||
s << membership << ' ';
|
||||
|
||||
if(defined(json::get<"redacts"_>(event)))
|
||||
s << json::get<"redacts"_>(event) << ' ';
|
||||
else
|
||||
s << "* ";
|
||||
|
||||
if(defined(json::get<"origin"_>(event)) && defined(json::get<"sender"_>(event)))
|
||||
if(at<"origin"_>(event) != user::id(at<"sender"_>(event)).host())
|
||||
s << ':' << json::get<"origin"_>(event) << ' ';
|
||||
|
||||
if(defined(json::get<"sender"_>(event)))
|
||||
s << json::get<"sender"_>(event) << ' ';
|
||||
else
|
||||
s << "@*:* ";
|
||||
|
||||
const json::object &contents
|
||||
{
|
||||
fmt >= 1?
|
||||
json::get<"content"_>(event):
|
||||
json::object{}
|
||||
};
|
||||
|
||||
if(!contents.empty())
|
||||
{
|
||||
s << "+" << string_view{contents}.size() << " bytes :";
|
||||
for(const auto &content : contents)
|
||||
s << content.first << ' ';
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::pretty_msgline(const event &event)
|
||||
{
|
||||
std::string ret;
|
||||
std::stringstream s;
|
||||
pubsetbuf(s, ret, 4096);
|
||||
pretty_msgline(s, event);
|
||||
resizebuf(s, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::pretty_msgline(std::ostream &s,
|
||||
const event &event)
|
||||
{
|
||||
s << json::get<"depth"_>(event) << " :";
|
||||
s << json::get<"type"_>(event) << ' ';
|
||||
s << json::get<"sender"_>(event) << ' ';
|
||||
s << event.event_id << ' ';
|
||||
|
||||
const auto &state_key
|
||||
{
|
||||
json::get<"state_key"_>(event)
|
||||
};
|
||||
|
||||
if(defined(state_key) && empty(state_key))
|
||||
s << "\"\"" << ' ';
|
||||
else if(defined(state_key))
|
||||
s << state_key << ' ';
|
||||
else
|
||||
s << "*" << ' ';
|
||||
|
||||
const json::object &content
|
||||
{
|
||||
json::get<"content"_>(event)
|
||||
};
|
||||
|
||||
switch(hash(json::get<"type"_>(event)))
|
||||
{
|
||||
case "m.room.message"_:
|
||||
s << json::string(content.get("msgtype")) << ' ';
|
||||
s << json::string(content.get("body")) << ' ';
|
||||
break;
|
||||
|
||||
default:
|
||||
s << string_view{content};
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::pretty(const event::prev &prev)
|
||||
{
|
||||
std::string ret;
|
||||
std::stringstream s;
|
||||
pubsetbuf(s, ret, 4096);
|
||||
pretty(s, prev);
|
||||
resizebuf(s, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::pretty(std::ostream &s,
|
||||
const event::prev &prev)
|
||||
{
|
||||
for(size_t i(0); i < prev.auth_events_count(); ++i)
|
||||
{
|
||||
const auto &[event_id, ref_hash]
|
||||
{
|
||||
prev.auth_events(i)
|
||||
};
|
||||
|
||||
s << std::setw(16) << std::right << "[auth event]"
|
||||
<< " :" << event_id;
|
||||
|
||||
for(const auto &[algorithm, digest] : ref_hash)
|
||||
{
|
||||
s << ' ' << json::string(algorithm);
|
||||
if(digest)
|
||||
s << ": " << json::string(digest);
|
||||
}
|
||||
|
||||
s << std::endl;
|
||||
}
|
||||
|
||||
for(size_t i(0); i < prev.prev_events_count(); ++i)
|
||||
{
|
||||
const auto &[event_id, ref_hash]
|
||||
{
|
||||
prev.prev_events(i)
|
||||
};
|
||||
|
||||
s << std::setw(16) << std::right << "[prev_event]"
|
||||
<< " :" << event_id;
|
||||
|
||||
for(const auto &[algorithm, digest] : ref_hash)
|
||||
{
|
||||
s << ' ' << json::string(algorithm);
|
||||
if(digest)
|
||||
s << ": " << json::string(digest);
|
||||
}
|
||||
|
||||
s << std::endl;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::pretty_oneline(std::ostream &s,
|
||||
const event::prev &prev)
|
||||
{
|
||||
const auto &auth_events{json::get<"auth_events"_>(prev)};
|
||||
s << "A[ ";
|
||||
for(const json::array auth_event : auth_events)
|
||||
s << json::string(auth_event[0]) << ' ';
|
||||
s << "] ";
|
||||
|
||||
const auto &prev_events{json::get<"prev_events"_>(prev)};
|
||||
s << "E[ ";
|
||||
for(const json::array prev_event : prev_events)
|
||||
s << json::string(prev_event[0]) << ' ';
|
||||
s << "] ";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue