🎨 增加 Go 后端
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/spf13/viper"
|
||||
"os"
|
||||
"whois-go/internal/global"
|
||||
)
|
||||
|
||||
func NewConfig() *viper.Viper {
|
||||
envConf := os.Getenv("APP_CONF")
|
||||
if envConf == "" {
|
||||
flag.StringVar(&envConf, "conf", "config/local.yml", "config path, eg: -conf config/local.yml")
|
||||
flag.Parse()
|
||||
}
|
||||
if envConf == "" {
|
||||
envConf = "config/local.yml"
|
||||
}
|
||||
fmt.Println("load conf file:", envConf)
|
||||
return getConfig(envConf)
|
||||
|
||||
}
|
||||
func getConfig(path string) *viper.Viper {
|
||||
conf := viper.New()
|
||||
conf.SetConfigFile(path)
|
||||
err := conf.ReadInConfig()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
conf.WatchConfig()
|
||||
|
||||
conf.OnConfigChange(func(e fsnotify.Event) {
|
||||
fmt.Println("config file changed:", e.Name)
|
||||
if err = conf.Unmarshal(&global.G_CONFIG); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
})
|
||||
if err = conf.Unmarshal(&global.G_CONFIG); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return conf
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package convert
|
||||
|
||||
const (
|
||||
base62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
)
|
||||
|
||||
func IntToBase62(n int) string {
|
||||
if n == 0 {
|
||||
return string(base62[0])
|
||||
}
|
||||
|
||||
var result []byte
|
||||
for n > 0 {
|
||||
result = append(result, base62[n%62])
|
||||
n /= 62
|
||||
}
|
||||
|
||||
// 反转字符串
|
||||
for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 {
|
||||
result[i], result[j] = result[j], result[i]
|
||||
}
|
||||
|
||||
return string(result)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package md5
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
func Md5(str string) string {
|
||||
hash := md5.Sum([]byte(str))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package resp
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type response struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func HandleSuccess(ctx *gin.Context, data interface{}) {
|
||||
if data == nil {
|
||||
data = map[string]string{}
|
||||
}
|
||||
resp := response{Code: 0, Message: "success", Data: data}
|
||||
ctx.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
func HandleError(ctx *gin.Context, httpCode, code int, message string, data interface{}) {
|
||||
if data == nil {
|
||||
data = map[string]string{}
|
||||
}
|
||||
resp := response{Code: code, Message: message, Data: data}
|
||||
ctx.JSON(httpCode, resp)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package sid
|
||||
|
||||
import (
|
||||
"whois-go/pkg/helper/convert"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sony/sonyflake"
|
||||
)
|
||||
|
||||
type Sid struct {
|
||||
sf *sonyflake.Sonyflake
|
||||
}
|
||||
|
||||
func NewSid() *Sid {
|
||||
sf := sonyflake.NewSonyflake(sonyflake.Settings{})
|
||||
if sf == nil {
|
||||
panic("sonyflake not created")
|
||||
}
|
||||
return &Sid{sf}
|
||||
}
|
||||
func (s Sid) GenString() (string, error) {
|
||||
// 生成分布式ID
|
||||
id, err := s.sf.NextID()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to generate sonyflake ID")
|
||||
}
|
||||
// 将ID转换为字符串
|
||||
return convert.IntToBase62(int(id)), nil
|
||||
}
|
||||
func (s Sid) GenUint64() (uint64, error) {
|
||||
// 生成分布式ID
|
||||
return s.sf.NextID()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package uuid
|
||||
|
||||
import "github.com/google/uuid"
|
||||
|
||||
func GenUUID() string {
|
||||
return uuid.NewString()
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gin-gonic/gin"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Run(r *gin.Engine, addr string) {
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: r,
|
||||
}
|
||||
|
||||
// Initializing the server in a goroutine so that
|
||||
// it won't block the graceful shutdown handling below
|
||||
go func() {
|
||||
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatalf("listen: %s\n", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for interrupt signal to gracefully shutdown the server with
|
||||
// a timeout of 5 seconds.
|
||||
quit := make(chan os.Signal, 1)
|
||||
// kill (no param) default send syscall.SIGTERM
|
||||
// kill -2 is syscall.SIGINT
|
||||
// kill -9 is syscall.SIGKILL but can't be catch, so don't need add it
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
log.Println("Shutting down server...")
|
||||
|
||||
// The context is used to inform the server it has 5 seconds to finish
|
||||
// the request it is currently handling
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
log.Fatal("Server forced to shutdown: ", err)
|
||||
}
|
||||
|
||||
log.Println("Server exiting")
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
const LOGGER_KEY = "zapLogger"
|
||||
|
||||
type Logger struct {
|
||||
*zap.Logger
|
||||
}
|
||||
|
||||
func NewLog(conf *viper.Viper) *Logger {
|
||||
return initZap(conf)
|
||||
}
|
||||
|
||||
func initZap(conf *viper.Viper) *Logger {
|
||||
// 日志地址 "out.log" 自定义
|
||||
lp := conf.GetString("log.log_file_name")
|
||||
// 日志级别 DEBUG,ERROR, INFO
|
||||
lv := conf.GetString("log.log_level")
|
||||
var level zapcore.Level
|
||||
//debug<info<warn<error<fatal<panic
|
||||
switch lv {
|
||||
case "debug":
|
||||
level = zap.DebugLevel
|
||||
case "info":
|
||||
level = zap.InfoLevel
|
||||
case "warn":
|
||||
level = zap.WarnLevel
|
||||
case "error":
|
||||
level = zap.ErrorLevel
|
||||
default:
|
||||
level = zap.InfoLevel
|
||||
}
|
||||
hook := lumberjack.Logger{
|
||||
Filename: lp, // 日志文件路径
|
||||
MaxSize: conf.GetInt("log.max_size"), // 每个日志文件保存的最大尺寸 单位:M
|
||||
MaxBackups: conf.GetInt("log.max_backups"), // 日志文件最多保存多少个备份
|
||||
MaxAge: conf.GetInt("log.max_age"), // 文件最多保存多少天
|
||||
Compress: conf.GetBool("log.compress"), // 是否压缩
|
||||
}
|
||||
|
||||
var encoder zapcore.Encoder
|
||||
if conf.GetString("log.encoding") == "console" {
|
||||
encoder = zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
|
||||
TimeKey: "ts",
|
||||
LevelKey: "level",
|
||||
NameKey: "Logger",
|
||||
CallerKey: "caller",
|
||||
MessageKey: "msg",
|
||||
StacktraceKey: "stacktrace",
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeLevel: zapcore.LowercaseColorLevelEncoder,
|
||||
EncodeTime: timeEncoder,
|
||||
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||||
EncodeCaller: zapcore.FullCallerEncoder,
|
||||
})
|
||||
} else {
|
||||
encoder = zapcore.NewJSONEncoder(zapcore.EncoderConfig{
|
||||
TimeKey: "ts",
|
||||
LevelKey: "level",
|
||||
NameKey: "logger",
|
||||
CallerKey: "caller",
|
||||
FunctionKey: zapcore.OmitKey,
|
||||
MessageKey: "msg",
|
||||
StacktraceKey: "stacktrace",
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeLevel: zapcore.LowercaseLevelEncoder,
|
||||
EncodeTime: zapcore.EpochTimeEncoder,
|
||||
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||||
EncodeCaller: zapcore.ShortCallerEncoder,
|
||||
})
|
||||
}
|
||||
core := zapcore.NewCore(
|
||||
encoder, // 编码器配置
|
||||
zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(&hook)), // 打印到控制台和文件
|
||||
level, // 日志级别
|
||||
)
|
||||
if conf.GetString("env") != "prod" {
|
||||
return &Logger{zap.New(core, zap.Development(), zap.AddCaller(), zap.AddStacktrace(zap.ErrorLevel))}
|
||||
}
|
||||
return &Logger{zap.New(core, zap.AddCaller(), zap.AddStacktrace(zap.ErrorLevel))}
|
||||
|
||||
}
|
||||
|
||||
// 自定义时间编码器
|
||||
func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
|
||||
//enc.AppendString(t.Format("2006-01-02 15:04:05"))
|
||||
enc.AppendString(t.Format("2006-01-02 15:04:05.000000000"))
|
||||
}
|
||||
|
||||
// NewContext 给指定的context添加字段
|
||||
func (l *Logger) NewContext(ctx *gin.Context, fields ...zapcore.Field) {
|
||||
ctx.Set(LOGGER_KEY, l.WithContext(ctx).With(fields...))
|
||||
}
|
||||
|
||||
// WithContext 从指定的context返回一个zap实例
|
||||
func (l *Logger) WithContext(ctx *gin.Context) *Logger {
|
||||
if ctx == nil {
|
||||
return l
|
||||
}
|
||||
zl, _ := ctx.Get(LOGGER_KEY)
|
||||
ctxLogger, ok := zl.(*zap.Logger)
|
||||
if ok {
|
||||
return &Logger{ctxLogger}
|
||||
}
|
||||
return l
|
||||
}
|
||||
Reference in New Issue
Block a user