-172
Cargo.lock
-172
Cargo.lock
···
558
558
"async-trait",
559
559
"atproto_api",
560
560
"atrium-api",
561
-
"bsky-sdk",
562
561
"chromiumoxide",
563
562
"dotenv",
564
563
"env_logger",
565
-
"futures-util",
566
-
"handlebars",
567
564
"log",
568
565
"logic",
569
566
"reqwest",
570
567
"rocketman",
571
-
"rust-embed",
572
568
"serde",
573
569
"serde_json",
574
570
"slingshot",
···
594
590
"thiserror 1.0.69",
595
591
"trait-variant",
596
592
"unicode-segmentation",
597
-
]
598
-
599
-
[[package]]
600
-
name = "bstr"
601
-
version = "1.12.0"
602
-
source = "registry+https://github.com/rust-lang/crates.io-index"
603
-
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
604
-
dependencies = [
605
-
"memchr",
606
-
"serde",
607
593
]
608
594
609
595
[[package]]
···
1457
1443
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
1458
1444
1459
1445
[[package]]
1460
-
name = "globset"
1461
-
version = "0.4.16"
1462
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1463
-
checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5"
1464
-
dependencies = [
1465
-
"aho-corasick",
1466
-
"bstr",
1467
-
"log",
1468
-
"regex-automata 0.4.9",
1469
-
"regex-syntax 0.8.5",
1470
-
]
1471
-
1472
-
[[package]]
1473
1446
name = "gloo-timers"
1474
1447
version = "0.3.0"
1475
1448
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1525
1498
]
1526
1499
1527
1500
[[package]]
1528
-
name = "handlebars"
1529
-
version = "6.3.2"
1530
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1531
-
checksum = "759e2d5aea3287cb1190c8ec394f42866cb5bf74fcbf213f354e3c856ea26098"
1532
-
dependencies = [
1533
-
"derive_builder",
1534
-
"log",
1535
-
"num-order",
1536
-
"pest",
1537
-
"pest_derive",
1538
-
"rust-embed",
1539
-
"serde",
1540
-
"serde_json",
1541
-
"thiserror 2.0.12",
1542
-
]
1543
-
1544
-
[[package]]
1545
1501
name = "hashbrown"
1546
1502
version = "0.14.5"
1547
1503
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2327
2283
]
2328
2284
2329
2285
[[package]]
2330
-
name = "num-modular"
2331
-
version = "0.6.1"
2332
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2333
-
checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f"
2334
-
2335
-
[[package]]
2336
-
name = "num-order"
2337
-
version = "1.2.0"
2338
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2339
-
checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6"
2340
-
dependencies = [
2341
-
"num-modular",
2342
-
]
2343
-
2344
-
[[package]]
2345
2286
name = "num-traits"
2346
2287
version = "0.2.19"
2347
2288
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2473
2414
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
2474
2415
2475
2416
[[package]]
2476
-
name = "pest"
2477
-
version = "2.8.2"
2478
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2479
-
checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8"
2480
-
dependencies = [
2481
-
"memchr",
2482
-
"thiserror 2.0.12",
2483
-
"ucd-trie",
2484
-
]
2485
-
2486
-
[[package]]
2487
-
name = "pest_derive"
2488
-
version = "2.8.2"
2489
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2490
-
checksum = "bc58706f770acb1dbd0973e6530a3cff4746fb721207feb3a8a6064cd0b6c663"
2491
-
dependencies = [
2492
-
"pest",
2493
-
"pest_generator",
2494
-
]
2495
-
2496
-
[[package]]
2497
-
name = "pest_generator"
2498
-
version = "2.8.2"
2499
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2500
-
checksum = "6d4f36811dfe07f7b8573462465d5cb8965fffc2e71ae377a33aecf14c2c9a2f"
2501
-
dependencies = [
2502
-
"pest",
2503
-
"pest_meta",
2504
-
"proc-macro2",
2505
-
"quote",
2506
-
"syn 2.0.101",
2507
-
]
2508
-
2509
-
[[package]]
2510
-
name = "pest_meta"
2511
-
version = "2.8.2"
2512
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2513
-
checksum = "42919b05089acbd0a5dcd5405fb304d17d1053847b81163d09c4ad18ce8e8420"
2514
-
dependencies = [
2515
-
"pest",
2516
-
"sha2",
2517
-
]
2518
-
2519
-
[[package]]
2520
2417
name = "pin-project-lite"
2521
2418
version = "0.2.16"
2522
2419
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2958
2855
]
2959
2856
2960
2857
[[package]]
2961
-
name = "rust-embed"
2962
-
version = "8.7.2"
2963
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2964
-
checksum = "025908b8682a26ba8d12f6f2d66b987584a4a87bc024abc5bbc12553a8cd178a"
2965
-
dependencies = [
2966
-
"rust-embed-impl",
2967
-
"rust-embed-utils",
2968
-
"walkdir",
2969
-
]
2970
-
2971
-
[[package]]
2972
-
name = "rust-embed-impl"
2973
-
version = "8.7.2"
2974
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2975
-
checksum = "6065f1a4392b71819ec1ea1df1120673418bf386f50de1d6f54204d836d4349c"
2976
-
dependencies = [
2977
-
"proc-macro2",
2978
-
"quote",
2979
-
"rust-embed-utils",
2980
-
"syn 2.0.101",
2981
-
"walkdir",
2982
-
]
2983
-
2984
-
[[package]]
2985
-
name = "rust-embed-utils"
2986
-
version = "8.7.2"
2987
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2988
-
checksum = "f6cc0c81648b20b70c491ff8cce00c1c3b223bb8ed2b5d41f0e54c6c4c0a3594"
2989
-
dependencies = [
2990
-
"globset",
2991
-
"sha2",
2992
-
"walkdir",
2993
-
]
2994
-
2995
-
[[package]]
2996
2858
name = "rustc-demangle"
2997
2859
version = "0.1.24"
2998
2860
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3137
2999
version = "1.0.20"
3138
3000
source = "registry+https://github.com/rust-lang/crates.io-index"
3139
3001
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
3140
-
3141
-
[[package]]
3142
-
name = "same-file"
3143
-
version = "1.0.6"
3144
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3145
-
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
3146
-
dependencies = [
3147
-
"winapi-util",
3148
-
]
3149
3002
3150
3003
[[package]]
3151
3004
name = "schannel"
···
4040
3893
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
4041
3894
4042
3895
[[package]]
4043
-
name = "ucd-trie"
4044
-
version = "0.1.7"
4045
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4046
-
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
4047
-
4048
-
[[package]]
4049
3896
name = "unicode-bidi"
4050
3897
version = "0.3.18"
4051
3898
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4157
4004
version = "0.9.5"
4158
4005
source = "registry+https://github.com/rust-lang/crates.io-index"
4159
4006
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
4160
-
4161
-
[[package]]
4162
-
name = "walkdir"
4163
-
version = "2.5.0"
4164
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4165
-
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
4166
-
dependencies = [
4167
-
"same-file",
4168
-
"winapi-util",
4169
-
]
4170
4007
4171
4008
[[package]]
4172
4009
name = "want"
···
4351
4188
version = "0.4.0"
4352
4189
source = "registry+https://github.com/rust-lang/crates.io-index"
4353
4190
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
4354
-
4355
-
[[package]]
4356
-
name = "winapi-util"
4357
-
version = "0.1.11"
4358
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4359
-
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
4360
-
dependencies = [
4361
-
"windows-sys 0.61.0",
4362
-
]
4363
4191
4364
4192
[[package]]
4365
4193
name = "winapi-x86_64-pc-windows-gnu"
-4
bot/Cargo.toml
-4
bot/Cargo.toml
···
6
6
[dependencies]
7
7
anyhow = "1.0.98"
8
8
atproto_api.workspace = true
9
-
bsky-sdk.workspace = true
10
9
chromiumoxide = { version = "0.7", features = ["tokio-runtime"] }
11
-
handlebars = { version = "6.3.2", features = ["rust-embed"] }
12
-
rust-embed = { version = "8.7.2", features = ["include-exclude"] }
13
10
rocketman.workspace = true
14
11
reqwest.workspace = true
15
12
atrium-api.workspace = true
···
24
21
logic.workspace = true
25
22
slingshot.workspace = true
26
23
urlencoding = "2.1.3"
27
-
futures-util = "0.3.31"
+35
-111
bot/src/main.rs
+35
-111
bot/src/main.rs
···
1
-
mod constellation;
2
-
3
1
extern crate dotenv;
4
-
5
2
use crate::constellation::fetch_constellation_count;
6
-
use atrium_api::app::bsky::embed::defs::AspectRatioData;
7
3
use atrium_api::app::bsky::feed::post::RecordEmbedRefs;
8
4
use atrium_api::app::bsky::richtext::facet::{ByteSliceData, LinkData, MainFeaturesItem};
9
5
use atrium_api::types::string::Language;
10
6
use atrium_api::types::{Collection, Union};
11
-
use bsky_sdk::rich_text::RichText;
12
-
use chromiumoxide::browser::{Browser, BrowserConfig, HeadlessMode};
13
-
use chromiumoxide::cdp::browser_protocol::page::{
14
-
CaptureScreenshotFormat, CaptureScreenshotParams, Viewport,
15
-
};
16
7
use dotenv::dotenv;
17
-
use futures_util::stream::StreamExt;
18
-
use handlebars::Handlebars;
19
-
use log::error;
20
8
use logic::BotApi;
21
9
use rocketman::{
22
10
connection::JetstreamConnection, handler, ingestion::LexiconIngestor,
23
11
options::JetstreamOptions, types::event::Operation,
24
12
};
25
-
use rust_embed::Embed;
26
13
use serde::Serialize;
27
14
use slingshot::Slingshot;
28
15
use sqlx::sqlite::{SqliteConnectOptions, SqlitePool};
···
31
18
use std::sync::{Arc, Mutex};
32
19
use std::time::Duration;
33
20
34
-
#[derive(Embed)]
35
-
#[folder = "templates/"]
36
-
#[include = "*.hbs"]
37
-
pub struct Templates;
21
+
mod constellation;
38
22
39
23
#[derive(Debug)]
40
-
struct Record {
24
+
struct ParsedRecord {
41
25
did: String,
42
26
collection: String,
43
27
rkey: String,
44
28
}
45
29
46
-
fn parse_uri(uri: &str) -> anyhow::Result<Record> {
30
+
struct StarIngestor {
31
+
pool: SqlitePool,
32
+
bot: Arc<BotApi>,
33
+
sling_shot: Arc<Slingshot>,
34
+
timeframe_hours: i64,
35
+
star_threshold: i64,
36
+
post_window_hours: i64,
37
+
}
38
+
39
+
#[derive(Serialize)]
40
+
struct RepoPreview {
41
+
repo: String,
42
+
stars: u64,
43
+
description: String,
44
+
}
45
+
46
+
fn parse_uri(uri: &str) -> anyhow::Result<ParsedRecord> {
47
47
let parts: Vec<&str> = uri.trim_start_matches("at://").split('/').collect();
48
48
if parts.len() != 3 {
49
49
return Err(anyhow::anyhow!("Invalid URI format"));
50
50
}
51
-
Ok(Record {
51
+
Ok(ParsedRecord {
52
52
did: parts[0].to_string(),
53
53
collection: parts[1].to_string(),
54
54
rkey: parts[2].to_string(),
···
107
107
let bot_api = BotApi::new_logged_in(bot_username, bot_password, bot_pds_url).await?;
108
108
let sling_shot = Arc::new(Slingshot::new("https://slingshot.microcosm.blue")?);
109
109
110
-
// setup handlebars
111
-
let mut hbs = Handlebars::new();
112
-
let _ = hbs.register_embed_templates::<Templates>();
113
-
114
-
// Initialize a long-running Chromium browser
115
-
let cfg = BrowserConfig::builder()
116
-
.headless_mode(HeadlessMode::New)
117
-
.no_sandbox()
118
-
.build()
119
-
.map_err(|e| anyhow::anyhow!(e))
120
-
.expect("build browser config");
121
-
122
-
let (browser, mut browser_handler) = Browser::launch(cfg).await.expect("launch browser");
123
-
// Drive the browser handler for the lifetime of the program
124
-
tokio::spawn(async move { while let Some(_evt) = browser_handler.next().await {} });
125
-
let browser = Arc::new(browser);
126
-
127
110
// Ingestor for the star collection
128
111
let mut ingestors: HashMap<String, Box<dyn LexiconIngestor + Send + Sync>> = HashMap::new();
129
112
ingestors.insert(
···
132
115
pool: pool.clone(),
133
116
bot: Arc::new(bot_api),
134
117
sling_shot: sling_shot.clone(),
135
-
browser: browser.clone(),
136
-
hbs: Arc::new(hbs),
137
118
timeframe_hours,
138
119
star_threshold,
139
120
post_window_hours,
···
167
148
.map_err(|e| anyhow::anyhow!(e.to_string()))
168
149
}
169
150
170
-
struct StarIngestor {
171
-
pool: SqlitePool,
172
-
bot: Arc<BotApi>,
173
-
sling_shot: Arc<Slingshot>,
174
-
browser: Arc<Browser>,
175
-
hbs: Arc<Handlebars<'static>>,
176
-
timeframe_hours: i64,
177
-
star_threshold: i64,
178
-
post_window_hours: i64,
179
-
}
180
-
181
151
#[async_trait::async_trait]
182
152
impl LexiconIngestor for StarIngestor {
183
153
/// Asynchronously processes an incoming event message related to "stars" and performs database operations and other actions based on the event type.
···
230
200
231
201
if count_in_window >= self.star_threshold {
232
202
log::info!(
233
-
"Star threshold met: {} stars in the last {} hour(s) (threshold: {})",
203
+
"Star threshold met: {} stars in the last {} hour(s) (threshold: {}), checking to see if it should be posted",
234
204
count_in_window,
235
205
self.timeframe_hours,
236
206
self.star_threshold
···
279
249
280
250
let handle_and_repo = format!("{handle}/{repo_name}");
281
251
282
-
let ctx = RepoPreview {
252
+
let _ctx = RepoPreview {
283
253
repo: handle_and_repo.clone(),
284
254
stars: stars as u64,
285
255
description: description.clone(),
286
256
};
287
257
288
-
let html = &self.hbs.render("repo_header.hbs", &ctx)?;
289
-
290
-
let bytes = render_with_chromiumoxide(
291
-
self.browser.as_ref(),
292
-
&html,
293
-
336,
294
-
114,
295
-
)
296
-
.await?;
258
+
// Fetch the pre-rendered image from the external service instead of rendering via Chromium
259
+
let encoded_subject = urlencoding::encode(&repo_subject);
260
+
let url = format!(
261
+
"https://tangled-search.bigmoves.deno.net/repo-image/{}",
262
+
encoded_subject
263
+
);
264
+
let bytes = reqwest::get(url).await?.bytes().await?.to_vec();
297
265
298
266
let blob_upload = &self
299
267
.bot
···
318
286
),
319
287
aspect_ratio: Some(
320
288
atrium_api::app::bsky::embed::defs::AspectRatioData {
321
-
height: NonZeroU64::try_from(114_u64)?,
322
-
width: NonZeroU64::try_from(336_u64)?,
289
+
height: NonZeroU64::try_from(400_u64)?,
290
+
width: NonZeroU64::try_from(800_u64)?,
323
291
}
324
292
.into(),
325
293
),
···
364
332
tags: None,
365
333
text: post_text,
366
334
};
367
-
335
+
log::info!(
336
+
"Threshold met and allowed to be posted, total stars: {stars}"
337
+
);
368
338
match self.bot.agent.create_record(post).await {
369
-
Ok(err) => {
339
+
Ok(_) => {
370
340
log::info!("NEW POST MADE")
371
341
}
372
342
Err(err) => {
373
343
log::error!("{err}")
374
344
}
375
345
}
376
-
log::info!(
377
-
"Threshold met and allowed to be posted, stars: {stars}"
378
-
);
379
346
}
380
347
}
381
348
}
···
394
361
Ok(())
395
362
}
396
363
}
397
-
398
-
#[derive(Serialize)]
399
-
struct RepoPreview {
400
-
repo: String,
401
-
stars: u64,
402
-
description: String,
403
-
}
404
-
405
-
async fn render_with_chromiumoxide(
406
-
browser: &Browser,
407
-
html: &str,
408
-
width: u32,
409
-
height: u32,
410
-
) -> Result<Vec<u8>, anyhow::Error> {
411
-
// Use the long-running browser to render a page and capture a screenshot
412
-
let page = browser.new_page("about:blank").await?;
413
-
414
-
// Load the provided HTML as a data URL to avoid external fetches
415
-
let data_url = format!("data:text/html;charset=utf-8,{}", urlencoding::encode(html));
416
-
page.goto(data_url).await?;
417
-
418
-
// Wait for navigation to settle
419
-
page.wait_for_navigation().await.ok();
420
-
421
-
// Screenshot: clip to desired viewport size regardless of page layout
422
-
let params = CaptureScreenshotParams::builder()
423
-
.format(CaptureScreenshotFormat::Png)
424
-
.clip(Viewport {
425
-
x: 0.0,
426
-
y: 0.0,
427
-
width: width as f64,
428
-
height: height as f64,
429
-
scale: 1.0,
430
-
})
431
-
.from_surface(true)
432
-
.build();
433
-
let png_bytes = page.screenshot(params).await?;
434
-
435
-
// Close just the page; keep the browser alive
436
-
page.close().await.ok();
437
-
438
-
Ok(png_bytes)
439
-
}
-45
bot/templates/repo_header.hbs
-45
bot/templates/repo_header.hbs
···
1
-
<html lang="en" class="dark:bg-gray-900">
2
-
<head>
3
-
<link rel="preload" href="https://tangled.sh/static/fonts/InterVariable.woff2" as="font" type="font/woff2"
4
-
crossorigin/>
5
-
<link rel="stylesheet" href="https://tangled.sh/static/tw.css?6a194d26" type="text/css"/>
6
-
<title>timeline · tangled</title>
7
-
</head>
8
-
<body>
9
-
10
-
<div class="flex-none h-full border border-gray-200 dark:border-gray-700 rounded-sm w-96">
11
-
<div class="py-4 px-6 gap-1 flex flex-col drop-shadow-sm rounded bg-white dark:bg-gray-800 min-h-32">
12
-
<div class="font-medium dark:text-white flex items-center">
13
-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
14
-
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
15
-
class="w-4 h-4 mr-1.5 shrink-0">
16
-
<path d="M10 2v8l3-3 3 3V2"></path>
17
-
<path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20"></path>
18
-
</svg>
19
-
<a href="/{{repo}}" class="truncate">{{repo}}</a></div>
20
-
21
-
<div class="text-gray-600 dark:text-gray-300 text-sm line-clamp-2">
22
-
{{description}}
23
-
24
-
</div>
25
-
26
-
27
-
<div class="text-gray-400 text-sm font-mono inline-flex gap-4 mt-auto">
28
-
<div class="flex gap-1 items-center text-sm">
29
-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
30
-
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
31
-
class="w-3 h-3 fill-current">
32
-
<path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"></path>
33
-
</svg>
34
-
35
-
<span>{{stars}}</span>
36
-
</div>
37
-
38
-
</div>
39
-
40
-
</div>
41
-
42
-
</div>
43
-
44
-
</body>
45
-
</html>
+2
-34
logic/src/lib.rs
+2
-34
logic/src/lib.rs
···
1
1
mod resolver;
2
2
use crate::resolver::ApiDNSTxtResolver;
3
-
use atrium_api::agent::atp_agent::store::MemorySessionStore;
4
-
use atrium_api::agent::atp_agent::{AtpSession, CredentialSession};
5
-
use atrium_api::agent::{Agent, Configure};
6
-
use atrium_api::did_doc::DidDocument;
7
-
use atrium_api::types::string::{Datetime, Did, Handle};
8
-
use atrium_api::types::{Collection, LimitedNonZeroU8};
3
+
use atrium_api::agent::Configure;
4
+
use atrium_api::types::string::{Did, Handle};
9
5
use atrium_common::resolver::Resolver;
10
-
use atrium_common::store::memory::MemoryStore;
11
6
use atrium_identity::did::{CommonDidResolver, CommonDidResolverConfig, DEFAULT_PLC_DIRECTORY_URL};
12
7
use atrium_identity::handle::{AtprotoHandleResolver, AtprotoHandleResolverConfig};
13
8
use atrium_oauth::DefaultHttpClient;
14
-
use atrium_xrpc_client::reqwest::ReqwestClient;
15
9
use bsky_sdk::BskyAgent;
16
-
use serde::{Deserialize, Serialize};
17
10
use std::sync::Arc;
18
11
use thiserror::Error;
19
12
···
40
33
pub agent: Arc<BskyAgent>,
41
34
handle_resolver: Arc<AtprotoHandleResolver<ApiDNSTxtResolver, DefaultHttpClient>>,
42
35
did_resolver: Arc<CommonDidResolver<DefaultHttpClient>>,
43
-
authenticated: bool,
44
-
}
45
-
46
-
fn get_new_session(
47
-
pds_url: String,
48
-
) -> CredentialSession<MemoryStore<(), AtpSession>, ReqwestClient> {
49
-
CredentialSession::new(
50
-
ReqwestClient::new(pds_url.as_str()),
51
-
MemorySessionStore::default(),
52
-
)
53
-
}
54
-
55
-
/// Parses the PDS url from the DidDocument
56
-
fn get_pds_from_doc<'a>(doc: DidDocument) -> Result<String, Error> {
57
-
Ok(doc
58
-
.service
59
-
.as_ref()
60
-
.and_then(|services| {
61
-
services
62
-
.iter()
63
-
.find(|service| service.r#type == "AtprotoPersonalDataServer")
64
-
.map(|service| service.service_endpoint.clone())
65
-
})
66
-
.ok_or_else(|| Error::ParseError("No valid PDS URL found for this DID".to_string()))?)
67
36
}
68
37
69
38
impl BotApi {
···
101
70
agent: Arc::new(agent),
102
71
handle_resolver: Arc::new(handle_resolver),
103
72
did_resolver: Arc::new(did_resolver),
104
-
authenticated: true,
105
73
})
106
74
}
107
75