fedimint_client_module/module/
init.rspub mod recovery;
use std::collections::BTreeMap;
use fedimint_api_client::api::{DynGlobalApi, DynModuleApi};
use fedimint_core::config::FederationId;
use fedimint_core::core::ModuleKind;
use fedimint_core::db::{Database, DatabaseVersion};
use fedimint_core::module::{ApiAuth, ApiVersion, CommonModuleInit, ModuleInit, MultiApiVersion};
use fedimint_core::task::TaskGroup;
use fedimint_core::{apply, async_trait_maybe_send, NumPeers};
use fedimint_derive_secret::DerivableSecret;
use fedimint_logging::LOG_CLIENT;
use tracing::warn;
use super::recovery::RecoveryProgress;
use super::ClientContext;
use crate::db::ClientMigrationFn;
use crate::module::ClientModule;
use crate::sm::ModuleNotifier;
pub struct ClientModuleInitArgs<C>
where
C: ClientModuleInit,
{
pub federation_id: FederationId,
pub peer_num: usize,
pub cfg: <<C as ModuleInit>::Common as CommonModuleInit>::ClientConfig,
pub db: Database,
pub core_api_version: ApiVersion,
pub module_api_version: ApiVersion,
pub module_root_secret: DerivableSecret,
pub notifier: ModuleNotifier<<<C as ClientModuleInit>::Module as ClientModule>::States>,
pub api: DynGlobalApi,
pub admin_auth: Option<ApiAuth>,
pub module_api: DynModuleApi,
pub context: ClientContext<<C as ClientModuleInit>::Module>,
pub task_group: TaskGroup,
}
impl<C> ClientModuleInitArgs<C>
where
C: ClientModuleInit,
{
pub fn federation_id(&self) -> &FederationId {
&self.federation_id
}
pub fn peer_num(&self) -> usize {
self.peer_num
}
pub fn cfg(&self) -> &<<C as ModuleInit>::Common as CommonModuleInit>::ClientConfig {
&self.cfg
}
pub fn db(&self) -> &Database {
&self.db
}
pub fn core_api_version(&self) -> &ApiVersion {
&self.core_api_version
}
pub fn module_api_version(&self) -> &ApiVersion {
&self.module_api_version
}
pub fn module_root_secret(&self) -> &DerivableSecret {
&self.module_root_secret
}
pub fn notifier(
&self,
) -> &ModuleNotifier<<<C as ClientModuleInit>::Module as ClientModule>::States> {
&self.notifier
}
pub fn api(&self) -> &DynGlobalApi {
&self.api
}
pub fn admin_auth(&self) -> Option<&ApiAuth> {
self.admin_auth.as_ref()
}
pub fn module_api(&self) -> &DynModuleApi {
&self.module_api
}
pub fn context(&self) -> ClientContext<<C as ClientModuleInit>::Module> {
self.context.clone()
}
pub fn task_group(&self) -> &TaskGroup {
&self.task_group
}
}
pub struct ClientModuleRecoverArgs<C>
where
C: ClientModuleInit,
{
pub federation_id: FederationId,
pub num_peers: NumPeers,
pub cfg: <<C as ModuleInit>::Common as CommonModuleInit>::ClientConfig,
pub db: Database,
pub core_api_version: ApiVersion,
pub module_api_version: ApiVersion,
pub module_root_secret: DerivableSecret,
pub notifier: ModuleNotifier<<<C as ClientModuleInit>::Module as ClientModule>::States>,
pub api: DynGlobalApi,
pub admin_auth: Option<ApiAuth>,
pub module_api: DynModuleApi,
pub context: ClientContext<<C as ClientModuleInit>::Module>,
pub progress_tx: tokio::sync::watch::Sender<RecoveryProgress>,
pub task_group: TaskGroup,
}
impl<C> ClientModuleRecoverArgs<C>
where
C: ClientModuleInit,
{
pub fn federation_id(&self) -> &FederationId {
&self.federation_id
}
pub fn num_peers(&self) -> NumPeers {
self.num_peers
}
pub fn cfg(&self) -> &<<C as ModuleInit>::Common as CommonModuleInit>::ClientConfig {
&self.cfg
}
pub fn db(&self) -> &Database {
&self.db
}
pub fn task_group(&self) -> &TaskGroup {
&self.task_group
}
pub fn core_api_version(&self) -> &ApiVersion {
&self.core_api_version
}
pub fn module_api_version(&self) -> &ApiVersion {
&self.module_api_version
}
pub fn module_root_secret(&self) -> &DerivableSecret {
&self.module_root_secret
}
pub fn notifier(
&self,
) -> &ModuleNotifier<<<C as ClientModuleInit>::Module as ClientModule>::States> {
&self.notifier
}
pub fn api(&self) -> &DynGlobalApi {
&self.api
}
pub fn admin_auth(&self) -> Option<&ApiAuth> {
self.admin_auth.as_ref()
}
pub fn module_api(&self) -> &DynModuleApi {
&self.module_api
}
pub fn context(&self) -> ClientContext<<C as ClientModuleInit>::Module> {
self.context.clone()
}
pub fn update_recovery_progress(&self, progress: RecoveryProgress) {
if progress.is_done() {
warn!(target: LOG_CLIENT, "Module trying to send a completed recovery progress. Ignoring");
} else if progress.is_none() {
warn!(target: LOG_CLIENT, "Module trying to send a none recovery progress. Ignoring");
} else if self.progress_tx.send(progress).is_err() {
warn!(target: LOG_CLIENT, "Module trying to send a recovery progress but nothing is listening");
}
}
}
#[apply(async_trait_maybe_send!)]
pub trait ClientModuleInit: ModuleInit + Sized {
type Module: ClientModule;
fn supported_api_versions(&self) -> MultiApiVersion;
fn kind() -> ModuleKind {
<Self::Module as ClientModule>::kind()
}
async fn recover(
&self,
_args: &ClientModuleRecoverArgs<Self>,
_snapshot: Option<&<Self::Module as ClientModule>::Backup>,
) -> anyhow::Result<()> {
warn!(
target: LOG_CLIENT,
kind = %<Self::Module as ClientModule>::kind(),
"Module does not support recovery, completing without doing anything"
);
Ok(())
}
async fn init(&self, args: &ClientModuleInitArgs<Self>) -> anyhow::Result<Self::Module>;
fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, ClientMigrationFn> {
BTreeMap::new()
}
}