Skip to main content

veilid_remote_api/
process.rs

1use super::*;
2
3pub fn to_json_api_result<T: Clone + fmt::Debug + JsonSchema>(
4    r: VeilidAPIResult<T>,
5) -> super::ApiResult<T> {
6    match r {
7        Err(e) => super::ApiResult::Err { error: e },
8        Ok(v) => super::ApiResult::Ok { value: v },
9    }
10}
11
12pub fn to_json_api_result_with_string<T: Clone + fmt::Debug>(
13    r: VeilidAPIResult<T>,
14) -> super::ApiResultWithString<T> {
15    match r {
16        Err(e) => super::ApiResultWithString::Err { error: e },
17        Ok(v) => super::ApiResultWithString::Ok { value: v },
18    }
19}
20
21pub fn to_json_api_result_with_vec_string<T: Clone + fmt::Debug>(
22    r: VeilidAPIResult<T>,
23) -> super::ApiResultWithVecString<T> {
24    match r {
25        Err(e) => super::ApiResultWithVecString::Err { error: e },
26        Ok(v) => super::ApiResultWithVecString::Ok { value: v },
27    }
28}
29
30pub fn to_json_api_result_with_opt_vec_string<T: Clone + fmt::Debug>(
31    r: VeilidAPIResult<T>,
32) -> super::ApiResultWithOptVecString<T> {
33    match r {
34        Err(e) => super::ApiResultWithOptVecString::Err { error: e },
35        Ok(v) => super::ApiResultWithOptVecString::Ok { value: v },
36    }
37}
38
39#[must_use]
40pub fn to_json_api_result_with_vec_u8(r: VeilidAPIResult<Vec<u8>>) -> super::ApiResultWithVecU8 {
41    match r {
42        Err(e) => super::ApiResultWithVecU8::Err { error: e },
43        Ok(v) => super::ApiResultWithVecU8::Ok { value: v },
44    }
45}
46
47#[must_use]
48pub fn to_json_api_result_with_vec_vec_u8(
49    r: VeilidAPIResult<Vec<Vec<u8>>>,
50) -> super::ApiResultWithVecVecU8 {
51    match r {
52        Err(e) => super::ApiResultWithVecVecU8::Err { error: e },
53        Ok(v) => super::ApiResultWithVecVecU8::Ok {
54            value: v.into_iter().map(|v| VecU8 { value: v }).collect(),
55        },
56    }
57}
58
59struct JsonRequestProcessorInner {
60    routing_contexts: BTreeMap<u32, RoutingContext>,
61    table_dbs: BTreeMap<u32, TableDB>,
62    table_db_transactions: BTreeMap<u32, TableDBTransaction>,
63    dht_transactions: BTreeMap<u32, DHTTransaction>,
64    crypto_kinds: BTreeMap<u32, CryptoKind>,
65}
66
67#[derive(Clone)]
68pub struct JsonRequestProcessor {
69    api: VeilidAPI,
70    inner: Arc<Mutex<JsonRequestProcessorInner>>,
71}
72
73impl JsonRequestProcessor {
74    #[must_use]
75    pub fn new(api: VeilidAPI) -> Self {
76        Self {
77            api,
78            inner: Arc::new(Mutex::new(JsonRequestProcessorInner {
79                routing_contexts: Default::default(),
80                table_dbs: Default::default(),
81                table_db_transactions: Default::default(),
82                dht_transactions: Default::default(),
83                crypto_kinds: Default::default(),
84            })),
85        }
86    }
87
88    // Routing Context
89    fn add_routing_context(&self, routing_context: RoutingContext) -> u32 {
90        let mut inner = self.inner.lock();
91        let mut next_id: u32 = 1;
92        while inner.routing_contexts.contains_key(&next_id) {
93            next_id += 1;
94        }
95        inner.routing_contexts.insert(next_id, routing_context);
96        next_id
97    }
98    fn lookup_routing_context(&self, id: u32, rc_id: u32) -> Result<RoutingContext, Response> {
99        let inner = self.inner.lock();
100        let Some(routing_context) = inner.routing_contexts.get(&rc_id).cloned() else {
101            return Err(Response {
102                id,
103                op: ResponseOp::RoutingContext(Box::new(RoutingContextResponse {
104                    rc_id,
105                    rc_op: RoutingContextResponseOp::InvalidId,
106                })),
107            });
108        };
109        Ok(routing_context)
110    }
111    fn release_routing_context(&self, id: u32) -> i32 {
112        let mut inner = self.inner.lock();
113        if inner.routing_contexts.remove(&id).is_none() {
114            return 0;
115        }
116        1
117    }
118
119    // TableDB
120    fn add_table_db(&self, table_db: TableDB) -> u32 {
121        let mut inner = self.inner.lock();
122        let mut next_id: u32 = 1;
123        while inner.table_dbs.contains_key(&next_id) {
124            next_id += 1;
125        }
126        inner.table_dbs.insert(next_id, table_db);
127        next_id
128    }
129    fn lookup_table_db(&self, id: u32, db_id: u32) -> Result<TableDB, Response> {
130        let inner = self.inner.lock();
131        let Some(table_db) = inner.table_dbs.get(&db_id).cloned() else {
132            return Err(Response {
133                id,
134                op: ResponseOp::TableDb(TableDbResponse {
135                    db_id,
136                    db_op: TableDbResponseOp::InvalidId,
137                }),
138            });
139        };
140        Ok(table_db)
141    }
142    fn release_table_db(&self, id: u32) -> i32 {
143        let mut inner = self.inner.lock();
144        if inner.table_dbs.remove(&id).is_none() {
145            return 0;
146        }
147        1
148    }
149
150    // TableDBTransaction
151    fn add_table_db_transaction(&self, tdbt: TableDBTransaction) -> u32 {
152        let mut inner = self.inner.lock();
153        let mut next_id: u32 = 1;
154        while inner.table_db_transactions.contains_key(&next_id) {
155            next_id += 1;
156        }
157        inner.table_db_transactions.insert(next_id, tdbt);
158        next_id
159    }
160    fn lookup_table_db_transaction(
161        &self,
162        id: u32,
163        tx_id: u32,
164    ) -> Result<TableDBTransaction, Response> {
165        let inner = self.inner.lock();
166        let Some(table_db_transaction) = inner.table_db_transactions.get(&tx_id).cloned() else {
167            return Err(Response {
168                id,
169                op: ResponseOp::TableDbTransaction(TableDbTransactionResponse {
170                    tx_id,
171                    tx_op: TableDbTransactionResponseOp::InvalidId,
172                }),
173            });
174        };
175        Ok(table_db_transaction)
176    }
177    fn release_table_db_transaction(&self, id: u32) -> i32 {
178        let mut inner = self.inner.lock();
179        if inner.table_db_transactions.remove(&id).is_none() {
180            return 0;
181        }
182        1
183    }
184
185    // CryptoSystem
186    fn add_crypto_system(&self, csv: CryptoKind) -> u32 {
187        let mut inner = self.inner.lock();
188        let mut next_id: u32 = 1;
189        while inner.crypto_kinds.contains_key(&next_id) {
190            next_id += 1;
191        }
192        inner.crypto_kinds.insert(next_id, csv);
193        next_id
194    }
195    fn lookup_crypto_system(&self, id: u32, cs_id: u32) -> Result<CryptoKind, Response> {
196        let inner = self.inner.lock();
197        let Some(crypto_kind) = inner.crypto_kinds.get(&cs_id).cloned() else {
198            return Err(Response {
199                id,
200                op: ResponseOp::CryptoSystem(CryptoSystemResponse {
201                    cs_id,
202                    cs_op: CryptoSystemResponseOp::InvalidId,
203                }),
204            });
205        };
206        Ok(crypto_kind)
207    }
208    fn release_crypto_system(&self, id: u32) -> i32 {
209        let mut inner = self.inner.lock();
210        if inner.crypto_kinds.remove(&id).is_none() {
211            return 0;
212        }
213        1
214    }
215
216    // Routing Context
217    fn add_dht_transaction(&self, dht_transaction: DHTTransaction) -> u32 {
218        let mut inner = self.inner.lock();
219        let mut next_id: u32 = 1;
220        while inner.dht_transactions.contains_key(&next_id) {
221            next_id += 1;
222        }
223        inner.dht_transactions.insert(next_id, dht_transaction);
224        next_id
225    }
226    fn lookup_dht_transaction(&self, id: u32, dhttx_id: u32) -> Result<DHTTransaction, Response> {
227        let inner = self.inner.lock();
228        let Some(dht_transaction) = inner.dht_transactions.get(&dhttx_id).cloned() else {
229            return Err(Response {
230                id,
231                op: ResponseOp::DhtTransaction(Box::new(DhtTransactionResponse {
232                    dhttx_id,
233                    dhttx_op: DhtTransactionResponseOp::InvalidId,
234                })),
235            });
236        };
237        Ok(dht_transaction)
238    }
239    fn release_dht_transaction(&self, id: u32) -> i32 {
240        let mut inner = self.inner.lock();
241        if inner.dht_transactions.remove(&id).is_none() {
242            return 0;
243        }
244        1
245    }
246
247    //////////////////////////////////////////////////////////////////////////////////////
248
249    #[instrument(level = "trace", target = "json_api", skip_all)]
250    pub async fn process_routing_context_request(
251        &self,
252        routing_context: RoutingContext,
253        rcr: RoutingContextRequest,
254    ) -> RoutingContextResponse {
255        let rc_op = match rcr.rc_op {
256            RoutingContextRequestOp::Release => {
257                self.release_routing_context(rcr.rc_id);
258                RoutingContextResponseOp::Release {}
259            }
260            RoutingContextRequestOp::WithDefaultSafety => {
261                RoutingContextResponseOp::WithDefaultSafety {
262                    result: to_json_api_result(
263                        routing_context
264                            .clone()
265                            .with_default_safety()
266                            .map(|new_rc| self.add_routing_context(new_rc)),
267                    ),
268                }
269            }
270            RoutingContextRequestOp::WithSafety { safety_selection } => {
271                RoutingContextResponseOp::WithSafety {
272                    result: to_json_api_result(
273                        routing_context
274                            .clone()
275                            .with_safety(safety_selection)
276                            .map(|new_rc| self.add_routing_context(new_rc)),
277                    ),
278                }
279            }
280            RoutingContextRequestOp::WithSequencing { sequencing } => {
281                RoutingContextResponseOp::WithSequencing {
282                    value: self
283                        .add_routing_context(routing_context.clone().with_sequencing(sequencing)),
284                }
285            }
286            RoutingContextRequestOp::Safety => RoutingContextResponseOp::Safety {
287                value: routing_context.safety(),
288            },
289            RoutingContextRequestOp::AppCall { target, message } => {
290                RoutingContextResponseOp::AppCall {
291                    result: to_json_api_result_with_vec_u8(
292                        async { routing_context.app_call(target, message).await }.await,
293                    ),
294                }
295            }
296            RoutingContextRequestOp::AppMessage { target, message } => {
297                RoutingContextResponseOp::AppMessage {
298                    result: to_json_api_result(
299                        async { routing_context.app_message(target, message).await }.await,
300                    ),
301                }
302            }
303            RoutingContextRequestOp::CreateDhtRecord {
304                kind,
305                schema,
306                owner,
307            } => RoutingContextResponseOp::CreateDhtRecord {
308                result: to_json_api_result(
309                    routing_context
310                        .create_dht_record(kind, schema, owner)
311                        .await
312                        .map(Box::new),
313                ),
314            },
315            RoutingContextRequestOp::OpenDhtRecord { key, writer } => {
316                RoutingContextResponseOp::OpenDhtRecord {
317                    result: to_json_api_result(
318                        routing_context
319                            .open_dht_record(key, writer)
320                            .await
321                            .map(Box::new),
322                    ),
323                }
324            }
325            RoutingContextRequestOp::CloseDhtRecord { key } => {
326                RoutingContextResponseOp::CloseDhtRecord {
327                    result: to_json_api_result(routing_context.close_dht_record(key).await),
328                }
329            }
330            RoutingContextRequestOp::DeleteDhtRecord { key } => {
331                RoutingContextResponseOp::DeleteDhtRecord {
332                    result: to_json_api_result(routing_context.delete_dht_record(key).await),
333                }
334            }
335            RoutingContextRequestOp::GetDhtValue {
336                key,
337                subkey,
338                force_refresh,
339            } => RoutingContextResponseOp::GetDhtValue {
340                result: to_json_api_result(
341                    routing_context
342                        .get_dht_value(key, subkey, force_refresh)
343                        .await,
344                ),
345            },
346            RoutingContextRequestOp::SetDhtValue {
347                key,
348                subkey,
349                data,
350                options,
351            } => RoutingContextResponseOp::SetDhtValue {
352                result: to_json_api_result(
353                    routing_context
354                        .set_dht_value(key, subkey, data, options)
355                        .await,
356                ),
357            },
358            RoutingContextRequestOp::WatchDhtValues {
359                key,
360                subkeys,
361                expiration,
362                count,
363            } => RoutingContextResponseOp::WatchDhtValues {
364                result: to_json_api_result(
365                    routing_context
366                        .watch_dht_values(key, subkeys, expiration, count)
367                        .await,
368                ),
369            },
370            RoutingContextRequestOp::CancelDhtWatch { key, subkeys } => {
371                RoutingContextResponseOp::CancelDhtWatch {
372                    result: to_json_api_result(
373                        routing_context.cancel_dht_watch(key, subkeys).await,
374                    ),
375                }
376            }
377            RoutingContextRequestOp::InspectDhtRecord {
378                key,
379                subkeys,
380                scope,
381            } => RoutingContextResponseOp::InspectDhtRecord {
382                result: to_json_api_result(
383                    routing_context
384                        .inspect_dht_record(key, subkeys, scope)
385                        .await
386                        .map(Box::new),
387                ),
388            },
389        };
390        RoutingContextResponse {
391            rc_id: rcr.rc_id,
392            rc_op,
393        }
394    }
395
396    #[instrument(level = "trace", target = "json_api", skip_all)]
397    pub async fn process_table_db_request(
398        &self,
399        table_db: TableDB,
400        tdr: TableDbRequest,
401    ) -> TableDbResponse {
402        let db_op = match tdr.db_op {
403            TableDbRequestOp::Release => {
404                self.release_table_db(tdr.db_id);
405                TableDbResponseOp::Release {}
406            }
407            TableDbRequestOp::GetColumnCount => TableDbResponseOp::GetColumnCount {
408                result: to_json_api_result(table_db.get_column_count()),
409            },
410            TableDbRequestOp::GetKeys { col } => TableDbResponseOp::GetKeys {
411                result: to_json_api_result_with_vec_vec_u8(table_db.get_keys(col).await),
412            },
413            TableDbRequestOp::Transact => TableDbResponseOp::Transact {
414                value: self.add_table_db_transaction(table_db.transact()),
415            },
416            TableDbRequestOp::Store { col, key, value } => TableDbResponseOp::Store {
417                result: to_json_api_result(table_db.store(col, &key, &value).await),
418            },
419            TableDbRequestOp::Load { col, key } => TableDbResponseOp::Load {
420                result: to_json_api_result(
421                    table_db
422                        .load(col, &key)
423                        .await
424                        .map(|vopt| vopt.map(|v| VecU8 { value: v })),
425                ),
426            },
427            TableDbRequestOp::Delete { col, key } => TableDbResponseOp::Delete {
428                result: to_json_api_result(
429                    table_db
430                        .delete(col, &key)
431                        .await
432                        .map(|vopt| vopt.map(|v| VecU8 { value: v })),
433                ),
434            },
435        };
436        TableDbResponse {
437            db_id: tdr.db_id,
438            db_op,
439        }
440    }
441
442    #[instrument(level = "trace", target = "json_api", skip_all)]
443    pub async fn process_table_db_transaction_request(
444        &self,
445        table_db_transaction: TableDBTransaction,
446        tdtr: TableDbTransactionRequest,
447    ) -> TableDbTransactionResponse {
448        let tx_op = match tdtr.tx_op {
449            TableDbTransactionRequestOp::Commit => TableDbTransactionResponseOp::Commit {
450                result: to_json_api_result(table_db_transaction.commit().await.map(|_| {
451                    self.release_table_db_transaction(tdtr.tx_id);
452                })),
453            },
454            TableDbTransactionRequestOp::Rollback => {
455                table_db_transaction.rollback();
456                self.release_table_db_transaction(tdtr.tx_id);
457                TableDbTransactionResponseOp::Rollback {}
458            }
459            TableDbTransactionRequestOp::Store { col, key, value } => {
460                TableDbTransactionResponseOp::Store {
461                    result: to_json_api_result(table_db_transaction.store(col, &key, &value).await),
462                }
463            }
464
465            TableDbTransactionRequestOp::Delete { col, key } => {
466                TableDbTransactionResponseOp::Delete {
467                    result: to_json_api_result(table_db_transaction.delete(col, &key).await),
468                }
469            }
470        };
471        TableDbTransactionResponse {
472            tx_id: tdtr.tx_id,
473            tx_op,
474        }
475    }
476
477    #[instrument(level = "trace", target = "json_api", skip_all)]
478    pub async fn process_crypto_system_request(
479        &self,
480        csv: &CryptoSystemGuard<'_>,
481        csr: CryptoSystemRequest,
482    ) -> CryptoSystemResponse {
483        let cs_op = match csr.cs_op {
484            CryptoSystemRequestOp::Release => {
485                self.release_crypto_system(csr.cs_id);
486                CryptoSystemResponseOp::Release {}
487            }
488            CryptoSystemRequestOp::Kind => CryptoSystemResponseOp::Kind { value: csv.kind() },
489            CryptoSystemRequestOp::CachedDh { key, secret } => CryptoSystemResponseOp::CachedDh {
490                result: to_json_api_result_with_string(csv.cached_dh(&key, &secret)),
491            },
492            CryptoSystemRequestOp::ComputeDh { key, secret } => CryptoSystemResponseOp::ComputeDh {
493                result: to_json_api_result_with_string(csv.compute_dh(&key, &secret)),
494            },
495            CryptoSystemRequestOp::GenerateSharedSecret {
496                key,
497                secret,
498                domain,
499            } => CryptoSystemResponseOp::GenerateSharedSecret {
500                result: to_json_api_result_with_string(
501                    csv.generate_shared_secret(&key, &secret, &domain),
502                ),
503            },
504
505            CryptoSystemRequestOp::RandomBytes { len } => CryptoSystemResponseOp::RandomBytes {
506                value: csv.random_bytes(len as usize),
507            },
508            CryptoSystemRequestOp::SharedSecretLength => {
509                CryptoSystemResponseOp::SharedSecretLength {
510                    value: csv.shared_secret_length() as u32,
511                }
512            }
513            CryptoSystemRequestOp::NonceLength => CryptoSystemResponseOp::NonceLength {
514                value: csv.nonce_length() as u32,
515            },
516            CryptoSystemRequestOp::HashDigestLength => CryptoSystemResponseOp::HashDigestLength {
517                value: csv.hash_digest_length() as u32,
518            },
519            CryptoSystemRequestOp::PublicKeyLength => CryptoSystemResponseOp::PublicKeyLength {
520                value: csv.public_key_length() as u32,
521            },
522            CryptoSystemRequestOp::SecretKeyLength => CryptoSystemResponseOp::SecretKeyLength {
523                value: csv.secret_key_length() as u32,
524            },
525            CryptoSystemRequestOp::SignatureLength => CryptoSystemResponseOp::SignatureLength {
526                value: csv.signature_length() as u32,
527            },
528            CryptoSystemRequestOp::DefaultSaltLength => CryptoSystemResponseOp::DefaultSaltLength {
529                value: csv.default_salt_length() as u32,
530            },
531            CryptoSystemRequestOp::AeadOverhead => CryptoSystemResponseOp::AeadOverhead {
532                value: csv.aead_overhead() as u32,
533            },
534            CryptoSystemRequestOp::CheckSharedSecret { secret } => {
535                CryptoSystemResponseOp::CheckSharedSecret {
536                    result: to_json_api_result(csv.check_shared_secret(&secret)),
537                }
538            }
539            CryptoSystemRequestOp::CheckNonce { nonce } => CryptoSystemResponseOp::CheckNonce {
540                result: to_json_api_result(csv.check_nonce(&nonce)),
541            },
542            CryptoSystemRequestOp::CheckHashDigest { digest } => {
543                CryptoSystemResponseOp::CheckHashDigest {
544                    result: to_json_api_result(csv.check_hash_digest(&digest)),
545                }
546            }
547            CryptoSystemRequestOp::CheckPublicKey { key } => {
548                CryptoSystemResponseOp::CheckPublicKey {
549                    result: to_json_api_result(csv.check_public_key(&key)),
550                }
551            }
552            CryptoSystemRequestOp::CheckSecretKey { key } => {
553                CryptoSystemResponseOp::CheckSecretKey {
554                    result: to_json_api_result(csv.check_secret_key(&key)),
555                }
556            }
557            CryptoSystemRequestOp::CheckSignature { signature } => {
558                CryptoSystemResponseOp::CheckSignature {
559                    result: to_json_api_result(csv.check_signature(&signature)),
560                }
561            }
562            CryptoSystemRequestOp::HashPassword { password, salt } => {
563                CryptoSystemResponseOp::HashPassword {
564                    result: to_json_api_result(csv.hash_password(&password, &salt)),
565                }
566            }
567            CryptoSystemRequestOp::VerifyPassword {
568                password,
569                password_hash,
570            } => CryptoSystemResponseOp::VerifyPassword {
571                result: to_json_api_result(csv.verify_password(&password, &password_hash)),
572            },
573            CryptoSystemRequestOp::DeriveSharedSecret { password, salt } => {
574                CryptoSystemResponseOp::DeriveSharedSecret {
575                    result: to_json_api_result_with_string(
576                        csv.derive_shared_secret(&password, &salt),
577                    ),
578                }
579            }
580            CryptoSystemRequestOp::RandomNonce => CryptoSystemResponseOp::RandomNonce {
581                value: csv.random_nonce(),
582            },
583            CryptoSystemRequestOp::RandomSharedSecret => {
584                CryptoSystemResponseOp::RandomSharedSecret {
585                    value: csv.random_shared_secret(),
586                }
587            }
588            CryptoSystemRequestOp::GenerateKeyPair => CryptoSystemResponseOp::GenerateKeyPair {
589                value: csv.generate_keypair(),
590            },
591            CryptoSystemRequestOp::GenerateHash { data } => CryptoSystemResponseOp::GenerateHash {
592                value: csv.generate_hash(&data),
593            },
594            CryptoSystemRequestOp::ValidateKeyPair { key, secret } => {
595                CryptoSystemResponseOp::ValidateKeyPair {
596                    result: to_json_api_result(csv.validate_keypair(&key, &secret)),
597                }
598            }
599            CryptoSystemRequestOp::ValidateHash { data, hash_digest } => {
600                CryptoSystemResponseOp::ValidateHash {
601                    result: to_json_api_result(csv.validate_hash(&data, &hash_digest)),
602                }
603            }
604            CryptoSystemRequestOp::Sign { key, secret, data } => CryptoSystemResponseOp::Sign {
605                result: to_json_api_result_with_string(csv.sign(&key, &secret, &data)),
606            },
607            CryptoSystemRequestOp::Verify {
608                key,
609                data,
610                signature,
611            } => CryptoSystemResponseOp::Verify {
612                result: to_json_api_result(csv.verify(&key, &data, &signature)),
613            },
614            CryptoSystemRequestOp::DecryptAead {
615                body,
616                nonce,
617                shared_secret,
618                associated_data,
619            } => CryptoSystemResponseOp::DecryptAead {
620                result: to_json_api_result_with_vec_u8(csv.decrypt_aead(
621                    &body,
622                    &nonce,
623                    &shared_secret,
624                    associated_data.as_deref(),
625                )),
626            },
627            CryptoSystemRequestOp::EncryptAead {
628                body,
629                nonce,
630                shared_secret,
631                associated_data,
632            } => CryptoSystemResponseOp::EncryptAead {
633                result: to_json_api_result_with_vec_u8(csv.encrypt_aead(
634                    &body,
635                    &nonce,
636                    &shared_secret,
637                    associated_data.as_deref(),
638                )),
639            },
640            CryptoSystemRequestOp::CryptNoAuth {
641                body,
642                nonce,
643                shared_secret,
644            } => CryptoSystemResponseOp::CryptNoAuth {
645                result: to_json_api_result_with_vec_u8(csv.crypt_no_auth_unaligned(
646                    &body,
647                    &nonce,
648                    &shared_secret,
649                )),
650            },
651        };
652        CryptoSystemResponse {
653            cs_id: csr.cs_id,
654            cs_op,
655        }
656    }
657
658    #[instrument(level = "trace", target = "json_api", skip_all)]
659    pub async fn process_dht_transaction_request(
660        &self,
661        dht_transaction: DHTTransaction,
662        dhttr: DhtTransactionRequest,
663    ) -> DhtTransactionResponse {
664        let dhttx_op = match dhttr.dhttx_op {
665            DhtTransactionRequestOp::Release => {
666                self.release_dht_transaction(dhttr.dhttx_id);
667                DhtTransactionResponseOp::Release {}
668            }
669            DhtTransactionRequestOp::Commit => DhtTransactionResponseOp::Commit {
670                result: to_json_api_result(dht_transaction.commit().await.map(|_| {
671                    self.release_dht_transaction(dhttr.dhttx_id);
672                })),
673            },
674            DhtTransactionRequestOp::Rollback => DhtTransactionResponseOp::Rollback {
675                result: to_json_api_result(dht_transaction.rollback().await.map(|_| {
676                    self.release_dht_transaction(dhttr.dhttx_id);
677                })),
678            },
679            DhtTransactionRequestOp::Get { key, subkey } => DhtTransactionResponseOp::Get {
680                result: to_json_api_result(dht_transaction.get(key, subkey).await),
681            },
682            DhtTransactionRequestOp::Set {
683                key,
684                subkey,
685                data,
686                options,
687            } => DhtTransactionResponseOp::Set {
688                result: to_json_api_result(dht_transaction.set(key, subkey, data, options).await),
689            },
690            DhtTransactionRequestOp::Inspect {
691                key,
692                subkeys,
693                scope,
694            } => DhtTransactionResponseOp::Inspect {
695                result: to_json_api_result(
696                    dht_transaction
697                        .inspect(key, subkeys, scope)
698                        .await
699                        .map(Box::new),
700                ),
701            },
702        };
703        DhtTransactionResponse {
704            dhttx_id: dhttr.dhttx_id,
705            dhttx_op,
706        }
707    }
708
709    #[instrument(level = "trace", target = "json_api", skip_all)]
710    pub async fn process_request(self, request: Request) -> Response {
711        let id = request.id;
712
713        let op = match request.op {
714            RequestOp::Control { args: _args } => ResponseOp::Control {
715                result: to_json_api_result(VeilidAPIResult::Err(VeilidAPIError::unimplemented(
716                    "control should be handled by veilid-core host application",
717                ))),
718            },
719            RequestOp::GetState => ResponseOp::GetState {
720                result: to_json_api_result(self.api.get_state().await.map(Box::new)),
721            },
722            RequestOp::IsShutdown => ResponseOp::IsShutdown {
723                value: self.api.is_shutdown(),
724            },
725            RequestOp::Attach => ResponseOp::Attach {
726                result: to_json_api_result(self.api.attach().await),
727            },
728            RequestOp::Detach => ResponseOp::Detach {
729                result: to_json_api_result(self.api.detach().await),
730            },
731            RequestOp::GenerateMemberId { writer_key } => ResponseOp::GenerateMemberId {
732                result: to_json_api_result_with_string(self.api.generate_member_id(&writer_key)),
733            },
734            RequestOp::GetDhtRecordKey {
735                schema,
736                owner,
737                encryption_key,
738            } => ResponseOp::GetDhtRecordKey {
739                result: to_json_api_result_with_string(
740                    self.api
741                        .get_dht_record_key(schema, owner, encryption_key)
742                        .await,
743                ),
744            },
745            RequestOp::NewPrivateRoute => ResponseOp::NewPrivateRoute {
746                result: to_json_api_result(self.api.new_private_route().await),
747            },
748            RequestOp::NewCustomPrivateRoute { private_spec } => {
749                ResponseOp::NewCustomPrivateRoute {
750                    result: to_json_api_result(
751                        self.api.new_custom_private_route(private_spec).await,
752                    ),
753                }
754            }
755            RequestOp::ImportRemotePrivateRoute { blob } => ResponseOp::ImportRemotePrivateRoute {
756                result: to_json_api_result_with_string(self.api.import_remote_private_route(blob)),
757            },
758            RequestOp::ReleasePrivateRoute { route_id } => ResponseOp::ReleasePrivateRoute {
759                result: to_json_api_result(self.api.release_private_route(route_id)),
760            },
761            RequestOp::AppCallReply { call_id, message } => ResponseOp::AppCallReply {
762                result: to_json_api_result(self.api.app_call_reply(call_id, message).await),
763            },
764            RequestOp::NewRoutingContext => ResponseOp::NewRoutingContext {
765                result: to_json_api_result(
766                    self.api
767                        .routing_context()
768                        .map(|rc| self.add_routing_context(rc)),
769                ),
770            },
771            RequestOp::RoutingContext(rcr) => {
772                let routing_context = match self.lookup_routing_context(id, rcr.rc_id) {
773                    Ok(v) => v,
774                    Err(e) => return e,
775                };
776                ResponseOp::RoutingContext(Box::new(
777                    self.process_routing_context_request(routing_context, rcr)
778                        .await,
779                ))
780            }
781            RequestOp::OpenTableDb { name, column_count } => {
782                let table_store = match self.api.table_store() {
783                    Ok(v) => v,
784                    Err(e) => {
785                        return Response {
786                            id,
787                            op: ResponseOp::OpenTableDb {
788                                result: to_json_api_result(Err(e)),
789                            },
790                        }
791                    }
792                };
793                ResponseOp::OpenTableDb {
794                    result: to_json_api_result(
795                        table_store
796                            .open(&name, column_count)
797                            .await
798                            .map(|table_db| self.add_table_db(table_db)),
799                    ),
800                }
801            }
802            RequestOp::DeleteTableDb { name } => {
803                let table_store = match self.api.table_store() {
804                    Ok(v) => v,
805                    Err(e) => {
806                        return Response {
807                            id,
808                            op: ResponseOp::DeleteTableDb {
809                                result: to_json_api_result(Err(e)),
810                            },
811                        }
812                    }
813                };
814                ResponseOp::DeleteTableDb {
815                    result: to_json_api_result(table_store.delete(&name).await),
816                }
817            }
818            RequestOp::TableDb(tdr) => {
819                let table_db = match self.lookup_table_db(id, tdr.db_id) {
820                    Ok(v) => v,
821                    Err(e) => return e,
822                };
823                ResponseOp::TableDb(self.process_table_db_request(table_db, tdr).await)
824            }
825            RequestOp::TableDbTransaction(tdtr) => {
826                let table_db_transaction = match self.lookup_table_db_transaction(id, tdtr.tx_id) {
827                    Ok(v) => v,
828                    Err(e) => return e,
829                };
830                ResponseOp::TableDbTransaction(
831                    self.process_table_db_transaction_request(table_db_transaction, tdtr)
832                        .await,
833                )
834            }
835            RequestOp::GetCryptoSystem { kind } => {
836                let crypto = match self.api.crypto() {
837                    Ok(v) => v,
838                    Err(e) => {
839                        return Response {
840                            id,
841                            op: ResponseOp::GetCryptoSystem {
842                                result: to_json_api_result(Err(e)),
843                            },
844                        }
845                    }
846                };
847                ResponseOp::GetCryptoSystem {
848                    result: to_json_api_result(
849                        crypto
850                            .get(kind)
851                            .ok_or_else(|| {
852                                VeilidAPIError::invalid_argument(
853                                    "unsupported cryptosystem",
854                                    "kind",
855                                    kind,
856                                )
857                            })
858                            .map(|csv| self.add_crypto_system(csv.kind())),
859                    ),
860                }
861            }
862            RequestOp::CryptoSystem(csr) => {
863                let crypto_kind = match self.lookup_crypto_system(id, csr.cs_id) {
864                    Ok(v) => v,
865                    Err(e) => return e,
866                };
867                let crypto = match self.api.crypto() {
868                    Ok(v) => v,
869                    Err(e) => {
870                        return Response {
871                            id,
872                            op: ResponseOp::GetCryptoSystem {
873                                result: to_json_api_result(Err(e)),
874                            },
875                        }
876                    }
877                };
878                let csv = crypto.get(crypto_kind).unwrap_or_log();
879
880                ResponseOp::CryptoSystem(self.process_crypto_system_request(&csv, csr).await)
881            }
882            RequestOp::VerifySignatures {
883                node_ids,
884                data,
885                signatures,
886            } => {
887                let crypto = match self.api.crypto() {
888                    Ok(v) => v,
889                    Err(e) => {
890                        return Response {
891                            id,
892                            op: ResponseOp::GetCryptoSystem {
893                                result: to_json_api_result(Err(e)),
894                            },
895                        }
896                    }
897                };
898                ResponseOp::VerifySignatures {
899                    result: to_json_api_result_with_opt_vec_string(crypto.verify_signatures(
900                        &node_ids,
901                        &data,
902                        &signatures,
903                    )),
904                }
905            }
906            RequestOp::GenerateSignatures { data, key_pairs } => {
907                let crypto = match self.api.crypto() {
908                    Ok(v) => v,
909                    Err(e) => {
910                        return Response {
911                            id,
912                            op: ResponseOp::GetCryptoSystem {
913                                result: to_json_api_result(Err(e)),
914                            },
915                        }
916                    }
917                };
918                ResponseOp::GenerateSignatures {
919                    result: to_json_api_result_with_vec_string(crypto.generate_signatures(
920                        &data,
921                        &key_pairs,
922                        |_k, s| s,
923                    )),
924                }
925            }
926            RequestOp::GenerateKeyPair { kind } => ResponseOp::GenerateKeyPair {
927                result: to_json_api_result_with_string(Crypto::generate_keypair(kind)),
928            },
929            RequestOp::Now => ResponseOp::Now {
930                value: Timestamp::now(),
931            },
932            RequestOp::Debug { command } => ResponseOp::Debug {
933                result: to_json_api_result(self.api.debug(command).await),
934            },
935            RequestOp::VeilidVersionString => ResponseOp::VeilidVersionString {
936                value: veilid_version_string(),
937            },
938            RequestOp::VeilidVersion => {
939                let (major, minor, patch) = veilid_version();
940
941                ResponseOp::VeilidVersion {
942                    major,
943                    minor,
944                    patch,
945                }
946            }
947            RequestOp::VeilidFeatures => ResponseOp::VeilidFeatures {
948                value: veilid_features(),
949            },
950            RequestOp::DefaultVeilidConfig => ResponseOp::DefaultVeilidConfig {
951                value: default_veilid_config(),
952            },
953            RequestOp::ValidCryptoKinds => ResponseOp::ValidCryptoKinds {
954                value: VALID_CRYPTO_KINDS.to_vec(),
955            },
956            RequestOp::DhtTransaction(dhttx) => {
957                let dht_transaction = match self.lookup_dht_transaction(id, dhttx.dhttx_id) {
958                    Ok(v) => v,
959                    Err(e) => return e,
960                };
961                ResponseOp::DhtTransaction(Box::new(
962                    self.process_dht_transaction_request(dht_transaction, dhttx)
963                        .await,
964                ))
965            }
966            RequestOp::TransactDhtRecords {
967                record_keys,
968                options,
969            } => ResponseOp::TransactDhtRecords {
970                result: to_json_api_result(
971                    self.api
972                        .transact_dht_records(record_keys, options)
973                        .await
974                        .map(|dht_tx| self.add_dht_transaction(dht_tx)),
975                ),
976            },
977        };
978
979        Response { id, op }
980    }
981}