summaryrefslogtreecommitdiffstats
path: root/src/raw_ptr.rs
blob: 5e2bddee1ae15522cf024b3274f5867a4aca6d79 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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<S: AsRef<str>>(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<Option<String>, 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<String> {
        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<String> {
        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();
    }
}