1use crate::signaldrequest::SignaldRequestBuilder;
2use crate::signaldrequest::SignaldRequest;
3use std::time::{Instant, Duration};
4use bus::{BusReader};
5use std::sync::mpsc::RecvTimeoutError::Timeout;
6use std::sync::mpsc::RecvTimeoutError;
7use crate::signaldresponse::{SignaldResponse, ResponseType};
8use crate::signald::FilterType::{Id, Type};
9use crate::signaldresponse::ResponseType::BusUpdate;
10use crate::socket::Socket;
11use crate::socket::signaldsocket::SignaldSocket;
12
13pub static SOCKET_PATH: &'static str = "/var/run/signald/signald.sock";
14
15pub enum FilterType {
16 Id(String),
17 Type(ResponseType)
18}
19
20pub struct Signald {
21 socket: SignaldSocket,
24 message_count: u32,
26}
27impl Signald {
28
29 pub fn connect() -> Signald {
31 Signald::connect_path(&SOCKET_PATH)
32 }
33 pub fn connect_path(socket_path: &str) -> Self {
35 let socket: SignaldSocket = SignaldSocket::connect(socket_path.to_string(), 100);
36
37 Self {
38 socket: socket,
40 message_count: 0,
41 }
42 }
43 pub fn send_request(&mut self, request: &SignaldRequest) {
45 self.message_count += 1;
46 self.socket.send_request(&request);
47 }
48
49 pub async fn send(&mut self, username: String, recipient_number: String, message_body: Option<String>) {
53 let mut request_builder = SignaldRequestBuilder::new();
54 request_builder.set_type("send".to_string());
55 request_builder.set_username(username);
56 request_builder.set_recipient_number(recipient_number);
57 if let Some(i) = message_body {
58 request_builder.set_message_body(i);
59 }
60
61 let request = request_builder.build();
62 self.send_request(&request);
63 }
64
65 pub async fn subscribe(&mut self, username: String) -> Result<SignaldResponse, RecvTimeoutError> {
67 let id = self.message_count.to_string();
68
69 let mut request_builder = SignaldRequestBuilder::new();
70 request_builder.set_type("subscribe".to_string());
71 request_builder.set_username(username);
72 request_builder.set_id(id.clone());
73 let request = request_builder.build();
74
75 self.send_request(&request);
76 self.wait_for_request(Id(id)).await
77 }
78 pub async fn unsubscribe(&mut self, username: String) -> Result<SignaldResponse, RecvTimeoutError> {
80 let id = self.message_count.to_string();
81
82 let mut request_builder = SignaldRequestBuilder::new();
83 request_builder.set_type("unsubscribe".to_string());
84 request_builder.set_username(username);
85 request_builder.set_id(id.clone());
86 let request = request_builder.build();
87
88 self.send_request(&request);
89 self.wait_for_request(Id(id)).await
90 }
91 pub async fn link(&mut self) -> Result<SignaldResponse, RecvTimeoutError> {
93 let id = self.message_count.to_string();
94
95 let mut request_builder = SignaldRequestBuilder::new();
96 request_builder.set_type("link".to_string());
97 request_builder.set_id(id.clone());
98 let request = request_builder.build();
99
100 self.send_request(&request);
101 self.wait_for_request(Id(id)).await
102 }
103 pub async fn version(&mut self) -> Result<SignaldResponse, RecvTimeoutError> {
105 let id = self.message_count.to_string();
106
107 let mut request_builder = SignaldRequestBuilder::new();
108 request_builder.set_type("version".to_string());
109 request_builder.set_id(id.clone());
110 let request = request_builder.build();
111
112 self.send_request(&request);
113 self.wait_for_request(Type(ResponseType::Version(None))).await
114 }
115 pub async fn list_contacts(&mut self, username: String) -> Result<SignaldResponse, RecvTimeoutError> {
117 let id = self.message_count.to_string();
118
119 let mut request_builder = SignaldRequestBuilder::new();
120 request_builder.set_type("list_contacts".to_string());
121 request_builder.set_username(username);
122 request_builder.set_id(id.clone());
123 let request = request_builder.build();
124
125 self.send_request(&request);
126 self.wait_for_request(Id(id)).await
127 }
128 pub fn sync_contacts(&mut self, username: String) {
130 let mut request_builder = SignaldRequestBuilder::new();
131 request_builder.set_type("sync_contacts".to_string());
132 request_builder.set_username(username);
133 request_builder.set_id(self.message_count.to_string());
134 let request = request_builder.build();
135
136 self.send_request(&request);
137 }
138 pub fn get_rx(&mut self) -> BusReader<SignaldResponse> {
140 self.socket.get_rx()
141 }
142
143 async fn wait_for_request(&mut self, filter: FilterType) -> Result<SignaldResponse, RecvTimeoutError> {
146 let end = Instant::now() + Duration::from_millis(3000);
148 let mut rx = self.socket.get_rx();
149
150 let result = rx.iter()
151 .take_while(|_| Instant::now() < end )
153 .find(|response| {
154 if let BusUpdate = response.data { return false; }
156
157 Signald::filter_request(&filter, &response)
158 });
159
160 match result {
162 Some(x) => {
163 Ok(x)
164 },
165 None => {
166 Err(Timeout)
167 }
168 }
169
170 }
171
172 fn filter_request(filter: &FilterType, message: &SignaldResponse) -> bool {
173 match filter {
174 Id(req_id) => {
176 match &message.id {
177 Some(s) => {
178 return s == req_id.as_str();
179 },
180 None => {
181 false
182 }
183 }
184 }
185 Type(req_type) => {
187 let disc1 = std::mem::discriminant(req_type);
188 let disc2 = std::mem::discriminant(&message.data);
189 return disc1 == disc2;
190 }
191 }
192 }
193
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn test_filter_request_id_success() {
202 let id = "test".to_string();
203
204 let message = SignaldResponse {
205 id: Some(id.clone()),
206 data: ResponseType::Subscribed
207 };
208
209 assert!(Signald::filter_request(&Id(id), &message));
210 }
211
212 #[test]
213 fn test_filter_request_id_wrong() {
214 let id = "test".to_string();
215
216 let message = SignaldResponse {
217 id: Some(id.clone()),
218 data: ResponseType::Subscribed
219 };
220
221 assert!(!Signald::filter_request(&Id("INCORRECT_ID".to_string()), &message));
222 }
223
224 #[test]
225 fn test_filter_request_type_correct() {
226 let message = SignaldResponse {
227 id: None,
228 data: ResponseType::Subscribed
229 };
230
231 assert!(Signald::filter_request(&Type(ResponseType::Subscribed), &message));
232 }
233
234 #[test]
235 fn test_filter_request_type_wrong() {
236 let message = SignaldResponse {
237 id: None,
238 data: ResponseType::Subscribed
239 };
240
241 assert!(!Signald::filter_request(&Type(ResponseType::Unsubscribed), &message));
242 }
243}