pub struct AppHandle { /* private fields */ }Implementations§
Source§impl AppHandle
impl AppHandle
pub async fn start() -> Result<Self>
pub async fn start_with_options( mode: NetworkMode, port: u16, master_key: Option<&[u8; 32]>, relays: Vec<Multiaddr>, ) -> Result<Self>
pub async fn start_with_db(db: Db) -> Result<Self>
pub async fn start_with_db_and_options( db: Db, mode: NetworkMode, port: u16, session_persist_key: [u8; 32], relays: Vec<Multiaddr>, ) -> Result<Self>
pub fn mode(&self) -> NetworkMode
pub fn subscribe(&self) -> Receiver<AppEvent>
pub fn fingerprint(&self) -> &str
pub fn peer_id(&self) -> PeerId
pub fn discovered_rooms(&self) -> Vec<DiscoveredRoom>
pub fn active_room_ids(&self) -> Vec<String>
pub fn active_room_info(&self, room_id: &str) -> Option<StoredRoom>
pub fn room_members(&self, room_id: &str) -> Vec<String>
pub fn room_messages( &self, room_id: &str, limit: i64, ) -> Result<Vec<StoredRoomMessage>>
pub fn search_room_messages( &self, room_id: &str, query: &str, limit: i64, ) -> Result<Vec<StoredRoomMessage>>
Sourcepub async fn start_room(
&self,
name: &str,
encrypted: bool,
passphrase: Option<&str>,
) -> Result<String>
pub async fn start_room( &self, name: &str, encrypted: bool, passphrase: Option<&str>, ) -> Result<String>
Create a new room. Returns its room_id.
Sourcepub async fn join_room(
&self,
room_id: &str,
passphrase: Option<&str>,
) -> Result<()>
pub async fn join_room( &self, room_id: &str, passphrase: Option<&str>, ) -> Result<()>
Join an existing room. The room may come from a live announcement
(preferred), our restorable set, or the DB directly — whichever has
the freshest copy. For encrypted rooms passphrase is required.
Sourcepub async fn leave_room(&self, room_id: &str) -> Result<bool>
pub async fn leave_room(&self, room_id: &str) -> Result<bool>
Leave a room. Returns true when the MemberLeave notice was
handed to the network layer, false when it couldn’t be encoded
(peers then only notice via the discovered-room TTL). The local
leave always succeeds regardless.
pub async fn send_room_message(&self, room_id: &str, body: &str) -> Result<()>
pub async fn shutdown(&self)
Sourcepub async fn dial(&self, input: &str) -> Result<()>
pub async fn dial(&self, input: &str) -> Result<()>
Dial a peer by a user-entered address. Accepts:
1.2.3.4:9000[fe80::1]:9000/ip4/.../tcp/...[/p2p/<peer>](raw multiaddr)
Sourcepub fn nat_reachable_addrs(&self) -> Vec<String>
pub fn nat_reachable_addrs(&self) -> Vec<String>
Phase D follow-up: snapshot of the NAT reachability state. Returns the addresses AutoNAT has confirmed as externally reachable in this session. The lobby renders an emoji badge from this — non-empty ⇒ ‘🌐 reachable’, empty ⇒ ‘🏠 LAN only’.
Sourcepub fn dialable_addrs(&self) -> Vec<String>
pub fn dialable_addrs(&self) -> Vec<String>
Phase D follow-up: addresses suitable for putting on the wire so other peers can dial us. Union of:
- AutoNAT-confirmed external addresses (direct internet)
- active
/p2p-circuitreservations on configured relays Capped at 4 entries to keep room announcements small. Relay-circuit addresses are listed first (they’re more likely to work for NAT’d peers).
Sourcepub async fn dial_invite(&self, address: &str, claimed_fp: &str) -> Result<()>
pub async fn dial_invite(&self, address: &str, claimed_fp: &str) -> Result<()>
Phase C follow-up: dial a peer whose multiaddr came from an
invite link claiming claimed_fp. Behaves identically to
dial, but additionally stashes (canonical_addr → claimed_fp)
in pending_invite_dials so the PeerIdentified handler can
assert the cryptographic fp matches the human-display one in
the invite. Mismatch ⇒ disconnect + InviteFingerprintMismatch
event.
libp2p’s /p2p/<peer-id> segment already enforces this at the
transport level (and our invite generator always includes it),
so this is defense in depth — but it makes the assert explicit
rather than relying on a structural side effect.
pub fn known_peers(&self) -> Vec<KnownPeerStatus>
pub async fn forget_peer(&self, address: &str) -> Result<()>
Sourcepub async fn redial(&self, address: &str) -> Result<()>
pub async fn redial(&self, address: &str) -> Result<()>
Re-dial a stored address — used by the lobby’s “reconnect” action.
Sourcepub async fn accept_inbound(&self, peer_id: PeerId, address: &str)
pub async fn accept_inbound(&self, peer_id: PeerId, address: &str)
Phase A: user pressed Accept on the inbound-dial modal. Promotes
the peer to the gossipsub mesh. Does NOT mark them trusted —
that’s trust_inbound, the explicit “remember and bypass next
time” path.
Sourcepub async fn reject_inbound(
&self,
peer_id: PeerId,
fingerprint: &str,
) -> Result<()>
pub async fn reject_inbound( &self, peer_id: PeerId, fingerprint: &str, ) -> Result<()>
Phase A: user pressed Reject on the inbound-dial modal. Disconnects the peer, adds them to the persistent blocklist, and ensures every subsequent connection attempt from this fingerprint is auto- dropped without re-prompting.
Sourcepub async fn trust_inbound(
&self,
peer_id: PeerId,
fingerprint: &str,
address: &str,
) -> Result<()>
pub async fn trust_inbound( &self, peer_id: PeerId, fingerprint: &str, address: &str, ) -> Result<()>
Phase A: user pressed Trust+Accept — accept the connection AND remember the peer so subsequent connections bypass the modal.
Sourcepub async fn send_file(&self, room_id: &str, path: &Path) -> Result<String>
pub async fn send_file(&self, room_id: &str, path: &Path) -> Result<String>
Send a local file to a room. Reads the file, optionally encrypts it for encrypted rooms, chunks it, broadcasts a FileOffer then each FileChunk. Returns the file_id once all chunks are queued.
Sourcepub async fn save_to_downloads(
&self,
room_id: &str,
file_id: &str,
) -> Result<PathBuf>
pub async fn save_to_downloads( &self, room_id: &str, file_id: &str, ) -> Result<PathBuf>
Save a completed/ready attachment to the user’s Downloads folder. Decrypts encrypted attachments on the way out.
Sourcepub async fn cancel_transfer(&self, room_id: &str, file_id: &str) -> Result<()>
pub async fn cancel_transfer(&self, room_id: &str, file_id: &str) -> Result<()>
Drop any in-flight chunks and remove the attachment row.
Sourcepub fn open_saved(&self, room_id: &str, file_id: &str) -> Result<()>
pub fn open_saved(&self, room_id: &str, file_id: &str) -> Result<()>
Launch the system’s default opener on a saved file.
pub fn list_room_attachments( &self, room_id: &str, ) -> Result<Vec<StoredAttachment>>
Sourcepub fn set_member_verified(
&self,
room_id: &str,
fingerprint: &str,
verified: bool,
) -> Result<()>
pub fn set_member_verified( &self, room_id: &str, fingerprint: &str, verified: bool, ) -> Result<()>
Mark a peer’s fingerprint as verified in the given room. Used by
the ^V verification modal after the user has compared the
fingerprint out-of-band.
pub fn verified_fingerprints(&self, room_id: &str) -> Vec<String>
Sourcepub fn is_owner(&self, room_id: &str, fingerprint: &str) -> bool
pub fn is_owner(&self, room_id: &str, fingerprint: &str) -> bool
Phase B: is fingerprint an owner of room_id? Used by the TUI
to gate ^K / ^G and the kick/grant member-picker actions.
pub fn we_are_owner(&self, room_id: &str) -> bool
Sourcepub fn room_owners(&self, room_id: &str) -> Vec<String>
pub fn room_owners(&self, room_id: &str) -> Vec<String>
Phase B: list current owner fingerprints for room_id — used to
render an owner badge in the member panel.
Sourcepub fn verified_only_inbound(&self) -> bool
pub fn verified_only_inbound(&self) -> bool
Phase E: global toggle — when true, inbound dials from unverified fingerprints are auto-rejected without prompting.
pub fn set_verified_only_inbound(&self, on: bool) -> Result<()>
Sourcepub fn room_verified_only(&self, room_id: &str) -> bool
pub fn room_verified_only(&self, room_id: &str) -> bool
Phase E: per-room verified-only-join. When true, the host (and
every honest existing member) drops MemberAnnounce from joiners
who aren’t globally SAS-verified, and the lowest-fp owner sends
back a signed JoinRefused so the joiner sees an explanation.
pub fn set_room_verified_only(&self, room_id: &str, on: bool) -> Result<()>
Sourcepub fn onboarding_seen(&self) -> bool
pub fn onboarding_seen(&self) -> bool
Phase H: first-launch onboarding flag.
pub fn mark_onboarding_seen(&self) -> Result<()>
Sourcepub async fn grant_owner(
&self,
room_id: &str,
target_fingerprint: &str,
) -> Result<()>
pub async fn grant_owner( &self, room_id: &str, target_fingerprint: &str, ) -> Result<()>
Phase B: promote target_fingerprint to owner. Builds a signed
OwnerGrant, broadcasts it, and applies it locally. Returns an
error if we ourselves aren’t an owner — only owners can grant.
Sourcepub async fn kick_member(
&self,
room_id: &str,
target_fingerprint: &str,
) -> Result<String>
pub async fn kick_member( &self, room_id: &str, target_fingerprint: &str, ) -> Result<String>
Phase B: kick target_fingerprint from room_id. Broadcasts a
signed BanMember, records the ban locally, then immediately
rotates the room key under a freshly-generated passphrase. Returns
the new passphrase so the caller can show it to the owner for
out-of-band sharing with remaining members.
The rotation is the cryptographic enforcement: a banned peer can still subscribe to the gossipsub topic and see the ciphertext, but they can’t unwrap the new session key without the new passphrase, so they can’t decrypt anything sent after the kick.
Sourcepub fn generate_join_code(&self, room_id: &str) -> Result<String>
pub fn generate_join_code(&self, room_id: &str) -> Result<String>
Phase F: generate an 8-char alphanumeric join code for room_id,
good for 10 minutes. Stored in memory only on the issuing owner’s
machine — a single use clears it. Caller is responsible for
sharing the code OOB with the prospective joiner.
Owner-only. Errors if room_id isn’t active or we’re not an owner.
Sourcepub async fn join_room_with_code(&self, room_id: &str, code: &str) -> Result<()>
pub async fn join_room_with_code(&self, room_id: &str, code: &str) -> Result<()>
Phase F: join room_id using a short-lived code instead of the
passphrase. Generates an ephemeral X25519 keypair, broadcasts a
signed CodeJoinRequest, and waits for the owner’s
CodeJoinResponse. The receive arm builds an ActiveRoom
flagged read-only (no passphrase = can’t share our outbound
session key with others).
Sourcepub async fn sas_start(
&self,
room_id: &str,
target_fingerprint: &str,
) -> Result<String>
pub async fn sas_start( &self, room_id: &str, target_fingerprint: &str, ) -> Result<String>
Phase G: start an SAS verification with target_fingerprint in
room_id. Returns the tx_id so the caller can correlate
subsequent events. The full flow is asynchronous — the partner
must accept on their end, both compute the ECDH-derived SAS
code, OOB-compare it, and each press Match.
Sourcepub async fn sas_match(&self, tx_id: &str) -> Result<()>
pub async fn sas_match(&self, tx_id: &str) -> Result<()>
Phase G: user pressed Match on the SAS code modal — broadcast our
signed SasConfirm{matched: true}. If the partner has already
matched, this completes verification on both sides.
Sourcepub fn sas_cancel(&self, tx_id: &str)
pub fn sas_cancel(&self, tx_id: &str)
Phase G: cancel an in-flight SAS — drop our local state. Doesn’t broadcast a “matched=false” notice in v1 (partner’s flow stays dangling; they can cancel their side too). Quiet teardown.
pub fn display_name(&self) -> Option<String>
pub fn set_display_name(&self, name: Option<&str>) -> Result<()>
Sourcepub async fn set_username(&self, name: Option<&str>) -> Result<()>
pub async fn set_username(&self, name: Option<&str>) -> Result<()>
huddle 0.5: set the local user’s self-declared username (or clear
it with None) and broadcast a signed ProfileUpdate to every
joined room. Receivers cache the latest per-fingerprint username
in peer_profiles; unsigned envelopes are dropped at the receive
arm so the username can’t be spoofed.
Sourcepub fn lookup_username(&self, fingerprint: &str) -> Option<String>
pub fn lookup_username(&self, fingerprint: &str) -> Option<String>
huddle 0.5: cached username for a peer (any peer we’ve ever
received a signed ProfileUpdate from), or None if unknown or
the peer cleared their username. Callers render [anonymous] on
None.
Sourcepub fn lookup_member_display_name(&self, fingerprint: &str) -> Option<String>
pub fn lookup_member_display_name(&self, fingerprint: &str) -> Option<String>
Look up the display name we’ve seen for a peer. Forwards to
lookup_username (the new signed-source-of-truth) so existing
call sites get the authenticated value without churn.
pub fn is_room_muted(&self, room_id: &str) -> bool
Sourcepub fn list_room_bans(&self, room_id: &str) -> Vec<String>
pub fn list_room_bans(&self, room_id: &str) -> Vec<String>
Phase B: list the fingerprints currently banned from a room
(newest first). Backs the ^B in-room view; intended for
owners but the read itself is harmless and we let callers
gate via we_are_owner if they want owner-only display.
Sourcepub fn list_blocked_peers(&self) -> Vec<String>
pub fn list_blocked_peers(&self) -> Vec<String>
Phase A: list every globally-blocked peer (one fingerprint per
row). Surfaced in the Settings modal alongside a clear-all
action that calls unblock_peer in a loop.
Sourcepub fn unblock_peer(&self, fingerprint: &str) -> Result<()>
pub fn unblock_peer(&self, fingerprint: &str) -> Result<()>
Phase A: remove fingerprint from the persistent blocklist. The
peer will no longer be auto-rejected on connection; they fall
back to the regular inbound-dial accept/reject prompt.
Sourcepub fn is_room_read_only(&self, room_id: &str) -> bool
pub fn is_room_read_only(&self, room_id: &str) -> bool
Phase F: rooms entered via a join code don’t have the passphrase
in memory, so the joining peer can’t wrap their own outbound
session key for newer members — they can read and send, they
just can’t onboard others. The TUI renders a (read-only)
badge in the room tab so the user understands.
pub fn set_room_muted(&self, room_id: &str, muted: bool) -> Result<()>
Sourcepub async fn broadcast_typing(&self, room_id: &str)
pub async fn broadcast_typing(&self, room_id: &str)
Broadcast a “I’m typing” pulse to the given room. Caller is responsible for debouncing (don’t fire more than every ~500ms).
Sourcepub fn typers_in_room(&self, room_id: &str) -> Vec<String>
pub fn typers_in_room(&self, room_id: &str) -> Vec<String>
Returns the fingerprints of peers currently typing in room_id,
pruning entries past their TTL.
Sourcepub async fn rotate_room(
&self,
room_id: &str,
new_passphrase: &str,
) -> Result<()>
pub async fn rotate_room( &self, room_id: &str, new_passphrase: &str, ) -> Result<()>
Rotate this room’s outbound Megolm session under a fresh
passphrase. Broadcasts RotateRoomKey (so other members know to
expect a new passphrase) and a fresh MemberAnnounce with the
new wrapped session key. Old inbound sessions stay in storage
for decrypting historic messages.
Sourcepub async fn accept_rotation(
&self,
room_id: &str,
new_salt: &[u8],
new_passphrase: &str,
) -> Result<()>
pub async fn accept_rotation( &self, room_id: &str, new_salt: &[u8], new_passphrase: &str, ) -> Result<()>
Used by the TUI when another member rotates a room we’re in. Derives the new key, updates our local state, and re-announces so the rotator can share their fresh outbound session with us.
Sourcepub async fn go_dark(&self, master_passphrase: &str) -> Result<()>
pub async fn go_dark(&self, master_passphrase: &str) -> Result<()>
huddle 0.5: irreversibly delete this account. Verifies the
master passphrase, best-effort MemberLeaves every joined room
(capped at 2 s so a single unresponsive transport can’t hang
the wipe), shuts down the network, then deletes the database,
keychain salt, log, and config files from config::data_dir().
Emits AppEvent::WentDark on success so the TUI can show a
goodbye modal and exit.
In --no-master-passphrase mode (self.session_persist_key
is all-zero), the passphrase check is skipped — the typed
DELETE EVERYTHING confirmation in the TUI is the only gate.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for AppHandle
impl !RefUnwindSafe for AppHandle
impl Send for AppHandle
impl Sync for AppHandle
impl Unpin for AppHandle
impl UnsafeUnpin for AppHandle
impl !UnwindSafe for AppHandle
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> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> 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 more