v_common_api/
api_client.rs

1#[macro_use]
2extern crate log;
3
4pub mod app;
5
6use app::*;
7use nng::{Message, Protocol, Socket};
8use serde_json::json;
9use serde_json::Value;
10use std::error::Error;
11use std::fmt;
12use v_onto::individual::Individual;
13
14use nng::options::{Options, RecvTimeout, SendTimeout};
15use std::time::Duration;
16pub use v_onto;
17
18pub const ALL_MODULES: i64 = 0;
19
20#[derive(Debug)]
21pub struct ApiError {
22    result: ResultCode,
23    info: String,
24}
25
26impl fmt::Display for ApiError {
27    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28        write!(f, "There is an error: {} {:?}", self.info, self.result)
29    }
30}
31
32impl Error for ApiError {}
33
34impl Default for ApiError {
35    fn default() -> Self {
36        ApiError {
37            result: ResultCode::Zero,
38            info: Default::default(),
39        }
40    }
41}
42#[derive(PartialEq, Debug, Clone)]
43#[repr(u16)]
44pub enum IndvOp {
45    /// Сохранить
46    Put = 1,
47
48    /// Сохранить
49    Get = 2,
50
51    /// Получить тикет
52    GetTicket = 3,
53
54    /// Авторизовать
55    Authorize = 8,
56
57    /// Установить в
58    SetIn = 45,
59
60    /// Добавить в
61    AddTo = 47,
62
63    /// Убрать из
64    RemoveFrom = 48,
65
66    /// Убрать
67    Remove = 51,
68
69    None = 52,
70}
71
72impl IndvOp {
73    pub fn from_i64(value: i64) -> IndvOp {
74        match value {
75            1 => IndvOp::Put,
76            2 => IndvOp::Get,
77            51 => IndvOp::Remove,
78            47 => IndvOp::AddTo,
79            45 => IndvOp::SetIn,
80            48 => IndvOp::RemoveFrom,
81            8 => IndvOp::Authorize,
82            3 => IndvOp::GetTicket,
83            // ...
84            _ => IndvOp::None,
85        }
86    }
87
88    pub fn to_i64(&self) -> i64 {
89        match self {
90            IndvOp::Put => 1,
91            IndvOp::Get => 2,
92            IndvOp::Remove => 51,
93            IndvOp::AddTo => 47,
94            IndvOp::SetIn => 45,
95            IndvOp::RemoveFrom => 48,
96            IndvOp::Authorize => 8,
97            IndvOp::GetTicket => 3,
98            // ...
99            IndvOp::None => 52,
100        }
101    }
102
103    pub fn as_string(&self) -> String {
104        match self {
105            IndvOp::Get => "get",
106            IndvOp::Put => "put",
107            IndvOp::Remove => "remove",
108            IndvOp::AddTo => "add_to",
109            IndvOp::SetIn => "set_in",
110            IndvOp::RemoveFrom => "remove_from",
111            IndvOp::Authorize => "authorize",
112            IndvOp::GetTicket => "get_ticket",
113            // ...
114            IndvOp::None => "none",
115        }
116        .to_string()
117    }
118}
119
120#[derive(Debug)]
121pub struct OpResult {
122    pub result: ResultCode,
123    pub op_id: i64,
124}
125
126impl OpResult {
127    pub fn res(r: ResultCode) -> Self {
128        OpResult {
129            result: r,
130            op_id: -1,
131        }
132    }
133}
134
135pub struct APIClient {
136    client: Socket,
137    addr: String,
138    is_ready: bool,
139}
140
141impl APIClient {
142    pub fn new(_addr: String) -> APIClient {
143        APIClient {
144            client: Socket::new(Protocol::Req0).unwrap(),
145            addr: _addr,
146            is_ready: false,
147        }
148    }
149
150    pub fn connect(&mut self) -> bool {
151        if self.addr.is_empty() {
152            error!("api-client:invalid addr: [{}]", self.addr);
153            return self.is_ready;
154        }
155
156        if let Err(e) = self.client.dial(self.addr.as_str()) {
157            error!("api-client:fail dial to main module, [{}], err={}", self.addr, e);
158        } else {
159            info!("success connect to main module, [{}]", self.addr);
160            self.is_ready = true;
161
162            if let Err(e) = self.client.set_opt::<RecvTimeout>(Some(Duration::from_secs(30))) {
163                error!("fail set recv timeout, err={}", e);
164            }
165            if let Err(e) = self.client.set_opt::<SendTimeout>(Some(Duration::from_secs(30))) {
166                error!("fail set send timeout, err={}", e);
167            }
168        }
169        self.is_ready
170    }
171
172    pub fn update(&mut self, ticket: &str, cmd: IndvOp, indv: &Individual) -> OpResult {
173        self.update_use_param(ticket, "", "", ALL_MODULES, cmd, indv)
174    }
175
176    pub fn update_or_err(&mut self, ticket: &str, event_id: &str, src: &str, cmd: IndvOp, indv: &Individual) -> Result<OpResult, ApiError> {
177        let res = self.update_use_param(ticket, event_id, src, ALL_MODULES, cmd, indv);
178        if res.result == ResultCode::Ok {
179            Ok(res)
180        } else {
181            Err(ApiError {
182                result: res.result,
183                info: "update_or_err".to_owned(),
184            })
185        }
186    }
187
188    pub fn update_use_param(&mut self, ticket: &str, event_id: &str, src: &str, assigned_subsystems: i64, cmd: IndvOp, indv: &Individual) -> OpResult {
189        if !self.is_ready {
190            self.connect();
191        }
192
193        if !self.is_ready {
194            return OpResult::res(ResultCode::NotReady);
195        }
196
197        let query = json!({
198            "function": cmd.as_string(),
199            "ticket": ticket,
200            "individuals": [ indv.get_obj().as_json() ],
201            "assigned_subsystems": assigned_subsystems,
202            "event_id" : event_id,
203            "src" : src
204        });
205
206        debug!("SEND {}", query.to_string());
207        let req = Message::from(query.to_string().as_bytes());
208
209        if let Err(e) = self.client.send(req) {
210            error!("api:update - fail send to main module, err={:?}", e);
211            return OpResult::res(ResultCode::NotReady);
212        }
213
214        // Wait for the response from the server.
215        let wmsg = self.client.recv();
216
217        if let Err(e) = wmsg {
218            error!("api:update - fail recv from main module, err={:?}", e);
219            return OpResult::res(ResultCode::NotReady);
220        }
221
222        let msg = wmsg.unwrap();
223
224        debug!("recv msg = {}", &String::from_utf8_lossy(&msg));
225
226        let reply = serde_json::from_str(&String::from_utf8_lossy(&msg));
227
228        if let Err(e) = reply {
229            error!("api:update - fail parse result operation [put], err={:?}", e);
230            return OpResult::res(ResultCode::BadRequest);
231        }
232
233        let json: Value = reply.unwrap();
234
235        if let Some(t) = json["type"].as_str() {
236            if t != "OpResult" {
237                error!("api:update - expecten \"type\" = \"OpResult\", found {}", t);
238                return OpResult::res(ResultCode::BadRequest);
239            }
240        } else {
241            error!("api:update - not found \"type\"");
242            return OpResult::res(ResultCode::BadRequest);
243        }
244
245        if let Some(arr) = json["data"].as_array() {
246            if arr.len() != 1 {
247                error!("api:update - invalid \"data\" section");
248                return OpResult::res(ResultCode::BadRequest);
249            }
250
251            if let Some(res) = arr[0]["result"].as_i64() {
252                if let Some(op_id) = arr[0]["op_id"].as_i64() {
253                    return OpResult {
254                        result: ResultCode::from_i64(res),
255                        op_id,
256                    };
257                }
258            } else {
259                error!("api:update - invalid \"data\" section");
260                return OpResult::res(ResultCode::BadRequest);
261            }
262        } else {
263            return if let Some(res) = json["result"].as_i64() {
264                OpResult {
265                    result: ResultCode::from_i64(res),
266                    op_id: 0,
267                }
268            } else {
269                error!("api:update - not found \"data\"");
270                OpResult::res(ResultCode::BadRequest)
271            };
272        }
273
274        OpResult::res(ResultCode::BadRequest)
275    }
276}