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