mirror of
https://github.com/matrix-construct/construct
synced 2025-01-23 21:09:59 +01:00
modules/m_command: Add watch support for server-side command line.
This commit is contained in:
parent
b4e75dfdf0
commit
b40c21545a
1 changed files with 209 additions and 35 deletions
|
@ -40,7 +40,21 @@ struct command_result
|
||||||
string_view msgtype {"m.notice"};
|
string_view msgtype {"m.notice"};
|
||||||
};
|
};
|
||||||
|
|
||||||
conf::item<bool>
|
static conf::item<size_t>
|
||||||
|
watch_limit
|
||||||
|
{
|
||||||
|
{ "name", "ircd.m.command.watch.limit" },
|
||||||
|
{ "default", 256 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static conf::item<bool>
|
||||||
|
watch_opers
|
||||||
|
{
|
||||||
|
{ "name", "ircd.m.command.watch.opers" },
|
||||||
|
{ "default", true },
|
||||||
|
};
|
||||||
|
|
||||||
|
static conf::item<bool>
|
||||||
command_typing
|
command_typing
|
||||||
{
|
{
|
||||||
{ "name", "ircd.m.command.typing" },
|
{ "name", "ircd.m.command.typing" },
|
||||||
|
@ -55,6 +69,30 @@ execute_command(const mutable_buffer &buf,
|
||||||
const m::event::id &reply_to,
|
const m::event::id &reply_to,
|
||||||
const bool public_response);
|
const bool public_response);
|
||||||
|
|
||||||
|
static void
|
||||||
|
watch_command(const m::user::id &user_id,
|
||||||
|
const m::room::id &room_id,
|
||||||
|
const m::event::id &reply_id,
|
||||||
|
const m::event::id &response_id,
|
||||||
|
const m::room::id &response_room,
|
||||||
|
const m::user::id &response_sender,
|
||||||
|
const string_view &response_type,
|
||||||
|
const string_view &cmd,
|
||||||
|
const bool &public_response,
|
||||||
|
const milliseconds &watch_delay);
|
||||||
|
|
||||||
|
static const json::value
|
||||||
|
undef_val
|
||||||
|
{
|
||||||
|
string_view{nullptr}, json::STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
static const json::value
|
||||||
|
html_format
|
||||||
|
{
|
||||||
|
"org.matrix.custom.html", json::STRING
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
handle_command(const m::event &event,
|
handle_command(const m::event &event,
|
||||||
m::vm::eval &eval)
|
m::vm::eval &eval)
|
||||||
|
@ -105,6 +143,18 @@ try
|
||||||
if(!is_command)
|
if(!is_command)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const json::string reply_to
|
||||||
|
{
|
||||||
|
content["reply_id"]
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto reply_id
|
||||||
|
{
|
||||||
|
reply_to?
|
||||||
|
m::event::id::buf{reply_to}:
|
||||||
|
m::event::id::buf{}
|
||||||
|
};
|
||||||
|
|
||||||
// View of the command string without prefix
|
// View of the command string without prefix
|
||||||
string_view input
|
string_view input
|
||||||
{
|
{
|
||||||
|
@ -120,29 +170,43 @@ try
|
||||||
startswith(input, '!')
|
startswith(input, '!')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(public_response)
|
||||||
|
input = lstrip(input, '!');
|
||||||
|
|
||||||
|
const bool command_watch
|
||||||
|
{
|
||||||
|
startswith(input, "watch ")
|
||||||
|
&& (!watch_opers || is_oper(user))
|
||||||
|
};
|
||||||
|
|
||||||
|
milliseconds watch_delay {0ms};
|
||||||
|
if(command_watch)
|
||||||
|
{
|
||||||
|
const auto delay
|
||||||
|
{
|
||||||
|
lex_cast<float>(token(input, ' ', 1))
|
||||||
|
};
|
||||||
|
|
||||||
|
watch_delay = milliseconds
|
||||||
|
{
|
||||||
|
long(delay * 1000.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
input = tokens_after(input, ' ', 1);
|
||||||
|
}
|
||||||
|
|
||||||
const string_view cmd
|
const string_view cmd
|
||||||
{
|
{
|
||||||
lstrip(input, '!')
|
input
|
||||||
};
|
|
||||||
|
|
||||||
const json::string reply_to
|
|
||||||
{
|
|
||||||
content["reply_id"]
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto reply_id
|
|
||||||
{
|
|
||||||
reply_to?
|
|
||||||
m::event::id{reply_to}:
|
|
||||||
m::event::id{}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
log::debug
|
log::debug
|
||||||
{
|
{
|
||||||
m::log, "Server command from %s in %s public:%b replying:%s :%s",
|
m::log, "Server command from %s in %s public:%b watch:%ld replying:%s :%s",
|
||||||
string_view{room_id},
|
string_view{room_id},
|
||||||
string_view{user.user_id},
|
string_view{user.user_id},
|
||||||
public_response,
|
public_response,
|
||||||
|
watch_delay.count(),
|
||||||
string_view{reply_id}?: "false"_sv,
|
string_view{reply_id}?: "false"_sv,
|
||||||
cmd
|
cmd
|
||||||
};
|
};
|
||||||
|
@ -175,7 +239,7 @@ try
|
||||||
public_response? "m.room.message" : "ircd.cmd.result"
|
public_response? "m.room.message" : "ircd.cmd.result"
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto &response_event_id
|
const auto &command_event_id
|
||||||
{
|
{
|
||||||
public_response?
|
public_response?
|
||||||
string_view{event_id}:
|
string_view{event_id}:
|
||||||
|
@ -192,16 +256,6 @@ try
|
||||||
alt?: "no alt text"_sv, json::STRING
|
alt?: "no alt text"_sv, json::STRING
|
||||||
};
|
};
|
||||||
|
|
||||||
static const json::value undef_val
|
|
||||||
{
|
|
||||||
string_view{nullptr}, json::STRING
|
|
||||||
};
|
|
||||||
|
|
||||||
static const json::value html_format
|
|
||||||
{
|
|
||||||
"org.matrix.custom.html", json::STRING
|
|
||||||
};
|
|
||||||
|
|
||||||
char relates_buf[576], reply_buf[288];
|
char relates_buf[576], reply_buf[288];
|
||||||
json::object in_reply_to, relates_to {json::empty_object};
|
json::object in_reply_to, relates_to {json::empty_object};
|
||||||
if(event_id)
|
if(event_id)
|
||||||
|
@ -219,6 +273,8 @@ try
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto response_id
|
||||||
|
{
|
||||||
m::send(response_room, response_sender, response_type,
|
m::send(response_room, response_sender, response_type,
|
||||||
{
|
{
|
||||||
{ "msgtype", msgtype?: "m.notice" },
|
{ "msgtype", msgtype?: "m.notice" },
|
||||||
|
@ -226,9 +282,43 @@ try
|
||||||
{ "body", content_body },
|
{ "body", content_body },
|
||||||
{ "formatted_body", html? html_val: undef_val },
|
{ "formatted_body", html? html_val: undef_val },
|
||||||
{ "room_id", room_id },
|
{ "room_id", room_id },
|
||||||
{ "input", input },
|
{ "input", cmd },
|
||||||
{ "m.relates_to", relates_to },
|
{ "m.relates_to", relates_to },
|
||||||
});
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
if(command_watch)
|
||||||
|
ctx::context
|
||||||
|
{
|
||||||
|
"watch", ctx::context::POST | ctx::context::DETACH,
|
||||||
|
[
|
||||||
|
user_id(m::user::id::buf(user.user_id)),
|
||||||
|
room_id(m::room::id::buf(room_id)),
|
||||||
|
reply_id(m::event::id::buf(reply_id)),
|
||||||
|
response_id(m::event::id::buf(response_id)),
|
||||||
|
response_room(m::room::id::buf(response_room)),
|
||||||
|
response_sender(m::user::id::buf(response_sender)),
|
||||||
|
response_type(std::string(response_type)),
|
||||||
|
cmd(std::string(cmd)),
|
||||||
|
public_response,
|
||||||
|
watch_delay
|
||||||
|
]
|
||||||
|
{
|
||||||
|
watch_command
|
||||||
|
(
|
||||||
|
user_id,
|
||||||
|
room_id,
|
||||||
|
reply_id,
|
||||||
|
response_id,
|
||||||
|
response_room,
|
||||||
|
response_sender,
|
||||||
|
response_type,
|
||||||
|
cmd,
|
||||||
|
public_response,
|
||||||
|
watch_delay
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
catch(const std::exception &e)
|
catch(const std::exception &e)
|
||||||
{
|
{
|
||||||
|
@ -258,6 +348,90 @@ catch(const std::exception &e)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
watch_command(const m::user::id &user_id,
|
||||||
|
const m::room::id &room_id,
|
||||||
|
const m::event::id &reply_id,
|
||||||
|
const m::event::id &response_id,
|
||||||
|
const m::room::id &response_room,
|
||||||
|
const m::user::id &response_sender,
|
||||||
|
const string_view &response_type,
|
||||||
|
const string_view &cmd,
|
||||||
|
const bool &public_response,
|
||||||
|
const milliseconds &watch_delay)
|
||||||
|
{
|
||||||
|
const auto annotation_id
|
||||||
|
{
|
||||||
|
public_response?
|
||||||
|
m::annotate(response_room, response_sender, response_id, "▶️"_sv):
|
||||||
|
m::event::id::buf{}
|
||||||
|
};
|
||||||
|
|
||||||
|
const unwind deannotate{[&]
|
||||||
|
{
|
||||||
|
if(annotation_id && !m::redacted(annotation_id))
|
||||||
|
m::redact(response_room, response_sender, annotation_id, "cleared");
|
||||||
|
}};
|
||||||
|
|
||||||
|
const unique_buffer<mutable_buffer> buf
|
||||||
|
{
|
||||||
|
56_KiB
|
||||||
|
};
|
||||||
|
|
||||||
|
for(size_t i(0); i < size_t(watch_limit); ++i)
|
||||||
|
{
|
||||||
|
sleep(watch_delay);
|
||||||
|
|
||||||
|
if(m::redacted(response_id))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(annotation_id && m::redacted(annotation_id))
|
||||||
|
break;
|
||||||
|
|
||||||
|
const auto &[html, alt, msgtype]
|
||||||
|
{
|
||||||
|
execute_command(buf, user_id, room_id, cmd, reply_id, public_response)
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!html && !alt)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const json::value html_val
|
||||||
|
{
|
||||||
|
html, json::STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
const json::value content_body
|
||||||
|
{
|
||||||
|
alt?: "no alt text"_sv, json::STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
m::send(response_room, response_sender, response_type,
|
||||||
|
{
|
||||||
|
{ "body", content_body },
|
||||||
|
{ "format", html? html_format: undef_val },
|
||||||
|
{ "formatted_body", html? html_val: undef_val },
|
||||||
|
{ "input", cmd },
|
||||||
|
{ "msgtype", msgtype?: "m.notice" },
|
||||||
|
{ "room_id", room_id },
|
||||||
|
{ "m.new_content", json::members
|
||||||
|
{
|
||||||
|
{ "body", content_body },
|
||||||
|
{ "format", html? html_format: undef_val },
|
||||||
|
{ "formatted_body", html? html_val: undef_val },
|
||||||
|
{ "input", cmd },
|
||||||
|
{ "msgtype", msgtype?: "m.notice" },
|
||||||
|
{ "room_id", room_id },
|
||||||
|
}},
|
||||||
|
{ "m.relates_to", json::members
|
||||||
|
{
|
||||||
|
{ "event_id", response_id },
|
||||||
|
{ "rel_type", "m.replace" },
|
||||||
|
}}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static command_result
|
static command_result
|
||||||
command__summarize(const mutable_buffer &buf,
|
command__summarize(const mutable_buffer &buf,
|
||||||
const m::user &user,
|
const m::user &user,
|
||||||
|
|
Loading…
Add table
Reference in a new issue