refactor: reorganize modules and add Linux build tooling

This commit is contained in:
2026-08-09 12:41:08 +08:00
parent 86024fa81d
commit 5cc5fd92ed
1461 changed files with 4054 additions and 4724 deletions

View File

@@ -0,0 +1,41 @@
package config
import (
"net"
"git.apinb.com/bsm-sdk/core/conf"
"git.apinb.com/bsm-sdk/core/crypto/encipher"
"git.apinb.com/bsm-sdk/core/env"
)
var (
Spec SrvConfig
)
type SrvConfig struct {
conf.Base `yaml:",inline"`
Databases *conf.DBConf `yaml:"Databases"`
MicroService *conf.MicroServiceConf `yaml:"MicroService"`
Rpc map[string]conf.RpcConf `yaml:"Rpc"`
Gateway *conf.GatewayConf `yaml:"Gateway"`
Apm *conf.ApmConf `yaml:"APM"`
Etcd *conf.EtcdConf `yaml:"Etcd"`
}
func New(srvKey string) {
// 初始化配置 创建一个新的配置实例,用于服务配置
conf.New(srvKey, &Spec)
// 配置校验 服务IP,端口; 端口如果不合规,则随机分配端口
Spec.Port = conf.CheckPort(Spec.Port)
Spec.BindIP = conf.CheckIP(Spec.BindIP)
Spec.Addr = net.JoinHostPort(Spec.BindIP, Spec.Port)
// 配置校验 服务名称地址及监听地址不能为空
conf.NotNil(Spec.Service, Spec.Cache)
// 初始化加密SecretKey
encipher.New(env.Runtime.JwtSecretKey)
conf.PrintInfo(Spec.Addr)
}

View File

@@ -0,0 +1,12 @@
package impl
import (
"git.apinb.com/bsm-sdk/core/vars"
)
func NewImpl() {
// with activating
withRedisCache(vars.ServiceKey) // redis cache
withDatabases() // model
withEtcd() // etcd
}

View File

@@ -0,0 +1,84 @@
package impl
import (
"time"
"bsm/full/module/ec/address/internal/config"
"bsm/full/module/ec/address/internal/models"
"git.apinb.com/bsm-sdk/core/cache/redis"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/printer"
"git.apinb.com/bsm-sdk/core/vars"
"go.etcd.io/etcd/client/pkg/v3/transport"
clientv3 "go.etcd.io/etcd/client/v3"
)
var (
RedisCache *redis.RedisClient
Etcd *clientv3.Client
)
func withRedisCache(srvKey string) {
if config.Spec.Cache != "" {
RedisCache = redis.New(config.Spec.Cache, srvKey)
}
// print inform.
printer.Info("[BSM - %s] Cache: %s, DBIndex: %d", vars.ServiceKey, config.Spec.Cache, RedisCache.DB)
}
func withDatabases() {
if config.Spec.Databases == nil || len(config.Spec.Databases.Source) == 0 {
panic("No Database Source Found !")
}
// print inform.
printer.Info("[BSM - %s] Databases: %v", vars.ServiceKey, config.Spec.Databases)
err := models.New(config.Spec.Databases.Driver, config.Spec.Databases.Source, nil)
if err != nil {
printer.Error("Database Init Failed !")
panic(err)
}
}
func withEtcd() {
if config.Spec.Etcd != nil {
if len(config.Spec.Etcd.Endpoints) == 0 {
panic(errcode.ErrNotFound(0, "Etcd Endpoints"))
}
cfg := clientv3.Config{
Endpoints: config.Spec.Etcd.Endpoints,
DialTimeout: 5 * time.Second,
}
if config.Spec.Etcd.Passwd != nil {
cfg.Username = config.Spec.Etcd.Passwd.Account
cfg.Password = config.Spec.Etcd.Passwd.Password
}
if config.Spec.Etcd.TLS != nil {
tlsInfo := transport.TLSInfo{
TrustedCAFile: config.Spec.Etcd.TLS.CaFile,
CertFile: config.Spec.Etcd.TLS.CertFile,
KeyFile: config.Spec.Etcd.TLS.KeyFile,
}
tlsConfig, err := tlsInfo.ClientConfig()
if err != nil {
printer.Error(errcode.ErrEtcd.Error())
panic(err)
}
cfg.TLS = tlsConfig
}
etcd, err := clientv3.New(cfg)
if err != nil {
printer.Error(errcode.ErrEtcd.Error())
panic(err)
}
Etcd = etcd
// print inform.
printer.Info("[BSM - %s] Service Center: %v", vars.ServiceKey, config.Spec.Etcd.Endpoints)
}
}

