tangled.org trending bluesky account
at main 4.0 kB view raw
1mod resolver; 2use crate::resolver::ApiDNSTxtResolver; 3use atrium_api::agent::Configure; 4use atrium_api::types::string::{Did, Handle}; 5use atrium_common::resolver::Resolver; 6use atrium_identity::did::{CommonDidResolver, CommonDidResolverConfig, DEFAULT_PLC_DIRECTORY_URL}; 7use atrium_identity::handle::{AtprotoHandleResolver, AtprotoHandleResolverConfig}; 8use atrium_oauth::DefaultHttpClient; 9use bsky_sdk::BskyAgent; 10use std::sync::Arc; 11use thiserror::Error; 12 13#[derive(Debug, Error)] 14pub enum Error { 15 #[error("General error: {0}")] 16 GeneralError(String), 17 #[error("Login error: {0}")] 18 LoginError(String), 19 #[error("Write error: {0}")] 20 WriteError(String), 21 #[error("Request error: {0}")] 22 RequestError(String), 23 #[error("Authentication required")] 24 NeedsAuthentication, 25 #[error("Parse error: {0}")] 26 ParseError(String), 27 #[error("Jet stream: {0}")] 28 JetstreamError(String), 29} 30 31#[derive(Clone)] 32pub struct BotApi { 33 pub agent: Arc<BskyAgent>, 34 handle_resolver: Arc<AtprotoHandleResolver<ApiDNSTxtResolver, DefaultHttpClient>>, 35 did_resolver: Arc<CommonDidResolver<DefaultHttpClient>>, 36} 37 38impl BotApi { 39 pub async fn new_logged_in( 40 handle: String, 41 password: String, 42 pds_url: String, 43 ) -> Result<Self, Error> { 44 // let session = get_new_session(pds_url); 45 // if let Err(error) = session.login(&handle, &password).await { 46 // return Err(Error::LoginError(error.to_string())); 47 // } 48 49 let agent = BskyAgent::builder() 50 .build() 51 .await 52 .expect("Failed to build agent"); 53 agent.configure_endpoint(pds_url); 54 // let agent = Agent::new(session); 55 agent 56 .login(handle, password) 57 .await 58 .expect("Failed to login"); 59 let handle_resolver = AtprotoHandleResolver::new(AtprotoHandleResolverConfig { 60 dns_txt_resolver: ApiDNSTxtResolver::default(), 61 http_client: Arc::new(DefaultHttpClient::default()), 62 }); 63 64 let did_resolver = CommonDidResolver::new(CommonDidResolverConfig { 65 plc_directory_url: DEFAULT_PLC_DIRECTORY_URL.to_string(), 66 http_client: Arc::new(DefaultHttpClient::default()), 67 }); 68 69 Ok(Self { 70 agent: Arc::new(agent), 71 handle_resolver: Arc::new(handle_resolver), 72 did_resolver: Arc::new(did_resolver), 73 }) 74 } 75 76 ///Takes a users handle like @baileytownsend.dev and resolves it ot the did 77 pub async fn resolve_handle(&self, handle: String) -> Result<Did, Error> { 78 let handle = Handle::new(handle).map_err(|e| Error::ParseError(e.to_string()))?; 79 self.handle_resolver 80 .resolve(&handle) 81 .await 82 .map_err(|e| Error::RequestError(e.to_string())) 83 } 84 85 /// Takes a did and returns a handle 86 pub async fn get_handle(&self, did: String) -> Result<String, Error> { 87 let did = Did::new(did).map_err(|e| Error::ParseError(e.to_string()))?; 88 match self.did_resolver.resolve(&did).await { 89 Ok(did_doc) => { 90 match did_doc.also_known_as { 91 None => Err(Error::ParseError( 92 "No also_known_as field found".to_string(), 93 ))?, 94 Some(also_known_as) => { 95 match also_known_as.is_empty() { 96 true => Err(Error::ParseError("also_known_as is empty".to_string()))?, 97 false => { 98 //also_known as a list starts the array with the highest priority handle 99 let formatted_handle = 100 format!("{}", also_known_as[0]).replace("at://", ""); 101 Ok(formatted_handle) 102 } 103 } 104 } 105 } 106 } 107 Err(err) => Err(Error::ParseError(err.to_string()))?, 108 } 109 } 110}