use glacier_ui::ContextMap;
use std::sync::{Arc, RwLock};
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct Session {
pub base_url: String,
pub token: Option<String>,
}
#[derive(Default)]
struct Espelho {
session: Option<Session>,
context: ContextMap,
}
#[derive(Clone, Default)]
pub(crate) struct SharedSession(Arc<RwLock<Espelho>>);
impl SharedSession {
pub(crate) fn get(&self) -> Option<Session> {
self.0.read().ok().and_then(|g| g.session.clone())
}
pub(crate) fn context_key(&self, key: &str) -> Option<String> {
self.0.read().ok().and_then(|g| g.context.get(key).cloned())
}
pub(crate) fn context(&self) -> ContextMap {
self.0.read().map(|g| g.context.clone()).unwrap_or_default()
}
pub(crate) fn sync_from_context(&self, ctx: &ContextMap) -> bool {
let nova = Session::from_context(ctx);
match self.0.write() {
Ok(mut e) => {
let mudou = e.session != nova;
e.session = nova;
e.context = ctx.clone();
mudou
}
Err(_) => false,
}
}
}
impl Session {
fn from_context(ctx: &ContextMap) -> Option<Self> {
if ctx.get("connected").map(String::as_str) != Some("true") {
return None;
}
let base_url = ctx.get("api_url")?.trim().trim_end_matches('/').to_string();
if base_url.is_empty() {
return None;
}
let token = ctx
.get("api_token")
.map(|t| t.trim())
.filter(|t| !t.is_empty())
.map(str::to_owned);
Some(Self { base_url, token })
}
}
#[cfg(test)]
mod tests {
use super::*;
fn ctx(pares: &[(&str, &str)]) -> ContextMap {
pares
.iter()
.map(|(k, v)| ((*k).to_string(), (*v).to_string()))
.collect()
}
#[test]
fn sem_conexao_nao_ha_sessao() {
let s = SharedSession::default();
s.sync_from_context(&ctx(&[("api_url", "https://x.dev"), ("api_token", "t")]));
assert!(s.get().is_none());
}
#[test]
fn conexao_valida_vira_sessao_com_a_barra_final_aparada() {
let s = SharedSession::default();
assert!(s.sync_from_context(&ctx(&[
("connected", "true"),
("api_url", "https://rustploy.exemplo.com/"),
("api_token", " segredo "),
])));
let sess = s.get().unwrap();
assert_eq!(sess.base_url, "https://rustploy.exemplo.com");
assert_eq!(sess.token.as_deref(), Some("segredo"));
}
#[test]
fn daemon_sem_token_vira_sessao_sem_token() {
let s = SharedSession::default();
s.sync_from_context(&ctx(&[
("connected", "true"),
("api_url", "http://127.0.0.1:9797"),
("api_token", ""),
]));
assert_eq!(s.get().unwrap().token, None);
}
#[test]
fn contexto_repetido_nao_conta_como_mudanca() {
let s = SharedSession::default();
let c = ctx(&[
("connected", "true"),
("api_url", "https://x.dev"),
("api_token", "t"),
]);
assert!(s.sync_from_context(&c));
assert!(!s.sync_from_context(&c));
}
#[test]
fn logout_derruba_a_sessao() {
let s = SharedSession::default();
s.sync_from_context(&ctx(&[
("connected", "true"),
("api_url", "https://x.dev"),
("api_token", "t"),
]));
assert!(s.get().is_some());
assert!(s.sync_from_context(&ctx(&[("connected", "false")])));
assert!(s.get().is_none());
}
#[test]
fn trocar_de_servidor_troca_o_alvo() {
let s = SharedSession::default();
s.sync_from_context(&ctx(&[
("connected", "true"),
("api_url", "https://a.dev"),
("api_token", "ta"),
]));
assert!(s.sync_from_context(&ctx(&[
("connected", "true"),
("api_url", "https://b.dev"),
("api_token", "tb"),
])));
assert_eq!(s.get().unwrap().base_url, "https://b.dev");
}
}