px_auth/infrastructure/
yaml_key_store.rs1use crate::domain::key_store::{ApiKeyRecord, KeyStore};
2use async_trait::async_trait;
3use px_errors::AppError;
4use serde::Deserialize;
5use std::collections::HashMap;
6use std::path::Path;
7
8#[derive(Debug, Deserialize)]
9struct KeysFile {
10 keys: Vec<ApiKeyRecord>,
11}
12
13pub struct YamlKeyStore {
14 by_id: HashMap<String, ApiKeyRecord>,
15}
16
17impl YamlKeyStore {
18 pub async fn load(path: impl AsRef<Path>) -> Result<Self, AppError> {
19 let bytes = tokio::fs::read(path.as_ref())
20 .await
21 .map_err(|e| AppError::InternalError(format!("read keys yaml: {e}")))?;
22 let parsed: KeysFile = serde_yaml::from_slice(&bytes)
23 .map_err(|e| AppError::InternalError(format!("parse keys yaml: {e}")))?;
24 let mut by_id = HashMap::new();
25 for k in parsed.keys {
26 by_id.insert(k.id.clone(), k);
27 }
28 Ok(Self { by_id })
29 }
30
31 pub fn from_records(records: Vec<ApiKeyRecord>) -> Self {
32 let by_id = records.into_iter().map(|r| (r.id.clone(), r)).collect();
33 Self { by_id }
34 }
35}
36
37#[async_trait]
38impl KeyStore for YamlKeyStore {
39 async fn find_by_id(&self, id: &str) -> Result<Option<ApiKeyRecord>, AppError> {
40 Ok(self.by_id.get(id).cloned())
41 }
42
43 async fn list_ids(&self) -> Result<Vec<String>, AppError> {
44 Ok(self.by_id.keys().cloned().collect())
45 }
46}