Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
fad0b852cb | |||
7f49105b23 | |||
6cd0fa3d6c | |||
9c8460fc44 | |||
5df55a364d |
115
api/api.go
Normal file
115
api/api.go
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
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
|
||||||
|
}
|
19
handler/healthz.go
Normal file
19
handler/healthz.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.loveuer.com/yizhisec/packages/resp"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Healthz(name, version string) gin.HandlerFunc {
|
||||||
|
start := time.Now()
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
resp.R200(c, gin.H{
|
||||||
|
"name": name,
|
||||||
|
"version": version,
|
||||||
|
"start_at": start,
|
||||||
|
"uptime": time.Since(start).String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
4
opt/opt.go
Normal file
4
opt/opt.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
package opt
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
}
|
@ -3,7 +3,7 @@ package resp
|
|||||||
const (
|
const (
|
||||||
Msg200 = "操作成功"
|
Msg200 = "操作成功"
|
||||||
Msg400 = "参数错误"
|
Msg400 = "参数错误"
|
||||||
Msg401 = "登录信息不存在或已过期, 请重新登录"
|
Msg401 = "该账号登录已失效, 请重新登录"
|
||||||
Msg401NoMulti = "用户已在其他地方登录"
|
Msg401NoMulti = "用户已在其他地方登录"
|
||||||
Msg403 = "权限不足"
|
Msg403 = "权限不足"
|
||||||
Msg404 = "资源不存在"
|
Msg404 = "资源不存在"
|
||||||
|
10
resp/resp.go
10
resp/resp.go
@ -3,6 +3,7 @@ package resp
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/spf13/cast"
|
||||||
)
|
)
|
||||||
|
|
||||||
type res struct {
|
type res struct {
|
||||||
@ -53,6 +54,10 @@ func _r(c *gin.Context, r *res, args ...any) {
|
|||||||
r.Data = args[1]
|
r.Data = args[1]
|
||||||
case 3:
|
case 3:
|
||||||
r.Err = args[2]
|
r.Err = args[2]
|
||||||
|
case 4:
|
||||||
|
if code, err := cast.ToIntE(args[3]); err == nil {
|
||||||
|
r.Code = code
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Msg == "" {
|
if r.Msg == "" {
|
||||||
@ -65,6 +70,7 @@ func _r(c *gin.Context, r *res, args ...any) {
|
|||||||
func R400(c *gin.Context, args ...any) {
|
func R400(c *gin.Context, args ...any) {
|
||||||
r := &res{
|
r := &res{
|
||||||
Status: 400,
|
Status: 400,
|
||||||
|
Code: -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
_r(c, r, args...)
|
_r(c, r, args...)
|
||||||
@ -73,6 +79,7 @@ func R400(c *gin.Context, args ...any) {
|
|||||||
func R401(c *gin.Context, args ...any) {
|
func R401(c *gin.Context, args ...any) {
|
||||||
r := &res{
|
r := &res{
|
||||||
Status: 401,
|
Status: 401,
|
||||||
|
Code: -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
_r(c, r, args...)
|
_r(c, r, args...)
|
||||||
@ -81,6 +88,7 @@ func R401(c *gin.Context, args ...any) {
|
|||||||
func R403(c *gin.Context, args ...any) {
|
func R403(c *gin.Context, args ...any) {
|
||||||
r := &res{
|
r := &res{
|
||||||
Status: 403,
|
Status: 403,
|
||||||
|
Code: -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
_r(c, r, args...)
|
_r(c, r, args...)
|
||||||
@ -89,6 +97,7 @@ func R403(c *gin.Context, args ...any) {
|
|||||||
func R500(c *gin.Context, args ...any) {
|
func R500(c *gin.Context, args ...any) {
|
||||||
r := &res{
|
r := &res{
|
||||||
Status: 500,
|
Status: 500,
|
||||||
|
Code: -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
_r(c, r, args...)
|
_r(c, r, args...)
|
||||||
@ -97,6 +106,7 @@ func R500(c *gin.Context, args ...any) {
|
|||||||
func R501(c *gin.Context, args ...any) {
|
func R501(c *gin.Context, args ...any) {
|
||||||
r := &res{
|
r := &res{
|
||||||
Status: 501,
|
Status: 501,
|
||||||
|
Code: -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
_r(c, r, args...)
|
_r(c, r, args...)
|
||||||
|
12
tool/gin.go
Normal file
12
tool/gin.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package tool
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
func Local(c *gin.Context, key string) any {
|
||||||
|
data, ok := c.Get(key)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
40
tool/must.go
40
tool/must.go
@ -1,7 +1,9 @@
|
|||||||
package tool
|
package tool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"gitea.loveuer.com/yizhisec/packages/logger"
|
"gitea.loveuer.com/yizhisec/packages/logger"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Must(errs ...error) {
|
func Must(errs ...error) {
|
||||||
@ -11,3 +13,41 @@ func Must(errs ...error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user