1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! This library allows the creation of custom shotover transforms.
//!
//! There are two consumers of this library:
//! ## Custom Transforms
//!
//! To create a custom transform you need to implement these traits:
//! * [`transforms::TransformConfig`] - Defines what configuration fields the transform has in the `topology.yaml`.
//! * [`transforms::TransformBuilder`] - Defines how to build the Transform for a new incoming connection. Only one instance is created over shotovers runtime.
//! * [`transforms::Transform`] - Defines the transformation logic of the transform. A new instance is created per incoming connection.
//!
//! Simple transforms can implement all of these onto a single struct but generally you need seperate structs for each.
//!
//! ## The shotover binary
//! All custom transforms the user wants to use are statically compiled into a single binary.
//! The crate for this binary is very simple, it just consists of a `main.rs` like:
//!
//! ```no_run
//! # mod transform_crate {
//! # pub type TransformConfig = shotover::transforms::null::NullSinkConfig;
//! # }
//! shotover::import_transform!(transform_crate::TransformConfig);
//!
//! fn main() {
//!     shotover::runner::Shotover::new().run_block();
//! }
//! ```
//!

// Accidentally printing would break json log output
#![deny(clippy::print_stdout)]
#![deny(clippy::print_stderr)]
#![allow(clippy::needless_doctest_main)]
#![allow(clippy::box_default)]
// Allow dead code if any of the protocol features are disabled
#![cfg_attr(
    any(
        not(feature = "cassandra"),
        not(feature = "redis"),
        not(feature = "kafka"),
        not(feature = "opensearch"),
    ),
    allow(dead_code, unused_imports, unused_variables, unused_mut)
)]
#[cfg(all(
    not(feature = "cassandra"),
    not(feature = "redis"),
    not(feature = "kafka"),
    not(feature = "opensearch"),
))]
compile_error!(
    "At least one protocol feature must be enabled, e.g. `cassandra`, `redis`, `kafka` or `opensearch`"
);

pub mod codec;
pub mod config;
mod connection_span;
pub mod frame;
pub mod message;
mod observability;
pub mod runner;
mod server;
pub mod sources;
pub mod tcp;
pub mod tls;
mod tracing_panic_handler;
pub mod transforms;

/// Imports a custom transform into the shotover binary.
///
/// When a custom transform is defined in its own crate, typetag wont kick in unless there is some kind of `use crate_name::CustomTransformConfig`.
/// This macro does that for you while making it clear that the `use` is a little bit magic.
/// It also performs some type checks to ensure that you are actually importing an implementer of [`transforms::TransformConfig`].
#[macro_export]
macro_rules! import_transform {
    ($ty:ty) => {
        // import the type, this is required for typetag to pick up the type
        use $ty;

        // assert that the type actually implements TransformConfig, this prevents the easy mistake of accidentally importing the Transform instead of the TransformConfig
        const _: fn() = || {
            // Only callable when `$ty` implements `TransformConfig`
            fn assert_impls_transform_config<T: ?Sized + shotover::transforms::TransformConfig>() {}
            assert_impls_transform_config::<$ty>();
        };
    };
}