pub struct Service {
services: Arc<OnceServices>,
channel: RwLock<Option<Sender<CommandInput>>>,
pub command: RwLock<Option<Arc<dyn Command>>>,
pub admin_alias: OwnedRoomAliasId,
register_nonces: Mutex<BTreeMap<String, Instant>>,
pub console: Arc<Console>,
}Fields§
§services: Arc<OnceServices>§channel: RwLock<Option<Sender<CommandInput>>>§command: RwLock<Option<Arc<dyn Command>>>§admin_alias: OwnedRoomAliasId§register_nonces: Mutex<BTreeMap<String, Instant>>§console: Arc<Console>Implementations§
Source§impl Service
impl Service
Sourcepub(super) async fn attach(
&self,
output: &CommandOutput,
) -> Result<RoomMessageEventContent>
pub(super) async fn attach( &self, output: &CommandOutput, ) -> Result<RoomMessageEventContent>
Uploads a command’s output to the media repository and builds an m.file message referencing it. The caller attaches the relation.
Source§impl Service
impl Service
Sourcepub(super) async fn console_auto_start(&self)
pub(super) async fn console_auto_start(&self)
Possibly spawn the terminal console at startup if configured and standard input is a terminal.
Source§impl Service
impl Service
Sourcepub(super) async fn console_auto_stop(&self)
pub(super) async fn console_auto_stop(&self)
Shutdown the console when the admin worker terminates.
Source§impl Service
impl Service
Sourcepub async fn startup_execute(&self) -> Result
pub async fn startup_execute(&self) -> Result
Execute admin commands after startup
Source§impl Service
impl Service
Sourcepub(super) async fn signal_execute(&self) -> Result
pub(super) async fn signal_execute(&self) -> Result
Execute admin commands after signal
Source§impl Service
impl Service
Sourceasync fn execute_command(&self, i: usize, command: String) -> Result
async fn execute_command(&self, i: usize, command: String) -> Result
Execute one admin command after startup or signal
Source§impl Service
impl Service
fn execute_command_output(i: usize, content: &CommandOutput) -> Result
Source§impl Service
impl Service
fn execute_command_error(i: usize, content: &CommandOutput) -> Result
Source§impl Service
impl Service
Sourcepub async fn make_user_admin(&self, user_id: &UserId) -> Result
pub async fn make_user_admin(&self, user_id: &UserId) -> Result
Invite the user to the tuwunel admin room.
This is equivalent to granting server admin privileges. A local user must already hold an account, or the grant would wait for whoever registers the name.
Source§impl Service
impl Service
Sourcepub async fn make_room_admin(&self, room_id: &RoomId, target: &UserId) -> Result
pub async fn make_room_admin(&self, room_id: &RoomId, target: &UserId) -> Result
Grant room admin powers to a target by impersonating the highest-powered local member.
The target is granted the impersonated member’s power level (100 when that
member is a room-version 12 creator with infinite power), sent as a new
m.room.power_levels from that member. When the room is non-public and the
target is neither joined nor invited, the target is invited first.
Source§impl Service
impl Service
async fn invite_new_admin( &self, user_id: &UserId, room_id: &RoomId, state_lock: &RoomMutexGuard, ) -> Result
Source§impl Service
impl Service
Sourcepub async fn revoke_admin(&self, user_id: &UserId) -> Result
pub async fn revoke_admin(&self, user_id: &UserId) -> Result
Demote an admin, removing its rights.
The server user is refused, since the admin room exists only while the server user stays joined.
Source§impl Service
impl Service
Sourcepub async fn notify_loud(&self, body: &str)
pub async fn notify_loud(&self, body: &str)
Sends a message gated on the admin_room_notices config; admin command responses use the unconditional send_text().
Source§impl Service
impl Service
Sourcepub async fn send_report(&self, body: &str)
pub async fn send_report(&self, body: &str)
Sends a markdown report to the configured report room, falling back to the admin room, as the server user.
Source§impl Service
impl Service
Sourcepub async fn send_message(
&self,
message_content: RoomMessageEventContent,
) -> Result
pub async fn send_message( &self, message_content: RoomMessageEventContent, ) -> Result
Sends a message to the admin room as the admin user (see send_text() for convenience).
Source§impl Service
impl Service
async fn send_to_room( &self, content: RoomMessageEventContent, room_id: &RoomId, ) -> Result
Source§impl Service
impl Service
Sourcepub fn consume_register_nonce(&self, nonce: &str) -> bool
pub fn consume_register_nonce(&self, nonce: &str) -> bool
Consume nonce if it exists and has not expired. The entry is removed
either way; true means the caller may proceed.
Source§impl Service
impl Service
Sourcepub fn register_is_enabled(&self) -> bool
pub fn register_is_enabled(&self) -> bool
Answered without opening the secret file, since the nonce endpoint this gates takes no authentication and is not rate limited.
Source§impl Service
impl Service
Reads registration_shared_secret_file on every call, so a rotated secret
takes effect without a restart.
Source§impl Service
impl Service
pub(super) async fn handle_response( &self, output: CommandOutput, reply_id: Option<&EventId>, ) -> Result
Source§impl Service
impl Service
Sourceasync fn respond(
&self,
output: &CommandOutput,
room_id: &RoomId,
sender: &UserId,
mode: &Mode,
) -> Result
async fn respond( &self, output: &CommandOutput, room_id: &RoomId, sender: &UserId, mode: &Mode, ) -> Result
Splits the output across up to admin_output_max_events reply or thread
events; output needing more events, or any output when the limit is zero,
is uploaded and posted as a single file attachment instead.
Source§impl Service
impl Service
pub(super) async fn respond_to_room( &self, content: RoomMessageEventContent, room_id: &RoomId, user_id: &UserId, ) -> Result
Source§impl Service
impl Service
async fn handle_response_error( &self, e: Error, room_id: &RoomId, user_id: &UserId, state_lock: &RoomMutexGuard, ) -> Result
Source§impl Service
impl Service
Sourcepub async fn command(&self, input: CommandInput) -> Result
pub async fn command(&self, input: CommandInput) -> Result
Queues a command for the service worker and returns once it is queued.
The worker processes it later and replies to the reply_id event in its
room, posting nothing without one. Queueing waits while the queue is
full, and errors when the queue is unavailable or closed.
Sourcepub async fn command_in_place(&self, input: CommandInput) -> ProcessorResult
pub async fn command_in_place(&self, input: CommandInput) -> ProcessorResult
Dispatches a command to the processor on the current task and waits for completion.
The queue is bypassed, so the outcome returns to the caller rather than being posted as a reply.
Sourcepub fn complete_command(&self, command: &str) -> Option<String>
pub fn complete_command(&self, command: &str) -> Option<String>
Invokes the tab-completer to complete the command. When unavailable, None is returned.
async fn handle_signal(&self, sig: &'static str)
async fn handle_command(&self, command: CommandInput)
async fn process_command(&self, command: &CommandInput) -> ProcessorResult
Sourcepub async fn user_is_admin(&self, user_id: &UserId) -> bool
pub async fn user_is_admin(&self, user_id: &UserId) -> bool
Checks whether a given user is an admin of this server
Sourcepub async fn user_is_last_admin(&self, user_id: &UserId) -> bool
pub async fn user_is_last_admin(&self, user_id: &UserId) -> bool
Checks whether a given user is the only active admin left on this server.
The server user is never counted: it can sign in only while an emergency password is configured. Deactivated accounts still joined to the admin room are not counted either, since none of them can sign in to act. Nor is a passwordless account, such as an appservice’s user, since it stores the same empty password as a deactivated one.
Sourcepub async fn get_admin_room(&self) -> Result<OwnedRoomId>
pub async fn get_admin_room(&self) -> Result<OwnedRoomId>
Gets the room ID of the admin room
Errors are propagated from the database, and will have None if there is no admin room
Sourcepub async fn get_report_room(&self) -> Result<OwnedRoomId>
pub async fn get_report_room(&self) -> Result<OwnedRoomId>
Gets the room reports are posted to: the configured report room when set and usable, otherwise the admin room.
async fn resolve_report_room( &self, report_room: &RoomOrAliasId, ) -> Result<OwnedRoomId>
Sourcepub async fn is_admin_command<Pdu>(&self, event: &Pdu, body: &str) -> boolwhere
Pdu: Event,
pub async fn is_admin_command<Pdu>(&self, event: &Pdu, body: &str) -> boolwhere
Pdu: Event,
Returns whether a message event is an admin command to run.
Only an m.text from an admin qualifies: prefixed with !admin or the
server user’s ID in the admin room, or escaped as \!admin by a local
admin anywhere when escape commands are enabled. The server user’s own
messages in the admin room are refused unless the emergency password is
set.
pub async fn is_admin_room(&self, room_id_: &RoomId) -> bool
Source§impl Service
impl Service
Sourcepub async fn lock_admin_room(&self) -> Option<RoomMutexGuard>
pub async fn lock_admin_room(&self) -> Option<RoomMutexGuard>
Locks the admins room’s state, when there is an admins room.
Hold the guard from the Service::user_is_last_admin check until the
change it permits is made. The admins room’s leave and ban guard runs under
the same lock, so two concurrent removals cannot each see the other as the
admin who remains.
Trait Implementations§
Source§impl Service for Service
impl Service for Service
Source§fn build(args: &Args<'_>) -> Result<Arc<Self>>
fn build(args: &Args<'_>) -> Result<Arc<Self>>
Source§fn worker<'async_trait>(
self: Arc<Self>,
) -> Pin<Box<dyn Future<Output = Result> + Send + 'async_trait>>where
Self: 'async_trait,
fn worker<'async_trait>(
self: Arc<Self>,
) -> Pin<Box<dyn Future<Output = Result> + Send + 'async_trait>>where
Self: 'async_trait,
Source§fn interrupt<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn interrupt<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn name(&self) -> &str
fn name(&self) -> &str
crate::service::make_name(std::module_path!())Source§fn clear_cache<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn clear_cache<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn memory_usage<'life0, 'life1, 'async_trait>(
&'life0 self,
_out: &'life1 mut (dyn Write + Send),
) -> Pin<Box<dyn Future<Output = Result> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn memory_usage<'life0, 'life1, 'async_trait>(
&'life0 self,
_out: &'life1 mut (dyn Write + Send),
) -> Pin<Box<dyn Future<Output = Result> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn unconstrained(&self) -> bool
fn unconstrained(&self) -> bool
Auto Trait Implementations§
impl !Freeze for Service
impl !RefUnwindSafe for Service
impl !UnwindSafe for Service
impl Send for Service
impl Sync for Service
impl Unpin for Service
impl UnsafeUnpin for Service
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> ExpectInto for T
impl<T> ExpectInto for T
Source§impl<T> Expected for T
impl<T> Expected for T
Source§fn expected_add(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedAdd,
fn expected_add(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedAdd,
rhs with an expectation that the operation is valid. Read moreSource§fn expected_sub(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedSub,
fn expected_sub(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedSub,
rhs with an expectation that the operation is valid. Read moreSource§fn expected_mul(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedMul,
fn expected_mul(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedMul,
rhs with an expectation that the operation is valid. Read moreSource§fn expected_div(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedDiv,
fn expected_div(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedDiv,
rhs with an expectation that the operation is valid. Read moreSource§fn expected_rem(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedRem,
fn expected_rem(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedRem,
§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreimpl<T> JsonCastable<CanonicalJsonValue> for T
impl<T> JsonCastable<Value> for T
§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling [Attribute] value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi [Quirk] value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the [Condition] value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
§impl<T> ServiceExt for T
impl<T> ServiceExt for T
§fn add_extension<T>(self, value: T) -> AddExtension<Self, T>where
Self: Sized,
fn add_extension<T>(self, value: T) -> AddExtension<Self, T>where
Self: Sized,
§fn compression(self) -> Compression<Self>where
Self: Sized,
fn compression(self) -> Compression<Self>where
Self: Sized,
§fn decompression(self) -> Decompression<Self>where
Self: Sized,
fn decompression(self) -> Decompression<Self>where
Self: Sized,
§fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>where
Self: Sized,
fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>where
Self: Sized,
§fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>where
Self: Sized,
fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>where
Self: Sized,
§fn follow_redirects(self) -> FollowRedirect<Self>where
Self: Sized,
fn follow_redirects(self) -> FollowRedirect<Self>where
Self: Sized,
§fn sensitive_headers(
self,
headers: impl IntoIterator<Item = HeaderName>,
) -> SetSensitiveRequestHeaders<SetSensitiveResponseHeaders<Self>>where
Self: Sized,
fn sensitive_headers(
self,
headers: impl IntoIterator<Item = HeaderName>,
) -> SetSensitiveRequestHeaders<SetSensitiveResponseHeaders<Self>>where
Self: Sized,
§fn sensitive_request_headers(
self,
headers: impl IntoIterator<Item = HeaderName>,
) -> SetSensitiveRequestHeaders<Self>where
Self: Sized,
fn sensitive_request_headers(
self,
headers: impl IntoIterator<Item = HeaderName>,
) -> SetSensitiveRequestHeaders<Self>where
Self: Sized,
§fn sensitive_response_headers(
self,
headers: impl IntoIterator<Item = HeaderName>,
) -> SetSensitiveResponseHeaders<Self>where
Self: Sized,
fn sensitive_response_headers(
self,
headers: impl IntoIterator<Item = HeaderName>,
) -> SetSensitiveResponseHeaders<Self>where
Self: Sized,
§fn override_request_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetRequestHeader<Self, M>where
Self: Sized,
fn override_request_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetRequestHeader<Self, M>where
Self: Sized,
§fn append_request_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetRequestHeader<Self, M>where
Self: Sized,
fn append_request_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetRequestHeader<Self, M>where
Self: Sized,
§fn insert_request_header_if_not_present<M>(
self,
header_name: HeaderName,
make: M,
) -> SetRequestHeader<Self, M>where
Self: Sized,
fn insert_request_header_if_not_present<M>(
self,
header_name: HeaderName,
make: M,
) -> SetRequestHeader<Self, M>where
Self: Sized,
§fn override_response_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetResponseHeader<Self, M>where
Self: Sized,
fn override_response_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetResponseHeader<Self, M>where
Self: Sized,
§fn append_response_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetResponseHeader<Self, M>where
Self: Sized,
fn append_response_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetResponseHeader<Self, M>where
Self: Sized,
§fn insert_response_header_if_not_present<M>(
self,
header_name: HeaderName,
make: M,
) -> SetResponseHeader<Self, M>where
Self: Sized,
fn insert_response_header_if_not_present<M>(
self,
header_name: HeaderName,
make: M,
) -> SetResponseHeader<Self, M>where
Self: Sized,
§fn catch_panic(self) -> CatchPanic<Self, DefaultResponseForPanic>where
Self: Sized,
fn catch_panic(self) -> CatchPanic<Self, DefaultResponseForPanic>where
Self: Sized,
500 Internal Server responses. Read moreSource§impl<T> Tried for T
impl<T> Tried for T
Source§fn try_add(self, rhs: Self) -> Result<Self, Error>where
Self: Sized + CheckedAdd,
fn try_add(self, rhs: Self) -> Result<Self, Error>where
Self: Sized + CheckedAdd,
rhs with checked arithmetic. Read moreSource§fn try_sub(self, rhs: Self) -> Result<Self, Error>where
Self: Sized + CheckedSub,
fn try_sub(self, rhs: Self) -> Result<Self, Error>where
Self: Sized + CheckedSub,
rhs with checked arithmetic. Read moreSource§fn try_mul(self, rhs: Self) -> Result<Self, Error>where
Self: Sized + CheckedMul,
fn try_mul(self, rhs: Self) -> Result<Self, Error>where
Self: Sized + CheckedMul,
rhs with checked arithmetic. Read more