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),
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(self.api.get_dht_record_key(
740                    schema,
741                    owner,
742                    encryption_key,
743                )),
744            },
745            RequestOp::NewPrivateRoute => ResponseOp::NewPrivateRoute {
746                result: to_json_api_result(self.api.new_private_route().await),
747            },
748            RequestOp::NewCustomPrivateRoute {
749                kinds,
750                stability,
751                sequencing,
752            } => ResponseOp::NewCustomPrivateRoute {
753                result: to_json_api_result(
754                    self.api
755                        .new_custom_private_route(&kinds, stability, sequencing)
756                        .await,
757                ),
758            },
759            RequestOp::ImportRemotePrivateRoute { blob } => ResponseOp::ImportRemotePrivateRoute {
760                result: to_json_api_result_with_string(self.api.import_remote_private_route(blob)),
761            },
762            RequestOp::ReleasePrivateRoute { route_id } => ResponseOp::ReleasePrivateRoute {
763                result: to_json_api_result(self.api.release_private_route(route_id)),
764            },
765            RequestOp::AppCallReply { call_id, message } => ResponseOp::AppCallReply {
766                result: to_json_api_result(self.api.app_call_reply(call_id, message).await),
767            },
768            RequestOp::NewRoutingContext => ResponseOp::NewRoutingContext {
769                result: to_json_api_result(
770                    self.api
771                        .routing_context()
772                        .map(|rc| self.add_routing_context(rc)),
773                ),
774            },
775            RequestOp::RoutingContext(rcr) => {
776                let routing_context = match self.lookup_routing_context(id, rcr.rc_id) {
777                    Ok(v) => v,
778                    Err(e) => return e,
779                };
780                ResponseOp::RoutingContext(Box::new(
781                    self.process_routing_context_request(routing_context, rcr)
782                        .await,
783                ))
784            }
785            RequestOp::OpenTableDb { name, column_count } => {
786                let table_store = match self.api.table_store() {
787                    Ok(v) => v,
788                    Err(e) => {
789                        return Response {
790                            id,
791                            op: ResponseOp::OpenTableDb {
792                                result: to_json_api_result(Err(e)),
793                            },
794                        }
795                    }
796                };
797                ResponseOp::OpenTableDb {
798                    result: to_json_api_result(
799                        table_store
800                            .open(&name, column_count)
801                            .await
802                            .map(|table_db| self.add_table_db(table_db)),
803                    ),
804                }
805            }
806            RequestOp::DeleteTableDb { name } => {
807                let table_store = match self.api.table_store() {
808                    Ok(v) => v,
809                    Err(e) => {
810                        return Response {
811                            id,
812                            op: ResponseOp::DeleteTableDb {
813                                result: to_json_api_result(Err(e)),
814                            },
815                        }
816                    }
817                };
818                ResponseOp::DeleteTableDb {
819                    result: to_json_api_result(table_store.delete(&name).await),
820                }
821            }
822            RequestOp::TableDb(tdr) => {
823                let table_db = match self.lookup_table_db(id, tdr.db_id) {
824                    Ok(v) => v,
825                    Err(e) => return e,
826                };
827                ResponseOp::TableDb(self.process_table_db_request(table_db, tdr).await)
828            }
829            RequestOp::TableDbTransaction(tdtr) => {
830                let table_db_transaction = match self.lookup_table_db_transaction(id, tdtr.tx_id) {
831                    Ok(v) => v,
832                    Err(e) => return e,
833                };
834                ResponseOp::TableDbTransaction(
835                    self.process_table_db_transaction_request(table_db_transaction, tdtr)
836                        .await,
837                )
838            }
839            RequestOp::GetCryptoSystem { kind } => {
840                let crypto = match self.api.crypto() {
841                    Ok(v) => v,
842                    Err(e) => {
843                        return Response {
844                            id,
845                            op: ResponseOp::GetCryptoSystem {
846                                result: to_json_api_result(Err(e)),
847                            },
848                        }
849                    }
850                };
851                ResponseOp::GetCryptoSystem {
852                    result: to_json_api_result(
853                        crypto
854                            .get(kind)
855                            .ok_or_else(|| {
856                                VeilidAPIError::invalid_argument(
857                                    "unsupported cryptosystem",
858                                    "kind",
859                                    kind,
860                                )
861                            })
862                            .map(|csv| self.add_crypto_system(csv.kind())),
863                    ),
864                }
865            }
866            RequestOp::CryptoSystem(csr) => {
867                let crypto_kind = match self.lookup_crypto_system(id, csr.cs_id) {
868                    Ok(v) => v,
869                    Err(e) => return e,
870                };
871                let crypto = match self.api.crypto() {
872                    Ok(v) => v,
873                    Err(e) => {
874                        return Response {
875                            id,
876                            op: ResponseOp::GetCryptoSystem {
877                                result: to_json_api_result(Err(e)),
878                            },
879                        }
880                    }
881                };
882                let csv = crypto.get(crypto_kind).unwrap();
883
884                ResponseOp::CryptoSystem(self.process_crypto_system_request(&csv, csr).await)
885            }
886            RequestOp::VerifySignatures {
887                node_ids,
888                data,
889                signatures,
890            } => {
891                let crypto = match self.api.crypto() {
892                    Ok(v) => v,
893                    Err(e) => {
894                        return Response {
895                            id,
896                            op: ResponseOp::GetCryptoSystem {
897                                result: to_json_api_result(Err(e)),
898                            },
899                        }
900                    }
901                };
902                ResponseOp::VerifySignatures {
903                    result: to_json_api_result_with_opt_vec_string(crypto.verify_signatures(
904                        &node_ids,
905                        &data,
906                        &signatures,
907                    )),
908                }
909            }
910            RequestOp::GenerateSignatures { data, key_pairs } => {
911                let crypto = match self.api.crypto() {
912                    Ok(v) => v,
913                    Err(e) => {
914                        return Response {
915                            id,
916                            op: ResponseOp::GetCryptoSystem {
917                                result: to_json_api_result(Err(e)),
918                            },
919                        }
920                    }
921                };
922                ResponseOp::GenerateSignatures {
923                    result: to_json_api_result_with_vec_string(crypto.generate_signatures(
924                        &data,
925                        &key_pairs,
926                        |_k, s| s,
927                    )),
928                }
929            }
930            RequestOp::GenerateKeyPair { kind } => ResponseOp::GenerateKeyPair {
931                result: to_json_api_result_with_string(Crypto::generate_keypair(kind)),
932            },
933            RequestOp::Now => ResponseOp::Now {
934                value: Timestamp::now(),
935            },
936            RequestOp::Debug { command } => ResponseOp::Debug {
937                result: to_json_api_result(self.api.debug(command).await),
938            },
939            RequestOp::VeilidVersionString => ResponseOp::VeilidVersionString {
940                value: veilid_version_string(),
941            },
942            RequestOp::VeilidVersion => {
943                let (major, minor, patch) = veilid_version();
944
945                ResponseOp::VeilidVersion {
946                    major,
947                    minor,
948                    patch,
949                }
950            }
951            RequestOp::VeilidFeatures => ResponseOp::VeilidFeatures {
952                value: veilid_features(),
953            },
954            RequestOp::DefaultVeilidConfig => ResponseOp::DefaultVeilidConfig {
955                value: default_veilid_config(),
956            },
957            RequestOp::ValidCryptoKinds => ResponseOp::ValidCryptoKinds {
958                value: VALID_CRYPTO_KINDS.to_vec(),
959            },
960            RequestOp::DhtTransaction(dhttx) => {
961                let dht_transaction = match self.lookup_dht_transaction(id, dhttx.dhttx_id) {
962                    Ok(v) => v,
963                    Err(e) => return e,
964                };
965                ResponseOp::DhtTransaction(Box::new(
966                    self.process_dht_transaction_request(dht_transaction, dhttx)
967                        .await,
968                ))
969            }
970            RequestOp::TransactDhtRecords {
971                record_keys,
972                options,
973            } => ResponseOp::TransactDhtRecords {
974                result: to_json_api_result(
975                    self.api
976                        .transact_dht_records(record_keys, options)
977                        .await
978                        .map(|dht_tx| self.add_dht_transaction(dht_tx)),
979                ),
980            },
981        };
982
983        Response { id, op }
984    }
985}