diff --git a/api/api.go b/api/api.go new file mode 100644 index 0000000..add4303 --- /dev/null +++ b/api/api.go @@ -0,0 +1,60 @@ +package api + +import ( + "context" + "crypto/tls" + "errors" + "gitea.loveuer.com/yizhisec/packages/logger" + "github.com/gin-gonic/gin" + "net" + "net/http" +) + +type Api struct { + Address string + Name string + App *gin.Engine + TlsConfig *tls.Config +} + +func New(ctx context.Context, api *Api) (func(context.Context) error, error) { + var ( + err error + fn func(context.Context) error + ln net.Listener + ) + + if api == nil { + return fn, errors.New("api is nil") + } + + if api.TlsConfig != nil { + ln, err = tls.Listen("tcp", api.Address, api.TlsConfig) + } else { + ln, err = net.Listen("tcp", api.Address) + } + + if err != nil { + return fn, err + } + + svc := &http.Server{ + Handler: api.App, + } + + go func() { + logger.InfoCtx(ctx, "[%s] api svc running at: %s", api.Name, api.Address) + if err = svc.Serve(ln); err != nil { + if !errors.Is(err, http.ErrServerClosed) { + logger.ErrorCtx(ctx, "api svc run failed, err = %s", err.Error()) + } + } + }() + + fn = func(timeout context.Context) error { + logger.WarnCtx(ctx, "[%s] api svc shutdown...", api.Name) + return svc.Shutdown(timeout) + } + + return fn, nil +} diff --git a/tool/must.go b/tool/must.go index 20154a0..742463c 100644 --- a/tool/must.go +++ b/tool/must.go @@ -1,7 +1,9 @@ package tool import ( + "context" "gitea.loveuer.com/yizhisec/packages/logger" + "sync" ) func Must(errs ...error) { @@ -16,3 +18,36 @@ func MustWithData[T any](data T, err error) T { Must(err) return data } + +func MustStop(ctx context.Context, stopFns ...func(ctx context.Context) error) { + if len(stopFns) == 0 { + return + } + + ok := make(chan struct{}) + + wg := &sync.WaitGroup{} + wg.Add(len(stopFns)) + + for _, fn := range stopFns { + go func() { + defer wg.Done() + + if err := fn(ctx); err != nil { + logger.ErrorCtx(ctx, "stop function failed, err = %s", err.Error()) + } + }() + } + + go func() { + select { + case <-ctx.Done(): + logger.FatalCtx(ctx, "stop function timeout, force down") + case _, _ = <-ok: + return + } + }() + + wg.Wait() + close(ok) +}