View File

@@ -0,0 +1,56 @@
package library
import (
"context"
"time"
"bsm/full/module/ec/address/internal/models"
pb "bsm/full/module/ec/address/pb"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/printer"
"git.apinb.com/bsm-sdk/core/service"
"git.apinb.com/bsm-sdk/core/utils"
)
// 新增地址
func Create(ctx context.Context, in *pb.AddressCreateRequest) (reply *pb.StatusReply, err error) {
// parse authorization meta.
auth, err := service.ParseMetaCtx(ctx, nil)
if err != nil {
return nil, err
}
address := &models.AddressLibrary{
Country: in.Country,
Phone: in.Phone,
Province: in.Province,
City: in.City,
Area: in.Area,
Detail: in.Detail,
Contact: in.Contact,
Name: in.Name,
Pics: in.Pics,
}
address.Identity = utils.UUID()
address.OwnerID = auth.ID
address.OwnerIdentity = auth.Identity
address.Status = int8(in.Status)
if address.Status == 2 {
models.DBService.Model(&models.AddressLibrary{}).Where("owner_id = ? and status=2", auth.ID).UpdateColumn("status", "1")
}
err = models.DBService.Create(address).Error
if err != nil {
printer.Error(err.Error())
return nil, errcode.ErrDB
}
return &pb.StatusReply{
Code: 0,
Message: "OK",
Timeseq: time.Now().UnixNano(),
}, nil
}

View File

@@ -0,0 +1,34 @@
package library
import (
"context"
"time"
"bsm/full/module/ec/address/internal/models"
pb "bsm/full/module/ec/address/pb"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/printer"
"git.apinb.com/bsm-sdk/core/service"
)
// 删除一个地址
func Delete(ctx context.Context, in *pb.AddressDeleteRequest) (reply *pb.StatusReply, err error) {
// parse authorization meta.
_, err = service.ParseMetaCtx(ctx, nil)
if err != nil {
return nil, err
}
err = models.DBService.Delete(&models.AddressLibrary{}, "id in ?", in.Id).Error
if err != nil {
printer.Error(err.Error())
return nil, errcode.ErrDB
}
return &pb.StatusReply{
Code: 0,
Message: "OK",
Timeseq: time.Now().UnixNano(),
}, nil
}

View File

@@ -0,0 +1,60 @@
package library
import (
"context"
"bsm/full/module/ec/address/internal/models"
pb "bsm/full/module/ec/address/pb"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/printer"
"git.apinb.com/bsm-sdk/core/service"
)
// 获取地址列表
func Fetch(ctx context.Context, in *pb.IdentRequest) (reply *pb.AddressListReply, err error) {
// parse authorization meta.
auth, err := service.ParseMetaCtx(ctx, nil)
if err != nil {
return nil, err
}
var (
address = make([]*models.AddressLibrary, 0)
result = make([]*pb.AddressItem, 0)
)
err = models.DBService.Where("owner_identity=?", auth.Identity).Find(&address).Error
if err != nil {
printer.Error(err.Error())
return nil, errcode.ErrDB
}
for _, item := range address {
result = append(result, ReflectProtoAddress(item))
}
// TODO: add your logic code & delete this line.
return
}
func ReflectProtoAddress(v *models.AddressLibrary) *pb.AddressItem {
if nil == v {
return nil
}
result := &pb.AddressItem{
Id: int64(v.ID),
Identity: v.Identity,
Country: v.Country,
Phone: v.Phone,
Province: v.Province,
City: v.City,
Area: v.Area,
Detail: v.Detail,
Contact: v.Contact,
Name: v.Name,
Pics: v.Pics,
Status: int32(v.Status),
}
return result
}

View File

@@ -0,0 +1,51 @@
package library
import (
"context"
"errors"
"bsm/full/module/ec/address/internal/models"
pb "bsm/full/module/ec/address/pb"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/printer"
"git.apinb.com/bsm-sdk/core/service"
)
// 获取一条地址
func Get(ctx context.Context, in *pb.IdentRequest) (reply *pb.AddressItem, err error) {
// parse authorization meta.
_, err = service.ParseMetaCtx(ctx, nil)
if err != nil {
return nil, err
}
if in.GetId() == 0 {
return nil, errcode.ErrInvalidArgument
}
address := new(models.AddressLibrary)
err = models.DBService.Where("id=?", in.Id).First(&address).Error
if err != nil {
if errors.Is(err, models.ErrNotFound) {
return nil, errcode.ErrRecordNotFound
}
printer.Error(err.Error())
return nil, errcode.ErrDB
}
return &pb.AddressItem{
Id: int64(address.ID),
Identity: address.Identity,
Name: address.Name,
Phone: address.Phone,
Province: address.Province,
City: address.City,
Area: address.Area,
Detail: address.Detail,
Country: address.Country,
Pics: address.Pics,
Contact: address.Contact,
Status: int32(address.Status),
}, nil
}

