Add some untested version of publishing a feed
Also adjust names of different env vars, and also adjust setup instructions
This commit is contained in:
		
							parent
							
								
									5128bf9d4a
								
							
						
					
					
						commit
						e95c4923d6
					
				| 
						 | 
					@ -1,3 +1,6 @@
 | 
				
			||||||
 | 
					PUBLISHER_BLUESKY_HANDLE="..."
 | 
				
			||||||
 | 
					PUBLISHER_BLUESKY_PASSWORD="..."
 | 
				
			||||||
 | 
					PUBLISHER_DID="..."
 | 
				
			||||||
CHAT_GPT_API_KEY="fake-chat-gpt-key"
 | 
					CHAT_GPT_API_KEY="fake-chat-gpt-key"
 | 
				
			||||||
DATABASE_URL="postgres://postgres:password@localhost/nederlandskie"
 | 
					DATABASE_URL="postgres://postgres:password@localhost/nederlandskie"
 | 
				
			||||||
HOSTNAME="..."
 | 
					FEED_GENERATOR_HOSTNAME="..."
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,6 +75,54 @@ dependencies = [
 | 
				
			||||||
 "libc",
 | 
					 "libc",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "anstream"
 | 
				
			||||||
 | 
					version = "0.5.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "anstyle",
 | 
				
			||||||
 | 
					 "anstyle-parse",
 | 
				
			||||||
 | 
					 "anstyle-query",
 | 
				
			||||||
 | 
					 "anstyle-wincon",
 | 
				
			||||||
 | 
					 "colorchoice",
 | 
				
			||||||
 | 
					 "utf8parse",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "anstyle"
 | 
				
			||||||
 | 
					version = "1.0.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "anstyle-parse"
 | 
				
			||||||
 | 
					version = "0.2.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "utf8parse",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "anstyle-query"
 | 
				
			||||||
 | 
					version = "1.0.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "windows-sys",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "anstyle-wincon"
 | 
				
			||||||
 | 
					version = "2.1.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "anstyle",
 | 
				
			||||||
 | 
					 "windows-sys",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "anyhow"
 | 
					name = "anyhow"
 | 
				
			||||||
version = "1.0.75"
 | 
					version = "1.0.75"
 | 
				
			||||||
| 
						 | 
					@ -430,6 +478,52 @@ dependencies = [
 | 
				
			||||||
 "unsigned-varint",
 | 
					 "unsigned-varint",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "clap"
 | 
				
			||||||
 | 
					version = "4.4.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "clap_builder",
 | 
				
			||||||
 | 
					 "clap_derive",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "clap_builder"
 | 
				
			||||||
 | 
					version = "4.4.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "anstream",
 | 
				
			||||||
 | 
					 "anstyle",
 | 
				
			||||||
 | 
					 "clap_lex",
 | 
				
			||||||
 | 
					 "strsim",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "clap_derive"
 | 
				
			||||||
 | 
					version = "4.4.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "heck",
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn 2.0.35",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "clap_lex"
 | 
				
			||||||
 | 
					version = "0.5.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "colorchoice"
 | 
				
			||||||
 | 
					version = "1.0.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "compact_str"
 | 
					name = "compact_str"
 | 
				
			||||||
version = "0.7.1"
 | 
					version = "0.7.1"
 | 
				
			||||||
| 
						 | 
					@ -2248,6 +2342,7 @@ dependencies = [
 | 
				
			||||||
 "chat-gpt-lib-rs",
 | 
					 "chat-gpt-lib-rs",
 | 
				
			||||||
 "chrono",
 | 
					 "chrono",
 | 
				
			||||||
 "ciborium",
 | 
					 "ciborium",
 | 
				
			||||||
 | 
					 "clap",
 | 
				
			||||||
 "dotenv",
 | 
					 "dotenv",
 | 
				
			||||||
 "env_logger",
 | 
					 "env_logger",
 | 
				
			||||||
 "futures",
 | 
					 "futures",
 | 
				
			||||||
| 
						 | 
					@ -3284,6 +3379,12 @@ dependencies = [
 | 
				
			||||||
 "unicode-normalization",
 | 
					 "unicode-normalization",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "strsim"
 | 
				
			||||||
 | 
					version = "0.10.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "strum"
 | 
					name = "strum"
 | 
				
			||||||
version = "0.24.1"
 | 
					version = "0.24.1"
 | 
				
			||||||
| 
						 | 
					@ -3658,6 +3759,12 @@ version = "0.7.6"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
 | 
					checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "utf8parse"
 | 
				
			||||||
 | 
					version = "0.2.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "vcpkg"
 | 
					name = "vcpkg"
 | 
				
			||||||
version = "0.2.15"
 | 
					version = "0.2.15"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
name = "nederlandskie"
 | 
					name = "nederlandskie"
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
edition = "2021"
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					default-run = "nederlandskie"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
					# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +15,7 @@ axum = "0.6.20"
 | 
				
			||||||
chat-gpt-lib-rs = "0.2.1"
 | 
					chat-gpt-lib-rs = "0.2.1"
 | 
				
			||||||
chrono = "0.4.31"
 | 
					chrono = "0.4.31"
 | 
				
			||||||
ciborium = "0.2.1"
 | 
					ciborium = "0.2.1"
 | 
				
			||||||
 | 
					clap = { version = "4.4.4", features = ["derive"] }
 | 
				
			||||||
dotenv = "0.15.0"
 | 
					dotenv = "0.15.0"
 | 
				
			||||||
env_logger = "0.10.0"
 | 
					env_logger = "0.10.0"
 | 
				
			||||||
futures = "0.3.28"
 | 
					futures = "0.3.28"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										28
									
								
								README.md
								
								
								
								
							
							
						
						
									
										28
									
								
								README.md
								
								
								
								
							| 
						 | 
					@ -15,14 +15,32 @@ Heavily WIP. Doesn't work yet at all, but does read the stream of posts as they
 | 
				
			||||||
- [ ] Publish the feed
 | 
					- [ ] Publish the feed
 | 
				
			||||||
- [ ] Handle deleting of posts
 | 
					- [ ] Handle deleting of posts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Initial setup
 | 
					## Configuration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Copy `.env.example` into `.env` and set up the environment variables within:
 | 
					1. Copy `.env.example` into `.env` and set up the environment variables within:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- `CHAT_GPT_API_KEY` for your ChatGPT key
 | 
					   - `PUBLISHER_BLUESKY_HANDLE` to your Bluesky handle
 | 
				
			||||||
- `DATABASE_URL` for PostgreSQL credentials
 | 
					   - `PUBLISHER_BLUESKY_PASSWORD` to Bluesky app password that you created in settings
 | 
				
			||||||
- `HOSTNAME` to the hostname of where you intend to host the feed
 | 
					   - `CHAT_GPT_API_KEY` for your ChatGPT key
 | 
				
			||||||
 | 
					   - `DATABASE_URL` for PostgreSQL credentials
 | 
				
			||||||
 | 
					   - `FEED_GENERATOR_HOSTNAME` to the hostname of where you intend to host the feed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. Determine your own DID and put it in `PUBLISHER_DID` env variable in `.env`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   ```
 | 
				
			||||||
 | 
					   cargo run --bin who_am_i
 | 
				
			||||||
 | 
					   ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Running
 | 
					## Running
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Populate and serve the feed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`cargo run`
 | 
					`cargo run`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Determine your own did for publishing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`cargo run --bin who_am_i`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Publish the feed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`cargo run --bin publish_feed -- --help`
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,66 @@
 | 
				
			||||||
 | 
					extern crate nederlandskie;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::env;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use anyhow::{Context, Result};
 | 
				
			||||||
 | 
					use clap::Parser;
 | 
				
			||||||
 | 
					use dotenv::dotenv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use nederlandskie::services::Bluesky;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Parser, Debug)]
 | 
				
			||||||
 | 
					struct Args {
 | 
				
			||||||
 | 
					    /// Short name of the feed. Must match one of the defined algos.
 | 
				
			||||||
 | 
					    #[arg(long)]
 | 
				
			||||||
 | 
					    name: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Name that will be displayed in Bluesky interface
 | 
				
			||||||
 | 
					    #[arg(long)]
 | 
				
			||||||
 | 
					    display_name: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Description that will be displayed in Bluesky interface
 | 
				
			||||||
 | 
					    #[arg(long)]
 | 
				
			||||||
 | 
					    description: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Filename of the avatar that will be displayed
 | 
				
			||||||
 | 
					    #[arg(long)]
 | 
				
			||||||
 | 
					    avatar_filename: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::main]
 | 
				
			||||||
 | 
					async fn main() -> Result<()> {
 | 
				
			||||||
 | 
					    dotenv()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let args = Args::parse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let handle = env::var("PUBLISHER_BLUESKY_HANDLE")
 | 
				
			||||||
 | 
					        .context("PUBLISHER_BLUESKY_HANDLE environment variable must be set")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let password = env::var("PUBLISHER_BLUESKY_PASSWORD")
 | 
				
			||||||
 | 
					        .context("PUBLISHER_BLUESKY_PASSWORD environment variable must be set")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let feed_generator_did = format!("did:web:{}", env::var("FEED_GENERATOR_HOSTNAME")?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let bluesky = Bluesky::new("https://bsky.social");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let session = bluesky.login(&handle, &password).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut avatar = None;
 | 
				
			||||||
 | 
					    if let Some(path) = args.avatar_filename {
 | 
				
			||||||
 | 
					        let bytes = std::fs::read(path)?;
 | 
				
			||||||
 | 
					        avatar = Some(bluesky.upload_blob(bytes).await?);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bluesky
 | 
				
			||||||
 | 
					        .publish_feed(
 | 
				
			||||||
 | 
					            &session.did,
 | 
				
			||||||
 | 
					            &feed_generator_did,
 | 
				
			||||||
 | 
					            &args.name,
 | 
				
			||||||
 | 
					            &args.display_name,
 | 
				
			||||||
 | 
					            &args.description,
 | 
				
			||||||
 | 
					            avatar,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					extern crate nederlandskie;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::env;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use anyhow::{Context, Result};
 | 
				
			||||||
 | 
					use dotenv::dotenv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use nederlandskie::services::Bluesky;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::main]
 | 
				
			||||||
 | 
					async fn main() -> Result<()> {
 | 
				
			||||||
 | 
					    dotenv()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let bluesky = Bluesky::new("https://bsky.social");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let handle = env::var("PUBLISHER_BLUESKY_HANDLE")
 | 
				
			||||||
 | 
					        .context("PUBLISHER_BLUESKY_HANDLE environment variable must be set")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let password = env::var("PUBLISHER_BLUESKY_PASSWORD")
 | 
				
			||||||
 | 
					        .context("PUBLISHER_BLUESKY_PASSWORD environment variable must be set")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let session = bluesky.login(&handle, &password).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    println!("{}", session.did);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -5,9 +5,9 @@ use std::env;
 | 
				
			||||||
pub struct Config {
 | 
					pub struct Config {
 | 
				
			||||||
    pub chat_gpt_api_key: String,
 | 
					    pub chat_gpt_api_key: String,
 | 
				
			||||||
    pub database_url: String,
 | 
					    pub database_url: String,
 | 
				
			||||||
    pub service_did: String,
 | 
					    pub feed_generator_did: String,
 | 
				
			||||||
    pub publisher_did: String,
 | 
					    pub publisher_did: String,
 | 
				
			||||||
    pub hostname: String,
 | 
					    pub feed_generator_hostname: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Config {
 | 
					impl Config {
 | 
				
			||||||
| 
						 | 
					@ -17,9 +17,9 @@ impl Config {
 | 
				
			||||||
        Ok(Self {
 | 
					        Ok(Self {
 | 
				
			||||||
            chat_gpt_api_key: env::var("CHAT_GPT_API_KEY")?,
 | 
					            chat_gpt_api_key: env::var("CHAT_GPT_API_KEY")?,
 | 
				
			||||||
            database_url: env::var("DATABASE_URL")?,
 | 
					            database_url: env::var("DATABASE_URL")?,
 | 
				
			||||||
            hostname: env::var("HOSTNAME")?,
 | 
					            feed_generator_hostname: env::var("FEED_GENERATOR_HOSTNAME")?,
 | 
				
			||||||
            service_did: format!("did:web:{}", env::var("HOSTNAME")?),
 | 
					            feed_generator_did: format!("did:web:{}", env::var("FEED_GENERATOR_HOSTNAME")?),
 | 
				
			||||||
            publisher_did: "".to_owned(), // TODO
 | 
					            publisher_did: env::var("PUBLISHER_DID")?,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@ pub async fn describe_feed_generator(
 | 
				
			||||||
    State(state): State<FeedServerState>,
 | 
					    State(state): State<FeedServerState>,
 | 
				
			||||||
) -> Json<FeedGeneratorDescription> {
 | 
					) -> Json<FeedGeneratorDescription> {
 | 
				
			||||||
    Json(FeedGeneratorDescription {
 | 
					    Json(FeedGeneratorDescription {
 | 
				
			||||||
        did: state.config.service_did.clone(),
 | 
					        did: state.config.feed_generator_did.clone(),
 | 
				
			||||||
        feeds: state
 | 
					        feeds: state
 | 
				
			||||||
            .algos
 | 
					            .algos
 | 
				
			||||||
            .iter_names()
 | 
					            .iter_names()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,11 +22,11 @@ pub struct Service {
 | 
				
			||||||
pub async fn did_json(State(state): State<FeedServerState>) -> Json<Did> {
 | 
					pub async fn did_json(State(state): State<FeedServerState>) -> Json<Did> {
 | 
				
			||||||
    Json(Did {
 | 
					    Json(Did {
 | 
				
			||||||
        context: vec!["https://www.w3.org/ns/did/v1".to_owned()],
 | 
					        context: vec!["https://www.w3.org/ns/did/v1".to_owned()],
 | 
				
			||||||
        id: state.config.service_did.clone(),
 | 
					        id: state.config.feed_generator_did.clone(),
 | 
				
			||||||
        service: vec![Service {
 | 
					        service: vec![Service {
 | 
				
			||||||
            id: "#bsky_fg".to_owned(),
 | 
					            id: "#bsky_fg".to_owned(),
 | 
				
			||||||
            type_: "BskyFeedGenerator".to_owned(),
 | 
					            type_: "BskyFeedGenerator".to_owned(),
 | 
				
			||||||
            service_endpoint: format!("https://{}", state.config.hostname),
 | 
					            service_endpoint: format!("https://{}", state.config.feed_generator_hostname),
 | 
				
			||||||
        }],
 | 
					        }],
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,12 +38,12 @@ impl PostIndexer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let cursor = self
 | 
					        let cursor = self
 | 
				
			||||||
            .database
 | 
					            .database
 | 
				
			||||||
            .fetch_subscription_cursor(&self.config.service_did)
 | 
					            .fetch_subscription_cursor(&self.config.feed_generator_did)
 | 
				
			||||||
            .await?;
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if cursor.is_none() {
 | 
					        if cursor.is_none() {
 | 
				
			||||||
            self.database
 | 
					            self.database
 | 
				
			||||||
                .create_subscription_state(&self.config.service_did)
 | 
					                .create_subscription_state(&self.config.feed_generator_did)
 | 
				
			||||||
                .await?;
 | 
					                .await?;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -91,10 +91,10 @@ impl CommitProcessor for PostIndexer {
 | 
				
			||||||
        if commit.seq % 20 == 0 {
 | 
					        if commit.seq % 20 == 0 {
 | 
				
			||||||
            info!(
 | 
					            info!(
 | 
				
			||||||
                "Updating cursor for {} to {}",
 | 
					                "Updating cursor for {} to {}",
 | 
				
			||||||
                self.config.service_did, commit.seq
 | 
					                self.config.feed_generator_did, commit.seq
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            self.database
 | 
					            self.database
 | 
				
			||||||
                .update_subscription_cursor(&self.config.service_did, commit.seq)
 | 
					                .update_subscription_cursor(&self.config.feed_generator_did, commit.seq)
 | 
				
			||||||
                .await?;
 | 
					                .await?;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,10 @@
 | 
				
			||||||
use anyhow::{anyhow, Result};
 | 
					use anyhow::{anyhow, Result};
 | 
				
			||||||
 | 
					use atrium_api::blob::BlobRef;
 | 
				
			||||||
use atrium_api::client::AtpServiceClient;
 | 
					use atrium_api::client::AtpServiceClient;
 | 
				
			||||||
use atrium_api::client::AtpServiceWrapper;
 | 
					use atrium_api::client::AtpServiceWrapper;
 | 
				
			||||||
 | 
					use atrium_api::records::Record;
 | 
				
			||||||
use atrium_xrpc::client::reqwest::ReqwestClient;
 | 
					use atrium_xrpc::client::reqwest::ReqwestClient;
 | 
				
			||||||
 | 
					use chrono::Utc;
 | 
				
			||||||
use futures::StreamExt;
 | 
					use futures::StreamExt;
 | 
				
			||||||
use log::error;
 | 
					use log::error;
 | 
				
			||||||
use tokio_tungstenite::{connect_async, tungstenite};
 | 
					use tokio_tungstenite::{connect_async, tungstenite};
 | 
				
			||||||
| 
						 | 
					@ -14,6 +17,11 @@ pub struct ProfileDetails {
 | 
				
			||||||
    pub description: String,
 | 
					    pub description: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub struct SessionDetails {
 | 
				
			||||||
 | 
					    pub did: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Bluesky {
 | 
					pub struct Bluesky {
 | 
				
			||||||
    client: AtpServiceClient<AtpServiceWrapper<ReqwestClient>>,
 | 
					    client: AtpServiceClient<AtpServiceWrapper<ReqwestClient>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -25,6 +33,77 @@ impl Bluesky {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn login(&self, handle: &str, password: &str) -> Result<SessionDetails> {
 | 
				
			||||||
 | 
					        use atrium_api::com::atproto::server::create_session::Input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let result = self
 | 
				
			||||||
 | 
					            .client
 | 
				
			||||||
 | 
					            .service
 | 
				
			||||||
 | 
					            .com
 | 
				
			||||||
 | 
					            .atproto
 | 
				
			||||||
 | 
					            .server
 | 
				
			||||||
 | 
					            .create_session(Input {
 | 
				
			||||||
 | 
					                identifier: handle.to_owned(),
 | 
				
			||||||
 | 
					                password: password.to_owned(),
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(SessionDetails { did: result.did })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn upload_blob(&self, blob: Vec<u8>) -> Result<BlobRef> {
 | 
				
			||||||
 | 
					        let result = self
 | 
				
			||||||
 | 
					            .client
 | 
				
			||||||
 | 
					            .service
 | 
				
			||||||
 | 
					            .com
 | 
				
			||||||
 | 
					            .atproto
 | 
				
			||||||
 | 
					            .repo
 | 
				
			||||||
 | 
					            .upload_blob(blob)
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(result.blob)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn publish_feed(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        publisher_did: &str,
 | 
				
			||||||
 | 
					        feed_generator_did: &str,
 | 
				
			||||||
 | 
					        name: &str,
 | 
				
			||||||
 | 
					        display_name: &str,
 | 
				
			||||||
 | 
					        description: &str,
 | 
				
			||||||
 | 
					        avatar: Option<BlobRef>,
 | 
				
			||||||
 | 
					    ) -> Result<()> {
 | 
				
			||||||
 | 
					        use atrium_api::com::atproto::repo::put_record::Input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.client
 | 
				
			||||||
 | 
					            .service
 | 
				
			||||||
 | 
					            .com
 | 
				
			||||||
 | 
					            .atproto
 | 
				
			||||||
 | 
					            .repo
 | 
				
			||||||
 | 
					            .put_record(Input {
 | 
				
			||||||
 | 
					                collection: "app.bsky.feed.generator".to_owned(),
 | 
				
			||||||
 | 
					                record: Record::AppBskyFeedGenerator(Box::new(
 | 
				
			||||||
 | 
					                    atrium_api::app::bsky::feed::generator::Record {
 | 
				
			||||||
 | 
					                        avatar,
 | 
				
			||||||
 | 
					                        created_at: Utc::now().to_string(),
 | 
				
			||||||
 | 
					                        description: Some(description.to_owned()),
 | 
				
			||||||
 | 
					                        description_facets: None,
 | 
				
			||||||
 | 
					                        did: feed_generator_did.to_owned(),
 | 
				
			||||||
 | 
					                        display_name: display_name.to_owned(),
 | 
				
			||||||
 | 
					                        labels: None,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                )),
 | 
				
			||||||
 | 
					                repo: publisher_did.to_owned(),
 | 
				
			||||||
 | 
					                rkey: name.to_owned(),
 | 
				
			||||||
 | 
					                swap_commit: None,
 | 
				
			||||||
 | 
					                swap_record: None,
 | 
				
			||||||
 | 
					                validate: None,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub async fn fetch_profile_details(&self, did: &str) -> Result<ProfileDetails> {
 | 
					    pub async fn fetch_profile_details(&self, did: &str) -> Result<ProfileDetails> {
 | 
				
			||||||
        let result = self
 | 
					        let result = self
 | 
				
			||||||
            .client
 | 
					            .client
 | 
				
			||||||
| 
						 | 
					@ -41,7 +120,7 @@ impl Bluesky {
 | 
				
			||||||
            .await?;
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let profile = match result.value {
 | 
					        let profile = match result.value {
 | 
				
			||||||
            atrium_api::records::Record::AppBskyActorProfile(profile) => profile,
 | 
					            Record::AppBskyActorProfile(profile) => profile,
 | 
				
			||||||
            _ => return Err(anyhow!("Big bad, no such profile")),
 | 
					            _ => return Err(anyhow!("Big bad, no such profile")),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue