"""ODF 光纤配线单元管理系统 - 业务逻辑层。 使用内存假数据存储,模拟 ODF 配线单元的管理功能。 提供机架、配线单元、端口、跳接连接的 CRUD 操作。 """ import uuid from datetime import datetime from typing import Optional from app.models import Rack, Unit, Port, Connection, PortType, PortStatus class OdfService: """ODF 光纤配线单元管理服务。 使用内存字典存储数据,提供对机架、配线单元、端口和跳接连接的管理能力。 此类为单例服务,所有数据在服务运行期间保存在内存中。 """ def __init__(self) -> None: """初始化内存数据存储和初始假数据。""" self._racks: dict[str, Rack] = {} self._units: dict[str, Unit] = {} self._ports: dict[str, Port] = {} self._connections: dict[str, Connection] = {} self._init_demo_data() def _init_demo_data(self) -> None: """初始化演示用假数据,方便测试和展示。""" # 创建 2 个机架 rack1 = Rack( rack_id="rack-001", rack_name="ODF-001", location="A机房-1列-01排", ) rack2 = Rack( rack_id="rack-002", rack_name="ODF-002", location="A机房-1列-02排", ) # 为机架1创建2个单元(每个单元12口) unit1 = self._create_unit_internal("rack-001", 1, "上排单元A", "上排", 12, PortType.LC) unit2 = self._create_unit_internal("rack-001", 2, "下排单元B", "下排", 12, PortType.SC) # 为机架2创建1个单元(24口) unit3 = self._create_unit_internal("rack-002", 1, "上排单元C", "上排", 24, PortType.LC) rack1.units = [unit1, unit2] rack2.units = [unit3] self._racks[rack1.rack_id] = rack1 self._racks[rack2.rack_id] = rack2 # 创建一条示例跳接连接:单元1的端口1 -> 单元2的端口1 unit1_ports = [p for p in self._ports.values() if p.unit_id == unit1.unit_id] unit2_ports = [p for p in self._ports.values() if p.unit_id == unit2.unit_id] if unit1_ports and unit2_ports: pa = unit1_ports[0] pb = unit2_ports[0] pa.status = PortStatus.IN_USE pb.status = PortStatus.IN_USE conn = Connection( connection_id=f"conn-{uuid.uuid4().hex[:8]}", port_a_id=pa.port_id, port_b_id=pb.port_id, fiber_length=3.5, create_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), remark="示例跳接", ) self._connections[conn.connection_id] = conn def _create_unit_internal( self, rack_id: str, unit_number: int, unit_name: str, position: str, port_count: int, port_type: PortType, ) -> Unit: """内部方法:创建一个配线单元及其端口。 Args: rack_id: 所属机架 ID。 unit_number: 单元编号。 unit_name: 单元名称。 position: 位置描述。 port_count: 端口数量。 port_type: 端口类型。 Returns: 创建的 Unit 实例。 """ unit_id = f"unit-{uuid.uuid4().hex[:8]}" unit = Unit( unit_id=unit_id, rack_id=rack_id, unit_number=unit_number, unit_name=unit_name, position=position, ports=[], ) ports: list[Port] = [] for i in range(1, port_count + 1): port_id = f"port-{uuid.uuid4().hex[:8]}" port = Port( port_id=port_id, unit_id=unit_id, port_number=i, port_type=port_type, status=PortStatus.FREE, label=f"{rack_id}-{unit_number}-{i:02d}", ) self._ports[port_id] = port ports.append(port) unit.ports = ports self._units[unit_id] = unit return unit # ==================== 机架管理 ==================== def list_racks(self) -> list[dict]: """获取所有机架的简要列表。 Returns: 包含机架信息和单元数量的字典列表。 """ result = [] for rack in self._racks.values(): result.append({ "rack_id": rack.rack_id, "rack_name": rack.rack_name, "location": rack.location, "unit_count": len(rack.units), }) return result def get_rack(self, rack_id: str) -> Optional[Rack]: """根据 ID 获取机架详情(包含单元和端口)。 Args: rack_id: 机架 ID。 Returns: 机架对象,未找到时返回 None。 """ return self._racks.get(rack_id) def create_rack(self, rack_name: str, location: str) -> Rack: """创建一个新的空机架。 Args: rack_name: 机架名称/编号。 location: 物理位置。 Returns: 新创建的机架对象。 """ rack_id = f"rack-{uuid.uuid4().hex[:8]}" rack = Rack( rack_id=rack_id, rack_name=rack_name, location=location, units=[], ) self._racks[rack_id] = rack return rack def delete_rack(self, rack_id: str) -> bool: """删除指定机架(同时删除其下的单元和端口)。 Args: rack_id: 机架 ID。 Returns: 删除成功返回 True,机架不存在返回 False。 """ if rack_id not in self._racks: return False rack = self._racks[rack_id] for unit in rack.units: for port in unit.ports: self._ports.pop(port.port_id, None) self._units.pop(unit.unit_id, None) del self._racks[rack_id] return True # ==================== 配线单元管理 ==================== def create_unit( self, rack_id: str, unit_number: int, unit_name: str, position: str, port_count: int, port_type: PortType, ) -> Optional[Unit]: """在指定机架下创建配线单元。 Args: rack_id: 所属机架 ID。 unit_number: 单元编号。 unit_name: 单元名称。 position: 位置描述。 port_count: 端口数量。 port_type: 端口类型。 Returns: 创建的 Unit 对象,机架不存在时返回 None。 """ if rack_id not in self._racks: return None unit = self._create_unit_internal(rack_id, unit_number, unit_name, position, port_count, port_type) self._racks[rack_id].units.append(unit) return unit def delete_unit(self, unit_id: str) -> bool: """删除指定配线单元(同时删除其端口)。 Args: unit_id: 单元 ID。 Returns: 删除成功返回 True,单元不存在返回 False。 """ if unit_id not in self._units: return False unit = self._units[unit_id] for port in unit.ports: self._ports.pop(port.port_id, None) rack = self._racks.get(unit.rack_id) if rack: rack.units = [u for u in rack.units if u.unit_id != unit_id] del self._units[unit_id] return True # ==================== 端口管理 ==================== def get_free_ports(self, rack_id: Optional[str] = None) -> list[dict]: """查询空闲端口列表。 Args: rack_id: 可选的机架 ID,指定时只查询该机架下的空闲端口。 Returns: 空闲端口信息列表,包含所属单元和机架信息。 """ result = [] for port in self._ports.values(): if port.status != PortStatus.FREE: continue unit = self._units.get(port.unit_id) if not unit: continue rack = self._racks.get(unit.rack_id) if not rack: continue if rack_id and rack.rack_id != rack_id: continue result.append({ "port_id": port.port_id, "port_number": port.port_number, "port_type": port.port_type, "label": port.label, "unit_id": unit.unit_id, "unit_number": unit.unit_number, "rack_id": rack.rack_id, "rack_name": rack.rack_name, }) return result def get_port_detail(self, port_id: str) -> Optional[dict]: """获取端口的详细信息(含所属单元和机架)。 Args: port_id: 端口 ID。 Returns: 端口详细信息字典,端口不存在时返回 None。 """ port = self._ports.get(port_id) if not port: return None unit = self._units.get(port.unit_id) if not unit: return None rack = self._racks.get(unit.rack_id) if not rack: return None return { "port_id": port.port_id, "port_number": port.port_number, "port_type": port.port_type, "status": port.status, "label": port.label, "unit_id": unit.unit_id, "unit_number": unit.unit_number, "rack_id": rack.rack_id, "rack_name": rack.rack_name, } # ==================== 跳接连接管理 ==================== def create_connection( self, port_a_id: str, port_b_id: str, fiber_length: float, remark: str, ) -> Optional[Connection]: """创建端口之间的跳接连接。 两个端口必须都存在且状态为空闲(FREE)。 Args: port_a_id: A 端端口 ID。 port_b_id: B 端端口 ID。 fiber_length: 光纤长度(米)。 remark: 备注。 Returns: 创建的 Connection 对象,端口不存在或端口繁忙时返回 None。 """ port_a = self._ports.get(port_a_id) port_b = self._ports.get(port_b_id) if not port_a or not port_b: return None if port_a.status != PortStatus.FREE or port_b.status != PortStatus.FREE: return None if port_a_id == port_b_id: return None connection_id = f"conn-{uuid.uuid4().hex[:8]}" conn = Connection( connection_id=connection_id, port_a_id=port_a_id, port_b_id=port_b_id, fiber_length=fiber_length, create_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), remark=remark, ) port_a.status = PortStatus.IN_USE port_b.status = PortStatus.IN_USE self._connections[connection_id] = conn return conn def list_connections(self) -> list[Connection]: """获取所有跳接连接列表。 Returns: 连接对象列表。 """ return list(self._connections.values()) def delete_connection(self, connection_id: str) -> bool: """删除跳接连接(释放两个端口状态为空闲)。 Args: connection_id: 连接 ID。 Returns: 删除成功返回 True,连接不存在返回 False。 """ conn = self._connections.get(connection_id) if not conn: return False port_a = self._ports.get(conn.port_a_id) port_b = self._ports.get(conn.port_b_id) if port_a: port_a.status = PortStatus.FREE if port_b: port_b.status = PortStatus.FREE del self._connections[connection_id] return True def get_port_path(self, port_id: str) -> Optional[dict]: """查询指定端口的连接路径信息。 Args: port_id: 端口 ID。 Returns: 包含端口信息和关联连接的字典,端口不存在时返回 None。 """ port = self._ports.get(port_id) if not port: return None unit = self._units.get(port.unit_id) rack = self._racks.get(unit.rack_id) if unit else None connected_conn = None for conn in self._connections.values(): if conn.port_a_id == port_id or conn.port_b_id == port_id: connected_conn = conn break other_port = None if connected_conn: other_port_id = ( connected_conn.port_b_id if connected_conn.port_a_id == port_id else connected_conn.port_a_id ) other_port = self.get_port_detail(other_port_id) return { "port": { "port_id": port.port_id, "port_number": port.port_number, "port_type": port.port_type, "status": port.status, "label": port.label, "unit_id": unit.unit_id if unit else "", "unit_number": unit.unit_number if unit else 0, "rack_id": rack.rack_id if rack else "", "rack_name": rack.rack_name if rack else "", }, "connection": { "connection_id": connected_conn.connection_id if connected_conn else None, "fiber_length": connected_conn.fiber_length if connected_conn else 0, "create_time": connected_conn.create_time if connected_conn else "", "remark": connected_conn.remark if connected_conn else "", } if connected_conn else None, "connected_port": other_port, } # 全局单例服务实例 service = OdfService()