drasi_lib/config/snapshot.rs
1// Copyright 2025 The Drasi Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Configuration snapshot types for capturing point-in-time instance state.
16//!
17//! A [`ConfigurationSnapshot`] captures the full topology, status, and configuration
18//! properties of all components in a drasi-lib instance. Hosts can serialize this
19//! snapshot to store it, and later use it to reconstruct an equivalent instance.
20//!
21//! **Important:** Sources and reactions are trait objects — their properties are
22//! captured but they cannot be automatically deserialized back into instances.
23//! The host must supply the appropriate plugin factories to reconstruct them.
24
25use std::collections::HashMap;
26
27use serde::{Deserialize, Serialize};
28
29use crate::channels::ComponentStatus;
30use crate::component_graph::GraphEdge;
31use crate::config::schema::QueryConfig;
32
33/// A point-in-time snapshot of the full drasi-lib instance configuration.
34///
35/// Contains the topology (components and dependency edges), lifecycle status,
36/// and configuration properties of every source, query, and reaction.
37///
38/// # Serialization
39///
40/// This type implements `Serialize` and `Deserialize`, so it can be stored
41/// as JSON, YAML, or any serde-compatible format.
42///
43/// # Example
44///
45/// ```no_run
46/// # use drasi_lib::DrasiLib;
47/// # async fn example(core: &DrasiLib) -> Result<(), Box<dyn std::error::Error>> {
48/// let snapshot = core.snapshot_configuration().await?;
49/// let json = serde_json::to_string_pretty(&snapshot)?;
50/// std::fs::write("config-snapshot.json", &json)?;
51/// # Ok(())
52/// # }
53/// ```
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct ConfigurationSnapshot {
56 /// Unique identifier of the drasi-lib instance
57 pub instance_id: String,
58 /// ISO 8601 timestamp when the snapshot was captured
59 pub timestamp: String,
60 /// All source components with their configuration properties
61 pub sources: Vec<SourceSnapshot>,
62 /// All query components with their full query configurations
63 pub queries: Vec<QuerySnapshot>,
64 /// All reaction components with their configuration properties
65 pub reactions: Vec<ReactionSnapshot>,
66 /// Dependency edges between components (source→query, query→reaction)
67 pub edges: Vec<GraphEdge>,
68}
69
70/// Snapshot of a source component's configuration.
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct SourceSnapshot {
73 /// Source component identifier
74 pub id: String,
75 /// Plugin type identifier (e.g., "postgres", "http", "grpc")
76 pub source_type: String,
77 /// Lifecycle status at the time of snapshot
78 pub status: ComponentStatus,
79 /// Whether the source was configured to auto-start
80 pub auto_start: bool,
81 /// Configuration properties from [`Source::properties()`], including secrets.
82 ///
83 /// This is the authoritative config used to persist and recreate the source.
84 /// It intentionally contains sensitive values — see the persistence contract
85 /// on [`Source::properties()`] for details.
86 pub properties: HashMap<String, serde_json::Value>,
87 /// Bootstrap provider configuration, if one is attached to this source
88 pub bootstrap_provider: Option<BootstrapSnapshot>,
89}
90
91/// Snapshot of a bootstrap provider's configuration.
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct BootstrapSnapshot {
94 /// Bootstrap provider kind (e.g., "postgres", "scriptfile", "noop")
95 pub kind: String,
96 /// Configuration properties for the bootstrap provider, including secrets.
97 pub properties: HashMap<String, serde_json::Value>,
98}
99
100/// Snapshot of a query component's configuration.
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct QuerySnapshot {
103 /// Query component identifier
104 pub id: String,
105 /// Full query configuration (query string, source subscriptions, joins, etc.)
106 pub config: QueryConfig,
107 /// Lifecycle status at the time of snapshot
108 pub status: ComponentStatus,
109}
110
111/// Snapshot of a reaction component's configuration.
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct ReactionSnapshot {
114 /// Reaction component identifier
115 pub id: String,
116 /// Plugin type identifier (e.g., "log", "http", "grpc")
117 pub reaction_type: String,
118 /// Lifecycle status at the time of snapshot
119 pub status: ComponentStatus,
120 /// Whether the reaction was configured to auto-start
121 pub auto_start: bool,
122 /// Query IDs this reaction subscribes to
123 pub queries: Vec<String>,
124 /// Configuration properties from [`Reaction::properties()`], including secrets.
125 ///
126 /// This is the authoritative config used to persist and recreate the reaction.
127 /// It intentionally contains sensitive values — see the persistence contract
128 /// on [`Reaction::properties()`] for details.
129 pub properties: HashMap<String, serde_json::Value>,
130}