"""Endpoint model for devices behind gateways.""" from datetime import datetime from enum import Enum as PyEnum from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Enum, Text from sqlalchemy.orm import relationship from ..database import Base class Protocol(str, PyEnum): """Network protocol for endpoint access.""" TCP = "tcp" UDP = "udp" class Endpoint(Base): """Endpoint model representing a device/service behind a gateway.""" __tablename__ = "endpoints" id = Column(Integer, primary_key=True, index=True) gateway_id = Column(Integer, ForeignKey("gateways.id"), nullable=False) # Endpoint info name = Column(String(255), nullable=False) description = Column(Text, nullable=True) # Network configuration internal_ip = Column(String(45), nullable=False) # IP in customer network port = Column(Integer, nullable=False) protocol = Column(Enum(Protocol), default=Protocol.TCP, nullable=False) # Application info application_name = Column(String(100), nullable=True) # e.g., "CoDeSys", "SSH", "HTTP" application_template_id = Column(Integer, ForeignKey("application_templates.id"), nullable=True) # Timestamps created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Relationships gateway = relationship("Gateway", back_populates="endpoints") user_access = relationship("UserEndpointAccess", back_populates="endpoint", cascade="all, delete-orphan") application_template = relationship("ApplicationTemplate") connection_logs = relationship("ConnectionLog", back_populates="endpoint") def __repr__(self): return f"" @property def address(self) -> str: """Get full address string.""" return f"{self.internal_ip}:{self.port}" class ApplicationTemplate(Base): """Pre-defined application templates with default ports.""" __tablename__ = "application_templates" id = Column(Integer, primary_key=True, index=True) name = Column(String(100), nullable=False, unique=True) description = Column(Text, nullable=True) default_port = Column(Integer, nullable=False) protocol = Column(Enum(Protocol), default=Protocol.TCP, nullable=False) icon = Column(String(100), nullable=True) # Icon name for client UI created_at = Column(DateTime, default=datetime.utcnow, nullable=False) def __repr__(self): return f"" # Default application templates to be seeded DEFAULT_APPLICATION_TEMPLATES = [ {"name": "CoDeSys", "description": "CoDeSys Runtime/Gateway", "default_port": 11740, "protocol": "tcp"}, {"name": "CoDeSys Gateway", "description": "CoDeSys Gateway Service", "default_port": 1217, "protocol": "tcp"}, {"name": "SSH", "description": "Secure Shell", "default_port": 22, "protocol": "tcp"}, {"name": "HTTP", "description": "Web Interface", "default_port": 80, "protocol": "tcp"}, {"name": "HTTPS", "description": "Secure Web Interface", "default_port": 443, "protocol": "tcp"}, {"name": "VNC", "description": "Virtual Network Computing", "default_port": 5900, "protocol": "tcp"}, {"name": "RDP", "description": "Remote Desktop Protocol", "default_port": 3389, "protocol": "tcp"}, {"name": "Modbus TCP", "description": "Modbus over TCP/IP", "default_port": 502, "protocol": "tcp"}, {"name": "OPC UA", "description": "OPC Unified Architecture", "default_port": 4840, "protocol": "tcp"}, {"name": "MQTT", "description": "Message Queue Telemetry Transport", "default_port": 1883, "protocol": "tcp"}, {"name": "S7 Communication", "description": "Siemens S7 Protocol", "default_port": 102, "protocol": "tcp"}, ]