v_common_v8/
session_cache.rs

1use std::collections::{HashMap, HashSet};
2use std::string::ToString;
3
4use v_common::module::remote_indv_r_storage::get_individual;
5use v_common::module::veda_backend::indv_apply_cmd;
6use v_common::onto::individual::Individual;
7use v_common::onto::onto_impl::Onto;
8use v_common::onto::parser::parse_raw;
9use v_common::v_api::api_client::UpdateOptions;
10use v_common::v_api::api_client::{IndvOp, MStorageClient, ALL_MODULES};
11use v_common::v_api::obj::ResultCode;
12
13#[derive(Default)]
14pub struct CallbackSharedData {
15    pub g_key2indv: HashMap<String, Individual>,
16    pub g_key2attr: HashMap<String, String>,
17}
18
19impl CallbackSharedData {
20    pub fn set_g_parent_script_id_etc(&mut self, event_id: &str) {
21        let mut event_id = event_id;
22
23        if !event_id.is_empty() {
24            let mut aa: Vec<&str> = event_id.split(';').collect();
25            if !aa.is_empty() {
26                event_id = aa.first().unwrap();
27            }
28
29            aa = event_id.split('+').collect();
30
31            if aa.len() >= 2 {
32                self.g_key2attr.insert("$parent_script_id".to_owned(), aa.get(1).unwrap().to_string());
33                self.g_key2attr.insert("$parent_document_id".to_owned(), aa.first().unwrap().to_string());
34            } else {
35                self.g_key2attr.insert("$parent_script_id".to_owned(), String::default());
36                self.g_key2attr.insert("$parent_document_id".to_owned(), String::default());
37            }
38        } else {
39            self.g_key2attr.insert("$parent_script_id".to_owned(), String::default());
40            self.g_key2attr.insert("$parent_document_id".to_owned(), String::default());
41        }
42    }
43
44    pub fn set_g_super_classes(&mut self, indv_types: &[String], onto: &Onto) {
45        let mut super_classes = HashSet::new();
46
47        for indv_type in indv_types.iter() {
48            onto.get_supers(indv_type, &mut super_classes);
49        }
50
51        let mut g_super_classes = String::new();
52
53        g_super_classes.push('[');
54        for s in super_classes.iter() {
55            if g_super_classes.len() > 2 {
56                g_super_classes.push(',');
57            }
58            g_super_classes.push('"');
59            g_super_classes.push_str(s);
60            g_super_classes.push('"');
61        }
62        g_super_classes.push(']');
63
64        self.g_key2attr.insert("$super_classes".to_owned(), g_super_classes);
65    }
66}
67
68pub struct TransactionItem {
69    uri: String,
70    pub cmd: IndvOp,
71    pub indv: Individual,
72    ticket_id: String,
73    pub rc: ResultCode,
74}
75
76pub struct Transaction {
77    pub sys_ticket: String,
78    pub id: i64,
79    pub event_id: String,
80    buff: HashMap<String, usize>,
81    pub queue: Vec<TransactionItem>,
82    pub src: String,
83}
84
85impl Default for Transaction {
86    fn default() -> Self {
87        Self {
88            sys_ticket: "".to_string(),
89            id: 0,
90            event_id: "".to_string(),
91            buff: Default::default(),
92            queue: vec![],
93            src: "".to_string(),
94        }
95    }
96}
97
98impl Transaction {
99    fn add_item(&mut self, item: TransactionItem) {
100        self.buff.insert(item.uri.clone(), self.queue.len());
101        self.queue.push(item);
102    }
103
104    pub(crate) fn get_indv(&mut self, id: &str) -> Option<&mut Individual> {
105        if let Some(idx) = self.buff.get(id) {
106            if let Some(ti) = self.queue.get_mut(*idx) {
107                return Some(&mut ti.indv);
108            }
109        }
110
111        None
112    }
113
114    pub(crate) fn add_to_transaction(&mut self, cmd: IndvOp, new_indv: Individual, ticket_id: String, _user_id: String) -> ResultCode {
115        let mut ti = TransactionItem {
116            uri: "".to_string(),
117            cmd,
118            indv: new_indv,
119            ticket_id,
120            rc: ResultCode::Ok,
121        };
122
123        if ti.cmd == IndvOp::Remove {
124            // No changes needed for Remove operation
125        } else {
126            ti.uri = ti.indv.get_id().to_string();
127
128            if ti.cmd == IndvOp::AddTo || ti.cmd == IndvOp::SetIn || ti.cmd == IndvOp::RemoveFrom {
129                if let Some(prev_indv) = self.get_indv(ti.indv.get_id()) {
130                    debug!("{:?} BEFORE: {}", ti.cmd, &prev_indv);
131                    debug!("{:?} APPLY: {}", ti.cmd, &ti.indv);
132                    indv_apply_cmd(&ti.cmd, prev_indv, &mut ti.indv);
133                    debug!("{:?} AFTER: {}", ti.cmd, &prev_indv);
134                    ti.indv = Individual::new_from_obj(prev_indv.get_obj());
135                } else {
136                    match get_individual(ti.indv.get_id()) {
137                        Ok(Some(mut prev_indv)) => {
138                            if parse_raw(&mut prev_indv).is_ok() {
139                                prev_indv.parse_all();
140                                debug!("{:?} BEFORE: {}", ti.cmd, &prev_indv);
141                                debug!("{:?} APPLY: {}", ti.cmd, &ti.indv);
142                                indv_apply_cmd(&ti.cmd, &mut prev_indv, &mut ti.indv);
143                                debug!("{:?} AFTER: {}", ti.cmd, &prev_indv);
144                                ti.indv = prev_indv;
145                            } else {
146                                ti.rc = ResultCode::UnprocessableEntity;
147                            }
148                        },
149                        Ok(None) => {
150                            // Individual not found
151                            ti.rc = ResultCode::NotFound;
152                        },
153                        Err(e) => {
154                            // Error occurred while getting individual
155                            error!("Error getting individual: {:?}", e);
156                            ti.rc = e;
157                        },
158                    }
159                }
160
161                if ti.rc == ResultCode::Ok {
162                    ti.cmd = IndvOp::Put;
163                }
164            }
165        }
166
167        if ti.rc == ResultCode::Ok {
168            self.add_item(ti);
169            ResultCode::Ok
170        } else {
171            ti.rc
172        }
173    }
174}
175
176pub fn commit(tnx: &Transaction, api_client: &mut MStorageClient) -> ResultCode {
177    for ti in tnx.queue.iter() {
178        if ti.cmd == IndvOp::Remove && ti.indv.get_id().is_empty() {
179            continue;
180        }
181
182        if ti.rc != ResultCode::Ok {
183            return ti.rc;
184        }
185
186        if ti.indv.get_id().is_empty() || ti.indv.get_id().len() < 2 {
187            warn!("skip individual with invalid id: {}", ti.indv.to_string());
188            continue;
189        }
190
191        debug!("commit {}", &ti.indv);
192        let update_options = UpdateOptions {
193            event_id: Some(&tnx.event_id),
194            src: Some(&tnx.src),
195            assigned_subsystems: Some(ALL_MODULES),
196            addr: None,
197        };
198
199        match api_client.update(&ti.indv, &ti.ticket_id, ti.cmd.clone(), update_options) {
200            Ok(res) => {
201                if res.result != ResultCode::Ok {
202                    error!("commit: op_id={}, code={:?}", res.op_id, res.result);
203                    return res.result;
204                }
205            },
206            Err(e) => {
207                return e.result;
208            },
209        }
210    }
211
212    ResultCode::Ok
213}