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 Put = 1,
47
48 Get = 2,
50
51 GetTicket = 3,
53
54 Authorize = 8,
56
57 SetIn = 45,
59
60 AddTo = 47,
62
63 RemoveFrom = 48,
65
66 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 _ => 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 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 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 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}