Something went wrong. Try again.
🌤 Track the weather for event days wed.fyi
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111use anyhow::{anyhow, Result};use jacquard::{ client::{AgentSessionExt, FileAuthStore}, common::{ deps::{fluent_uri::Uri, smol_str::SmolStr}, session::SessionHint, }, identity::JacquardResolver, oauth::{ atproto::AtprotoClientMetadata, client::OAuthClient, loopback::{LoopbackConfig, LoopbackPort}, scopes::Scopes, session::ClientData, types::AuthorizeOptions, },};use reqwest::Client;use std::path::PathBuf;
use shared::{ atproto::{lexicon::event, AtprotoClient}, event::Event,};
pub const CLIENT_SCOPES: &str = "atproto repo:fyi.wed.event";
const REDIRECT_URI: &str = "http://127.0.0.1/callback";
pub struct WedOAuth(OAuthClient<JacquardResolver<Client>, FileAuthStore>);
fn auth_path() -> Result<PathBuf> { let home = home::home_dir().ok_or_else(|| anyhow!("could not find home directory"))?; Ok(home.join(".wed-auth.json"))}
fn loopback_config() -> LoopbackConfig { LoopbackConfig { port: LoopbackPort::Ephemeral, ..Default::default() }}
fn client_data(app_url: &str) -> Result<ClientData<SmolStr>> { let client_id = Uri::parse(format!("{app_url}/cli-metadata.json")) .map_err(|(e, _)| anyhow!("invalid client id: {e}"))?; let redirect = Uri::parse(REDIRECT_URI.to_string()).map_err(|(e, _)| anyhow!("invalid redirect: {e}"))?; let scopes = Scopes::new(SmolStr::new(CLIENT_SCOPES)).map_err(|e| anyhow!("invalid scopes: {e}"))?; let config = AtprotoClientMetadata::new(vec![redirect], client_id, Some(scopes)); Ok(ClientData { keyset: None, config, })}
pub fn oauth(app_url: &str) -> Result<WedOAuth> { let store = FileAuthStore::new(&auth_path()?); Ok(WedOAuth(OAuthClient::new( store, client_data(app_url)?, Client::new(), )))}
pub async fn login(handler: &str, app_url: &str) -> Result<()> { oauth(app_url)? .0 .login_with_local_server(handler, AuthorizeOptions::default(), loopback_config()) .await .map_err(|e| anyhow!("OAuth login failed: {e}"))?; Ok(())}
pub async fn resume(app_url: &str) -> Result<WedOAuth> { let oauth = oauth(app_url)?; let hint = SessionHint::from_optional_input(None); let session = oauth .0 .resume_or_login_with_local_server(&hint, AuthorizeOptions::default(), loopback_config()) .await .map_err(|e| anyhow!("OAuth session resume failed: {e}"))?; session.ok_or_else(|| anyhow!("No AT Protocol auth found. Run `wed auth` first."))?; Ok(oauth)}
impl AtprotoClient for WedOAuth { async fn create_event(&self, event: &Event) -> Result<String> { let record = event.to_record()?; let output = self .0 .create_record(record, None) .await .map_err(|e| anyhow!("createRecord: {e}"))?; Ok(output.uri.as_str().to_string()) }
async fn delete_event(&self, rkey: &str) -> Result<()> { let rkey: jacquard_common::types::recordkey::RecordKey< jacquard_common::types::recordkey::Rkey<jacquard_common::DefaultStr>, > = rkey.parse()?; self.0 .delete_record::<event::Event>(rkey) .await .map_err(|e| anyhow!("deleteRecord: {e}"))?; Ok(()) }}