1#[cfg(feature = "node")]
12pub mod bootstrap;
13#[cfg(feature = "node")]
14pub mod cli_args;
15#[cfg(feature = "node")]
16pub mod database;
17#[cfg(feature = "node")]
18pub mod module_db;
19#[cfg(feature = "node")]
20pub mod storage;
21
22#[cfg(feature = "wasm-modules")]
23pub mod wasm;
24
25#[cfg(feature = "node")]
37#[macro_export]
38macro_rules! run_module_main {
39 ($module_type:ty) => {
40 #[tokio::main]
41 async fn main() -> Result<(), Box<dyn std::error::Error>> {
42 let bootstrap = $crate::module::ModuleBootstrap::from_env()?;
43 blvm_node::utils::init_module_logging(
44 <$module_type as $crate::module::ModuleMeta>::MODULE_NAME
45 .replace('-', "_")
46 .as_str(),
47 None,
48 );
49 let db = $crate::module::ModuleDb::open(&bootstrap.data_dir)?;
50 db.run_migrations(<$module_type as $crate::module::ModuleMeta>::migrations())?;
51 let config = <<$module_type as $crate::module::ModuleMeta>::Config>::load(
52 bootstrap.data_dir.join("config.toml"),
53 )
54 .unwrap_or_default();
55 let module = <$module_type as $crate::module::ModuleMeta>::__module_new(config);
56 $crate::run_module! {
57 bootstrap: &bootstrap,
58 module_name: <$module_type as $crate::module::ModuleMeta>::MODULE_NAME,
59 module: module,
60 module_type: $module_type,
61 db: db.as_db(),
62 }?;
63 Ok(())
64 }
65 };
66 (
67 $module_name:expr,
68 $module_type:ty,
69 $config_type:ty,
70 $migrations:expr,
71 ) => {
72 #[tokio::main]
73 async fn main() -> Result<(), Box<dyn std::error::Error>> {
74 blvm_node::utils::init_module_logging($module_name.replace('-', "_").as_str(), None);
75 let bootstrap = $crate::module::ModuleBootstrap::from_env()?;
76 let db = $crate::module::ModuleDb::open(&bootstrap.data_dir)?;
77 db.run_migrations($migrations)?;
78 let config =
79 <$config_type>::load(bootstrap.data_dir.join("config.toml")).unwrap_or_default();
80 let module = <$module_type>::__module_new(config);
81 $crate::run_module! {
82 bootstrap: &bootstrap,
83 module_name: $module_name,
84 module: module,
85 module_type: $module_type,
86 db: db.as_db(),
87 }?;
88 Ok(())
89 }
90 };
91}
92
93#[cfg(feature = "node")]
100#[macro_export]
101macro_rules! migrations {
102 ($($v:literal => $up:ident),* $(,)?) => {
103 &[$(($v, $up as $crate::module::MigrationUp)),*]
104 };
105}
106
107#[cfg(feature = "node")]
140#[macro_export]
141macro_rules! run_module {
142 (
143 bootstrap: $bootstrap:expr,
144 module_name: $module_name:expr,
145 module: $module:expr,
146 module_type: $module_type:ty,
147 db: $db:expr,
148 ) => {{
149 let __bootstrap = $bootstrap;
150 let __module = $module;
151 $crate::run_module! {
152 socket_path: __bootstrap.socket_path.clone(),
153 module_id: &__bootstrap.module_id,
154 module_name: $module_name,
155 version: env!("CARGO_PKG_VERSION"),
156 cli: __module.clone(),
157 cli_type: $module_type,
158 module_type: $module_type,
159 module: __module,
160 db: $db,
161 }
162 }};
163 (
164 bootstrap: $bootstrap:expr,
165 module_name: $module_name:expr,
166 module_type: $module_type:ty,
167 cli_type: $cli_type:ty,
168 db: $db:expr,
169 setup: $setup:expr,
170 event_types: $event_types:expr,
171 ) => {{
172 let __bootstrap = $bootstrap;
173 let __db = Arc::clone(&$db);
174 $crate::run_module! {
175 socket_path: __bootstrap.socket_path.clone(),
176 module_id: &__bootstrap.module_id,
177 module_name: $module_name,
178 version: env!("CARGO_PKG_VERSION"),
179 module_type: $module_type,
180 cli_type: $cli_type,
181 db: __db,
182 setup: $setup,
183 event_types: $event_types,
184 on_event: |e, m: &$module_type, ctx| {
185 let m = m.clone();
186 let ctx = ctx.clone();
187 async move { m.dispatch_event(e, &ctx).await }
188 },
189 data_dir: __bootstrap.data_dir.as_path(),
190 }
191 }};
192 (
193 bootstrap: $bootstrap:expr,
194 module_name: $module_name:expr,
195 module_type: $module_type:ty,
196 cli_type: $cli_type:ty,
197 db: $db:expr,
198 setup: $setup:expr,
199 event_types: $event_types:expr,
200 on_event: $on_event:expr,
201 ) => {{
202 let __bootstrap = $bootstrap;
203 let __db = Arc::clone(&$db);
204 $crate::run_module! {
205 socket_path: __bootstrap.socket_path.clone(),
206 module_id: &__bootstrap.module_id,
207 module_name: $module_name,
208 version: env!("CARGO_PKG_VERSION"),
209 module_type: $module_type,
210 cli_type: $cli_type,
211 db: __db,
212 setup: $setup,
213 event_types: $event_types,
214 on_event: $on_event,
215 data_dir: __bootstrap.data_dir.as_path(),
216 }
217 }};
218 (
219 socket_path: $socket_path:expr,
220 module_id: $module_id:expr,
221 module_name: $module_name:expr,
222 version: $version:expr,
223 module_type: $module_type:ty,
224 cli_type: $cli_type:ty,
225 db: $db:expr,
226 setup: $setup:expr,
227 event_types: $event_types:expr,
228 on_event: $on_event:expr,
229 data_dir: $data_dir:expr,
230 ) => {{
231 use blvm_node::module::ipc::protocol::{
232 InvocationMessage, InvocationResultMessage, InvocationResultPayload, InvocationType,
233 };
234 use std::sync::Arc;
235 use $crate::module::runner::{run_module_with_setup, InvocationContext};
236
237 let db = Arc::clone(&$db);
238
239 let dispatch = |invocation: InvocationMessage,
240 ctx: InvocationContext,
241 module: &$module_type,
242 cli: &$cli_type| {
243 let (success, payload, error) = match &invocation.invocation_type {
244 InvocationType::Cli { subcommand, args } => {
245 let args: Vec<String> = args.clone();
246 match cli.dispatch_cli(&ctx, subcommand, &args) {
247 Ok(stdout) => (
248 true,
249 Some(InvocationResultPayload::Cli {
250 stdout,
251 stderr: String::new(),
252 exit_code: 0,
253 }),
254 None,
255 ),
256 Err(e) => (false, None, Some(e.to_string())),
257 }
258 }
259 InvocationType::Rpc { method, params } => {
260 let db_ref = ctx.db();
261 match module.dispatch_rpc(method, params, db_ref) {
262 Ok(v) => (true, Some(InvocationResultPayload::Rpc(v)), None),
263 Err(e) => (false, None, Some(e.to_string())),
264 }
265 }
266 InvocationType::ModuleApi { .. } => (
267 false,
268 None,
269 Some("ModuleApi is not supported by run_module!; use run_module_with_setup_and_api".to_string()),
270 ),
271 };
272 InvocationResultMessage {
273 correlation_id: invocation.correlation_id,
274 success,
275 payload,
276 error,
277 }
278 };
279
280 let rpc_names = <$module_type>::rpc_method_names();
281 let cli_spec = <$cli_type>::cli_spec();
282
283 run_module_with_setup(
284 $socket_path,
285 $module_id,
286 $module_name,
287 $version,
288 cli_spec,
289 rpc_names.as_slice(),
290 $event_types,
291 dispatch,
292 $on_event,
293 $setup,
294 db,
295 $data_dir,
296 )
297 .await
298 }};
299 (
300 socket_path: $socket_path:expr,
301 module_id: $module_id:expr,
302 module_name: $module_name:expr,
303 version: $version:expr,
304 cli: $cli:expr,
305 cli_type: $cli_type:ty,
306 module_type: $module_type:ty,
307 module: $module:expr,
308 db: $db:expr,
309 ) => {{
310 use blvm_node::module::ipc::protocol::{
311 InvocationMessage, InvocationResultMessage, InvocationResultPayload, InvocationType,
312 };
313 use std::sync::Arc;
314 use $crate::module::runner::{run_module as run_module_fn, InvocationContext};
315
316 let cli = $cli;
317 let module = Arc::new($module);
318 let db = Arc::clone(&$db);
319
320 let dispatch = |invocation: InvocationMessage,
321 ctx: InvocationContext,
322 module: &Arc<$module_type>,
323 cli: &$cli_type| {
324 let (success, payload, error) = match &invocation.invocation_type {
325 InvocationType::Cli { subcommand, args } => {
326 let args: Vec<String> = args.clone();
327 match cli.dispatch_cli(&ctx, subcommand, &args) {
328 Ok(stdout) => (
329 true,
330 Some(InvocationResultPayload::Cli {
331 stdout,
332 stderr: String::new(),
333 exit_code: 0,
334 }),
335 None,
336 ),
337 Err(e) => (false, None, Some(e.to_string())),
338 }
339 }
340 InvocationType::Rpc { method, params } => {
341 let db_ref = ctx.db();
342 match module.dispatch_rpc(method, params, db_ref) {
343 Ok(v) => (true, Some(InvocationResultPayload::Rpc(v)), None),
344 Err(e) => (false, None, Some(e.to_string())),
345 }
346 }
347 InvocationType::ModuleApi { .. } => (
348 false,
349 None,
350 Some("ModuleApi is not supported by run_module!; use run_module_with_setup_and_api".to_string()),
351 ),
352 };
353 InvocationResultMessage {
354 correlation_id: invocation.correlation_id,
355 success,
356 payload,
357 error,
358 }
359 };
360
361 let rpc_names = <$module_type>::rpc_method_names();
362 let cli_spec = <$cli_type>::cli_spec();
363
364 run_module_fn(
365 $socket_path,
366 $module_id,
367 $module_name,
368 $version,
369 cli_spec,
370 rpc_names.as_slice(),
371 <$module_type>::event_types(),
372 dispatch,
373 |e, m: &Arc<$module_type>, ctx: &InvocationContext| {
374 let m = std::sync::Arc::clone(m);
375 let ctx = ctx.clone();
376 async move { m.dispatch_event(e, &ctx).await }
377 },
378 module,
379 cli,
380 db,
381 )
382 .await
383 }};
384 (
385 bootstrap: $bootstrap:expr,
386 module_name: $module_name:expr,
387 module: $module:expr,
388 module_type: $module_type:ty,
389 db: $db:expr,
390 on_connect: $on_connect:expr,
391 on_tick: $on_tick:expr,
392 ) => {{
393 let __bootstrap = $bootstrap;
394 let __module = $module;
395 $crate::run_module! {
396 socket_path: __bootstrap.socket_path.clone(),
397 module_id: &__bootstrap.module_id,
398 module_name: $module_name,
399 version: env!("CARGO_PKG_VERSION"),
400 cli: __module.clone(),
401 cli_type: $module_type,
402 module_type: $module_type,
403 module: __module,
404 db: $db,
405 on_connect: Some($on_connect),
406 on_tick: Some($on_tick),
407 }
408 }};
409 (
410 socket_path: $socket_path:expr,
411 module_id: $module_id:expr,
412 module_name: $module_name:expr,
413 version: $version:expr,
414 cli: $cli:expr,
415 cli_type: $cli_type:ty,
416 module_type: $module_type:ty,
417 module: $module:expr,
418 db: $db:expr,
419 on_connect: $on_connect:expr,
420 on_tick: $on_tick:expr,
421 ) => {{
422 use blvm_node::module::ipc::protocol::{
423 InvocationMessage, InvocationResultMessage, InvocationResultPayload, InvocationType,
424 };
425 use std::sync::Arc;
426 use $crate::module::runner::{run_module_with_tick, InvocationContext};
427
428 let cli = $cli;
429 let module = Arc::new($module);
430 let db = Arc::clone(&$db);
431
432 let dispatch = |invocation: InvocationMessage,
433 ctx: InvocationContext,
434 module: &Arc<$module_type>,
435 cli: &$cli_type| {
436 let (success, payload, error) = match &invocation.invocation_type {
437 InvocationType::Cli { subcommand, args } => {
438 let args: Vec<String> = args.clone();
439 match cli.dispatch_cli(&ctx, subcommand, &args) {
440 Ok(stdout) => (
441 true,
442 Some(InvocationResultPayload::Cli {
443 stdout,
444 stderr: String::new(),
445 exit_code: 0,
446 }),
447 None,
448 ),
449 Err(e) => (false, None, Some(e.to_string())),
450 }
451 }
452 InvocationType::Rpc { method, params } => {
453 let db_ref = ctx.db();
454 match module.dispatch_rpc(method, params, db_ref) {
455 Ok(v) => (true, Some(InvocationResultPayload::Rpc(v)), None),
456 Err(e) => (false, None, Some(e.to_string())),
457 }
458 }
459 InvocationType::ModuleApi { .. } => (
460 false,
461 None,
462 Some("ModuleApi is not supported by run_module!; use run_module_with_setup_and_api".to_string()),
463 ),
464 };
465 InvocationResultMessage {
466 correlation_id: invocation.correlation_id,
467 success,
468 payload,
469 error,
470 }
471 };
472
473 let rpc_names = <$module_type>::rpc_method_names();
474 let cli_spec = <$cli_type>::cli_spec();
475
476 run_module_with_tick(
477 $socket_path,
478 $module_id,
479 $module_name,
480 $version,
481 cli_spec,
482 rpc_names.as_slice(),
483 <$module_type>::event_types(),
484 dispatch,
485 |e, m: &Arc<$module_type>, ctx: &InvocationContext| {
486 let m = std::sync::Arc::clone(m);
487 let ctx = ctx.clone();
488 async move { m.dispatch_event(e, &ctx).await }
489 },
490 $on_connect,
491 $on_tick,
492 module,
493 cli,
494 db,
495 )
496 .await
497 }};
498}
499
500#[macro_export]
512macro_rules! register_rpc_methods {
513 ($api:expr, $($method:expr),* $(,)?) => {
514 async {
515 let api = $api;
516 $(
517 api.register_rpc_endpoint($method.to_string(), String::new()).await?;
518 )*
519 Ok::<(), blvm_node::module::traits::ModuleError>(())
520 }
521 };
522}
523
524#[cfg(feature = "node")]
525pub mod ipc;
526#[cfg(feature = "node")]
527pub mod manifest;
528#[cfg(feature = "node")]
529pub mod prelude;
530#[cfg(feature = "node")]
531pub mod runner;
532#[cfg(feature = "node")]
533pub mod security;
534#[cfg(feature = "node")]
535pub mod traits;
536
537#[cfg(feature = "node")]
539pub use bootstrap::{ModuleBootstrap, ModuleConfig};
540#[cfg(feature = "node")]
541pub use database::{
542 open_module_db, run_migrations, run_migrations_down, run_migrations_with_down, Migration,
543 MigrationContext, MigrationDown, MigrationUp,
544};
545#[cfg(feature = "node")]
546pub use ipc::client::ModuleIpcClient;
547#[cfg(feature = "node")]
548pub use ipc::protocol::*;
549#[cfg(feature = "node")]
550pub use manifest::ModuleManifest;
551#[cfg(feature = "node")]
552pub use module_db::ModuleDb;
553#[cfg(feature = "node")]
554pub use runner::{
555 run_async, run_module, run_module_with_setup, run_module_with_setup_and_api,
556 run_module_with_tick, InvocationContext,
557};
558#[cfg(feature = "node")]
559pub use security::{Permission, PermissionSet};
560#[cfg(feature = "node")]
561pub use storage::{DatabaseStorageAdapter, ModuleStorage, ModuleStorageDatabaseBridge, ModuleTree};
562#[cfg(feature = "node")]
563pub use traits::*;