tangled
alpha
login
or
join now
microcosm.blue
/
microcosm-rs
65
fork
atom
Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm
65
fork
atom
overview
issues
8
pulls
2
pipelines
fmt
bad-example.com
1 month ago
02dff51f
741ef2f0
+233
-123
3 changed files
expand all
collapse all
unified
split
slingshot
src
identity.rs
proxy.rs
server.rs
+24
-14
slingshot/src/identity.rs
···
61
61
#[derive(Debug, Serialize, Deserialize)]
62
62
enum IdentityData {
63
63
NotFound,
64
64
-
Did(Did), // from handle
65
65
-
Doc(PartialMiniDoc), // from did
64
64
+
Did(Did), // from handle
65
65
+
Doc(PartialMiniDoc), // from did
66
66
ServiceDoc(MiniServiceDoc), // from service did
67
67
}
68
68
···
86
86
s += std::mem::size_of_val(&sv.endpoint);
87
87
}
88
88
s
89
89
-
},
89
89
+
}
90
90
};
91
91
wrapping + inner
92
92
}
···
189
189
190
190
impl MiniServiceDoc {
191
191
pub fn get(&self, id_fragment: &str, service_type: Option<&str>) -> Option<&MiniService> {
192
192
-
self.services
193
193
-
.iter()
194
194
-
.find(|MiniService { full_id, r#type, .. }|
195
195
-
full_id.ends_with(id_fragment)
196
196
-
&& service_type
197
197
-
.map(|t| t == *r#type)
198
198
-
.unwrap_or(true))
192
192
+
self.services.iter().find(|ms| {
193
193
+
ms.full_id.ends_with(id_fragment)
194
194
+
&& service_type.map(|t| t == ms.r#type).unwrap_or(true)
195
195
+
})
199
196
}
200
197
}
201
198
···
217
214
let mut services = Vec::new();
218
215
let mut seen = HashSet::new();
219
216
220
220
-
for DidDocServic { id, r#type, service_endpoint } in did_doc.service.unwrap_or(vec![]) {
217
217
+
for DidDocServic {
218
218
+
id,
219
219
+
r#type,
220
220
+
service_endpoint,
221
221
+
} in did_doc.service.unwrap_or(vec![])
222
222
+
{
221
223
let Some((_, id_fragment)) = id.rsplit_once('#') else {
222
224
continue;
223
225
};
···
474
476
),
475
477
Ok(did_doc) => match did_doc.try_into() {
476
478
Ok(mini_service_doc) => (
477
477
-
Ok(IdentityVal(UtcDateTime::now(), IdentityData::ServiceDoc(mini_service_doc))),
479
479
+
Ok(IdentityVal(
480
480
+
UtcDateTime::now(),
481
481
+
IdentityData::ServiceDoc(mini_service_doc),
482
482
+
)),
478
483
"true",
479
484
),
480
485
Err(e) => (Err(IdentityError::BadDidDoc(e)), "false"),
···
510
515
Ok(Some(mini_service_doc.clone()))
511
516
}
512
517
_ => {
513
513
-
log::error!("identity value mixup: got a doc from a different key type (should be a service did)");
518
518
+
log::error!(
519
519
+
"identity value mixup: got a doc from a different key type (should be a service did)"
520
520
+
);
514
521
Err(IdentityError::IdentityValTypeMixup(did.to_string()))
515
522
}
516
523
}
···
715
722
.increment(1);
716
723
self.cache.insert(
717
724
task_key.clone(),
718
718
-
IdentityVal(UtcDateTime::now(), IdentityData::ServiceDoc(mini_service_doc)),
725
725
+
IdentityVal(
726
726
+
UtcDateTime::now(),
727
727
+
IdentityData::ServiceDoc(mini_service_doc),
728
728
+
),
719
729
);
720
730
}
721
731
Err(atrium_identity::Error::NotFound) => {
+119
-56
slingshot/src/proxy.rs
···
1
1
+
use crate::{Identity, Repo, error::ProxyError, server::HydrationSource};
1
2
use atrium_api::types::string::{Did, Nsid};
2
2
-
use url::Url;
3
3
-
use std::{collections::HashMap, time::Duration};
4
4
-
use crate::{Repo, Identity, server::HydrationSource, error::ProxyError};
5
3
use reqwest::Client;
6
4
use serde_json::{Map, Value};
5
5
+
use std::{collections::HashMap, time::Duration};
6
6
+
use url::Url;
7
7
8
8
pub enum ParamValue {
9
9
String(Vec<String>),
···
13
13
pub struct Params(HashMap<String, ParamValue>);
14
14
15
15
impl TryFrom<Map<String, Value>> for Params {
16
16
-
type Error = (); // TODO
16
16
+
type Error = (); // TODO
17
17
fn try_from(val: Map<String, Value>) -> Result<Self, Self::Error> {
18
18
let mut out = HashMap::new();
19
19
for (k, v) in val {
···
86
86
.timeout(Duration::from_secs(6))
87
87
.build()
88
88
.unwrap();
89
89
-
Self { repo, client, identity }
89
89
+
Self {
90
90
+
repo,
91
91
+
client,
92
92
+
identity,
93
93
+
}
90
94
}
91
95
92
96
pub async fn proxy(
···
96
100
xrpc: &Nsid,
97
101
params: Option<Map<String, Value>>,
98
102
) -> Result<Value, ProxyError> {
99
99
-
100
103
let mut upstream: Url = self
101
104
.identity
102
105
.did_to_mini_service_doc(service_did)
···
134
137
}
135
138
136
139
// TODO: other headers to proxy
137
137
-
Ok(self.client
140
140
+
Ok(self
141
141
+
.client
138
142
.get(upstream)
139
143
.send()
140
144
.await?
···
160
164
while let Some((i, c)) = chars.next() {
161
165
match c {
162
166
'[' if in_bracket => return Err(format!("nested opening bracket not allowed, at {i}")),
163
163
-
'[' if key_acc.is_empty() => return Err(format!("missing key before opening bracket, at {i}")),
167
167
+
'[' if key_acc.is_empty() => {
168
168
+
return Err(format!("missing key before opening bracket, at {i}"));
169
169
+
}
164
170
'[' => in_bracket = true,
165
171
']' if in_bracket => {
166
172
in_bracket = false;
167
173
let key = std::mem::take(&mut key_acc);
168
174
let r#type = std::mem::take(&mut type_acc);
169
169
-
let t = if r#type.is_empty() { None } else { Some(r#type) };
175
175
+
let t = if r#type.is_empty() {
176
176
+
None
177
177
+
} else {
178
178
+
Some(r#type)
179
179
+
};
170
180
out.push(PathPart::Vector(key, t));
171
181
// peek ahead because we need a dot after array if there's more and i don't want to add more loop state
172
182
let Some((i, c)) = chars.next() else {
173
183
break;
174
184
};
175
185
if c != '.' {
176
176
-
return Err(format!("expected dot after close bracket, found {c:?} at {i}"));
186
186
+
return Err(format!(
187
187
+
"expected dot after close bracket, found {c:?} at {i}"
188
188
+
));
177
189
}
178
190
}
179
191
']' => return Err(format!("unexpected close bracket at {i}")),
180
192
'.' if in_bracket => type_acc.push(c),
181
181
-
'.' if key_acc.is_empty() => return Err(format!("missing key before next segment, at {i}")),
193
193
+
'.' if key_acc.is_empty() => {
194
194
+
return Err(format!("missing key before next segment, at {i}"));
195
195
+
}
182
196
'.' => {
183
197
let key = std::mem::take(&mut key_acc);
184
198
assert!(type_acc.is_empty());
···
224
238
225
239
#[derive(Debug, PartialEq)]
226
240
pub enum MatchedRef {
227
227
-
AtUri {
228
228
-
uri: String,
229
229
-
cid: Option<String>,
230
230
-
},
241
241
+
AtUri { uri: String, cid: Option<String> },
231
242
Identifier(String),
232
243
}
233
244
···
241
252
let o = val.as_object()?;
242
253
let uri = o.get("uri")?.as_str()?.to_string();
243
254
let cid = o.get("cid")?.as_str()?.to_string();
244
244
-
Some(MatchedRef::AtUri { uri, cid: Some(cid) })
255
255
+
Some(MatchedRef::AtUri {
256
256
+
uri,
257
257
+
cid: Some(cid),
258
258
+
})
245
259
}
246
260
RefShape::AtUri => {
247
261
let uri = val.as_str()?.to_string();
···
270
284
}
271
285
Some(MatchedRef::Identifier(id.to_string()))
272
286
}
273
273
-
RefShape::AtIdentifier => {
274
274
-
Some(MatchedRef::Identifier(val.as_str()?.to_string()))
275
275
-
}
287
287
+
RefShape::AtIdentifier => Some(MatchedRef::Identifier(val.as_str()?.to_string())),
276
288
}
277
289
}
278
290
···
311
323
}
312
324
impl<'a> PathWalker<'a> {
313
325
fn new(path_parts: &'a [PathPart], skeleton: &'a Value) -> Self {
314
314
-
Self { todo: vec![(path_parts, skeleton)] }
326
326
+
Self {
327
327
+
todo: vec![(path_parts, skeleton)],
328
328
+
}
315
329
}
316
330
}
317
331
impl<'a> Iterator for PathWalker<'a> {
···
336
350
let Some(a) = o.get(k).and_then(|v| v.as_array()) else {
337
351
continue;
338
352
};
339
339
-
for v in a
340
340
-
.iter()
341
341
-
.rev()
342
342
-
.filter(|c| {
343
343
-
let Some(t) = t else { return true };
344
344
-
c
345
345
-
.as_object()
346
346
-
.and_then(|o| o.get("$type"))
347
347
-
.and_then(|v| v.as_str())
348
348
-
.map(|s| s == t)
349
349
-
.unwrap_or(false)
350
350
-
})
351
351
-
{
353
353
+
for v in a.iter().rev().filter(|c| {
354
354
+
let Some(t) = t else { return true };
355
355
+
c.as_object()
356
356
+
.and_then(|o| o.get("$type"))
357
357
+
.and_then(|v| v.as_str())
358
358
+
.map(|s| s == t)
359
359
+
.unwrap_or(false)
360
360
+
}) {
352
361
self.todo.push((rest, v))
353
362
}
354
363
}
···
356
365
}
357
366
}
358
367
}
359
359
-
360
368
361
369
#[cfg(test)]
362
370
mod tests {
···
369
377
("", vec![]),
370
378
("subject", vec![PathPart::Scalar("subject".into())]),
371
379
("authorDid", vec![PathPart::Scalar("authorDid".into())]),
372
372
-
("subject.uri", vec![PathPart::Scalar("subject".into()), PathPart::Scalar("uri".into())]),
380
380
+
(
381
381
+
"subject.uri",
382
382
+
vec![
383
383
+
PathPart::Scalar("subject".into()),
384
384
+
PathPart::Scalar("uri".into()),
385
385
+
],
386
386
+
),
373
387
("members[]", vec![PathPart::Vector("members".into(), None)]),
374
374
-
("add[].key", vec![
375
375
-
PathPart::Vector("add".into(), None),
376
376
-
PathPart::Scalar("key".into()),
377
377
-
]),
388
388
+
(
389
389
+
"add[].key",
390
390
+
vec![
391
391
+
PathPart::Vector("add".into(), None),
392
392
+
PathPart::Scalar("key".into()),
393
393
+
],
394
394
+
),
378
395
("a[b]", vec![PathPart::Vector("a".into(), Some("b".into()))]),
379
379
-
("a[b.c]", vec![PathPart::Vector("a".into(), Some("b.c".into()))]),
380
380
-
("facets[app.bsky.richtext.facet].features[app.bsky.richtext.facet#mention].did", vec![
381
381
-
PathPart::Vector("facets".into(), Some("app.bsky.richtext.facet".into())),
382
382
-
PathPart::Vector("features".into(), Some("app.bsky.richtext.facet#mention".into())),
383
383
-
PathPart::Scalar("did".into()),
384
384
-
]),
396
396
+
(
397
397
+
"a[b.c]",
398
398
+
vec![PathPart::Vector("a".into(), Some("b.c".into()))],
399
399
+
),
400
400
+
(
401
401
+
"facets[app.bsky.richtext.facet].features[app.bsky.richtext.facet#mention].did",
402
402
+
vec![
403
403
+
PathPart::Vector("facets".into(), Some("app.bsky.richtext.facet".into())),
404
404
+
PathPart::Vector(
405
405
+
"features".into(),
406
406
+
Some("app.bsky.richtext.facet#mention".into()),
407
407
+
),
408
408
+
PathPart::Scalar("did".into()),
409
409
+
],
410
410
+
),
385
411
];
386
412
387
413
for (path, expected) in cases {
···
402
428
(
403
429
"strong-ref",
404
430
json!({ "uri": "abc", "cid": "def" }),
405
405
-
Some(MatchedRef::AtUri { uri: "abc".to_string(), cid: Some("def".to_string()) }),
431
431
+
Some(MatchedRef::AtUri {
432
432
+
uri: "abc".to_string(),
433
433
+
cid: Some("def".to_string()),
434
434
+
}),
406
435
),
407
436
("at-uri", json!({ "uri": "abc" }), None),
408
437
("at-uri", json!({ "uri": "abc", "cid": "def" }), None),
409
438
(
410
439
"at-uri",
411
440
json!("abc"),
412
412
-
Some(MatchedRef::AtUri { uri: "abc".to_string(), cid: None }),
441
441
+
Some(MatchedRef::AtUri {
442
442
+
uri: "abc".to_string(),
443
443
+
cid: None,
444
444
+
}),
413
445
),
414
446
("at-uri-parts", json!("abc"), None),
415
447
("at-uri-parts", json!({}), None),
416
448
(
417
449
"at-uri-parts",
418
450
json!({"repo": "a", "collection": "b", "rkey": "c"}),
419
419
-
Some(MatchedRef::AtUri { uri: "at://a/b/c".to_string(), cid: None }),
451
451
+
Some(MatchedRef::AtUri {
452
452
+
uri: "at://a/b/c".to_string(),
453
453
+
cid: None,
454
454
+
}),
420
455
),
421
456
(
422
457
"at-uri-parts",
423
458
json!({"did": "a", "collection": "b", "rkey": "c"}),
424
424
-
Some(MatchedRef::AtUri { uri: "at://a/b/c".to_string(), cid: None }),
459
459
+
Some(MatchedRef::AtUri {
460
460
+
uri: "at://a/b/c".to_string(),
461
461
+
cid: None,
462
462
+
}),
425
463
),
426
464
(
427
465
"at-uri-parts",
428
466
// 'repo' takes precedence over 'did'
429
467
json!({"did": "a", "repo": "z", "collection": "b", "rkey": "c"}),
430
430
-
Some(MatchedRef::AtUri { uri: "at://z/b/c".to_string(), cid: None }),
468
468
+
Some(MatchedRef::AtUri {
469
469
+
uri: "at://z/b/c".to_string(),
470
470
+
cid: None,
471
471
+
}),
431
472
),
432
473
(
433
474
"at-uri-parts",
434
475
json!({"repo": "a", "collection": "b", "rkey": "c", "cid": "def"}),
435
435
-
Some(MatchedRef::AtUri { uri: "at://a/b/c".to_string(), cid: Some("def".to_string()) }),
476
476
+
Some(MatchedRef::AtUri {
477
477
+
uri: "at://a/b/c".to_string(),
478
478
+
cid: Some("def".to_string()),
479
479
+
}),
436
480
),
437
481
(
438
482
"at-uri-parts",
439
483
json!({"repo": "a", "collection": "b", "rkey": "c", "cid": {}}),
440
440
-
Some(MatchedRef::AtUri { uri: "at://a/b/c".to_string(), cid: None }),
484
484
+
Some(MatchedRef::AtUri {
485
485
+
uri: "at://a/b/c".to_string(),
486
486
+
cid: None,
487
487
+
}),
441
488
),
442
489
("did", json!({}), None),
443
490
("did", json!(""), None),
444
491
("did", json!("bad-example.com"), None),
445
445
-
("did", json!("did:plc:xyz"), Some(MatchedRef::Identifier("did:plc:xyz".to_string()))),
492
492
+
(
493
493
+
"did",
494
494
+
json!("did:plc:xyz"),
495
495
+
Some(MatchedRef::Identifier("did:plc:xyz".to_string())),
496
496
+
),
446
497
("handle", json!({}), None),
447
447
-
("handle", json!("bad-example.com"), Some(MatchedRef::Identifier("bad-example.com".to_string()))),
498
498
+
(
499
499
+
"handle",
500
500
+
json!("bad-example.com"),
501
501
+
Some(MatchedRef::Identifier("bad-example.com".to_string())),
502
502
+
),
448
503
("handle", json!("did:plc:xyz"), None),
449
504
("at-identifier", json!({}), None),
450
450
-
("at-identifier", json!("bad-example.com"), Some(MatchedRef::Identifier("bad-example.com".to_string()))),
451
451
-
("at-identifier", json!("did:plc:xyz"), Some(MatchedRef::Identifier("did:plc:xyz".to_string()))),
505
505
+
(
506
506
+
"at-identifier",
507
507
+
json!("bad-example.com"),
508
508
+
Some(MatchedRef::Identifier("bad-example.com".to_string())),
509
509
+
),
510
510
+
(
511
511
+
"at-identifier",
512
512
+
json!("did:plc:xyz"),
513
513
+
Some(MatchedRef::Identifier("did:plc:xyz".to_string())),
514
514
+
),
452
515
];
453
516
for (shape, val, expected) in cases {
454
517
let s = shape.try_into().unwrap();
+90
-53
slingshot/src/server.rs
···
1
1
use crate::{
2
2
CachedRecord, ErrorResponseObject, Identity, Proxy, Repo,
3
3
error::{RecordError, ServerError},
4
4
-
proxy::{extract_links, MatchedRef},
4
4
+
proxy::{MatchedRef, extract_links},
5
5
record::RawRecord,
6
6
};
7
7
use atrium_api::types::string::{Cid, Did, Handle, Nsid, RecordKey};
8
8
use foyer::HybridCache;
9
9
use links::at_uri::parse_at_uri as normalize_at_uri;
10
10
use serde::Serialize;
11
11
-
use std::{path::PathBuf, str::FromStr, sync::Arc, time::Instant, collections::HashMap};
11
11
+
use std::{collections::HashMap, path::PathBuf, str::FromStr, sync::Arc, time::Instant};
12
12
use tokio::sync::mpsc;
13
13
use tokio_util::sync::CancellationToken;
14
14
···
24
24
};
25
25
use poem_openapi::{
26
26
ApiResponse, ContactObject, ExternalDocumentObject, Object, OpenApi, OpenApiService, Tags,
27
27
-
Union,
28
28
-
param::Query, payload::Json, types::Example,
27
27
+
Union, param::Query, payload::Json, types::Example,
29
28
};
30
29
31
30
fn example_handle() -> String {
···
233
232
Ok(Json<ServiceResponseObject>),
234
233
/// Bad request or service not resolved
235
234
#[oai(status = 400)]
236
236
-
BadRequest(XrpcError)
235
235
+
BadRequest(XrpcError),
237
236
}
238
237
239
238
#[derive(Object)]
···
257
256
}
258
257
259
258
// todo: there's gotta be a supertrait that collects these?
260
260
-
use poem_openapi::types::{Type, ToJSON, ParseFromJSON, IsObjectType};
259
259
+
use poem_openapi::types::{IsObjectType, ParseFromJSON, ToJSON, Type};
261
260
262
261
#[derive(Union)]
263
262
#[oai(discriminator_name = "status", rename_all = "camelCase")]
···
281
280
fn example() -> Self {
282
281
Self {
283
282
output: serde_json::json!({}),
284
284
-
records: HashMap::from([
285
285
-
("asdf".into(), Hydration::Pending(ProxyHydrationPending { url: "todo".into() })),
286
286
-
]),
283
283
+
records: HashMap::from([(
284
284
+
"asdf".into(),
285
285
+
Hydration::Pending(ProxyHydrationPending { url: "todo".into() }),
286
286
+
)]),
287
287
identifiers: HashMap::new(),
288
288
}
289
289
}
···
295
295
#[oai(status = 200)]
296
296
Ok(Json<ProxyHydrateResponseObject>),
297
297
#[oai(status = 400)]
298
298
-
BadRequest(XrpcError)
298
298
+
BadRequest(XrpcError),
299
299
}
300
300
301
301
#[derive(Object)]
···
329
329
/// Paths within the response to look for at-uris that can be hydrated
330
330
hydration_sources: Vec<HydrationSource>,
331
331
// todo: deadline thing
332
332
-
333
332
}
334
333
impl Example for ProxyQueryPayload {
335
334
fn example() -> Self {
···
339
338
params: Some(serde_json::json!({
340
339
"feed": "at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.generator/atproto",
341
340
})),
342
342
-
hydration_sources: vec![
343
343
-
HydrationSource {
344
344
-
path: "feed[].post".to_string(),
345
345
-
shape: "at-uri".to_string(),
346
346
-
}
347
347
-
],
341
341
+
hydration_sources: vec![HydrationSource {
342
342
+
path: "feed[].post".to_string(),
343
343
+
shape: "at-uri".to_string(),
344
344
+
}],
348
345
}
349
346
}
350
347
}
···
741
738
Query(r#type): Query<Option<String>>,
742
739
) -> ResolveServiceResponse {
743
740
let Ok(did) = Did::new(did) else {
744
744
-
return ResolveServiceResponse::BadRequest(xrpc_error("InvalidRequest", "could not parse 'did' into a DID"));
741
741
+
return ResolveServiceResponse::BadRequest(xrpc_error(
742
742
+
"InvalidRequest",
743
743
+
"could not parse 'did' into a DID",
744
744
+
));
745
745
};
746
746
let identity = self.identity.clone();
747
747
Self::resolve_service_impl(&did, &id, r#type.as_deref(), identity).await
···
751
751
did: &Did,
752
752
id_fragment: &str,
753
753
service_type: Option<&str>,
754
754
-
identity: Identity
754
754
+
identity: Identity,
755
755
) -> ResolveServiceResponse {
756
756
let invalid = |reason: &'static str| {
757
757
ResolveServiceResponse::BadRequest(xrpc_error("InvalidRequest", reason))
758
758
};
759
759
-
let Ok(service_mini_doc) = identity.did_to_mini_service_doc(&did).await else {
759
759
+
let Ok(service_mini_doc) = identity.did_to_mini_service_doc(did).await else {
760
760
return invalid("Failed to get DID doc");
761
761
};
762
762
let Some(service_mini_doc) = service_mini_doc else {
···
795
795
panic!("params have to be an object");
796
796
};
797
797
Some(map)
798
798
-
} else { None };
798
798
+
} else {
799
799
+
None
800
800
+
};
799
801
800
802
let Some((service_did, id_fragment)) = payload.atproto_proxy.rsplit_once("#") else {
801
801
-
return ProxyHydrateResponse::BadRequest(xrpc_error("BadParameter", "atproto_proxy could not be understood"));
803
803
+
return ProxyHydrateResponse::BadRequest(xrpc_error(
804
804
+
"BadParameter",
805
805
+
"atproto_proxy could not be understood",
806
806
+
));
802
807
};
803
808
804
809
let Ok(service_did) = service_did.parse() else {
805
805
-
return ProxyHydrateResponse::BadRequest(xrpc_error("BadParameter", "atproto_proxy service did could not be parsed"));
810
810
+
return ProxyHydrateResponse::BadRequest(xrpc_error(
811
811
+
"BadParameter",
812
812
+
"atproto_proxy service did could not be parsed",
813
813
+
));
806
814
};
807
815
808
816
let Ok(xrpc) = payload.xrpc.parse() else {
809
809
-
return ProxyHydrateResponse::BadRequest(xrpc_error("BadParameter", "invalid NSID for xrpc param"));
817
817
+
return ProxyHydrateResponse::BadRequest(xrpc_error(
818
818
+
"BadParameter",
819
819
+
"invalid NSID for xrpc param",
820
820
+
));
810
821
};
811
822
812
812
-
match self.proxy.proxy(
813
813
-
&service_did,
814
814
-
&format!("#{id_fragment}"),
815
815
-
&xrpc,
816
816
-
params,
817
817
-
).await {
823
823
+
match self
824
824
+
.proxy
825
825
+
.proxy(&service_did, &format!("#{id_fragment}"), &xrpc, params)
826
826
+
.await
827
827
+
{
818
828
Ok(skeleton) => {
819
829
let links = match extract_links(payload.hydration_sources, &skeleton) {
820
830
Ok(l) => l,
821
831
Err(e) => {
822
832
log::warn!("problem extracting: {e:?}");
823
823
-
return ProxyHydrateResponse::BadRequest(xrpc_error("oop", "sorry, error extracting"))
833
833
+
return ProxyHydrateResponse::BadRequest(xrpc_error(
834
834
+
"oop",
835
835
+
"sorry, error extracting",
836
836
+
));
824
837
}
825
838
};
826
839
let mut records = HashMap::new();
···
842
855
}
843
856
let mut u = url::Url::parse("https://example.com").unwrap();
844
857
u.query_pairs_mut().append_pair("at_uri", &uri); // BLEH todo
845
845
-
records.insert(uri.clone(), Hydration::Pending(ProxyHydrationPending {
846
846
-
url: format!("/xrpc/blue.microcosm.repo.getRecordByUri?{}", u.query().unwrap()), // TODO better; with cid, etc.
847
847
-
}));
858
858
+
records.insert(
859
859
+
uri.clone(),
860
860
+
Hydration::Pending(ProxyHydrationPending {
861
861
+
url: format!(
862
862
+
"/xrpc/blue.microcosm.repo.getRecordByUri?{}",
863
863
+
u.query().unwrap()
864
864
+
), // TODO better; with cid, etc.
865
865
+
}),
866
866
+
);
848
867
let tx = tx.clone();
849
868
let identity = self.identity.clone();
850
869
let repo = self.repo.clone();
···
860
879
identity.handle_to_did(handle).await.unwrap().unwrap()
861
880
};
862
881
863
863
-
let res = match repo.get_record(
864
864
-
&did,
865
865
-
&Nsid::new(collection.to_string()).unwrap(),
866
866
-
&RecordKey::new(rkey.to_string()).unwrap(),
867
867
-
&cid.as_ref().map(|s| Cid::from_str(s).unwrap()),
868
868
-
).await {
869
869
-
Ok(CachedRecord::Deleted) =>
882
882
+
let res = match repo
883
883
+
.get_record(
884
884
+
&did,
885
885
+
&Nsid::new(collection.to_string()).unwrap(),
886
886
+
&RecordKey::new(rkey.to_string()).unwrap(),
887
887
+
&cid.as_ref().map(|s| Cid::from_str(s).unwrap()),
888
888
+
)
889
889
+
.await
890
890
+
{
891
891
+
Ok(CachedRecord::Deleted) => {
870
892
Hydration::Error(ProxyHydrationError {
871
893
reason: "record deleted".to_string(),
872
872
-
}),
873
873
-
Ok(CachedRecord::Found(RawRecord { cid: found_cid, record })) => {
874
874
-
if let Some(c) = cid && found_cid.as_ref().to_string() != c {
894
894
+
})
895
895
+
}
896
896
+
Ok(CachedRecord::Found(RawRecord {
897
897
+
cid: found_cid,
898
898
+
record,
899
899
+
})) => {
900
900
+
if let Some(c) = cid
901
901
+
&& found_cid.as_ref().to_string() != c
902
902
+
{
875
903
log::warn!("ignoring cid mismatch");
876
904
}
877
905
let value = serde_json::from_str(&record).unwrap();
···
895
923
}
896
924
let mut u = url::Url::parse("https://example.com").unwrap();
897
925
u.query_pairs_mut().append_pair("identifier", &id);
898
898
-
identifiers.insert(id.clone(), Hydration::Pending(ProxyHydrationPending {
899
899
-
url: format!("/xrpc/blue.microcosm.identity.resolveMiniDoc?{}", u.query().unwrap()), // gross
900
900
-
}));
926
926
+
identifiers.insert(
927
927
+
id.clone(),
928
928
+
Hydration::Pending(ProxyHydrationPending {
929
929
+
url: format!(
930
930
+
"/xrpc/blue.microcosm.identity.resolveMiniDoc?{}",
931
931
+
u.query().unwrap()
932
932
+
), // gross
933
933
+
}),
934
934
+
);
901
935
let tx = tx.clone();
902
936
let identity = self.identity.clone();
903
937
tokio::task::spawn(async move {
904
938
let res = match Self::resolve_mini_doc_impl(&id, identity).await {
905
905
-
ResolveMiniDocResponse::Ok(Json(mini_doc)) => Hydration::Found(ProxyHydrationIdentifierFound {
906
906
-
mini_doc
907
907
-
}),
939
939
+
ResolveMiniDocResponse::Ok(Json(mini_doc)) => {
940
940
+
Hydration::Found(ProxyHydrationIdentifierFound { mini_doc })
941
941
+
}
908
942
ResolveMiniDocResponse::BadRequest(e) => {
909
943
log::warn!("minidoc fail: {:?}", e.0);
910
944
Hydration::Error(ProxyHydrationError {
···
923
957
924
958
while let Some(hydration) = rx.recv().await {
925
959
match hydration {
926
926
-
GetThing::Record(uri, h) => { records.insert(uri, h); }
927
927
-
GetThing::Identifier(uri, md) => { identifiers.insert(uri, md); }
960
960
+
GetThing::Record(uri, h) => {
961
961
+
records.insert(uri, h);
962
962
+
}
963
963
+
GetThing::Identifier(uri, md) => {
964
964
+
identifiers.insert(uri, md);
965
965
+
}
928
966
};
929
967
}
930
968
···
939
977
ProxyHydrateResponse::BadRequest(xrpc_error("oop", "sorry"))
940
978
}
941
979
}
942
942
-
943
980
}
944
981
945
982
async fn get_record_impl(