ports.go
54 lines1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package internal
import (
"fmt"
"strconv"
"strings"
)
// AllocatePort finds the next available port starting at 5002.
// Scans running Docker containers for used host ports.
func AllocatePort() (int, error) {
containers, _ := ListContainers()
used := make(map[int]bool)
for _, c := range containers {
for _, port := range parseHostPorts(c.Ports) {
used[port] = true
}
}
// Start at 5002 — port 5001 is used by the dev platform itself.
for port := 5002; port < 5100; port++ {
if !used[port] {
return port, nil
}
}
return 0, fmt.Errorf("no available ports")
}
// parseHostPorts extracts host ports from a Docker ports string like
// "0.0.0.0:5002->5000/tcp, 0.0.0.0:5003->8080/tcp"
func parseHostPorts(ports string) []int {
var result []int
for _, part := range strings.Split(ports, ",") {
part = strings.TrimSpace(part)
if part == "" {
continue
}
// Format: "0.0.0.0:5002->5000/tcp" or ":::5002->5000/tcp"
arrow := strings.Index(part, "->")
if arrow < 0 {
continue
}
hostPart := part[:arrow]
// Extract port from "0.0.0.0:5002" or just "5002"
colon := strings.LastIndex(hostPart, ":")
if colon < 0 {
continue
}
portStr := hostPart[colon+1:]
if port, err := strconv.Atoi(portStr); err == nil {
result = append(result, port)
}
}
return result
}