trace2e_core/traceability/
naming.rs

1//! Resource naming and identification system.
2//!
3//! This module defines the core resource identification and naming conventions used throughout
4//! the trace2e traceability system. It provides a unified way to represent and identify
5//! different types of computational resources including files, network streams, and processes.
6//!
7//! ## Resource Hierarchy
8//!
9//! **File Descriptors (Fd)**: Represent operating system file descriptors that can point to
10//! either files in the filesystem or network streams (sockets).
11//!
12//! **Files**: Filesystem resources identified by their path, supporting both absolute and
13//! relative path specifications.
14//!
15//! **Streams**: Network communication channels defined by local and peer socket addresses,
16//! supporting TCP connections, Unix domain sockets, and other network protocols.
17//!
18//! **Processes**: Running system processes identified by PID with additional metadata including
19//! start time and executable path for precise identification across process reuse.
20//!
21//! ## Resource Construction
22//!
23//! Resources can be constructed using dedicated factory methods that handle system queries
24//! and validation, or using mock variants for testing purposes.
25
26use std::fmt::Debug;
27
28use sysinfo::{Pid, System};
29
30/// Represents a file resource in the filesystem.
31///
32/// Files are identified by their path, which can be absolute or relative.
33/// The path is stored as provided without normalization to preserve
34/// the original specification for audit and debugging purposes.
35#[derive(Debug, Clone, Eq, PartialEq, Hash)]
36pub struct File {
37    /// Filesystem path to the file, as specified by the application
38    pub path: String,
39}
40
41/// Represents a network stream or socket connection.
42///
43/// Streams are bidirectional communication channels between two endpoints,
44/// typically used for TCP connections, Unix domain sockets, or other
45/// network protocols. Both endpoints must be specified to enable proper
46/// flow tracking and policy enforcement.
47#[derive(Debug, Clone, Eq, PartialEq, Hash)]
48pub struct Stream {
49    /// Local socket address (e.g., "127.0.0.1:8080")
50    pub local_socket: String,
51    /// Remote peer socket address (e.g., "192.168.1.100:9000")
52    pub peer_socket: String,
53}
54
55/// Represents a file descriptor that can point to either a file or a stream.
56///
57/// File descriptors are the operating system's handle for I/O operations.
58/// This enum distinguishes between filesystem-based I/O (files) and
59/// network-based I/O (streams) while maintaining a unified interface.
60#[derive(Debug, Clone, Eq, PartialEq, Hash)]
61pub enum Fd {
62    /// File descriptor pointing to a filesystem file
63    File(File),
64    /// File descriptor pointing to a network stream or socket
65    Stream(Stream),
66}
67
68/// Represents a running system process with identifying metadata.
69///
70/// Processes are identified not only by their PID (which can be reused)
71/// but also by their start time and executable path to ensure precise
72/// identification across the system lifecycle.
73#[derive(Debug, Clone, Eq, PartialEq, Hash)]
74pub struct Process {
75    /// Process identifier assigned by the operating system
76    pub pid: i32,
77    /// Process start time in seconds since epoch for uniqueness
78    pub starttime: u64,
79    /// Path to the executable that created this process
80    pub exe_path: String,
81}
82
83/// Unified resource identifier for all trackable entities in the system.
84///
85/// Resources represent any entity that can participate in data flows within
86/// the traceability system. This includes file descriptors (which may point
87/// to files or streams), processes, or null resources for uninitialized states.
88#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
89pub enum Resource {
90    /// File descriptor resource (file or stream)
91    Fd(Fd),
92    /// Process resource  
93    Process(Process),
94    /// Null or uninitialized resource
95    #[default]
96    None,
97}
98
99impl Resource {
100    /// Creates a new file resource with the specified filesystem path.
101    ///
102    /// The path is stored as provided without validation or normalization.
103    /// Applications should provide valid paths to ensure proper resource tracking.
104    pub fn new_file(path: String) -> Self {
105        Self::Fd(Fd::File(File { path }))
106    }
107
108    /// Creates a new stream resource with the specified socket addresses.
109    ///
110    /// Both local and peer socket addresses should be valid network addresses
111    /// in the format appropriate for the protocol (e.g., "IP:port" for TCP).
112    pub fn new_stream(local_socket: String, peer_socket: String) -> Self {
113        Self::Fd(Fd::Stream(Stream { local_socket, peer_socket }))
114    }
115
116    /// Creates a new process resource by querying the system for process information.
117    ///
118    /// Attempts to retrieve the process start time and executable path from the
119    /// system process table. If the process is not found, creates a process
120    /// resource with default values for the metadata fields.
121    pub fn new_process(pid: i32) -> Self {
122        let mut system = System::new();
123        system.refresh_all();
124        if let Some(process) = system.process(Pid::from(pid as usize)) {
125            let starttime = process.start_time();
126            let exe_path = if let Some(exe) = process.exe() {
127                exe.to_string_lossy().to_string()
128            } else {
129                String::new()
130            };
131            Self::Process(Process { pid, starttime, exe_path })
132        } else {
133            Self::Process(Process { pid, starttime: 0, exe_path: String::new() })
134        }
135    }
136
137    /// Creates a mock process resource for testing purposes.
138    ///
139    /// Creates a process resource with the specified PID but default values
140    /// for start time and executable path. Should only be used in test
141    /// environments where system process queries are not needed.
142    pub fn new_process_mock(pid: i32) -> Self {
143        Self::Process(Process { pid, starttime: 0, exe_path: String::new() })
144    }
145
146    /// Checks if this resource represents a filesystem file.
147    ///
148    /// Returns true if the resource is a file descriptor pointing to a file,
149    /// false for streams, processes, or null resources.
150    pub fn is_file(&self) -> bool {
151        matches!(self, Resource::Fd(Fd::File(_)))
152    }
153
154    /// Returns the reverse stream resource if this is a stream resource.
155    ///
156    /// For stream resources, returns a new resource with the local and peer
157    /// socket addresses swapped. This is useful for tracking bidirectional
158    /// flows. Returns None for non-stream resources.
159    pub fn is_stream(&self) -> Option<Self> {
160        if let Resource::Fd(Fd::Stream(stream)) = self {
161            Some(Self::new_stream(stream.peer_socket.to_owned(), stream.local_socket.to_owned()))
162        } else {
163            None
164        }
165    }
166
167    /// Checks if this resource represents a system process.
168    ///
169    /// Returns true if the resource is a process, false for file descriptors
170    /// or null resources.
171    pub fn is_process(&self) -> bool {
172        matches!(self, Resource::Process(_))
173    }
174}
175
176/// Trait for services that have a node identifier in distributed systems.
177///
178/// This trait is implemented by services that participate in distributed
179/// traceability operations and need to identify themselves to remote peers.
180/// The node ID is typically used in provenance records and logging to
181/// track which middleware instance processed specific operations.
182pub trait NodeId {
183    /// Returns the unique identifier for this node in the distributed system.
184    ///
185    /// Node IDs should be unique across the distributed deployment and
186    /// persistent across service restarts to maintain consistent provenance records.
187    fn node_id(&self) -> String;
188}