任务一完成

This commit is contained in:
Yvan
2026-01-07 10:13:35 +08:00
parent e8f8c2819a
commit 35ab7c0b70
24 changed files with 3397 additions and 160 deletions
+1290 -138
View File
File diff suppressed because it is too large Load Diff
+112 -5
View File
@@ -1,13 +1,17 @@
syntax = "proto3";
package kratos.api;
option go_package = "kratos-admin/internal/conf;conf";
option go_package = "kra/internal/conf;conf";
import "google/protobuf/duration.proto";
message Bootstrap {
Server server = 1;
Data data = 2;
JWT jwt = 3;
Casbin casbin = 4;
Captcha captcha = 5;
Upload upload = 6;
}
message Server {
@@ -29,13 +33,116 @@ message Data {
message Database {
string driver = 1;
string source = 2;
string table_prefix = 3;
int32 max_idle_conns = 4;
int32 max_open_conns = 5;
int32 max_lifetime = 6;
bool log_mode = 7;
}
message Redis {
string network = 1;
string addr = 2;
google.protobuf.Duration read_timeout = 3;
google.protobuf.Duration write_timeout = 4;
string addr = 1;
string password = 2;
int32 db = 3;
bool use_cluster = 4;
repeated string cluster_addrs = 5;
}
Database database = 1;
Redis redis = 2;
}
message JWT {
string signing_key = 1;
string expires_time = 2;
string buffer_time = 3;
string issuer = 4;
}
message Casbin {
string model_path = 1;
}
message Captcha {
int32 key_long = 1;
int32 img_width = 2;
int32 img_height = 3;
int32 open_captcha = 4;
int32 open_captcha_timeout = 5;
}
message Upload {
string type = 1;
string path = 2;
int64 max_size = 3;
message Local {
string store_path = 1;
}
message Aliyun {
string endpoint = 1;
string access_key_id = 2;
string access_key_secret = 3;
string bucket_name = 4;
string bucket_url = 5;
string base_path = 6;
}
message Tencent {
string bucket = 1;
string region = 2;
string secret_id = 3;
string secret_key = 4;
string base_url = 5;
string path_prefix = 6;
}
message Qiniu {
string zone = 1;
string bucket = 2;
string img_path = 3;
string access_key = 4;
string secret_key = 5;
bool use_https = 6;
bool use_cdn_domains = 7;
}
message Minio {
string id = 1;
string secret = 2;
string bucket = 3;
string endpoint = 4;
string base_path = 5;
bool use_ssl = 6;
}
message AwsS3 {
string bucket = 1;
string region = 2;
string endpoint = 3;
string secret_id = 4;
string secret_key = 5;
string base_url = 6;
string path_prefix = 7;
bool s3_force_path_style = 8;
bool disable_ssl = 9;
}
message HuaweiObs {
string path = 1;
string bucket = 2;
string endpoint = 3;
string access_key = 4;
string secret_key = 5;
}
message CloudflareR2 {
string bucket = 1;
string base_url = 2;
string path = 3;
string account_id = 4;
string access_key_id = 5;
string secret_access_key = 6;
}
Local local = 4;
Aliyun aliyun = 5;
Tencent tencent = 6;
Qiniu qiniu = 7;
Minio minio = 8;
AwsS3 aws_s3 = 9;
HuaweiObs huawei_obs = 10;
CloudflareR2 cloudflare_r2 = 11;
}
+74
View File
@@ -0,0 +1,74 @@
package data
import (
"time"
"kra/internal/conf"
"github.com/go-kratos/kratos/v2/log"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
// NewGormDB 创建GORM数据库连接
func NewGormDB(c *conf.Data, l log.Logger) (*gorm.DB, func(), error) {
helper := log.NewHelper(l)
var dialector gorm.Dialector
switch c.Database.Driver {
case "mysql":
dialector = mysql.Open(c.Database.Source)
case "postgres":
dialector = postgres.Open(c.Database.Source)
case "sqlite":
dialector = sqlite.Open(c.Database.Source)
default:
dialector = mysql.Open(c.Database.Source)
}
gormConfig := &gorm.Config{
NamingStrategy: schema.NamingStrategy{
TablePrefix: c.Database.TablePrefix,
SingularTable: true,
},
DisableForeignKeyConstraintWhenMigrating: true,
}
// 设置日志级别
if c.Database.LogMode {
gormConfig.Logger = logger.Default.LogMode(logger.Info)
} else {
gormConfig.Logger = logger.Default.LogMode(logger.Silent)
}
db, err := gorm.Open(dialector, gormConfig)
if err != nil {
helper.Errorf("failed to connect database: %v", err)
return nil, nil, err
}
sqlDB, err := db.DB()
if err != nil {
helper.Errorf("failed to get sql.DB: %v", err)
return nil, nil, err
}
// 连接池配置
sqlDB.SetMaxIdleConns(int(c.Database.MaxIdleConns))
sqlDB.SetMaxOpenConns(int(c.Database.MaxOpenConns))
sqlDB.SetConnMaxLifetime(time.Duration(c.Database.MaxLifetime) * time.Second)
cleanup := func() {
helper.Info("closing database connection")
if err := sqlDB.Close(); err != nil {
helper.Errorf("failed to close database: %v", err)
}
}
helper.Info("database connected successfully")
return db, cleanup, nil
}
+30
View File
@@ -0,0 +1,30 @@
package model
import (
"time"
"gorm.io/gorm"
)
// Model 基础模型
type Model struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
}
// PageInfo 分页请求
type PageInfo struct {
Page int `json:"page" form:"page"`
PageSize int `json:"pageSize" form:"pageSize"`
Keyword string `json:"keyword" form:"keyword"`
}
// PageResult 分页响应
type PageResult struct {
List interface{} `json:"list"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
}
+47
View File
@@ -0,0 +1,47 @@
package data
import (
"context"
"kra/internal/conf"
"github.com/go-kratos/kratos/v2/log"
"github.com/redis/go-redis/v9"
)
// NewRedisClient 创建Redis客户端
func NewRedisClient(c *conf.Data, l log.Logger) (redis.UniversalClient, func(), error) {
helper := log.NewHelper(l)
var client redis.UniversalClient
if c.Redis.UseCluster {
client = redis.NewClusterClient(&redis.ClusterOptions{
Addrs: c.Redis.ClusterAddrs,
Password: c.Redis.Password,
})
} else {
client = redis.NewClient(&redis.Options{
Addr: c.Redis.Addr,
Password: c.Redis.Password,
DB: int(c.Redis.Db),
})
}
// 测试连接
ctx := context.Background()
if _, err := client.Ping(ctx).Result(); err != nil {
helper.Errorf("failed to connect redis: %v", err)
return nil, nil, err
}
cleanup := func() {
helper.Info("closing redis connection")
if err := client.Close(); err != nil {
helper.Errorf("failed to close redis: %v", err)
}
}
helper.Info("redis connected successfully")
return client, cleanup, nil
}