use std::{ collections::HashMap, sync::{Arc, OnceLock}, }; use axum::{extract::State, Extension, Json}; use jmap_proto::{ common::{Id, SessionState}, endpoints::session::{Account, AccountCapabilities, Session}, }; use oxide_auth::primitives::grant::Grant; use crate::{ context::Context, store::{AccountProvider, UserProvider}, }; static API_URL: OnceLock> = OnceLock::new(); static DOWNLOAD_URL: OnceLock> = OnceLock::new(); static UPLOAD_URL: OnceLock> = OnceLock::new(); static EVENT_SOURCE_URL: OnceLock> = OnceLock::new(); pub async fn get( State(context): State>, Extension(grant): Extension, ) -> Json> { let username = grant.owner_id; let user = context .store .get_by_username(&username) .await .unwrap() .unwrap(); let (accounts, user_seq_number) = tokio::join!( async { context .store .get_accounts_for_user(user.id) .await .unwrap() .into_iter() .map(|acc| { ( Id(acc.id.to_string().into()), Account { name: acc.name.into(), is_personal: acc.is_personal, is_read_only: acc.is_read_only, account_capabilities: AccountCapabilities {}, }, ) }) .collect() }, async { context .store .fetch_seq_number_for_user(user.id) .await .unwrap() } ); Json(Session { capabilities: context .extension_registry .build_session_capabilities(user.id), accounts, primary_accounts: HashMap::default(), username: username.into(), api_url: API_URL .get_or_init(|| { context .base_url .join("api/") .unwrap() .to_string() .into_boxed_str() }) .as_ref() .into(), download_url: DOWNLOAD_URL .get_or_init(|| { let base = context.base_url.join("download/").unwrap(); format!("{base}{{accountId}}/{{blobId}}/{{name}}?accept={{type}}").into_boxed_str() }) .as_ref() .into(), upload_url: UPLOAD_URL .get_or_init(|| { let base = context.base_url.join("upload/").unwrap(); format!("{base}{{accountId}}/").into_boxed_str() }) .as_ref() .into(), event_source_url: EVENT_SOURCE_URL .get_or_init(|| { context .base_url .join("eventsource/?types={types}&closeafter={closeafter}&ping={ping}") .unwrap() .to_string() .into_boxed_str() }) .as_ref() .into(), state: SessionState(user_seq_number.to_string().into()), }) }