1use crate::foundation::types::constants;
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct ValidatedPacket {
8 pub packet: DataPacket,
10 pub is_valid: bool,
12}
13
14impl ValidatedPacket {
15 #[inline]
17 pub fn new(packet: DataPacket, is_valid: bool) -> Self {
18 Self { packet, is_valid }
19 }
20
21 #[inline]
23 pub fn is_valid(&self) -> bool {
24 self.is_valid
25 }
26
27 #[inline]
29 pub fn is_invalid(&self) -> bool {
30 !self.is_valid
31 }
32
33 #[inline]
35 pub fn get_timestamp_ns(&self) -> u64 {
36 self.packet.get_timestamp_ns()
37 }
38
39 #[inline]
41 pub fn packet_length(&self) -> usize {
42 self.packet.packet_length()
43 }
44
45 #[inline]
47 pub fn capture_time(&self) -> DateTime<Utc> {
48 self.packet.capture_time()
49 }
50
51 #[inline]
53 pub fn checksum(&self) -> u32 {
54 self.packet.checksum()
55 }
56
57 #[inline]
59 pub fn total_size(&self) -> usize {
60 self.packet.total_size()
61 }
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct PcapFileHeader {
67 pub magic_number: u32,
69 pub major_version: u16,
71 pub minor_version: u16,
73 pub timezone_offset: i32,
75 pub timestamp_accuracy: u32,
77}
78
79impl PcapFileHeader {
80 pub const HEADER_SIZE: usize = 16; pub const DEFAULT_TIMESTAMP_ACCURACY: u32 = 1;
85
86 pub fn new(timezone_offset: i32) -> Self {
88 Self {
89 magic_number: constants::PCAP_MAGIC_NUMBER,
90 major_version: constants::MAJOR_VERSION,
91 minor_version: constants::MINOR_VERSION,
92 timezone_offset,
93 timestamp_accuracy:
94 Self::DEFAULT_TIMESTAMP_ACCURACY,
95 }
96 }
97
98 pub fn from_bytes(
100 bytes: &[u8],
101 ) -> Result<Self, String> {
102 if bytes.len() < Self::HEADER_SIZE {
103 return Err("字节数组长度不足".to_string());
104 }
105
106 let magic_number = u32::from_le_bytes([
107 bytes[0], bytes[1], bytes[2], bytes[3],
108 ]);
109 let major_version =
110 u16::from_le_bytes([bytes[4], bytes[5]]);
111 let minor_version =
112 u16::from_le_bytes([bytes[6], bytes[7]]);
113 let timezone_offset = i32::from_le_bytes([
114 bytes[8], bytes[9], bytes[10], bytes[11],
115 ]);
116 let timestamp_accuracy = u32::from_le_bytes([
117 bytes[12], bytes[13], bytes[14], bytes[15],
118 ]);
119
120 Ok(Self {
121 magic_number,
122 major_version,
123 minor_version,
124 timezone_offset,
125 timestamp_accuracy,
126 })
127 }
128
129 pub fn to_bytes(&self) -> Vec<u8> {
131 let mut bytes =
132 Vec::with_capacity(Self::HEADER_SIZE);
133 bytes.extend_from_slice(
134 &self.magic_number.to_le_bytes(),
135 );
136 bytes.extend_from_slice(
137 &self.major_version.to_le_bytes(),
138 );
139 bytes.extend_from_slice(
140 &self.minor_version.to_le_bytes(),
141 );
142 bytes.extend_from_slice(
143 &self.timezone_offset.to_le_bytes(),
144 );
145 bytes.extend_from_slice(
146 &self.timestamp_accuracy.to_le_bytes(),
147 );
148 bytes
149 }
150
151 pub fn is_valid(&self) -> bool {
153 self.magic_number == constants::PCAP_MAGIC_NUMBER
154 && self.major_version
155 == constants::MAJOR_VERSION
156 && self.minor_version
157 == constants::MINOR_VERSION
158 }
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct DataPacketHeader {
164 pub timestamp_seconds: u32,
166 pub timestamp_nanoseconds: u32,
168 pub packet_length: u32,
170 pub checksum: u32,
172}
173
174impl DataPacketHeader {
175 pub const HEADER_SIZE: usize = 16; pub fn new(
180 timestamp_seconds: u32,
181 timestamp_nanoseconds: u32,
182 packet_length: u32,
183 checksum: u32,
184 ) -> Result<Self, String> {
185 Ok(Self {
186 timestamp_seconds,
187 timestamp_nanoseconds,
188 packet_length,
189 checksum,
190 })
191 }
192
193 pub fn from_datetime(
195 capture_time: DateTime<Utc>,
196 packet_length: u32,
197 checksum: u32,
198 ) -> Result<Self, String> {
199 let timestamp_seconds =
200 capture_time.timestamp() as u32;
201 let timestamp_nanoseconds =
202 capture_time.timestamp_subsec_nanos();
203
204 Self::new(
205 timestamp_seconds,
206 timestamp_nanoseconds,
207 packet_length,
208 checksum,
209 )
210 }
211
212 pub fn from_packet_data(
214 capture_time: DateTime<Utc>,
215 packet_data: &[u8],
216 ) -> Result<Self, String> {
217 let checksum =
218 crate::foundation::utils::calculate_crc32(
219 packet_data,
220 );
221 let packet_length = packet_data.len() as u32;
222
223 Self::from_datetime(
224 capture_time,
225 packet_length,
226 checksum,
227 )
228 }
229
230 pub fn from_bytes(
232 bytes: &[u8],
233 ) -> Result<Self, String> {
234 if bytes.len() < Self::HEADER_SIZE {
235 return Err("字节数组长度不足".to_string());
236 }
237
238 let timestamp_seconds = u32::from_le_bytes([
239 bytes[0], bytes[1], bytes[2], bytes[3],
240 ]);
241 let timestamp_nanoseconds = u32::from_le_bytes([
242 bytes[4], bytes[5], bytes[6], bytes[7],
243 ]);
244 let packet_length = u32::from_le_bytes([
245 bytes[8], bytes[9], bytes[10], bytes[11],
246 ]);
247 let checksum = u32::from_le_bytes([
248 bytes[12], bytes[13], bytes[14], bytes[15],
249 ]);
250
251 Self::new(
252 timestamp_seconds,
253 timestamp_nanoseconds,
254 packet_length,
255 checksum,
256 )
257 }
258
259 pub fn to_bytes(&self) -> Vec<u8> {
261 let mut bytes =
262 Vec::with_capacity(Self::HEADER_SIZE);
263 bytes.extend_from_slice(
264 &self.timestamp_seconds.to_le_bytes(),
265 );
266 bytes.extend_from_slice(
267 &self.timestamp_nanoseconds.to_le_bytes(),
268 );
269 bytes.extend_from_slice(
270 &self.packet_length.to_le_bytes(),
271 );
272 bytes.extend_from_slice(
273 &self.checksum.to_le_bytes(),
274 );
275 bytes
276 }
277
278 pub fn capture_time(&self) -> DateTime<Utc> {
280 DateTime::from_timestamp(
281 self.timestamp_seconds as i64,
282 self.timestamp_nanoseconds,
283 )
284 .unwrap_or_else(|| {
285 Utc::now()
287 })
288 }
289}
290
291#[derive(Debug, Clone, Serialize, Deserialize)]
293pub struct DataPacket {
294 pub header: DataPacketHeader,
296 pub data: Vec<u8>,
298}
299
300impl DataPacket {
301 pub fn new(
303 header: DataPacketHeader,
304 data: Vec<u8>,
305 ) -> Result<Self, String> {
306 if data.len() != header.packet_length as usize {
307 return Err(
308 "数据长度与头部长度不匹配".to_string()
309 );
310 }
311
312 Ok(Self { header, data })
313 }
314
315 pub fn from_datetime(
317 capture_time: DateTime<Utc>,
318 data: Vec<u8>,
319 ) -> Result<Self, String> {
320 let header = DataPacketHeader::from_packet_data(
321 capture_time,
322 &data,
323 )?;
324 Self::new(header, data)
325 }
326
327 pub fn from_timestamp(
329 timestamp_seconds: u32,
330 timestamp_nanoseconds: u32,
331 data: Vec<u8>,
332 ) -> Result<Self, String> {
333 let checksum =
334 crate::foundation::utils::calculate_crc32(
335 &data,
336 );
337 let packet_length = data.len() as u32;
338
339 let header = DataPacketHeader::new(
340 timestamp_seconds,
341 timestamp_nanoseconds,
342 packet_length,
343 checksum,
344 )?;
345
346 Self::new(header, data)
347 }
348
349 #[inline]
351 pub fn capture_time(&self) -> DateTime<Utc> {
352 self.header.capture_time()
353 }
354
355 #[inline]
357 pub fn packet_length(&self) -> usize {
358 self.data.len()
359 }
360
361 #[inline]
363 pub fn total_size(&self) -> usize {
364 DataPacketHeader::HEADER_SIZE + self.packet_length()
365 }
366
367 #[inline]
369 pub fn checksum(&self) -> u32 {
370 self.header.checksum
371 }
372
373 #[inline]
375 pub fn get_timestamp_ns(&self) -> u64 {
376 let capture_time = self.capture_time();
377 capture_time.timestamp() as u64 * 1_000_000_000
378 + capture_time.timestamp_subsec_nanos() as u64
379 }
380
381 #[inline]
383 pub fn is_valid(&self) -> bool {
384 let calculated_checksum =
385 crate::foundation::utils::calculate_crc32(
386 &self.data,
387 );
388 calculated_checksum == self.header.checksum
389 }
390
391 pub fn to_bytes(&self) -> Vec<u8> {
393 let mut bytes =
394 Vec::with_capacity(self.total_size());
395 bytes.extend_from_slice(&self.header.to_bytes());
396 bytes.extend_from_slice(&self.data);
397 bytes
398 }
399}
400
401impl std::fmt::Display for DataPacket {
402 fn fmt(
403 &self,
404 f: &mut std::fmt::Formatter<'_>,
405 ) -> std::fmt::Result {
406 write!(
407 f,
408 "DataPacket {{ timestamp: {:?}, length: {}, checksum: 0x{:08X} }}",
409 self.capture_time(),
410 self.packet_length(),
411 self.checksum()
412 )
413 }
414}
415
416#[derive(Debug, Clone, Serialize, Deserialize)]
420pub struct DatasetInfo {
421 pub name: String,
423 pub path: std::path::PathBuf,
425 pub file_count: usize,
427 pub total_packets: u64,
429 pub total_size: u64,
431 pub start_timestamp: Option<u64>,
433 pub end_timestamp: Option<u64>,
435 pub created_time: String,
437 pub modified_time: String,
439 pub has_index: bool,
441}
442
443impl DatasetInfo {
444 pub fn new<P: AsRef<std::path::Path>>(
446 name: String,
447 path: P,
448 ) -> Self {
449 use chrono::Utc;
450
451 Self {
452 name,
453 path: path.as_ref().to_path_buf(),
454 file_count: 0,
455 total_packets: 0,
456 total_size: 0,
457 start_timestamp: None,
458 end_timestamp: None,
459 created_time: Utc::now().to_rfc3339(),
460 modified_time: Utc::now().to_rfc3339(),
461 has_index: false,
462 }
463 }
464
465 pub fn time_range(&self) -> Option<(u64, u64)> {
467 match (self.start_timestamp, self.end_timestamp) {
468 (Some(start), Some(end)) => Some((start, end)),
469 _ => None,
470 }
471 }
472
473 pub fn total_duration_ns(&self) -> u64 {
475 match self.time_range() {
476 Some((start, end)) => end.saturating_sub(start),
477 None => 0,
478 }
479 }
480
481 pub fn total_duration_seconds(&self) -> f64 {
483 self.total_duration_ns() as f64 / 1_000_000_000.0
484 }
485
486 pub fn average_packet_rate(&self) -> f64 {
488 let duration = self.total_duration_seconds();
489 if duration > 0.0 {
490 self.total_packets as f64 / duration
491 } else {
492 0.0
493 }
494 }
495}
496
497#[derive(Debug, Clone, Serialize, Deserialize)]
499pub struct FileInfo {
500 pub file_name: String,
502 pub file_path: std::path::PathBuf,
504 pub file_size: u64,
506 pub packet_count: u64,
508 pub start_timestamp: Option<u64>,
510 pub end_timestamp: Option<u64>,
512 pub file_hash: Option<String>,
514 pub created_time: String,
516 pub modified_time: String,
518 pub is_valid: bool,
520}
521
522impl FileInfo {
523 pub fn new<P: AsRef<std::path::Path>>(
525 file_path: P,
526 ) -> Self {
527 use chrono::Utc;
528
529 let path = file_path.as_ref();
530 let file_name = path
531 .file_name()
532 .and_then(|name| name.to_str())
533 .unwrap_or("")
534 .to_string();
535
536 Self {
537 file_name,
538 file_path: path.to_path_buf(),
539 file_size: 0,
540 packet_count: 0,
541 start_timestamp: None,
542 end_timestamp: None,
543 file_hash: None,
544 created_time: Utc::now().to_rfc3339(),
545 modified_time: Utc::now().to_rfc3339(),
546 is_valid: false,
547 }
548 }
549
550 pub fn from_file<P: AsRef<std::path::Path>>(
552 file_path: P,
553 ) -> Result<Self, std::io::Error> {
554 let path = file_path.as_ref();
555 let metadata = std::fs::metadata(path)?;
556
557 let file_name = path
558 .file_name()
559 .and_then(|name| name.to_str())
560 .unwrap_or("")
561 .to_string();
562
563 let created_time = metadata
564 .created()
565 .map(|time| {
566 DateTime::<Utc>::from(time).to_rfc3339()
567 })
568 .unwrap_or_else(|_| Utc::now().to_rfc3339());
569
570 let modified_time = metadata
571 .modified()
572 .map(|time| {
573 DateTime::<Utc>::from(time).to_rfc3339()
574 })
575 .unwrap_or_else(|_| Utc::now().to_rfc3339());
576
577 Ok(Self {
578 file_name,
579 file_path: path.to_path_buf(),
580 file_size: metadata.len(),
581 packet_count: 0,
582 start_timestamp: None,
583 end_timestamp: None,
584 file_hash: None,
585 created_time,
586 modified_time,
587 is_valid: path.exists() && metadata.is_file(),
588 })
589 }
590
591 pub fn time_range(&self) -> Option<(u64, u64)> {
593 match (self.start_timestamp, self.end_timestamp) {
594 (Some(start), Some(end)) => Some((start, end)),
595 _ => None,
596 }
597 }
598
599 pub fn duration_ns(&self) -> u64 {
601 match self.time_range() {
602 Some((start, end)) => end.saturating_sub(start),
603 None => 0,
604 }
605 }
606
607 pub fn duration_seconds(&self) -> f64 {
609 self.duration_ns() as f64 / 1_000_000_000.0
610 }
611
612 pub fn calculate_hash(
614 &mut self,
615 ) -> Result<(), std::io::Error> {
616 use sha2::{Digest, Sha256};
617 use std::io::Read;
618
619 let mut file =
620 std::fs::File::open(&self.file_path)?;
621 let mut hasher = Sha256::new();
622 let mut buffer = [0; 8192];
623
624 loop {
625 let bytes_read = file.read(&mut buffer)?;
626 if bytes_read == 0 {
627 break;
628 }
629 hasher.update(&buffer[..bytes_read]);
630 }
631
632 self.file_hash =
633 Some(format!("{:x}", hasher.finalize()));
634 Ok(())
635 }
636}