v_common_v8/
session_cache.rs1use 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 } 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 ti.rc = ResultCode::NotFound;
152 },
153 Err(e) => {
154 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}