Skip to main content

hyperion_framework/containerisation/
traits.rs

1// -------------------------------------------------------------------------------------------------
2// Hyperion Framework
3// https://github.com/robert-hannah/hyperion-framework
4//
5// A lightweight component-based TCP framework for building service-oriented Rust applications with
6// CLI control, async messaging, and lifecycle management.
7//
8// Copyright 2025 Robert Hannah
9//
10// Licensed under the Apache License, Version 2.0 (the "License");
11// you may not use this file except in compliance with the License.
12// You may obtain a copy of the License at
13//
14//     http://www.apache.org/licenses/LICENSE-2.0
15//
16// Unless required by applicable law or agreed to in writing, software
17// distributed under the License is distributed on an "AS IS" BASIS,
18// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19// See the License for the specific language governing permissions and
20// limitations under the License.
21// -------------------------------------------------------------------------------------------------
22
23// Standard
24use std::collections::HashMap;
25use std::sync::Arc as StdArc;
26use std::sync::atomic::AtomicUsize;
27
28// Package
29use async_trait::async_trait;
30use tokio::sync::Notify;
31use tokio::sync::mpsc::{Receiver, Sender};
32
33// Local
34use crate::messages::client_broker_message::ClientBrokerMessage;
35use crate::messages::container_directive::ContainerDirective;
36
37// Traits
38pub trait Initialisable {
39    type ConfigType;
40    fn initialise(
41        container_state: StdArc<AtomicUsize>,
42        container_state_notify: StdArc<Notify>,
43        config: StdArc<Self::ConfigType>,
44    ) -> Self;
45}
46// For example, Hyperion Network Containerisation - Initialise Component
47// impl Initialisable for Component {
48//     type ConfigType = Config;
49//     fn initialise(container_state: StdArc<AtomicUsize>, container_state_notify: StdArc<Notify>, config: StdArc<Self::ConfigType>) -> Self {
50//         // Will panic if there's a problem, which we want seeing we do this on startup
51//         Component::new(container_state, container_state_notify, config)
52//     }
53// }
54
55#[async_trait]
56pub trait Run {
57    // Uses async_trait which isn't perfect and does introduce a small overhead, but it is a lot
58    // cleaner than the alternative. Since this is only used once to start the component, I don't
59    // see it as a big deal. Performance overhead comes from lack of return type (compiler can't optimise)
60
61    // Using self, instead of &mut self, as the clone must be consumed by Run to ensure a fresh
62    // state is kept in the container
63    type Message;
64    async fn run(
65        self,
66        comp_in_rx: Receiver<Self::Message>,
67        comp_out_tx: Sender<ClientBrokerMessage<Self::Message>>,
68    );
69}
70// For example, Hyperion Network Containerisation - Run Component
71// #[async_trait]
72// impl Run for Component {
73//     type Message = ContainerMessage;
74//     async fn run(mut self, mut comp_in_rx: Receiver<Self::Message>, comp_out_tx: Sender<ClientBrokerMessage<Self::Message>>) {
75//         log::debug!("{} has started successfully", self.config.container_id.name);
76//         loop {
77//             if self.component_state == ComponentState::Dead { break; }
78//             tokio::select! {
79//                 Some(message) = comp_in_rx.recv() => {
80//                     log::trace!("{} received message: {:?}", self.config.container_id.name, message);
81//                     if let Some(result) = self.process_incoming_message(message).await {
82//                         let from_location = format!("{} main loop", self.config.container_id.name);
83//                         let to_location = format!("{} Container", self.config.container_id.name);
84//                         add_to_tx_with_retry(&comp_out_tx, &result, &from_location, &to_location).await;
85//                     }
86//                 }
87//                 _ = self.container_state_notify.notified() => {
88//                     // Check if container is shutting down
89//                     if self.container_state.load(Ordering::SeqCst) == ContainerState::ShuttingDown as usize {
90//                         self.component_state = ComponentState::Dormant;
91//                         break;
92//                     }
93//                 }
94//             }
95//         }
96//         log::info!("{} task has closed", self.config.container_id.name);
97//     }
98// }
99
100pub trait HyperionContainerDirectiveMessage {
101    fn get_container_directive_message(&self) -> Option<&ContainerDirective>;
102}
103// For example,
104// impl HyperionContainerDirectiveMessage for ContainerMessage {
105//     // Gets ContainerDirective if is instance
106//     fn get_container_directive_message(&self) -> Option<&ContainerDirective> {
107//         if let ContainerMessage::ContainerDirectiveMsg(directive) = self {
108//             Some(directive)
109//         } else {
110//             None
111//         }
112//     }
113// }
114
115pub trait ContainerIdentidy {
116    fn container_identity(&self) -> HashMap<String, String>;
117}
118// For example,
119// impl ContainerIdentidy for Config {
120//     fn container_identity(&self) -> HashMap<String, String> {
121//         let mut identity = HashMap::new();
122//         identity.insert("name".to_string(), self.container.name.clone());
123//         identity.insert("version".to_string(), self.container.version.clone());
124//         identity.insert("version_title".to_string(), self.container.version_title.clone());
125//         identity.insert("software_collection".to_string(), self.container.software_collection.clone());
126//         identity
127//     }
128// }
129
130pub trait LogLevel {
131    fn log_level(&self) -> &str;
132}
133// For example,
134// impl LogLevel for Config {
135//     fn log_level(&self) -> &str {
136//         &self.logging.level
137//     }
138// }