use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::keri::Said;
use crate::keri::state::KeyState;
pub const SCHEMA_VERSION: u32 = 1;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct TipInfo {
pub version: u32,
pub sequence: u128,
pub said: Said,
}
impl TipInfo {
pub fn new(sequence: u128, said: Said) -> Self {
Self {
version: SCHEMA_VERSION,
sequence,
said,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct CachedStateJson {
pub version: u32,
pub state: KeyState,
pub validated_against_said: Said,
}
impl CachedStateJson {
pub fn new(state: KeyState, validated_against_said: Said) -> Self {
Self {
version: SCHEMA_VERSION,
state,
validated_against_said,
}
}
pub fn is_valid_for(&self, tip_said: &Said) -> bool {
self.validated_against_said == *tip_said
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct RegistryMetadata {
pub version: u32,
pub identity_count: u64,
pub device_count: u64,
#[serde(default)]
pub member_count: u64,
pub updated_at: DateTime<Utc>,
}
impl RegistryMetadata {
pub fn new(
now: DateTime<Utc>,
identity_count: u64,
device_count: u64,
member_count: u64,
) -> Self {
Self {
version: SCHEMA_VERSION,
identity_count,
device_count,
member_count,
updated_at: now,
}
}
pub fn empty() -> Self {
Self {
version: SCHEMA_VERSION,
identity_count: 0,
device_count: 0,
member_count: 0,
updated_at: DateTime::<Utc>::UNIX_EPOCH,
}
}
}
impl Default for RegistryMetadata {
fn default() -> Self {
Self::empty()
}
}
#[cfg(test)]
#[allow(clippy::disallowed_methods)]
mod tests {
use super::*;
use crate::keri::{CesrKey, Prefix, Said, Threshold};
#[test]
fn tip_info_new_sets_version() {
let tip = TipInfo::new(5, Said::new_unchecked("ESaidTest123".to_string()));
assert_eq!(tip.version, SCHEMA_VERSION);
assert_eq!(tip.sequence, 5);
assert_eq!(tip.said, "ESaidTest123");
}
#[test]
fn tip_info_roundtrips() {
let tip = TipInfo::new(42, Said::new_unchecked("ETestSaid".to_string()));
let json = serde_json::to_string(&tip).unwrap();
let parsed: TipInfo = serde_json::from_str(&json).unwrap();
assert_eq!(tip, parsed);
}
#[test]
fn cached_state_is_valid_for_matching_said() {
let state = KeyState::from_inception(
Prefix::new_unchecked("EPrefix".to_string()),
vec![CesrKey::new_unchecked("DKey".to_string())],
vec![Said::new_unchecked("ENext".to_string())],
Threshold::Simple(1),
Threshold::Simple(1),
Said::new_unchecked("ESaid".to_string()),
vec![],
Threshold::Simple(0),
vec![],
);
let tip_said = Said::new_unchecked("ETipSaid".to_string());
let cached = CachedStateJson::new(state, tip_said.clone());
assert!(cached.is_valid_for(&tip_said));
let different_said = Said::new_unchecked("EDifferentSaid".to_string());
assert!(!cached.is_valid_for(&different_said));
}
#[test]
fn cached_state_roundtrips() {
let state = KeyState::from_inception(
Prefix::new_unchecked("EPrefix".to_string()),
vec![CesrKey::new_unchecked("DKey".to_string())],
vec![Said::new_unchecked("ENext".to_string())],
Threshold::Simple(1),
Threshold::Simple(1),
Said::new_unchecked("ESaid".to_string()),
vec![],
Threshold::Simple(0),
vec![],
);
let cached =
CachedStateJson::new(state.clone(), Said::new_unchecked("ETipSaid".to_string()));
let json = serde_json::to_string(&cached).unwrap();
let parsed: CachedStateJson = serde_json::from_str(&json).unwrap();
assert_eq!(cached.version, parsed.version);
assert_eq!(cached.state, parsed.state);
assert_eq!(cached.validated_against_said, parsed.validated_against_said);
}
#[test]
fn registry_metadata_new_sets_given_time() {
let now = Utc::now();
let meta = RegistryMetadata::new(now, 10, 20, 5);
assert_eq!(meta.version, SCHEMA_VERSION);
assert_eq!(meta.identity_count, 10);
assert_eq!(meta.device_count, 20);
assert_eq!(meta.member_count, 5);
assert_eq!(meta.updated_at, now);
}
#[test]
fn registry_metadata_empty_has_zero_counts() {
let meta = RegistryMetadata::empty();
assert_eq!(meta.identity_count, 0);
assert_eq!(meta.device_count, 0);
assert_eq!(meta.member_count, 0);
}
#[test]
fn registry_metadata_roundtrips() {
let meta = RegistryMetadata::new(Utc::now(), 100, 500, 25);
let json = serde_json::to_string(&meta).unwrap();
let parsed: RegistryMetadata = serde_json::from_str(&json).unwrap();
assert_eq!(meta, parsed);
}
}