use crate::error::TdlibSysError; use libc::c_char; use std::ffi::CStr; use std::ffi::CString; #[derive(Debug)] pub struct TdPtr(*mut tdlib_sys::TdLibRawPtr); // Send + Sync is guaranteed by TDLib unsafe impl Send for TdPtr {} unsafe impl Sync for TdPtr {} /// TDLib uses 6 fixed logging levels /// /// You can also set even more logging through `More` variant, /// providing desired logging level #[derive(Debug, PartialEq, Eq)] pub enum LogLevel { Fatal, Error, Warn, Info, Debug, Verbose, /// This sets more verbose logging. /// /// Must be between 6 and 1024 inclusively More(u16), } impl std::default::Default for LogLevel { fn default() -> Self { Self::Verbose // 5 is default value from tdlib's docs } } impl TdPtr { /// Sets the verbosity level of the internal logging of TDLib. /// By default the TDLib uses a log verbosity level of 5 (meaning [`LogLevel::Verbose`]). pub fn set_log_verbosity_level(level: LogLevel) -> Result<(), TdlibSysError> { let numeric_level: i32 = match level { LogLevel::Fatal => 0, LogLevel::Error => 1, LogLevel::Warn => 2, LogLevel::Info => 3, LogLevel::Debug => 4, LogLevel::Verbose => 5, LogLevel::More(n) => { if n > 1024 { return Err(TdlibSysError::LogLevelOutOfBounds(n)); } else { n as i32 } } }; unsafe { tdlib_sys::td_set_log_verbosity_level(numeric_level) }; Ok(()) } /// Sets the maximum size of the file to where the internal TDLib log is written /// before the file will be auto-rotated. /// /// Unused if log is not written to a file. Defaults to 10 MB. pub fn set_log_max_file_size(size: i64) { unsafe { tdlib_sys::td_set_log_max_file_size(size) }; } /// Sets the path to the file where the internal TDLib log will be written. /// /// By default TDLib writes logs to stderr or an OS specific log. /// /// Use this method to write the log to a file instead. pub fn set_log_file_path>(path: S) -> Result<(), TdlibSysError> { let cpath = CString::new(path.as_ref())?; if unsafe { tdlib_sys::td_set_log_file_path(cpath.as_ptr()) } == 0 { Err(TdlibSysError::CannotSetLogFile) } else { Ok(()) } } /// Resets log file. /// /// This function reverts writing to a log file and restores /// default behaviour for logging. At the time of writing, this means /// logging to stderr pub fn reset_log_file_path() -> Result<(), TdlibSysError> { if unsafe { tdlib_sys::td_set_log_file_path(std::ptr::null()) } == 0 { Err(TdlibSysError::CannotSetLogFile) } else { Ok(()) } } /// Creates a new instance of TDLib. pub fn new() -> Self { Self(unsafe { tdlib_sys::td_json_client_create() }) } /// Sends request to the TDLib client. /// /// May be called from any thread. pub fn send(&self, request: &str) -> Result<(), TdlibSysError> { let cstring = CString::new(request)?; unsafe { tdlib_sys::td_json_client_send(self.0, cstring.as_ptr()) }; Ok(()) } /// Receives incoming updates and request responses from the TDLib client. /// /// May be called from any thread, but must not be called simultaneously /// from two different threads. pub fn execute(&self, request: &str) -> Result, TdlibSysError> { let repr_c = CString::new(request)?.as_ptr(); Ok(Self::string_from_mut_char(unsafe { tdlib_sys::td_json_client_execute(self.0, repr_c) })) } /// Receives incoming updates and request responses from the TDLib client. /// /// May be called from any thread, but shouldn't be called simultaneously /// from two different threads. pub fn receive(&self, timeout: f64) -> Option { Self::string_from_mut_char(unsafe { tdlib_sys::td_json_client_receive(self.0, timeout) }) } /// Convert `*mut c_char` into String. /// /// Returns None if `ptr` is null fn string_from_mut_char(ptr: *mut c_char) -> Option { let cstr = unsafe { CStr::from_ptr(ptr.as_ref()?) }; Some(cstr.to_string_lossy().into_owned()) } } impl Drop for TdPtr { fn drop(&mut self) { unsafe { tdlib_sys::td_json_client_destroy(self.0); } } } mod tests { #[test] fn test_create() { let _td = super::TdPtr::new(); } }