Files
mygo/internal/server/server.go
Huxley 7fb125ea87 Implement web API foundation
Add application container, Gin router, graceful shutdown handler,
and version endpoint. This establishes the skeleton for the WebDisk
HTTP API as described in the architecture.

- Add internal/app/WebApp for runtime dependencies and version
- Add internal/server/router with GET /api/v1/version route
- Add graceful shutdown runner with signal handling in cmd/serve
- Add internal/api/ErrorResponse for standard HTTP error body
- Update roadmap, architecture, and decisions documentation
2026-04-27 23:06:06 +08:00

50 lines
1.1 KiB
Go

package server
import (
"context"
"errors"
"fmt"
"net/http"
"time"
"github.com/dhao2001/mygo/internal/config"
)
// Address returns the HTTP listen address for a server config.
func Address(cfg config.ServerConfig) string {
return fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
}
// RunWithGracefulShutdown starts an HTTP server and shuts it down when ctx is canceled.
func RunWithGracefulShutdown(ctx context.Context, addr string, handler http.Handler) error {
if handler == nil {
return errors.New("handler: must not be nil")
}
httpServer := &http.Server{
Addr: addr,
Handler: handler,
ReadHeaderTimeout: 5 * time.Second,
}
errCh := make(chan error, 1)
go func() {
errCh <- httpServer.ListenAndServe()
}()
select {
case <-ctx.Done():
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := httpServer.Shutdown(shutdownCtx); err != nil {
return fmt.Errorf("shutdown server: %w", err)
}
return nil
case err := <-errCh:
if errors.Is(err, http.ErrServerClosed) {
return nil
}
return fmt.Errorf("listen and serve: %w", err)
}
}