fedimint_client_module/module/
init.rs1pub mod recovery;
2
3use std::collections::{BTreeMap, BTreeSet};
4
5use fedimint_api_client::api::{DynGlobalApi, DynModuleApi};
6use fedimint_connectors::ConnectorRegistry;
7use fedimint_core::config::FederationId;
8use fedimint_core::core::ModuleKind;
9use fedimint_core::db::{Database, DatabaseVersion};
10use fedimint_core::module::{ApiAuth, ApiVersion, CommonModuleInit, ModuleInit, MultiApiVersion};
11use fedimint_core::task::TaskGroup;
12use fedimint_core::{NumPeers, apply, async_trait_maybe_send};
13use fedimint_derive_secret::DerivableSecret;
14use fedimint_logging::LOG_CLIENT;
15use tracing::warn;
16
17use super::ClientContext;
18use super::recovery::RecoveryProgress;
19use crate::db::ClientModuleMigrationFn;
20use crate::module::ClientModule;
21use crate::sm::ModuleNotifier;
22
23pub struct ClientModuleInitArgs<C>
24where
25 C: ClientModuleInit,
26{
27 pub federation_id: FederationId,
28 pub peer_num: usize,
29 pub cfg: <<C as ModuleInit>::Common as CommonModuleInit>::ClientConfig,
30 pub db: Database,
31 pub core_api_version: ApiVersion,
32 pub module_api_version: ApiVersion,
33 pub module_root_secret: DerivableSecret,
34 pub notifier: ModuleNotifier<<<C as ClientModuleInit>::Module as ClientModule>::States>,
35 pub api: DynGlobalApi,
36 pub admin_auth: Option<ApiAuth>,
37 pub module_api: DynModuleApi,
38 pub context: ClientContext<<C as ClientModuleInit>::Module>,
39 pub task_group: TaskGroup,
40 pub connector_registry: ConnectorRegistry,
41}
42
43impl<C> ClientModuleInitArgs<C>
44where
45 C: ClientModuleInit,
46{
47 pub fn federation_id(&self) -> &FederationId {
48 &self.federation_id
49 }
50
51 pub fn peer_num(&self) -> usize {
52 self.peer_num
53 }
54
55 pub fn cfg(&self) -> &<<C as ModuleInit>::Common as CommonModuleInit>::ClientConfig {
56 &self.cfg
57 }
58
59 pub fn db(&self) -> &Database {
60 &self.db
61 }
62
63 pub fn core_api_version(&self) -> &ApiVersion {
64 &self.core_api_version
65 }
66
67 pub fn module_api_version(&self) -> &ApiVersion {
68 &self.module_api_version
69 }
70
71 pub fn module_root_secret(&self) -> &DerivableSecret {
72 &self.module_root_secret
73 }
74
75 pub fn notifier(
76 &self,
77 ) -> &ModuleNotifier<<<C as ClientModuleInit>::Module as ClientModule>::States> {
78 &self.notifier
79 }
80
81 pub fn api(&self) -> &DynGlobalApi {
82 &self.api
83 }
84
85 pub fn admin_auth(&self) -> Option<&ApiAuth> {
86 self.admin_auth.as_ref()
87 }
88
89 pub fn module_api(&self) -> &DynModuleApi {
90 &self.module_api
91 }
92
93 pub fn context(&self) -> ClientContext<<C as ClientModuleInit>::Module> {
100 self.context.clone()
101 }
102
103 pub fn task_group(&self) -> &TaskGroup {
104 &self.task_group
105 }
106
107 pub fn connector_registry(&self) -> &ConnectorRegistry {
108 &self.connector_registry
109 }
110}
111
112pub struct ClientModuleRecoverArgs<C>
113where
114 C: ClientModuleInit,
115{
116 pub federation_id: FederationId,
117 pub num_peers: NumPeers,
118 pub cfg: <<C as ModuleInit>::Common as CommonModuleInit>::ClientConfig,
119 pub db: Database,
120 pub core_api_version: ApiVersion,
121 pub module_api_version: ApiVersion,
122 pub module_root_secret: DerivableSecret,
123 pub notifier: ModuleNotifier<<<C as ClientModuleInit>::Module as ClientModule>::States>,
124 pub api: DynGlobalApi,
125 pub admin_auth: Option<ApiAuth>,
126 pub module_api: DynModuleApi,
127 pub context: ClientContext<<C as ClientModuleInit>::Module>,
128 pub progress_tx: tokio::sync::watch::Sender<RecoveryProgress>,
129 pub task_group: TaskGroup,
130}
131
132impl<C> ClientModuleRecoverArgs<C>
133where
134 C: ClientModuleInit,
135{
136 pub fn federation_id(&self) -> &FederationId {
137 &self.federation_id
138 }
139
140 pub fn num_peers(&self) -> NumPeers {
141 self.num_peers
142 }
143
144 pub fn cfg(&self) -> &<<C as ModuleInit>::Common as CommonModuleInit>::ClientConfig {
145 &self.cfg
146 }
147
148 pub fn db(&self) -> &Database {
149 &self.db
150 }
151
152 pub fn task_group(&self) -> &TaskGroup {
153 &self.task_group
154 }
155
156 pub fn core_api_version(&self) -> &ApiVersion {
157 &self.core_api_version
158 }
159
160 pub fn module_api_version(&self) -> &ApiVersion {
161 &self.module_api_version
162 }
163
164 pub fn module_root_secret(&self) -> &DerivableSecret {
165 &self.module_root_secret
166 }
167
168 pub fn notifier(
169 &self,
170 ) -> &ModuleNotifier<<<C as ClientModuleInit>::Module as ClientModule>::States> {
171 &self.notifier
172 }
173
174 pub fn api(&self) -> &DynGlobalApi {
175 &self.api
176 }
177
178 pub fn admin_auth(&self) -> Option<&ApiAuth> {
179 self.admin_auth.as_ref()
180 }
181
182 pub fn module_api(&self) -> &DynModuleApi {
183 &self.module_api
184 }
185
186 pub fn context(&self) -> ClientContext<<C as ClientModuleInit>::Module> {
191 self.context.clone()
192 }
193
194 pub fn update_recovery_progress(&self, progress: RecoveryProgress) {
195 #[allow(clippy::disallowed_methods)]
197 if progress.is_done() {
198 warn!(target: LOG_CLIENT, "Module trying to send a completed recovery progress. Ignoring");
201 } else if progress.is_none() {
202 warn!(target: LOG_CLIENT, "Module trying to send a none recovery progress. Ignoring");
205 } else if self.progress_tx.send(progress).is_err() {
206 warn!(target: LOG_CLIENT, "Module trying to send a recovery progress but nothing is listening");
207 }
208 }
209}
210
211#[apply(async_trait_maybe_send!)]
212pub trait ClientModuleInit: ModuleInit + Sized {
213 type Module: ClientModule;
214
215 fn supported_api_versions(&self) -> MultiApiVersion;
218
219 fn kind() -> ModuleKind {
220 <Self::Module as ClientModule>::kind()
221 }
222
223 async fn recover(
229 &self,
230 _args: &ClientModuleRecoverArgs<Self>,
231 _snapshot: Option<&<Self::Module as ClientModule>::Backup>,
232 ) -> anyhow::Result<()> {
233 warn!(
234 target: LOG_CLIENT,
235 kind = %<Self::Module as ClientModule>::kind(),
236 "Module does not support recovery, completing without doing anything"
237 );
238 Ok(())
239 }
240
241 async fn init(&self, args: &ClientModuleInitArgs<Self>) -> anyhow::Result<Self::Module>;
243
244 fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, ClientModuleMigrationFn> {
248 BTreeMap::new()
249 }
250
251 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>> {
261 None
262 }
263}