fix(go): repair migration wire contracts and runtime lifecycle; document incomplete port
This commit is contained in:
1 parent
e43a310617
commit
32e47014b5
35 files changed
+16826
-438
No files matched your search
+30
-69
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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{
|
||||
|
||||
Reference in new issue
Block a user