Skip to main content

darkbio_wire/protocol/
closer.rs

1// wire-rs: encrypted protocol between Ark and host
2// Copyright 2026 Dark Bio AG. All rights reserved.
3
4//! Handles for closing a session or server from another thread.
5
6use super::{Error, server::ServerInner, session::SessionInner};
7use std::sync::Weak;
8
9/// Clonable handle for closing the session or server that created it.
10///
11/// From [`super::Session::closer`], it closes that session, with the semantics of
12/// [`super::Session::close`]. From [`super::Server::closer`], it closes the server
13/// and its active session, with the semantics of [`super::Server::close`].
14/// Its target never changes: a session's closer cannot affect a successor session.
15///
16/// This handle does not keep its owner open. Dropping it does not close anything.
17#[derive(Clone)]
18pub struct Closer {
19    /// Session or server to close.
20    target: Target,
21}
22
23/// The session or server targeted by a `Closer`.
24#[derive(Clone)]
25enum Target {
26    /// One session, even after another session connects to the same server.
27    Session(Weak<SessionInner>),
28    /// One persistent server and whichever session it has attached at closure.
29    Server(Weak<ServerInner>),
30}
31
32impl Closer {
33    /// Closes the original owner. Repeated calls have no further effect.
34    pub fn close(&self) {
35        match &self.target {
36            Target::Session(target) => {
37                if let Some(session) = target.upgrade() {
38                    session.close(Error::Closed);
39                }
40            }
41            Target::Server(target) => {
42                if let Some(server) = target.upgrade() {
43                    server.close(Error::Closed);
44                }
45            }
46        }
47    }
48
49    /// Creates a closer for one session using a weak reference.
50    pub(super) fn session(target: Weak<SessionInner>) -> Self {
51        Self {
52            target: Target::Session(target),
53        }
54    }
55
56    /// Creates a closer for one server using a weak reference.
57    pub(super) fn server(target: Weak<ServerInner>) -> Self {
58        Self {
59            target: Target::Server(target),
60        }
61    }
62}
63
64/// Checks that the same closer type works for sessions and servers.
65#[cfg(test)]
66#[cfg_attr(coverage_nightly, coverage(off))]
67mod tests {
68    use crate::protocol::{Closer, Server, Session};
69
70    /// Compiles closing sessions and servers through cloned handles on other threads.
71    #[allow(dead_code)]
72    fn cross_thread_close(session: &Session, server: &Server) {
73        let session_closer: Closer = session.closer();
74        let server_closer: Closer = server.closer();
75        let session_copy = session_closer.clone();
76        let server_copy = server_closer.clone();
77        std::thread::spawn(move || session_copy.close());
78        std::thread::spawn(move || server_copy.close());
79        session.close();
80        server.close();
81    }
82
83    /// Checks that `Closer` implements `Clone`, `Send`, and `Sync`.
84    #[test]
85    fn test_thread_capabilities() {
86        /// Requires a handle to be clonable and usable by multiple threads.
87        fn shared<T: Clone + Send + Sync + 'static>() {}
88        shared::<Closer>();
89    }
90}