View File

@@ -0,0 +1,49 @@
package library
import (
"context"
"time"
"bsm/full/module/ec/address/internal/models"
pb "bsm/full/module/ec/address/pb"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/printer"
"git.apinb.com/bsm-sdk/core/service"
)
// 修改地址
func Modify(ctx context.Context, in *pb.AddressItem) (reply *pb.StatusReply, err error) {
// parse authorization meta.
auth, err := service.ParseMetaCtx(ctx, nil)
if err != nil {
return nil, err
}
address := &models.AddressLibrary{
Country: in.Country,
Phone: in.Phone,
Province: in.Province,
City: in.City,
Area: in.Area,
Detail: in.Detail,
Contact: in.Contact,
}
address.Status = int8(in.Status)
if address.Status == 2 {
models.DBService.Model(&models.AddressLibrary{}).Where("owner_id = ? and status=2", auth.ID).UpdateColumn("status", "1")
}
err = models.DBService.Where("id=?", in.Id).Updates(&address).Error
if err != nil {
printer.Error(err.Error())
return nil, errcode.ErrDB
}
return &pb.StatusReply{
Code: 0,
Message: "OK",
Timeseq: time.Now().UnixNano(),
}, nil
}

View File

@@ -0,0 +1,32 @@
// Models generated by mesh dev cli,@Author: David Yan(david.yan@qq.com).
package models
import (
"git.apinb.com/bsm-sdk/core/types"
)
/*
* OrderAddress
* Comment:
* Version: 10
* Created: 2022-04-12 18:21:15 , Updated:0001-01-01 00:00:00
*/
type AddressLibrary struct {
types.Std_IICUDS
OwnerID uint `gorm:"column:owner_id;Index;" json:"owner_id"`
OwnerIdentity string `gorm:"column:owner_identity;type:varchar(36);Index;" json:"owner_identity"` // 用户唯一标识24位NanoID,36位为UUID
Phone string `gorm:"column:phone;type:varchar(20);default:'';" json:"phone"` // 地址电话
Country string `gorm:"column:country;type:varchar(255);default:'';" json:"country"` // 国家
Province string `gorm:"column:province;type:varchar(255);default:'';" json:"province"` // 省
City string `gorm:"column:city;type:varchar(255);default:'';" json:"city"` // 市
Area string `gorm:"column:area;type:varchar(255);default:'';" json:"area"` // 区
Detail string `gorm:"column:detail;type:varchar(255);default:'';" json:"detail"` // 详细地址
Contact string `gorm:"column:contact;type:varchar(20);default:'';" json:"contact"` // 收件人
Name string `gorm:"column:name;type:varchar(255);default:'';" json:"name"` // 名称
Pics string `gorm:"column:pics;default:'';" json:"pics"` // 图片信息
}
// TableName .
func (table *AddressLibrary) TableName() string {
return "address_library" //对应数据库表名
}

View File

