+20
-70
Cargo.lock
+20
-70
Cargo.lock
···
204
204
]
205
205
206
206
[[package]]
207
-
name = "async-lock"
208
-
version = "3.4.1"
209
-
source = "registry+https://github.com/rust-lang/crates.io-index"
210
-
checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc"
211
-
dependencies = [
212
-
"event-listener",
213
-
"event-listener-strategy",
214
-
"pin-project-lite",
215
-
]
216
-
217
-
[[package]]
218
207
name = "async-trait"
219
208
version = "0.1.89"
220
209
source = "registry+https://github.com/rust-lang/crates.io-index"
···
795
784
checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb"
796
785
797
786
[[package]]
798
-
name = "concurrent-queue"
799
-
version = "2.5.0"
800
-
source = "registry+https://github.com/rust-lang/crates.io-index"
801
-
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
802
-
dependencies = [
803
-
"crossbeam-utils",
804
-
]
805
-
806
-
[[package]]
807
787
name = "console"
808
788
version = "0.15.11"
809
789
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1328
1308
]
1329
1309
1330
1310
[[package]]
1331
-
name = "event-listener"
1332
-
version = "5.4.1"
1333
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1334
-
checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
1335
-
dependencies = [
1336
-
"concurrent-queue",
1337
-
"parking",
1338
-
"pin-project-lite",
1339
-
]
1340
-
1341
-
[[package]]
1342
-
name = "event-listener-strategy"
1343
-
version = "0.5.4"
1344
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1345
-
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
1346
-
dependencies = [
1347
-
"event-listener",
1348
-
"pin-project-lite",
1349
-
]
1350
-
1351
-
[[package]]
1352
1311
name = "expect-json"
1353
1312
version = "1.5.0"
1354
1313
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2434
2393
"jacquard-common",
2435
2394
"jacquard-lexicon",
2436
2395
"miette",
2437
-
"moka",
2396
+
"mini-moka",
2438
2397
"n0-future",
2439
2398
"percent-encoding",
2440
2399
"reqwest",
···
2942
2901
]
2943
2902
2944
2903
[[package]]
2904
+
name = "mini-moka"
2905
+
version = "0.11.0"
2906
+
source = "git+https://github.com/moka-rs/mini-moka?rev=da864e849f5d034f32e02197fee9bb5d5af36d3d#da864e849f5d034f32e02197fee9bb5d5af36d3d"
2907
+
dependencies = [
2908
+
"crossbeam-channel",
2909
+
"crossbeam-utils",
2910
+
"dashmap",
2911
+
"smallvec",
2912
+
"tagptr",
2913
+
"triomphe",
2914
+
]
2915
+
2916
+
[[package]]
2945
2917
name = "minimal-lexical"
2946
2918
version = "0.2.1"
2947
2919
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2976
2948
"libc",
2977
2949
"wasi",
2978
2950
"windows-sys 0.61.2",
2979
-
]
2980
-
2981
-
[[package]]
2982
-
name = "moka"
2983
-
version = "0.12.11"
2984
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2985
-
checksum = "8261cd88c312e0004c1d51baad2980c66528dfdb2bee62003e643a4d8f86b077"
2986
-
dependencies = [
2987
-
"async-lock",
2988
-
"crossbeam-channel",
2989
-
"crossbeam-epoch",
2990
-
"crossbeam-utils",
2991
-
"equivalent",
2992
-
"event-listener",
2993
-
"futures-util",
2994
-
"parking_lot",
2995
-
"portable-atomic",
2996
-
"rustc_version",
2997
-
"smallvec",
2998
-
"tagptr",
2999
-
"uuid",
3000
2951
]
3001
2952
3002
2953
[[package]]
···
3491
3442
"flate2",
3492
3443
"miniz_oxide 0.8.9",
3493
3444
]
3494
-
3495
-
[[package]]
3496
-
name = "portable-atomic"
3497
-
version = "1.11.1"
3498
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3499
-
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
3500
3445
3501
3446
[[package]]
3502
3447
name = "potential_utf"
···
5239
5184
]
5240
5185
5241
5186
[[package]]
5187
+
name = "triomphe"
5188
+
version = "0.1.15"
5189
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5190
+
checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39"
5191
+
5192
+
[[package]]
5242
5193
name = "try-lock"
5243
5194
version = "0.2.5"
5244
5195
source = "registry+https://github.com/rust-lang/crates.io-index"
···
5411
5362
source = "registry+https://github.com/rust-lang/crates.io-index"
5412
5363
checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
5413
5364
dependencies = [
5414
-
"getrandom 0.3.4",
5415
5365
"js-sys",
5416
5366
"wasm-bindgen",
5417
5367
]
+1
Cargo.toml
+1
Cargo.toml
+2
-2
crates/jacquard-identity/Cargo.toml
+2
-2
crates/jacquard-identity/Cargo.toml
···
16
16
dns = ["dep:hickory-resolver"]
17
17
tracing = ["dep:tracing"]
18
18
streaming = ["jacquard-common/streaming", "dep:n0-future"]
19
-
cache = ["dep:moka"]
19
+
cache = ["dep:mini-moka"]
20
20
21
21
[dependencies]
22
22
trait-variant.workspace = true
···
37
37
urlencoding.workspace = true
38
38
tracing = { workspace = true, optional = true }
39
39
n0-future = { workspace = true, optional = true }
40
+
mini-moka = { git = "https://github.com/moka-rs/mini-moka", rev = "da864e849f5d034f32e02197fee9bb5d5af36d3d", optional = true }
40
41
41
42
[target.'cfg(not(target_family = "wasm"))'.dependencies]
42
-
moka = { workspace = true, features = ["future"], optional = true }
43
43
hickory-resolver = { optional = true, version = "0.24", default-features = false, features = ["system-config", "tokio-runtime"]}
44
44
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
45
45
+8
-7
crates/jacquard-identity/src/lexicon_resolver.rs
+8
-7
crates/jacquard-identity/src/lexicon_resolver.rs
···
246
246
#[cfg(feature = "cache")]
247
247
if let Some(caches) = &self.caches {
248
248
let authority = jacquard_common::smol_str::SmolStr::from(nsid.domain_authority());
249
-
if let Some(did) = caches.authority_to_did.get(&authority).await {
249
+
if let Some(did) = crate::cache_impl::get(&caches.authority_to_did, &authority) {
250
250
return Ok(did);
251
251
}
252
252
}
···
262
262
if let Some(caches) = &self.caches {
263
263
let authority =
264
264
jacquard_common::smol_str::SmolStr::from(nsid.domain_authority());
265
-
caches.authority_to_did.insert(authority, did.clone()).await;
265
+
crate::cache_impl::insert(&caches.authority_to_did, authority, did.clone());
266
266
}
267
267
}
268
268
Err(_) => {
···
298
298
#[cfg(feature = "cache")]
299
299
if let Some(caches) = &self.caches {
300
300
let key = nsid.clone().into_static();
301
-
if let Some(schema) = caches.nsid_to_schema.get(&key).await {
301
+
if let Some(schema) = crate::cache_impl::get(&caches.nsid_to_schema, &key) {
302
302
return Ok((*schema).clone());
303
303
}
304
304
}
···
375
375
// Cache successful resolution
376
376
#[cfg(feature = "cache")]
377
377
if let Some(caches) = &self.caches {
378
-
caches
379
-
.nsid_to_schema
380
-
.insert(nsid.clone().into_static(), std::sync::Arc::new(schema.clone()))
381
-
.await;
378
+
crate::cache_impl::insert(
379
+
&caches.nsid_to_schema,
380
+
nsid.clone().into_static(),
381
+
std::sync::Arc::new(schema.clone()),
382
+
);
382
383
}
383
384
Ok(schema)
384
385
}
+124
-39
crates/jacquard-identity/src/lib.rs
+124
-39
crates/jacquard-identity/src/lib.rs
···
100
100
use {
101
101
crate::lexicon_resolver::ResolvedLexiconSchema,
102
102
jacquard_common::{smol_str::SmolStr, types::string::Nsid},
103
-
moka::future::Cache,
104
103
std::time::Duration,
105
104
};
106
105
···
110
109
))]
111
110
use std::sync::Arc;
112
111
112
+
// Platform-specific cache implementations
113
+
#[cfg(all(feature = "cache", not(target_arch = "wasm32")))]
114
+
mod cache_impl {
115
+
/// Native: Use sync cache (thread-safe, no mutex needed)
116
+
pub type Cache<K, V> = mini_moka::sync::Cache<K, V>;
117
+
118
+
pub fn new_cache<K, V>(max_capacity: u64, ttl: std::time::Duration) -> Cache<K, V>
119
+
where
120
+
K: std::hash::Hash + Eq + Send + Sync + 'static,
121
+
V: Clone + Send + Sync + 'static,
122
+
{
123
+
mini_moka::sync::Cache::builder()
124
+
.max_capacity(max_capacity)
125
+
.time_to_live(ttl)
126
+
.build()
127
+
}
128
+
129
+
pub fn get<K, V>(cache: &Cache<K, V>, key: &K) -> Option<V>
130
+
where
131
+
K: std::hash::Hash + Eq + Send + Sync + 'static,
132
+
V: Clone + Send + Sync + 'static,
133
+
{
134
+
cache.get(key)
135
+
}
136
+
137
+
pub fn insert<K, V>(cache: &Cache<K, V>, key: K, value: V)
138
+
where
139
+
K: std::hash::Hash + Eq + Send + Sync + 'static,
140
+
V: Clone + Send + Sync + 'static,
141
+
{
142
+
cache.insert(key, value);
143
+
}
144
+
145
+
pub fn invalidate<K, V>(cache: &Cache<K, V>, key: &K)
146
+
where
147
+
K: std::hash::Hash + Eq + Send + Sync + 'static,
148
+
V: Clone + Send + Sync + 'static,
149
+
{
150
+
cache.invalidate(key);
151
+
}
152
+
}
153
+
154
+
#[cfg(all(feature = "cache", target_arch = "wasm32"))]
155
+
mod cache_impl {
156
+
use std::sync::{Arc, Mutex};
157
+
158
+
/// WASM: Use unsync cache in Arc<Mutex<_>> (no threads, but need interior mutability)
159
+
pub type Cache<K, V> = Arc<Mutex<mini_moka::unsync::Cache<K, V>>>;
160
+
161
+
pub fn new_cache<K, V>(max_capacity: u64, ttl: std::time::Duration) -> Cache<K, V>
162
+
where
163
+
K: std::hash::Hash + Eq + 'static,
164
+
V: Clone + 'static,
165
+
{
166
+
Arc::new(Mutex::new(
167
+
mini_moka::unsync::Cache::builder()
168
+
.max_capacity(max_capacity)
169
+
.time_to_live(ttl)
170
+
.build(),
171
+
))
172
+
}
173
+
174
+
pub fn get<K, V>(cache: &Cache<K, V>, key: &K) -> Option<V>
175
+
where
176
+
K: std::hash::Hash + Eq + 'static,
177
+
V: Clone + 'static,
178
+
{
179
+
cache.lock().unwrap().get(key).cloned()
180
+
}
181
+
182
+
pub fn insert<K, V>(cache: &Cache<K, V>, key: K, value: V)
183
+
where
184
+
K: std::hash::Hash + Eq + 'static,
185
+
V: Clone + 'static,
186
+
{
187
+
cache.lock().unwrap().insert(key, value);
188
+
}
189
+
190
+
pub fn invalidate<K, V>(cache: &Cache<K, V>, key: &K)
191
+
where
192
+
K: std::hash::Hash + Eq + 'static,
193
+
V: Clone + 'static,
194
+
{
195
+
cache.lock().unwrap().invalidate(key);
196
+
}
197
+
}
198
+
113
199
/// Configuration for resolver caching
114
200
#[cfg(feature = "cache")]
115
201
#[derive(Clone, Debug)]
···
194
280
#[cfg(feature = "cache")]
195
281
#[derive(Clone)]
196
282
pub struct ResolverCaches {
197
-
pub handle_to_did: Cache<Handle<'static>, Did<'static>>,
198
-
pub did_to_doc: Cache<Did<'static>, Arc<DidDocResponse>>,
199
-
pub authority_to_did: Cache<SmolStr, Did<'static>>,
200
-
pub nsid_to_schema: Cache<Nsid<'static>, Arc<ResolvedLexiconSchema<'static>>>,
283
+
pub handle_to_did: cache_impl::Cache<Handle<'static>, Did<'static>>,
284
+
pub did_to_doc: cache_impl::Cache<Did<'static>, Arc<DidDocResponse>>,
285
+
pub authority_to_did: cache_impl::Cache<SmolStr, Did<'static>>,
286
+
pub nsid_to_schema: cache_impl::Cache<Nsid<'static>, Arc<ResolvedLexiconSchema<'static>>>,
201
287
}
202
288
203
289
#[cfg(feature = "cache")]
204
290
impl ResolverCaches {
205
291
pub fn new(config: &CacheConfig) -> Self {
206
292
Self {
207
-
handle_to_did: Cache::builder()
208
-
.max_capacity(config.handle_to_did_capacity)
209
-
.time_to_live(config.handle_to_did_ttl)
210
-
.build(),
211
-
did_to_doc: Cache::builder()
212
-
.max_capacity(config.did_to_doc_capacity)
213
-
.time_to_live(config.did_to_doc_ttl)
214
-
.build(),
215
-
authority_to_did: Cache::builder()
216
-
.max_capacity(config.authority_to_did_capacity)
217
-
.time_to_live(config.authority_to_did_ttl)
218
-
.build(),
219
-
nsid_to_schema: Cache::builder()
220
-
.max_capacity(config.nsid_to_schema_capacity)
221
-
.time_to_live(config.nsid_to_schema_ttl)
222
-
.build(),
293
+
handle_to_did: cache_impl::new_cache(
294
+
config.handle_to_did_capacity,
295
+
config.handle_to_did_ttl,
296
+
),
297
+
did_to_doc: cache_impl::new_cache(config.did_to_doc_capacity, config.did_to_doc_ttl),
298
+
authority_to_did: cache_impl::new_cache(
299
+
config.authority_to_did_capacity,
300
+
config.authority_to_did_ttl,
301
+
),
302
+
nsid_to_schema: cache_impl::new_cache(
303
+
config.nsid_to_schema_capacity,
304
+
config.nsid_to_schema_ttl,
305
+
),
223
306
}
224
307
}
225
308
}
···
498
581
#[cfg(feature = "cache")]
499
582
if let Some(caches) = &self.caches {
500
583
let key = handle.clone().into_static();
501
-
if let Some(did) = caches.handle_to_did.get(&key).await {
584
+
if let Some(did) = cache_impl::get(&caches.handle_to_did, &key) {
502
585
return Ok(did);
503
586
}
504
587
}
···
600
683
// Cache successful resolution
601
684
#[cfg(feature = "cache")]
602
685
if let Some(caches) = &self.caches {
603
-
caches
604
-
.handle_to_did
605
-
.insert(handle.clone().into_static(), did.clone())
606
-
.await;
686
+
cache_impl::insert(
687
+
&caches.handle_to_did,
688
+
handle.clone().into_static(),
689
+
did.clone(),
690
+
);
607
691
}
608
692
Ok(did)
609
693
} else {
···
620
704
#[cfg(feature = "cache")]
621
705
if let Some(caches) = &self.caches {
622
706
let key = did.clone().into_static();
623
-
if let Some(doc_resp) = caches.did_to_doc.get(&key).await {
707
+
if let Some(doc_resp) = cache_impl::get(&caches.did_to_doc, &key) {
624
708
return Ok((*doc_resp).clone());
625
709
}
626
710
}
···
690
774
// Cache successful resolution
691
775
#[cfg(feature = "cache")]
692
776
if let Some(caches) = &self.caches {
693
-
caches
694
-
.did_to_doc
695
-
.insert(did.clone().into_static(), Arc::new(doc_resp.clone()))
696
-
.await;
777
+
cache_impl::insert(
778
+
&caches.did_to_doc,
779
+
did.clone().into_static(),
780
+
Arc::new(doc_resp.clone()),
781
+
);
697
782
}
698
783
Ok(doc_resp)
699
784
} else {
···
813
898
async fn invalidate_handle_chain(&self, handle: &Handle<'_>) {
814
899
if let Some(caches) = &self.caches {
815
900
let key = handle.clone().into_static();
816
-
caches.handle_to_did.invalidate(&key).await;
901
+
cache_impl::invalidate(&caches.handle_to_did, &key);
817
902
}
818
903
}
819
904
···
822
907
if let Some(caches) = &self.caches {
823
908
let did_key = did.clone().into_static();
824
909
// Get doc before evicting to extract handles
825
-
if let Some(doc_resp) = caches.did_to_doc.get(&did_key).await {
910
+
if let Some(doc_resp) = cache_impl::get(&caches.did_to_doc, &did_key) {
826
911
let doc_resp_clone = (*doc_resp).clone();
827
912
if let Ok(doc) = doc_resp_clone.parse() {
828
913
if let Some(aliases) = &doc.also_known_as {
···
830
915
if let Some(handle_str) = alias.as_ref().strip_prefix("at://") {
831
916
if let Ok(handle) = Handle::new(handle_str) {
832
917
let handle_key = handle.into_static();
833
-
caches.handle_to_did.invalidate(&handle_key).await;
918
+
cache_impl::invalidate(&caches.handle_to_did, &handle_key);
834
919
}
835
920
}
836
921
}
837
922
}
838
923
}
839
924
}
840
-
caches.did_to_doc.invalidate(&did_key).await;
925
+
cache_impl::invalidate(&caches.did_to_doc, &did_key);
841
926
}
842
927
}
843
928
···
845
930
async fn invalidate_authority_chain(&self, authority: &str) {
846
931
if let Some(caches) = &self.caches {
847
932
let authority = SmolStr::from(authority);
848
-
caches.authority_to_did.invalidate(&authority).await;
933
+
cache_impl::invalidate(&caches.authority_to_did, &authority);
849
934
}
850
935
}
851
936
···
853
938
async fn invalidate_lexicon_chain(&self, nsid: &jacquard_common::types::string::Nsid<'_>) {
854
939
if let Some(caches) = &self.caches {
855
940
let nsid_key = nsid.clone().into_static();
856
-
if let Some(schema) = caches.nsid_to_schema.get(&nsid_key).await {
941
+
if let Some(schema) = cache_impl::get(&caches.nsid_to_schema, &nsid_key) {
857
942
let authority = SmolStr::from(nsid.domain_authority());
858
-
caches.authority_to_did.invalidate(&authority).await;
943
+
cache_impl::invalidate(&caches.authority_to_did, &authority);
859
944
self.invalidate_did_chain(&schema.repo).await;
860
945
}
861
-
caches.nsid_to_schema.invalidate(&nsid_key).await;
946
+
cache_impl::invalidate(&caches.nsid_to_schema, &nsid_key);
862
947
}
863
948
}
864
949