From 44152bf93abbc06b0fe59bfc4cd68554a86ed745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A7=E9=A9=8A?= Date: Tue, 8 Apr 2025 08:51:58 +0800 Subject: [PATCH] feat: add service --- client/product/product.go | 17 ++ etc/product.yaml | 23 +++ gen_result/pb/product/product.pb.go | 164 +++++++++++++++++- gen_result/pb/product/product_grpc.pb.go | 53 +++++- internal/config/config.go | 27 ++- .../logic/product/create_category_logic.go | 30 ++++ internal/server/product/product_server.go | 9 + internal/svc/service_context.go | 56 +++++- 8 files changed, 363 insertions(+), 16 deletions(-) create mode 100644 internal/logic/product/create_category_logic.go diff --git a/client/product/product.go b/client/product/product.go index 49c06f1..a943f13 100644 --- a/client/product/product.go +++ b/client/product/product.go @@ -5,11 +5,22 @@ package product import ( + "context" + + "code.30cm.net/digimon/app-cloudep-product-service/gen_result/pb/product" + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" ) type ( + CreateCategoryReq = product.CreateCategoryReq + NoneReq = product.NoneReq + OKResp = product.OKResp + Product interface { + // CreateCategory 建立 product 分類 + CreateCategory(ctx context.Context, in *CreateCategoryReq, opts ...grpc.CallOption) (*OKResp, error) } defaultProduct struct { @@ -22,3 +33,9 @@ func NewProduct(cli zrpc.Client) Product { cli: cli, } } + +// CreateCategory 建立 product 分類 +func (m *defaultProduct) CreateCategory(ctx context.Context, in *CreateCategoryReq, opts ...grpc.CallOption) (*OKResp, error) { + client := product.NewProductClient(m.cli.Conn()) + return client.CreateCategory(ctx, in, opts...) +} diff --git a/etc/product.yaml b/etc/product.yaml index c4ba00d..a4da31d 100644 --- a/etc/product.yaml +++ b/etc/product.yaml @@ -4,3 +4,26 @@ Etcd: Hosts: - 127.0.0.1:2379 Key: product.rpc + +Cache: + - Host: 127.0.0.1:6379 + type: node +CacheExpireTime: 1s +CacheWithNotFoundExpiry: 1s + +Mongo: + Schema: mongodb+srv + Host: dev.pwj5m.mongodb.net + User: "service" + Password: "lReiYk7GRjH4RUqH" + Port: "27017" + Database: digimon_member + ReplicaName: "rs0" + MaxStaleness: 30m + MaxPoolSize: 30 + MinPoolSize: 10 + MaxConnIdleTime: 30m + Compressors: + - f + EnableStandardReadWriteSplitMode: true + ConnectTimeoutMs : 300 \ No newline at end of file diff --git a/gen_result/pb/product/product.pb.go b/gen_result/pb/product/product.pb.go index 311cfa1..e8805b3 100644 --- a/gen_result/pb/product/product.pb.go +++ b/gen_result/pb/product/product.pb.go @@ -7,10 +7,10 @@ package product import ( - reflect "reflect" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( @@ -20,20 +20,165 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// OKResp +type OKResp struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *OKResp) Reset() { + *x = OKResp{} + mi := &file_generate_protobuf_product_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *OKResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OKResp) ProtoMessage() {} + +func (x *OKResp) ProtoReflect() protoreflect.Message { + mi := &file_generate_protobuf_product_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 OKResp.ProtoReflect.Descriptor instead. +func (*OKResp) Descriptor() ([]byte, []int) { + return file_generate_protobuf_product_proto_rawDescGZIP(), []int{0} +} + +// NoneReq +type NoneReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NoneReq) Reset() { + *x = NoneReq{} + mi := &file_generate_protobuf_product_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NoneReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NoneReq) ProtoMessage() {} + +func (x *NoneReq) ProtoReflect() protoreflect.Message { + mi := &file_generate_protobuf_product_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 NoneReq.ProtoReflect.Descriptor instead. +func (*NoneReq) Descriptor() ([]byte, []int) { + return file_generate_protobuf_product_proto_rawDescGZIP(), []int{1} +} + +type CreateCategoryReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateCategoryReq) Reset() { + *x = CreateCategoryReq{} + mi := &file_generate_protobuf_product_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateCategoryReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateCategoryReq) ProtoMessage() {} + +func (x *CreateCategoryReq) ProtoReflect() protoreflect.Message { + mi := &file_generate_protobuf_product_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 CreateCategoryReq.ProtoReflect.Descriptor instead. +func (*CreateCategoryReq) Descriptor() ([]byte, []int) { + return file_generate_protobuf_product_proto_rawDescGZIP(), []int{2} +} + +func (x *CreateCategoryReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + var File_generate_protobuf_product_proto protoreflect.FileDescriptor var file_generate_protobuf_product_proto_rawDesc = []byte{ 0x0a, 0x1f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x12, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x32, 0x09, 0x0a, 0x07, 0x50, 0x72, - 0x6f, 0x64, 0x75, 0x63, 0x74, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x64, 0x75, - 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x12, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x22, 0x08, 0x0a, 0x06, 0x4f, 0x4b, + 0x52, 0x65, 0x73, 0x70, 0x22, 0x09, 0x0a, 0x07, 0x4e, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x22, + 0x27, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, + 0x79, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0x48, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x74, 0x12, 0x3d, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x65, + 0x71, 0x1a, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x2e, 0x4f, 0x4b, 0x52, 0x65, + 0x73, 0x70, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } -var file_generate_protobuf_product_proto_goTypes = []any{} +var ( + file_generate_protobuf_product_proto_rawDescOnce sync.Once + file_generate_protobuf_product_proto_rawDescData = file_generate_protobuf_product_proto_rawDesc +) + +func file_generate_protobuf_product_proto_rawDescGZIP() []byte { + file_generate_protobuf_product_proto_rawDescOnce.Do(func() { + file_generate_protobuf_product_proto_rawDescData = protoimpl.X.CompressGZIP(file_generate_protobuf_product_proto_rawDescData) + }) + return file_generate_protobuf_product_proto_rawDescData +} + +var file_generate_protobuf_product_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_generate_protobuf_product_proto_goTypes = []any{ + (*OKResp)(nil), // 0: product.OKResp + (*NoneReq)(nil), // 1: product.NoneReq + (*CreateCategoryReq)(nil), // 2: product.CreateCategoryReq +} var file_generate_protobuf_product_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type + 2, // 0: product.Product.CreateCategory:input_type -> product.CreateCategoryReq + 0, // 1: product.Product.CreateCategory:output_type -> product.OKResp + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] 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 @@ -50,12 +195,13 @@ func file_generate_protobuf_product_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_generate_protobuf_product_proto_rawDesc, NumEnums: 0, - NumMessages: 0, + NumMessages: 3, NumExtensions: 0, NumServices: 1, }, GoTypes: file_generate_protobuf_product_proto_goTypes, DependencyIndexes: file_generate_protobuf_product_proto_depIdxs, + MessageInfos: file_generate_protobuf_product_proto_msgTypes, }.Build() File_generate_protobuf_product_proto = out.File file_generate_protobuf_product_proto_rawDesc = nil diff --git a/gen_result/pb/product/product_grpc.pb.go b/gen_result/pb/product/product_grpc.pb.go index dc5d168..4e4a985 100644 --- a/gen_result/pb/product/product_grpc.pb.go +++ b/gen_result/pb/product/product_grpc.pb.go @@ -7,7 +7,10 @@ package product 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 @@ -15,10 +18,16 @@ import ( // Requires gRPC-Go v1.64.0 or later. const _ = grpc.SupportPackageIsVersion9 +const ( + Product_CreateCategory_FullMethodName = "/product.Product/CreateCategory" +) + // ProductClient is the client API for Product 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 ProductClient interface { + // CreateCategory 建立 product 分類 + CreateCategory(ctx context.Context, in *CreateCategoryReq, opts ...grpc.CallOption) (*OKResp, error) } type productClient struct { @@ -29,10 +38,22 @@ func NewProductClient(cc grpc.ClientConnInterface) ProductClient { return &productClient{cc} } +func (c *productClient) CreateCategory(ctx context.Context, in *CreateCategoryReq, opts ...grpc.CallOption) (*OKResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(OKResp) + err := c.cc.Invoke(ctx, Product_CreateCategory_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // ProductServer is the server API for Product service. // All implementations must embed UnimplementedProductServer // for forward compatibility. type ProductServer interface { + // CreateCategory 建立 product 分類 + CreateCategory(context.Context, *CreateCategoryReq) (*OKResp, error) mustEmbedUnimplementedProductServer() } @@ -43,6 +64,9 @@ type ProductServer interface { // pointer dereference when methods are called. type UnimplementedProductServer struct{} +func (UnimplementedProductServer) CreateCategory(context.Context, *CreateCategoryReq) (*OKResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateCategory not implemented") +} func (UnimplementedProductServer) mustEmbedUnimplementedProductServer() {} func (UnimplementedProductServer) testEmbeddedByValue() {} @@ -64,13 +88,36 @@ func RegisterProductServer(s grpc.ServiceRegistrar, srv ProductServer) { s.RegisterService(&Product_ServiceDesc, srv) } +func _Product_CreateCategory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateCategoryReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProductServer).CreateCategory(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Product_CreateCategory_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProductServer).CreateCategory(ctx, req.(*CreateCategoryReq)) + } + return interceptor(ctx, in, info, handler) +} + // Product_ServiceDesc is the grpc.ServiceDesc for Product service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var Product_ServiceDesc = grpc.ServiceDesc{ ServiceName: "product.Product", HandlerType: (*ProductServer)(nil), - Methods: []grpc.MethodDesc{}, - Streams: []grpc.StreamDesc{}, - Metadata: "generate/protobuf/product.proto", + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateCategory", + Handler: _Product_CreateCategory_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "generate/protobuf/product.proto", } diff --git a/internal/config/config.go b/internal/config/config.go index c1f85b9..94afd5e 100755 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,7 +1,32 @@ package config -import "github.com/zeromicro/go-zero/zrpc" +import ( + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/zrpc" + "time" +) type Config struct { zrpc.RpcServerConf + // Redis Cluster + Cache cache.CacheConf + CacheExpireTime time.Duration + CacheWithNotFoundExpiry time.Duration + + Mongo struct { + Schema string + User string + Password string + Host string + Port string + Database string + ReplicaName string + MaxStaleness time.Duration + MaxPoolSize uint64 + MinPoolSize uint64 + MaxConnIdleTime time.Duration + Compressors []string + EnableStandardReadWriteSplitMode bool + ConnectTimeoutMs int64 + } } diff --git a/internal/logic/product/create_category_logic.go b/internal/logic/product/create_category_logic.go new file mode 100644 index 0000000..3950f4f --- /dev/null +++ b/internal/logic/product/create_category_logic.go @@ -0,0 +1,30 @@ +package productlogic + +import ( + "context" + + "code.30cm.net/digimon/app-cloudep-product-service/gen_result/pb/product" + "code.30cm.net/digimon/app-cloudep-product-service/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), + } +} + +// CreateCategory 建立 product 分類 +func (l *CreateCategoryLogic) CreateCategory(in *product.CreateCategoryReq) (*product.OKResp, error) { + + return &product.OKResp{}, nil +} diff --git a/internal/server/product/product_server.go b/internal/server/product/product_server.go index bb3c30e..0e59bff 100644 --- a/internal/server/product/product_server.go +++ b/internal/server/product/product_server.go @@ -5,7 +5,10 @@ package server import ( + "context" + "code.30cm.net/digimon/app-cloudep-product-service/gen_result/pb/product" + "code.30cm.net/digimon/app-cloudep-product-service/internal/logic/product" "code.30cm.net/digimon/app-cloudep-product-service/internal/svc" ) @@ -19,3 +22,9 @@ func NewProductServer(svcCtx *svc.ServiceContext) *ProductServer { svcCtx: svcCtx, } } + +// CreateCategory 建立 product 分類 +func (s *ProductServer) CreateCategory(ctx context.Context, in *product.CreateCategoryReq) (*product.OKResp, error) { + l := productlogic.NewCreateCategoryLogic(ctx, s.svcCtx) + return l.CreateCategory(in) +} diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go index e3929b6..fe90265 100644 --- a/internal/svc/service_context.go +++ b/internal/svc/service_context.go @@ -1,13 +1,63 @@ package svc -import "code.30cm.net/digimon/app-cloudep-product-service/internal/config" +import ( + "code.30cm.net/digimon/app-cloudep-product-service/internal/config" + "code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/usecase" + repo "code.30cm.net/digimon/app-cloudep-product-service/pkg/repository" + uc "code.30cm.net/digimon/app-cloudep-product-service/pkg/usecase" + mgo "code.30cm.net/digimon/library-go/mongo" + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/mon" +) type ServiceContext struct { - Config config.Config + Config config.Config + CategoryUseCase usecase.CategoryUseCase } func NewServiceContext(c config.Config) *ServiceContext { return &ServiceContext{ - Config: c, + CategoryUseCase: MustCategory(c), + Config: c, } } + +func MustCategory(c config.Config) usecase.CategoryUseCase { + // 準備Mongo Config + conf := &mgo.Conf{ + Schema: c.Mongo.Schema, + Host: c.Mongo.Host, + Database: c.Mongo.Database, + MaxStaleness: c.Mongo.MaxStaleness, + MaxPoolSize: c.Mongo.MaxPoolSize, + MinPoolSize: c.Mongo.MinPoolSize, + MaxConnIdleTime: c.Mongo.MaxConnIdleTime, + Compressors: c.Mongo.Compressors, + EnableStandardReadWriteSplitMode: c.Mongo.EnableStandardReadWriteSplitMode, + ConnectTimeoutMs: c.Mongo.ConnectTimeoutMs, + } + if c.Mongo.User != "" { + conf.User = c.Mongo.User + conf.Password = c.Mongo.Password + } + + // 快取選項 + cacheOpts := []cache.Option{ + cache.WithExpiry(c.CacheExpireTime), + cache.WithNotFoundExpiry(c.CacheWithNotFoundExpiry), + } + dbOpts := []mon.Option{ + mgo.SetCustomDecimalType(), + mgo.InitMongoOptions(*conf), + } + + categoryRepo := repo.MustCategoryRepository(repo.CategoryRepositoryParam{ + Conf: conf, + CacheConf: c.Cache, + CacheOpts: cacheOpts, + DBOpts: dbOpts, + }) + + return uc.MustCategoryUseCase(uc.CategoryUseCaseParam{ + CategoryRepo: categoryRepo}) +}