shao 1 hafta önce
ebeveyn
işleme
de59f229e3

+ 0 - 69
api/v1/config.go

@@ -1,69 +0,0 @@
-package v1
-
-import (
-	"log"
-)
-
-import (
-	"github.com/gin-gonic/gin"
-	"github.com/spf13/cast"
-)
-
-import (
-	"resource-server/common"
-	"resource-server/models"
-	"resource-server/service"
-)
-
-func GetConfigs(c *gin.Context) {
-	res, err := service.GetConfigList()
-	if err != nil {
-		common.HttpErr(c, err)
-		return
-	}
-	common.HttpSuccess(c, res)
-}
-
-func GetConfigOptions(c *gin.Context) {
-	flag := c.Query("flag")
-	enable := cast.ToBool(c.Query("enable"))
-	res, err := service.GetConfigOptionList(flag, enable)
-	if err != nil {
-		common.HttpErr(c, err)
-		return
-	}
-	common.HttpSuccess(c, res)
-}
-
-func UpdateConfigItems(c *gin.Context) {
-	var items map[string]interface{}
-	if err := c.ShouldBindJSON(&items); err != nil {
-		common.HttpErr(c, err)
-		return
-	}
-	for key, value := range items {
-		log.Printf("Key: %s, Value: %v", key, value)
-		var configItem models.ConfigItem
-		if err := models.DB.Model(&models.ConfigItem{}).First(&configItem, "uri = ?", key).Error; err != nil {
-			//todo 回滚
-			common.HttpErr(c, err)
-			return
-		} else {
-			//todo 校验 回滚
-			switch configItem.ValueType {
-			case "string":
-				configItem.Value = cast.ToString(value)
-			case "int":
-				configItem.Value = cast.ToString(cast.ToInt(value))
-			case "bool":
-				configItem.Value = cast.ToString(cast.ToBool(value))
-			}
-			err := models.DB.Save(&configItem).Error
-			if err != nil {
-				common.HttpErr(c, err)
-				return
-			}
-		}
-	}
-	common.HttpSuccess(c)
-}

+ 0 - 44
api/v1/public.go

@@ -1,44 +0,0 @@
-package v1
-
-import (
-	"github.com/gin-gonic/gin"
-)
-
-import (
-	"resource-server/common"
-	"resource-server/service"
-)
-
-func Ping(c *gin.Context) {
-	common.HttpSuccess(c, "pong")
-}
-
-func SoftwareInfo(c *gin.Context) {
-	common.HttpSuccess(c, map[string]interface{}{
-		"server": map[string]interface{}{
-			"resource-server": map[string]interface{}{
-				"desc":    common.Desc,
-				"build":   common.Build,
-				"version": common.Version,
-			},
-		},
-		"language": common.MetadataConfig.GetLanguages(),
-	})
-}
-
-func Login(c *gin.Context) {
-	request := &struct {
-		Username string `json:"username" binding:"required"`
-		Password string `json:"password" binding:"required"`
-	}{}
-	if err := c.ShouldBindJSON(request); err != nil {
-		common.HttpErr(c, err)
-		return
-	}
-	res, err := service.Login(request.Username, request.Password)
-	if err != nil {
-		common.HttpErr(c, err)
-		return
-	}
-	common.HttpSuccess(c, res)
-}

+ 2 - 2
cmd/cobra.go

