use crate::api::Owner;
use crate::context::Context;
use crate::provider::{self, ProviderId};
use crate::state::{Key, State, new_id};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct InUse {
pub owner: Option<Owner>,
pub login: String,
pub known_at: i64,
pub named: Option<String>,
}
impl InUse {
pub(crate) fn agrees(&self, which: ProviderId, other: &InUse) -> bool {
self.account(which) == other.account(which)
&& self.login == other.login
&& self.named == other.named
}
pub fn account(&self, which: ProviderId) -> Option<String> {
self.owner.as_ref().map(|owner| new_id(which, owner))
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Identified {
pub changed: bool,
pub replaced: Option<Replaced>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Replaced {
pub key: Key,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Known {
pub last: Option<InUse>,
pub doubt: Option<Doubt>,
pub own_record: Option<Owner>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Doubt {
NeverEstablished,
NamedMoved,
LoginUnreadable,
}
impl Known {
pub fn owner(&self) -> Option<&Owner> {
self.last.as_ref()?.owner.as_ref()
}
pub(crate) fn named_another(&self, which: ProviderId) -> Option<&Owner> {
let owner = self.owner()?;
let named = self.own_record.as_ref()?;
(self.doubt.is_none() && new_id(which, named) != new_id(which, owner)).then_some(named)
}
}
pub(crate) fn known(ctx: &Context, state: &State, which: ProviderId) -> Known {
let tool = provider::of(which);
if !tool.identifies_by_itself() {
return judged(ctx, which, state.in_use(which).cloned());
}
let found = |owner: Option<Owner>, login: String| Known {
last: Some(InUse {
owner,
login,
known_at: ctx.now(),
named: None,
}),
doubt: None,
own_record: None,
};
match tool.read_live(ctx) {
Err(_) => Known {
last: state.in_use(which).cloned(),
doubt: Some(Doubt::LoginUnreadable),
own_record: None,
},
Ok(None) => found(None, String::new()),
Ok(Some(credential)) => match tool.identify(ctx, &credential) {
Ok(owner) => found(Some(Owner::from(owner)), tool.fingerprint(&credential.raw)),
Err(_) => Known {
last: None,
doubt: None,
own_record: None,
},
},
}
}
pub(crate) fn judged(ctx: &Context, which: ProviderId, last: Option<InUse>) -> Known {
let own_record = names(ctx, which);
let now = own_record.as_ref().map(|owner| new_id(which, owner));
let doubt = match &last {
None => Some(Doubt::NeverEstablished),
Some(record) if record.known_at == 0 => Some(Doubt::NeverEstablished),
Some(record) if record.named != now => Some(Doubt::NamedMoved),
Some(_) => None,
};
Known {
last,
doubt,
own_record,
}
}
pub(crate) fn names(ctx: &Context, which: ProviderId) -> Option<Owner> {
provider::of(which).own_record(ctx).map(Owner::from)
}
pub(crate) fn named(ctx: &Context, which: ProviderId) -> Option<String> {
names(ctx, which).map(|owner| new_id(which, &owner))
}
pub(crate) fn naming(which: ProviderId, owner: &Owner) -> Option<String> {
(!provider::of(which).identifies_by_itself()).then(|| new_id(which, owner))
}
#[cfg(test)]
impl InUse {
pub(crate) fn of(account: &crate::state::Account, login: &str, at: i64) -> InUse {
InUse {
owner: Some(account.owner()),
login: login.into(),
known_at: at,
named: None,
}
}
}