commit 531bb42d01c96bc4b505049f546c41be12d2a68a Author: konjacpotato Date: Thu May 22 19:39:08 2025 +0800 initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..38a30e9 --- /dev/null +++ b/README.md @@ -0,0 +1,214 @@ +# godemo + +这是一个使用Go语言开发的示例项目,用于演示Go语言的基础知识。 + +## 目录结构 + +``` +godemo/ # 项目根目录 +├── README.md # 项目说明文档 +├── go.mod # Go模块定义 +├── go.sum # 依赖校验 +├── docker/ # Docker文件目录 + └── docker-gateway/ # gateway服务的Docker文件目录 + ├── Dockerfile # gateway服务的Dockerfile文件 + └── docker-compose.yml # gateway服务的docker-compose文件 +├── sql/ # 数据库SQL定义 + └── users.sql # 用户表SQL文件 +├── api/ # HTTP服务定义 + └── gateway.api # gateway服务的HTTP API定义文件 +├── rpc/ # RPC服务定义 + └── user.proto # user服务的RPC定义文件 +├── user/ # 用户服务 +├── gateway/ # 网关服务 +... ... +``` + +## 基于.proto生成RPC服务代码 + +```bash +# 在项目的根目录执行(以user服务为例) +> goctl rpc protoc [rpc/user.proto] --go-grpc_out=[user] --go_out=[user] --zrpc_out=[user] +``` + +## 基于.api生成HTTP服务代码 + +```bash +# 在项目的根目录执行(以gateway服务为例) +> goctl api go -api [api/gateway.api] -dir [gateway] +``` + +## 基于数据库生成模型层代码 + +```bash +# 在项目的根目录执行(以category服务为例) +> goctl model pg datasource -url="postgres://postgres:postgres@localhost:19732/godemo?sslmode=disable" -schema="public" -table="categories" -dir="./category/internal/model" +``` + +**说明** + +数据表的定义在sql目录下,到postgres执行对应的数据表文件,然后用上面的命令生成模型层代码。 + +后续模型层增加接口,可以在internal/model/categoriesmodel.go中增加接口定义(以category服务为例): +)。 + +## 整合模型层代码 + +生成的模型层代码要被业务代码使用,需要引入到业务代码中。主要修改三个地方(以category服务为例): + +```go +# etc/category.yaml 增加下面的配置 +DB: + DataSource: postgres://postgres:postgres@localhost:19732/godemo?sslmode=disable + MaxOpenConns: 100 + MaxIdleConns: 20 + ConnMaxLifetime: 3600 + +# internal/config/config.go +type Config struct { + zrpc.RpcServerConf + DB struct { + DataSource string + MaxOpenConns int + MaxIdleConns int + ConnMaxLifetime int + } +} + +# internal/svc/serviceContext.go +import ( + "godemo/category/internal/config" + "godemo/category/internal/model" + + _ "github.com/lib/pq" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) + +type ServiceContext struct { + Config config.Config + CategoryModel model.CategoriesModel +} + +func NewServiceContext(c config.Config) *ServiceContext { + conn := sqlx.NewSqlConn("postgres", c.DB.DataSource) + return &ServiceContext{ + Config: c, + CategoryModel: model.NewCategoriesModel(conn), + } +} +``` + +## 创建Dockerfile + +```bash +# 在项目的根目录执行(以category服务为例) +> goctl docker -go [category/category.go] +``` + +生成的Dockerfile里面有些路径需要修改,也有些内容需要增加。 + +然后再docker目录创建[docker-category]文件夹,把Dockerfile移动到docker-category文件夹下。 + +## 创建docker-compose.yml + +在Dockerfile同级目录创建docker-compose.yaml,内容可以参考下面的category服务的。另外需要在当前目录创建etc文件夹,把服务的配置文件拷贝到etc文件夹下,并命名为config.yaml。 + +```yml +services: + category: + image: category:v1 + container_name: category + restart: always + volumes: + - ./etc:/app/etc + networks: + - godemo_network + # 端口映射,生产环境非必须,开发环境用于方便调试 + ports: + - "60300:60300" + +networks: + godemo_network: + name: godemo_network + external: true +``` + +## 编译Docker镜像 + +```bash +# 在项目的根目录执行(以file服务为例) +> docker build -t [file:v1] -f [docker/docker-file/Dockerfile] . +``` + +## 运行Docker容器 + +```bash +# 在对应服务的docker目录执行(以file服务为例) +> docker/docker-file> docker compose up -d +``` + +## RPC服务测试/调试 + +```bash +# 查看60200端口下的RPC服务提供的服务 +> grpcurl -plaintext localhost:60200 list + +# 查看某个服务提供的接口 +> grpcurl -plaintext localhost:60200 list file.File + +# 调用某个接口 +> grpcurl -d '{\"file_id\": \"aaaa/333333333333.png\"}' -plaintext localhost:60200 file.File/GetFileUrl +``` + +## 网关服务 + +## 用户服务 + +**接口定义** + +- 用户登录 +- 获取用户信息 +- 用户注册 +- 用户注销 + +## 文件服务 + +## 分类服务 + +分类服务(Category Service),这是一个用于统一管理多系统/多模块分类体系的微服务。 +- 支持多级分类 +- 通过system_id支持多系统分类 + +```dev +# 增 +grpcurl -plaintext -d '{\"system_id\": \"ecommerce\",\"name\": \"Electronics\",\"alias\": \"electronics\",\"parent_id\": \"\"}' localhost:60300 category.Category/CreateCategory + +# 删 +grpcurl -plaintext -d '{\"id\": \"fe8d31d5-11f4-4ddd-a4ac-76d358faed2b\"}' localhost:60300 category.Category/DeleteCategory + +# 改 +grpcurl -plaintext -d '{\"id\": \"d628cf35-539f-4533-a5a2-492d729ecf3b\",\"name\": \"New Electronics Name\" +}' localhost:60300 category.Category/UpdateCategory + +# 查 +grpcurl -plaintext -d '{\"id\": \"d628cf35-539f-4533-a5a2-492d729ecf3b\"}' localhost:60300 category.Category/GetCategory + +``` + +## 图库服务 + +**接口定义** + +- 获取图片列表 +- 获取图片详情 +- 获取分类 +- 上传图片 +- 删除图片 +- 修改图片 +- 获取图片URL +- 下载图片 + +/api/gallery/v1/ + + + diff --git a/api/gateway.api b/api/gateway.api new file mode 100644 index 0000000..1e8b7ce --- /dev/null +++ b/api/gateway.api @@ -0,0 +1,61 @@ +syntax = "v1" + +type RegisterReq { + Username string `json:"username"` + Password string `json:"password"` + Email string `json:"email"` +} + +type RegisterResp { + UserId string `json:"user_id"` +} + +type LoginReq { + Username string `json:"username"` + Password string `json:"password"` +} + +type LoginResp { + Token string `json:"token"` + ExpiresAt int64 `json:"expires_at"` +} + +type LogoutReq { + Token string `json:"token"` +} + +type LogoutResp { + Success bool `json:"success"` +} + +type GetUserInfoReq { + UserId string `path:"user_id"` +} + +type GetUserInfoResp { + UserId string `json:"user_id"` + Username string `json:"username"` + Email string `json:"email"` + CreatedAt int64 `json:"created_at"` + Roles []string `json:"roles"` +} + +service user-api { + @handler registerHandler + post /api/user/register (RegisterReq) returns (RegisterResp) + + @handler loginHandler + post /api/user/login (LoginReq) returns (LoginResp) +} + +@server ( + jwt: JwtAuth +) +service user-api { + @handler logoutHandler + post /api/user/logout (LogoutReq) returns (LogoutResp) + + @handler getUserInfoHandler + get /api/user/:user_id (GetUserInfoReq) returns (GetUserInfoResp) +} + diff --git a/category/category.go b/category/category.go new file mode 100644 index 0000000..d44b8ef --- /dev/null +++ b/category/category.go @@ -0,0 +1,39 @@ +package main + +import ( + "flag" + "fmt" + + "godemo/category/category" + "godemo/category/internal/config" + "godemo/category/internal/server" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/conf" + "github.com/zeromicro/go-zero/core/service" + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var configFile = flag.String("f", "etc/category.yaml", "the config file") + +func main() { + flag.Parse() + + var c config.Config + conf.MustLoad(*configFile, &c) + ctx := svc.NewServiceContext(c) + + s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { + category.RegisterCategoryServer(grpcServer, server.NewCategoryServer(ctx)) + + if c.Mode == service.DevMode || c.Mode == service.TestMode { + reflection.Register(grpcServer) + } + }) + defer s.Stop() + + fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) + s.Start() +} diff --git a/category/category/category.pb.go b/category/category/category.pb.go new file mode 100644 index 0000000..eb0cc4f --- /dev/null +++ b/category/category/category.pb.go @@ -0,0 +1,1574 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.6 +// protoc v3.19.4 +// source: rpc/category.proto + +package category + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// 健康检查请求 +type PingRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Ping string `protobuf:"bytes,1,opt,name=ping,proto3" json:"ping,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PingRequest) Reset() { + *x = PingRequest{} + mi := &file_rpc_category_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PingRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PingRequest) ProtoMessage() {} + +func (x *PingRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PingRequest.ProtoReflect.Descriptor instead. +func (*PingRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{0} +} + +func (x *PingRequest) GetPing() string { + if x != nil { + return x.Ping + } + return "" +} + +// 健康检查响应 +type PingResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Pong string `protobuf:"bytes,1,opt,name=pong,proto3" json:"pong,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PingResponse) Reset() { + *x = PingResponse{} + mi := &file_rpc_category_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PingResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PingResponse) ProtoMessage() {} + +func (x *PingResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PingResponse.ProtoReflect.Descriptor instead. +func (*PingResponse) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{1} +} + +func (x *PingResponse) GetPong() string { + if x != nil { + return x.Pong + } + return "" +} + +// 分类基础信息 +type CategoryInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // UUID + SystemId string `protobuf:"bytes,2,opt,name=system_id,json=systemId,proto3" json:"system_id,omitempty"` // 所属系统标识 + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` // 分类名称 + Alias string `protobuf:"bytes,4,opt,name=alias,proto3" json:"alias,omitempty"` // URL别名 + ParentId string `protobuf:"bytes,5,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"` // 父分类ID + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` // 描述 + CreatedAt int64 `protobuf:"varint,7,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` // 创建时间戳 + UpdatedAt int64 `protobuf:"varint,8,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` // 更新时间戳 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CategoryInfo) Reset() { + *x = CategoryInfo{} + mi := &file_rpc_category_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CategoryInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CategoryInfo) ProtoMessage() {} + +func (x *CategoryInfo) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CategoryInfo.ProtoReflect.Descriptor instead. +func (*CategoryInfo) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{2} +} + +func (x *CategoryInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *CategoryInfo) GetSystemId() string { + if x != nil { + return x.SystemId + } + return "" +} + +func (x *CategoryInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CategoryInfo) GetAlias() string { + if x != nil { + return x.Alias + } + return "" +} + +func (x *CategoryInfo) GetParentId() string { + if x != nil { + return x.ParentId + } + return "" +} + +func (x *CategoryInfo) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *CategoryInfo) GetCreatedAt() int64 { + if x != nil { + return x.CreatedAt + } + return 0 +} + +func (x *CategoryInfo) GetUpdatedAt() int64 { + if x != nil { + return x.UpdatedAt + } + return 0 +} + +// 创建分类请求 +type CreateCategoryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SystemId string `protobuf:"bytes,1,opt,name=system_id,json=systemId,proto3" json:"system_id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Alias string `protobuf:"bytes,3,opt,name=alias,proto3" json:"alias,omitempty"` + ParentId string `protobuf:"bytes,4,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"` // 空字符串表示根分类 + Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateCategoryRequest) Reset() { + *x = CreateCategoryRequest{} + mi := &file_rpc_category_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateCategoryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateCategoryRequest) ProtoMessage() {} + +func (x *CreateCategoryRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateCategoryRequest.ProtoReflect.Descriptor instead. +func (*CreateCategoryRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{3} +} + +func (x *CreateCategoryRequest) GetSystemId() string { + if x != nil { + return x.SystemId + } + return "" +} + +func (x *CreateCategoryRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CreateCategoryRequest) GetAlias() string { + if x != nil { + return x.Alias + } + return "" +} + +func (x *CreateCategoryRequest) GetParentId() string { + if x != nil { + return x.ParentId + } + return "" +} + +func (x *CreateCategoryRequest) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +// 更新分类请求 +type UpdateCategoryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Alias string `protobuf:"bytes,3,opt,name=alias,proto3" json:"alias,omitempty"` + ParentId string `protobuf:"bytes,4,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"` // 修改父分类时使用 + Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateCategoryRequest) Reset() { + *x = UpdateCategoryRequest{} + mi := &file_rpc_category_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateCategoryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateCategoryRequest) ProtoMessage() {} + +func (x *UpdateCategoryRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateCategoryRequest.ProtoReflect.Descriptor instead. +func (*UpdateCategoryRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{4} +} + +func (x *UpdateCategoryRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateCategoryRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpdateCategoryRequest) GetAlias() string { + if x != nil { + return x.Alias + } + return "" +} + +func (x *UpdateCategoryRequest) GetParentId() string { + if x != nil { + return x.ParentId + } + return "" +} + +func (x *UpdateCategoryRequest) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +// 删除分类请求 +type DeleteCategoryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteCategoryRequest) Reset() { + *x = DeleteCategoryRequest{} + mi := &file_rpc_category_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteCategoryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteCategoryRequest) ProtoMessage() {} + +func (x *DeleteCategoryRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteCategoryRequest.ProtoReflect.Descriptor instead. +func (*DeleteCategoryRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{5} +} + +func (x *DeleteCategoryRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +// 删除响应 +type DeleteResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteResponse) Reset() { + *x = DeleteResponse{} + mi := &file_rpc_category_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteResponse) ProtoMessage() {} + +func (x *DeleteResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteResponse.ProtoReflect.Descriptor instead. +func (*DeleteResponse) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{6} +} + +func (x *DeleteResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +// 分类查询请求 +type GetCategoryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetCategoryRequest) Reset() { + *x = GetCategoryRequest{} + mi := &file_rpc_category_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetCategoryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCategoryRequest) ProtoMessage() {} + +func (x *GetCategoryRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetCategoryRequest.ProtoReflect.Descriptor instead. +func (*GetCategoryRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{7} +} + +func (x *GetCategoryRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +// 分类信息响应 +type CategoryInfoResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Category *CategoryInfo `protobuf:"bytes,1,opt,name=category,proto3" json:"category,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CategoryInfoResponse) Reset() { + *x = CategoryInfoResponse{} + mi := &file_rpc_category_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CategoryInfoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CategoryInfoResponse) ProtoMessage() {} + +func (x *CategoryInfoResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CategoryInfoResponse.ProtoReflect.Descriptor instead. +func (*CategoryInfoResponse) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{8} +} + +func (x *CategoryInfoResponse) GetCategory() *CategoryInfo { + if x != nil { + return x.Category + } + return nil +} + +// 层级结构操作请求 +type GetChildrenRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ParentId string `protobuf:"bytes,1,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"` // 为空时查询根分类 + Recursive bool `protobuf:"varint,2,opt,name=recursive,proto3" json:"recursive,omitempty"` // 是否递归获取所有子节点 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetChildrenRequest) Reset() { + *x = GetChildrenRequest{} + mi := &file_rpc_category_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetChildrenRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetChildrenRequest) ProtoMessage() {} + +func (x *GetChildrenRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetChildrenRequest.ProtoReflect.Descriptor instead. +func (*GetChildrenRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{9} +} + +func (x *GetChildrenRequest) GetParentId() string { + if x != nil { + return x.ParentId + } + return "" +} + +func (x *GetChildrenRequest) GetRecursive() bool { + if x != nil { + return x.Recursive + } + return false +} + +// 树形结构请求 +type GetTreeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SystemId string `protobuf:"bytes,1,opt,name=system_id,json=systemId,proto3" json:"system_id,omitempty"` // 必须指定系统 + RootId string `protobuf:"bytes,2,opt,name=root_id,json=rootId,proto3" json:"root_id,omitempty"` // 空字符串表示从根开始 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTreeRequest) Reset() { + *x = GetTreeRequest{} + mi := &file_rpc_category_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTreeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTreeRequest) ProtoMessage() {} + +func (x *GetTreeRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTreeRequest.ProtoReflect.Descriptor instead. +func (*GetTreeRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{10} +} + +func (x *GetTreeRequest) GetSystemId() string { + if x != nil { + return x.SystemId + } + return "" +} + +func (x *GetTreeRequest) GetRootId() string { + if x != nil { + return x.RootId + } + return "" +} + +// 移动分类请求 +type MoveCategoryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + NewParentId string `protobuf:"bytes,2,opt,name=new_parent_id,json=newParentId,proto3" json:"new_parent_id,omitempty"` // 空字符串表示移动到根 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MoveCategoryRequest) Reset() { + *x = MoveCategoryRequest{} + mi := &file_rpc_category_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MoveCategoryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MoveCategoryRequest) ProtoMessage() {} + +func (x *MoveCategoryRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MoveCategoryRequest.ProtoReflect.Descriptor instead. +func (*MoveCategoryRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{11} +} + +func (x *MoveCategoryRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *MoveCategoryRequest) GetNewParentId() string { + if x != nil { + return x.NewParentId + } + return "" +} + +// 祖先路径请求 +type GetAncestorPathRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetAncestorPathRequest) Reset() { + *x = GetAncestorPathRequest{} + mi := &file_rpc_category_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetAncestorPathRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAncestorPathRequest) ProtoMessage() {} + +func (x *GetAncestorPathRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAncestorPathRequest.ProtoReflect.Descriptor instead. +func (*GetAncestorPathRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{12} +} + +func (x *GetAncestorPathRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +// 分类路径响应 +type CategoryPathResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Path []*CategoryInfo `protobuf:"bytes,1,rep,name=path,proto3" json:"path,omitempty"` // 从根到当前分类的路径 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CategoryPathResponse) Reset() { + *x = CategoryPathResponse{} + mi := &file_rpc_category_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CategoryPathResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CategoryPathResponse) ProtoMessage() {} + +func (x *CategoryPathResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CategoryPathResponse.ProtoReflect.Descriptor instead. +func (*CategoryPathResponse) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{13} +} + +func (x *CategoryPathResponse) GetPath() []*CategoryInfo { + if x != nil { + return x.Path + } + return nil +} + +// 批量操作请求 +type BatchCreateRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Categories []*CreateCategoryRequest `protobuf:"bytes,1,rep,name=categories,proto3" json:"categories,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BatchCreateRequest) Reset() { + *x = BatchCreateRequest{} + mi := &file_rpc_category_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BatchCreateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchCreateRequest) ProtoMessage() {} + +func (x *BatchCreateRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchCreateRequest.ProtoReflect.Descriptor instead. +func (*BatchCreateRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{14} +} + +func (x *BatchCreateRequest) GetCategories() []*CreateCategoryRequest { + if x != nil { + return x.Categories + } + return nil +} + +type BatchCreateResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + CreatedCategories []*CategoryInfo `protobuf:"bytes,1,rep,name=created_categories,json=createdCategories,proto3" json:"created_categories,omitempty"` + SuccessCount int32 `protobuf:"varint,2,opt,name=success_count,json=successCount,proto3" json:"success_count,omitempty"` + FailCount int32 `protobuf:"varint,3,opt,name=fail_count,json=failCount,proto3" json:"fail_count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BatchCreateResponse) Reset() { + *x = BatchCreateResponse{} + mi := &file_rpc_category_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BatchCreateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchCreateResponse) ProtoMessage() {} + +func (x *BatchCreateResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchCreateResponse.ProtoReflect.Descriptor instead. +func (*BatchCreateResponse) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{15} +} + +func (x *BatchCreateResponse) GetCreatedCategories() []*CategoryInfo { + if x != nil { + return x.CreatedCategories + } + return nil +} + +func (x *BatchCreateResponse) GetSuccessCount() int32 { + if x != nil { + return x.SuccessCount + } + return 0 +} + +func (x *BatchCreateResponse) GetFailCount() int32 { + if x != nil { + return x.FailCount + } + return 0 +} + +type BatchUpdateRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Categories []*UpdateCategoryRequest `protobuf:"bytes,1,rep,name=categories,proto3" json:"categories,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BatchUpdateRequest) Reset() { + *x = BatchUpdateRequest{} + mi := &file_rpc_category_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BatchUpdateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateRequest) ProtoMessage() {} + +func (x *BatchUpdateRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchUpdateRequest.ProtoReflect.Descriptor instead. +func (*BatchUpdateRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{16} +} + +func (x *BatchUpdateRequest) GetCategories() []*UpdateCategoryRequest { + if x != nil { + return x.Categories + } + return nil +} + +type BatchUpdateResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdatedCategories []*CategoryInfo `protobuf:"bytes,1,rep,name=updated_categories,json=updatedCategories,proto3" json:"updated_categories,omitempty"` + SuccessCount int32 `protobuf:"varint,2,opt,name=success_count,json=successCount,proto3" json:"success_count,omitempty"` + FailCount int32 `protobuf:"varint,3,opt,name=fail_count,json=failCount,proto3" json:"fail_count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BatchUpdateResponse) Reset() { + *x = BatchUpdateResponse{} + mi := &file_rpc_category_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BatchUpdateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateResponse) ProtoMessage() {} + +func (x *BatchUpdateResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchUpdateResponse.ProtoReflect.Descriptor instead. +func (*BatchUpdateResponse) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{17} +} + +func (x *BatchUpdateResponse) GetUpdatedCategories() []*CategoryInfo { + if x != nil { + return x.UpdatedCategories + } + return nil +} + +func (x *BatchUpdateResponse) GetSuccessCount() int32 { + if x != nil { + return x.SuccessCount + } + return 0 +} + +func (x *BatchUpdateResponse) GetFailCount() int32 { + if x != nil { + return x.FailCount + } + return 0 +} + +// 列表查询请求 +type ListCategoryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SystemId string `protobuf:"bytes,1,opt,name=system_id,json=systemId,proto3" json:"system_id,omitempty"` + ParentId string `protobuf:"bytes,2,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"` // 空字符串表示根分类 + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` // 模糊匹配 + Alias string `protobuf:"bytes,4,opt,name=alias,proto3" json:"alias,omitempty"` // 精确匹配 + Page int32 `protobuf:"varint,5,opt,name=page,proto3" json:"page,omitempty"` // 分页参数 + PageSize int32 `protobuf:"varint,6,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListCategoryRequest) Reset() { + *x = ListCategoryRequest{} + mi := &file_rpc_category_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListCategoryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListCategoryRequest) ProtoMessage() {} + +func (x *ListCategoryRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListCategoryRequest.ProtoReflect.Descriptor instead. +func (*ListCategoryRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{18} +} + +func (x *ListCategoryRequest) GetSystemId() string { + if x != nil { + return x.SystemId + } + return "" +} + +func (x *ListCategoryRequest) GetParentId() string { + if x != nil { + return x.ParentId + } + return "" +} + +func (x *ListCategoryRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ListCategoryRequest) GetAlias() string { + if x != nil { + return x.Alias + } + return "" +} + +func (x *ListCategoryRequest) GetPage() int32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *ListCategoryRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +// 列表响应 +type CategoryListResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Categories []*CategoryInfo `protobuf:"bytes,1,rep,name=categories,proto3" json:"categories,omitempty"` + Total int32 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CategoryListResponse) Reset() { + *x = CategoryListResponse{} + mi := &file_rpc_category_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CategoryListResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CategoryListResponse) ProtoMessage() {} + +func (x *CategoryListResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CategoryListResponse.ProtoReflect.Descriptor instead. +func (*CategoryListResponse) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{19} +} + +func (x *CategoryListResponse) GetCategories() []*CategoryInfo { + if x != nil { + return x.Categories + } + return nil +} + +func (x *CategoryListResponse) GetTotal() int32 { + if x != nil { + return x.Total + } + return 0 +} + +// 树形结构响应 +type CategoryTreeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Root *CategoryTreeResponse_TreeNode `protobuf:"bytes,1,opt,name=root,proto3" json:"root,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CategoryTreeResponse) Reset() { + *x = CategoryTreeResponse{} + mi := &file_rpc_category_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CategoryTreeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CategoryTreeResponse) ProtoMessage() {} + +func (x *CategoryTreeResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CategoryTreeResponse.ProtoReflect.Descriptor instead. +func (*CategoryTreeResponse) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{20} +} + +func (x *CategoryTreeResponse) GetRoot() *CategoryTreeResponse_TreeNode { + if x != nil { + return x.Root + } + return nil +} + +// 别名检查请求 +type CheckAliasRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SystemId string `protobuf:"bytes,1,opt,name=system_id,json=systemId,proto3" json:"system_id,omitempty"` + ParentId string `protobuf:"bytes,2,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"` // 空字符串表示根父级 + Alias string `protobuf:"bytes,3,opt,name=alias,proto3" json:"alias,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CheckAliasRequest) Reset() { + *x = CheckAliasRequest{} + mi := &file_rpc_category_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CheckAliasRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckAliasRequest) ProtoMessage() {} + +func (x *CheckAliasRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckAliasRequest.ProtoReflect.Descriptor instead. +func (*CheckAliasRequest) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{21} +} + +func (x *CheckAliasRequest) GetSystemId() string { + if x != nil { + return x.SystemId + } + return "" +} + +func (x *CheckAliasRequest) GetParentId() string { + if x != nil { + return x.ParentId + } + return "" +} + +func (x *CheckAliasRequest) GetAlias() string { + if x != nil { + return x.Alias + } + return "" +} + +// 别名检查响应 +type CheckAliasResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + IsAvailable bool `protobuf:"varint,1,opt,name=is_available,json=isAvailable,proto3" json:"is_available,omitempty"` + ExistingId string `protobuf:"bytes,2,opt,name=existing_id,json=existingId,proto3" json:"existing_id,omitempty"` // 冲突时返回已存在的分类ID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CheckAliasResponse) Reset() { + *x = CheckAliasResponse{} + mi := &file_rpc_category_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CheckAliasResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckAliasResponse) ProtoMessage() {} + +func (x *CheckAliasResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckAliasResponse.ProtoReflect.Descriptor instead. +func (*CheckAliasResponse) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{22} +} + +func (x *CheckAliasResponse) GetIsAvailable() bool { + if x != nil { + return x.IsAvailable + } + return false +} + +func (x *CheckAliasResponse) GetExistingId() string { + if x != nil { + return x.ExistingId + } + return "" +} + +type CategoryTreeResponse_TreeNode struct { + state protoimpl.MessageState `protogen:"open.v1"` + Category *CategoryInfo `protobuf:"bytes,1,opt,name=category,proto3" json:"category,omitempty"` + Children []*CategoryTreeResponse_TreeNode `protobuf:"bytes,2,rep,name=children,proto3" json:"children,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CategoryTreeResponse_TreeNode) Reset() { + *x = CategoryTreeResponse_TreeNode{} + mi := &file_rpc_category_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CategoryTreeResponse_TreeNode) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CategoryTreeResponse_TreeNode) ProtoMessage() {} + +func (x *CategoryTreeResponse_TreeNode) ProtoReflect() protoreflect.Message { + mi := &file_rpc_category_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CategoryTreeResponse_TreeNode.ProtoReflect.Descriptor instead. +func (*CategoryTreeResponse_TreeNode) Descriptor() ([]byte, []int) { + return file_rpc_category_proto_rawDescGZIP(), []int{20, 0} +} + +func (x *CategoryTreeResponse_TreeNode) GetCategory() *CategoryInfo { + if x != nil { + return x.Category + } + return nil +} + +func (x *CategoryTreeResponse_TreeNode) GetChildren() []*CategoryTreeResponse_TreeNode { + if x != nil { + return x.Children + } + return nil +} + +var File_rpc_category_proto protoreflect.FileDescriptor + +const file_rpc_category_proto_rawDesc = "" + + "\n" + + "\x12rpc/category.proto\x12\bcategory\"!\n" + + "\vPingRequest\x12\x12\n" + + "\x04ping\x18\x01 \x01(\tR\x04ping\"\"\n" + + "\fPingResponse\x12\x12\n" + + "\x04pong\x18\x01 \x01(\tR\x04pong\"\xe2\x01\n" + + "\fCategoryInfo\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x1b\n" + + "\tsystem_id\x18\x02 \x01(\tR\bsystemId\x12\x12\n" + + "\x04name\x18\x03 \x01(\tR\x04name\x12\x14\n" + + "\x05alias\x18\x04 \x01(\tR\x05alias\x12\x1b\n" + + "\tparent_id\x18\x05 \x01(\tR\bparentId\x12 \n" + + "\vdescription\x18\x06 \x01(\tR\vdescription\x12\x1d\n" + + "\n" + + "created_at\x18\a \x01(\x03R\tcreatedAt\x12\x1d\n" + + "\n" + + "updated_at\x18\b \x01(\x03R\tupdatedAt\"\x9d\x01\n" + + "\x15CreateCategoryRequest\x12\x1b\n" + + "\tsystem_id\x18\x01 \x01(\tR\bsystemId\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x14\n" + + "\x05alias\x18\x03 \x01(\tR\x05alias\x12\x1b\n" + + "\tparent_id\x18\x04 \x01(\tR\bparentId\x12 \n" + + "\vdescription\x18\x05 \x01(\tR\vdescription\"\x90\x01\n" + + "\x15UpdateCategoryRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x14\n" + + "\x05alias\x18\x03 \x01(\tR\x05alias\x12\x1b\n" + + "\tparent_id\x18\x04 \x01(\tR\bparentId\x12 \n" + + "\vdescription\x18\x05 \x01(\tR\vdescription\"'\n" + + "\x15DeleteCategoryRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"*\n" + + "\x0eDeleteResponse\x12\x18\n" + + "\asuccess\x18\x01 \x01(\bR\asuccess\"$\n" + + "\x12GetCategoryRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"J\n" + + "\x14CategoryInfoResponse\x122\n" + + "\bcategory\x18\x01 \x01(\v2\x16.category.CategoryInfoR\bcategory\"O\n" + + "\x12GetChildrenRequest\x12\x1b\n" + + "\tparent_id\x18\x01 \x01(\tR\bparentId\x12\x1c\n" + + "\trecursive\x18\x02 \x01(\bR\trecursive\"F\n" + + "\x0eGetTreeRequest\x12\x1b\n" + + "\tsystem_id\x18\x01 \x01(\tR\bsystemId\x12\x17\n" + + "\aroot_id\x18\x02 \x01(\tR\x06rootId\"I\n" + + "\x13MoveCategoryRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\"\n" + + "\rnew_parent_id\x18\x02 \x01(\tR\vnewParentId\"(\n" + + "\x16GetAncestorPathRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"B\n" + + "\x14CategoryPathResponse\x12*\n" + + "\x04path\x18\x01 \x03(\v2\x16.category.CategoryInfoR\x04path\"U\n" + + "\x12BatchCreateRequest\x12?\n" + + "\n" + + "categories\x18\x01 \x03(\v2\x1f.category.CreateCategoryRequestR\n" + + "categories\"\xa0\x01\n" + + "\x13BatchCreateResponse\x12E\n" + + "\x12created_categories\x18\x01 \x03(\v2\x16.category.CategoryInfoR\x11createdCategories\x12#\n" + + "\rsuccess_count\x18\x02 \x01(\x05R\fsuccessCount\x12\x1d\n" + + "\n" + + "fail_count\x18\x03 \x01(\x05R\tfailCount\"U\n" + + "\x12BatchUpdateRequest\x12?\n" + + "\n" + + "categories\x18\x01 \x03(\v2\x1f.category.UpdateCategoryRequestR\n" + + "categories\"\xa0\x01\n" + + "\x13BatchUpdateResponse\x12E\n" + + "\x12updated_categories\x18\x01 \x03(\v2\x16.category.CategoryInfoR\x11updatedCategories\x12#\n" + + "\rsuccess_count\x18\x02 \x01(\x05R\fsuccessCount\x12\x1d\n" + + "\n" + + "fail_count\x18\x03 \x01(\x05R\tfailCount\"\xaa\x01\n" + + "\x13ListCategoryRequest\x12\x1b\n" + + "\tsystem_id\x18\x01 \x01(\tR\bsystemId\x12\x1b\n" + + "\tparent_id\x18\x02 \x01(\tR\bparentId\x12\x12\n" + + "\x04name\x18\x03 \x01(\tR\x04name\x12\x14\n" + + "\x05alias\x18\x04 \x01(\tR\x05alias\x12\x12\n" + + "\x04page\x18\x05 \x01(\x05R\x04page\x12\x1b\n" + + "\tpage_size\x18\x06 \x01(\x05R\bpageSize\"d\n" + + "\x14CategoryListResponse\x126\n" + + "\n" + + "categories\x18\x01 \x03(\v2\x16.category.CategoryInfoR\n" + + "categories\x12\x14\n" + + "\x05total\x18\x02 \x01(\x05R\x05total\"\xd9\x01\n" + + "\x14CategoryTreeResponse\x12;\n" + + "\x04root\x18\x01 \x01(\v2'.category.CategoryTreeResponse.TreeNodeR\x04root\x1a\x83\x01\n" + + "\bTreeNode\x122\n" + + "\bcategory\x18\x01 \x01(\v2\x16.category.CategoryInfoR\bcategory\x12C\n" + + "\bchildren\x18\x02 \x03(\v2'.category.CategoryTreeResponse.TreeNodeR\bchildren\"c\n" + + "\x11CheckAliasRequest\x12\x1b\n" + + "\tsystem_id\x18\x01 \x01(\tR\bsystemId\x12\x1b\n" + + "\tparent_id\x18\x02 \x01(\tR\bparentId\x12\x14\n" + + "\x05alias\x18\x03 \x01(\tR\x05alias\"X\n" + + "\x12CheckAliasResponse\x12!\n" + + "\fis_available\x18\x01 \x01(\bR\visAvailable\x12\x1f\n" + + "\vexisting_id\x18\x02 \x01(\tR\n" + + "existingId2\xfd\a\n" + + "\bCategory\x125\n" + + "\x04Ping\x12\x15.category.PingRequest\x1a\x16.category.PingResponse\x12Q\n" + + "\x0eCreateCategory\x12\x1f.category.CreateCategoryRequest\x1a\x1e.category.CategoryInfoResponse\x12Q\n" + + "\x0eUpdateCategory\x12\x1f.category.UpdateCategoryRequest\x1a\x1e.category.CategoryInfoResponse\x12K\n" + + "\x0eDeleteCategory\x12\x1f.category.DeleteCategoryRequest\x1a\x18.category.DeleteResponse\x12K\n" + + "\vGetCategory\x12\x1c.category.GetCategoryRequest\x1a\x1e.category.CategoryInfoResponse\x12K\n" + + "\vGetChildren\x12\x1c.category.GetChildrenRequest\x1a\x1e.category.CategoryListResponse\x12C\n" + + "\aGetTree\x12\x18.category.GetTreeRequest\x1a\x1e.category.CategoryTreeResponse\x12M\n" + + "\fMoveCategory\x12\x1d.category.MoveCategoryRequest\x1a\x1e.category.CategoryInfoResponse\x12S\n" + + "\x0fGetAncestorPath\x12 .category.GetAncestorPathRequest\x1a\x1e.category.CategoryPathResponse\x12T\n" + + "\x15BatchCreateCategories\x12\x1c.category.BatchCreateRequest\x1a\x1d.category.BatchCreateResponse\x12T\n" + + "\x15BatchUpdateCategories\x12\x1c.category.BatchUpdateRequest\x1a\x1d.category.BatchUpdateResponse\x12O\n" + + "\x0eListCategories\x12\x1d.category.ListCategoryRequest\x1a\x1e.category.CategoryListResponse\x12G\n" + + "\n" + + "CheckAlias\x12\x1b.category.CheckAliasRequest\x1a\x1c.category.CheckAliasResponseB\fZ\n" + + "./categoryb\x06proto3" + +var ( + file_rpc_category_proto_rawDescOnce sync.Once + file_rpc_category_proto_rawDescData []byte +) + +func file_rpc_category_proto_rawDescGZIP() []byte { + file_rpc_category_proto_rawDescOnce.Do(func() { + file_rpc_category_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_rpc_category_proto_rawDesc), len(file_rpc_category_proto_rawDesc))) + }) + return file_rpc_category_proto_rawDescData +} + +var file_rpc_category_proto_msgTypes = make([]protoimpl.MessageInfo, 24) +var file_rpc_category_proto_goTypes = []any{ + (*PingRequest)(nil), // 0: category.PingRequest + (*PingResponse)(nil), // 1: category.PingResponse + (*CategoryInfo)(nil), // 2: category.CategoryInfo + (*CreateCategoryRequest)(nil), // 3: category.CreateCategoryRequest + (*UpdateCategoryRequest)(nil), // 4: category.UpdateCategoryRequest + (*DeleteCategoryRequest)(nil), // 5: category.DeleteCategoryRequest + (*DeleteResponse)(nil), // 6: category.DeleteResponse + (*GetCategoryRequest)(nil), // 7: category.GetCategoryRequest + (*CategoryInfoResponse)(nil), // 8: category.CategoryInfoResponse + (*GetChildrenRequest)(nil), // 9: category.GetChildrenRequest + (*GetTreeRequest)(nil), // 10: category.GetTreeRequest + (*MoveCategoryRequest)(nil), // 11: category.MoveCategoryRequest + (*GetAncestorPathRequest)(nil), // 12: category.GetAncestorPathRequest + (*CategoryPathResponse)(nil), // 13: category.CategoryPathResponse + (*BatchCreateRequest)(nil), // 14: category.BatchCreateRequest + (*BatchCreateResponse)(nil), // 15: category.BatchCreateResponse + (*BatchUpdateRequest)(nil), // 16: category.BatchUpdateRequest + (*BatchUpdateResponse)(nil), // 17: category.BatchUpdateResponse + (*ListCategoryRequest)(nil), // 18: category.ListCategoryRequest + (*CategoryListResponse)(nil), // 19: category.CategoryListResponse + (*CategoryTreeResponse)(nil), // 20: category.CategoryTreeResponse + (*CheckAliasRequest)(nil), // 21: category.CheckAliasRequest + (*CheckAliasResponse)(nil), // 22: category.CheckAliasResponse + (*CategoryTreeResponse_TreeNode)(nil), // 23: category.CategoryTreeResponse.TreeNode +} +var file_rpc_category_proto_depIdxs = []int32{ + 2, // 0: category.CategoryInfoResponse.category:type_name -> category.CategoryInfo + 2, // 1: category.CategoryPathResponse.path:type_name -> category.CategoryInfo + 3, // 2: category.BatchCreateRequest.categories:type_name -> category.CreateCategoryRequest + 2, // 3: category.BatchCreateResponse.created_categories:type_name -> category.CategoryInfo + 4, // 4: category.BatchUpdateRequest.categories:type_name -> category.UpdateCategoryRequest + 2, // 5: category.BatchUpdateResponse.updated_categories:type_name -> category.CategoryInfo + 2, // 6: category.CategoryListResponse.categories:type_name -> category.CategoryInfo + 23, // 7: category.CategoryTreeResponse.root:type_name -> category.CategoryTreeResponse.TreeNode + 2, // 8: category.CategoryTreeResponse.TreeNode.category:type_name -> category.CategoryInfo + 23, // 9: category.CategoryTreeResponse.TreeNode.children:type_name -> category.CategoryTreeResponse.TreeNode + 0, // 10: category.Category.Ping:input_type -> category.PingRequest + 3, // 11: category.Category.CreateCategory:input_type -> category.CreateCategoryRequest + 4, // 12: category.Category.UpdateCategory:input_type -> category.UpdateCategoryRequest + 5, // 13: category.Category.DeleteCategory:input_type -> category.DeleteCategoryRequest + 7, // 14: category.Category.GetCategory:input_type -> category.GetCategoryRequest + 9, // 15: category.Category.GetChildren:input_type -> category.GetChildrenRequest + 10, // 16: category.Category.GetTree:input_type -> category.GetTreeRequest + 11, // 17: category.Category.MoveCategory:input_type -> category.MoveCategoryRequest + 12, // 18: category.Category.GetAncestorPath:input_type -> category.GetAncestorPathRequest + 14, // 19: category.Category.BatchCreateCategories:input_type -> category.BatchCreateRequest + 16, // 20: category.Category.BatchUpdateCategories:input_type -> category.BatchUpdateRequest + 18, // 21: category.Category.ListCategories:input_type -> category.ListCategoryRequest + 21, // 22: category.Category.CheckAlias:input_type -> category.CheckAliasRequest + 1, // 23: category.Category.Ping:output_type -> category.PingResponse + 8, // 24: category.Category.CreateCategory:output_type -> category.CategoryInfoResponse + 8, // 25: category.Category.UpdateCategory:output_type -> category.CategoryInfoResponse + 6, // 26: category.Category.DeleteCategory:output_type -> category.DeleteResponse + 8, // 27: category.Category.GetCategory:output_type -> category.CategoryInfoResponse + 19, // 28: category.Category.GetChildren:output_type -> category.CategoryListResponse + 20, // 29: category.Category.GetTree:output_type -> category.CategoryTreeResponse + 8, // 30: category.Category.MoveCategory:output_type -> category.CategoryInfoResponse + 13, // 31: category.Category.GetAncestorPath:output_type -> category.CategoryPathResponse + 15, // 32: category.Category.BatchCreateCategories:output_type -> category.BatchCreateResponse + 17, // 33: category.Category.BatchUpdateCategories:output_type -> category.BatchUpdateResponse + 19, // 34: category.Category.ListCategories:output_type -> category.CategoryListResponse + 22, // 35: category.Category.CheckAlias:output_type -> category.CheckAliasResponse + 23, // [23:36] is the sub-list for method output_type + 10, // [10:23] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name +} + +func init() { file_rpc_category_proto_init() } +func file_rpc_category_proto_init() { + if File_rpc_category_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_rpc_category_proto_rawDesc), len(file_rpc_category_proto_rawDesc)), + NumEnums: 0, + NumMessages: 24, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_rpc_category_proto_goTypes, + DependencyIndexes: file_rpc_category_proto_depIdxs, + MessageInfos: file_rpc_category_proto_msgTypes, + }.Build() + File_rpc_category_proto = out.File + file_rpc_category_proto_goTypes = nil + file_rpc_category_proto_depIdxs = nil +} diff --git a/category/category/category_grpc.pb.go b/category/category/category_grpc.pb.go new file mode 100644 index 0000000..d68b451 --- /dev/null +++ b/category/category/category_grpc.pb.go @@ -0,0 +1,591 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v3.19.4 +// source: rpc/category.proto + +package category + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Category_Ping_FullMethodName = "/category.Category/Ping" + Category_CreateCategory_FullMethodName = "/category.Category/CreateCategory" + Category_UpdateCategory_FullMethodName = "/category.Category/UpdateCategory" + Category_DeleteCategory_FullMethodName = "/category.Category/DeleteCategory" + Category_GetCategory_FullMethodName = "/category.Category/GetCategory" + Category_GetChildren_FullMethodName = "/category.Category/GetChildren" + Category_GetTree_FullMethodName = "/category.Category/GetTree" + Category_MoveCategory_FullMethodName = "/category.Category/MoveCategory" + Category_GetAncestorPath_FullMethodName = "/category.Category/GetAncestorPath" + Category_BatchCreateCategories_FullMethodName = "/category.Category/BatchCreateCategories" + Category_BatchUpdateCategories_FullMethodName = "/category.Category/BatchUpdateCategories" + Category_ListCategories_FullMethodName = "/category.Category/ListCategories" + Category_CheckAlias_FullMethodName = "/category.Category/CheckAlias" +) + +// CategoryClient is the client API for Category service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// 分类服务 - 分类管理、树形结构操作、批量处理 +type CategoryClient interface { + // 健康检查 + Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) + // 分类基础操作 + CreateCategory(ctx context.Context, in *CreateCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) + UpdateCategory(ctx context.Context, in *UpdateCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) + DeleteCategory(ctx context.Context, in *DeleteCategoryRequest, opts ...grpc.CallOption) (*DeleteResponse, error) + GetCategory(ctx context.Context, in *GetCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) + // 层级结构操作 + GetChildren(ctx context.Context, in *GetChildrenRequest, opts ...grpc.CallOption) (*CategoryListResponse, error) + GetTree(ctx context.Context, in *GetTreeRequest, opts ...grpc.CallOption) (*CategoryTreeResponse, error) + MoveCategory(ctx context.Context, in *MoveCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) + GetAncestorPath(ctx context.Context, in *GetAncestorPathRequest, opts ...grpc.CallOption) (*CategoryPathResponse, error) + // 批量操作 + BatchCreateCategories(ctx context.Context, in *BatchCreateRequest, opts ...grpc.CallOption) (*BatchCreateResponse, error) + BatchUpdateCategories(ctx context.Context, in *BatchUpdateRequest, opts ...grpc.CallOption) (*BatchUpdateResponse, error) + // 查询过滤 + ListCategories(ctx context.Context, in *ListCategoryRequest, opts ...grpc.CallOption) (*CategoryListResponse, error) + CheckAlias(ctx context.Context, in *CheckAliasRequest, opts ...grpc.CallOption) (*CheckAliasResponse, error) +} + +type categoryClient struct { + cc grpc.ClientConnInterface +} + +func NewCategoryClient(cc grpc.ClientConnInterface) CategoryClient { + return &categoryClient{cc} +} + +func (c *categoryClient) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PingResponse) + err := c.cc.Invoke(ctx, Category_Ping_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *categoryClient) CreateCategory(ctx context.Context, in *CreateCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CategoryInfoResponse) + err := c.cc.Invoke(ctx, Category_CreateCategory_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *categoryClient) UpdateCategory(ctx context.Context, in *UpdateCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CategoryInfoResponse) + err := c.cc.Invoke(ctx, Category_UpdateCategory_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *categoryClient) DeleteCategory(ctx context.Context, in *DeleteCategoryRequest, opts ...grpc.CallOption) (*DeleteResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteResponse) + err := c.cc.Invoke(ctx, Category_DeleteCategory_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *categoryClient) GetCategory(ctx context.Context, in *GetCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CategoryInfoResponse) + err := c.cc.Invoke(ctx, Category_GetCategory_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *categoryClient) GetChildren(ctx context.Context, in *GetChildrenRequest, opts ...grpc.CallOption) (*CategoryListResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CategoryListResponse) + err := c.cc.Invoke(ctx, Category_GetChildren_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *categoryClient) GetTree(ctx context.Context, in *GetTreeRequest, opts ...grpc.CallOption) (*CategoryTreeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CategoryTreeResponse) + err := c.cc.Invoke(ctx, Category_GetTree_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *categoryClient) MoveCategory(ctx context.Context, in *MoveCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CategoryInfoResponse) + err := c.cc.Invoke(ctx, Category_MoveCategory_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *categoryClient) GetAncestorPath(ctx context.Context, in *GetAncestorPathRequest, opts ...grpc.CallOption) (*CategoryPathResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CategoryPathResponse) + err := c.cc.Invoke(ctx, Category_GetAncestorPath_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *categoryClient) BatchCreateCategories(ctx context.Context, in *BatchCreateRequest, opts ...grpc.CallOption) (*BatchCreateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(BatchCreateResponse) + err := c.cc.Invoke(ctx, Category_BatchCreateCategories_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *categoryClient) BatchUpdateCategories(ctx context.Context, in *BatchUpdateRequest, opts ...grpc.CallOption) (*BatchUpdateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(BatchUpdateResponse) + err := c.cc.Invoke(ctx, Category_BatchUpdateCategories_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *categoryClient) ListCategories(ctx context.Context, in *ListCategoryRequest, opts ...grpc.CallOption) (*CategoryListResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CategoryListResponse) + err := c.cc.Invoke(ctx, Category_ListCategories_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *categoryClient) CheckAlias(ctx context.Context, in *CheckAliasRequest, opts ...grpc.CallOption) (*CheckAliasResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CheckAliasResponse) + err := c.cc.Invoke(ctx, Category_CheckAlias_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// CategoryServer is the server API for Category service. +// All implementations must embed UnimplementedCategoryServer +// for forward compatibility. +// +// 分类服务 - 分类管理、树形结构操作、批量处理 +type CategoryServer interface { + // 健康检查 + Ping(context.Context, *PingRequest) (*PingResponse, error) + // 分类基础操作 + CreateCategory(context.Context, *CreateCategoryRequest) (*CategoryInfoResponse, error) + UpdateCategory(context.Context, *UpdateCategoryRequest) (*CategoryInfoResponse, error) + DeleteCategory(context.Context, *DeleteCategoryRequest) (*DeleteResponse, error) + GetCategory(context.Context, *GetCategoryRequest) (*CategoryInfoResponse, error) + // 层级结构操作 + GetChildren(context.Context, *GetChildrenRequest) (*CategoryListResponse, error) + GetTree(context.Context, *GetTreeRequest) (*CategoryTreeResponse, error) + MoveCategory(context.Context, *MoveCategoryRequest) (*CategoryInfoResponse, error) + GetAncestorPath(context.Context, *GetAncestorPathRequest) (*CategoryPathResponse, error) + // 批量操作 + BatchCreateCategories(context.Context, *BatchCreateRequest) (*BatchCreateResponse, error) + BatchUpdateCategories(context.Context, *BatchUpdateRequest) (*BatchUpdateResponse, error) + // 查询过滤 + ListCategories(context.Context, *ListCategoryRequest) (*CategoryListResponse, error) + CheckAlias(context.Context, *CheckAliasRequest) (*CheckAliasResponse, error) + mustEmbedUnimplementedCategoryServer() +} + +// UnimplementedCategoryServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedCategoryServer struct{} + +func (UnimplementedCategoryServer) Ping(context.Context, *PingRequest) (*PingResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented") +} +func (UnimplementedCategoryServer) CreateCategory(context.Context, *CreateCategoryRequest) (*CategoryInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateCategory not implemented") +} +func (UnimplementedCategoryServer) UpdateCategory(context.Context, *UpdateCategoryRequest) (*CategoryInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateCategory not implemented") +} +func (UnimplementedCategoryServer) DeleteCategory(context.Context, *DeleteCategoryRequest) (*DeleteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteCategory not implemented") +} +func (UnimplementedCategoryServer) GetCategory(context.Context, *GetCategoryRequest) (*CategoryInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetCategory not implemented") +} +func (UnimplementedCategoryServer) GetChildren(context.Context, *GetChildrenRequest) (*CategoryListResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetChildren not implemented") +} +func (UnimplementedCategoryServer) GetTree(context.Context, *GetTreeRequest) (*CategoryTreeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTree not implemented") +} +func (UnimplementedCategoryServer) MoveCategory(context.Context, *MoveCategoryRequest) (*CategoryInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method MoveCategory not implemented") +} +func (UnimplementedCategoryServer) GetAncestorPath(context.Context, *GetAncestorPathRequest) (*CategoryPathResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAncestorPath not implemented") +} +func (UnimplementedCategoryServer) BatchCreateCategories(context.Context, *BatchCreateRequest) (*BatchCreateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method BatchCreateCategories not implemented") +} +func (UnimplementedCategoryServer) BatchUpdateCategories(context.Context, *BatchUpdateRequest) (*BatchUpdateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method BatchUpdateCategories not implemented") +} +func (UnimplementedCategoryServer) ListCategories(context.Context, *ListCategoryRequest) (*CategoryListResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListCategories not implemented") +} +func (UnimplementedCategoryServer) CheckAlias(context.Context, *CheckAliasRequest) (*CheckAliasResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CheckAlias not implemented") +} +func (UnimplementedCategoryServer) mustEmbedUnimplementedCategoryServer() {} +func (UnimplementedCategoryServer) testEmbeddedByValue() {} + +// UnsafeCategoryServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to CategoryServer will +// result in compilation errors. +type UnsafeCategoryServer interface { + mustEmbedUnimplementedCategoryServer() +} + +func RegisterCategoryServer(s grpc.ServiceRegistrar, srv CategoryServer) { + // If the following call pancis, it indicates UnimplementedCategoryServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Category_ServiceDesc, srv) +} + +func _Category_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PingRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).Ping(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_Ping_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).Ping(ctx, req.(*PingRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Category_CreateCategory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateCategoryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).CreateCategory(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_CreateCategory_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).CreateCategory(ctx, req.(*CreateCategoryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Category_UpdateCategory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateCategoryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).UpdateCategory(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_UpdateCategory_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).UpdateCategory(ctx, req.(*UpdateCategoryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Category_DeleteCategory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteCategoryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).DeleteCategory(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_DeleteCategory_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).DeleteCategory(ctx, req.(*DeleteCategoryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Category_GetCategory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetCategoryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).GetCategory(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_GetCategory_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).GetCategory(ctx, req.(*GetCategoryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Category_GetChildren_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetChildrenRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).GetChildren(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_GetChildren_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).GetChildren(ctx, req.(*GetChildrenRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Category_GetTree_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTreeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).GetTree(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_GetTree_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).GetTree(ctx, req.(*GetTreeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Category_MoveCategory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MoveCategoryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).MoveCategory(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_MoveCategory_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).MoveCategory(ctx, req.(*MoveCategoryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Category_GetAncestorPath_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAncestorPathRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).GetAncestorPath(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_GetAncestorPath_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).GetAncestorPath(ctx, req.(*GetAncestorPathRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Category_BatchCreateCategories_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BatchCreateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).BatchCreateCategories(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_BatchCreateCategories_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).BatchCreateCategories(ctx, req.(*BatchCreateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Category_BatchUpdateCategories_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BatchUpdateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).BatchUpdateCategories(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_BatchUpdateCategories_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).BatchUpdateCategories(ctx, req.(*BatchUpdateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Category_ListCategories_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListCategoryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).ListCategories(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_ListCategories_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).ListCategories(ctx, req.(*ListCategoryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Category_CheckAlias_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CheckAliasRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CategoryServer).CheckAlias(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Category_CheckAlias_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CategoryServer).CheckAlias(ctx, req.(*CheckAliasRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Category_ServiceDesc is the grpc.ServiceDesc for Category service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Category_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "category.Category", + HandlerType: (*CategoryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Ping", + Handler: _Category_Ping_Handler, + }, + { + MethodName: "CreateCategory", + Handler: _Category_CreateCategory_Handler, + }, + { + MethodName: "UpdateCategory", + Handler: _Category_UpdateCategory_Handler, + }, + { + MethodName: "DeleteCategory", + Handler: _Category_DeleteCategory_Handler, + }, + { + MethodName: "GetCategory", + Handler: _Category_GetCategory_Handler, + }, + { + MethodName: "GetChildren", + Handler: _Category_GetChildren_Handler, + }, + { + MethodName: "GetTree", + Handler: _Category_GetTree_Handler, + }, + { + MethodName: "MoveCategory", + Handler: _Category_MoveCategory_Handler, + }, + { + MethodName: "GetAncestorPath", + Handler: _Category_GetAncestorPath_Handler, + }, + { + MethodName: "BatchCreateCategories", + Handler: _Category_BatchCreateCategories_Handler, + }, + { + MethodName: "BatchUpdateCategories", + Handler: _Category_BatchUpdateCategories_Handler, + }, + { + MethodName: "ListCategories", + Handler: _Category_ListCategories_Handler, + }, + { + MethodName: "CheckAlias", + Handler: _Category_CheckAlias_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "rpc/category.proto", +} diff --git a/category/categoryclient/category.go b/category/categoryclient/category.go new file mode 100644 index 0000000..86a89d4 --- /dev/null +++ b/category/categoryclient/category.go @@ -0,0 +1,142 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.8.3 +// Source: category.proto + +package categoryclient + +import ( + "context" + + "godemo/category/category" + + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" +) + +type ( + BatchCreateRequest = category.BatchCreateRequest + BatchCreateResponse = category.BatchCreateResponse + BatchUpdateRequest = category.BatchUpdateRequest + BatchUpdateResponse = category.BatchUpdateResponse + CategoryInfo = category.CategoryInfo + CategoryInfoResponse = category.CategoryInfoResponse + CategoryListResponse = category.CategoryListResponse + CategoryPathResponse = category.CategoryPathResponse + CategoryTreeResponse = category.CategoryTreeResponse + CategoryTreeResponse_TreeNode = category.CategoryTreeResponse_TreeNode + CheckAliasRequest = category.CheckAliasRequest + CheckAliasResponse = category.CheckAliasResponse + CreateCategoryRequest = category.CreateCategoryRequest + DeleteCategoryRequest = category.DeleteCategoryRequest + DeleteResponse = category.DeleteResponse + GetAncestorPathRequest = category.GetAncestorPathRequest + GetCategoryRequest = category.GetCategoryRequest + GetChildrenRequest = category.GetChildrenRequest + GetTreeRequest = category.GetTreeRequest + ListCategoryRequest = category.ListCategoryRequest + MoveCategoryRequest = category.MoveCategoryRequest + PingRequest = category.PingRequest + PingResponse = category.PingResponse + UpdateCategoryRequest = category.UpdateCategoryRequest + + Category interface { + // 健康检查 + Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) + // 分类基础操作 + CreateCategory(ctx context.Context, in *CreateCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) + UpdateCategory(ctx context.Context, in *UpdateCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) + DeleteCategory(ctx context.Context, in *DeleteCategoryRequest, opts ...grpc.CallOption) (*DeleteResponse, error) + GetCategory(ctx context.Context, in *GetCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) + // 层级结构操作 + GetChildren(ctx context.Context, in *GetChildrenRequest, opts ...grpc.CallOption) (*CategoryListResponse, error) + GetTree(ctx context.Context, in *GetTreeRequest, opts ...grpc.CallOption) (*CategoryTreeResponse, error) + MoveCategory(ctx context.Context, in *MoveCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) + GetAncestorPath(ctx context.Context, in *GetAncestorPathRequest, opts ...grpc.CallOption) (*CategoryPathResponse, error) + // 批量操作 + BatchCreateCategories(ctx context.Context, in *BatchCreateRequest, opts ...grpc.CallOption) (*BatchCreateResponse, error) + BatchUpdateCategories(ctx context.Context, in *BatchUpdateRequest, opts ...grpc.CallOption) (*BatchUpdateResponse, error) + // 查询过滤 + ListCategories(ctx context.Context, in *ListCategoryRequest, opts ...grpc.CallOption) (*CategoryListResponse, error) + CheckAlias(ctx context.Context, in *CheckAliasRequest, opts ...grpc.CallOption) (*CheckAliasResponse, error) + } + + defaultCategory struct { + cli zrpc.Client + } +) + +func NewCategory(cli zrpc.Client) Category { + return &defaultCategory{ + cli: cli, + } +} + +// 健康检查 +func (m *defaultCategory) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.Ping(ctx, in, opts...) +} + +// 分类基础操作 +func (m *defaultCategory) CreateCategory(ctx context.Context, in *CreateCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.CreateCategory(ctx, in, opts...) +} + +func (m *defaultCategory) UpdateCategory(ctx context.Context, in *UpdateCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.UpdateCategory(ctx, in, opts...) +} + +func (m *defaultCategory) DeleteCategory(ctx context.Context, in *DeleteCategoryRequest, opts ...grpc.CallOption) (*DeleteResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.DeleteCategory(ctx, in, opts...) +} + +func (m *defaultCategory) GetCategory(ctx context.Context, in *GetCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.GetCategory(ctx, in, opts...) +} + +// 层级结构操作 +func (m *defaultCategory) GetChildren(ctx context.Context, in *GetChildrenRequest, opts ...grpc.CallOption) (*CategoryListResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.GetChildren(ctx, in, opts...) +} + +func (m *defaultCategory) GetTree(ctx context.Context, in *GetTreeRequest, opts ...grpc.CallOption) (*CategoryTreeResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.GetTree(ctx, in, opts...) +} + +func (m *defaultCategory) MoveCategory(ctx context.Context, in *MoveCategoryRequest, opts ...grpc.CallOption) (*CategoryInfoResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.MoveCategory(ctx, in, opts...) +} + +func (m *defaultCategory) GetAncestorPath(ctx context.Context, in *GetAncestorPathRequest, opts ...grpc.CallOption) (*CategoryPathResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.GetAncestorPath(ctx, in, opts...) +} + +// 批量操作 +func (m *defaultCategory) BatchCreateCategories(ctx context.Context, in *BatchCreateRequest, opts ...grpc.CallOption) (*BatchCreateResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.BatchCreateCategories(ctx, in, opts...) +} + +func (m *defaultCategory) BatchUpdateCategories(ctx context.Context, in *BatchUpdateRequest, opts ...grpc.CallOption) (*BatchUpdateResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.BatchUpdateCategories(ctx, in, opts...) +} + +// 查询过滤 +func (m *defaultCategory) ListCategories(ctx context.Context, in *ListCategoryRequest, opts ...grpc.CallOption) (*CategoryListResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.ListCategories(ctx, in, opts...) +} + +func (m *defaultCategory) CheckAlias(ctx context.Context, in *CheckAliasRequest, opts ...grpc.CallOption) (*CheckAliasResponse, error) { + client := category.NewCategoryClient(m.cli.Conn()) + return client.CheckAlias(ctx, in, opts...) +} diff --git a/category/etc/category.yaml b/category/etc/category.yaml new file mode 100644 index 0000000..2ffc926 --- /dev/null +++ b/category/etc/category.yaml @@ -0,0 +1,13 @@ +Name: category.rpc +ListenOn: 0.0.0.0:60300 +Mode: dev +Etcd: + Hosts: + - 127.0.0.1:2379 + Key: category.rpc + +DB: + DataSource: postgres://postgres:postgres@localhost:5432/godemo?sslmode=disable + MaxOpenConns: 100 + MaxIdleConns: 20 + ConnMaxLifetime: 3600 \ No newline at end of file diff --git a/category/internal/config/config.go b/category/internal/config/config.go new file mode 100644 index 0000000..17ee257 --- /dev/null +++ b/category/internal/config/config.go @@ -0,0 +1,13 @@ +package config + +import "github.com/zeromicro/go-zero/zrpc" + +type Config struct { + zrpc.RpcServerConf + DB struct { + DataSource string + MaxOpenConns int + MaxIdleConns int + ConnMaxLifetime int + } +} diff --git a/category/internal/logic/batchcreatecategorieslogic.go b/category/internal/logic/batchcreatecategorieslogic.go new file mode 100644 index 0000000..8f3089f --- /dev/null +++ b/category/internal/logic/batchcreatecategorieslogic.go @@ -0,0 +1,31 @@ +package logic + +import ( + "context" + + "godemo/category/category" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type BatchCreateCategoriesLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewBatchCreateCategoriesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchCreateCategoriesLogic { + return &BatchCreateCategoriesLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 批量操作 +func (l *BatchCreateCategoriesLogic) BatchCreateCategories(in *category.BatchCreateRequest) (*category.BatchCreateResponse, error) { + // todo: add your logic here and delete this line + + return &category.BatchCreateResponse{}, nil +} diff --git a/category/internal/logic/batchupdatecategorieslogic.go b/category/internal/logic/batchupdatecategorieslogic.go new file mode 100644 index 0000000..31d3c0e --- /dev/null +++ b/category/internal/logic/batchupdatecategorieslogic.go @@ -0,0 +1,30 @@ +package logic + +import ( + "context" + + "godemo/category/category" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type BatchUpdateCategoriesLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewBatchUpdateCategoriesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchUpdateCategoriesLogic { + return &BatchUpdateCategoriesLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *BatchUpdateCategoriesLogic) BatchUpdateCategories(in *category.BatchUpdateRequest) (*category.BatchUpdateResponse, error) { + // todo: add your logic here and delete this line + + return &category.BatchUpdateResponse{}, nil +} diff --git a/category/internal/logic/checkaliaslogic.go b/category/internal/logic/checkaliaslogic.go new file mode 100644 index 0000000..4f5cf8b --- /dev/null +++ b/category/internal/logic/checkaliaslogic.go @@ -0,0 +1,30 @@ +package logic + +import ( + "context" + + "godemo/category/category" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type CheckAliasLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewCheckAliasLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CheckAliasLogic { + return &CheckAliasLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *CheckAliasLogic) CheckAlias(in *category.CheckAliasRequest) (*category.CheckAliasResponse, error) { + // todo: add your logic here and delete this line + + return &category.CheckAliasResponse{}, nil +} diff --git a/category/internal/logic/createcategorylogic.go b/category/internal/logic/createcategorylogic.go new file mode 100644 index 0000000..9cefcc0 --- /dev/null +++ b/category/internal/logic/createcategorylogic.go @@ -0,0 +1,118 @@ +package logic + +import ( + "context" + "database/sql" + "errors" + "time" + + "godemo/category/category" + "godemo/category/internal/model" + "godemo/category/internal/svc" + + "github.com/google/uuid" + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type CreateCategoryLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewCreateCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateCategoryLogic { + return &CreateCategoryLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *CreateCategoryLogic) CreateCategory(in *category.CreateCategoryRequest) (*category.CategoryInfoResponse, error) { + // 参数校验 + if in.SystemId == "" || in.Name == "" { + return nil, status.Error(codes.InvalidArgument, "system_id 和 name 不能为空") + } + + // 检查唯一性 + exists, err := l.checkCategoryExists(in) + if err != nil { + logx.Error("唯一性检查失败: ", err) + return nil, status.Error(codes.Internal, "内部错误") + } + if exists { + return nil, status.Error(codes.AlreadyExists, "分类已存在") + } + + // 构建模型 + newCategory := &model.Categories{ + Id: uuid.New().String(), + SystemId: in.SystemId, + Name: in.Name, + Alias: toNullString(in.Alias), + ParentId: toNullString(in.ParentId), + Description: toNullString(in.Description), + CreatedAt: time.Now(), + UpdatedAt: sql.NullTime{Time: time.Now(), Valid: true}, + } + + // 插入数据库 + if _, err := l.svcCtx.CategoryModel.Insert(l.ctx, newCategory); err != nil { + logx.Error("插入失败: ", err) + return nil, status.Error(codes.Internal, "创建分类失败") + } + + // 返回响应 + return &category.CategoryInfoResponse{ + Category: &category.CategoryInfo{ + Id: newCategory.Id, + SystemId: newCategory.SystemId, + Name: newCategory.Name, + Alias: in.Alias, + ParentId: in.ParentId, + Description: in.Description, + CreatedAt: newCategory.CreatedAt.Unix(), + UpdatedAt: newCategory.UpdatedAt.Time.Unix(), + }, + }, nil +} + +// 空字符串转换为 sql.NullString +func toNullString(s string) sql.NullString { + return sql.NullString{String: s, Valid: s != ""} +} + +// 唯一性检查逻辑 +func (l *CreateCategoryLogic) checkCategoryExists(in *category.CreateCategoryRequest) (bool, error) { + // 检查名称唯一性 + _, err := l.svcCtx.CategoryModel.FindBySystemParentName( + l.ctx, + in.SystemId, + in.ParentId, + in.Name, + ) + if err == nil { + return true, nil + } else if !errors.Is(err, model.ErrNotFound) { + return false, err + } + + // 检查别名唯一性(如果提供了别名) + if in.Alias != "" { + _, err := l.svcCtx.CategoryModel.FindBySystemParentAlias( + l.ctx, + in.SystemId, + in.ParentId, + in.Alias, + ) + if err == nil { + return true, nil + } else if !errors.Is(err, model.ErrNotFound) { + return false, err + } + } + + return false, nil +} diff --git a/category/internal/logic/deletecategorylogic.go b/category/internal/logic/deletecategorylogic.go new file mode 100644 index 0000000..9941f9a --- /dev/null +++ b/category/internal/logic/deletecategorylogic.go @@ -0,0 +1,91 @@ +package logic + +import ( + "context" + "errors" + "fmt" + + "godemo/category/category" + "godemo/category/internal/model" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type DeleteCategoryLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewDeleteCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteCategoryLogic { + return &DeleteCategoryLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *DeleteCategoryLogic) DeleteCategory(in *category.DeleteCategoryRequest) (*category.DeleteResponse, error) { + // 1. 参数校验 + if in.Id == "" { + return nil, status.Error(codes.InvalidArgument, "分类ID不能为空") + } + + // 2. 检查分类是否存在 + _, err := l.svcCtx.CategoryModel.FindOne(l.ctx, in.Id) + if err != nil { + if errors.Is(err, model.ErrNotFound) { + return nil, status.Error(codes.NotFound, "分类不存在") + } + l.Logger.Errorf("查询分类失败: %v", err) + return nil, status.Error(codes.Internal, "内部错误") + } + + // 3. 开启事务执行删除 + err = l.svcCtx.CategoryModel.Transact(l.ctx, func(ctx context.Context, session sqlx.Session) error { + // 3.1 处理子分类(根据外键约束自动级联删除或设为NULL) + if err := l.handleChildren(ctx, session, in.Id); err != nil { + return err + } + + // 3.2 删除主分类 + if err := l.svcCtx.CategoryModel.WithSession(session).Delete(ctx, in.Id); err != nil { + return fmt.Errorf("删除分类失败: %w", err) + } + + return nil + }) + + if err != nil { + l.Logger.Errorf("删除分类事务失败: %v", err) + return nil, status.Error(codes.Internal, "删除分类失败") + } + + return &category.DeleteResponse{ + Success: true, + }, nil +} + +// handleChildren 处理子分类(根据外键约束配置决定行为) +func (l *DeleteCategoryLogic) handleChildren(ctx context.Context, session sqlx.Session, parentID string) error { + // 如果外键是 ON DELETE SET NULL,需要显式更新子分类 + if l.needUpdateChildren() { + query := "UPDATE categories SET parent_id = NULL WHERE parent_id = $1" + if _, err := session.ExecCtx(ctx, query, parentID); err != nil { + return fmt.Errorf("更新子分类失败: %w", err) + } + } + // 如果是 ON DELETE CASCADE 则无需额外处理 + return nil +} + +// needUpdateChildren 根据配置决定是否需要更新子分类 +func (l *DeleteCategoryLogic) needUpdateChildren() bool { + // 这里根据实际数据库外键约束配置返回 + // 可以在 config 中添加配置项控制行为 + return false // 默认假设是 ON DELETE CASCADE +} diff --git a/category/internal/logic/getancestorpathlogic.go b/category/internal/logic/getancestorpathlogic.go new file mode 100644 index 0000000..42d9f86 --- /dev/null +++ b/category/internal/logic/getancestorpathlogic.go @@ -0,0 +1,30 @@ +package logic + +import ( + "context" + + "godemo/category/category" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetAncestorPathLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGetAncestorPathLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAncestorPathLogic { + return &GetAncestorPathLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *GetAncestorPathLogic) GetAncestorPath(in *category.GetAncestorPathRequest) (*category.CategoryPathResponse, error) { + // todo: add your logic here and delete this line + + return &category.CategoryPathResponse{}, nil +} diff --git a/category/internal/logic/getcategorylogic.go b/category/internal/logic/getcategorylogic.go new file mode 100644 index 0000000..98b7092 --- /dev/null +++ b/category/internal/logic/getcategorylogic.go @@ -0,0 +1,85 @@ +package logic + +import ( + "context" + "errors" + + "godemo/category/category" + "godemo/category/internal/model" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type GetCategoryLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGetCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetCategoryLogic { + return &GetCategoryLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *GetCategoryLogic) GetCategory(in *category.GetCategoryRequest) (*category.CategoryInfoResponse, error) { + // 1. 参数校验 + if in.Id == "" { + return nil, status.Error(codes.InvalidArgument, "分类ID不能为空") + } + + // 2. 查询数据库 + categoryData, err := l.svcCtx.CategoryModel.FindOne(l.ctx, in.Id) + if err != nil { + if errors.Is(err, model.ErrNotFound) { + l.Logger.Errorf("分类不存在, ID: %s", in.Id) + return nil, status.Error(codes.NotFound, "分类不存在") + } + l.Logger.Errorf("数据库查询失败: %v", err) + return nil, status.Error(codes.Internal, "内部错误") + } + + // 3. 转换响应格式 + return l.convertToResponse(categoryData), nil +} + +func (l *GetCategoryLogic) convertToResponse(c *model.Categories) *category.CategoryInfoResponse { + // 处理可能为空的字段 + var alias, parentID, description string + + if c.Alias.Valid { + alias = c.Alias.String + } + if c.ParentId.Valid { + parentID = c.ParentId.String + } + if c.Description.Valid { + description = c.Description.String + } + + // 处理时间戳 + var updatedAt int64 + if c.UpdatedAt.Valid { + updatedAt = c.UpdatedAt.Time.Unix() + } else { + updatedAt = c.CreatedAt.Unix() // 如果未更新过,使用创建时间 + } + + return &category.CategoryInfoResponse{ + Category: &category.CategoryInfo{ + Id: c.Id, + SystemId: c.SystemId, + Name: c.Name, + Alias: alias, + ParentId: parentID, + Description: description, + CreatedAt: c.CreatedAt.Unix(), + UpdatedAt: updatedAt, + }, + } +} diff --git a/category/internal/logic/getchildrenlogic.go b/category/internal/logic/getchildrenlogic.go new file mode 100644 index 0000000..ca3e834 --- /dev/null +++ b/category/internal/logic/getchildrenlogic.go @@ -0,0 +1,31 @@ +package logic + +import ( + "context" + + "godemo/category/category" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetChildrenLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGetChildrenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetChildrenLogic { + return &GetChildrenLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 层级结构操作 +func (l *GetChildrenLogic) GetChildren(in *category.GetChildrenRequest) (*category.CategoryListResponse, error) { + // todo: add your logic here and delete this line + + return &category.CategoryListResponse{}, nil +} diff --git a/category/internal/logic/gettreelogic.go b/category/internal/logic/gettreelogic.go new file mode 100644 index 0000000..cfd2dd4 --- /dev/null +++ b/category/internal/logic/gettreelogic.go @@ -0,0 +1,30 @@ +package logic + +import ( + "context" + + "godemo/category/category" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetTreeLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGetTreeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetTreeLogic { + return &GetTreeLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *GetTreeLogic) GetTree(in *category.GetTreeRequest) (*category.CategoryTreeResponse, error) { + // todo: add your logic here and delete this line + + return &category.CategoryTreeResponse{}, nil +} diff --git a/category/internal/logic/listcategorieslogic.go b/category/internal/logic/listcategorieslogic.go new file mode 100644 index 0000000..b4b6f7e --- /dev/null +++ b/category/internal/logic/listcategorieslogic.go @@ -0,0 +1,31 @@ +package logic + +import ( + "context" + + "godemo/category/category" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type ListCategoriesLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewListCategoriesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListCategoriesLogic { + return &ListCategoriesLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 查询过滤 +func (l *ListCategoriesLogic) ListCategories(in *category.ListCategoryRequest) (*category.CategoryListResponse, error) { + // todo: add your logic here and delete this line + + return &category.CategoryListResponse{}, nil +} diff --git a/category/internal/logic/movecategorylogic.go b/category/internal/logic/movecategorylogic.go new file mode 100644 index 0000000..453c7b0 --- /dev/null +++ b/category/internal/logic/movecategorylogic.go @@ -0,0 +1,30 @@ +package logic + +import ( + "context" + + "godemo/category/category" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type MoveCategoryLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewMoveCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MoveCategoryLogic { + return &MoveCategoryLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *MoveCategoryLogic) MoveCategory(in *category.MoveCategoryRequest) (*category.CategoryInfoResponse, error) { + // todo: add your logic here and delete this line + + return &category.CategoryInfoResponse{}, nil +} diff --git a/category/internal/logic/pinglogic.go b/category/internal/logic/pinglogic.go new file mode 100644 index 0000000..9f3c581 --- /dev/null +++ b/category/internal/logic/pinglogic.go @@ -0,0 +1,31 @@ +package logic + +import ( + "context" + + "godemo/category/category" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type PingLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewPingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PingLogic { + return &PingLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 健康检查 +func (l *PingLogic) Ping(in *category.PingRequest) (*category.PingResponse, error) { + // todo: add your logic here and delete this line + + return &category.PingResponse{}, nil +} diff --git a/category/internal/logic/updatecategorylogic.go b/category/internal/logic/updatecategorylogic.go new file mode 100644 index 0000000..8371d64 --- /dev/null +++ b/category/internal/logic/updatecategorylogic.go @@ -0,0 +1,218 @@ +package logic + +import ( + "context" + "database/sql" + "errors" + "fmt" + "time" + + "godemo/category/category" + "godemo/category/internal/model" + "godemo/category/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type UpdateCategoryLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewUpdateCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateCategoryLogic { + return &UpdateCategoryLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *UpdateCategoryLogic) UpdateCategory(in *category.UpdateCategoryRequest) (*category.CategoryInfoResponse, error) { + // 1. 参数校验 + if err := l.validateRequest(in); err != nil { + return nil, err + } + + // 2. 获取现有分类 + existing, err := l.svcCtx.CategoryModel.FindOne(l.ctx, in.Id) + if err != nil { + return l.handleFindError(err, in.Id) + } + + // 3. 检查更新后的名称/别名是否冲突 + if err := l.checkUniqueness(in, existing); err != nil { + return nil, err + } + + // 4. 构建更新模型 + updatedCategory := l.buildUpdatedModel(in, existing) + + // 5. 事务更新 + if err := l.updateWithTransaction(updatedCategory); err != nil { + return nil, err + } + + // 6. 清理缓存 + + // 7. 返回更新后的数据 + return l.buildResponse(updatedCategory), nil +} + +// 参数校验 +func (l *UpdateCategoryLogic) validateRequest(in *category.UpdateCategoryRequest) error { + if in.Id == "" { + return status.Error(codes.InvalidArgument, "分类ID不能为空") + } + if in.Name == "" && in.Alias == "" && in.ParentId == "" && in.Description == "" { + return status.Error(codes.InvalidArgument, "至少需要提供一个更新字段") + } + return nil +} + +// 处理查询错误 +func (l *UpdateCategoryLogic) handleFindError(err error, id string) (*category.CategoryInfoResponse, error) { + if errors.Is(err, model.ErrNotFound) { + l.Logger.Errorf("分类不存在, ID: %s", id) + return nil, status.Error(codes.NotFound, "分类不存在") + } + l.Logger.Errorf("查询分类失败: %v", err) + return nil, status.Error(codes.Internal, "内部错误") +} + +// 检查名称/别名唯一性 +func (l *UpdateCategoryLogic) checkUniqueness(in *category.UpdateCategoryRequest, existing *model.Categories) error { + // 如果名称有修改,检查新名称是否冲突 + if in.Name != "" && in.Name != existing.Name { + parentID := existing.ParentId + if in.ParentId != "" { + parentID = sql.NullString{String: in.ParentId, Valid: true} + } + + _, err := l.svcCtx.CategoryModel.FindBySystemParentName( + l.ctx, + existing.SystemId, + parentID.String, + in.Name, + ) + if err == nil { + return status.Error(codes.AlreadyExists, "分类名称已存在") + } else if !errors.Is(err, model.ErrNotFound) { + l.Logger.Errorf("名称唯一性检查失败: %v", err) + return status.Error(codes.Internal, "内部错误") + } + } + + // 如果别名有修改,检查新别名是否冲突 + if in.Alias != "" && in.Alias != existing.Alias.String { + parentID := existing.ParentId + if in.ParentId != "" { + parentID = sql.NullString{String: in.ParentId, Valid: true} + } + + _, err := l.svcCtx.CategoryModel.FindBySystemParentAlias( + l.ctx, + existing.SystemId, + parentID.String, + in.Alias, + ) + if err == nil { + return status.Error(codes.AlreadyExists, "分类别名已存在") + } else if !errors.Is(err, model.ErrNotFound) { + l.Logger.Errorf("别名唯一性检查失败: %v", err) + return status.Error(codes.Internal, "内部错误") + } + } + + return nil +} + +// 构建更新后的模型 +func (l *UpdateCategoryLogic) buildUpdatedModel(in *category.UpdateCategoryRequest, existing *model.Categories) *model.Categories { + updated := *existing // 复制原有值 + + // 只更新提供的字段 + if in.Name != "" { + updated.Name = in.Name + } + + if in.Alias != "" { + updated.Alias = sql.NullString{String: in.Alias, Valid: true} + } else if in.Alias == "" && existing.Alias.Valid { + // 明确传递空字符串表示清空别名 + updated.Alias = sql.NullString{Valid: false} + } + + if in.ParentId != "" { + if in.ParentId == "NULL" { // 特殊值表示设为NULL + updated.ParentId = sql.NullString{Valid: false} + } else { + updated.ParentId = sql.NullString{String: in.ParentId, Valid: true} + } + } + + if in.Description != "" { + updated.Description = sql.NullString{String: in.Description, Valid: true} + } else if in.Description == "" && existing.Description.Valid { + // 明确传递空字符串表示清空描述 + updated.Description = sql.NullString{Valid: false} + } + + updated.UpdatedAt = sql.NullTime{Time: time.Now(), Valid: true} + return &updated +} + +// 事务更新 +func (l *UpdateCategoryLogic) updateWithTransaction(updated *model.Categories) error { + return l.svcCtx.CategoryModel.Transact(l.ctx, func(ctx context.Context, session sqlx.Session) error { + // 检查父分类是否存在(如果修改了父分类) + if updated.ParentId.Valid && updated.ParentId.String != "" { + if _, err := l.svcCtx.CategoryModel.WithSession(session).FindOne(ctx, updated.ParentId.String); err != nil { + if errors.Is(err, model.ErrNotFound) { + return status.Error(codes.InvalidArgument, "指定的父分类不存在") + } + return fmt.Errorf("查询父分类失败: %w", err) + } + } + + // 执行更新 + if err := l.svcCtx.CategoryModel.WithSession(session).Update(ctx, updated); err != nil { + return fmt.Errorf("更新分类失败: %w", err) + } + + return nil + }) +} + +// 构建响应 +func (l *UpdateCategoryLogic) buildResponse(c *model.Categories) *category.CategoryInfoResponse { + resp := &category.CategoryInfoResponse{ + Category: &category.CategoryInfo{ + Id: c.Id, + SystemId: c.SystemId, + Name: c.Name, + CreatedAt: c.CreatedAt.Unix(), + }, + } + + // 处理可能为空的字段 + if c.Alias.Valid { + resp.Category.Alias = c.Alias.String + } + if c.ParentId.Valid { + resp.Category.ParentId = c.ParentId.String + } + if c.Description.Valid { + resp.Category.Description = c.Description.String + } + if c.UpdatedAt.Valid { + resp.Category.UpdatedAt = c.UpdatedAt.Time.Unix() + } else { + resp.Category.UpdatedAt = c.CreatedAt.Unix() + } + + return resp +} diff --git a/category/internal/model/categoriesmodel.go b/category/internal/model/categoriesmodel.go new file mode 100644 index 0000000..5a64e25 --- /dev/null +++ b/category/internal/model/categoriesmodel.go @@ -0,0 +1,74 @@ +package model + +import ( + "context" + + "github.com/zeromicro/go-zero/core/stores/sqlx" +) + +var _ CategoriesModel = (*customCategoriesModel)(nil) + +type ( + // CategoriesModel is an interface to be customized, add more methods here, + // and implement the added methods in customCategoriesModel. + CategoriesModel interface { + categoriesModel + WithSession(session sqlx.Session) CategoriesModel + Transact(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error + FindBySystemParentName(ctx context.Context, systemID string, parentID string, name string) (*Categories, error) + FindBySystemParentAlias(ctx context.Context, systemID string, parentID string, alias string) (*Categories, error) + } + + customCategoriesModel struct { + *defaultCategoriesModel + } +) + +// NewCategoriesModel returns a model for the database table. +func NewCategoriesModel(conn sqlx.SqlConn) CategoriesModel { + return &customCategoriesModel{ + defaultCategoriesModel: newCategoriesModel(conn), + } +} + +func (m *customCategoriesModel) WithSession(session sqlx.Session) CategoriesModel { + return NewCategoriesModel(sqlx.NewSqlConnFromSession(session)) +} + +func (m *customCategoriesModel) Transact(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error { + return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error { + return fn(ctx, session) + }) +} + +// 根据 system_id + parent_id + name 查询 +func (m *customCategoriesModel) FindBySystemParentName(ctx context.Context, systemID string, parentID string, name string) (*Categories, error) { + query := ` + SELECT * FROM categories + WHERE system_id = $1 + AND COALESCE(parent_id, '') = COALESCE($2, '') + AND name = $3 + ` + var resp Categories + err := m.conn.QueryRowCtx(ctx, &resp, query, systemID, parentID, name) + if err != nil { + return nil, err + } + return &resp, nil +} + +// 根据 system_id + parent_id + alias 查询 +func (m *customCategoriesModel) FindBySystemParentAlias(ctx context.Context, systemID string, parentID string, alias string) (*Categories, error) { + query := ` + SELECT * FROM categories + WHERE system_id = $1 + AND COALESCE(parent_id, '') = COALESCE($2, '') + AND alias = $3 + ` + var resp Categories + err := m.conn.QueryRowCtx(ctx, &resp, query, systemID, parentID, alias) + if err != nil { + return nil, err + } + return &resp, nil +} diff --git a/category/internal/model/categoriesmodel_gen.go b/category/internal/model/categoriesmodel_gen.go new file mode 100644 index 0000000..fed4729 --- /dev/null +++ b/category/internal/model/categoriesmodel_gen.go @@ -0,0 +1,122 @@ +// Code generated by goctl. DO NOT EDIT. +// versions: +// goctl version: 1.8.3 + +package model + +import ( + "context" + "database/sql" + "fmt" + "strings" + "time" + + "github.com/zeromicro/go-zero/core/stores/builder" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "github.com/zeromicro/go-zero/core/stringx" +) + +var ( + categoriesFieldNames = builder.RawFieldNames(&Categories{}, true) + categoriesRows = strings.Join(categoriesFieldNames, ",") + categoriesRowsExpectAutoSet = strings.Join(stringx.Remove(categoriesFieldNames, "create_at", "create_time", "created_at", "update_at", "update_time", "updated_at"), ",") + categoriesRowsWithPlaceHolder = builder.PostgreSqlJoin(stringx.Remove(categoriesFieldNames, "id", "create_at", "create_time", "created_at", "update_at", "update_time", "updated_at")) +) + +type ( + categoriesModel interface { + Insert(ctx context.Context, data *Categories) (sql.Result, error) + FindOne(ctx context.Context, id string) (*Categories, error) + FindOneBySystemIdParentIdAlias(ctx context.Context, systemId string, parentId sql.NullString, alias sql.NullString) (*Categories, error) + FindOneBySystemIdParentIdName(ctx context.Context, systemId string, parentId sql.NullString, name string) (*Categories, error) + Update(ctx context.Context, data *Categories) error + Delete(ctx context.Context, id string) error + } + + defaultCategoriesModel struct { + conn sqlx.SqlConn + table string + } + + Categories struct { + Id string `db:"id"` + SystemId string `db:"system_id"` + Name string `db:"name"` + Alias sql.NullString `db:"alias"` + ParentId sql.NullString `db:"parent_id"` + Description sql.NullString `db:"description"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt sql.NullTime `db:"updated_at"` + } +) + +func newCategoriesModel(conn sqlx.SqlConn) *defaultCategoriesModel { + return &defaultCategoriesModel{ + conn: conn, + table: `"public"."categories"`, + } +} + +func (m *defaultCategoriesModel) Delete(ctx context.Context, id string) error { + query := fmt.Sprintf("delete from %s where id = $1", m.table) + _, err := m.conn.ExecCtx(ctx, query, id) + return err +} + +func (m *defaultCategoriesModel) FindOne(ctx context.Context, id string) (*Categories, error) { + query := fmt.Sprintf("select %s from %s where id = $1 limit 1", categoriesRows, m.table) + var resp Categories + err := m.conn.QueryRowCtx(ctx, &resp, query, id) + switch err { + case nil: + return &resp, nil + case sqlx.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultCategoriesModel) FindOneBySystemIdParentIdAlias(ctx context.Context, systemId string, parentId sql.NullString, alias sql.NullString) (*Categories, error) { + var resp Categories + query := fmt.Sprintf("select %s from %s where system_id = $1 and parent_id = $2 and alias = $3 limit 1", categoriesRows, m.table) + err := m.conn.QueryRowCtx(ctx, &resp, query, systemId, parentId, alias) + switch err { + case nil: + return &resp, nil + case sqlx.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultCategoriesModel) FindOneBySystemIdParentIdName(ctx context.Context, systemId string, parentId sql.NullString, name string) (*Categories, error) { + var resp Categories + query := fmt.Sprintf("select %s from %s where system_id = $1 and parent_id = $2 and name = $3 limit 1", categoriesRows, m.table) + err := m.conn.QueryRowCtx(ctx, &resp, query, systemId, parentId, name) + switch err { + case nil: + return &resp, nil + case sqlx.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultCategoriesModel) Insert(ctx context.Context, data *Categories) (sql.Result, error) { + query := fmt.Sprintf("insert into %s (%s) values ($1, $2, $3, $4, $5, $6)", m.table, categoriesRowsExpectAutoSet) + ret, err := m.conn.ExecCtx(ctx, query, data.Id, data.SystemId, data.Name, data.Alias, data.ParentId, data.Description) + return ret, err +} + +func (m *defaultCategoriesModel) Update(ctx context.Context, newData *Categories) error { + query := fmt.Sprintf("update %s set %s where id = $1", m.table, categoriesRowsWithPlaceHolder) + _, err := m.conn.ExecCtx(ctx, query, newData.Id, newData.SystemId, newData.Name, newData.Alias, newData.ParentId, newData.Description) + return err +} + +func (m *defaultCategoriesModel) tableName() string { + return m.table +} diff --git a/category/internal/model/vars.go b/category/internal/model/vars.go new file mode 100644 index 0000000..69ca814 --- /dev/null +++ b/category/internal/model/vars.go @@ -0,0 +1,5 @@ +package model + +import "github.com/zeromicro/go-zero/core/stores/sqlx" + +var ErrNotFound = sqlx.ErrNotFound diff --git a/category/internal/server/categoryserver.go b/category/internal/server/categoryserver.go new file mode 100644 index 0000000..702b6ec --- /dev/null +++ b/category/internal/server/categoryserver.go @@ -0,0 +1,94 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.8.3 +// Source: category.proto + +package server + +import ( + "context" + + "godemo/category/category" + "godemo/category/internal/logic" + "godemo/category/internal/svc" +) + +type CategoryServer struct { + svcCtx *svc.ServiceContext + category.UnimplementedCategoryServer +} + +func NewCategoryServer(svcCtx *svc.ServiceContext) *CategoryServer { + return &CategoryServer{ + svcCtx: svcCtx, + } +} + +// 健康检查 +func (s *CategoryServer) Ping(ctx context.Context, in *category.PingRequest) (*category.PingResponse, error) { + l := logic.NewPingLogic(ctx, s.svcCtx) + return l.Ping(in) +} + +// 分类基础操作 +func (s *CategoryServer) CreateCategory(ctx context.Context, in *category.CreateCategoryRequest) (*category.CategoryInfoResponse, error) { + l := logic.NewCreateCategoryLogic(ctx, s.svcCtx) + return l.CreateCategory(in) +} + +func (s *CategoryServer) UpdateCategory(ctx context.Context, in *category.UpdateCategoryRequest) (*category.CategoryInfoResponse, error) { + l := logic.NewUpdateCategoryLogic(ctx, s.svcCtx) + return l.UpdateCategory(in) +} + +func (s *CategoryServer) DeleteCategory(ctx context.Context, in *category.DeleteCategoryRequest) (*category.DeleteResponse, error) { + l := logic.NewDeleteCategoryLogic(ctx, s.svcCtx) + return l.DeleteCategory(in) +} + +func (s *CategoryServer) GetCategory(ctx context.Context, in *category.GetCategoryRequest) (*category.CategoryInfoResponse, error) { + l := logic.NewGetCategoryLogic(ctx, s.svcCtx) + return l.GetCategory(in) +} + +// 层级结构操作 +func (s *CategoryServer) GetChildren(ctx context.Context, in *category.GetChildrenRequest) (*category.CategoryListResponse, error) { + l := logic.NewGetChildrenLogic(ctx, s.svcCtx) + return l.GetChildren(in) +} + +func (s *CategoryServer) GetTree(ctx context.Context, in *category.GetTreeRequest) (*category.CategoryTreeResponse, error) { + l := logic.NewGetTreeLogic(ctx, s.svcCtx) + return l.GetTree(in) +} + +func (s *CategoryServer) MoveCategory(ctx context.Context, in *category.MoveCategoryRequest) (*category.CategoryInfoResponse, error) { + l := logic.NewMoveCategoryLogic(ctx, s.svcCtx) + return l.MoveCategory(in) +} + +func (s *CategoryServer) GetAncestorPath(ctx context.Context, in *category.GetAncestorPathRequest) (*category.CategoryPathResponse, error) { + l := logic.NewGetAncestorPathLogic(ctx, s.svcCtx) + return l.GetAncestorPath(in) +} + +// 批量操作 +func (s *CategoryServer) BatchCreateCategories(ctx context.Context, in *category.BatchCreateRequest) (*category.BatchCreateResponse, error) { + l := logic.NewBatchCreateCategoriesLogic(ctx, s.svcCtx) + return l.BatchCreateCategories(in) +} + +func (s *CategoryServer) BatchUpdateCategories(ctx context.Context, in *category.BatchUpdateRequest) (*category.BatchUpdateResponse, error) { + l := logic.NewBatchUpdateCategoriesLogic(ctx, s.svcCtx) + return l.BatchUpdateCategories(in) +} + +// 查询过滤 +func (s *CategoryServer) ListCategories(ctx context.Context, in *category.ListCategoryRequest) (*category.CategoryListResponse, error) { + l := logic.NewListCategoriesLogic(ctx, s.svcCtx) + return l.ListCategories(in) +} + +func (s *CategoryServer) CheckAlias(ctx context.Context, in *category.CheckAliasRequest) (*category.CheckAliasResponse, error) { + l := logic.NewCheckAliasLogic(ctx, s.svcCtx) + return l.CheckAlias(in) +} diff --git a/category/internal/svc/servicecontext.go b/category/internal/svc/servicecontext.go new file mode 100644 index 0000000..2416487 --- /dev/null +++ b/category/internal/svc/servicecontext.go @@ -0,0 +1,22 @@ +package svc + +import ( + "godemo/category/internal/config" + "godemo/category/internal/model" + + _ "github.com/lib/pq" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) + +type ServiceContext struct { + Config config.Config + CategoryModel model.CategoriesModel +} + +func NewServiceContext(c config.Config) *ServiceContext { + conn := sqlx.NewSqlConn("postgres", c.DB.DataSource) + return &ServiceContext{ + Config: c, + CategoryModel: model.NewCategoriesModel(conn), + } +} diff --git a/docker/docker-category/Dockerfile b/docker/docker-category/Dockerfile new file mode 100644 index 0000000..b04b02b --- /dev/null +++ b/docker/docker-category/Dockerfile @@ -0,0 +1,31 @@ +FROM golang:alpine AS builder + +LABEL stage=gobuilder + +ENV GOPROXY=https://goproxy.cn,direct +ENV CGO_ENABLED=0 + + +RUN apk update --no-cache && apk add --no-cache tzdata + +WORKDIR /build + +ADD go.mod . +ADD go.sum . +RUN go mod download +COPY . . + +RUN go build -ldflags="-s -w" -o /app/category category/category.go + + +FROM scratch + +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai +ENV TZ=Asia/Shanghai + +WORKDIR /app +COPY --from=builder /app/category /app/category + + +CMD ["./category", "-f", "etc/config.yaml"] diff --git a/docker/docker-category/docker-compose.yaml b/docker/docker-category/docker-compose.yaml new file mode 100644 index 0000000..6d944a6 --- /dev/null +++ b/docker/docker-category/docker-compose.yaml @@ -0,0 +1,17 @@ +services: + category: + image: category:v1 + container_name: category + restart: always + volumes: + - ./etc:/app/etc + networks: + - godemo_network + # 端口映射,生产环境非必须,开发环境用于方便调试 + ports: + - "60300:60300" + +networks: + godemo_network: + name: godemo_network + external: true diff --git a/docker/docker-category/etc/config.yaml b/docker/docker-category/etc/config.yaml new file mode 100644 index 0000000..779aaab --- /dev/null +++ b/docker/docker-category/etc/config.yaml @@ -0,0 +1,13 @@ +Name: category.rpc +ListenOn: 0.0.0.0:60300 +Mode: dev +Etcd: + Hosts: + - etcd:2379 + Key: category.rpc + +DB: + DataSource: postgres://postgres:postgres@localhost:5432/godemo?sslmode=disable + MaxOpenConns: 100 + MaxIdleConns: 20 + ConnMaxLifetime: 3600 \ No newline at end of file diff --git a/docker/docker-file/Dockerfile b/docker/docker-file/Dockerfile new file mode 100644 index 0000000..0a5fa80 --- /dev/null +++ b/docker/docker-file/Dockerfile @@ -0,0 +1,30 @@ +FROM golang:alpine AS builder + +LABEL stage=gobuilder + +ENV GOPROXY=https://goproxy.cn,direct +ENV CGO_ENABLED=0 + + +RUN apk update --no-cache && apk add --no-cache tzdata + +WORKDIR /build + +ADD go.mod . +ADD go.sum . +RUN go mod download +COPY . . + +RUN go build -ldflags="-s -w" -o /app/file file/file.go + + +FROM scratch + +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai +ENV TZ=Asia/Shanghai + +WORKDIR /app +COPY --from=builder /app/file /app/file + +CMD ["./file", "-f", "etc/config.yaml"] diff --git a/docker/docker-file/docker-compose.yaml b/docker/docker-file/docker-compose.yaml new file mode 100644 index 0000000..ca7fefb --- /dev/null +++ b/docker/docker-file/docker-compose.yaml @@ -0,0 +1,17 @@ +services: + file: + image: file:v1 + container_name: file + restart: always + volumes: + - ./etc:/app/etc + networks: + - godemo_network + # 端口映射,生产环境非必须,开发环境用于方便调试 + ports: + - "60200:60200" + +networks: + godemo_network: + name: godemo_network + external: true diff --git a/docker/docker-file/etc/config.yaml b/docker/docker-file/etc/config.yaml new file mode 100644 index 0000000..d307b63 --- /dev/null +++ b/docker/docker-file/etc/config.yaml @@ -0,0 +1,14 @@ +Name: file.rpc +ListenOn: 0.0.0.0:60200 +Mode: dev +Etcd: + Hosts: + - etcd:2379 + Key: file.rpc + +Minio: + Endpoint: "minio:9000" + Id: "minioadmin" + Secret: "minioadmin" + Token: "" + Secure: false \ No newline at end of file diff --git a/docker/docker-gateway/Dockerfile b/docker/docker-gateway/Dockerfile new file mode 100644 index 0000000..7c3c79d --- /dev/null +++ b/docker/docker-gateway/Dockerfile @@ -0,0 +1,30 @@ +FROM golang:alpine AS builder + +LABEL stage=gobuilder + +ENV GOPROXY=https://goproxy.cn,direct +ENV CGO_ENABLED=0 + + +RUN apk update --no-cache && apk add --no-cache tzdata + +WORKDIR /build + +ADD go.mod . +ADD go.sum . +RUN go mod download +COPY . . + +RUN go build -ldflags="-s -w" -o /app/gateway gateway/gateway.go + + +FROM scratch + +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai +ENV TZ=Asia/Shanghai + +WORKDIR /app +COPY --from=builder /app/gateway /app/gateway + +CMD ["./gateway", "-f", "etc/config.yaml"] diff --git a/docker/docker-gateway/docker-compose.yaml b/docker/docker-gateway/docker-compose.yaml new file mode 100644 index 0000000..9247ba1 --- /dev/null +++ b/docker/docker-gateway/docker-compose.yaml @@ -0,0 +1,16 @@ +services: + gateway: + image: gateway:v1 + container_name: gateway + restart: always + ports: + - 60000:60000 + volumes: + - ./etc:/app/etc + networks: + - godemo_network + +networks: + godemo_network: + name: godemo_network + external: true diff --git a/docker/docker-gateway/etc/config.yaml b/docker/docker-gateway/etc/config.yaml new file mode 100644 index 0000000..3a12200 --- /dev/null +++ b/docker/docker-gateway/etc/config.yaml @@ -0,0 +1,13 @@ +Name: gateway-api +Host: 0.0.0.0 +Port: 60000 + +JwtAuth: + AccessSecret: "your-secure-secret" + AccessExpire: 900 # 可选,单位秒,15分钟 + +UserRpc: + Etcd: + Hosts: + - etcd:2379 + Key: user.rpc \ No newline at end of file diff --git a/docker/docker-user/Dockerfile b/docker/docker-user/Dockerfile new file mode 100644 index 0000000..c1badcd --- /dev/null +++ b/docker/docker-user/Dockerfile @@ -0,0 +1,30 @@ +FROM golang:alpine AS builder + +LABEL stage=gobuilder + +ENV GOPROXY=https://goproxy.cn,direct +ENV CGO_ENABLED=0 + + +RUN apk update --no-cache && apk add --no-cache tzdata + +WORKDIR /build + +ADD go.mod . +ADD go.sum . +RUN go mod download +COPY . . + +RUN go build -ldflags="-s -w" -o /app/user user/user.go + + +FROM scratch + +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai +ENV TZ=Asia/Shanghai + +WORKDIR /app +COPY --from=builder /app/user /app/user + +CMD ["./user", "-f", "etc/config.yaml"] diff --git a/docker/docker-user/docker-compose.yaml b/docker/docker-user/docker-compose.yaml new file mode 100644 index 0000000..0554446 --- /dev/null +++ b/docker/docker-user/docker-compose.yaml @@ -0,0 +1,17 @@ +services: + user: + image: user:v1 + container_name: user + restart: always + volumes: + - ./etc:/app/etc + networks: + - godemo_network + # 端口映射,生产环境非必须,开发环境用于方便调试 + ports: + - "60100:60100" + +networks: + godemo_network: + name: godemo_network + external: true diff --git a/docker/docker-user/etc/config.yaml b/docker/docker-user/etc/config.yaml new file mode 100644 index 0000000..7db4ea5 --- /dev/null +++ b/docker/docker-user/etc/config.yaml @@ -0,0 +1,13 @@ +Name: user.rpc +ListenOn: 0.0.0.0:60100 +Mode: dev +Etcd: + Hosts: + - etcd:2379 + Key: user.rpc + +DataSource: "postgres://postgres:postgres@postgres:5432/godemo?sslmode=disable" + +JwtAuth: + AccessSecret: "your-secure-secret" + AccessExpire: 900 # 可选,单位秒,15分钟 diff --git a/file/etc/file.yaml b/file/etc/file.yaml new file mode 100644 index 0000000..e21f01c --- /dev/null +++ b/file/etc/file.yaml @@ -0,0 +1,14 @@ +Name: file.rpc +ListenOn: 0.0.0.0:60200 +Mode: dev +Etcd: + Hosts: + - 127.0.0.1:2379 + Key: file.rpc + +Minio: + Endpoint: "localhost:9000" + Id: "minioadmin" + Secret: "minioadmin" + Token: "" + Secure: false \ No newline at end of file diff --git a/file/file.go b/file/file.go new file mode 100644 index 0000000..9e0d902 --- /dev/null +++ b/file/file.go @@ -0,0 +1,39 @@ +package main + +import ( + "flag" + "fmt" + + "godemo/file/file" + "godemo/file/internal/config" + "godemo/file/internal/server" + "godemo/file/internal/svc" + + "github.com/zeromicro/go-zero/core/conf" + "github.com/zeromicro/go-zero/core/service" + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var configFile = flag.String("f", "etc/file.yaml", "the config file") + +func main() { + flag.Parse() + + var c config.Config + conf.MustLoad(*configFile, &c) + ctx := svc.NewServiceContext(c) + + s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { + file.RegisterFileServer(grpcServer, server.NewFileServer(ctx)) + + if c.Mode == service.DevMode || c.Mode == service.TestMode { + reflection.Register(grpcServer) + } + }) + defer s.Stop() + + fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) + s.Start() +} diff --git a/file/file/file.pb.go b/file/file/file.pb.go new file mode 100644 index 0000000..64954b9 --- /dev/null +++ b/file/file/file.pb.go @@ -0,0 +1,410 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.6 +// protoc v3.20.3 +// source: rpc/file.proto + +package file + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// 上传文件请求 +type UploadRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Filename string `protobuf:"bytes,1,opt,name=filename,proto3" json:"filename,omitempty"` // 文件名(建议客户端传原始名,服务端会生成唯一名) + ContentType string `protobuf:"bytes,2,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` // 文件类型(如 image/jpeg) + Content []byte `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` // 文件二进制内容(base64 编码由客户端完成) + Folder string `protobuf:"bytes,4,opt,name=folder,proto3" json:"folder,omitempty"` // 可选,文件夹或分类路径,如 "avatars"、"wallpapers" + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadRequest) Reset() { + *x = UploadRequest{} + mi := &file_rpc_file_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadRequest) ProtoMessage() {} + +func (x *UploadRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_file_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadRequest.ProtoReflect.Descriptor instead. +func (*UploadRequest) Descriptor() ([]byte, []int) { + return file_rpc_file_proto_rawDescGZIP(), []int{0} +} + +func (x *UploadRequest) GetFilename() string { + if x != nil { + return x.Filename + } + return "" +} + +func (x *UploadRequest) GetContentType() string { + if x != nil { + return x.ContentType + } + return "" +} + +func (x *UploadRequest) GetContent() []byte { + if x != nil { + return x.Content + } + return nil +} + +func (x *UploadRequest) GetFolder() string { + if x != nil { + return x.Folder + } + return "" +} + +// 上传响应 +type UploadResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + FileId string `protobuf:"bytes,1,opt,name=file_id,json=fileId,proto3" json:"file_id,omitempty"` // 文件唯一 ID(或路径) + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` // 可访问 URL(带 CDN 或签名) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadResponse) Reset() { + *x = UploadResponse{} + mi := &file_rpc_file_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadResponse) ProtoMessage() {} + +func (x *UploadResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_file_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadResponse.ProtoReflect.Descriptor instead. +func (*UploadResponse) Descriptor() ([]byte, []int) { + return file_rpc_file_proto_rawDescGZIP(), []int{1} +} + +func (x *UploadResponse) GetFileId() string { + if x != nil { + return x.FileId + } + return "" +} + +func (x *UploadResponse) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +// 获取访问链接请求 +type GetFileUrlRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + FileId string `protobuf:"bytes,1,opt,name=file_id,json=fileId,proto3" json:"file_id,omitempty"` // 文件唯一 ID 或路径 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetFileUrlRequest) Reset() { + *x = GetFileUrlRequest{} + mi := &file_rpc_file_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetFileUrlRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFileUrlRequest) ProtoMessage() {} + +func (x *GetFileUrlRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_file_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFileUrlRequest.ProtoReflect.Descriptor instead. +func (*GetFileUrlRequest) Descriptor() ([]byte, []int) { + return file_rpc_file_proto_rawDescGZIP(), []int{2} +} + +func (x *GetFileUrlRequest) GetFileId() string { + if x != nil { + return x.FileId + } + return "" +} + +// 获取访问链接响应 +type GetFileUrlResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` // 可访问链接 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetFileUrlResponse) Reset() { + *x = GetFileUrlResponse{} + mi := &file_rpc_file_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetFileUrlResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFileUrlResponse) ProtoMessage() {} + +func (x *GetFileUrlResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_file_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFileUrlResponse.ProtoReflect.Descriptor instead. +func (*GetFileUrlResponse) Descriptor() ([]byte, []int) { + return file_rpc_file_proto_rawDescGZIP(), []int{3} +} + +func (x *GetFileUrlResponse) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +// 删除文件请求 +type DeleteRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + FileId string `protobuf:"bytes,1,opt,name=file_id,json=fileId,proto3" json:"file_id,omitempty"` // 要删除的文件 ID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteRequest) Reset() { + *x = DeleteRequest{} + mi := &file_rpc_file_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteRequest) ProtoMessage() {} + +func (x *DeleteRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_file_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead. +func (*DeleteRequest) Descriptor() ([]byte, []int) { + return file_rpc_file_proto_rawDescGZIP(), []int{4} +} + +func (x *DeleteRequest) GetFileId() string { + if x != nil { + return x.FileId + } + return "" +} + +// 删除文件响应 +type DeleteResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` // 是否删除成功 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteResponse) Reset() { + *x = DeleteResponse{} + mi := &file_rpc_file_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteResponse) ProtoMessage() {} + +func (x *DeleteResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_file_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteResponse.ProtoReflect.Descriptor instead. +func (*DeleteResponse) Descriptor() ([]byte, []int) { + return file_rpc_file_proto_rawDescGZIP(), []int{5} +} + +func (x *DeleteResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +var File_rpc_file_proto protoreflect.FileDescriptor + +const file_rpc_file_proto_rawDesc = "" + + "\n" + + "\x0erpc/file.proto\x12\x04file\"\x80\x01\n" + + "\rUploadRequest\x12\x1a\n" + + "\bfilename\x18\x01 \x01(\tR\bfilename\x12!\n" + + "\fcontent_type\x18\x02 \x01(\tR\vcontentType\x12\x18\n" + + "\acontent\x18\x03 \x01(\fR\acontent\x12\x16\n" + + "\x06folder\x18\x04 \x01(\tR\x06folder\";\n" + + "\x0eUploadResponse\x12\x17\n" + + "\afile_id\x18\x01 \x01(\tR\x06fileId\x12\x10\n" + + "\x03url\x18\x02 \x01(\tR\x03url\",\n" + + "\x11GetFileUrlRequest\x12\x17\n" + + "\afile_id\x18\x01 \x01(\tR\x06fileId\"&\n" + + "\x12GetFileUrlResponse\x12\x10\n" + + "\x03url\x18\x01 \x01(\tR\x03url\"(\n" + + "\rDeleteRequest\x12\x17\n" + + "\afile_id\x18\x01 \x01(\tR\x06fileId\"*\n" + + "\x0eDeleteResponse\x12\x18\n" + + "\asuccess\x18\x01 \x01(\bR\asuccess2\xb1\x01\n" + + "\x04File\x123\n" + + "\x06Upload\x12\x13.file.UploadRequest\x1a\x14.file.UploadResponse\x12?\n" + + "\n" + + "GetFileUrl\x12\x17.file.GetFileUrlRequest\x1a\x18.file.GetFileUrlResponse\x123\n" + + "\x06Delete\x12\x13.file.DeleteRequest\x1a\x14.file.DeleteResponseB\bZ\x06./fileb\x06proto3" + +var ( + file_rpc_file_proto_rawDescOnce sync.Once + file_rpc_file_proto_rawDescData []byte +) + +func file_rpc_file_proto_rawDescGZIP() []byte { + file_rpc_file_proto_rawDescOnce.Do(func() { + file_rpc_file_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_rpc_file_proto_rawDesc), len(file_rpc_file_proto_rawDesc))) + }) + return file_rpc_file_proto_rawDescData +} + +var file_rpc_file_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_rpc_file_proto_goTypes = []any{ + (*UploadRequest)(nil), // 0: file.UploadRequest + (*UploadResponse)(nil), // 1: file.UploadResponse + (*GetFileUrlRequest)(nil), // 2: file.GetFileUrlRequest + (*GetFileUrlResponse)(nil), // 3: file.GetFileUrlResponse + (*DeleteRequest)(nil), // 4: file.DeleteRequest + (*DeleteResponse)(nil), // 5: file.DeleteResponse +} +var file_rpc_file_proto_depIdxs = []int32{ + 0, // 0: file.File.Upload:input_type -> file.UploadRequest + 2, // 1: file.File.GetFileUrl:input_type -> file.GetFileUrlRequest + 4, // 2: file.File.Delete:input_type -> file.DeleteRequest + 1, // 3: file.File.Upload:output_type -> file.UploadResponse + 3, // 4: file.File.GetFileUrl:output_type -> file.GetFileUrlResponse + 5, // 5: file.File.Delete:output_type -> file.DeleteResponse + 3, // [3:6] is the sub-list for method output_type + 0, // [0:3] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_rpc_file_proto_init() } +func file_rpc_file_proto_init() { + if File_rpc_file_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_rpc_file_proto_rawDesc), len(file_rpc_file_proto_rawDesc)), + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_rpc_file_proto_goTypes, + DependencyIndexes: file_rpc_file_proto_depIdxs, + MessageInfos: file_rpc_file_proto_msgTypes, + }.Build() + File_rpc_file_proto = out.File + file_rpc_file_proto_goTypes = nil + file_rpc_file_proto_depIdxs = nil +} diff --git a/file/file/file_grpc.pb.go b/file/file/file_grpc.pb.go new file mode 100644 index 0000000..cb39488 --- /dev/null +++ b/file/file/file_grpc.pb.go @@ -0,0 +1,207 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v3.20.3 +// source: rpc/file.proto + +package file + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + File_Upload_FullMethodName = "/file.File/Upload" + File_GetFileUrl_FullMethodName = "/file.File/GetFileUrl" + File_Delete_FullMethodName = "/file.File/Delete" +) + +// FileClient is the client API for File service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// 文件服务 - 上传图片、获取地址、删除文件等 +type FileClient interface { + // 上传文件(图片/头像/壁纸等) + Upload(ctx context.Context, in *UploadRequest, opts ...grpc.CallOption) (*UploadResponse, error) + // 获取文件访问链接(带签名,防盗链) + GetFileUrl(ctx context.Context, in *GetFileUrlRequest, opts ...grpc.CallOption) (*GetFileUrlResponse, error) + // 删除文件 + Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error) +} + +type fileClient struct { + cc grpc.ClientConnInterface +} + +func NewFileClient(cc grpc.ClientConnInterface) FileClient { + return &fileClient{cc} +} + +func (c *fileClient) Upload(ctx context.Context, in *UploadRequest, opts ...grpc.CallOption) (*UploadResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UploadResponse) + err := c.cc.Invoke(ctx, File_Upload_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fileClient) GetFileUrl(ctx context.Context, in *GetFileUrlRequest, opts ...grpc.CallOption) (*GetFileUrlResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetFileUrlResponse) + err := c.cc.Invoke(ctx, File_GetFileUrl_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fileClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteResponse) + err := c.cc.Invoke(ctx, File_Delete_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// FileServer is the server API for File service. +// All implementations must embed UnimplementedFileServer +// for forward compatibility. +// +// 文件服务 - 上传图片、获取地址、删除文件等 +type FileServer interface { + // 上传文件(图片/头像/壁纸等) + Upload(context.Context, *UploadRequest) (*UploadResponse, error) + // 获取文件访问链接(带签名,防盗链) + GetFileUrl(context.Context, *GetFileUrlRequest) (*GetFileUrlResponse, error) + // 删除文件 + Delete(context.Context, *DeleteRequest) (*DeleteResponse, error) + mustEmbedUnimplementedFileServer() +} + +// UnimplementedFileServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedFileServer struct{} + +func (UnimplementedFileServer) Upload(context.Context, *UploadRequest) (*UploadResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Upload not implemented") +} +func (UnimplementedFileServer) GetFileUrl(context.Context, *GetFileUrlRequest) (*GetFileUrlResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetFileUrl not implemented") +} +func (UnimplementedFileServer) Delete(context.Context, *DeleteRequest) (*DeleteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") +} +func (UnimplementedFileServer) mustEmbedUnimplementedFileServer() {} +func (UnimplementedFileServer) testEmbeddedByValue() {} + +// UnsafeFileServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to FileServer will +// result in compilation errors. +type UnsafeFileServer interface { + mustEmbedUnimplementedFileServer() +} + +func RegisterFileServer(s grpc.ServiceRegistrar, srv FileServer) { + // If the following call pancis, it indicates UnimplementedFileServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&File_ServiceDesc, srv) +} + +func _File_Upload_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UploadRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FileServer).Upload(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: File_Upload_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FileServer).Upload(ctx, req.(*UploadRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _File_GetFileUrl_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFileUrlRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FileServer).GetFileUrl(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: File_GetFileUrl_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FileServer).GetFileUrl(ctx, req.(*GetFileUrlRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _File_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FileServer).Delete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: File_Delete_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FileServer).Delete(ctx, req.(*DeleteRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// File_ServiceDesc is the grpc.ServiceDesc for File service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var File_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "file.File", + HandlerType: (*FileServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Upload", + Handler: _File_Upload_Handler, + }, + { + MethodName: "GetFileUrl", + Handler: _File_GetFileUrl_Handler, + }, + { + MethodName: "Delete", + Handler: _File_Delete_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "rpc/file.proto", +} diff --git a/file/fileclient/file.go b/file/fileclient/file.go new file mode 100644 index 0000000..03bd000 --- /dev/null +++ b/file/fileclient/file.go @@ -0,0 +1,60 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.8.3 +// Source: file.proto + +package fileclient + +import ( + "context" + + "godemo/file/file" + + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" +) + +type ( + DeleteRequest = file.DeleteRequest + DeleteResponse = file.DeleteResponse + GetFileUrlRequest = file.GetFileUrlRequest + GetFileUrlResponse = file.GetFileUrlResponse + UploadRequest = file.UploadRequest + UploadResponse = file.UploadResponse + + File interface { + // 上传文件(图片/头像/壁纸等) + Upload(ctx context.Context, in *UploadRequest, opts ...grpc.CallOption) (*UploadResponse, error) + // 获取文件访问链接(带签名,防盗链) + GetFileUrl(ctx context.Context, in *GetFileUrlRequest, opts ...grpc.CallOption) (*GetFileUrlResponse, error) + // 删除文件 + Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error) + } + + defaultFile struct { + cli zrpc.Client + } +) + +func NewFile(cli zrpc.Client) File { + return &defaultFile{ + cli: cli, + } +} + +// 上传文件(图片/头像/壁纸等) +func (m *defaultFile) Upload(ctx context.Context, in *UploadRequest, opts ...grpc.CallOption) (*UploadResponse, error) { + client := file.NewFileClient(m.cli.Conn()) + return client.Upload(ctx, in, opts...) +} + +// 获取文件访问链接(带签名,防盗链) +func (m *defaultFile) GetFileUrl(ctx context.Context, in *GetFileUrlRequest, opts ...grpc.CallOption) (*GetFileUrlResponse, error) { + client := file.NewFileClient(m.cli.Conn()) + return client.GetFileUrl(ctx, in, opts...) +} + +// 删除文件 +func (m *defaultFile) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error) { + client := file.NewFileClient(m.cli.Conn()) + return client.Delete(ctx, in, opts...) +} diff --git a/file/internal/config/config.go b/file/internal/config/config.go new file mode 100644 index 0000000..57c2d9d --- /dev/null +++ b/file/internal/config/config.go @@ -0,0 +1,16 @@ +package config + +import "github.com/zeromicro/go-zero/zrpc" + +type Minio struct { + Endpoint string + Id string + Secret string + Token string + Secure bool +} + +type Config struct { + zrpc.RpcServerConf + Minio Minio +} diff --git a/file/internal/logic/deletelogic.go b/file/internal/logic/deletelogic.go new file mode 100644 index 0000000..975fd0c --- /dev/null +++ b/file/internal/logic/deletelogic.go @@ -0,0 +1,51 @@ +package logic + +import ( + "context" + "strings" + + "godemo/file/file" + "godemo/file/internal/svc" + + "github.com/minio/minio-go/v7" + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type DeleteLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewDeleteLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteLogic { + return &DeleteLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 删除文件 +func (l *DeleteLogic) Delete(in *file.DeleteRequest) (*file.DeleteResponse, error) { + // 假设 fileId 格式为: "bucketName/objectName" + parts := strings.SplitN(in.FileId, "/", 2) + if len(parts) != 2 { + return nil, status.Error(codes.InvalidArgument, "invalid fileId format") + } + + bucketName := parts[0] + objectName := parts[1] + + // 删除对象 + err := l.svcCtx.MinioClient.RemoveObject(l.ctx, bucketName, objectName, minio.RemoveObjectOptions{}) + if err != nil { + // return nil, err + return nil, status.Error(codes.Internal, err.Error()) + } + + return &file.DeleteResponse{ + Success: true, + }, nil +} diff --git a/file/internal/logic/getfileurllogic.go b/file/internal/logic/getfileurllogic.go new file mode 100644 index 0000000..5563c4d --- /dev/null +++ b/file/internal/logic/getfileurllogic.go @@ -0,0 +1,57 @@ +package logic + +import ( + "context" + "net/url" + "strings" + "time" + + "godemo/file/file" + "godemo/file/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type GetFileUrlLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGetFileUrlLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFileUrlLogic { + return &GetFileUrlLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 获取文件访问链接(带签名,防盗链) +func (l *GetFileUrlLogic) GetFileUrl(in *file.GetFileUrlRequest) (*file.GetFileUrlResponse, error) { + // 假设 fileId 格式为: "bucketName/objectName" + parts := strings.SplitN(in.FileId, "/", 2) + if len(parts) != 2 { + return nil, status.Error(codes.InvalidArgument, "invalid fileId format") + } + + bucketName := parts[0] + objectName := parts[1] + + // 生成预签名 URL,有效期 1 小时 + presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject( + l.ctx, + bucketName, + objectName, + time.Hour, + url.Values{}, + ) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return &file.GetFileUrlResponse{ + Url: presignedUrl.String(), + }, nil +} diff --git a/file/internal/logic/uploadlogic.go b/file/internal/logic/uploadlogic.go new file mode 100644 index 0000000..7d78f93 --- /dev/null +++ b/file/internal/logic/uploadlogic.go @@ -0,0 +1,88 @@ +package logic + +import ( + "bytes" + "context" + "net/url" + "path/filepath" + "time" + + "godemo/file/file" + "godemo/file/internal/svc" + + "github.com/google/uuid" + "github.com/minio/minio-go/v7" + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type UploadLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewUploadLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadLogic { + return &UploadLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 上传文件(图片/头像/壁纸等) +func (l *UploadLogic) Upload(in *file.UploadRequest) (*file.UploadResponse, error) { + bucketName := "default" + if in.Folder != "" { + bucketName = in.Folder + } + + // 确保 bucket 存在(自动创建) + exists, err := l.svcCtx.MinioClient.BucketExists(l.ctx, bucketName) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + if !exists { + err := l.svcCtx.MinioClient.MakeBucket(l.ctx, bucketName, minio.MakeBucketOptions{}) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + } + + // 生成唯一文件名 + ext := getFileExtension(in.Filename) + newFileName := uuid.New().String() + ext + + // 上传对象 + _, err = l.svcCtx.MinioClient.PutObject(l.ctx, bucketName, newFileName, + bytes.NewReader(in.Content), + int64(len(in.Content)), + minio.PutObjectOptions{ + ContentType: in.ContentType, + }) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + // 生成预签名 URL(有效期1小时) + reqParams := make(url.Values) + presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, bucketName, newFileName, time.Hour, reqParams) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return &file.UploadResponse{ + FileId: newFileName, + Url: presignedUrl.String(), + }, nil +} + +// 获取文件扩展名(默认 .jpg) +func getFileExtension(name string) string { + ext := filepath.Ext(name) + if ext == "" { + return ".jpg" + } + return ext +} diff --git a/file/internal/server/fileserver.go b/file/internal/server/fileserver.go new file mode 100644 index 0000000..5935d27 --- /dev/null +++ b/file/internal/server/fileserver.go @@ -0,0 +1,42 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.8.3 +// Source: file.proto + +package server + +import ( + "context" + + "godemo/file/file" + "godemo/file/internal/logic" + "godemo/file/internal/svc" +) + +type FileServer struct { + svcCtx *svc.ServiceContext + file.UnimplementedFileServer +} + +func NewFileServer(svcCtx *svc.ServiceContext) *FileServer { + return &FileServer{ + svcCtx: svcCtx, + } +} + +// 上传文件(图片/头像/壁纸等) +func (s *FileServer) Upload(ctx context.Context, in *file.UploadRequest) (*file.UploadResponse, error) { + l := logic.NewUploadLogic(ctx, s.svcCtx) + return l.Upload(in) +} + +// 获取文件访问链接(带签名,防盗链) +func (s *FileServer) GetFileUrl(ctx context.Context, in *file.GetFileUrlRequest) (*file.GetFileUrlResponse, error) { + l := logic.NewGetFileUrlLogic(ctx, s.svcCtx) + return l.GetFileUrl(in) +} + +// 删除文件 +func (s *FileServer) Delete(ctx context.Context, in *file.DeleteRequest) (*file.DeleteResponse, error) { + l := logic.NewDeleteLogic(ctx, s.svcCtx) + return l.Delete(in) +} diff --git a/file/internal/svc/servicecontext.go b/file/internal/svc/servicecontext.go new file mode 100644 index 0000000..ba3c8f7 --- /dev/null +++ b/file/internal/svc/servicecontext.go @@ -0,0 +1,29 @@ +package svc + +import ( + "godemo/file/internal/config" + "log" + + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" +) + +type ServiceContext struct { + Config config.Config + MinioClient *minio.Client +} + +func NewServiceContext(c config.Config) *ServiceContext { + // 初始化 MinIO 客户端 + minioClient, err := minio.New(c.Minio.Endpoint, &minio.Options{ + Creds: credentials.NewStaticV4(c.Minio.Id, c.Minio.Secret, c.Minio.Token), + Secure: c.Minio.Secure, // 本地部署不用 https + }) + if err != nil { + log.Fatalf("failed to initialize minio client: %v", err) + } + return &ServiceContext{ + Config: c, + MinioClient: minioClient, + } +} diff --git a/gallery/etc/gallery.yaml b/gallery/etc/gallery.yaml new file mode 100644 index 0000000..20101fd --- /dev/null +++ b/gallery/etc/gallery.yaml @@ -0,0 +1,12 @@ +Name: gallery.rpc +ListenOn: 0.0.0.0:50000 +Etcd: + Hosts: + - 127.0.0.1:2379 + Key: gallery.rpc + +FileRpc: + Etcd: + Hosts: + - 127.0.0.1:2379 + Key: file.rpc \ No newline at end of file diff --git a/gallery/gallery.go b/gallery/gallery.go new file mode 100644 index 0000000..c67c740 --- /dev/null +++ b/gallery/gallery.go @@ -0,0 +1,39 @@ +package main + +import ( + "flag" + "fmt" + + "godemo/gallery/gallery" + "godemo/gallery/internal/config" + "godemo/gallery/internal/server" + "godemo/gallery/internal/svc" + + "github.com/zeromicro/go-zero/core/conf" + "github.com/zeromicro/go-zero/core/service" + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var configFile = flag.String("f", "etc/gallery.yaml", "the config file") + +func main() { + flag.Parse() + + var c config.Config + conf.MustLoad(*configFile, &c) + ctx := svc.NewServiceContext(c) + + s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { + gallery.RegisterGalleryServer(grpcServer, server.NewGalleryServer(ctx)) + + if c.Mode == service.DevMode || c.Mode == service.TestMode { + reflection.Register(grpcServer) + } + }) + defer s.Stop() + + fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) + s.Start() +} diff --git a/gallery/gallery/gallery.pb.go b/gallery/gallery/gallery.pb.go new file mode 100644 index 0000000..bdfc436 --- /dev/null +++ b/gallery/gallery/gallery.pb.go @@ -0,0 +1,1420 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.6 +// protoc v3.19.4 +// source: rpc/gallery.proto + +package gallery + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// 健康检查 +type PingRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Ping string `protobuf:"bytes,1,opt,name=ping,proto3" json:"ping,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PingRequest) Reset() { + *x = PingRequest{} + mi := &file_rpc_gallery_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PingRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PingRequest) ProtoMessage() {} + +func (x *PingRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PingRequest.ProtoReflect.Descriptor instead. +func (*PingRequest) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{0} +} + +func (x *PingRequest) GetPing() string { + if x != nil { + return x.Ping + } + return "" +} + +type PingResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Pong string `protobuf:"bytes,1,opt,name=pong,proto3" json:"pong,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PingResponse) Reset() { + *x = PingResponse{} + mi := &file_rpc_gallery_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PingResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PingResponse) ProtoMessage() {} + +func (x *PingResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PingResponse.ProtoReflect.Descriptor instead. +func (*PingResponse) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{1} +} + +func (x *PingResponse) GetPong() string { + if x != nil { + return x.Pong + } + return "" +} + +// 图片元数据 +type ImageMeta struct { + state protoimpl.MessageState `protogen:"open.v1"` + ImageId string `protobuf:"bytes,1,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"` + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + CategoryId string `protobuf:"bytes,4,opt,name=category_id,json=categoryId,proto3" json:"category_id,omitempty"` + Tags []string `protobuf:"bytes,5,rep,name=tags,proto3" json:"tags,omitempty"` + FileSize int64 `protobuf:"varint,6,opt,name=file_size,json=fileSize,proto3" json:"file_size,omitempty"` + Width int32 `protobuf:"varint,7,opt,name=width,proto3" json:"width,omitempty"` + Height int32 `protobuf:"varint,8,opt,name=height,proto3" json:"height,omitempty"` + StorageKey string `protobuf:"bytes,9,opt,name=storage_key,json=storageKey,proto3" json:"storage_key,omitempty"` + FileName string `protobuf:"bytes,10,opt,name=file_name,json=fileName,proto3" json:"file_name,omitempty"` + MimeType string `protobuf:"bytes,11,opt,name=mime_type,json=mimeType,proto3" json:"mime_type,omitempty"` + CreatedAt int64 `protobuf:"varint,12,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt int64 `protobuf:"varint,13,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ImageMeta) Reset() { + *x = ImageMeta{} + mi := &file_rpc_gallery_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ImageMeta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImageMeta) ProtoMessage() {} + +func (x *ImageMeta) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImageMeta.ProtoReflect.Descriptor instead. +func (*ImageMeta) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{2} +} + +func (x *ImageMeta) GetImageId() string { + if x != nil { + return x.ImageId + } + return "" +} + +func (x *ImageMeta) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *ImageMeta) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *ImageMeta) GetCategoryId() string { + if x != nil { + return x.CategoryId + } + return "" +} + +func (x *ImageMeta) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +func (x *ImageMeta) GetFileSize() int64 { + if x != nil { + return x.FileSize + } + return 0 +} + +func (x *ImageMeta) GetWidth() int32 { + if x != nil { + return x.Width + } + return 0 +} + +func (x *ImageMeta) GetHeight() int32 { + if x != nil { + return x.Height + } + return 0 +} + +func (x *ImageMeta) GetStorageKey() string { + if x != nil { + return x.StorageKey + } + return "" +} + +func (x *ImageMeta) GetFileName() string { + if x != nil { + return x.FileName + } + return "" +} + +func (x *ImageMeta) GetMimeType() string { + if x != nil { + return x.MimeType + } + return "" +} + +func (x *ImageMeta) GetCreatedAt() int64 { + if x != nil { + return x.CreatedAt + } + return 0 +} + +func (x *ImageMeta) GetUpdatedAt() int64 { + if x != nil { + return x.UpdatedAt + } + return 0 +} + +// 图片列表 +type ImageListRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Page int32 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"` + PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + CategoryId string `protobuf:"bytes,3,opt,name=category_id,json=categoryId,proto3" json:"category_id,omitempty"` + Tags []string `protobuf:"bytes,4,rep,name=tags,proto3" json:"tags,omitempty"` + OrderBy string `protobuf:"bytes,5,opt,name=order_by,json=orderBy,proto3" json:"order_by,omitempty"` // created_at_desc | updated_at_asc + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ImageListRequest) Reset() { + *x = ImageListRequest{} + mi := &file_rpc_gallery_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ImageListRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImageListRequest) ProtoMessage() {} + +func (x *ImageListRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImageListRequest.ProtoReflect.Descriptor instead. +func (*ImageListRequest) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{3} +} + +func (x *ImageListRequest) GetPage() int32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *ImageListRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ImageListRequest) GetCategoryId() string { + if x != nil { + return x.CategoryId + } + return "" +} + +func (x *ImageListRequest) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +func (x *ImageListRequest) GetOrderBy() string { + if x != nil { + return x.OrderBy + } + return "" +} + +type ImageListResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Images []*ImageMeta `protobuf:"bytes,1,rep,name=images,proto3" json:"images,omitempty"` + Total int32 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ImageListResponse) Reset() { + *x = ImageListResponse{} + mi := &file_rpc_gallery_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ImageListResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImageListResponse) ProtoMessage() {} + +func (x *ImageListResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImageListResponse.ProtoReflect.Descriptor instead. +func (*ImageListResponse) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{4} +} + +func (x *ImageListResponse) GetImages() []*ImageMeta { + if x != nil { + return x.Images + } + return nil +} + +func (x *ImageListResponse) GetTotal() int32 { + if x != nil { + return x.Total + } + return 0 +} + +// 图片详情 +type ImageDetailRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ImageId string `protobuf:"bytes,1,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ImageDetailRequest) Reset() { + *x = ImageDetailRequest{} + mi := &file_rpc_gallery_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ImageDetailRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImageDetailRequest) ProtoMessage() {} + +func (x *ImageDetailRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImageDetailRequest.ProtoReflect.Descriptor instead. +func (*ImageDetailRequest) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{5} +} + +func (x *ImageDetailRequest) GetImageId() string { + if x != nil { + return x.ImageId + } + return "" +} + +type ImageDetailResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Meta *ImageMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ImageDetailResponse) Reset() { + *x = ImageDetailResponse{} + mi := &file_rpc_gallery_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ImageDetailResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImageDetailResponse) ProtoMessage() {} + +func (x *ImageDetailResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImageDetailResponse.ProtoReflect.Descriptor instead. +func (*ImageDetailResponse) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{6} +} + +func (x *ImageDetailResponse) GetMeta() *ImageMeta { + if x != nil { + return x.Meta + } + return nil +} + +// 更新图片 +type UpdateImageRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ImageId string `protobuf:"bytes,1,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"` + Title *string `protobuf:"bytes,2,opt,name=title,proto3,oneof" json:"title,omitempty"` + Description *string `protobuf:"bytes,3,opt,name=description,proto3,oneof" json:"description,omitempty"` + CategoryId *string `protobuf:"bytes,4,opt,name=category_id,json=categoryId,proto3,oneof" json:"category_id,omitempty"` + Tags []string `protobuf:"bytes,5,rep,name=tags,proto3" json:"tags,omitempty"` // 全量替换 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateImageRequest) Reset() { + *x = UpdateImageRequest{} + mi := &file_rpc_gallery_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateImageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateImageRequest) ProtoMessage() {} + +func (x *UpdateImageRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateImageRequest.ProtoReflect.Descriptor instead. +func (*UpdateImageRequest) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{7} +} + +func (x *UpdateImageRequest) GetImageId() string { + if x != nil { + return x.ImageId + } + return "" +} + +func (x *UpdateImageRequest) GetTitle() string { + if x != nil && x.Title != nil { + return *x.Title + } + return "" +} + +func (x *UpdateImageRequest) GetDescription() string { + if x != nil && x.Description != nil { + return *x.Description + } + return "" +} + +func (x *UpdateImageRequest) GetCategoryId() string { + if x != nil && x.CategoryId != nil { + return *x.CategoryId + } + return "" +} + +func (x *UpdateImageRequest) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +type UpdateImageResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateImageResponse) Reset() { + *x = UpdateImageResponse{} + mi := &file_rpc_gallery_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateImageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateImageResponse) ProtoMessage() {} + +func (x *UpdateImageResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateImageResponse.ProtoReflect.Descriptor instead. +func (*UpdateImageResponse) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{8} +} + +func (x *UpdateImageResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +// 删除图片 +type DeleteImageRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ImageId string `protobuf:"bytes,1,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"` + Permanent bool `protobuf:"varint,2,opt,name=permanent,proto3" json:"permanent,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteImageRequest) Reset() { + *x = DeleteImageRequest{} + mi := &file_rpc_gallery_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteImageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteImageRequest) ProtoMessage() {} + +func (x *DeleteImageRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteImageRequest.ProtoReflect.Descriptor instead. +func (*DeleteImageRequest) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{9} +} + +func (x *DeleteImageRequest) GetImageId() string { + if x != nil { + return x.ImageId + } + return "" +} + +func (x *DeleteImageRequest) GetPermanent() bool { + if x != nil { + return x.Permanent + } + return false +} + +type DeleteImageResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteImageResponse) Reset() { + *x = DeleteImageResponse{} + mi := &file_rpc_gallery_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteImageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteImageResponse) ProtoMessage() {} + +func (x *DeleteImageResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteImageResponse.ProtoReflect.Descriptor instead. +func (*DeleteImageResponse) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{10} +} + +func (x *DeleteImageResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +// 图片上传 +type UploadImageRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + FileContent []byte `protobuf:"bytes,1,opt,name=file_content,json=fileContent,proto3" json:"file_content,omitempty"` + FileName string `protobuf:"bytes,2,opt,name=file_name,json=fileName,proto3" json:"file_name,omitempty"` + Title *string `protobuf:"bytes,3,opt,name=title,proto3,oneof" json:"title,omitempty"` + Description *string `protobuf:"bytes,4,opt,name=description,proto3,oneof" json:"description,omitempty"` + CategoryId *string `protobuf:"bytes,5,opt,name=category_id,json=categoryId,proto3,oneof" json:"category_id,omitempty"` + Tags []string `protobuf:"bytes,6,rep,name=tags,proto3" json:"tags,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadImageRequest) Reset() { + *x = UploadImageRequest{} + mi := &file_rpc_gallery_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadImageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadImageRequest) ProtoMessage() {} + +func (x *UploadImageRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadImageRequest.ProtoReflect.Descriptor instead. +func (*UploadImageRequest) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{11} +} + +func (x *UploadImageRequest) GetFileContent() []byte { + if x != nil { + return x.FileContent + } + return nil +} + +func (x *UploadImageRequest) GetFileName() string { + if x != nil { + return x.FileName + } + return "" +} + +func (x *UploadImageRequest) GetTitle() string { + if x != nil && x.Title != nil { + return *x.Title + } + return "" +} + +func (x *UploadImageRequest) GetDescription() string { + if x != nil && x.Description != nil { + return *x.Description + } + return "" +} + +func (x *UploadImageRequest) GetCategoryId() string { + if x != nil && x.CategoryId != nil { + return *x.CategoryId + } + return "" +} + +func (x *UploadImageRequest) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +type UploadImageResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + ImageMeta *ImageMeta `protobuf:"bytes,1,opt,name=image_meta,json=imageMeta,proto3" json:"image_meta,omitempty"` + PreviewUrl string `protobuf:"bytes,2,opt,name=preview_url,json=previewUrl,proto3" json:"preview_url,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadImageResponse) Reset() { + *x = UploadImageResponse{} + mi := &file_rpc_gallery_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadImageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadImageResponse) ProtoMessage() {} + +func (x *UploadImageResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadImageResponse.ProtoReflect.Descriptor instead. +func (*UploadImageResponse) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{12} +} + +func (x *UploadImageResponse) GetImageMeta() *ImageMeta { + if x != nil { + return x.ImageMeta + } + return nil +} + +func (x *UploadImageResponse) GetPreviewUrl() string { + if x != nil { + return x.PreviewUrl + } + return "" +} + +// 分类管理 +type CategoryNode struct { + state protoimpl.MessageState `protogen:"open.v1"` + CategoryId string `protobuf:"bytes,1,opt,name=category_id,json=categoryId,proto3" json:"category_id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Children []*CategoryNode `protobuf:"bytes,3,rep,name=children,proto3" json:"children,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CategoryNode) Reset() { + *x = CategoryNode{} + mi := &file_rpc_gallery_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CategoryNode) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CategoryNode) ProtoMessage() {} + +func (x *CategoryNode) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CategoryNode.ProtoReflect.Descriptor instead. +func (*CategoryNode) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{13} +} + +func (x *CategoryNode) GetCategoryId() string { + if x != nil { + return x.CategoryId + } + return "" +} + +func (x *CategoryNode) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CategoryNode) GetChildren() []*CategoryNode { + if x != nil { + return x.Children + } + return nil +} + +type CategoryTreeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + IncludeCount bool `protobuf:"varint,1,opt,name=include_count,json=includeCount,proto3" json:"include_count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CategoryTreeRequest) Reset() { + *x = CategoryTreeRequest{} + mi := &file_rpc_gallery_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CategoryTreeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CategoryTreeRequest) ProtoMessage() {} + +func (x *CategoryTreeRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CategoryTreeRequest.ProtoReflect.Descriptor instead. +func (*CategoryTreeRequest) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{14} +} + +func (x *CategoryTreeRequest) GetIncludeCount() bool { + if x != nil { + return x.IncludeCount + } + return false +} + +type CategoryTreeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Categories []*CategoryNode `protobuf:"bytes,1,rep,name=categories,proto3" json:"categories,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CategoryTreeResponse) Reset() { + *x = CategoryTreeResponse{} + mi := &file_rpc_gallery_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CategoryTreeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CategoryTreeResponse) ProtoMessage() {} + +func (x *CategoryTreeResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CategoryTreeResponse.ProtoReflect.Descriptor instead. +func (*CategoryTreeResponse) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{15} +} + +func (x *CategoryTreeResponse) GetCategories() []*CategoryNode { + if x != nil { + return x.Categories + } + return nil +} + +type CreateCategoryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + ParentId string `protobuf:"bytes,2,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateCategoryRequest) Reset() { + *x = CreateCategoryRequest{} + mi := &file_rpc_gallery_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateCategoryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateCategoryRequest) ProtoMessage() {} + +func (x *CreateCategoryRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateCategoryRequest.ProtoReflect.Descriptor instead. +func (*CreateCategoryRequest) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{16} +} + +func (x *CreateCategoryRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CreateCategoryRequest) GetParentId() string { + if x != nil { + return x.ParentId + } + return "" +} + +type CreateCategoryResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + CategoryId string `protobuf:"bytes,1,opt,name=category_id,json=categoryId,proto3" json:"category_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateCategoryResponse) Reset() { + *x = CreateCategoryResponse{} + mi := &file_rpc_gallery_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateCategoryResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateCategoryResponse) ProtoMessage() {} + +func (x *CreateCategoryResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateCategoryResponse.ProtoReflect.Descriptor instead. +func (*CreateCategoryResponse) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{17} +} + +func (x *CreateCategoryResponse) GetCategoryId() string { + if x != nil { + return x.CategoryId + } + return "" +} + +// URL生成 +type GenerateUrlRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ImageId string `protobuf:"bytes,1,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"` + Width *int32 `protobuf:"varint,2,opt,name=width,proto3,oneof" json:"width,omitempty"` + Height *int32 `protobuf:"varint,3,opt,name=height,proto3,oneof" json:"height,omitempty"` + Format *string `protobuf:"bytes,4,opt,name=format,proto3,oneof" json:"format,omitempty"` // webp/jpg/png + Quality *int32 `protobuf:"varint,5,opt,name=quality,proto3,oneof" json:"quality,omitempty"` // 1-100 + Expires int32 `protobuf:"varint,6,opt,name=expires,proto3" json:"expires,omitempty"` // 有效期(秒) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GenerateUrlRequest) Reset() { + *x = GenerateUrlRequest{} + mi := &file_rpc_gallery_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GenerateUrlRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenerateUrlRequest) ProtoMessage() {} + +func (x *GenerateUrlRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenerateUrlRequest.ProtoReflect.Descriptor instead. +func (*GenerateUrlRequest) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{18} +} + +func (x *GenerateUrlRequest) GetImageId() string { + if x != nil { + return x.ImageId + } + return "" +} + +func (x *GenerateUrlRequest) GetWidth() int32 { + if x != nil && x.Width != nil { + return *x.Width + } + return 0 +} + +func (x *GenerateUrlRequest) GetHeight() int32 { + if x != nil && x.Height != nil { + return *x.Height + } + return 0 +} + +func (x *GenerateUrlRequest) GetFormat() string { + if x != nil && x.Format != nil { + return *x.Format + } + return "" +} + +func (x *GenerateUrlRequest) GetQuality() int32 { + if x != nil && x.Quality != nil { + return *x.Quality + } + return 0 +} + +func (x *GenerateUrlRequest) GetExpires() int32 { + if x != nil { + return x.Expires + } + return 0 +} + +type GenerateUrlResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + SignedUrl string `protobuf:"bytes,1,opt,name=signed_url,json=signedUrl,proto3" json:"signed_url,omitempty"` + ExpiresAt int64 `protobuf:"varint,2,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"` // Unix时间戳 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GenerateUrlResponse) Reset() { + *x = GenerateUrlResponse{} + mi := &file_rpc_gallery_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GenerateUrlResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenerateUrlResponse) ProtoMessage() {} + +func (x *GenerateUrlResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_gallery_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenerateUrlResponse.ProtoReflect.Descriptor instead. +func (*GenerateUrlResponse) Descriptor() ([]byte, []int) { + return file_rpc_gallery_proto_rawDescGZIP(), []int{19} +} + +func (x *GenerateUrlResponse) GetSignedUrl() string { + if x != nil { + return x.SignedUrl + } + return "" +} + +func (x *GenerateUrlResponse) GetExpiresAt() int64 { + if x != nil { + return x.ExpiresAt + } + return 0 +} + +var File_rpc_gallery_proto protoreflect.FileDescriptor + +const file_rpc_gallery_proto_rawDesc = "" + + "\n" + + "\x11rpc/gallery.proto\x12\agallery\"!\n" + + "\vPingRequest\x12\x12\n" + + "\x04ping\x18\x01 \x01(\tR\x04ping\"\"\n" + + "\fPingResponse\x12\x12\n" + + "\x04pong\x18\x01 \x01(\tR\x04pong\"\xf7\x02\n" + + "\tImageMeta\x12\x19\n" + + "\bimage_id\x18\x01 \x01(\tR\aimageId\x12\x14\n" + + "\x05title\x18\x02 \x01(\tR\x05title\x12 \n" + + "\vdescription\x18\x03 \x01(\tR\vdescription\x12\x1f\n" + + "\vcategory_id\x18\x04 \x01(\tR\n" + + "categoryId\x12\x12\n" + + "\x04tags\x18\x05 \x03(\tR\x04tags\x12\x1b\n" + + "\tfile_size\x18\x06 \x01(\x03R\bfileSize\x12\x14\n" + + "\x05width\x18\a \x01(\x05R\x05width\x12\x16\n" + + "\x06height\x18\b \x01(\x05R\x06height\x12\x1f\n" + + "\vstorage_key\x18\t \x01(\tR\n" + + "storageKey\x12\x1b\n" + + "\tfile_name\x18\n" + + " \x01(\tR\bfileName\x12\x1b\n" + + "\tmime_type\x18\v \x01(\tR\bmimeType\x12\x1d\n" + + "\n" + + "created_at\x18\f \x01(\x03R\tcreatedAt\x12\x1d\n" + + "\n" + + "updated_at\x18\r \x01(\x03R\tupdatedAt\"\x93\x01\n" + + "\x10ImageListRequest\x12\x12\n" + + "\x04page\x18\x01 \x01(\x05R\x04page\x12\x1b\n" + + "\tpage_size\x18\x02 \x01(\x05R\bpageSize\x12\x1f\n" + + "\vcategory_id\x18\x03 \x01(\tR\n" + + "categoryId\x12\x12\n" + + "\x04tags\x18\x04 \x03(\tR\x04tags\x12\x19\n" + + "\border_by\x18\x05 \x01(\tR\aorderBy\"U\n" + + "\x11ImageListResponse\x12*\n" + + "\x06images\x18\x01 \x03(\v2\x12.gallery.ImageMetaR\x06images\x12\x14\n" + + "\x05total\x18\x02 \x01(\x05R\x05total\"/\n" + + "\x12ImageDetailRequest\x12\x19\n" + + "\bimage_id\x18\x01 \x01(\tR\aimageId\"=\n" + + "\x13ImageDetailResponse\x12&\n" + + "\x04meta\x18\x01 \x01(\v2\x12.gallery.ImageMetaR\x04meta\"\xd5\x01\n" + + "\x12UpdateImageRequest\x12\x19\n" + + "\bimage_id\x18\x01 \x01(\tR\aimageId\x12\x19\n" + + "\x05title\x18\x02 \x01(\tH\x00R\x05title\x88\x01\x01\x12%\n" + + "\vdescription\x18\x03 \x01(\tH\x01R\vdescription\x88\x01\x01\x12$\n" + + "\vcategory_id\x18\x04 \x01(\tH\x02R\n" + + "categoryId\x88\x01\x01\x12\x12\n" + + "\x04tags\x18\x05 \x03(\tR\x04tagsB\b\n" + + "\x06_titleB\x0e\n" + + "\f_descriptionB\x0e\n" + + "\f_category_id\"/\n" + + "\x13UpdateImageResponse\x12\x18\n" + + "\asuccess\x18\x01 \x01(\bR\asuccess\"M\n" + + "\x12DeleteImageRequest\x12\x19\n" + + "\bimage_id\x18\x01 \x01(\tR\aimageId\x12\x1c\n" + + "\tpermanent\x18\x02 \x01(\bR\tpermanent\"/\n" + + "\x13DeleteImageResponse\x12\x18\n" + + "\asuccess\x18\x01 \x01(\bR\asuccess\"\xfa\x01\n" + + "\x12UploadImageRequest\x12!\n" + + "\ffile_content\x18\x01 \x01(\fR\vfileContent\x12\x1b\n" + + "\tfile_name\x18\x02 \x01(\tR\bfileName\x12\x19\n" + + "\x05title\x18\x03 \x01(\tH\x00R\x05title\x88\x01\x01\x12%\n" + + "\vdescription\x18\x04 \x01(\tH\x01R\vdescription\x88\x01\x01\x12$\n" + + "\vcategory_id\x18\x05 \x01(\tH\x02R\n" + + "categoryId\x88\x01\x01\x12\x12\n" + + "\x04tags\x18\x06 \x03(\tR\x04tagsB\b\n" + + "\x06_titleB\x0e\n" + + "\f_descriptionB\x0e\n" + + "\f_category_id\"i\n" + + "\x13UploadImageResponse\x121\n" + + "\n" + + "image_meta\x18\x01 \x01(\v2\x12.gallery.ImageMetaR\timageMeta\x12\x1f\n" + + "\vpreview_url\x18\x02 \x01(\tR\n" + + "previewUrl\"v\n" + + "\fCategoryNode\x12\x1f\n" + + "\vcategory_id\x18\x01 \x01(\tR\n" + + "categoryId\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x121\n" + + "\bchildren\x18\x03 \x03(\v2\x15.gallery.CategoryNodeR\bchildren\":\n" + + "\x13CategoryTreeRequest\x12#\n" + + "\rinclude_count\x18\x01 \x01(\bR\fincludeCount\"M\n" + + "\x14CategoryTreeResponse\x125\n" + + "\n" + + "categories\x18\x01 \x03(\v2\x15.gallery.CategoryNodeR\n" + + "categories\"H\n" + + "\x15CreateCategoryRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1b\n" + + "\tparent_id\x18\x02 \x01(\tR\bparentId\"9\n" + + "\x16CreateCategoryResponse\x12\x1f\n" + + "\vcategory_id\x18\x01 \x01(\tR\n" + + "categoryId\"\xe9\x01\n" + + "\x12GenerateUrlRequest\x12\x19\n" + + "\bimage_id\x18\x01 \x01(\tR\aimageId\x12\x19\n" + + "\x05width\x18\x02 \x01(\x05H\x00R\x05width\x88\x01\x01\x12\x1b\n" + + "\x06height\x18\x03 \x01(\x05H\x01R\x06height\x88\x01\x01\x12\x1b\n" + + "\x06format\x18\x04 \x01(\tH\x02R\x06format\x88\x01\x01\x12\x1d\n" + + "\aquality\x18\x05 \x01(\x05H\x03R\aquality\x88\x01\x01\x12\x18\n" + + "\aexpires\x18\x06 \x01(\x05R\aexpiresB\b\n" + + "\x06_widthB\t\n" + + "\a_heightB\t\n" + + "\a_formatB\n" + + "\n" + + "\b_quality\"S\n" + + "\x13GenerateUrlResponse\x12\x1d\n" + + "\n" + + "signed_url\x18\x01 \x01(\tR\tsignedUrl\x12\x1d\n" + + "\n" + + "expires_at\x18\x02 \x01(\x03R\texpiresAt2\x9d\x05\n" + + "\aGallery\x123\n" + + "\x04Ping\x12\x14.gallery.PingRequest\x1a\x15.gallery.PingResponse\x12E\n" + + "\fGetImageList\x12\x19.gallery.ImageListRequest\x1a\x1a.gallery.ImageListResponse\x12K\n" + + "\x0eGetImageDetail\x12\x1b.gallery.ImageDetailRequest\x1a\x1c.gallery.ImageDetailResponse\x12H\n" + + "\vUpdateImage\x12\x1b.gallery.UpdateImageRequest\x1a\x1c.gallery.UpdateImageResponse\x12H\n" + + "\vDeleteImage\x12\x1b.gallery.DeleteImageRequest\x1a\x1c.gallery.DeleteImageResponse\x12H\n" + + "\vUploadImage\x12\x1b.gallery.UploadImageRequest\x1a\x1c.gallery.UploadImageResponse\x12N\n" + + "\x0fGetCategoryTree\x12\x1c.gallery.CategoryTreeRequest\x1a\x1d.gallery.CategoryTreeResponse\x12Q\n" + + "\x0eCreateCategory\x12\x1e.gallery.CreateCategoryRequest\x1a\x1f.gallery.CreateCategoryResponse\x12H\n" + + "\vGenerateUrl\x12\x1b.gallery.GenerateUrlRequest\x1a\x1c.gallery.GenerateUrlResponseB\vZ\t./galleryb\x06proto3" + +var ( + file_rpc_gallery_proto_rawDescOnce sync.Once + file_rpc_gallery_proto_rawDescData []byte +) + +func file_rpc_gallery_proto_rawDescGZIP() []byte { + file_rpc_gallery_proto_rawDescOnce.Do(func() { + file_rpc_gallery_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_rpc_gallery_proto_rawDesc), len(file_rpc_gallery_proto_rawDesc))) + }) + return file_rpc_gallery_proto_rawDescData +} + +var file_rpc_gallery_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_rpc_gallery_proto_goTypes = []any{ + (*PingRequest)(nil), // 0: gallery.PingRequest + (*PingResponse)(nil), // 1: gallery.PingResponse + (*ImageMeta)(nil), // 2: gallery.ImageMeta + (*ImageListRequest)(nil), // 3: gallery.ImageListRequest + (*ImageListResponse)(nil), // 4: gallery.ImageListResponse + (*ImageDetailRequest)(nil), // 5: gallery.ImageDetailRequest + (*ImageDetailResponse)(nil), // 6: gallery.ImageDetailResponse + (*UpdateImageRequest)(nil), // 7: gallery.UpdateImageRequest + (*UpdateImageResponse)(nil), // 8: gallery.UpdateImageResponse + (*DeleteImageRequest)(nil), // 9: gallery.DeleteImageRequest + (*DeleteImageResponse)(nil), // 10: gallery.DeleteImageResponse + (*UploadImageRequest)(nil), // 11: gallery.UploadImageRequest + (*UploadImageResponse)(nil), // 12: gallery.UploadImageResponse + (*CategoryNode)(nil), // 13: gallery.CategoryNode + (*CategoryTreeRequest)(nil), // 14: gallery.CategoryTreeRequest + (*CategoryTreeResponse)(nil), // 15: gallery.CategoryTreeResponse + (*CreateCategoryRequest)(nil), // 16: gallery.CreateCategoryRequest + (*CreateCategoryResponse)(nil), // 17: gallery.CreateCategoryResponse + (*GenerateUrlRequest)(nil), // 18: gallery.GenerateUrlRequest + (*GenerateUrlResponse)(nil), // 19: gallery.GenerateUrlResponse +} +var file_rpc_gallery_proto_depIdxs = []int32{ + 2, // 0: gallery.ImageListResponse.images:type_name -> gallery.ImageMeta + 2, // 1: gallery.ImageDetailResponse.meta:type_name -> gallery.ImageMeta + 2, // 2: gallery.UploadImageResponse.image_meta:type_name -> gallery.ImageMeta + 13, // 3: gallery.CategoryNode.children:type_name -> gallery.CategoryNode + 13, // 4: gallery.CategoryTreeResponse.categories:type_name -> gallery.CategoryNode + 0, // 5: gallery.Gallery.Ping:input_type -> gallery.PingRequest + 3, // 6: gallery.Gallery.GetImageList:input_type -> gallery.ImageListRequest + 5, // 7: gallery.Gallery.GetImageDetail:input_type -> gallery.ImageDetailRequest + 7, // 8: gallery.Gallery.UpdateImage:input_type -> gallery.UpdateImageRequest + 9, // 9: gallery.Gallery.DeleteImage:input_type -> gallery.DeleteImageRequest + 11, // 10: gallery.Gallery.UploadImage:input_type -> gallery.UploadImageRequest + 14, // 11: gallery.Gallery.GetCategoryTree:input_type -> gallery.CategoryTreeRequest + 16, // 12: gallery.Gallery.CreateCategory:input_type -> gallery.CreateCategoryRequest + 18, // 13: gallery.Gallery.GenerateUrl:input_type -> gallery.GenerateUrlRequest + 1, // 14: gallery.Gallery.Ping:output_type -> gallery.PingResponse + 4, // 15: gallery.Gallery.GetImageList:output_type -> gallery.ImageListResponse + 6, // 16: gallery.Gallery.GetImageDetail:output_type -> gallery.ImageDetailResponse + 8, // 17: gallery.Gallery.UpdateImage:output_type -> gallery.UpdateImageResponse + 10, // 18: gallery.Gallery.DeleteImage:output_type -> gallery.DeleteImageResponse + 12, // 19: gallery.Gallery.UploadImage:output_type -> gallery.UploadImageResponse + 15, // 20: gallery.Gallery.GetCategoryTree:output_type -> gallery.CategoryTreeResponse + 17, // 21: gallery.Gallery.CreateCategory:output_type -> gallery.CreateCategoryResponse + 19, // 22: gallery.Gallery.GenerateUrl:output_type -> gallery.GenerateUrlResponse + 14, // [14:23] is the sub-list for method output_type + 5, // [5:14] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_rpc_gallery_proto_init() } +func file_rpc_gallery_proto_init() { + if File_rpc_gallery_proto != nil { + return + } + file_rpc_gallery_proto_msgTypes[7].OneofWrappers = []any{} + file_rpc_gallery_proto_msgTypes[11].OneofWrappers = []any{} + file_rpc_gallery_proto_msgTypes[18].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_rpc_gallery_proto_rawDesc), len(file_rpc_gallery_proto_rawDesc)), + NumEnums: 0, + NumMessages: 20, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_rpc_gallery_proto_goTypes, + DependencyIndexes: file_rpc_gallery_proto_depIdxs, + MessageInfos: file_rpc_gallery_proto_msgTypes, + }.Build() + File_rpc_gallery_proto = out.File + file_rpc_gallery_proto_goTypes = nil + file_rpc_gallery_proto_depIdxs = nil +} diff --git a/gallery/gallery/gallery_grpc.pb.go b/gallery/gallery/gallery_grpc.pb.go new file mode 100644 index 0000000..3e48ce4 --- /dev/null +++ b/gallery/gallery/gallery_grpc.pb.go @@ -0,0 +1,435 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v3.19.4 +// source: rpc/gallery.proto + +package gallery + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Gallery_Ping_FullMethodName = "/gallery.Gallery/Ping" + Gallery_GetImageList_FullMethodName = "/gallery.Gallery/GetImageList" + Gallery_GetImageDetail_FullMethodName = "/gallery.Gallery/GetImageDetail" + Gallery_UpdateImage_FullMethodName = "/gallery.Gallery/UpdateImage" + Gallery_DeleteImage_FullMethodName = "/gallery.Gallery/DeleteImage" + Gallery_UploadImage_FullMethodName = "/gallery.Gallery/UploadImage" + Gallery_GetCategoryTree_FullMethodName = "/gallery.Gallery/GetCategoryTree" + Gallery_CreateCategory_FullMethodName = "/gallery.Gallery/CreateCategory" + Gallery_GenerateUrl_FullMethodName = "/gallery.Gallery/GenerateUrl" +) + +// GalleryClient is the client API for Gallery service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type GalleryClient interface { + // 健康检查 + Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) + // 图片元数据操作 + GetImageList(ctx context.Context, in *ImageListRequest, opts ...grpc.CallOption) (*ImageListResponse, error) + GetImageDetail(ctx context.Context, in *ImageDetailRequest, opts ...grpc.CallOption) (*ImageDetailResponse, error) + UpdateImage(ctx context.Context, in *UpdateImageRequest, opts ...grpc.CallOption) (*UpdateImageResponse, error) + DeleteImage(ctx context.Context, in *DeleteImageRequest, opts ...grpc.CallOption) (*DeleteImageResponse, error) + // 图片上传 + UploadImage(ctx context.Context, in *UploadImageRequest, opts ...grpc.CallOption) (*UploadImageResponse, error) + // 分类管理 + GetCategoryTree(ctx context.Context, in *CategoryTreeRequest, opts ...grpc.CallOption) (*CategoryTreeResponse, error) + CreateCategory(ctx context.Context, in *CreateCategoryRequest, opts ...grpc.CallOption) (*CreateCategoryResponse, error) + // 访问控制 + GenerateUrl(ctx context.Context, in *GenerateUrlRequest, opts ...grpc.CallOption) (*GenerateUrlResponse, error) +} + +type galleryClient struct { + cc grpc.ClientConnInterface +} + +func NewGalleryClient(cc grpc.ClientConnInterface) GalleryClient { + return &galleryClient{cc} +} + +func (c *galleryClient) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PingResponse) + err := c.cc.Invoke(ctx, Gallery_Ping_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *galleryClient) GetImageList(ctx context.Context, in *ImageListRequest, opts ...grpc.CallOption) (*ImageListResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ImageListResponse) + err := c.cc.Invoke(ctx, Gallery_GetImageList_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *galleryClient) GetImageDetail(ctx context.Context, in *ImageDetailRequest, opts ...grpc.CallOption) (*ImageDetailResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ImageDetailResponse) + err := c.cc.Invoke(ctx, Gallery_GetImageDetail_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *galleryClient) UpdateImage(ctx context.Context, in *UpdateImageRequest, opts ...grpc.CallOption) (*UpdateImageResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateImageResponse) + err := c.cc.Invoke(ctx, Gallery_UpdateImage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *galleryClient) DeleteImage(ctx context.Context, in *DeleteImageRequest, opts ...grpc.CallOption) (*DeleteImageResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteImageResponse) + err := c.cc.Invoke(ctx, Gallery_DeleteImage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *galleryClient) UploadImage(ctx context.Context, in *UploadImageRequest, opts ...grpc.CallOption) (*UploadImageResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UploadImageResponse) + err := c.cc.Invoke(ctx, Gallery_UploadImage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *galleryClient) GetCategoryTree(ctx context.Context, in *CategoryTreeRequest, opts ...grpc.CallOption) (*CategoryTreeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CategoryTreeResponse) + err := c.cc.Invoke(ctx, Gallery_GetCategoryTree_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *galleryClient) CreateCategory(ctx context.Context, in *CreateCategoryRequest, opts ...grpc.CallOption) (*CreateCategoryResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateCategoryResponse) + err := c.cc.Invoke(ctx, Gallery_CreateCategory_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *galleryClient) GenerateUrl(ctx context.Context, in *GenerateUrlRequest, opts ...grpc.CallOption) (*GenerateUrlResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GenerateUrlResponse) + err := c.cc.Invoke(ctx, Gallery_GenerateUrl_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// GalleryServer is the server API for Gallery service. +// All implementations must embed UnimplementedGalleryServer +// for forward compatibility. +type GalleryServer interface { + // 健康检查 + Ping(context.Context, *PingRequest) (*PingResponse, error) + // 图片元数据操作 + GetImageList(context.Context, *ImageListRequest) (*ImageListResponse, error) + GetImageDetail(context.Context, *ImageDetailRequest) (*ImageDetailResponse, error) + UpdateImage(context.Context, *UpdateImageRequest) (*UpdateImageResponse, error) + DeleteImage(context.Context, *DeleteImageRequest) (*DeleteImageResponse, error) + // 图片上传 + UploadImage(context.Context, *UploadImageRequest) (*UploadImageResponse, error) + // 分类管理 + GetCategoryTree(context.Context, *CategoryTreeRequest) (*CategoryTreeResponse, error) + CreateCategory(context.Context, *CreateCategoryRequest) (*CreateCategoryResponse, error) + // 访问控制 + GenerateUrl(context.Context, *GenerateUrlRequest) (*GenerateUrlResponse, error) + mustEmbedUnimplementedGalleryServer() +} + +// UnimplementedGalleryServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedGalleryServer struct{} + +func (UnimplementedGalleryServer) Ping(context.Context, *PingRequest) (*PingResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented") +} +func (UnimplementedGalleryServer) GetImageList(context.Context, *ImageListRequest) (*ImageListResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetImageList not implemented") +} +func (UnimplementedGalleryServer) GetImageDetail(context.Context, *ImageDetailRequest) (*ImageDetailResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetImageDetail not implemented") +} +func (UnimplementedGalleryServer) UpdateImage(context.Context, *UpdateImageRequest) (*UpdateImageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateImage not implemented") +} +func (UnimplementedGalleryServer) DeleteImage(context.Context, *DeleteImageRequest) (*DeleteImageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteImage not implemented") +} +func (UnimplementedGalleryServer) UploadImage(context.Context, *UploadImageRequest) (*UploadImageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UploadImage not implemented") +} +func (UnimplementedGalleryServer) GetCategoryTree(context.Context, *CategoryTreeRequest) (*CategoryTreeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetCategoryTree not implemented") +} +func (UnimplementedGalleryServer) CreateCategory(context.Context, *CreateCategoryRequest) (*CreateCategoryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateCategory not implemented") +} +func (UnimplementedGalleryServer) GenerateUrl(context.Context, *GenerateUrlRequest) (*GenerateUrlResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GenerateUrl not implemented") +} +func (UnimplementedGalleryServer) mustEmbedUnimplementedGalleryServer() {} +func (UnimplementedGalleryServer) testEmbeddedByValue() {} + +// UnsafeGalleryServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to GalleryServer will +// result in compilation errors. +type UnsafeGalleryServer interface { + mustEmbedUnimplementedGalleryServer() +} + +func RegisterGalleryServer(s grpc.ServiceRegistrar, srv GalleryServer) { + // If the following call pancis, it indicates UnimplementedGalleryServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Gallery_ServiceDesc, srv) +} + +func _Gallery_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PingRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GalleryServer).Ping(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Gallery_Ping_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GalleryServer).Ping(ctx, req.(*PingRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Gallery_GetImageList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ImageListRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GalleryServer).GetImageList(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Gallery_GetImageList_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GalleryServer).GetImageList(ctx, req.(*ImageListRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Gallery_GetImageDetail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ImageDetailRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GalleryServer).GetImageDetail(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Gallery_GetImageDetail_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GalleryServer).GetImageDetail(ctx, req.(*ImageDetailRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Gallery_UpdateImage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateImageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GalleryServer).UpdateImage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Gallery_UpdateImage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GalleryServer).UpdateImage(ctx, req.(*UpdateImageRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Gallery_DeleteImage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteImageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GalleryServer).DeleteImage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Gallery_DeleteImage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GalleryServer).DeleteImage(ctx, req.(*DeleteImageRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Gallery_UploadImage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UploadImageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GalleryServer).UploadImage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Gallery_UploadImage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GalleryServer).UploadImage(ctx, req.(*UploadImageRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Gallery_GetCategoryTree_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CategoryTreeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GalleryServer).GetCategoryTree(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Gallery_GetCategoryTree_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GalleryServer).GetCategoryTree(ctx, req.(*CategoryTreeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Gallery_CreateCategory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateCategoryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GalleryServer).CreateCategory(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Gallery_CreateCategory_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GalleryServer).CreateCategory(ctx, req.(*CreateCategoryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Gallery_GenerateUrl_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GenerateUrlRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GalleryServer).GenerateUrl(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Gallery_GenerateUrl_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GalleryServer).GenerateUrl(ctx, req.(*GenerateUrlRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Gallery_ServiceDesc is the grpc.ServiceDesc for Gallery service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Gallery_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "gallery.Gallery", + HandlerType: (*GalleryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Ping", + Handler: _Gallery_Ping_Handler, + }, + { + MethodName: "GetImageList", + Handler: _Gallery_GetImageList_Handler, + }, + { + MethodName: "GetImageDetail", + Handler: _Gallery_GetImageDetail_Handler, + }, + { + MethodName: "UpdateImage", + Handler: _Gallery_UpdateImage_Handler, + }, + { + MethodName: "DeleteImage", + Handler: _Gallery_DeleteImage_Handler, + }, + { + MethodName: "UploadImage", + Handler: _Gallery_UploadImage_Handler, + }, + { + MethodName: "GetCategoryTree", + Handler: _Gallery_GetCategoryTree_Handler, + }, + { + MethodName: "CreateCategory", + Handler: _Gallery_CreateCategory_Handler, + }, + { + MethodName: "GenerateUrl", + Handler: _Gallery_GenerateUrl_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "rpc/gallery.proto", +} diff --git a/gallery/galleryclient/gallery.go b/gallery/galleryclient/gallery.go new file mode 100644 index 0000000..995e445 --- /dev/null +++ b/gallery/galleryclient/gallery.go @@ -0,0 +1,114 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.8.3 +// Source: gallery.proto + +package galleryclient + +import ( + "context" + + "godemo/gallery/gallery" + + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" +) + +type ( + CategoryNode = gallery.CategoryNode + CategoryTreeRequest = gallery.CategoryTreeRequest + CategoryTreeResponse = gallery.CategoryTreeResponse + CreateCategoryRequest = gallery.CreateCategoryRequest + CreateCategoryResponse = gallery.CreateCategoryResponse + DeleteImageRequest = gallery.DeleteImageRequest + DeleteImageResponse = gallery.DeleteImageResponse + GenerateUrlRequest = gallery.GenerateUrlRequest + GenerateUrlResponse = gallery.GenerateUrlResponse + ImageDetailRequest = gallery.ImageDetailRequest + ImageDetailResponse = gallery.ImageDetailResponse + ImageListRequest = gallery.ImageListRequest + ImageListResponse = gallery.ImageListResponse + ImageMeta = gallery.ImageMeta + PingRequest = gallery.PingRequest + PingResponse = gallery.PingResponse + UpdateImageRequest = gallery.UpdateImageRequest + UpdateImageResponse = gallery.UpdateImageResponse + UploadImageRequest = gallery.UploadImageRequest + UploadImageResponse = gallery.UploadImageResponse + + Gallery interface { + // 健康检查 + Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) + // 图片元数据操作 + GetImageList(ctx context.Context, in *ImageListRequest, opts ...grpc.CallOption) (*ImageListResponse, error) + GetImageDetail(ctx context.Context, in *ImageDetailRequest, opts ...grpc.CallOption) (*ImageDetailResponse, error) + UpdateImage(ctx context.Context, in *UpdateImageRequest, opts ...grpc.CallOption) (*UpdateImageResponse, error) + DeleteImage(ctx context.Context, in *DeleteImageRequest, opts ...grpc.CallOption) (*DeleteImageResponse, error) + // 图片上传 + UploadImage(ctx context.Context, in *UploadImageRequest, opts ...grpc.CallOption) (*UploadImageResponse, error) + // 分类管理 + GetCategoryTree(ctx context.Context, in *CategoryTreeRequest, opts ...grpc.CallOption) (*CategoryTreeResponse, error) + CreateCategory(ctx context.Context, in *CreateCategoryRequest, opts ...grpc.CallOption) (*CreateCategoryResponse, error) + // 访问控制 + GenerateUrl(ctx context.Context, in *GenerateUrlRequest, opts ...grpc.CallOption) (*GenerateUrlResponse, error) + } + + defaultGallery struct { + cli zrpc.Client + } +) + +func NewGallery(cli zrpc.Client) Gallery { + return &defaultGallery{ + cli: cli, + } +} + +// 健康检查 +func (m *defaultGallery) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) { + client := gallery.NewGalleryClient(m.cli.Conn()) + return client.Ping(ctx, in, opts...) +} + +// 图片元数据操作 +func (m *defaultGallery) GetImageList(ctx context.Context, in *ImageListRequest, opts ...grpc.CallOption) (*ImageListResponse, error) { + client := gallery.NewGalleryClient(m.cli.Conn()) + return client.GetImageList(ctx, in, opts...) +} + +func (m *defaultGallery) GetImageDetail(ctx context.Context, in *ImageDetailRequest, opts ...grpc.CallOption) (*ImageDetailResponse, error) { + client := gallery.NewGalleryClient(m.cli.Conn()) + return client.GetImageDetail(ctx, in, opts...) +} + +func (m *defaultGallery) UpdateImage(ctx context.Context, in *UpdateImageRequest, opts ...grpc.CallOption) (*UpdateImageResponse, error) { + client := gallery.NewGalleryClient(m.cli.Conn()) + return client.UpdateImage(ctx, in, opts...) +} + +func (m *defaultGallery) DeleteImage(ctx context.Context, in *DeleteImageRequest, opts ...grpc.CallOption) (*DeleteImageResponse, error) { + client := gallery.NewGalleryClient(m.cli.Conn()) + return client.DeleteImage(ctx, in, opts...) +} + +// 图片上传 +func (m *defaultGallery) UploadImage(ctx context.Context, in *UploadImageRequest, opts ...grpc.CallOption) (*UploadImageResponse, error) { + client := gallery.NewGalleryClient(m.cli.Conn()) + return client.UploadImage(ctx, in, opts...) +} + +// 分类管理 +func (m *defaultGallery) GetCategoryTree(ctx context.Context, in *CategoryTreeRequest, opts ...grpc.CallOption) (*CategoryTreeResponse, error) { + client := gallery.NewGalleryClient(m.cli.Conn()) + return client.GetCategoryTree(ctx, in, opts...) +} + +func (m *defaultGallery) CreateCategory(ctx context.Context, in *CreateCategoryRequest, opts ...grpc.CallOption) (*CreateCategoryResponse, error) { + client := gallery.NewGalleryClient(m.cli.Conn()) + return client.CreateCategory(ctx, in, opts...) +} + +// 访问控制 +func (m *defaultGallery) GenerateUrl(ctx context.Context, in *GenerateUrlRequest, opts ...grpc.CallOption) (*GenerateUrlResponse, error) { + client := gallery.NewGalleryClient(m.cli.Conn()) + return client.GenerateUrl(ctx, in, opts...) +} diff --git a/gallery/internal/config/config.go b/gallery/internal/config/config.go new file mode 100644 index 0000000..41cf205 --- /dev/null +++ b/gallery/internal/config/config.go @@ -0,0 +1,8 @@ +package config + +import "github.com/zeromicro/go-zero/zrpc" + +type Config struct { + zrpc.RpcServerConf + FileRpc zrpc.RpcClientConf +} diff --git a/gallery/internal/logic/createcategorylogic.go b/gallery/internal/logic/createcategorylogic.go new file mode 100644 index 0000000..fc2919d --- /dev/null +++ b/gallery/internal/logic/createcategorylogic.go @@ -0,0 +1,30 @@ +package logic + +import ( + "context" + + "godemo/gallery/gallery" + "godemo/gallery/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type CreateCategoryLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewCreateCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateCategoryLogic { + return &CreateCategoryLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *CreateCategoryLogic) CreateCategory(in *gallery.CreateCategoryRequest) (*gallery.CreateCategoryResponse, error) { + // todo: add your logic here and delete this line + + return &gallery.CreateCategoryResponse{}, nil +} diff --git a/gallery/internal/logic/deleteimagelogic.go b/gallery/internal/logic/deleteimagelogic.go new file mode 100644 index 0000000..3c071f4 --- /dev/null +++ b/gallery/internal/logic/deleteimagelogic.go @@ -0,0 +1,30 @@ +package logic + +import ( + "context" + + "godemo/gallery/gallery" + "godemo/gallery/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type DeleteImageLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewDeleteImageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteImageLogic { + return &DeleteImageLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *DeleteImageLogic) DeleteImage(in *gallery.DeleteImageRequest) (*gallery.DeleteImageResponse, error) { + // todo: add your logic here and delete this line + + return &gallery.DeleteImageResponse{}, nil +} diff --git a/gallery/internal/logic/generateurllogic.go b/gallery/internal/logic/generateurllogic.go new file mode 100644 index 0000000..f9b806e --- /dev/null +++ b/gallery/internal/logic/generateurllogic.go @@ -0,0 +1,31 @@ +package logic + +import ( + "context" + + "godemo/gallery/gallery" + "godemo/gallery/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GenerateUrlLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGenerateUrlLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GenerateUrlLogic { + return &GenerateUrlLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 访问控制 +func (l *GenerateUrlLogic) GenerateUrl(in *gallery.GenerateUrlRequest) (*gallery.GenerateUrlResponse, error) { + // todo: add your logic here and delete this line + + return &gallery.GenerateUrlResponse{}, nil +} diff --git a/gallery/internal/logic/getcategorytreelogic.go b/gallery/internal/logic/getcategorytreelogic.go new file mode 100644 index 0000000..cb28fd6 --- /dev/null +++ b/gallery/internal/logic/getcategorytreelogic.go @@ -0,0 +1,31 @@ +package logic + +import ( + "context" + + "godemo/gallery/gallery" + "godemo/gallery/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetCategoryTreeLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGetCategoryTreeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetCategoryTreeLogic { + return &GetCategoryTreeLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 分类管理 +func (l *GetCategoryTreeLogic) GetCategoryTree(in *gallery.CategoryTreeRequest) (*gallery.CategoryTreeResponse, error) { + // todo: add your logic here and delete this line + + return &gallery.CategoryTreeResponse{}, nil +} diff --git a/gallery/internal/logic/getimagedetaillogic.go b/gallery/internal/logic/getimagedetaillogic.go new file mode 100644 index 0000000..2128703 --- /dev/null +++ b/gallery/internal/logic/getimagedetaillogic.go @@ -0,0 +1,30 @@ +package logic + +import ( + "context" + + "godemo/gallery/gallery" + "godemo/gallery/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetImageDetailLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGetImageDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetImageDetailLogic { + return &GetImageDetailLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *GetImageDetailLogic) GetImageDetail(in *gallery.ImageDetailRequest) (*gallery.ImageDetailResponse, error) { + // todo: add your logic here and delete this line + + return &gallery.ImageDetailResponse{}, nil +} diff --git a/gallery/internal/logic/getimagelistlogic.go b/gallery/internal/logic/getimagelistlogic.go new file mode 100644 index 0000000..1792900 --- /dev/null +++ b/gallery/internal/logic/getimagelistlogic.go @@ -0,0 +1,31 @@ +package logic + +import ( + "context" + + "godemo/gallery/gallery" + "godemo/gallery/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetImageListLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGetImageListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetImageListLogic { + return &GetImageListLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 图片元数据操作 +func (l *GetImageListLogic) GetImageList(in *gallery.ImageListRequest) (*gallery.ImageListResponse, error) { + // todo: add your logic here and delete this line + + return &gallery.ImageListResponse{}, nil +} diff --git a/gallery/internal/logic/pinglogic.go b/gallery/internal/logic/pinglogic.go new file mode 100644 index 0000000..d7241cd --- /dev/null +++ b/gallery/internal/logic/pinglogic.go @@ -0,0 +1,31 @@ +package logic + +import ( + "context" + + "godemo/gallery/gallery" + "godemo/gallery/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type PingLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewPingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PingLogic { + return &PingLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 健康检查 +func (l *PingLogic) Ping(in *gallery.PingRequest) (*gallery.PingResponse, error) { + // todo: add your logic here and delete this line + + return &gallery.PingResponse{}, nil +} diff --git a/gallery/internal/logic/updateimagelogic.go b/gallery/internal/logic/updateimagelogic.go new file mode 100644 index 0000000..b88916b --- /dev/null +++ b/gallery/internal/logic/updateimagelogic.go @@ -0,0 +1,30 @@ +package logic + +import ( + "context" + + "godemo/gallery/gallery" + "godemo/gallery/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type UpdateImageLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewUpdateImageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateImageLogic { + return &UpdateImageLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *UpdateImageLogic) UpdateImage(in *gallery.UpdateImageRequest) (*gallery.UpdateImageResponse, error) { + // todo: add your logic here and delete this line + + return &gallery.UpdateImageResponse{}, nil +} diff --git a/gallery/internal/logic/uploadimagelogic.go b/gallery/internal/logic/uploadimagelogic.go new file mode 100644 index 0000000..fb6f629 --- /dev/null +++ b/gallery/internal/logic/uploadimagelogic.go @@ -0,0 +1,43 @@ +package logic + +import ( + "context" + + "godemo/file/file" + "godemo/gallery/gallery" + "godemo/gallery/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type UploadImageLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewUploadImageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadImageLogic { + return &UploadImageLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 图片上传 +func (l *UploadImageLogic) UploadImage(in *gallery.UploadImageRequest) (*gallery.UploadImageResponse, error) { + // 1. 根据 in.CategoryId 查询分类信息,获取分类名称 + var categoryName string + + // 2. 调用 file rpc Upload 接口,上传文件到MinIO + l.svcCtx.FileRpc.Upload(l.ctx, &file.UploadRequest{ + Filename: in.FileName, + Content: in.FileContent, + Folder: categoryName, + }) + + // 3. 图片信息存入数据库 + + // 4. 返回接口执行结果 + return &gallery.UploadImageResponse{}, nil +} diff --git a/gallery/internal/server/galleryserver.go b/gallery/internal/server/galleryserver.go new file mode 100644 index 0000000..26e1d74 --- /dev/null +++ b/gallery/internal/server/galleryserver.go @@ -0,0 +1,74 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.8.3 +// Source: gallery.proto + +package server + +import ( + "context" + + "godemo/gallery/gallery" + "godemo/gallery/internal/logic" + "godemo/gallery/internal/svc" +) + +type GalleryServer struct { + svcCtx *svc.ServiceContext + gallery.UnimplementedGalleryServer +} + +func NewGalleryServer(svcCtx *svc.ServiceContext) *GalleryServer { + return &GalleryServer{ + svcCtx: svcCtx, + } +} + +// 健康检查 +func (s *GalleryServer) Ping(ctx context.Context, in *gallery.PingRequest) (*gallery.PingResponse, error) { + l := logic.NewPingLogic(ctx, s.svcCtx) + return l.Ping(in) +} + +// 图片元数据操作 +func (s *GalleryServer) GetImageList(ctx context.Context, in *gallery.ImageListRequest) (*gallery.ImageListResponse, error) { + l := logic.NewGetImageListLogic(ctx, s.svcCtx) + return l.GetImageList(in) +} + +func (s *GalleryServer) GetImageDetail(ctx context.Context, in *gallery.ImageDetailRequest) (*gallery.ImageDetailResponse, error) { + l := logic.NewGetImageDetailLogic(ctx, s.svcCtx) + return l.GetImageDetail(in) +} + +func (s *GalleryServer) UpdateImage(ctx context.Context, in *gallery.UpdateImageRequest) (*gallery.UpdateImageResponse, error) { + l := logic.NewUpdateImageLogic(ctx, s.svcCtx) + return l.UpdateImage(in) +} + +func (s *GalleryServer) DeleteImage(ctx context.Context, in *gallery.DeleteImageRequest) (*gallery.DeleteImageResponse, error) { + l := logic.NewDeleteImageLogic(ctx, s.svcCtx) + return l.DeleteImage(in) +} + +// 图片上传 +func (s *GalleryServer) UploadImage(ctx context.Context, in *gallery.UploadImageRequest) (*gallery.UploadImageResponse, error) { + l := logic.NewUploadImageLogic(ctx, s.svcCtx) + return l.UploadImage(in) +} + +// 分类管理 +func (s *GalleryServer) GetCategoryTree(ctx context.Context, in *gallery.CategoryTreeRequest) (*gallery.CategoryTreeResponse, error) { + l := logic.NewGetCategoryTreeLogic(ctx, s.svcCtx) + return l.GetCategoryTree(in) +} + +func (s *GalleryServer) CreateCategory(ctx context.Context, in *gallery.CreateCategoryRequest) (*gallery.CreateCategoryResponse, error) { + l := logic.NewCreateCategoryLogic(ctx, s.svcCtx) + return l.CreateCategory(in) +} + +// 访问控制 +func (s *GalleryServer) GenerateUrl(ctx context.Context, in *gallery.GenerateUrlRequest) (*gallery.GenerateUrlResponse, error) { + l := logic.NewGenerateUrlLogic(ctx, s.svcCtx) + return l.GenerateUrl(in) +} diff --git a/gallery/internal/svc/servicecontext.go b/gallery/internal/svc/servicecontext.go new file mode 100644 index 0000000..c649b94 --- /dev/null +++ b/gallery/internal/svc/servicecontext.go @@ -0,0 +1,21 @@ +package svc + +import ( + "godemo/file/file" + "godemo/gallery/internal/config" + + "github.com/zeromicro/go-zero/zrpc" +) + +type ServiceContext struct { + Config config.Config + FileRpc file.FileClient +} + +func NewServiceContext(c config.Config) *ServiceContext { + conn := zrpc.MustNewClient(c.FileRpc).Conn() + return &ServiceContext{ + Config: c, + FileRpc: file.NewFileClient(conn), + } +} diff --git a/gateway/etc/gateway-api.yaml b/gateway/etc/gateway-api.yaml new file mode 100644 index 0000000..f67dd25 --- /dev/null +++ b/gateway/etc/gateway-api.yaml @@ -0,0 +1,13 @@ +Name: gateway-api +Host: 0.0.0.0 +Port: 60000 + +JwtAuth: + AccessSecret: "your-secure-secret" + AccessExpire: 900 # 可选,单位秒,15分钟 + +UserRpc: + Etcd: + Hosts: + - 127.0.0.1:2379 + Key: user.rpc \ No newline at end of file diff --git a/gateway/gateway.go b/gateway/gateway.go new file mode 100644 index 0000000..56fcca2 --- /dev/null +++ b/gateway/gateway.go @@ -0,0 +1,31 @@ +package main + +import ( + "flag" + "fmt" + + "godemo/gateway/internal/config" + "godemo/gateway/internal/handler" + "godemo/gateway/internal/svc" + + "github.com/zeromicro/go-zero/core/conf" + "github.com/zeromicro/go-zero/rest" +) + +var configFile = flag.String("f", "etc/gateway-api.yaml", "the config file") + +func main() { + flag.Parse() + + var c config.Config + conf.MustLoad(*configFile, &c) + + server := rest.MustNewServer(c.RestConf) + defer server.Stop() + + ctx := svc.NewServiceContext(c) + handler.RegisterHandlers(server, ctx) + + fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) + server.Start() +} diff --git a/gateway/internal/config/config.go b/gateway/internal/config/config.go new file mode 100644 index 0000000..325da65 --- /dev/null +++ b/gateway/internal/config/config.go @@ -0,0 +1,15 @@ +package config + +import ( + "github.com/zeromicro/go-zero/rest" + "github.com/zeromicro/go-zero/zrpc" +) + +type Config struct { + rest.RestConf + JwtAuth struct { + AccessSecret string + AccessExpire int64 + } + UserRpc zrpc.RpcClientConf +} diff --git a/gateway/internal/handler/getuserinfohandler.go b/gateway/internal/handler/getuserinfohandler.go new file mode 100644 index 0000000..1ed2d1f --- /dev/null +++ b/gateway/internal/handler/getuserinfohandler.go @@ -0,0 +1,28 @@ +package handler + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "godemo/gateway/internal/logic" + "godemo/gateway/internal/svc" + "godemo/gateway/internal/types" +) + +func getUserInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.GetUserInfoReq + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := logic.NewGetUserInfoLogic(r.Context(), svcCtx) + resp, err := l.GetUserInfo(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/gateway/internal/handler/loginhandler.go b/gateway/internal/handler/loginhandler.go new file mode 100644 index 0000000..e5ec8df --- /dev/null +++ b/gateway/internal/handler/loginhandler.go @@ -0,0 +1,51 @@ +package handler + +import ( + "net/http" + + "godemo/gateway/internal/logic" + "godemo/gateway/internal/svc" + "godemo/gateway/internal/types" + + "github.com/zeromicro/go-zero/rest/httpx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func loginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.LoginReq + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := logic.NewLoginLogic(r.Context(), svcCtx) + resp, err := l.Login(&req) + + if err != nil { + if s, ok := status.FromError(err); ok { + // 判断 gRPC 错误码,并自定义 HTTP 返回 + var code int + switch s.Code() { + case codes.NotFound: + code = http.StatusNotFound + case codes.InvalidArgument: + code = http.StatusBadRequest + default: + code = http.StatusInternalServerError + } + + // 自定义 JSON 错误格式 + httpx.WriteJson(w, code, map[string]interface{}{ + "code": code, + "message": s.Message(), + }) + } else { + httpx.ErrorCtx(r.Context(), w, err) + } + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/gateway/internal/handler/logouthandler.go b/gateway/internal/handler/logouthandler.go new file mode 100644 index 0000000..96ae328 --- /dev/null +++ b/gateway/internal/handler/logouthandler.go @@ -0,0 +1,28 @@ +package handler + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "godemo/gateway/internal/logic" + "godemo/gateway/internal/svc" + "godemo/gateway/internal/types" +) + +func logoutHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.LogoutReq + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := logic.NewLogoutLogic(r.Context(), svcCtx) + resp, err := l.Logout(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/gateway/internal/handler/registerhandler.go b/gateway/internal/handler/registerhandler.go new file mode 100644 index 0000000..e46f7cd --- /dev/null +++ b/gateway/internal/handler/registerhandler.go @@ -0,0 +1,28 @@ +package handler + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "godemo/gateway/internal/logic" + "godemo/gateway/internal/svc" + "godemo/gateway/internal/types" +) + +func registerHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.RegisterReq + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := logic.NewRegisterLogic(r.Context(), svcCtx) + resp, err := l.Register(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/gateway/internal/handler/routes.go b/gateway/internal/handler/routes.go new file mode 100644 index 0000000..cf880f1 --- /dev/null +++ b/gateway/internal/handler/routes.go @@ -0,0 +1,45 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.8.3 + +package handler + +import ( + "net/http" + + "godemo/gateway/internal/svc" + + "github.com/zeromicro/go-zero/rest" +) + +func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { + server.AddRoutes( + []rest.Route{ + { + Method: http.MethodPost, + Path: "/api/user/login", + Handler: loginHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/api/user/register", + Handler: registerHandler(serverCtx), + }, + }, + ) + + server.AddRoutes( + []rest.Route{ + { + Method: http.MethodGet, + Path: "/api/user/:user_id", + Handler: getUserInfoHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/api/user/logout", + Handler: logoutHandler(serverCtx), + }, + }, + rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret), + ) +} diff --git a/gateway/internal/logic/getuserinfologic.go b/gateway/internal/logic/getuserinfologic.go new file mode 100644 index 0000000..ddb0709 --- /dev/null +++ b/gateway/internal/logic/getuserinfologic.go @@ -0,0 +1,45 @@ +package logic + +import ( + "context" + + "godemo/gateway/internal/svc" + "godemo/gateway/internal/types" + "godemo/user/user" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetUserInfoLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewGetUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserInfoLogic { + return &GetUserInfoLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetUserInfoLogic) GetUserInfo(req *types.GetUserInfoReq) (resp *types.GetUserInfoResp, err error) { + // todo: add your logic here and delete this line + rpcResp, err := l.svcCtx.UserRpc.GetUserInfo(l.ctx, &user.GetUserInfoRequest{ + UserId: req.UserId, + }) + if err != nil { + return nil, err + } + + // 构造 API 返回值 + resp = &types.GetUserInfoResp{ + UserId: rpcResp.UserId, + Username: rpcResp.Username, + Email: rpcResp.Email, + CreatedAt: rpcResp.CreatedAt, + Roles: rpcResp.Roles, + } + return +} diff --git a/gateway/internal/logic/loginlogic.go b/gateway/internal/logic/loginlogic.go new file mode 100644 index 0000000..98a8882 --- /dev/null +++ b/gateway/internal/logic/loginlogic.go @@ -0,0 +1,43 @@ +package logic + +import ( + "context" + + "godemo/gateway/internal/svc" + "godemo/gateway/internal/types" + "godemo/user/user" + + "github.com/zeromicro/go-zero/core/logx" +) + +type LoginLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic { + return &LoginLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.LoginResp, err error) { + // 调用 user RPC 的 Login 方法 + rpcResp, err := l.svcCtx.UserRpc.Login(l.ctx, &user.LoginRequest{ + Username: req.Username, + Password: req.Password, + }) + if err != nil { + return nil, err + } + + // 构造 API 返回值 + resp = &types.LoginResp{ + Token: rpcResp.Token, + ExpiresAt: rpcResp.ExpiresAt, + } + return +} diff --git a/gateway/internal/logic/logoutlogic.go b/gateway/internal/logic/logoutlogic.go new file mode 100644 index 0000000..ea25951 --- /dev/null +++ b/gateway/internal/logic/logoutlogic.go @@ -0,0 +1,30 @@ +package logic + +import ( + "context" + + "godemo/gateway/internal/svc" + "godemo/gateway/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type LogoutLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewLogoutLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LogoutLogic { + return &LogoutLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *LogoutLogic) Logout(req *types.LogoutReq) (resp *types.LogoutResp, err error) { + // todo: add your logic here and delete this line + + return +} diff --git a/gateway/internal/logic/registerlogic.go b/gateway/internal/logic/registerlogic.go new file mode 100644 index 0000000..5412bf4 --- /dev/null +++ b/gateway/internal/logic/registerlogic.go @@ -0,0 +1,40 @@ +package logic + +import ( + "context" + + "godemo/gateway/internal/svc" + "godemo/gateway/internal/types" + "godemo/user/user" + + "github.com/zeromicro/go-zero/core/logx" +) + +type RegisterLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterLogic { + return &RegisterLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *RegisterLogic) Register(req *types.RegisterReq) (resp *types.RegisterResp, err error) { + rpcResp, err := l.svcCtx.UserRpc.Register(l.ctx, &user.RegisterRequest{ + Email: req.Email, + Password: req.Password, + Username: req.Username, + }) + if err != nil { + return nil, err + } + resp = &types.RegisterResp{ + UserId: rpcResp.UserId, + } + return +} diff --git a/gateway/internal/svc/servicecontext.go b/gateway/internal/svc/servicecontext.go new file mode 100644 index 0000000..e02c900 --- /dev/null +++ b/gateway/internal/svc/servicecontext.go @@ -0,0 +1,21 @@ +package svc + +import ( + "godemo/gateway/internal/config" + "godemo/user/user" + + "github.com/zeromicro/go-zero/zrpc" +) + +type ServiceContext struct { + Config config.Config + UserRpc user.UserClient +} + +func NewServiceContext(c config.Config) *ServiceContext { + conn := zrpc.MustNewClient(c.UserRpc).Conn() + return &ServiceContext{ + Config: c, + UserRpc: user.NewUserClient(conn), + } +} diff --git a/gateway/internal/types/types.go b/gateway/internal/types/types.go new file mode 100644 index 0000000..de9d39c --- /dev/null +++ b/gateway/internal/types/types.go @@ -0,0 +1,44 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.8.3 + +package types + +type GetUserInfoReq struct { + UserId string `path:"user_id"` +} + +type GetUserInfoResp struct { + UserId string `json:"user_id"` + Username string `json:"username"` + Email string `json:"email"` + CreatedAt int64 `json:"created_at"` + Roles []string `json:"roles"` +} + +type LoginReq struct { + Username string `json:"username"` + Password string `json:"password"` +} + +type LoginResp struct { + Token string `json:"token"` + ExpiresAt int64 `json:"expires_at"` +} + +type LogoutReq struct { + Token string `json:"token"` +} + +type LogoutResp struct { + Success bool `json:"success"` +} + +type RegisterReq struct { + Username string `json:"username"` + Password string `json:"password"` + Email string `json:"email"` +} + +type RegisterResp struct { + UserId string `json:"user_id"` +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f739017 --- /dev/null +++ b/go.mod @@ -0,0 +1,107 @@ +module godemo + +go 1.24.3 + +require ( + github.com/golang-jwt/jwt/v4 v4.5.2 + github.com/jmoiron/sqlx v1.4.0 + github.com/lib/pq v1.10.9 + github.com/zeromicro/go-zero v1.8.3 + golang.org/x/crypto v0.36.0 + google.golang.org/grpc v1.72.1 + google.golang.org/protobuf v1.36.6 +) + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/go-ini/ini v1.67.0 // indirect + github.com/go-sql-driver/mysql v1.9.0 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/minio/crc64nvme v1.0.1 // indirect + github.com/minio/md5-simd v1.1.2 // indirect + github.com/rs/xid v1.6.0 // indirect +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/coreos/go-semver v0.3.1 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.4 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/mock v1.6.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.6.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/minio/minio-go/v7 v7.0.91 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/openzipkin/zipkin-go v0.4.3 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/prometheus/client_golang v1.21.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.62.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/redis/go-redis/v9 v9.8.0 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + go.etcd.io/etcd/api/v3 v3.5.15 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect + go.etcd.io/etcd/client/v3 v3.5.15 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.34.0 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 // indirect + go.opentelemetry.io/otel/exporters/zipkin v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.34.0 // indirect + go.opentelemetry.io/otel/sdk v1.34.0 // indirect + go.opentelemetry.io/otel/trace v1.34.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/automaxprocs v1.6.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + go.uber.org/zap v1.24.0 // indirect + golang.org/x/net v0.38.0 // indirect + golang.org/x/oauth2 v0.26.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect + golang.org/x/text v0.23.0 // indirect + golang.org/x/time v0.10.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.29.3 // indirect + k8s.io/apimachinery v0.29.4 // indirect + k8s.io/client-go v0.29.3 // indirect + k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..167291b --- /dev/null +++ b/go.sum @@ -0,0 +1,313 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= +github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= +github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE= +github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQggTglU/0= +github.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqRWqM3nksiyXk5s8= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= +github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo= +github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY= +github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg= +github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= +github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= +github.com/minio/minio-go/v7 v7.0.91 h1:tWLZnEfo3OZl5PoXQwcwTAPNNrjyWwOh6cbZitW5JQc= +github.com/minio/minio-go/v7 v7.0.91/go.mod h1:uvMUcGrpgeSAAI6+sD3818508nUyMULw94j2Nxku/Go= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= +github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= +github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= +github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= +github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI= +github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= +github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +github.com/zeromicro/go-zero v1.8.3 h1:AwpBJQLAsZAt4OOnK0eR8UU1Ja2RFBIXfKkHdnXQKfc= +github.com/zeromicro/go-zero v1.8.3/go.mod h1:EnuEA3XdIQvAvc4WWTskRTO0jM2/aQi7OXv1gKWRNJ0= +go.etcd.io/etcd/api/v3 v3.5.15 h1:3KpLJir1ZEBrYuV2v+Twaa/e2MdDCEZ/70H+lzEiwsk= +go.etcd.io/etcd/api/v3 v3.5.15/go.mod h1:N9EhGzXq58WuMllgH9ZvnEr7SI9pS0k0+DHZezGp7jM= +go.etcd.io/etcd/client/pkg/v3 v3.5.15 h1:fo0HpWz/KlHGMCC+YejpiCmyWDEuIpnTDzpJLB5fWlA= +go.etcd.io/etcd/client/pkg/v3 v3.5.15/go.mod h1:mXDI4NAOwEiszrHCb0aqfAYNCrZP4e9hRca3d1YK8EU= +go.etcd.io/etcd/client/v3 v3.5.15 h1:23M0eY4Fd/inNv1ZfU3AxrbbOdW79r9V9Rl62Nm6ip4= +go.etcd.io/etcd/client/v3 v3.5.15/go.mod h1:CLSJxrYjvLtHsrPKsy7LmZEE+DK2ktfd2bN4RhBMwlU= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 h1:s0PHtIkN+3xrbDOpt2M8OTG92cWqUESvzh2MxiR5xY8= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0/go.mod h1:hZlFbDbRt++MMPCCfSJfmhkGIWnX1h3XjkfxZUjLrIA= +go.opentelemetry.io/otel/exporters/zipkin v1.24.0 h1:3evrL5poBuh1KF51D9gO/S+N/1msnm4DaBqs/rpXUqY= +go.opentelemetry.io/otel/exporters/zipkin v1.24.0/go.mod h1:0EHgD8R0+8yRhUYJOGR8Hfg2dpiJQxDOszd5smVO9wM= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= +golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0= +google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= +gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= +k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= +k8s.io/apimachinery v0.29.4 h1:RaFdJiDmuKs/8cm1M6Dh1Kvyh59YQFDcFuFTSmXes6Q= +k8s.io/apimachinery v0.29.4/go.mod h1:i3FJVwhvSp/6n8Fl4K97PJEP8C+MM+aoDq4+ZJBf70Y= +k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= +k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/rpc/category.proto b/rpc/category.proto new file mode 100644 index 0000000..57ea223 --- /dev/null +++ b/rpc/category.proto @@ -0,0 +1,178 @@ +syntax = "proto3"; + +package category; + +option go_package = "./category"; + +// 分类服务 - 分类管理、树形结构操作、批量处理 +service Category { + // 健康检查 + rpc Ping(PingRequest) returns (PingResponse); + + // 分类基础操作 + rpc CreateCategory(CreateCategoryRequest) returns (CategoryInfoResponse); + rpc UpdateCategory(UpdateCategoryRequest) returns (CategoryInfoResponse); + rpc DeleteCategory(DeleteCategoryRequest) returns (DeleteResponse); + rpc GetCategory(GetCategoryRequest) returns (CategoryInfoResponse); + + // 层级结构操作 + rpc GetChildren(GetChildrenRequest) returns (CategoryListResponse); + rpc GetTree(GetTreeRequest) returns (CategoryTreeResponse); + rpc MoveCategory(MoveCategoryRequest) returns (CategoryInfoResponse); + rpc GetAncestorPath(GetAncestorPathRequest) returns (CategoryPathResponse); + + // 批量操作 + rpc BatchCreateCategories(BatchCreateRequest) returns (BatchCreateResponse); + rpc BatchUpdateCategories(BatchUpdateRequest) returns (BatchUpdateResponse); + + // 查询过滤 + rpc ListCategories(ListCategoryRequest) returns (CategoryListResponse); + rpc CheckAlias(CheckAliasRequest) returns (CheckAliasResponse); +} + +// 健康检查请求 +message PingRequest { + string ping = 1; +} + +// 健康检查响应 +message PingResponse { + string pong = 1; +} + +// 分类基础信息 +message CategoryInfo { + string id = 1; // UUID + string system_id = 2; // 所属系统标识 + string name = 3; // 分类名称 + string alias = 4; // URL别名 + string parent_id = 5; // 父分类ID + string description = 6; // 描述 + int64 created_at = 7; // 创建时间戳 + int64 updated_at = 8; // 更新时间戳 +} + +// 创建分类请求 +message CreateCategoryRequest { + string system_id = 1; + string name = 2; + string alias = 3; + string parent_id = 4; // 空字符串表示根分类 + string description = 5; +} + +// 更新分类请求 +message UpdateCategoryRequest { + string id = 1; + string name = 2; + string alias = 3; + string parent_id = 4; // 修改父分类时使用 + string description = 5; +} + +// 删除分类请求 +message DeleteCategoryRequest { + string id = 1; +} + +// 删除响应 +message DeleteResponse { + bool success = 1; +} + +// 分类查询请求 +message GetCategoryRequest { + string id = 1; +} + +// 分类信息响应 +message CategoryInfoResponse { + CategoryInfo category = 1; +} + +// 层级结构操作请求 +message GetChildrenRequest { + string parent_id = 1; // 为空时查询根分类 + bool recursive = 2; // 是否递归获取所有子节点 +} + +// 树形结构请求 +message GetTreeRequest { + string system_id = 1; // 必须指定系统 + string root_id = 2; // 空字符串表示从根开始 +} + +// 移动分类请求 +message MoveCategoryRequest { + string id = 1; + string new_parent_id = 2; // 空字符串表示移动到根 +} + +// 祖先路径请求 +message GetAncestorPathRequest { + string id = 1; +} + +// 分类路径响应 +message CategoryPathResponse { + repeated CategoryInfo path = 1; // 从根到当前分类的路径 +} + +// 批量操作请求 +message BatchCreateRequest { + repeated CreateCategoryRequest categories = 1; +} + +message BatchCreateResponse { + repeated CategoryInfo created_categories = 1; + int32 success_count = 2; + int32 fail_count = 3; +} + +message BatchUpdateRequest { + repeated UpdateCategoryRequest categories = 1; +} + +message BatchUpdateResponse { + repeated CategoryInfo updated_categories = 1; + int32 success_count = 2; + int32 fail_count = 3; +} + +// 列表查询请求 +message ListCategoryRequest { + string system_id = 1; + string parent_id = 2; // 空字符串表示根分类 + string name = 3; // 模糊匹配 + string alias = 4; // 精确匹配 + int32 page = 5; // 分页参数 + int32 page_size = 6; +} + +// 列表响应 +message CategoryListResponse { + repeated CategoryInfo categories = 1; + int32 total = 2; +} + +// 树形结构响应 +message CategoryTreeResponse { + message TreeNode { + CategoryInfo category = 1; + repeated TreeNode children = 2; + } + TreeNode root = 1; +} + +// 别名检查请求 +message CheckAliasRequest { + string system_id = 1; + string parent_id = 2; // 空字符串表示根父级 + string alias = 3; +} + +// 别名检查响应 +message CheckAliasResponse { + bool is_available = 1; + string existing_id = 2; // 冲突时返回已存在的分类ID +} \ No newline at end of file diff --git a/rpc/file.proto b/rpc/file.proto new file mode 100644 index 0000000..46c1d9b --- /dev/null +++ b/rpc/file.proto @@ -0,0 +1,51 @@ +syntax = "proto3"; + +package file; + +option go_package = "./file"; + +// 文件服务 - 上传图片、获取地址、删除文件等 +service File { + // 上传文件(图片/头像/壁纸等) + rpc Upload (UploadRequest) returns (UploadResponse); + + // 获取文件访问链接(带签名,防盗链) + rpc GetFileUrl (GetFileUrlRequest) returns (GetFileUrlResponse); + + // 删除文件 + rpc Delete (DeleteRequest) returns (DeleteResponse); +} + +// 上传文件请求 +message UploadRequest { + string filename = 1; // 文件名(建议客户端传原始名,服务端会生成唯一名) + string content_type = 2; // 文件类型(如 image/jpeg) + bytes content = 3; // 文件二进制内容(base64 编码由客户端完成) + string folder = 4; // 可选,文件夹或分类路径,如 "avatars"、"wallpapers" +} + +// 上传响应 +message UploadResponse { + string file_id = 1; // 文件唯一 ID(或路径) + string url = 2; // 可访问 URL(带 CDN 或签名) +} + +// 获取访问链接请求 +message GetFileUrlRequest { + string file_id = 1; // 文件唯一 ID 或路径 +} + +// 获取访问链接响应 +message GetFileUrlResponse { + string url = 1; // 可访问链接 +} + +// 删除文件请求 +message DeleteRequest { + string file_id = 1; // 要删除的文件 ID +} + +// 删除文件响应 +message DeleteResponse { + bool success = 1; // 是否删除成功 +} diff --git a/rpc/gallery.proto b/rpc/gallery.proto new file mode 100644 index 0000000..e3d0e35 --- /dev/null +++ b/rpc/gallery.proto @@ -0,0 +1,131 @@ +syntax = "proto3"; + +package gallery; + +option go_package = "./gallery"; + +service Gallery { + // 健康检查 + rpc Ping(PingRequest) returns (PingResponse); + + // 图片元数据操作 + rpc GetImageList(ImageListRequest) returns (ImageListResponse); + rpc GetImageDetail(ImageDetailRequest) returns (ImageDetailResponse); + rpc UpdateImage(UpdateImageRequest) returns (UpdateImageResponse); + rpc DeleteImage(DeleteImageRequest) returns (DeleteImageResponse); + + // 图片上传 + rpc UploadImage(UploadImageRequest) returns (UploadImageResponse); + + // 分类管理 + rpc GetCategoryTree(CategoryTreeRequest) returns (CategoryTreeResponse); + rpc CreateCategory(CreateCategoryRequest) returns (CreateCategoryResponse); + + // 访问控制 + rpc GenerateUrl(GenerateUrlRequest) returns (GenerateUrlResponse); +} + +// 健康检查 +message PingRequest { string ping = 1; } +message PingResponse { string pong = 1; } + +// 图片元数据 +message ImageMeta { + string image_id = 1; + string title = 2; + string description = 3; + string category_id = 4; + repeated string tags = 5; + int64 file_size = 6; + int32 width = 7; + int32 height = 8; + string storage_key = 9; + string file_name = 10; + string mime_type = 11; + int64 created_at = 12; + int64 updated_at = 13; +} + +// 图片列表 +message ImageListRequest { + int32 page = 1; + int32 page_size = 2; + string category_id = 3; + repeated string tags = 4; + string order_by = 5; // created_at_desc | updated_at_asc +} + +message ImageListResponse { + repeated ImageMeta images = 1; + int32 total = 2; +} + +// 图片详情 +message ImageDetailRequest { string image_id = 1; } +message ImageDetailResponse { ImageMeta meta = 1; } + +// 更新图片 +message UpdateImageRequest { + string image_id = 1; + optional string title = 2; + optional string description = 3; + optional string category_id = 4; + repeated string tags = 5; // 全量替换 +} + +message UpdateImageResponse { bool success = 1; } + +// 删除图片 +message DeleteImageRequest { + string image_id = 1; + bool permanent = 2; +} + +message DeleteImageResponse { bool success = 1; } + +// 图片上传 +message UploadImageRequest { + bytes file_content = 1; + string file_name = 2; + optional string title = 3; + optional string description = 4; + optional string category_id = 5; + repeated string tags = 6; +} + +message UploadImageResponse { + ImageMeta image_meta = 1; + string preview_url = 2; +} + +// 分类管理 +message CategoryNode { + string category_id = 1; + string name = 2; + repeated CategoryNode children = 3; +} + +message CategoryTreeRequest { bool include_count = 1; } +message CategoryTreeResponse { repeated CategoryNode categories = 1; } + +message CreateCategoryRequest { + string name = 1; + string parent_id = 2; +} + +message CreateCategoryResponse { string category_id = 1; } + +// URL生成 +message GenerateUrlRequest { + string image_id = 1; + optional int32 width = 2; + optional int32 height = 3; + optional string format = 4; // webp/jpg/png + optional int32 quality = 5; // 1-100 + int32 expires = 6; // 有效期(秒) +} + +message GenerateUrlResponse { + string signed_url = 1; + int64 expires_at = 2; // Unix时间戳 +} \ No newline at end of file diff --git a/rpc/user.proto b/rpc/user.proto new file mode 100644 index 0000000..c2de2df --- /dev/null +++ b/rpc/user.proto @@ -0,0 +1,81 @@ +syntax = "proto3"; + +package user; + +option go_package = "./user"; + +// 用户服务 - 注册、登录、登出、获取用户信息、健康检查 +service User { + // 健康检查 + rpc Ping (PingRequest) returns (PingResponse); + + // 用户注册 + rpc Register (RegisterRequest) returns (RegisterResponse); + + // 用户登录,返回 JWT Token + rpc Login (LoginRequest) returns (LoginResponse); + + // 用户登出,可选实现 + rpc Logout (LogoutRequest) returns (LogoutResponse); + + // 获取用户信息 + rpc GetUserInfo (GetUserInfoRequest) returns (GetUserInfoResponse); +} + +// 健康检查请求 +message PingRequest { + string ping = 1; +} + +// 健康检查响应 +message PingResponse { + string pong = 1; +} + +// 注册请求 +message RegisterRequest { + string username = 1; // 用户名 + string password = 2; // 密码(明文或哈希后) + string email = 3; // 邮箱,可选 +} + +// 注册响应 +message RegisterResponse { + string user_id = 1; // 新注册用户的唯一 ID +} + +// 登录请求 +message LoginRequest { + string username = 1; // 用户名 + string password = 2; // 密码 +} + +// 登录响应 +message LoginResponse { + string token = 1; // JWT 访问令牌 + int64 expires_at = 2; // 过期时间(Unix 时间戳) +} + +// 登出请求 +message LogoutRequest { + string token = 1; // 要废弃的 JWT +} + +// 登出响应 +message LogoutResponse { + bool success = 1; // 是否登出成功 +} + +// 获取用户信息请求 +message GetUserInfoRequest { + string user_id = 1; // 目标用户 ID +} + +// 获取用户信息响应 +message GetUserInfoResponse { + string user_id = 1; // 用户唯一 ID + string username = 2; // 用户名 + string email = 3; // 用户邮箱 + int64 created_at = 4; // 账号创建时间(Unix 时间戳) + repeated string roles = 5; // 用户角色列表,可选 +} diff --git a/sql/categories.sql b/sql/categories.sql new file mode 100644 index 0000000..7bdd491 --- /dev/null +++ b/sql/categories.sql @@ -0,0 +1,58 @@ +-- 分类表 (支持多系统/模块使用,支持多级分类,使用 alias 字段) +CREATE TABLE categories ( + -- 分类的唯一标识符,全局唯一 + id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid()::varchar, + + -- 标识分类所属的系统、模块或服务 + system_id TEXT NOT NULL, + + -- 分类名称 + name TEXT NOT NULL, + + -- 用于 URL 或程序内部识别的别名 + alias TEXT, + + -- 父级分类的 ID + -- 如果是顶级分类,此字段为 NULL + parent_id VARCHAR(36) REFERENCES categories(id) ON DELETE SET NULL, + + -- 可选字段:分类的描述 + description TEXT, + + -- 记录创建时间 + created_at TIMESTAMP WITH TIME ZONE DEFAULT now(), + + -- 记录最后更新时间(可选) + updated_at TIMESTAMP WITH TIME ZONE, + + -- 复合唯一约束:确保在同一个 system_id + parent_id 下,分类名称不重复 + -- 这允许不同父级下的同名子分类,也允许不同系统下的同名顶级分类 (parent_id IS NULL) + CONSTRAINT uix_categories_system_parent_name UNIQUE (system_id, parent_id, name), + + -- 复合唯一约束:确保在同一个 system_id + parent_id 下,分类 alias 不重复 (如果使用 alias 字段) + CONSTRAINT uix_categories_system_parent_alias UNIQUE (system_id, parent_id, alias), + + -- 外键约束:parent_id 引用回 categories 表自身的 id + CONSTRAINT fk_categories_parent + FOREIGN KEY (parent_id) + REFERENCES categories (id) + ON DELETE CASCADE -- 或 ON DELETE SET NULL,根据业务决定删除父分类时如何处理子分类 + -- ON DELETE CASCADE: 删除父分类时,所有子分类也会被删除 + -- ON DELETE SET NULL: 删除父分类时,所有子分类的 parent_id 设为 NULL,使其成为顶级分类 +); + +-- 为 system_id, parent_id, name 添加索引,用于按系统、父级和名称快速查找分类 +CREATE INDEX idx_categories_system_parent_name ON categories (system_id, parent_id, name); + +-- 如果经常按 system_id, parent_id 和 alias 查询分类 +CREATE INDEX idx_categories_system_parent_alias ON categories (system_id, parent_id, alias); + +-- 为 parent_id 添加索引,用于查找某个父级下的所有子分类 +CREATE INDEX idx_categories_parent_id ON categories (parent_id); + +-- 如果经常需要查找某个系统下的所有分类 (包括顶级和子级) +CREATE INDEX idx_categories_system_id ON categories (system_id); + +-- 原有的 system_id + name/alias 索引已包含在新的复合索引中,通常不需要单独创建 +-- CREATE INDEX idx_categories_system_id_name ON categories (system_id, name); +-- CREATE INDEX idx_categories_system_id_alias ON categories (system_id, alias); \ No newline at end of file diff --git a/sql/images.sql b/sql/images.sql new file mode 100644 index 0000000..2fe7de7 --- /dev/null +++ b/sql/images.sql @@ -0,0 +1,40 @@ +-- 图片主表基础版 +CREATE TABLE images ( + -- 核心标识字段 + image_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + + -- 存储元数据 + storage_key TEXT NOT NULL CHECK (storage_key ~ '^[a-z0-9/-]+$'), + file_name TEXT NOT NULL, + mime_type VARCHAR(32) NOT NULL CHECK (mime_type LIKE 'image/%'), + file_size BIGINT NOT NULL CHECK (file_size > 0), + width INT CHECK (width > 0), + height INT CHECK (height > 0), + + -- 业务元数据 + category_id UUID, -- 分类服务提供的UUID + tags TEXT[] DEFAULT '{}'::TEXT[], + + -- 系统管控字段 + created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, + updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, + is_deleted BOOLEAN DEFAULT FALSE NOT NULL +); + +-- 索引配置 +CREATE INDEX idx_images_category ON images (category_id); +CREATE INDEX idx_images_created ON images (created_at); +CREATE INDEX idx_images_tags ON images USING GIN(tags); + +-- 自动更新时间触发器 +CREATE OR REPLACE FUNCTION update_image_modified() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = NOW(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_update_image +BEFORE UPDATE ON images +FOR EACH ROW EXECUTE FUNCTION update_image_modified(); \ No newline at end of file diff --git a/sql/users.sql b/sql/users.sql new file mode 100644 index 0000000..24360c2 --- /dev/null +++ b/sql/users.sql @@ -0,0 +1,13 @@ +-- 1. 用户表 DDL +CREATE TABLE users ( + user_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- 唯一用户 ID + username TEXT NOT NULL UNIQUE, -- 用户名 + email TEXT UNIQUE, -- 邮箱 + password_hash TEXT NOT NULL, -- 密码哈希 + roles TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], -- 角色列表 + created_at TIMESTAMPTZ NOT NULL DEFAULT now() -- 创建时间 +); + +-- 为 username、email 建立索引,加速查询 +CREATE INDEX idx_users_username ON users(username); +CREATE INDEX idx_users_email ON users(email); diff --git a/user/etc/user.yaml b/user/etc/user.yaml new file mode 100644 index 0000000..0e9be9a --- /dev/null +++ b/user/etc/user.yaml @@ -0,0 +1,13 @@ +Name: user.rpc +ListenOn: 0.0.0.0:60100 +Mode: dev +Etcd: + Hosts: + - localhost:2379 + Key: user.rpc + +DataSource: "postgres://postgres:postgres@localhost:5432/godemo?sslmode=disable" + +JwtAuth: + AccessSecret: "your-secure-secret" + AccessExpire: 900 # 可选,单位秒,15分钟 diff --git a/user/internal/config/config.go b/user/internal/config/config.go new file mode 100644 index 0000000..822c0c4 --- /dev/null +++ b/user/internal/config/config.go @@ -0,0 +1,14 @@ +package config + +import "github.com/zeromicro/go-zero/zrpc" + +type JwtAuth struct { + AccessSecret string + AccessExpire int64 +} + +type Config struct { + zrpc.RpcServerConf + DataSource string + JwtAuth JwtAuth +} diff --git a/user/internal/logic/getuserinfologic.go b/user/internal/logic/getuserinfologic.go new file mode 100644 index 0000000..9475e71 --- /dev/null +++ b/user/internal/logic/getuserinfologic.go @@ -0,0 +1,50 @@ +package logic + +import ( + "context" + "database/sql" + "errors" + "fmt" + + "godemo/user/internal/model" + "godemo/user/internal/svc" + "godemo/user/user" + + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/status" +) + +type GetUserInfoLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGetUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserInfoLogic { + return &GetUserInfoLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 获取用户信息 +func (l *GetUserInfoLogic) GetUserInfo(in *user.GetUserInfoRequest) (*user.GetUserInfoResponse, error) { + // todo: add your logic here and delete this line + var userModel model.User + err := l.svcCtx.DB.Get(&userModel, "SELECT * FROM users WHERE user_id = $1", in.UserId) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, status.Error(status.Code(err), fmt.Sprintf("用户 %s 不存在", in.UserId)) + } + return nil, status.Error(status.Code(err), err.Error()) + } + + return &user.GetUserInfoResponse{ + UserId: userModel.UserId, + Username: userModel.Username, + Email: userModel.Email.String, + CreatedAt: userModel.CreatedAt.Unix(), + Roles: userModel.Roles, + }, nil +} diff --git a/user/internal/logic/loginlogic.go b/user/internal/logic/loginlogic.go new file mode 100644 index 0000000..3f9b2c2 --- /dev/null +++ b/user/internal/logic/loginlogic.go @@ -0,0 +1,69 @@ +package logic + +import ( + "context" + "database/sql" + "errors" + "godemo/user/internal/model" + "godemo/user/internal/svc" + "godemo/user/user" + "time" + + "github.com/golang-jwt/jwt/v4" + "github.com/zeromicro/go-zero/core/logx" + "golang.org/x/crypto/bcrypt" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type LoginLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic { + return &LoginLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *LoginLogic) Login(in *user.LoginRequest) (*user.LoginResponse, error) { + // 1. 查找用户 + var u model.User + err := l.svcCtx.DB.Get(&u, "SELECT * FROM users WHERE username = $1", in.Username) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, status.Error(codes.NotFound, "用户不存在") + } + return nil, status.Error(codes.Internal, err.Error()) + } + + // 2. 校验密码(假设密码已加密存储) + err = bcrypt.CompareHashAndPassword([]byte(u.PasswordHash), []byte(in.Password)) + if err != nil { + return nil, status.Error(codes.Unauthenticated, "密码错误") + } + + // 3. 签发 JWT Token + claims := jwt.MapClaims{ + "sub": u.UserId, + "exp": time.Now().Add(time.Minute * 15).Unix(), // 默认 15 分钟有效期 + "iat": time.Now().Unix(), + "roles": u.Roles, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + signedToken, err := token.SignedString([]byte(l.svcCtx.Config.JwtAuth.AccessSecret)) + if err != nil { + return nil, status.Error(codes.Unavailable, "token生成失败") + } + + // 4. 返回响应 + return &user.LoginResponse{ + Token: signedToken, + ExpiresAt: claims["exp"].(int64), + }, nil +} diff --git a/user/internal/logic/logoutlogic.go b/user/internal/logic/logoutlogic.go new file mode 100644 index 0000000..a8d0cb2 --- /dev/null +++ b/user/internal/logic/logoutlogic.go @@ -0,0 +1,31 @@ +package logic + +import ( + "context" + + "godemo/user/internal/svc" + "godemo/user/user" + + "github.com/zeromicro/go-zero/core/logx" +) + +type LogoutLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewLogoutLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LogoutLogic { + return &LogoutLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 用户登出,可选实现 +func (l *LogoutLogic) Logout(in *user.LogoutRequest) (*user.LogoutResponse, error) { + // todo: add your logic here and delete this line + + return &user.LogoutResponse{}, nil +} diff --git a/user/internal/logic/pinglogic.go b/user/internal/logic/pinglogic.go new file mode 100644 index 0000000..9a45617 --- /dev/null +++ b/user/internal/logic/pinglogic.go @@ -0,0 +1,31 @@ +package logic + +import ( + "context" + + "godemo/user/internal/svc" + "godemo/user/user" + + "github.com/zeromicro/go-zero/core/logx" +) + +type PingLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewPingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PingLogic { + return &PingLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 健康检查 +func (l *PingLogic) Ping(in *user.PingRequest) (*user.PingResponse, error) { + // todo: add your logic here and delete this line + + return &user.PingResponse{}, nil +} diff --git a/user/internal/logic/registerlogic.go b/user/internal/logic/registerlogic.go new file mode 100644 index 0000000..a49a6f9 --- /dev/null +++ b/user/internal/logic/registerlogic.go @@ -0,0 +1,90 @@ +package logic + +import ( + "context" + "database/sql" + "godemo/user/internal/model" + "godemo/user/internal/svc" + "godemo/user/user" + "time" + + "github.com/lib/pq" + "github.com/zeromicro/go-zero/core/logx" + "golang.org/x/crypto/bcrypt" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type RegisterLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterLogic { + return &RegisterLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// 用户注册 +func (l *RegisterLogic) Register(in *user.RegisterRequest) (*user.RegisterResponse, error) { + // 1. 检查用户名是否已存在 + var existingUser model.User + err := l.svcCtx.DB.Get(&existingUser, "SELECT * FROM users WHERE username = $1", in.Username) + if err == nil { + // 用户名已存在 + return nil, status.Error(codes.AlreadyExists, "用户名已存在") + } + + // 2. 加密密码 + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(in.Password), bcrypt.DefaultCost) + if err != nil { + // 密码加密失败 + return nil, status.Error(codes.Internal, err.Error()) + } + + // 3. 转换 email 为 sql.NullString + var email sql.NullString + if in.Email != "" { + email = sql.NullString{ + String: in.Email, + Valid: true, + } + } else { + email = sql.NullString{Valid: false} + } + + // 4. 保存新用户到数据库 + userModel := model.User{ + Username: in.Username, + PasswordHash: string(hashedPassword), + Email: email, // 使用 sql.NullString 类型存储 email + Roles: []string{"user"}, // 默认角色为 "user" + CreatedAt: time.Now(), // 当前时间戳 + } + + // 执行插入数据库操作 + _, err = l.svcCtx.DB.Exec( + "INSERT INTO users (username, password_hash, email, roles, created_at) VALUES ($1, $2, $3, $4, $5)", + userModel.Username, + userModel.PasswordHash, + userModel.Email, + pq.Array(userModel.Roles), // pq.Array 用于处理 PostgreSQL 数组类型 + userModel.CreatedAt, + ) + if err != nil { + // 数据库插入失败 + return nil, status.Error(codes.Internal, err.Error()) + } + + // 获取插入的记录的 UserId + l.svcCtx.DB.Get(&existingUser, "SELECT * FROM users WHERE username = $1", in.Username) + + // 5. 返回成功响应 + return &user.RegisterResponse{ + UserId: existingUser.UserId, // 将 UserId 转换为字符串 + }, nil +} diff --git a/user/internal/model/user.go b/user/internal/model/user.go new file mode 100644 index 0000000..80a9e0d --- /dev/null +++ b/user/internal/model/user.go @@ -0,0 +1,17 @@ +package model + +import ( + "database/sql" + "time" + + "github.com/lib/pq" +) + +type User struct { + UserId string `db:"user_id"` + Username string `db:"username"` + Email sql.NullString `db:"email"` + PasswordHash string `db:"password_hash"` + Roles pq.StringArray `db:"roles"` + CreatedAt time.Time `db:"created_at"` +} diff --git a/user/internal/server/userserver.go b/user/internal/server/userserver.go new file mode 100644 index 0000000..2406a4e --- /dev/null +++ b/user/internal/server/userserver.go @@ -0,0 +1,54 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.8.3 +// Source: user.proto + +package server + +import ( + "context" + + "godemo/user/internal/logic" + "godemo/user/internal/svc" + "godemo/user/user" +) + +type UserServer struct { + svcCtx *svc.ServiceContext + user.UnimplementedUserServer +} + +func NewUserServer(svcCtx *svc.ServiceContext) *UserServer { + return &UserServer{ + svcCtx: svcCtx, + } +} + +// 健康检查 +func (s *UserServer) Ping(ctx context.Context, in *user.PingRequest) (*user.PingResponse, error) { + l := logic.NewPingLogic(ctx, s.svcCtx) + return l.Ping(in) +} + +// 用户注册 +func (s *UserServer) Register(ctx context.Context, in *user.RegisterRequest) (*user.RegisterResponse, error) { + l := logic.NewRegisterLogic(ctx, s.svcCtx) + return l.Register(in) +} + +// 用户登录,返回 JWT Token +func (s *UserServer) Login(ctx context.Context, in *user.LoginRequest) (*user.LoginResponse, error) { + l := logic.NewLoginLogic(ctx, s.svcCtx) + return l.Login(in) +} + +// 用户登出,可选实现 +func (s *UserServer) Logout(ctx context.Context, in *user.LogoutRequest) (*user.LogoutResponse, error) { + l := logic.NewLogoutLogic(ctx, s.svcCtx) + return l.Logout(in) +} + +// 获取用户信息 +func (s *UserServer) GetUserInfo(ctx context.Context, in *user.GetUserInfoRequest) (*user.GetUserInfoResponse, error) { + l := logic.NewGetUserInfoLogic(ctx, s.svcCtx) + return l.GetUserInfo(in) +} diff --git a/user/internal/svc/servicecontext.go b/user/internal/svc/servicecontext.go new file mode 100644 index 0000000..b341ab1 --- /dev/null +++ b/user/internal/svc/servicecontext.go @@ -0,0 +1,23 @@ +package svc + +import ( + "godemo/user/internal/config" + + "github.com/jmoiron/sqlx" + _ "github.com/lib/pq" +) + +type ServiceContext struct { + Config config.Config + DB *sqlx.DB +} + +func NewServiceContext(c config.Config) *ServiceContext { + db := sqlx.MustConnect("postgres", c.DataSource) + db.SetMaxOpenConns(10) + db.SetMaxIdleConns(5) + return &ServiceContext{ + Config: c, + DB: db, + } +} diff --git a/user/user.go b/user/user.go new file mode 100644 index 0000000..58a63de --- /dev/null +++ b/user/user.go @@ -0,0 +1,39 @@ +package main + +import ( + "flag" + "fmt" + + "godemo/user/internal/config" + "godemo/user/internal/server" + "godemo/user/internal/svc" + "godemo/user/user" + + "github.com/zeromicro/go-zero/core/conf" + "github.com/zeromicro/go-zero/core/service" + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var configFile = flag.String("f", "etc/user.yaml", "the config file") + +func main() { + flag.Parse() + + var c config.Config + conf.MustLoad(*configFile, &c) + ctx := svc.NewServiceContext(c) + + s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { + user.RegisterUserServer(grpcServer, server.NewUserServer(ctx)) + + if c.Mode == service.DevMode || c.Mode == service.TestMode { + reflection.Register(grpcServer) + } + }) + defer s.Stop() + + fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) + s.Start() +} diff --git a/user/user/user.pb.go b/user/user/user.pb.go new file mode 100644 index 0000000..ce13d1b --- /dev/null +++ b/user/user/user.pb.go @@ -0,0 +1,645 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.6 +// protoc v3.20.3 +// source: rpc/user.proto + +package user + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// 健康检查请求 +type PingRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Ping string `protobuf:"bytes,1,opt,name=ping,proto3" json:"ping,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PingRequest) Reset() { + *x = PingRequest{} + mi := &file_rpc_user_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PingRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PingRequest) ProtoMessage() {} + +func (x *PingRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_user_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PingRequest.ProtoReflect.Descriptor instead. +func (*PingRequest) Descriptor() ([]byte, []int) { + return file_rpc_user_proto_rawDescGZIP(), []int{0} +} + +func (x *PingRequest) GetPing() string { + if x != nil { + return x.Ping + } + return "" +} + +// 健康检查响应 +type PingResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Pong string `protobuf:"bytes,1,opt,name=pong,proto3" json:"pong,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PingResponse) Reset() { + *x = PingResponse{} + mi := &file_rpc_user_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PingResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PingResponse) ProtoMessage() {} + +func (x *PingResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_user_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PingResponse.ProtoReflect.Descriptor instead. +func (*PingResponse) Descriptor() ([]byte, []int) { + return file_rpc_user_proto_rawDescGZIP(), []int{1} +} + +func (x *PingResponse) GetPong() string { + if x != nil { + return x.Pong + } + return "" +} + +// 注册请求 +type RegisterRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` // 用户名 + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` // 密码(明文或哈希后) + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` // 邮箱,可选 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RegisterRequest) Reset() { + *x = RegisterRequest{} + mi := &file_rpc_user_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegisterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterRequest) ProtoMessage() {} + +func (x *RegisterRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_user_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead. +func (*RegisterRequest) Descriptor() ([]byte, []int) { + return file_rpc_user_proto_rawDescGZIP(), []int{2} +} + +func (x *RegisterRequest) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *RegisterRequest) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *RegisterRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +// 注册响应 +type RegisterResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // 新注册用户的唯一 ID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RegisterResponse) Reset() { + *x = RegisterResponse{} + mi := &file_rpc_user_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegisterResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterResponse) ProtoMessage() {} + +func (x *RegisterResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_user_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterResponse.ProtoReflect.Descriptor instead. +func (*RegisterResponse) Descriptor() ([]byte, []int) { + return file_rpc_user_proto_rawDescGZIP(), []int{3} +} + +func (x *RegisterResponse) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +// 登录请求 +type LoginRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` // 用户名 + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` // 密码 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LoginRequest) Reset() { + *x = LoginRequest{} + mi := &file_rpc_user_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LoginRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoginRequest) ProtoMessage() {} + +func (x *LoginRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_user_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead. +func (*LoginRequest) Descriptor() ([]byte, []int) { + return file_rpc_user_proto_rawDescGZIP(), []int{4} +} + +func (x *LoginRequest) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *LoginRequest) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +// 登录响应 +type LoginResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` // JWT 访问令牌 + ExpiresAt int64 `protobuf:"varint,2,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"` // 过期时间(Unix 时间戳) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LoginResponse) Reset() { + *x = LoginResponse{} + mi := &file_rpc_user_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LoginResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoginResponse) ProtoMessage() {} + +func (x *LoginResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_user_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoginResponse.ProtoReflect.Descriptor instead. +func (*LoginResponse) Descriptor() ([]byte, []int) { + return file_rpc_user_proto_rawDescGZIP(), []int{5} +} + +func (x *LoginResponse) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *LoginResponse) GetExpiresAt() int64 { + if x != nil { + return x.ExpiresAt + } + return 0 +} + +// 登出请求 +type LogoutRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` // 要废弃的 JWT + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LogoutRequest) Reset() { + *x = LogoutRequest{} + mi := &file_rpc_user_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LogoutRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LogoutRequest) ProtoMessage() {} + +func (x *LogoutRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_user_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LogoutRequest.ProtoReflect.Descriptor instead. +func (*LogoutRequest) Descriptor() ([]byte, []int) { + return file_rpc_user_proto_rawDescGZIP(), []int{6} +} + +func (x *LogoutRequest) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +// 登出响应 +type LogoutResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` // 是否登出成功 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LogoutResponse) Reset() { + *x = LogoutResponse{} + mi := &file_rpc_user_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LogoutResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LogoutResponse) ProtoMessage() {} + +func (x *LogoutResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_user_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LogoutResponse.ProtoReflect.Descriptor instead. +func (*LogoutResponse) Descriptor() ([]byte, []int) { + return file_rpc_user_proto_rawDescGZIP(), []int{7} +} + +func (x *LogoutResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +// 获取用户信息请求 +type GetUserInfoRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // 目标用户 ID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetUserInfoRequest) Reset() { + *x = GetUserInfoRequest{} + mi := &file_rpc_user_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetUserInfoRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserInfoRequest) ProtoMessage() {} + +func (x *GetUserInfoRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_user_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserInfoRequest.ProtoReflect.Descriptor instead. +func (*GetUserInfoRequest) Descriptor() ([]byte, []int) { + return file_rpc_user_proto_rawDescGZIP(), []int{8} +} + +func (x *GetUserInfoRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +// 获取用户信息响应 +type GetUserInfoResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // 用户唯一 ID + Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` // 用户名 + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` // 用户邮箱 + CreatedAt int64 `protobuf:"varint,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` // 账号创建时间(Unix 时间戳) + Roles []string `protobuf:"bytes,5,rep,name=roles,proto3" json:"roles,omitempty"` // 用户角色列表,可选 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetUserInfoResponse) Reset() { + *x = GetUserInfoResponse{} + mi := &file_rpc_user_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetUserInfoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserInfoResponse) ProtoMessage() {} + +func (x *GetUserInfoResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_user_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserInfoResponse.ProtoReflect.Descriptor instead. +func (*GetUserInfoResponse) Descriptor() ([]byte, []int) { + return file_rpc_user_proto_rawDescGZIP(), []int{9} +} + +func (x *GetUserInfoResponse) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *GetUserInfoResponse) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *GetUserInfoResponse) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *GetUserInfoResponse) GetCreatedAt() int64 { + if x != nil { + return x.CreatedAt + } + return 0 +} + +func (x *GetUserInfoResponse) GetRoles() []string { + if x != nil { + return x.Roles + } + return nil +} + +var File_rpc_user_proto protoreflect.FileDescriptor + +const file_rpc_user_proto_rawDesc = "" + + "\n" + + "\x0erpc/user.proto\x12\x04user\"!\n" + + "\vPingRequest\x12\x12\n" + + "\x04ping\x18\x01 \x01(\tR\x04ping\"\"\n" + + "\fPingResponse\x12\x12\n" + + "\x04pong\x18\x01 \x01(\tR\x04pong\"_\n" + + "\x0fRegisterRequest\x12\x1a\n" + + "\busername\x18\x01 \x01(\tR\busername\x12\x1a\n" + + "\bpassword\x18\x02 \x01(\tR\bpassword\x12\x14\n" + + "\x05email\x18\x03 \x01(\tR\x05email\"+\n" + + "\x10RegisterResponse\x12\x17\n" + + "\auser_id\x18\x01 \x01(\tR\x06userId\"F\n" + + "\fLoginRequest\x12\x1a\n" + + "\busername\x18\x01 \x01(\tR\busername\x12\x1a\n" + + "\bpassword\x18\x02 \x01(\tR\bpassword\"D\n" + + "\rLoginResponse\x12\x14\n" + + "\x05token\x18\x01 \x01(\tR\x05token\x12\x1d\n" + + "\n" + + "expires_at\x18\x02 \x01(\x03R\texpiresAt\"%\n" + + "\rLogoutRequest\x12\x14\n" + + "\x05token\x18\x01 \x01(\tR\x05token\"*\n" + + "\x0eLogoutResponse\x12\x18\n" + + "\asuccess\x18\x01 \x01(\bR\asuccess\"-\n" + + "\x12GetUserInfoRequest\x12\x17\n" + + "\auser_id\x18\x01 \x01(\tR\x06userId\"\x95\x01\n" + + "\x13GetUserInfoResponse\x12\x17\n" + + "\auser_id\x18\x01 \x01(\tR\x06userId\x12\x1a\n" + + "\busername\x18\x02 \x01(\tR\busername\x12\x14\n" + + "\x05email\x18\x03 \x01(\tR\x05email\x12\x1d\n" + + "\n" + + "created_at\x18\x04 \x01(\x03R\tcreatedAt\x12\x14\n" + + "\x05roles\x18\x05 \x03(\tR\x05roles2\x9b\x02\n" + + "\x04User\x12-\n" + + "\x04Ping\x12\x11.user.PingRequest\x1a\x12.user.PingResponse\x129\n" + + "\bRegister\x12\x15.user.RegisterRequest\x1a\x16.user.RegisterResponse\x120\n" + + "\x05Login\x12\x12.user.LoginRequest\x1a\x13.user.LoginResponse\x123\n" + + "\x06Logout\x12\x13.user.LogoutRequest\x1a\x14.user.LogoutResponse\x12B\n" + + "\vGetUserInfo\x12\x18.user.GetUserInfoRequest\x1a\x19.user.GetUserInfoResponseB\bZ\x06./userb\x06proto3" + +var ( + file_rpc_user_proto_rawDescOnce sync.Once + file_rpc_user_proto_rawDescData []byte +) + +func file_rpc_user_proto_rawDescGZIP() []byte { + file_rpc_user_proto_rawDescOnce.Do(func() { + file_rpc_user_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_rpc_user_proto_rawDesc), len(file_rpc_user_proto_rawDesc))) + }) + return file_rpc_user_proto_rawDescData +} + +var file_rpc_user_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_rpc_user_proto_goTypes = []any{ + (*PingRequest)(nil), // 0: user.PingRequest + (*PingResponse)(nil), // 1: user.PingResponse + (*RegisterRequest)(nil), // 2: user.RegisterRequest + (*RegisterResponse)(nil), // 3: user.RegisterResponse + (*LoginRequest)(nil), // 4: user.LoginRequest + (*LoginResponse)(nil), // 5: user.LoginResponse + (*LogoutRequest)(nil), // 6: user.LogoutRequest + (*LogoutResponse)(nil), // 7: user.LogoutResponse + (*GetUserInfoRequest)(nil), // 8: user.GetUserInfoRequest + (*GetUserInfoResponse)(nil), // 9: user.GetUserInfoResponse +} +var file_rpc_user_proto_depIdxs = []int32{ + 0, // 0: user.User.Ping:input_type -> user.PingRequest + 2, // 1: user.User.Register:input_type -> user.RegisterRequest + 4, // 2: user.User.Login:input_type -> user.LoginRequest + 6, // 3: user.User.Logout:input_type -> user.LogoutRequest + 8, // 4: user.User.GetUserInfo:input_type -> user.GetUserInfoRequest + 1, // 5: user.User.Ping:output_type -> user.PingResponse + 3, // 6: user.User.Register:output_type -> user.RegisterResponse + 5, // 7: user.User.Login:output_type -> user.LoginResponse + 7, // 8: user.User.Logout:output_type -> user.LogoutResponse + 9, // 9: user.User.GetUserInfo:output_type -> user.GetUserInfoResponse + 5, // [5:10] is the sub-list for method output_type + 0, // [0:5] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_rpc_user_proto_init() } +func file_rpc_user_proto_init() { + if File_rpc_user_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_rpc_user_proto_rawDesc), len(file_rpc_user_proto_rawDesc)), + NumEnums: 0, + NumMessages: 10, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_rpc_user_proto_goTypes, + DependencyIndexes: file_rpc_user_proto_depIdxs, + MessageInfos: file_rpc_user_proto_msgTypes, + }.Build() + File_rpc_user_proto = out.File + file_rpc_user_proto_goTypes = nil + file_rpc_user_proto_depIdxs = nil +} diff --git a/user/user/user_grpc.pb.go b/user/user/user_grpc.pb.go new file mode 100644 index 0000000..236da23 --- /dev/null +++ b/user/user/user_grpc.pb.go @@ -0,0 +1,287 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v3.20.3 +// source: rpc/user.proto + +package user + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + User_Ping_FullMethodName = "/user.User/Ping" + User_Register_FullMethodName = "/user.User/Register" + User_Login_FullMethodName = "/user.User/Login" + User_Logout_FullMethodName = "/user.User/Logout" + User_GetUserInfo_FullMethodName = "/user.User/GetUserInfo" +) + +// UserClient is the client API for User service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// 用户服务 - 注册、登录、登出、获取用户信息、健康检查 +type UserClient interface { + // 健康检查 + Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) + // 用户注册 + Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) + // 用户登录,返回 JWT Token + Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error) + // 用户登出,可选实现 + Logout(ctx context.Context, in *LogoutRequest, opts ...grpc.CallOption) (*LogoutResponse, error) + // 获取用户信息 + GetUserInfo(ctx context.Context, in *GetUserInfoRequest, opts ...grpc.CallOption) (*GetUserInfoResponse, error) +} + +type userClient struct { + cc grpc.ClientConnInterface +} + +func NewUserClient(cc grpc.ClientConnInterface) UserClient { + return &userClient{cc} +} + +func (c *userClient) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PingResponse) + err := c.cc.Invoke(ctx, User_Ping_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RegisterResponse) + err := c.cc.Invoke(ctx, User_Register_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(LoginResponse) + err := c.cc.Invoke(ctx, User_Login_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) Logout(ctx context.Context, in *LogoutRequest, opts ...grpc.CallOption) (*LogoutResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(LogoutResponse) + err := c.cc.Invoke(ctx, User_Logout_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetUserInfo(ctx context.Context, in *GetUserInfoRequest, opts ...grpc.CallOption) (*GetUserInfoResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetUserInfoResponse) + err := c.cc.Invoke(ctx, User_GetUserInfo_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UserServer is the server API for User service. +// All implementations must embed UnimplementedUserServer +// for forward compatibility. +// +// 用户服务 - 注册、登录、登出、获取用户信息、健康检查 +type UserServer interface { + // 健康检查 + Ping(context.Context, *PingRequest) (*PingResponse, error) + // 用户注册 + Register(context.Context, *RegisterRequest) (*RegisterResponse, error) + // 用户登录,返回 JWT Token + Login(context.Context, *LoginRequest) (*LoginResponse, error) + // 用户登出,可选实现 + Logout(context.Context, *LogoutRequest) (*LogoutResponse, error) + // 获取用户信息 + GetUserInfo(context.Context, *GetUserInfoRequest) (*GetUserInfoResponse, error) + mustEmbedUnimplementedUserServer() +} + +// UnimplementedUserServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedUserServer struct{} + +func (UnimplementedUserServer) Ping(context.Context, *PingRequest) (*PingResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented") +} +func (UnimplementedUserServer) Register(context.Context, *RegisterRequest) (*RegisterResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Register not implemented") +} +func (UnimplementedUserServer) Login(context.Context, *LoginRequest) (*LoginResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Login not implemented") +} +func (UnimplementedUserServer) Logout(context.Context, *LogoutRequest) (*LogoutResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Logout not implemented") +} +func (UnimplementedUserServer) GetUserInfo(context.Context, *GetUserInfoRequest) (*GetUserInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUserInfo not implemented") +} +func (UnimplementedUserServer) mustEmbedUnimplementedUserServer() {} +func (UnimplementedUserServer) testEmbeddedByValue() {} + +// UnsafeUserServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to UserServer will +// result in compilation errors. +type UnsafeUserServer interface { + mustEmbedUnimplementedUserServer() +} + +func RegisterUserServer(s grpc.ServiceRegistrar, srv UserServer) { + // If the following call pancis, it indicates UnimplementedUserServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&User_ServiceDesc, srv) +} + +func _User_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PingRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).Ping(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: User_Ping_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).Ping(ctx, req.(*PingRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RegisterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).Register(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: User_Register_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).Register(ctx, req.(*RegisterRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LoginRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).Login(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: User_Login_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).Login(ctx, req.(*LoginRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_Logout_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LogoutRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).Logout(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: User_Logout_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).Logout(ctx, req.(*LogoutRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetUserInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserInfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetUserInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: User_GetUserInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetUserInfo(ctx, req.(*GetUserInfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// User_ServiceDesc is the grpc.ServiceDesc for User service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var User_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "user.User", + HandlerType: (*UserServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Ping", + Handler: _User_Ping_Handler, + }, + { + MethodName: "Register", + Handler: _User_Register_Handler, + }, + { + MethodName: "Login", + Handler: _User_Login_Handler, + }, + { + MethodName: "Logout", + Handler: _User_Logout_Handler, + }, + { + MethodName: "GetUserInfo", + Handler: _User_GetUserInfo_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "rpc/user.proto", +} diff --git a/user/userclient/user.go b/user/userclient/user.go new file mode 100644 index 0000000..54ed8ab --- /dev/null +++ b/user/userclient/user.go @@ -0,0 +1,80 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.8.3 +// Source: user.proto + +package userclient + +import ( + "context" + + "godemo/user/user" + + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" +) + +type ( + GetUserInfoRequest = user.GetUserInfoRequest + GetUserInfoResponse = user.GetUserInfoResponse + LoginRequest = user.LoginRequest + LoginResponse = user.LoginResponse + LogoutRequest = user.LogoutRequest + LogoutResponse = user.LogoutResponse + PingRequest = user.PingRequest + PingResponse = user.PingResponse + RegisterRequest = user.RegisterRequest + RegisterResponse = user.RegisterResponse + + User interface { + // 健康检查 + Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) + // 用户注册 + Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) + // 用户登录,返回 JWT Token + Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error) + // 用户登出,可选实现 + Logout(ctx context.Context, in *LogoutRequest, opts ...grpc.CallOption) (*LogoutResponse, error) + // 获取用户信息 + GetUserInfo(ctx context.Context, in *GetUserInfoRequest, opts ...grpc.CallOption) (*GetUserInfoResponse, error) + } + + defaultUser struct { + cli zrpc.Client + } +) + +func NewUser(cli zrpc.Client) User { + return &defaultUser{ + cli: cli, + } +} + +// 健康检查 +func (m *defaultUser) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) { + client := user.NewUserClient(m.cli.Conn()) + return client.Ping(ctx, in, opts...) +} + +// 用户注册 +func (m *defaultUser) Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) { + client := user.NewUserClient(m.cli.Conn()) + return client.Register(ctx, in, opts...) +} + +// 用户登录,返回 JWT Token +func (m *defaultUser) Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error) { + client := user.NewUserClient(m.cli.Conn()) + return client.Login(ctx, in, opts...) +} + +// 用户登出,可选实现 +func (m *defaultUser) Logout(ctx context.Context, in *LogoutRequest, opts ...grpc.CallOption) (*LogoutResponse, error) { + client := user.NewUserClient(m.cli.Conn()) + return client.Logout(ctx, in, opts...) +} + +// 获取用户信息 +func (m *defaultUser) GetUserInfo(ctx context.Context, in *GetUserInfoRequest, opts ...grpc.CallOption) (*GetUserInfoResponse, error) { + client := user.NewUserClient(m.cli.Conn()) + return client.GetUserInfo(ctx, in, opts...) +}