Files
tunnel-please/internal/port/port.go
T
bagas 5857dec730
SonarQube Scan / SonarQube Trigger (push) Successful in 4m6s
Docker Build and Push / Run Tests (push) Successful in 2m31s
Docker Build and Push / Build and Push Docker Image (push) Successful in 18m4s
Fix data races across session/forwarder/registry, resolve POST/PUT hang, harden port allocation, add frontendURL env (#157)
Reviewed-on: #157
Co-authored-by: Bagas <bagas@fossy.my.id>
Co-committed-by: Bagas <bagas@fossy.my.id>
2026-07-19 14:10:50 +07:00

89 lines
1.6 KiB
Go

package port
import (
"fmt"
"sort"
"sync"
)
type Port interface {
AddRange(startPort, endPort uint16) error
Unassigned() (uint16, bool)
SetStatus(port uint16, assigned bool) error
Claim(port uint16) (claimed bool)
}
type port struct {
mu sync.RWMutex
ports map[uint16]bool
sortedPorts []uint16
}
func New() Port {
return &port{
ports: make(map[uint16]bool),
sortedPorts: []uint16{},
}
}
func (pm *port) AddRange(startPort, endPort uint16) error {
pm.mu.Lock()
defer pm.mu.Unlock()
if startPort > endPort {
return fmt.Errorf("start port cannot be greater than end port")
}
for index := startPort; ; index++ {
if index != 0 {
if _, exists := pm.ports[index]; !exists {
pm.ports[index] = false
pm.sortedPorts = append(pm.sortedPorts, index)
}
}
if index == endPort {
break
}
}
sort.Slice(pm.sortedPorts, func(i, j int) bool {
return pm.sortedPorts[i] < pm.sortedPorts[j]
})
return nil
}
func (pm *port) Unassigned() (uint16, bool) {
pm.mu.Lock()
defer pm.mu.Unlock()
for _, index := range pm.sortedPorts {
if !pm.ports[index] {
pm.ports[index] = true
return index, true
}
}
return 0, false
}
func (pm *port) SetStatus(port uint16, assigned bool) error {
pm.mu.Lock()
defer pm.mu.Unlock()
if _, exists := pm.ports[port]; !exists {
return fmt.Errorf("port %d is not in the allowed range", port)
}
pm.ports[port] = assigned
return nil
}
func (pm *port) Claim(port uint16) (claimed bool) {
pm.mu.Lock()
defer pm.mu.Unlock()
status, exists := pm.ports[port]
if !exists || status {
return false
}
pm.ports[port] = true
return true
}