@@ -10,7 +10,7 @@ import (
 
 import (
 	"resource-server/cmd/crypto"
-	"resource-server/cmd/httpserver"
+	"resource-server/cmd/server"
 	"resource-server/cmd/version"
 )
 
@@ -25,7 +25,7 @@ var rootCmd = &cobra.Command{
 }
 
 func init() {
-	rootCmd.AddCommand(httpserver.StartCmd)
+	rootCmd.AddCommand(server.StartCmd)
 	rootCmd.AddCommand(version.StartCmd)
 	rootCmd.AddCommand(crypto.StartCmd)
 }

+ 27 - 36
cmd/httpserver/server.go → cmd/server/server.go

@@ -1,33 +1,32 @@
-package httpserver
+package server
 
 import (
-	"context"
 	"fmt"
 	"log/slog"
-	"net/http"
+	"net"
 	"os"
 	"os/signal"
 	"strings"
-	"time"
 )
 
 import (
-	"github.com/gin-gonic/gin"
 	"github.com/spf13/cobra"
-	"github.com/spf13/viper"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/health"
+	"google.golang.org/grpc/health/grpc_health_v1"
 )
 
 import (
 	"resource-server/common"
 	"resource-server/logger"
 	"resource-server/models"
-	"resource-server/router"
-	_ "resource-server/service"
+	pb "resource-server/rpc_idl/dr_resource_pb"
+	"resource-server/service"
 )
 
 var (
 	configFolder string
-	port         int
+	addr         string
 	mode         string
 	StartCmd     = &cobra.Command{
 		Use:          "run",
@@ -45,10 +44,8 @@ var (
 
 func init() {
 	StartCmd.Flags().StringVarP(&configFolder, "config", "c", "config/", "Start server with provided configuration folder")
-	StartCmd.Flags().IntVarP(&port, "port", "p", 8000, "Tcp port server listening on")
+	StartCmd.Flags().StringVarP(&addr, "addr", "a", "localhost:6102", "Tcp server listening on")
 	StartCmd.Flags().StringVarP(&mode, "mode", "m", "debug", "server mode ; eg:debug,test,release")
-	viper.BindPFlag("port", StartCmd.Flags().Lookup("port"))
-	viper.BindPFlag("mode", StartCmd.Flags().Lookup("mode"))
 }
 
 func setup() {
@@ -60,7 +57,7 @@ func setup() {
 	}
 	configToml := configFolder + "/config.toml"
 	//1. 读取配置
-	common.SetupConfig(configToml)
+	common.SetupConfig(configToml, addr, mode)
 	//2. 设置日志
 	logger.SetupLogger(true)
 	//3. 初始化gorm
@@ -68,45 +65,39 @@ func setup() {
 	//4. 初始化i18n
 	common.SetupTrans()
 
-	slog.Info(`starting api server`, "pid", os.Getpid())
+	slog.Info(`starting server`, "pid", os.Getpid())
 }
 
 func run() error {
-	gin.SetMode(common.ApplicationConfig.Mode)
-	r := router.InitRouter()
-
-	srv := &http.Server{
-		Addr:    common.ApplicationConfig.Addr(),
-		Handler: r,
+	slog.Info(fmt.Sprintf("common.ServerConfig.Resource %v", common.ServerConfig.Resource))
+	lis, err := net.Listen("tcp", common.ServerConfig.Resource)
+	if err != nil {
+		slog.Error("failed to listen", "err", err.Error())
+		return err
 	}
-
-	go func() {
-		// 服务连接
-		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
-			slog.Error("listen: ", err)
-			panic("http server closed")
-		}
-	}()
+	s := grpc.NewServer()
+	grpc_health_v1.RegisterHealthServer(s, health.NewServer())
+	pb.RegisterBasicServer(s, &service.BasicServer{})
+	pb.RegisterConfigServer(s, &service.ConfigServer{})
 
 	slog.Info("module: " + common.Module)
 	slog.Info("desc: " + common.Desc)
 	slog.Info("version: " + common.Version)
 	slog.Info("build: " + common.Build)
-	slog.Info(fmt.Sprintf("Server run at: %s", common.Now()))
-	slog.Info(fmt.Sprintf("-  Network: http://%s:%d/ \n", common.ApplicationConfig.Host, common.ApplicationConfig.Port))
+	slog.Info(fmt.Sprintf("server run at: %s", common.Now()))
+	slog.Info(fmt.Sprintf("server listening at %v", lis.Addr()))
 	slog.Info("Enter Control + C Shutdown Server \n")
+	if err := s.Serve(lis); err != nil {
+		slog.Error("failed to serve", "err", err.Error())
+		return err
+	}
 
-	// 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间)
 	quit := make(chan os.Signal)
 	signal.Notify(quit, os.Interrupt)
 	<-quit
 	fmt.Printf("%s Shutdown Server ... \n", common.Now())
 
-	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
-	defer cancel()
-	if err := srv.Shutdown(ctx); err != nil {
-		slog.Error("Server Shutdown:", "err", err)
-	}
+	s.GracefulStop()
 	slog.Info("Server exiting")
 	logger.ShutdownLogger()
 	return nil

+ 31 - 25
common/config.go

@@ -12,27 +12,23 @@ import (
 //配置文件
 
 var (
-	ApplicationConfig = new(application)
-	BasicConfig       = new(basic)
-	LoggerConfig      = new(logger)
-	RobotConfig       = new(robot)
-	PostgresConfig    = new(postgres)
-	MetadataConfig    = new(metadata)
+	BasicConfig    = new(basic)
+	ServerConfig   = new(server)
+	LoggerConfig   = new(logger)
+	RobotConfig    = new(robot)
+	PostgresConfig = new(postgres)
+	MetadataConfig = new(metadata)
 )
 
 // 应用配置
-type application struct {
-	Host string
-	Port int
-	Mode string
-}
-
-func (p *application) Addr() string {
-	return fmt.Sprintf("%s:%d", p.Host, p.Port)
+type server struct {
+	Auth     string
+	Resource string
 }
 
 type basic struct {
-	Jwt string
+	Jwt  string
+	Mode string
 }
 
 // 日志配置
@@ -75,6 +71,7 @@ func (p *postgres) setup() {
 
 // metadata配置
 type metadata struct {
+	Locales   []string
 	Languages []Lang
 	Product   Product
 	Sources   []Source
@@ -110,14 +107,6 @@ func (p *metadata) GetSources() []Source {
 	return p.Sources
 }
 
-func InitApplication() *application {
-	return &application{
-		Host: viper.GetString("host"),
-		Port: viper.GetInt("port"),
-		Mode: viper.GetString("mode"),
-	}
-}
-
 func InitBasic(cfg *viper.Viper) *basic {
 	var basic basic
 	err := cfg.Unmarshal(&basic)
@@ -127,6 +116,15 @@ func InitBasic(cfg *viper.Viper) *basic {
 	return &basic
 }
 
+func InitServer(cfg *viper.Viper) *server {
+	var server server
+	err := cfg.Unmarshal(&server)
+	if err != nil {
+		panic("InitServer err")
+	}
+	return &server
+}
+
 func InitLog(cfg *viper.Viper) *logger {
 	var logger logger
 	err := cfg.Unmarshal(&logger)
@@ -168,12 +166,11 @@ func InitMetadata(cfg *viper.Viper) *metadata {
 }
 
 // 载入配置文件
-func SetupConfig(path string) {
+func SetupConfig(path string, addr string, mode string) {
 	viper.SetConfigFile(path)
 	if err := viper.ReadInConfig(); err != nil {
 		panic(err)
 	}
-	ApplicationConfig = InitApplication()
 
 	cfgBasic := viper.Sub("basic")
 	if cfgBasic == nil {
@@ -181,6 +178,15 @@ func SetupConfig(path string) {
 	}
 	BasicConfig = InitBasic(cfgBasic)
 
+	cfgServer := viper.Sub("server")
+	if cfgServer == nil {
+		panic("No found server in the configuration")
+	}
+	ServerConfig = InitServer(cfgServer)
+
+	BasicConfig.Mode = mode
+	ServerConfig.Resource = addr
+
 	cfgLog := viper.Sub("logger")
 	if cfgLog == nil {
 		panic("No found logger in the configuration")

+ 0 - 127
common/rescode.go

@@ -1,127 +0,0 @@
-package common
-
-import (
-	"fmt"
-	"log/slog"
-)
-
-import (
-	"github.com/gin-gonic/gin"
-	"github.com/nicksnyder/go-i18n/v2/i18n"
-	"github.com/spf13/cast"
-)
-
-const OKCode = "0x000000"
-const InvalidTokenCode = "0x010101"
-const InvalidRoleCode = "0x010102"
-
-type ResDesc string
-
-var (
-	// 全局
-	Success           ResDesc = "ErrCode_Success"
-	InvalidTokenError ResDesc = "ErrCode_InvalidTokenError"
-	InvalidRoleError  ResDesc = "ErrCode_InvalidRoleError"
-	InvalidParamError ResDesc = "ErrCode_InvalidParamError"
-	NotExistsError    ResDesc = "ErrCode_NotExistsError"
-	NotSupportError   ResDesc = "ErrCode_NotSupportError"
-	NoAuthError       ResDesc = "ErrCode_NoAuthError"
-	ExistsError       ResDesc = "ErrCode_ExistsError"
-	NotAvailableError ResDesc = "ErrCode_NotAvailableError"
-	UnknownError      ResDesc = "ErrCode_UnknownError"
-
-	InvalidLanguageError ResDesc = "ErrCode_InvalidLanguageError"
-	InvalidSourceError   ResDesc = "ErrCode_InvalidSourceError"
-	InvalidProductError  ResDesc = "ErrCode_InvalidProductError"
-
-	// 业务 错误
-	InvalidIdError ResDesc = "InvalidIdError"
-	FieldTypeError ResDesc = "FieldTypeError"
-)
-
-var (
-	OK           = &ResStatus{Code: "0x000000", Description: Success, Solution: ""}
-	InvalidToken = &ResStatus{Code: "0x000101", Description: InvalidTokenError, Solution: ""}
-	InvalidRole  = &ResStatus{Code: "0x000102", Description: InvalidRoleError, Solution: ""}
-
-	InvalidParam = &ResStatus{Code: "0x000103", Description: InvalidParamError, Solution: ""}
-	NotExists    = &ResStatus{Code: "0x000104", Description: NotExistsError, Solution: ""}
-	NotSupport   = &ResStatus{Code: "0x000105", Description: NotSupportError, Solution: ""}
-	NoAuth       = &ResStatus{Code: "0x000106", Description: NoAuthError, Solution: ""}
-	Exists       = &ResStatus{Code: "0x000107", Description: ExistsError, Solution: ""}
-	NotAvailable = &ResStatus{Code: "0x000108", Description: NotAvailableError, Solution: ""}
-
-	InvalidLanguage = &ResStatus{Code: "0x000111", Description: InvalidLanguageError, Solution: ""}
-	InvalidSource   = &ResStatus{Code: "0x000112", Description: InvalidSourceError, Solution: ""}
-	InvalidProduct  = &ResStatus{Code: "0x000113", Description: InvalidProductError, Solution: ""}
-
-	InvalidUsernameOrPasswd = &ResStatus{Code: "0x010101", Description: "ErrCode_InvalidUsernameOrPasswdError", Solution: ""}
-
-	Unknown = &ResStatus{Code: "0x999999", Description: UnknownError, Solution: ""}
-)
-
-func helper(code string, msg ResDesc) *ResStatus {
-	return &ResStatus{
-		Code:        code,
-		Description: msg,
-		Solution:    "",
-	}
-}
-
-type ResStatus struct {
-	Code        string                 `json:"code"`
-	Description ResDesc                `json:"description"`
-	Params      map[string]interface{} `json:"-"`
-	Solution    string                 `json:"solution"`
-}
-
-func (p *ResStatus) Error() string {
-	return string(p.Description)
-}
-
-func (p *ResStatus) Desc(msg ResDesc) *ResStatus {
-	return &ResStatus{p.Code, msg, nil, p.Solution}
-}
-
-func convertParamsToMap(params ...interface{}) map[string]interface{} {
-	result := make(map[string]interface{})
-	for i := 0; i < len(params); i += 2 {
-		var value interface{}
-		if i+1 < len(params) {
-			value = params[i+1]
-		} else {
-			value = nil
-		}
-		result[cast.ToString(params[i])] = value
-	}
-	return result
-}
-
-func (p *ResStatus) SetParam(params ...interface{}) *ResStatus {
-	return &ResStatus{p.Code, p.Description, convertParamsToMap(params), p.Solution}
-}
-
-func (p *ResStatus) Translator(localizer *i18n.Localizer) *ResStatus {
-	params := []string{}
-	if len(p.Params) > 0 {
-		for _, param := range p.Params {
-			params = append(params, fmt.Sprintf("%v", param))
-		}
-	}
-	t, err := localizer.Localize(&i18n.LocalizeConfig{
-		MessageID:    string(p.Description),
-		TemplateData: params,
-	})
-	if err != nil {
-		slog.Error("translator fail\n", "desc", p.Description, "err", err)
-		t = string(p.Description)
-	}
-	return &ResStatus{p.Code, ResDesc(t), p.Params, p.Solution}
-}
-
-func (p *ResStatus) H(data ...interface{}) gin.H {
-	if len(data) > 0 {
-		return gin.H{"status": helper(p.Code, p.Description), "data": data[0]}
-	}
-	return gin.H{"status": helper(p.Code, p.Description), "data": gin.H{}}
-}

+ 0 - 63
common/response.go

@@ -1,63 +0,0 @@
-package common
-
-import (
-	"encoding/json"
-	"errors"
-	"fmt"
-	"log/slog"
-	"net/http"
-	"reflect"
-	"runtime/debug"
-)
-
-import (
-	"gorm.io/gorm"
-)
-
-import (
-	"github.com/gin-gonic/gin"
-	"github.com/go-playground/validator/v10"
-)
-
-func HttpSuccess(c *gin.Context, data ...interface{}) {
-	if len(data) > 0 {
-		c.JSON(http.StatusOK, OK.Translator(GetTrans(c.GetHeader("Language"))).H(data[0]))
-	} else {
-		c.JSON(http.StatusOK, OK.H())
-	}
-}
-
-func ErrToH(err interface{}, locale string) gin.H {
-	h := gin.H{}
-
-	switch err.(type) {
-	case *ResStatus:
-		h = err.(*ResStatus).Translator(GetTrans(locale)).H()
-	case *json.UnmarshalTypeError:
-		utErr := err.(*json.UnmarshalTypeError)
-		h = InvalidParam.Desc(FieldTypeError).SetParam(utErr.Field, utErr.Type.String()).Translator(GetTrans(locale)).H()
-	case validator.ValidationErrors:
-		for _, fieldError := range err.(validator.ValidationErrors) {
-			return InvalidParam.Desc(ResDesc(fieldError.Error())).Translator(GetTrans(locale)).H()
-		}
-	default:
-		if fmt.Sprintf("%v", err) == "EOF" {
-			return InvalidParam.Desc("empty body").Translator(GetTrans(locale)).H()
-		}
-		if fmt.Sprintf("%v", err) == "unexpected EOF" {
-			return InvalidParam.Desc("body must be in json format").Translator(GetTrans(locale)).H()
-		}
-		if errors.Is(err.(error), gorm.ErrRecordNotFound) {
-			return NotExists.Translator(GetTrans(locale)).H()
-		}
-		slog.Error("uncaught error occurred", "type", reflect.TypeOf(err), "err", err, "stack", string(debug.Stack()))
-		h = Unknown.Desc(ResDesc(fmt.Sprintf("%v", err))).Translator(GetTrans(locale)).H()
-	}
-	return h
-}
-
-func HttpErr(c *gin.Context, err interface{}) {
-	h := ErrToH(err, c.GetHeader("Language"))
-	slog.Warn("http err response", "method", c.Request.Method, "uri", c.Request.RequestURI, "msg", h)
-	c.JSON(http.StatusOK, h)
-}

+ 6 - 7
common/translator.go

@@ -16,13 +16,12 @@ func SetupTrans() {
 	slog.Info("setup trans")
 	bundle = i18n.NewBundle(language.English)
 	bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
-	_, err := bundle.LoadMessageFile("static/locale/common.en.toml")
-	if err != nil {
-		panic(err)
-	}
-	_, err = bundle.LoadMessageFile("static/locale/common.zh.toml")
-	if err != nil {
-		panic(err)
+	for _, filename := range MetadataConfig.Locales {
+		slog.Info("loading locale", "filename", filename)
+		_, err := bundle.LoadMessageFile(filename)
+		if err != nil {
+			panic(err)
+		}
 	}
 	slog.Info("setup trans ok")
 }

+ 9 - 4
config/config.toml.template

@@ -1,9 +1,10 @@
-host = "0.0.0.0"
-port = 6001
-mode = "debug" # 模式 debug | test | release
-
 [basic]
 jwt = "BOLQ3HoltjaQqAgWXAG6UXnq2OWGefzqYGwyiYJjAVmuDNyJAOZaFqK8cgQsUrhDA5WDVFuk0mqDRHAK"
+mode = "debug" # 模式 debug | test | release
+
+[server]
+auth = "0.0.0.0:6001"
+resource = "localhost:6102"
 
 [logger]
 logDir = "./logs/dr.log" # 日志存储目录
@@ -28,6 +29,10 @@ password = "24a4e49b95adb006fbadd7c5a74dbb2ee4d67d61abab"
 name = "mytestdatabase"
 
 [metadata]
+locales = [
+    "../locale/common.en.toml",
+    "../locale/common.zh.toml"
+]
 # 支持的语言,可选项:"en","zh"
 languages = ["en", "zh"]
 # 支持的产品,可选项:"droc","vetdroc"

+ 0 - 25
dto/config.go

@@ -1,25 +0,0 @@
-package dto
-
-type ConfigResp struct {
-	Key         string `json:"key"`
-	Value       string `json:"value"`
-	OptionKey   string `json:"option_key"`
-	ValueType   string `json:"value_type"`
-	Description string `json:"description"`
-	Order       int    `json:"order"`
-	IsEnabled   bool   `json:"is_enabled"`
-	Uri         string `json:"uri"`
-}
-
-type ConfigOptionResp struct {
-	Flag   string `json:"flag"`
-	Text   string `json:"text"`
-	Value  string `json:"value"`
-	Order  int    `json:"order"`
-	Enable bool   `json:"enable"`
-}
-
-type ConfigItemReq struct {
-	Title   string   `json:"title"`
-	Columns []string `json:"columns"`
-}

+ 0 - 9
dto/user.go

@@ -1,9 +0,0 @@
-package dto
-
-type UserInfoResp struct {
-	Token  string `json:"token"`
-	Expire int64  `json:"expire"`
-	Uid    uint   `json:"uid"`
-	Name   string `json:"name"`
-	Avatar string `json:"avatar"`
-}

+ 7 - 2
logger/logger.go

@@ -4,6 +4,7 @@ import (
 	"io"
 	"log/slog"
 	"os"
+	"strings"
 )
 
 import (
@@ -37,8 +38,12 @@ func SetupLogger(persisted bool) {
 		AddSource: true,
 	}
 
+	filename := common.LoggerConfig.LogDir + "/resource.log"
+	if strings.HasSuffix(common.LoggerConfig.LogDir, "/") {
+		filename = common.LoggerConfig.LogDir + "resource.log"
+	}
 	lumberJackLogger = &lumberjack.Logger{
-		Filename:   common.LoggerConfig.LogDir,     //日志文件的位置
+		Filename:   filename,                       //日志文件的位置
 		MaxSize:    common.LoggerConfig.MaxSize,    //在进行切割之前,日志文件的最大大小(以MB为单位)
 		MaxBackups: common.LoggerConfig.MaxBackups, //最多保留文件个数
 		MaxAge:     common.LoggerConfig.MaxAge,     //保留旧文件的最大天数
@@ -60,7 +65,7 @@ func SetupLogger(persisted bool) {
 
 	slog.Info("setup logger ok",
 		"level", level.String(),
-		"filename", common.LoggerConfig.LogDir,
+		"filename", filename,
 		"max size", common.LoggerConfig.MaxSize,
 		"max backups", common.LoggerConfig.MaxBackups,
 		"max age", common.LoggerConfig.MaxAge,

+ 0 - 33
models/model.go

@@ -1,42 +1,9 @@
 package models
 
 import (
-	"time"
-)
-
-import (
-	"golang.org/x/crypto/bcrypt"
 	"gorm.io/gorm"
 )
 
-type User struct {
-	gorm.Model
-	OpenID        string `gorm:"uniqueIndex"`
-	OrgID         uint   `gorm:"index"`
-	Name          string
-	Avatar        string
-	Password      string `json:"-"`
-	Mobile        string `json:"mobile" gorm:"type:varchar(15);unique_index"`
-	Email         string `json:"email"  gorm:"type:varchar(255);unique_index"`
-	LastLoginTime time.Time
-}
-
-func (u *User) GenerateFromPassword(password []byte) error {
-	hashPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
-	if err != nil {
-		return err
-	}
-	u.Password = string(hashPassword)
-	return nil
-}
-
-func (u *User) CompareHashAndPassword(password []byte) bool {
-	if err := bcrypt.CompareHashAndPassword([]byte(u.Password), password); err != nil {
-		return false
-	}
-	return true
-}
-
 type ConfigItem struct {
 	gorm.Model
 	Group        string `gorm:"index"`

+ 0 - 10
models/setup.go

@@ -1,7 +1,6 @@
 package models
 
 import (
-	"errors"
 	"fmt"
 	"log/slog"
 )
@@ -28,15 +27,6 @@ func panicHelper(err error) {
 }
 
 func migrate() {
-	panicHelper(DB.AutoMigrate(&User{}))
-	var user User
-	err := DB.First(&user).Error
-	if errors.Is(err, gorm.ErrRecordNotFound) {
-		newAdmin := User{Name: "admin"}
-		newAdmin.GenerateFromPassword([]byte("123456"))
-		DB.Create(&newAdmin)
-	}
-
 	panicHelper(DB.AutoMigrate(&ConfigItem{}))
 	var count int64
 	DB.Model(&ConfigItem{}).Count(&count)

+ 0 - 165
router/middleware.go

@@ -1,165 +0,0 @@
-package router
-
-import (
-	"fmt"
-	"log/slog"
-	"net/http"
-	"runtime/debug"
-	"strings"
-	"time"
-)
-
-import (
-	"github.com/gin-gonic/gin"
-)
-
-import (
-	"resource-server/common"
-	"resource-server/logger"
-)
-
-func InitMiddleware(r *gin.Engine) {
-	// NoCache is a middleware function that appends headers
-	r.Use(NoCache)
-	// 跨域处理
-	r.Use(Options)
-	// Secure is a middleware function that appends security
-	r.Use(Secure)
-	// Use Slog Logger
-	r.Use(GinLogger(logger.WithGroup("gin")))
-	// Global Recover
-	r.Use(GinRecovery(logger.WithGroup("ginRecovery")))
-	// check header
-	r.Use(CheckLanguage)
-	r.Use(CheckSource)
-	r.Use(CheckProduct)
-	// check token
-	r.Use(CheckAuth)
-}
-
-// NoCache is a middleware function that appends headers
-// to prevent the client from caching the HTTP response.
-func NoCache(c *gin.Context) {
-	c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value")
-	c.Header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT")
-	c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
-	c.Next()
-}
-
-// Options is a middleware function that appends headers
-// for options requests and aborts then exits the middleware
-// chain and ends the request.
-func Options(c *gin.Context) {
-	if c.Request.Method != "OPTIONS" {
-		c.Next()
-	} else {
-		c.Header("Access-Control-Allow-Origin", "*")
-		c.Header("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS")
-		c.Header("Access-Control-Allow-Headers", "authorization, origin, content-type, accept")
-		c.Header("Allow", "HEAD,GET,POST,PUT,PATCH,DELETE,OPTIONS")
-		c.Header("Content-Type", "application/json")
-		c.AbortWithStatus(200)
-	}
-}
-
-// Secure is a middleware function that appends security
-// and resource access headers.
-func Secure(c *gin.Context) {
-	c.Header("Access-Control-Allow-Origin", "*")
-	//c.Header("X-Frame-Options", "DENY")
-	c.Header("X-Content-Type-Options", "nosniff")
-	c.Header("X-XSS-Protection", "1; mode=block")
-	if c.Request.TLS != nil {
-		c.Header("Strict-Transport-Security", "max-age=31536000")
-	}
-
-	// Also consider adding Content-Security-Policy headers
-	// c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com")
-}
-
-func CheckLanguage(c *gin.Context) {
-	ok := false
-	language := c.Request.Header.Get("Language")
-	for _, l := range common.MetadataConfig.GetLanguages() {
-		if language == l.ToString() {
-			ok = true
-		}
-	}
-	if !ok {
-		c.AbortWithStatusJSON(200, common.ErrToH(common.InvalidLanguage, c.GetHeader("locale")))
-	} else {
-		c.Set("language", language)
-	}
-	c.Next()
-}
-
-func CheckSource(c *gin.Context) {
-	source := c.Request.Header.Get("Source")
-	ok := false
-	for _, s := range common.MetadataConfig.GetSources() {
-		if source == s.ToString() {
-			ok = true
-		}
-	}
-	if !ok {
-		c.AbortWithStatusJSON(200, common.ErrToH(common.InvalidSource, c.GetHeader("locale")))
-	} else {
-		c.Set("source", source)
-	}
-	c.Next()
-}
-
-func CheckProduct(c *gin.Context) {
-	product := c.Request.Header.Get("Product")
-	if product != common.MetadataConfig.GetProduct().ToString() {
-		c.AbortWithStatusJSON(200, common.ErrToH(common.InvalidProduct, product))
-	} else {
-		c.Set("product", product)
-	}
-	c.Next()
-}
-
-func CheckAuth(c *gin.Context) {
-	if strings.HasPrefix(c.FullPath(), "/dr/api/v1/auth") {
-		token := c.Request.Header.Get("Authorization")
-		uid, username, err := common.ParseToken(strings.TrimPrefix(token, "Bearer "))
-		if err != nil {
-			c.AbortWithStatusJSON(200, common.ErrToH(common.InvalidToken, c.GetHeader("locale")))
-		}
-		c.Set("uid", uid)
-		c.Set("username", username)
-	}
-	c.Next()
-}
-
-func GinLogger(logger *slog.Logger) gin.HandlerFunc {
-	return func(c *gin.Context) {
-		start := time.Now()
-		path := c.Request.URL.Path
-		if len(c.Request.URL.RawQuery) > 0 {
-			path += "?" + c.Request.URL.RawQuery
-		}
-		c.Next()
-
-		cost := time.Since(start)
-		logger.Info(fmt.Sprintf("[%s]%s, header[%s-%s-%s] ip[%s], resp[%d] %s errors[%s]",
-			c.Request.Method,
-			path,
-			c.GetHeader("Product"),
-			c.GetHeader("Source"),
-			c.GetHeader("Language"),
-			c.ClientIP(),
-			c.Writer.Status(),
-			cost.String(),
-			c.Errors.ByType(gin.ErrorTypePrivate).String(),
-		))
-	}
-}
-
-func GinRecovery(logger *slog.Logger) gin.HandlerFunc {
-	return gin.CustomRecovery(func(c *gin.Context, recovered interface{}) {
-		logger.Error("Recovery from panic", "recoverd", recovered, "stack", string(debug.Stack()))
-		common.HttpErr(c, common.Unknown)
-		c.AbortWithStatus(http.StatusOK)
-	})
-}

+ 0 - 35
router/router.go

@@ -1,35 +0,0 @@
-package router
-
-import (
-	"github.com/gin-gonic/gin"
-	apiv1 "resource-server/api/v1"
-)
-
-func InitRouter() *gin.Engine {
-
-	r := gin.New()
-
-	InitMiddleware(r)
-
-	r.StaticFile("/dr/", "./dist/index.html")
-	r.Static("/dr/front/", "./dist/")
-
-	// 注册路由
-	v1 := r.Group("/dr/api/v1/")
-	pubV1 := v1.Group("/pub")
-	{
-		pubV1.GET("/ping", apiv1.Ping)
-		pubV1.GET("software_info", apiv1.SoftwareInfo)
-		pubV1.POST("login", apiv1.Login)
-	}
-	authV1 := v1.Group("/auth")
-	{
-		configV1 := authV1.Group("/configs")
-		{
-			configV1.GET("items", apiv1.GetConfigs)
-			configV1.GET("options", apiv1.GetConfigOptions)
-			configV1.POST("items", apiv1.UpdateConfigItems)
-		}
-	}
-	return r
-}

+ 25 - 0
service/basic.go

@@ -0,0 +1,25 @@
+package service
+
+import (
+	"context"
+	"log/slog"
+)
+
+import (
+	"resource-server/common"
+	pb "resource-server/rpc_idl/dr_resource_pb"
+)
+
+type BasicServer struct {
+	pb.UnimplementedBasicServer
+}
+
+func (s *BasicServer) SoftwareInfo(_ context.Context, in *pb.EmptyRequest) (*pb.SoftwareInfoReply, error) {
+	slog.Info("Received SoftwareInfo")
+	return &pb.SoftwareInfoReply{
+		Module:  common.Module,
+		Desc:    common.Desc,
+		Build:   common.Build,
+		Version: common.Version,
+	}, nil
+}

+ 76 - 55
service/config.go

@@ -1,71 +1,92 @@
 package service
 
 import (
-	"resource-server/common"
-	"resource-server/dto"
-	"resource-server/models"
+	"context"
+	"fmt"
 )
 
-func GetConfigList() ([]*dto.ConfigResp, error) {
-	res := []*dto.ConfigResp{}
-	var items []*models.ConfigItem
-	query := models.DB.Model(&models.ConfigItem{})
-	err := query.Order("id").Find(&items).Error
-	if err != nil {
-		return res, err
-	}
-	for _, c := range items {
-		res = append(res, &dto.ConfigResp{
-			Key:         c.Key,
-			Value:       c.Value,
-			OptionKey:   c.OptionKey,
-			ValueType:   c.ValueType,
-			Description: c.Description,
-			Order:       c.Order,
-			IsEnabled:   c.IsEnabled,
-			Uri:         c.Uri,
-		})
-	}
-	return res, nil
+import (
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/metadata"
+	"google.golang.org/grpc/status"
+)
+
+import (
+	pb "resource-server/rpc_idl/dr_resource_pb"
+)
+
+type ConfigServer struct {
+	pb.UnimplementedConfigServer
 }
 
-func GetConfigOptionList(flag string, enable bool) ([]*dto.ConfigOptionResp, error) {
-	res := []*dto.ConfigOptionResp{}
-	switch flag {
+func (s *ConfigServer) ConfigOptionList(ctx context.Context, in *pb.ConfigOptionListRequest) (*pb.ConfigOptionListReply, error) {
+	md, ok := metadata.FromIncomingContext(ctx)
+	if ok {
+		fmt.Printf("Received metadata: %v\n", md)
+	}
+	res := pb.ConfigOptionListReply{}
+	switch in.GetFlag() {
 	case "TimeFormat":
-		res = append(res, &dto.ConfigOptionResp{Flag: "TimeFormat", Text: "HH:mm:ss", Value: "HH:mm:ss", Order: 1, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "TimeFormat", Text: "HH:mm", Value: "HH:mm", Order: 2, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "TimeFormat", Text: "HH-mm-ss", Value: "HH-mm-ss", Order: 3, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "TimeFormat", Text: "HHmmss", Value: "HHmmss", Order: 4, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "TimeFormat", Text: "hh:mm:ss tt", Value: "hh:mm:ss tt", Order: 5, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "TimeFormat", Text: "h:mm:ss tt", Value: "h:mm:ss tt", Order: 6, Enable: true})
+		//res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "TimeFormat", Text: "HH:mm:ss", Value: "HH:mm:ss", Order: 1, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "TimeFormat", Text: "HH:mm", Value: "HH:mm", Order: 2, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "TimeFormat", Text: "HH-mm-ss", Value: "HH-mm-ss", Order: 3, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "TimeFormat", Text: "HHmmss", Value: "HHmmss", Order: 4, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "TimeFormat", Text: "hh:mm:ss tt", Value: "hh:mm:ss tt", Order: 5, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "TimeFormat", Text: "h:mm:ss tt", Value: "h:mm:ss tt", Order: 6, IsEnabled: true})
 	case "DateFormat":
-		res = append(res, &dto.ConfigOptionResp{Flag: "DateFormat", Text: "yyyy.MM.dd", Value: "yyyy.MM.dd", Order: 1, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "DateFormat", Text: "yyyy/M/d", Value: "yyyy/M/d", Order: 2, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "DateFormat", Text: "M-d-yyyy", Value: "M-d-yyyy", Order: 3, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "DateFormat", Text: "yyyy/M/dd", Value: "yyyy/M/dd", Order: 4, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "DateFormat", Text: "yyyy-MM-dd", Value: "yyyy-MM-dd", Order: 5, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "DateFormat", Text: "M-dd-yyyy", Value: "M-dd-yyyy", Order: 6, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "DateFormat", Text: "yyyy.M.dd", Value: "yyyy.M.dd", Order: 7, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "DateFormat", Text: "yyyy/MM/dd", Value: "yyyy/MM/dd", Order: 8, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "DateFormat", Text: "MMM-dd-yyyy", Value: "MMM-dd-yyyy", Order: 9, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "DateFormat", Text: "yyyy-MMM-dd", Value: "yyyy-MMM-dd", Order: 10, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "DateFormat", Text: "dd-MMM-yyyy", Value: "dd-MMM-yyyy", Order: 11, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "DateFormat", Text: "dd.MM.yyyy", Value: "dd.MM.yyyy", Order: 12, Enable: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DateFormat", Text: "yyyy.MM.dd", Value: "yyyy.MM.dd", Order: 1, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DateFormat", Text: "yyyy/M/d", Value: "yyyy/M/d", Order: 2, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DateFormat", Text: "M-d-yyyy", Value: "M-d-yyyy", Order: 3, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DateFormat", Text: "yyyy/M/dd", Value: "yyyy/M/dd", Order: 4, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DateFormat", Text: "yyyy-MM-dd", Value: "yyyy-MM-dd", Order: 5, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DateFormat", Text: "M-dd-yyyy", Value: "M-dd-yyyy", Order: 6, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DateFormat", Text: "yyyy.M.dd", Value: "yyyy.M.dd", Order: 7, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DateFormat", Text: "yyyy/MM/dd", Value: "yyyy/MM/dd", Order: 8, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DateFormat", Text: "MMM-dd-yyyy", Value: "MMM-dd-yyyy", Order: 9, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DateFormat", Text: "yyyy-MMM-dd", Value: "yyyy-MMM-dd", Order: 10, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DateFormat", Text: "dd-MMM-yyyy", Value: "dd-MMM-yyyy", Order: 11, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DateFormat", Text: "dd.MM.yyyy", Value: "dd.MM.yyyy", Order: 12, IsEnabled: true})
 	case "DoseUnit":
-		res = append(res, &dto.ConfigOptionResp{Flag: "DoseUnit", Text: "rad", Value: "rad", Order: 1, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "DoseUnit", Text: "mGy", Value: "mGy", Order: 2, Enable: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DoseUnit", Text: "rad", Value: "rad", Order: 1, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "DoseUnit", Text: "mGy", Value: "mGy", Order: 2, IsEnabled: true})
 	case "WeightUnit":
-		res = append(res, &dto.ConfigOptionResp{Flag: "WeightUnit", Text: "kg", Value: "kg", Order: 1, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "WeightUnit", Text: "pound", Value: "pound", Order: 2, Enable: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "WeightUnit", Text: "kg", Value: "kg", Order: 1, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "WeightUnit", Text: "pound", Value: "pound", Order: 2, IsEnabled: true})
 	case "LengthUnit":
-		res = append(res, &dto.ConfigOptionResp{Flag: "LengthUnit", Text: "cm", Value: "cm", Order: 1, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "LengthUnit", Text: "inch", Value: "inch", Order: 2, Enable: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "LengthUnit", Text: "cm", Value: "cm", Order: 1, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "LengthUnit", Text: "inch", Value: "inch", Order: 2, IsEnabled: true})
 	case "FontFamily":
-		res = append(res, &dto.ConfigOptionResp{Flag: "FontFamily", Text: "Arial Unicode MS", Value: "Arial Unicode MS", Order: 1, Enable: true})
-		res = append(res, &dto.ConfigOptionResp{Flag: "FontFamily", Text: "Arial", Value: "Arial", Order: 2, Enable: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "FontFamily", Text: "Arial Unicode MS", Value: "Arial Unicode MS", Order: 1, IsEnabled: true})
+		res.ConfigOption = append(res.ConfigOption, &pb.ConfigOption{Flag: "FontFamily", Text: "Arial", Value: "Arial", Order: 2, IsEnabled: true})
 	default:
-		return res, common.NotExists
+		return &res, status.Errorf(codes.NotFound, "flag %s not found", in.GetFlag())
 	}
-	return res, nil
+	return &res, nil
 }
+func (s *ConfigServer) ConfigList(ctx context.Context, in *pb.ConfigListRequest) (*pb.ConfigListResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ConfigList not implemented")
+}
+
+//func GetConfigList() ([]*dto.ConfigResp, error) {
+//	res := []*dto.ConfigResp{}
+//	var items []*models.ConfigItem
+//	query := models.DB.Model(&models.ConfigItem{})
+//	err := query.Order("id").Find(&items).Error
+//	if err != nil {
+//		return res, err
+//	}
+//	for _, c := range items {
+//		res = append(res, &dto.ConfigResp{
+//			Key:         c.Key,
+//			Value:       c.Value,
+//			OptionKey:   c.OptionKey,
+//			ValueType:   c.ValueType,
+//			Description: c.Description,
+//			Order:       c.Order,
+//			IsEnabled:   c.IsEnabled,
+//			Uri:         c.Uri,
+//		})
+//	}
+//	return res, nil
+//}

+ 0 - 35
service/user.go

@@ -1,35 +0,0 @@
-package service
-
-import (
-	"resource-server/common"
-	"resource-server/dto"
-	"resource-server/models"
-	"time"
-)
-
-func Login(username string, password string) (*dto.UserInfoResp, error) {
-	var user models.User
-	err := models.DB.Model(&models.User{}).First(&user, "name = ?", username).Error
-	if err != nil {
-		return nil, err
-	}
-	if ok := user.CompareHashAndPassword([]byte(password)); !ok {
-		return nil, common.InvalidUsernameOrPasswd
-	}
-	user.LastLoginTime = time.Now()
-	err = models.DB.Save(&user).Error
-	if err != nil {
-		return nil, err
-	}
-	token, expire, err := common.NewToken(user.ID, user.Name)
-	if err != nil {
-		return nil, err
-	}
-	return &dto.UserInfoResp{
-		Token:  token,
-		Expire: expire,
-		Uid:    user.ID,
-		Name:   user.Name,
-		Avatar: user.Avatar,
-	}, nil
-}

+ 0 - 0
static/basic.go → static/static.go