initial
This commit is contained in:
127
app/shared/models.py
Normal file
127
app/shared/models.py
Normal file
@@ -0,0 +1,127 @@
|
||||
"""Data models for the disk reorganizer"""
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class FileRecord:
|
||||
"""Core file record with all metadata"""
|
||||
path: Path
|
||||
size: int
|
||||
modified_time: float
|
||||
created_time: float
|
||||
disk_label: str
|
||||
checksum: Optional[str] = None
|
||||
status: str = 'indexed' # indexed, planned, moved, verified
|
||||
category: Optional[str] = None
|
||||
duplicate_of: Optional[str] = None
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Convert to dictionary for serialization"""
|
||||
return {
|
||||
'path': str(self.path),
|
||||
'size': self.size,
|
||||
'modified_time': self.modified_time,
|
||||
'created_time': self.created_time,
|
||||
'disk_label': self.disk_label,
|
||||
'checksum': self.checksum,
|
||||
'status': self.status,
|
||||
'category': self.category,
|
||||
'duplicate_of': self.duplicate_of
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class OperationRecord:
|
||||
"""Record of a migration operation"""
|
||||
source_path: Path
|
||||
target_path: Path
|
||||
operation_type: str # move, copy, hardlink, symlink
|
||||
size: int = 0
|
||||
status: str = 'pending' # pending, in_progress, completed, failed
|
||||
error: Optional[str] = None
|
||||
executed_at: Optional[datetime] = None
|
||||
verified: bool = False
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Convert to dictionary for serialization"""
|
||||
return {
|
||||
'source_path': str(self.source_path),
|
||||
'target_path': str(self.target_path),
|
||||
'operation_type': self.operation_type,
|
||||
'size': self.size,
|
||||
'status': self.status,
|
||||
'error': self.error,
|
||||
'executed_at': self.executed_at.isoformat() if self.executed_at else None,
|
||||
'verified': self.verified
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class DiskInfo:
|
||||
"""Information about a disk/volume"""
|
||||
name: str
|
||||
device: str
|
||||
mount_point: Path
|
||||
total_size: int
|
||||
used_size: int
|
||||
free_size: int
|
||||
fs_type: str
|
||||
|
||||
@property
|
||||
def usage_percent(self) -> float:
|
||||
"""Calculate usage percentage"""
|
||||
if self.total_size == 0:
|
||||
return 0.0
|
||||
return (self.used_size / self.total_size) * 100
|
||||
|
||||
|
||||
@dataclass
|
||||
class MigrationPlan:
|
||||
"""Complete migration plan"""
|
||||
target_disk: str
|
||||
destination_disks: list[str]
|
||||
operations: list[OperationRecord]
|
||||
total_size: int
|
||||
file_count: int
|
||||
created_at: datetime = field(default_factory=datetime.now)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Convert to dictionary for serialization"""
|
||||
return {
|
||||
'target_disk': self.target_disk,
|
||||
'destination_disks': self.destination_disks,
|
||||
'operations': [op.to_dict() for op in self.operations],
|
||||
'total_size': self.total_size,
|
||||
'file_count': self.file_count,
|
||||
'created_at': self.created_at.isoformat()
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProcessingStats:
|
||||
"""Statistics for processing operations"""
|
||||
files_processed: int = 0
|
||||
bytes_processed: int = 0
|
||||
files_succeeded: int = 0
|
||||
files_failed: int = 0
|
||||
start_time: datetime = field(default_factory=datetime.now)
|
||||
|
||||
@property
|
||||
def elapsed_seconds(self) -> float:
|
||||
"""Calculate elapsed time in seconds"""
|
||||
return (datetime.now() - self.start_time).total_seconds()
|
||||
|
||||
@property
|
||||
def files_per_second(self) -> float:
|
||||
"""Calculate processing rate"""
|
||||
elapsed = self.elapsed_seconds
|
||||
return self.files_processed / elapsed if elapsed > 0 else 0.0
|
||||
|
||||
@property
|
||||
def bytes_per_second(self) -> float:
|
||||
"""Calculate throughput"""
|
||||
elapsed = self.elapsed_seconds
|
||||
return self.bytes_processed / elapsed if elapsed > 0 else 0.0
|
||||
Reference in New Issue
Block a user