@@ -0,0 +1,84 @@
package models
import (
"log"
"strings"
"git.apinb.com/bsm-sdk/core/database/sql"
"git.apinb.com/bsm-sdk/core/types"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DBService *gorm.DB
var migrateTables = []any{
&AddressLibrary{},
}
func New(driver string, dsn []string, options *types.SqlOptions) (err error) {
driver = strings.ToLower(driver)
switch driver {
case "mysql":
DBService, err = NewMysql(dsn, options)
case "postgres":
DBService, err = NewPostgres(dsn, options)
default:
log.Fatalln("Unsupported database driver:", driver)
return
}
if err != nil {
log.Fatalln(err)
return err
}
// auto migrate table.
err = DBService.AutoMigrate(migrateTables...)
if err != nil {
log.Fatalln(err)
return err
}
return
}
func NewMysql(dsn []string, options *types.SqlOptions) (gormDb *gorm.DB, err error) {
//set connection default val.
options = sql.SetOptions(options)
gormDb, err = gorm.Open(mysql.Open(dsn[0]), &gorm.Config{
SkipDefaultTransaction: true,
})
if err != nil {
return nil, err
}
if options.Debug {
gormDb = gormDb.Debug()
}
// 获取通用数据库对象 sql.DB ,然后使用其提供的功能
sqlDB, _ := gormDb.DB()
// SetMaxIdleConns 用于设置连接池中空闲连接的最大数量。
sqlDB.SetMaxIdleConns(options.MaxIdleConns)
// SetMaxOpenConns 设置打开数据库连接的最大数量。
sqlDB.SetMaxOpenConns(options.MaxOpenConns)
// SetConnMaxLifetime 设置了连接可复用的最大时间。
sqlDB.SetConnMaxLifetime(options.ConnMaxLifetime)
return gormDb, nil
}
func NewPostgres(dsn []string, options *types.SqlOptions) (gormDb *gorm.DB, err error) {
//set connection default val.
options = sql.SetOptions(options)
db, err := sql.NewPostgreSql(dsn[0], options)
if err != nil {
return nil, err
}
db = db.Debug()
return db, nil
}

View File

@@ -0,0 +1,5 @@
package models
import "gorm.io/gorm"
var ErrNotFound = gorm.ErrRecordNotFound

View File

@@ -0,0 +1,41 @@
// Code generated by protoc-gen-slc. DO NOT EDIT.
package server
import (
"context"
"bsm/full/module/ec/address/internal/logic/library"
pb "bsm/full/module/ec/address/pb"
)
type LibraryServer struct {
pb.UnimplementedLibraryServer
}
func NewLibraryServer() *LibraryServer {
return &LibraryServer{}
}
// 新增地址
func (s *LibraryServer) Create(ctx context.Context, in *pb.AddressCreateRequest) (*pb.StatusReply, error) {
return library.Create(ctx, in)
}
// 修改地址
func (s *LibraryServer) Modify(ctx context.Context, in *pb.AddressItem) (*pb.StatusReply, error) {
return library.Modify(ctx, in)
}
// 获取一条地址
func (s *LibraryServer) Get(ctx context.Context, in *pb.IdentRequest) (*pb.AddressItem, error) {
return library.Get(ctx, in)
}
// 获取地址列表
func (s *LibraryServer) Fetch(ctx context.Context, in *pb.IdentRequest) (*pb.AddressListReply, error) {
return library.Fetch(ctx, in)
}
// 删除一个地址
func (s *LibraryServer) Delete(ctx context.Context, in *pb.AddressDeleteRequest) (*pb.StatusReply, error) {
return library.Delete(ctx, in)
}

View File

@@ -0,0 +1,71 @@
// Code generated by protoc-gen-slc. DO NOT EDIT.
package server
import (
"context"
pb "bsm/full/module/ec/address/pb"
"git.apinb.com/bsm-sdk/core/vars"
gwRuntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"google.golang.org/protobuf/proto"
"net/http"
"os"
"strings"
)
type Server struct {
Grpc *grpc.Server
Ctx context.Context
Mux *gwRuntime.ServeMux
}
func New(addr string) *Server {
srv := &Server{Ctx: context.Background(), Grpc: grpc.NewServer(), Mux: gwRuntime.NewServeMux(
gwRuntime.WithForwardResponseRewriter(responseEnvelope),
)}
// register service to grpc.Server
pb.RegisterLibraryServer(srv.Grpc, NewLibraryServer())
reflection.Register(srv.Grpc)
// 将服务注册到Gateway
opts := []grpc.DialOption{grpc.WithInsecure()}
pb.RegisterLibraryHandlerFromEndpoint(srv.Ctx, srv.Mux, addr, opts)
// Register services swagger
srv.RegisterSwagger()
return srv
}
// RegisterSwagger 注册swagger
func (s *Server) RegisterSwagger() {
srvKey := strings.ToLower(vars.ServiceKey)
s.Mux.HandlePath("GET", "/"+srvKey+".swagger.json", func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
w.Header().Set("Content-Type", "application/json")
bytes, err := os.ReadFile("./swagger/" + srvKey + ".swagger.json")
if err != nil {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(err.Error()))
return
}
w.Write(bytes)
return
})
}
// response envelope
func responseEnvelope(_ context.Context, response proto.Message) (interface{}, error) {
name := string(response.ProtoReflect().Descriptor().Name())
if name == "Status" || name == "Error" || name == "StatusReply" {
return response, nil
}
return map[string]any{
"code": 0,
"message": "OK",
"result": response,
}, nil
}