Skip to main content

libsession_rs/
lib.rs

1#[cfg(test)]
2mod tests;
3
4use std::os::fd;
5use std::os::fd::{AsFd, AsRawFd};
6use std::{ffi, ptr};
7
8pub struct Context(ptr::NonNull<libsession_sys::LibsessionContext>);
9
10impl Context {
11    #[must_use]
12    pub fn connect() -> Option<Self> {
13        ptr::NonNull::new(libsession_sys::libsession_new()).map(Self)
14    }
15
16    pub fn get_backend(&self) -> libsession_sys::Result<libsession_sys::LibsessionBackend> {
17        let mut backend = libsession_sys::LibsessionBackend::Sessiond;
18
19        libsession_sys::Result::<()>::from(unsafe {
20            libsession_sys::libsession_get_backend(self.0.as_ptr(), &raw mut backend)
21        })?;
22
23        Ok(backend)
24    }
25
26    /// Retrieves the session ID for the current process.
27    ///
28    /// # Errors
29    ///
30    /// Returns `Error::NotFound` if the backend cannot resolve the session,
31    /// or `Error::InternalError` if it returns a null session ID.
32    pub fn get_session(&self) -> libsession_sys::Result<Session> {
33        let mut id = ptr::null_mut();
34
35        libsession_sys::Result::<()>::from(unsafe {
36            libsession_sys::libsession_get_session(self.0.as_ptr(), &raw mut id)
37        })?;
38
39        let id = ptr::NonNull::new(id).ok_or(libsession_sys::Error::InternalError)?;
40        Ok(Session(id))
41    }
42
43    /// Retrieves the session ID for a process.
44    ///
45    /// # Errors
46    ///
47    /// Returns `Error::NotFound` if the backend cannot resolve the
48    /// session, or `Error::InternalError` if it returns a null ID.
49    pub fn get_session_for_pid(&self, pid: i32) -> libsession_sys::Result<Session> {
50        let mut id = ptr::null_mut();
51        libsession_sys::Result::<()>::from(unsafe {
52            libsession_sys::libsession_pid_get_session(self.0.as_ptr(), pid, &raw mut id)
53        })?;
54
55        let id = ptr::NonNull::new(id).ok_or(libsession_sys::Error::InternalError)?;
56        Ok(Session(id))
57    }
58
59    pub fn get_display_for_uid(&self, uid: u32) -> libsession_sys::Result<Session> {
60        let mut id = ptr::null_mut();
61        libsession_sys::Result::<()>::from(unsafe {
62            libsession_sys::libsession_uid_get_display(self.0.as_ptr(), uid, &raw mut id)
63        })?;
64
65        let id = ptr::NonNull::new(id).ok_or(libsession_sys::Error::InternalError)?;
66        Ok(Session(id))
67    }
68
69    pub fn list_sessions(&self) -> libsession_sys::Result<Vec<Session>> {
70        let mut sessions = ptr::null_mut();
71        let mut count = 0usize;
72
73        libsession_sys::Result::<()>::from(unsafe {
74            libsession_sys::libsession_session_list(
75                self.0.as_ptr(),
76                &raw mut sessions,
77                &raw mut count,
78            )
79        })?;
80
81        if count == 0 {
82            return Ok(Vec::new());
83        }
84
85        let sessions = ptr::NonNull::new(sessions).ok_or(libsession_sys::Error::InternalError)?;
86
87        let ids = unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(sessions.as_ptr(), count)) };
88
89        Ok(ids
90            .iter()
91            .map(|&id| {
92                // Every entry was allocated with Box::into_raw and is non-null.
93                Session(unsafe { ptr::NonNull::new_unchecked(id) })
94            })
95            .collect())
96    }
97
98    pub fn is_session_local(&self, session: &Session) -> libsession_sys::Result<bool> {
99        let mut is_local = false;
100
101        libsession_sys::Result::<()>::from(unsafe {
102            libsession_sys::libsession_session_is_local(
103                self.0.as_ptr(),
104                session.0.as_ptr(),
105                &raw mut is_local,
106            )
107        })?;
108
109        Ok(is_local)
110    }
111
112    pub fn get_owner_uid_for_pid(&self, pid: i32) -> libsession_sys::Result<u32> {
113        let mut uid = 0u32;
114
115        libsession_sys::Result::<()>::from(unsafe {
116            libsession_sys::libsession_pid_get_owner_uid(self.0.as_ptr(), pid, &raw mut uid)
117        })?;
118
119        Ok(uid)
120    }
121
122    pub fn get_user_state(
123        &self,
124        uid: u32,
125    ) -> libsession_sys::Result<libsession_sys::LibsessionUserState> {
126        let mut state = libsession_sys::LibsessionUserState::Offline;
127
128        libsession_sys::Result::<()>::from(unsafe {
129            libsession_sys::libsession_uid_get_state(self.0.as_ptr(), uid, &raw mut state)
130        })?;
131
132        Ok(state)
133    }
134
135    pub fn get_session_uid(&self, session: &Session) -> libsession_sys::Result<u32> {
136        let mut uid = 0u32;
137
138        libsession_sys::Result::<()>::from(unsafe {
139            libsession_sys::libsession_session_get_uid(
140                self.0.as_ptr(),
141                session.0.as_ptr(),
142                &raw mut uid,
143            )
144        })?;
145
146        Ok(uid)
147    }
148
149    pub fn get_session_state(
150        &self,
151        session: &Session,
152    ) -> libsession_sys::Result<libsession_sys::LibsessionSessionState> {
153        let mut state = libsession_sys::LibsessionSessionState::Unkown;
154
155        libsession_sys::Result::<()>::from(unsafe {
156            libsession_sys::libsession_session_get_state(
157                self.0.as_ptr(),
158                session.0.as_ptr(),
159                &raw mut state,
160            )
161        })?;
162
163        Ok(state)
164    }
165
166    pub fn is_session_active(&self, session: &Session) -> libsession_sys::Result<bool> {
167        let mut is_active = false;
168
169        libsession_sys::Result::<()>::from(unsafe {
170            libsession_sys::libsession_session_is_active(
171                self.0.as_ptr(),
172                session.0.as_ptr(),
173                &raw mut is_active,
174            )
175        })?;
176
177        Ok(is_active)
178    }
179
180    /// Sets the logging callback, or disables callbacks with `None`.
181    ///
182    /// # Errors
183    ///
184    /// Returns an error if the underlying call fails.
185    ///
186    /// # Safety
187    ///
188    /// The callback must remain callable until replaced or this context is
189    /// dropped. It must not unwind or access this context reentrantly. The
190    /// message pointer is valid only during the callback; it must not be
191    /// retained or freed.
192    pub unsafe fn set_log_fn(
193        &self,
194        callback: libsession_sys::LibsessionLogFn,
195    ) -> libsession_sys::Result<()> {
196        libsession_sys::Result::<()>::from(unsafe {
197            libsession_sys::libsession_set_log_fn(self.0.as_ptr(), callback)
198        })
199    }
200
201    /// Sets the logging level. `Off` disables logging.
202    ///
203    /// # Errors
204    ///
205    /// Returns an error if the underlying call fails.
206    pub fn set_log_level(
207        &self,
208        level: libsession_sys::LibsessionLogLevel,
209    ) -> libsession_sys::Result<()> {
210        libsession_sys::Result::<()>::from(unsafe {
211            libsession_sys::libsession_set_log_level(self.0.as_ptr(), level)
212        })
213    }
214
215    /// Retrieves the current logging level.
216    #[must_use]
217    pub fn get_log_level(&self) -> libsession_sys::LibsessionLogLevel {
218        unsafe { libsession_sys::libsession_get_log_level(self.0.as_ptr()) }
219    }
220
221    /// Creates a monitor for session changes.
222    ///
223    /// # Errors
224    ///
225    /// Returns `Error::Unavailable` if the backend cannot create a monitor.
226    pub fn get_monitor(&mut self) -> libsession_sys::Result<Monitor> {
227        ptr::NonNull::new(libsession_sys::libsession_monitor_new(self.0.as_ptr()))
228            .map(Monitor)
229            .ok_or(libsession_sys::Error::Unavailable)
230    }
231}
232
233pub struct Session(ptr::NonNull<libsession_sys::LibsessionSession>);
234
235impl Session {
236    pub fn id(&self) -> libsession_sys::Result<String> {
237        let mut id = ptr::null_mut();
238        unsafe { libsession_sys::libsession_session_get_id(self.0.as_ptr(), &raw mut id) };
239
240        unsafe { ffi::CString::from_raw(id) }
241            .into_string()
242            .map_err(|_| libsession_sys::Error::InvalidData)
243    }
244}
245
246impl Drop for Session {
247    fn drop(&mut self) {
248        unsafe { libsession_sys::libsession_session_free(self.0.as_ptr()) };
249    }
250}
251
252pub struct Monitor(ptr::NonNull<libsession_sys::libsession_monitor>);
253
254impl Monitor {
255    pub fn flush(&mut self) {
256        libsession_sys::libsession_monitor_flush(self.0.as_ptr());
257    }
258}
259
260impl AsRawFd for Monitor {
261    fn as_raw_fd(&self) -> fd::RawFd {
262        libsession_sys::libsession_monitor_fd(self.0.as_ptr())
263    }
264}
265
266impl AsFd for Monitor {
267    fn as_fd(&self) -> fd::BorrowedFd<'_> {
268        unsafe { fd::BorrowedFd::borrow_raw(self.as_raw_fd()) }
269    }
270}
271
272impl Drop for Monitor {
273    fn drop(&mut self) {
274        libsession_sys::libsession_monitor_free(self.0.as_ptr());
275    }
276}
277
278impl Drop for Context {
279    fn drop(&mut self) {
280        libsession_sys::libsession_free(self.0.as_ptr());
281    }
282}