pub mod link;
pub mod store;
#[cfg(feature = "voting")]
pub mod ops;
#[cfg(feature = "voting")]
pub mod sweeper;
use std::sync::Arc;
use serde::{Deserialize, Serialize};
use crate::store::KeyspaceHandle;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VotingConfig {
#[serde(default)]
pub trusted_ballot_boxes: Vec<TrustedBallotBox>,
}
impl VotingConfig {
pub fn is_empty(&self) -> bool {
self.trusted_ballot_boxes.is_empty()
}
#[must_use]
pub fn trusted(&self, did: &str) -> Option<&TrustedBallotBox> {
self.trusted_ballot_boxes.iter().find(|b| b.did == did)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TrustedBallotBox {
pub did: String,
pub operator: String,
pub same_operator: bool,
}
pub struct Elections {
ks: KeyspaceHandle,
link: Option<Arc<dyn link::BallotBoxChannel>>,
#[cfg(feature = "voting")]
registrar: tokio::sync::OnceCell<Arc<vti_voting::registrar::Registrar>>,
issue_lock: tokio::sync::Mutex<()>,
}
impl std::fmt::Debug for Elections {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Elections")
.field("link", &self.link.is_some())
.finish_non_exhaustive()
}
}
impl Elections {
pub fn new(ks: KeyspaceHandle, link: Option<Arc<dyn link::BallotBoxChannel>>) -> Self {
Self {
ks,
link,
#[cfg(feature = "voting")]
registrar: tokio::sync::OnceCell::new(),
issue_lock: tokio::sync::Mutex::new(()),
}
}
pub fn ks(&self) -> &KeyspaceHandle {
&self.ks
}
pub fn link(&self) -> Option<&Arc<dyn link::BallotBoxChannel>> {
self.link.as_ref()
}
pub async fn close_issuance_after_restore(
&self,
now: chrono::DateTime<chrono::Utc>,
) -> Result<Vec<String>, crate::error::AppError> {
let _guard = self.issue_lock.lock().await;
let mut closed = Vec::new();
for mut rec in store::all(&self.ks).await? {
let issuing = matches!(
rec.standing,
store::Standing::PendingRegistration | store::Standing::Registered
) && !rec.issuance_stopped
&& rec.issuance_closed_by_restore.is_none()
&& now >= rec.registration_opens
&& now < rec.voting_closes;
if issuing {
rec.issuance_closed_by_restore = Some(now);
store::put(&self.ks, &rec).await?;
closed.push(rec.election_id);
}
}
Ok(closed)
}
pub async fn carry_tickets(
&self,
from: &str,
to: &str,
) -> Result<tokio::sync::MutexGuard<'_, ()>, crate::error::AppError> {
let guard = self.issue_lock.lock().await;
store::carry_tickets(&self.ks, from, to).await?;
Ok(guard)
}
}