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}