futu_cache/qot_right/
backend_apply.rs1use super::*;
7
8impl QotRightCache {
9 pub fn apply_6651_changes(&self, items: &[(i32, i32, i32)]) -> Vec<i32> {
10 let mut d = self.data.write();
11 let mut changed_types = Vec::new();
12
13 for &(quote_type, before, after) in items {
14 let current = QotRightPushCurrentFacts {
15 api_us_qot_right: d.api_us_qot_right,
16 us_lv2_arca: d.us_lv2_arca_qot_right,
17 us_lv2_nyse: d.us_lv2_nyse_qot_right,
18 us_lv2_nasdaq_totalview: d.us_lv2_nasdaq_totalview_qot_right,
19 };
20 if let Some(projection) = project_qot_right_6651_change_with_current(
21 QotRight6651Change {
22 quote_type,
23 before,
24 after,
25 },
26 current,
27 ) {
28 apply_backend_projection(&mut d, projection.patch);
29 changed_types.push(projection.quote_type);
30 }
31 }
32 if !changed_types.is_empty() {
33 drop(d);
34 let mut m = self.meta.lock();
35 m.freshness = qot_right_after_push_changes(m.freshness.clone(), true);
36 if m.freshness.is_fresh() {
37 m.last_refresh_at_ms = now_ms();
38 }
39 }
40 changed_types
41 }
42
43 pub fn apply_direct_auth_changes(&self, items: &[(i32, u32)]) -> Vec<i32> {
44 let mut d = self.data.write();
45 let mut changed_types = Vec::new();
46
47 for &(quote_type, after) in items {
48 if let Some(projection) =
49 project_qot_right_direct_auth_change(QotRightDirectAuthChange { quote_type, after })
50 {
51 apply_backend_projection(&mut d, projection.patch);
52 changed_types.push(projection.quote_type);
53 }
54 }
55 if !changed_types.is_empty() {
56 drop(d);
57 let mut m = self.meta.lock();
58 m.freshness = qot_right_after_push_changes(m.freshness.clone(), true);
59 if m.freshness.is_fresh() {
60 m.last_refresh_at_ms = now_ms();
61 }
62 }
63 changed_types
64 }
65
66 pub fn apply_6006_auth_changes_if_source(
73 &self,
74 expected_generation: u64,
75 source_publication_epoch: u64,
76 items: &[(i32, u32)],
77 cn_after: Option<u32>,
78 ) -> Option<Vec<i32>> {
79 let mut data = self.data.write();
80 let mut meta = self.meta.lock();
81 if meta.backend_generation != expected_generation
82 || meta
83 .source_publication_epoch
84 .is_some_and(|epoch| epoch != source_publication_epoch)
85 {
86 return None;
87 }
88
89 let mut changed_types = Vec::new();
90 for &(quote_type, after) in items {
91 if let Some(projection) =
92 project_qot_right_direct_auth_change(QotRightDirectAuthChange { quote_type, after })
93 {
94 apply_backend_projection(&mut data, projection.patch);
95 changed_types.push(projection.quote_type);
96 }
97 }
98 if let Some(cn_after) = cn_after {
99 let projection = project_qot_right_backend_update(
100 QotRightBackendCurrent {
101 us_qot_right: data.us_qot_right,
102 },
103 QotRightBackendUpdate {
104 cn_got: Some(cn_after),
105 ..Default::default()
106 },
107 );
108 apply_backend_projection(&mut data, projection);
109 changed_types.push(2);
110 }
111 if !changed_types.is_empty() {
112 meta.freshness = qot_right_after_push_changes(meta.freshness.clone(), true);
113 meta.last_refresh_at_ms = now_ms();
114 }
115 Some(changed_types)
116 }
117
118 pub fn update_from_backend(
127 &self,
128 update: QotRightBackendUpdate,
129 ) -> QotRightBackendApplyOutcome {
130 let mut data = self.data.write();
131 let mut meta = self.meta.lock();
132 let expected_generation = meta.backend_generation;
133 Self::apply_full_backend_update_locked(
134 &mut data,
135 &mut meta,
136 QotRightFullApplyFacts {
137 expected_generation,
138 source_publication_epoch: None,
139 is_highest: false,
140 force_resub: false,
141 pushed_notify_version: None,
142 },
143 update,
144 )
145 }
146
147 pub fn update_from_backend_if_generation(
148 &self,
149 facts: QotRightFullApplyFacts,
150 update: QotRightBackendUpdate,
151 ) -> Option<QotRightBackendApplyOutcome> {
152 let mut d = self.data.write();
153 let mut m = self.meta.lock();
154 if m.backend_generation != facts.expected_generation {
155 return None;
156 }
157 Some(Self::apply_full_backend_update_locked(
158 &mut d, &mut m, facts, update,
159 ))
160 }
161
162 fn apply_full_backend_update_locked(
163 d: &mut QotRightData,
164 m: &mut QotRightStateMeta,
165 facts: QotRightFullApplyFacts,
166 update: QotRightBackendUpdate,
167 ) -> QotRightBackendApplyOutcome {
168 let has_set_qot_right_before = has_set_qot_right_like_cpp(d);
169 let public_before = QotRightPublicSnapshot::from(&*d);
170 let reconnect_before = QotRightReconnectSnapshot::from(&*d);
171 let has_us_utp_before = d.has_us_utp;
172 let quota_before = (d.sub_quota, d.history_kl_quota);
173 let projection = project_qot_right_backend_update(
174 QotRightBackendCurrent {
175 us_qot_right: d.us_qot_right,
176 },
177 update,
178 );
179 let event_contract_became_level1 = projection.event_contract_qot_right
180 == Some(QOT_RIGHT_LEVEL1)
181 && d.event_contract_qot_right != QOT_RIGHT_LEVEL1;
182 apply_backend_projection(d, projection);
183 let quota_data_changed = quota_before != (d.sub_quota, d.history_kl_quota);
184 let public_rights_changed = public_before != QotRightPublicSnapshot::from(&*d);
185 let reconnect_quote_types = reconnect_before.changed_quote_types(d);
186 let has_us_utp_changed = has_us_utp_before != d.has_us_utp;
187
188 m.freshness = qot_right_mark_fresh();
190 m.source_publication_epoch = facts.source_publication_epoch;
191 m.last_refresh_at_ms = now_ms();
192 m.event_contract_category_preload_pending |= event_contract_became_level1;
193
194 if facts.is_highest
195 && (!reconnect_quote_types.is_empty() || facts.force_resub)
196 && facts.pushed_notify_version == Some(m.last_pushed_quote_change_notify_version)
197 {
198 m.last_pushed_quote_change_notify = None;
199 }
200
201 QotRightBackendApplyOutcome {
202 public_rights_changed,
203 reconnect_quote_types,
204 has_set_qot_right_before,
205 has_us_utp_changed,
206 quota_data_changed,
207 quota_projection_available: true,
211 }
212 }
213
214 pub fn update_quotas_from_backend_if_generation(
215 &self,
216 expected_generation: u64,
217 update: QotRightBackendUpdate,
218 ) -> Option<QotRightBackendApplyOutcome> {
219 let projection =
220 project_qot_right_backend_update(QotRightBackendCurrent::default(), update);
221 let mut d = self.data.write();
222 let m = self.meta.lock();
223 if m.backend_generation != expected_generation {
224 return None;
225 }
226 let quota_before = (d.sub_quota, d.history_kl_quota);
227 if let Some(value) = projection.sub_quota {
228 d.sub_quota = value;
229 }
230 if let Some(value) = projection.history_kl_quota {
231 d.history_kl_quota = value;
232 }
233 Some(QotRightBackendApplyOutcome {
234 public_rights_changed: false,
235 reconnect_quote_types: Vec::new(),
236 has_set_qot_right_before: false,
237 has_us_utp_changed: false,
238 quota_data_changed: quota_before != (d.sub_quota, d.history_kl_quota),
239 quota_projection_available: true,
240 })
241 }
242}
243
244fn apply_backend_projection(data: &mut QotRightData, projection: QotRightBackendProjection) {
245 if let Some(v) = projection.hk_own_qot_right {
246 data.hk_own_qot_right = v;
247 }
248 if let Some(v) = projection.hk_qot_right {
249 data.hk_qot_right = v;
250 }
251 if let Some(v) = projection.us_own_qot_right {
252 data.us_own_qot_right = v;
253 }
254 if let Some(v) = projection.us_qot_right {
255 data.us_qot_right = v;
256 }
257 if let Some(v) = projection.api_us_qot_right {
258 data.api_us_qot_right = v;
259 }
260 if let Some(v) = projection.has_us_utp {
261 data.has_us_utp = v;
262 }
263 if let Some(v) = projection.has_us_overnight {
264 data.has_us_overnight = v;
265 }
266 if let Some(v) = projection.sh_qot_right {
267 data.sh_qot_right = v;
268 }
269 if let Some(v) = projection.sz_qot_right {
270 data.sz_qot_right = v;
271 }
272 if let Some(v) = projection.hk_option_qot_right {
273 data.hk_option_qot_right = v;
274 }
275 if let Some(v) = projection.hk_future_qot_right {
276 data.hk_future_qot_right = v;
277 }
278 if let Some(v) = projection.hk_option_orderbook_depth {
279 data.hk_option_orderbook_depth = Some(v);
280 }
281 if let Some(v) = projection.hk_future_orderbook_depth {
282 data.hk_future_orderbook_depth = Some(v);
283 }
284 if let Some(v) = projection.has_us_option_qot_right {
285 data.has_us_option_qot_right = v;
286 }
287 if let Some(v) = projection.us_option_qot_right {
288 data.us_option_qot_right = v;
289 }
290 if let Some(v) = projection.us_index_qot_right {
291 data.us_index_qot_right = v;
292 }
293 if let Some(v) = projection.us_otc_qot_right {
294 data.us_otc_qot_right = v;
295 }
296 if let Some(v) = projection.us_cme_future_qot_right {
297 data.us_cme_future_qot_right = v;
298 }
299 if let Some(v) = projection.us_cbot_future_qot_right {
300 data.us_cbot_future_qot_right = v;
301 }
302 if let Some(v) = projection.us_nymex_future_qot_right {
303 data.us_nymex_future_qot_right = v;
304 }
305 if let Some(v) = projection.us_comex_future_qot_right {
306 data.us_comex_future_qot_right = v;
307 }
308 if let Some(v) = projection.us_cboe_future_qot_right {
309 data.us_cboe_future_qot_right = v;
310 }
311 if let Some(v) = projection.sg_future_qot_right {
312 data.sg_future_qot_right = v;
313 }
314 if let Some(v) = projection.jp_future_qot_right {
315 data.jp_future_qot_right = v;
316 }
317 if let Some(v) = projection.sg_stock_qot_right {
318 data.sg_stock_qot_right = v;
319 }
320 if let Some(v) = projection.my_stock_qot_right {
321 data.my_stock_qot_right = v;
322 }
323 if let Some(v) = projection.jp_stock_qot_right {
324 data.jp_stock_qot_right = v;
325 }
326 if let Some(v) = projection.cc_qot_right {
327 data.cc_qot_right = v;
328 }
329 if let Some(v) = projection.has_digital_future_auth {
330 data.has_digital_future_auth = v;
331 }
332 if let Some(v) = projection.cc_pt_orderbook_qot_right {
333 data.cc_pt_orderbook_qot_right = v;
334 }
335 if let Some(v) = projection.event_contract_qot_right {
336 data.event_contract_qot_right = v;
337 }
338 if let Some(ids) = projection.event_contract_prohibited_category_ids {
339 data.event_contract_prohibited_category_ids = ids;
340 }
341 if let Some(v) = projection.us_lv2_arca_qot_right {
342 data.us_lv2_arca_qot_right = v;
343 }
344 if let Some(v) = projection.us_lv2_nyse_qot_right {
345 data.us_lv2_nyse_qot_right = v;
346 }
347 if let Some(v) = projection.us_lv2_nasdaq_totalview_qot_right {
348 data.us_lv2_nasdaq_totalview_qot_right = v;
349 }
350 if let Some(v) = projection.sub_quota {
351 data.sub_quota = v;
352 }
353 if let Some(v) = projection.history_kl_quota {
354 data.history_kl_quota = v;
355 }
356}