Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
127c57dc3a | |||
d6b0b8ea36 | |||
23d7841ccf | |||
247490c35d | |||
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
|
||||
}
|
2
database/cache/new.go
vendored
2
database/cache/new.go
vendored
@ -45,7 +45,7 @@ func New(opts ...OptionFn) (Cache, error) {
|
||||
Password: password,
|
||||
})
|
||||
|
||||
if err = client.Ping(tool.CtxTimeout(cfg.ctx, 5)).Err(); err != nil {
|
||||
if err = client.Ping(tool.TimeoutCtx(cfg.ctx, 5)).Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
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 {
|
||||
}
|
19
resp/msg.go
19
resp/msg.go
@ -1,15 +1,16 @@
|
||||
package resp
|
||||
|
||||
const (
|
||||
Msg200 = "操作成功"
|
||||
Msg400 = "参数错误"
|
||||
Msg401 = "登录信息不存在或已过期, 请重新登录"
|
||||
Msg401NoMulti = "用户已在其他地方登录"
|
||||
Msg403 = "权限不足"
|
||||
Msg404 = "资源不存在"
|
||||
Msg500 = "服务器开小差了"
|
||||
Msg501 = "服务不可用"
|
||||
Msg503 = "服务不可用或正在升级, 请联系管理员"
|
||||
Msg200 = "操作成功"
|
||||
Msg400 = "参数错误"
|
||||
Msg401 = "该账号登录已失效, 请重新登录"
|
||||
Msg401NoMulti = "用户已在其他地方登录"
|
||||
Msg401Inactive = "当前用户尚未生效, 请稍后再试"
|
||||
Msg403 = "权限不足"
|
||||
Msg404 = "资源不存在"
|
||||
Msg500 = "服务器开小差了"
|
||||
Msg501 = "服务不可用"
|
||||
Msg503 = "服务不可用或正在升级, 请联系管理员"
|
||||
)
|
||||
|
||||
func Msg(status int) string {
|
||||
|
52
resp/resp.go
52
resp/resp.go
@ -3,6 +3,7 @@ package resp
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type res struct {
|
||||
@ -42,18 +43,44 @@ func RE(c *gin.Context, err error) {
|
||||
|
||||
func _r(c *gin.Context, r *res, args ...any) {
|
||||
length := len(args)
|
||||
switch length {
|
||||
case 0:
|
||||
break
|
||||
case 1:
|
||||
if msg, ok := args[0].(string); ok {
|
||||
r.Msg = msg
|
||||
}
|
||||
case 2:
|
||||
r.Data = args[1]
|
||||
case 3:
|
||||
|
||||
if length == 0 {
|
||||
goto END
|
||||
}
|
||||
|
||||
if length >= 4 {
|
||||
goto H4
|
||||
}
|
||||
|
||||
if length >= 3 {
|
||||
goto H3
|
||||
}
|
||||
|
||||
if length >= 2 {
|
||||
goto H2
|
||||
}
|
||||
if length >= 1 {
|
||||
goto H1
|
||||
}
|
||||
|
||||
H4:
|
||||
if code, err := cast.ToIntE(args[3]); err == nil {
|
||||
r.Code = code
|
||||
}
|
||||
H3:
|
||||
if es, ok := args[2].(error); ok {
|
||||
r.Err = es.Error()
|
||||
} else {
|
||||
r.Err = args[2]
|
||||
}
|
||||
H2:
|
||||
r.Data = args[1]
|
||||
H1:
|
||||
if msg, ok := args[0].(string); ok {
|
||||
r.Msg = msg
|
||||
}
|
||||
|
||||
END:
|
||||
|
||||
if r.Msg == "" {
|
||||
r.Msg = Msg(r.Status)
|
||||
@ -65,6 +92,7 @@ func _r(c *gin.Context, r *res, args ...any) {
|
||||
func R400(c *gin.Context, args ...any) {
|
||||
r := &res{
|
||||
Status: 400,
|
||||
Code: -1,
|
||||
}
|
||||
|
||||
_r(c, r, args...)
|
||||
@ -73,6 +101,7 @@ func R400(c *gin.Context, args ...any) {
|
||||
func R401(c *gin.Context, args ...any) {
|
||||
r := &res{
|
||||
Status: 401,
|
||||
Code: -1,
|
||||
}
|
||||
|
||||
_r(c, r, args...)
|
||||
@ -81,6 +110,7 @@ func R401(c *gin.Context, args ...any) {
|
||||
func R403(c *gin.Context, args ...any) {
|
||||
r := &res{
|
||||
Status: 403,
|
||||
Code: -1,
|
||||
}
|
||||
|
||||
_r(c, r, args...)
|
||||
@ -89,6 +119,7 @@ func R403(c *gin.Context, args ...any) {
|
||||
func R500(c *gin.Context, args ...any) {
|
||||
r := &res{
|
||||
Status: 500,
|
||||
Code: -1,
|
||||
}
|
||||
|
||||
_r(c, r, args...)
|
||||
@ -97,6 +128,7 @@ func R500(c *gin.Context, args ...any) {
|
||||
func R501(c *gin.Context, args ...any) {
|
||||
r := &res{
|
||||
Status: 501,
|
||||
Code: -1,
|
||||
}
|
||||
|
||||
_r(c, r, args...)
|
||||
|
9
resp/resp_test.go
Normal file
9
resp/resp_test.go
Normal file
@ -0,0 +1,9 @@
|
||||
package resp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestResp(t *testing.T) {
|
||||
|
||||
}
|
@ -23,7 +23,7 @@ func Timeout(seconds ...int) (ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
func CtxTimeout(ctx context.Context, seconds ...int) context.Context {
|
||||
func TimeoutCtx(ctx context.Context, seconds ...int) context.Context {
|
||||
var (
|
||||
duration time.Duration
|
||||
)
|
||||
|
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"gitea.loveuer.com/yizhisec/packages/logger"
|
||||
"sync"
|
||||
)
|
||||
|
||||
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