package api import ( "context" "crypto/tls" "errors" "gitea.loveuer.com/yizhisec/packages/handler" "gitea.loveuer.com/yizhisec/packages/logger" "github.com/gin-gonic/gin" "net" "net/http" ) type Option func(*option) type option struct { name string version string address string app *gin.Engine tlsConfig *tls.Config } func WithName(name string) Option { return func(o *option) { if name != "" { o.name = name } } } func WithVersion(version string) Option { return func(o *option) { if version != "" { o.version = version } } } func WithAddress(address string) Option { return func(o *option) { if address != "" { o.address = address } } } func WithApp(app *gin.Engine) Option { return func(o *option) { if app != nil { o.app = app } } } func WithTLSConfig(tlsConfig *tls.Config) Option { return func(o *option) { if tlsConfig != nil { o.tlsConfig = tlsConfig } } } func New(ctx context.Context, optFns ...Option) (func(context.Context) error, error) { var ( err error fn func(context.Context) error ln net.Listener opt = &option{ name: "unknown", version: "v0.0.1", address: "127.0.0.1:9119", tlsConfig: nil, } ) for _, ofn := range optFns { ofn(opt) } if opt.app == nil { opt.app = gin.Default() opt.app.GET("/healthz", handler.Healthz(opt.name, opt.version)) } if opt.tlsConfig != nil { ln, err = tls.Listen("tcp", opt.address, opt.tlsConfig) } else { ln, err = net.Listen("tcp", opt.address) } if err != nil { return fn, err } svc := &http.Server{ Handler: opt.app, } go func() { logger.InfoCtx(ctx, "[%s] api svc running at: %s", opt.name, opt.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...", opt.name) return svc.Shutdown(timeout) } return fn, nil }