ringo_core/backend.rs
1use std::sync::mpsc::Receiver;
2
3use anyhow::Result;
4
5use crate::account::{Account, BackendOptions};
6use crate::event::{AppEvent, InviteHeaders};
7use crate::phone::Phone;
8
9pub use crate::baresip::BaresipBackend;
10pub use crate::baresip::call_count;
11pub use crate::baresip::is_registered;
12pub use crate::baresip::received_audio;
13pub use crate::baresip::sent_audio;
14pub use crate::baresip::{sip_trace_file, sip_trace_stderr};
15
16/// Shut down the backend's global runtime: hang up calls, tear down the user
17/// agents, stop the event loop and join its thread. Call once at process exit;
18/// a no-op if the backend was never started. Agnostic façade over the concrete
19/// backend's teardown (the FFI backend stops its libre event thread here).
20pub fn shutdown() {
21 crate::baresip::stop_re_thread();
22}
23
24/// A backend provides SIP user-agent functionality — library init, event
25/// translation and the phone command interface. The FFI backend links
26/// libbaresip directly (statically with `vendored`, or dynamically via
27/// pkg-config).
28pub trait Backend: Send {
29 /// Spawn the backend (process or library), start I/O tasks on `rt`, and
30 /// return a [`Session`] handle. The session owns the event stream, phone
31 /// command interface, and optional header-polling closure. Connect retry
32 /// happens internally; `AppEvent::BackendConnectFailed` lands in the event
33 /// stream on failure.
34 fn spawn_session(
35 &self,
36 rt: &tokio::runtime::Handle,
37 name: &str,
38 account: &Account,
39 options: &BackendOptions,
40 ) -> Result<Session>;
41}
42
43/// A live backend session. Dropping this tears down the backend (stops the
44/// process / closes the library) and cleans up resources.
45pub struct Session {
46 /// Event stream (already translated to backend-neutral `AppEvent`s).
47 pub events: Receiver<AppEvent>,
48 /// Phone command interface.
49 pub phone: Box<dyn Phone>,
50 /// Poll for inbound INVITE headers. Returns `None` when there is nothing
51 /// new; `Some(headers)` when new headers have been parsed. `None` on the
52 /// closure itself means the backend exposes headers directly in events
53 /// (no trace polling needed).
54 pub header_poll: Option<Box<dyn Fn() -> Option<InviteHeaders> + Send + Sync>>,
55 /// Opaque handle — drop ends the backend session + cleanup.
56 pub handle: Box<dyn Send>,
57}
58
59impl Session {
60 pub fn new(
61 events: Receiver<AppEvent>,
62 phone: Box<dyn Phone>,
63 header_poll: Option<Box<dyn Fn() -> Option<InviteHeaders> + Send + Sync>>,
64 handle: Box<dyn Send>,
65 ) -> Self {
66 Self {
67 events,
68 phone,
69 header_poll,
70 handle,
71 }
72 }
73}