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 false,
273 None,
274 Some("unsupported invocation".to_string()),
275 ),
276 };
277 InvocationResultMessage {
278 correlation_id: invocation.correlation_id,
279 success,
280 payload,
281 error,
282 }
283 };
284
285 let rpc_names = <$module_type>::rpc_method_names();
286 let cli_spec = <$cli_type>::cli_spec();
287
288 run_module_with_setup(
289 $socket_path,
290 $module_id,
291 $module_name,
292 $version,
293 cli_spec,
294 rpc_names.as_slice(),
295 $event_types,
296 dispatch,
297 $on_event,
298 $setup,
299 db,
300 $data_dir,
301 )
302 .await
303 }};
304 (
305 socket_path: $socket_path:expr,
306 module_id: $module_id:expr,
307 module_name: $module_name:expr,
308 version: $version:expr,
309 cli: $cli:expr,
310 cli_type: $cli_type:ty,
311 module_type: $module_type:ty,
312 module: $module:expr,
313 db: $db:expr,
314 ) => {{
315 use blvm_node::module::ipc::protocol::{
316 InvocationMessage, InvocationResultMessage, InvocationResultPayload, InvocationType,
317 };
318 use std::sync::Arc;
319 use $crate::module::runner::{run_module as run_module_fn, InvocationContext};
320
321 let cli = $cli;
322 let module = Arc::new($module);
323 let db = Arc::clone(&$db);
324
325 let dispatch = |invocation: InvocationMessage,
326 ctx: InvocationContext,
327 module: &Arc<$module_type>,
328 cli: &$cli_type| {
329 let (success, payload, error) = match &invocation.invocation_type {
330 InvocationType::Cli { subcommand, args } => {
331 let args: Vec<String> = args.clone();
332 match cli.dispatch_cli(&ctx, subcommand, &args) {
333 Ok(stdout) => (
334 true,
335 Some(InvocationResultPayload::Cli {
336 stdout,
337 stderr: String::new(),
338 exit_code: 0,
339 }),
340 None,
341 ),
342 Err(e) => (false, None, Some(e.to_string())),
343 }
344 }
345 InvocationType::Rpc { method, params } => {
346 let db_ref = ctx.db();
347 match module.dispatch_rpc(method, params, db_ref) {
348 Ok(v) => (true, Some(InvocationResultPayload::Rpc(v)), None),
349 Err(e) => (false, None, Some(e.to_string())),
350 }
351 }
352 InvocationType::ModuleApi { .. } => (
353 false,
354 None,
355 Some("ModuleApi is not supported by run_module!; use run_module_with_setup_and_api".to_string()),
356 ),
357 _ => (
358 false,
359 None,
360 Some("unsupported invocation".to_string()),
361 ),
362 };
363 InvocationResultMessage {
364 correlation_id: invocation.correlation_id,
365 success,
366 payload,
367 error,
368 }
369 };
370
371 let rpc_names = <$module_type>::rpc_method_names();
372 let cli_spec = <$cli_type>::cli_spec();
373
374 run_module_fn(
375 $socket_path,
376 $module_id,
377 $module_name,
378 $version,
379 cli_spec,
380 rpc_names.as_slice(),
381 <$module_type>::event_types(),
382 dispatch,
383 |e, m: &Arc<$module_type>, ctx: &InvocationContext| {
384 let m = std::sync::Arc::clone(m);
385 let ctx = ctx.clone();
386 async move { m.dispatch_event(e, &ctx).await }
387 },
388 module,
389 cli,
390 db,
391 )
392 .await
393 }};
394 (
395 bootstrap: $bootstrap:expr,
396 module_name: $module_name:expr,
397 module: $module:expr,
398 module_type: $module_type:ty,
399 db: $db:expr,
400 on_connect: $on_connect:expr,
401 on_tick: $on_tick:expr,
402 ) => {{
403 let __bootstrap = $bootstrap;
404 let __module = $module;
405 $crate::run_module! {
406 socket_path: __bootstrap.socket_path.clone(),
407 module_id: &__bootstrap.module_id,
408 module_name: $module_name,
409 version: env!("CARGO_PKG_VERSION"),
410 cli: __module.clone(),
411 cli_type: $module_type,
412 module_type: $module_type,
413 module: __module,
414 db: $db,
415 on_connect: Some($on_connect),
416 on_tick: Some($on_tick),
417 }
418 }};
419 (
420 socket_path: $socket_path:expr,
421 module_id: $module_id:expr,
422 module_name: $module_name:expr,
423 version: $version:expr,
424 cli: $cli:expr,
425 cli_type: $cli_type:ty,
426 module_type: $module_type:ty,
427 module: $module:expr,
428 db: $db:expr,
429 on_connect: $on_connect:expr,
430 on_tick: $on_tick:expr,
431 ) => {{
432 use blvm_node::module::ipc::protocol::{
433 InvocationMessage, InvocationResultMessage, InvocationResultPayload, InvocationType,
434 };
435 use std::sync::Arc;
436 use $crate::module::runner::{run_module_with_tick, InvocationContext};
437
438 let cli = $cli;
439 let module = Arc::new($module);
440 let db = Arc::clone(&$db);
441
442 let dispatch = |invocation: InvocationMessage,
443 ctx: InvocationContext,
444 module: &Arc<$module_type>,
445 cli: &$cli_type| {
446 let (success, payload, error) = match &invocation.invocation_type {
447 InvocationType::Cli { subcommand, args } => {
448 let args: Vec<String> = args.clone();
449 match cli.dispatch_cli(&ctx, subcommand, &args) {
450 Ok(stdout) => (
451 true,
452 Some(InvocationResultPayload::Cli {
453 stdout,
454 stderr: String::new(),
455 exit_code: 0,
456 }),
457 None,
458 ),
459 Err(e) => (false, None, Some(e.to_string())),
460 }
461 }
462 InvocationType::Rpc { method, params } => {
463 let db_ref = ctx.db();
464 match module.dispatch_rpc(method, params, db_ref) {
465 Ok(v) => (true, Some(InvocationResultPayload::Rpc(v)), None),
466 Err(e) => (false, None, Some(e.to_string())),
467 }
468 }
469 InvocationType::ModuleApi { .. } => (
470 false,
471 None,
472 Some("ModuleApi is not supported by run_module!; use run_module_with_setup_and_api".to_string()),
473 ),
474 _ => (
475 false,
476 None,
477 Some("unsupported invocation".to_string()),
478 ),
479 };
480 InvocationResultMessage {
481 correlation_id: invocation.correlation_id,
482 success,
483 payload,
484 error,
485 }
486 };
487
488 let rpc_names = <$module_type>::rpc_method_names();
489 let cli_spec = <$cli_type>::cli_spec();
490
491 run_module_with_tick(
492 $socket_path,
493 $module_id,
494 $module_name,
495 $version,
496 cli_spec,
497 rpc_names.as_slice(),
498 <$module_type>::event_types(),
499 dispatch,
500 |e, m: &Arc<$module_type>, ctx: &InvocationContext| {
501 let m = std::sync::Arc::clone(m);
502 let ctx = ctx.clone();
503 async move { m.dispatch_event(e, &ctx).await }
504 },
505 $on_connect,
506 $on_tick,
507 module,
508 cli,
509 db,
510 )
511 .await
512 }};
513}
514
515#[macro_export]
527macro_rules! register_rpc_methods {
528 ($api:expr, $($method:expr),* $(,)?) => {
529 async {
530 let api = $api;
531 $(
532 api.register_rpc_endpoint($method.to_string(), String::new()).await?;
533 )*
534 Ok::<(), blvm_node::module::traits::ModuleError>(())
535 }
536 };
537}
538
539#[cfg(feature = "node")]
540pub mod ipc;
541#[cfg(feature = "node")]
542pub mod manifest;
543#[cfg(feature = "node")]
544pub mod prelude;
545#[cfg(feature = "node")]
546pub mod runner;
547#[cfg(feature = "node")]
548pub mod security;
549#[cfg(feature = "node")]
550pub mod timers;
551#[cfg(feature = "node")]
552pub mod traits;
553
554#[cfg(feature = "node")]
556pub use bootstrap::{ModuleBootstrap, ModuleConfig};
557#[cfg(feature = "node")]
558pub use database::{
559 Migration, MigrationContext, MigrationDown, MigrationUp, open_module_db, run_migrations,
560 run_migrations_down, run_migrations_with_down,
561};
562#[cfg(feature = "node")]
563pub use ipc::client::ModuleIpcClient;
564#[cfg(feature = "node")]
565pub use ipc::protocol::*;
566#[cfg(feature = "node")]
567pub use manifest::ModuleManifest;
568#[cfg(feature = "node")]
569pub use module_db::ModuleDb;
570#[cfg(feature = "node")]
571pub use runner::{
572 InvocationContext, run_async, run_module, run_module_with_setup, run_module_with_setup_and_api,
573 run_module_with_tick,
574};
575#[cfg(feature = "node")]
576pub use security::{Permission, PermissionSet};
577#[cfg(feature = "node")]
578pub use storage::{DatabaseStorageAdapter, ModuleStorage, ModuleStorageDatabaseBridge, ModuleTree};
579#[cfg(feature = "node")]
580pub use timers::{Exec, TimerBuilder, TimerHandle, TimerRegistry, sdk_tick_spec};
581#[cfg(feature = "node")]
582pub use traits::*;