fix(go): repair migration wire contracts and runtime lifecycle; document incomplete port

This commit is contained in:
CAtlas0784 committed 2026-10-29 15:35:35 +07:00
1 parent e43a310617
commit 32e47014b5
35 files changed
+16826 -438

No files matched your search

+30 -69
View File
@@ -60,80 +60,41 @@ func New(cfg *config.Config, publicDir, certDir string) *Gateway {
}
func (g *Gateway) Start() error {
ctx, cancel := context.WithCancel(context.Background())
g.cancelFunc = cancel
cert, err := tls.LoadX509KeyPair(filepath.Join(g.certDir, "cert.pem"), filepath.Join(g.certDir, "key.pem"))
if err != nil {
return fmt.Errorf("load gateway TLS certificate: %w", err)
}
mux := http.NewServeMux()
mux.HandleFunc("/", g.handleDispatch)
// 1. Port 5801: LoginList & Mobile Dispatch Server
listAddr := fmt.Sprintf("%s:%d", g.cfg.Network.BindHost, g.cfg.Network.Proxy.LoginListPort)
g.listSrv = &http.Server{
Addr: listAddr,
Handler: mux,
}
go func() {
log.Printf("[GATEWAY] LoginList & Mobile Dispatch listening on http://%s (Port %d)", g.cfg.Network.AdvertisedHost, g.cfg.Network.Proxy.LoginListPort)
if err := g.listSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Printf("[GATEWAY] LoginList server error: %v", err)
}
}()
// 2. Port 80: HTTP Gateway
httpAddr := fmt.Sprintf("%s:%d", g.cfg.Network.BindHost, g.cfg.Network.Proxy.HttpPort)
g.httpSrv = &http.Server{
Addr: httpAddr,
Handler: mux,
}
go func() {
log.Printf("[GATEWAY] HTTP Proxy listening on port %d", g.cfg.Network.Proxy.HttpPort)
if err := g.httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Printf("[GATEWAY] HTTP Proxy error (might need Admin privileges for port 80): %v", err)
}
}()
// 3. Port 443: HTTPS Proxy with TLS SNI
certFile := filepath.Join(g.certDir, "cert.pem")
keyFile := filepath.Join(g.certDir, "key.pem")
if _, err := os.Stat(certFile); err == nil {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err == nil {
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
return &cert, nil
},
addr := func(port int) string { return net.JoinHostPort(g.cfg.Network.BindHost, fmt.Sprint(port)) }
g.listSrv = &http.Server{Addr: addr(g.cfg.Network.Proxy.LoginListPort), Handler: mux}
g.httpSrv = &http.Server{Addr: addr(g.cfg.Network.Proxy.HttpPort), Handler: mux}
g.httpsSrv = &http.Server{Addr: addr(g.cfg.Network.Proxy.HttpsPort), Handler: mux,
TLSConfig: &tls.Config{Certificates: []tls.Certificate{cert}, MinVersion: tls.VersionTLS12}}
servers := []*http.Server{g.listSrv, g.httpSrv, g.httpsSrv}
listeners := make([]net.Listener, 0, len(servers))
for _, srv := range servers {
ln, err := net.Listen("tcp", srv.Addr)
if err != nil {
for _, opened := range listeners {
opened.Close()
}
httpsAddr := fmt.Sprintf("%s:%d", g.cfg.Network.BindHost, g.cfg.Network.Proxy.HttpsPort)
g.httpsSrv = &http.Server{
Addr: httpsAddr,
Handler: mux,
TLSConfig: tlsConfig,
}
go func() {
log.Printf("[GATEWAY] HTTPS SNI Proxy listening on port %d", g.cfg.Network.Proxy.HttpsPort)
ln, err := net.Listen("tcp", httpsAddr)
if err != nil {
log.Printf("[GATEWAY] HTTPS Proxy listen error (port 443): %v", err)
return
}
tlsLn := tls.NewListener(ln, tlsConfig)
if err := g.httpsSrv.Serve(tlsLn); err != nil && err != http.ErrServerClosed {
log.Printf("[GATEWAY] HTTPS Proxy error: %v", err)
}
}()
} else {
log.Printf("[GATEWAY] Warning: failed to load TLS certificate %s: %v", certFile, err)
return fmt.Errorf("listen gateway %s: %w", srv.Addr, err)
}
} else {
log.Printf("[GATEWAY] Warning: cert.pem not found in %s; HTTPS port 443 disabled", g.certDir)
listeners = append(listeners, ln)
}
for i, srv := range servers {
ln := listeners[i]
if srv == g.httpsSrv {
ln = tls.NewListener(ln, srv.TLSConfig)
}
log.Printf("[GATEWAY] Listening on %s", ln.Addr())
go func() {
if err := srv.Serve(ln); err != nil && err != http.ErrServerClosed {
log.Printf("[GATEWAY] Serve error: %v", err)
}
}()
}
_ = ctx
return nil
}
+37
View File
@@ -1,6 +1,8 @@
package gateway
import (
"fmt"
"net"
"net/http"
"net/http/httptest"
"strings"
@@ -9,6 +11,41 @@ import (
"ananta-ps/internal/config"
)
func TestGatewayReportsBindFailureAndRollsBack(t *testing.T) {
blocker, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer blocker.Close()
probe, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
listPort := probe.Addr().(*net.TCPAddr).Port
probe.Close()
cfg := &config.Config{Network: config.NetworkConfig{BindHost: "127.0.0.1", Proxy: config.ProxyConfig{
LoginListPort: listPort, HttpPort: blocker.Addr().(*net.TCPAddr).Port,
}}}
gw := New(cfg, "../../public", "../../certs")
if err := gw.Start(); err == nil {
gw.Stop()
t.Fatal("occupied HTTP port reported as ready")
}
ln, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", fmt.Sprint(listPort)))
if err != nil {
t.Fatalf("partial startup leaked login-list listener: %v", err)
}
ln.Close()
}
func TestGatewayRequiresUsableTLSCertificate(t *testing.T) {
gw := New(&config.Config{}, t.TempDir(), t.TempDir())
if err := gw.Start(); err == nil {
gw.Stop()
t.Fatal("missing certificate silently disabled HTTPS")
}
}
func TestGatewayDispatch(t *testing.T) {
cfg := &config.Config{
Client: config.ClientConfig{