Files
2026-05-12 15:45:50 +08:00

279 lines
7.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package portmanager
import (
"errors"
"fmt"
"net"
"sync"
"time"
"FireLeave_tool/logger"
)
// PortManager 管理端口分配
type PortManager struct {
mu sync.Mutex
allocated map[string]DevicePorts // DeviceUUID 到端口映射的映射
portPool []int // 推理端口池(HTTP
available map[int]bool // 可用端口标记
}
// NewPortManager 创建端口管理器
func NewPortManager() *PortManager {
// 初始化端口池
var ports []int
for port := BasePortStart; port <= BasePortEnd; port++ {
ports = append(ports, port)
}
// 初始化可用端口映射
available := make(map[int]bool)
for _, port := range ports {
available[port] = true
}
return &PortManager{
allocated: make(map[string]DevicePorts),
portPool: ports,
available: available,
}
}
// AllocatePort 为设备分配基础端口
func (pm *PortManager) AllocatePort(deviceUUID string) (int, error) {
pm.mu.Lock()
defer pm.mu.Unlock()
// 检查设备是否已分配端口
if ports, exists := pm.allocated[deviceUUID]; exists {
logger.Logger.Printf("Device %s already allocated port: %d", deviceUUID, ports.Inference)
return ports.Inference, nil
}
// 查找可用端口
for _, port := range pm.portPool {
if !pm.available[port] {
continue // 端口已被分配
}
tempPort := port + TemperaturePortOffset // 温度端口(TCP
// 检查推理端口(HTTP)是否可用
inferenceLn, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
logger.Logger.Printf("Port %d (inference) is not available: %v", port, err)
continue
}
inferenceLn.Close()
// 检查温度端口(TCP)是否可用
tempLn, err := net.Listen("tcp", fmt.Sprintf(":%d", tempPort))
if err != nil {
logger.Logger.Printf("Port %d (temperature) is not available: %v", tempPort, err)
continue
}
tempLn.Close()
// 端口可用,记录分配
pm.allocated[deviceUUID] = DevicePorts{
Inference: port,
Temperature: tempPort,
}
pm.available[port] = false
logger.Logger.Printf("Port allocated for device %s: inference=%d, temperature=%d",
deviceUUID, port, tempPort)
return port, nil
}
return 0, errors.New("no available ports for inference and temperature")
}
// AllocateFireCheckPort 为火焰检测程序分配端口
func (pm *PortManager) AllocateFireCheckPort(deviceUUID string) (int, error) {
pm.mu.Lock()
defer pm.mu.Unlock()
// 检查设备是否已分配端口
ports, exists := pm.allocated[deviceUUID]
if !exists {
// 先分配基础端口
_, err := pm.AllocatePort(deviceUUID)
if err != nil {
return 0, fmt.Errorf("failed to allocate base port: %v", err)
}
// 重新获取更新后的端口映射
ports = pm.allocated[deviceUUID]
}
// 计算火焰检测端口
fireCheckPort := ports.Inference + FireCheckPortOffset
// 检查火焰检测端口是否可用
fireCheckLn, err := net.Listen("tcp", fmt.Sprintf(":%d", fireCheckPort))
if err != nil {
logger.Logger.Printf("Port %d (fire_check) is not available: %v", fireCheckPort, err)
return 0, fmt.Errorf("fire check port %d not available: %v", fireCheckPort, err)
}
fireCheckLn.Close()
// 更新端口映射
ports.FireCheck = fireCheckPort
pm.allocated[deviceUUID] = ports
logger.Logger.Printf("Fire check port allocated for device %s: %d", deviceUUID, fireCheckPort)
return fireCheckPort, nil
}
// ReleasePort 释放设备端口
func (pm *PortManager) ReleasePort(deviceUUID string) {
pm.mu.Lock()
defer pm.mu.Unlock()
// 删除设备端口映射
if ports, exists := pm.allocated[deviceUUID]; exists {
delete(pm.allocated, deviceUUID)
pm.available[ports.Inference] = true // 标记基础端口为可用
logger.Logger.Printf("Port released for device %s: inference=%d, temperature=%d, fire_check=%d",
deviceUUID, ports.Inference, ports.Temperature, ports.FireCheck)
}
}
// GetPort 获取设备基础端口
func (pm *PortManager) GetPort(deviceUUID string) (int, error) {
pm.mu.Lock()
defer pm.mu.Unlock()
if ports, exists := pm.allocated[deviceUUID]; exists {
return ports.Inference, nil
}
return 0, fmt.Errorf("device %s has no allocated port", deviceUUID)
}
// GetFireCheckPort 获取火焰检测程序端口
func (pm *PortManager) GetFireCheckPort(deviceUUID string) (int, error) {
pm.mu.Lock()
defer pm.mu.Unlock()
if ports, exists := pm.allocated[deviceUUID]; exists {
if ports.FireCheck > 0 {
return ports.FireCheck, nil
}
return 0, fmt.Errorf("device %s has no allocated fire check port", deviceUUID)
}
return 0, fmt.Errorf("device %s has no allocated ports", deviceUUID)
}
// GetTemperaturePort 获取温度程序端口
func (pm *PortManager) GetTemperaturePort(deviceUUID string) (int, error) {
pm.mu.Lock()
defer pm.mu.Unlock()
if ports, exists := pm.allocated[deviceUUID]; exists {
return ports.Temperature, nil
}
return 0, fmt.Errorf("device %s has no allocated ports", deviceUUID)
}
// GetAllocatedPorts 获取所有已分配的端口信息
func (pm *PortManager) GetAllocatedPorts() []PortInfo {
pm.mu.Lock()
defer pm.mu.Unlock()
var portInfos []PortInfo
now := time.Now().Unix()
for deviceUUID, ports := range pm.allocated {
// 基础推理端口
portInfos = append(portInfos, PortInfo{
DeviceUUID: deviceUUID,
PortType: PortTypeInference,
Port: ports.Inference,
AllocatedAt: now,
})
// 温度端口
portInfos = append(portInfos, PortInfo{
DeviceUUID: deviceUUID,
PortType: PortTypeTemperature,
Port: ports.Temperature,
AllocatedAt: now,
})
// 火焰检测端口
if ports.FireCheck > 0 {
portInfos = append(portInfos, PortInfo{
DeviceUUID: deviceUUID,
PortType: PortTypeFireCheck,
Port: ports.FireCheck,
AllocatedAt: now,
})
}
// 新推理端口
if ports.NewInference > 0 {
portInfos = append(portInfos, PortInfo{
DeviceUUID: deviceUUID,
PortType: PortTypeNewInference,
Port: ports.NewInference,
AllocatedAt: now,
})
}
}
return portInfos
}
// GetDevicePorts 获取设备的所有端口
func (pm *PortManager) GetDevicePorts(deviceUUID string) (DevicePorts, error) {
pm.mu.Lock()
defer pm.mu.Unlock()
if ports, exists := pm.allocated[deviceUUID]; exists {
return ports, nil
}
return DevicePorts{}, fmt.Errorf("device %s has no allocated ports", deviceUUID)
}
// IsPortAvailable 检查端口是否可用
func (pm *PortManager) IsPortAvailable(port int) bool {
pm.mu.Lock()
defer pm.mu.Unlock()
// 检查是否在端口池中
for _, p := range pm.portPool {
if p == port {
return pm.available[port]
}
}
// 对于非端口池中的端口,直接检查可用性
ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
return false
}
ln.Close()
return true
}
// GetAvailablePortCount 获取可用端口数量
func (pm *PortManager) GetAvailablePortCount() int {
pm.mu.Lock()
defer pm.mu.Unlock()
count := 0
for _, available := range pm.available {
if available {
count++
}
}
return count
}
// GlobalPortManager 全局端口管理器
var GlobalPortManager = NewPortManager()