From cb16071b209d381e4133ade46469d2970be265b4 Mon Sep 17 00:00:00 2001 From: zzw <1464003642@qq.com> Date: Thu, 24 Sep 2026 10:38:00 +0800 Subject: [PATCH] feat: add support --- .gitea/workflows/cd-test.yml | 1 + .gitea/workflows/ci.yml | 3 +- rpc/support/pb/support.pb.go | 229 ++++++++++++++++++ rpc/support/pb/support_grpc.pb.go | 121 +++++++++ rpc/support/support.pb | Bin 0 -> 14009 bytes rpc/support/support.proto | 29 +++ services/support/.gitignore | 2 + services/support/Dockerfile | 39 +++ services/support/etc/support.yaml | 7 + services/support/internal/ccc/client.go | 80 ++++++ services/support/internal/config/config.go | 13 + services/support/internal/logic/callLogic.go | 43 ++++ services/support/internal/logic/response.go | 31 +++ .../support/internal/server/supportServer.go | 25 ++ .../support/internal/svc/serviceContext.go | 22 ++ services/support/run.toml | 48 ++++ services/support/support.go | 152 ++++++++++++ services/support/supportClient/support.go | 32 +++ services/support/validator/call.go | 25 ++ 19 files changed, 901 insertions(+), 1 deletion(-) create mode 100644 rpc/support/pb/support.pb.go create mode 100644 rpc/support/pb/support_grpc.pb.go create mode 100644 rpc/support/support.pb create mode 100644 rpc/support/support.proto create mode 100644 services/support/.gitignore create mode 100644 services/support/Dockerfile create mode 100644 services/support/etc/support.yaml create mode 100644 services/support/internal/ccc/client.go create mode 100644 services/support/internal/config/config.go create mode 100644 services/support/internal/logic/callLogic.go create mode 100644 services/support/internal/logic/response.go create mode 100644 services/support/internal/server/supportServer.go create mode 100644 services/support/internal/svc/serviceContext.go create mode 100644 services/support/run.toml create mode 100644 services/support/support.go create mode 100644 services/support/supportClient/support.go create mode 100644 services/support/validator/call.go diff --git a/.gitea/workflows/cd-test.yml b/.gitea/workflows/cd-test.yml index 11b5bc4..9145a65 100644 --- a/.gitea/workflows/cd-test.yml +++ b/.gitea/workflows/cd-test.yml @@ -48,4 +48,5 @@ jobs: docker pull ${{ vars.REGISTRY }}/lone/record:latest docker pull ${{ vars.REGISTRY }}/lone/factory:latest docker pull ${{ vars.REGISTRY }}/lone/message:latest + docker pull ${{ vars.REGISTRY }}/lone/support:latest docker compose up -d diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index b2a509a..e532c76 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: - name: Detect changes id: filter run: | - SERVICES="bff product admin user ad chore order express sale wecom task equipment record payment factory message" + SERVICES="bff product admin user ad chore order express sale wecom task equipment record payment factory message support" pattern_for() { case "$1" in @@ -97,6 +97,7 @@ jobs: - factory - message - order + - support env: BUILD_LIST: ${{ needs.changes.outputs.build_list }} NAME: lone/${{ matrix.name }} diff --git a/rpc/support/pb/support.pb.go b/rpc/support/pb/support.pb.go new file mode 100644 index 0000000..a5b15b0 --- /dev/null +++ b/rpc/support/pb/support.pb.go @@ -0,0 +1,229 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v3.19.4 +// source: support/support.proto + +package support + +import ( + _ "google.golang.org/genproto/googleapis/api/annotations" + 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 Response struct { + state protoimpl.MessageState `protogen:"open.v1"` + Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` + Data string `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Response) Reset() { + *x = Response{} + mi := &file_support_support_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Response) ProtoMessage() {} + +func (x *Response) ProtoReflect() protoreflect.Message { + mi := &file_support_support_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 Response.ProtoReflect.Descriptor instead. +func (*Response) Descriptor() ([]byte, []int) { + return file_support_support_proto_rawDescGZIP(), []int{0} +} + +func (x *Response) GetCode() int32 { + if x != nil { + return x.Code + } + return 0 +} + +func (x *Response) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +func (x *Response) GetData() string { + if x != nil { + return x.Data + } + return "" +} + +type CallReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Action string `protobuf:"bytes,1,opt,name=action,proto3" json:"action,omitempty"` + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` + Request string `protobuf:"bytes,3,opt,name=request,proto3" json:"request,omitempty"` + // 与旧云呼一致:前端传入的 AccessKey + A string `protobuf:"bytes,4,opt,name=a,proto3" json:"a,omitempty"` + S string `protobuf:"bytes,5,opt,name=s,proto3" json:"s,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CallReq) Reset() { + *x = CallReq{} + mi := &file_support_support_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CallReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CallReq) ProtoMessage() {} + +func (x *CallReq) ProtoReflect() protoreflect.Message { + mi := &file_support_support_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 CallReq.ProtoReflect.Descriptor instead. +func (*CallReq) Descriptor() ([]byte, []int) { + return file_support_support_proto_rawDescGZIP(), []int{1} +} + +func (x *CallReq) GetAction() string { + if x != nil { + return x.Action + } + return "" +} + +func (x *CallReq) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *CallReq) GetRequest() string { + if x != nil { + return x.Request + } + return "" +} + +func (x *CallReq) GetA() string { + if x != nil { + return x.A + } + return "" +} + +func (x *CallReq) GetS() string { + if x != nil { + return x.S + } + return "" +} + +var File_support_support_proto protoreflect.FileDescriptor + +const file_support_support_proto_rawDesc = "" + + "\n" + + "\x15support/support.proto\x12\asupport\x1a\x1cgoogle/api/annotations.proto\"D\n" + + "\bResponse\x12\x12\n" + + "\x04code\x18\x01 \x01(\x05R\x04code\x12\x10\n" + + "\x03msg\x18\x02 \x01(\tR\x03msg\x12\x12\n" + + "\x04data\x18\x03 \x01(\tR\x04data\"q\n" + + "\aCallReq\x12\x16\n" + + "\x06action\x18\x01 \x01(\tR\x06action\x12\x18\n" + + "\aversion\x18\x02 \x01(\tR\aversion\x12\x18\n" + + "\arequest\x18\x03 \x01(\tR\arequest\x12\f\n" + + "\x01a\x18\x04 \x01(\tR\x01a\x12\f\n" + + "\x01s\x18\x05 \x01(\tR\x01s2W\n" + + "\aSupport\x12L\n" + + "\x04Call\x12\x10.support.CallReq\x1a\x11.support.Response\"\x1f\x82\xd3\xe4\x93\x02\x19:\x01*\"\x14/api/v3/support/callB\x1bZ\x19lone-services/rpc/supportb\x06proto3" + +var ( + file_support_support_proto_rawDescOnce sync.Once + file_support_support_proto_rawDescData []byte +) + +func file_support_support_proto_rawDescGZIP() []byte { + file_support_support_proto_rawDescOnce.Do(func() { + file_support_support_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_support_support_proto_rawDesc), len(file_support_support_proto_rawDesc))) + }) + return file_support_support_proto_rawDescData +} + +var file_support_support_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_support_support_proto_goTypes = []any{ + (*Response)(nil), // 0: support.Response + (*CallReq)(nil), // 1: support.CallReq +} +var file_support_support_proto_depIdxs = []int32{ + 1, // 0: support.Support.Call:input_type -> support.CallReq + 0, // 1: support.Support.Call:output_type -> support.Response + 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 +} + +func init() { file_support_support_proto_init() } +func file_support_support_proto_init() { + if File_support_support_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_support_support_proto_rawDesc), len(file_support_support_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_support_support_proto_goTypes, + DependencyIndexes: file_support_support_proto_depIdxs, + MessageInfos: file_support_support_proto_msgTypes, + }.Build() + File_support_support_proto = out.File + file_support_support_proto_goTypes = nil + file_support_support_proto_depIdxs = nil +} diff --git a/rpc/support/pb/support_grpc.pb.go b/rpc/support/pb/support_grpc.pb.go new file mode 100644 index 0000000..0e80a8b --- /dev/null +++ b/rpc/support/pb/support_grpc.pb.go @@ -0,0 +1,121 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.2 +// - protoc v3.19.4 +// source: support/support.proto + +package support + +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 ( + Support_Call_FullMethodName = "/support.Support/Call" +) + +// SupportClient is the client API for Support 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 SupportClient interface { + Call(ctx context.Context, in *CallReq, opts ...grpc.CallOption) (*Response, error) +} + +type supportClient struct { + cc grpc.ClientConnInterface +} + +func NewSupportClient(cc grpc.ClientConnInterface) SupportClient { + return &supportClient{cc} +} + +func (c *supportClient) Call(ctx context.Context, in *CallReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Support_Call_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// SupportServer is the server API for Support service. +// All implementations must embed UnimplementedSupportServer +// for forward compatibility. +type SupportServer interface { + Call(context.Context, *CallReq) (*Response, error) + mustEmbedUnimplementedSupportServer() +} + +// UnimplementedSupportServer 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 UnimplementedSupportServer struct{} + +func (UnimplementedSupportServer) Call(context.Context, *CallReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Call not implemented") +} +func (UnimplementedSupportServer) mustEmbedUnimplementedSupportServer() {} +func (UnimplementedSupportServer) testEmbeddedByValue() {} + +// UnsafeSupportServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to SupportServer will +// result in compilation errors. +type UnsafeSupportServer interface { + mustEmbedUnimplementedSupportServer() +} + +func RegisterSupportServer(s grpc.ServiceRegistrar, srv SupportServer) { + // If the following call panics, it indicates UnimplementedSupportServer 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(&Support_ServiceDesc, srv) +} + +func _Support_Call_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CallReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SupportServer).Call(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Support_Call_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SupportServer).Call(ctx, req.(*CallReq)) + } + return interceptor(ctx, in, info, handler) +} + +// Support_ServiceDesc is the grpc.ServiceDesc for Support service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Support_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "support.Support", + HandlerType: (*SupportServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Call", + Handler: _Support_Call_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "support/support.proto", +} diff --git a/rpc/support/support.pb b/rpc/support/support.pb new file mode 100644 index 0000000000000000000000000000000000000000..24c1affc0e45b46c652a2529bd9728b0dd76535e GIT binary patch literal 14009 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 /etc/timezone + +COPY --from=builder /out/main . + +EXPOSE 11600 + +CMD ["./main", "-f", "etc/support.yaml"] diff --git a/services/support/etc/support.yaml b/services/support/etc/support.yaml new file mode 100644 index 0000000..551c236 --- /dev/null +++ b/services/support/etc/support.yaml @@ -0,0 +1,7 @@ +Nacos: + Hosts: + - rnacos:8848 + NamespaceId: test + Group: LONE_SERVICES + RegisterIP: support + ConfigID: support diff --git a/services/support/internal/ccc/client.go b/services/support/internal/ccc/client.go new file mode 100644 index 0000000..3a9d6ea --- /dev/null +++ b/services/support/internal/ccc/client.go @@ -0,0 +1,80 @@ +package ccc + +import ( + "encoding/json" + "fmt" + "strings" + + openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" + openapiutil "github.com/alibabacloud-go/openapi-util/service" + util "github.com/alibabacloud-go/tea-utils/v2/service" + "github.com/alibabacloud-go/tea/tea" +) + +const defaultEndpoint = "ccc.cn-shanghai.aliyuncs.com" + +func createClient(accessKeyId, accessKeySecret, endpoint string) (*openapi.Client, error) { + if endpoint == "" { + endpoint = defaultEndpoint + } + cfg := &openapi.Config{ + AccessKeyId: tea.String(accessKeyId), + AccessKeySecret: tea.String(accessKeySecret), + Endpoint: tea.String(endpoint), + } + return openapi.NewClient(cfg) +} + +func createApiInfo(action, version string) *openapi.Params { + return &openapi.Params{ + Action: tea.String(action), + Version: tea.String(version), + Protocol: tea.String("HTTPS"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + Pathname: tea.String("/"), + ReqBodyType: tea.String("json"), + BodyType: tea.String("json"), + } +} + +func capitalizeKey(key string) string { + if key == "" { + return key + } + return strings.ToUpper(key[:1]) + key[1:] +} + +func Call(action, version, requestJSON, accessKeyId, accessKeySecret, endpoint string) (any, error) { + client, err := createClient(accessKeyId, accessKeySecret, endpoint) + if err != nil { + return nil, err + } + + requestStr := strings.TrimSpace(requestJSON) + if requestStr == "" { + requestStr = "{}" + } + + var requestStruct map[string]any + if err = json.NewDecoder(strings.NewReader(requestStr)).Decode(&requestStruct); err != nil { + return nil, fmt.Errorf("request json: %w", err) + } + + queries := make(map[string]any, len(requestStruct)) + for key, value := range requestStruct { + queries[capitalizeKey(key)] = value + } + + res, err := client.CallApi(createApiInfo(action, version), &openapi.OpenApiRequest{ + Query: openapiutil.Query(queries), + }, &util.RuntimeOptions{}) + if err != nil { + return nil, err + } + if res == nil { + return nil, nil + } + return res["body"], nil +} diff --git a/services/support/internal/config/config.go b/services/support/internal/config/config.go new file mode 100644 index 0000000..a1979dd --- /dev/null +++ b/services/support/internal/config/config.go @@ -0,0 +1,13 @@ +package config + +type Config struct { + Nacos NacosConf +} + +type NacosConf struct { + Hosts []string + NamespaceId string `json:",optional"` + Group string `json:",optional"` + RegisterIP string `json:",optional"` + ConfigID string `json:",optional"` +} diff --git a/services/support/internal/logic/callLogic.go b/services/support/internal/logic/callLogic.go new file mode 100644 index 0000000..759d4ff --- /dev/null +++ b/services/support/internal/logic/callLogic.go @@ -0,0 +1,43 @@ +package logic + +import ( + "context" + + "lone-services/pkg/utils" + "lone-services/pkg/validate" + support "lone-services/rpc/support/pb" + "lone-services/services/support/internal/ccc" + "lone-services/services/support/internal/svc" + "lone-services/services/support/validator" + + "github.com/zeromicro/go-zero/core/logx" +) + +type CallLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewCallLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CallLogic { + return &CallLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *CallLogic) Call(in *support.CallReq) (*support.Response, error) { + var req validator.CallValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + endpoint := utils.GetConfigString("ccc.endpoint") + body, err := ccc.Call(req.Action, req.Version, req.Request, req.A, req.S, endpoint) + if err != nil { + l.Errorf("ccc call action=%s version=%s: %v", req.Action, req.Version, err) + return outResponse(utils.Fail, err.Error()), nil + } + return okResponse(body), nil +} diff --git a/services/support/internal/logic/response.go b/services/support/internal/logic/response.go new file mode 100644 index 0000000..d867dbb --- /dev/null +++ b/services/support/internal/logic/response.go @@ -0,0 +1,31 @@ +package logic + +import ( + "lone-services/pkg/utils" + support "lone-services/rpc/support/pb" + + jsoniter "github.com/json-iterator/go" +) + +func okResponse(data any) *support.Response { + buf, _ := jsoniter.Marshal(data) + return &support.Response{ + Code: utils.Ok.Code, + Msg: utils.Ok.Msg, + Data: string(buf), + } +} + +func failResponse(status utils.Status) *support.Response { + return &support.Response{ + Code: status.Code, + Msg: status.Msg, + } +} + +func outResponse(status utils.Status, msg string) *support.Response { + return &support.Response{ + Code: status.Code, + Msg: msg, + } +} diff --git a/services/support/internal/server/supportServer.go b/services/support/internal/server/supportServer.go new file mode 100644 index 0000000..2199346 --- /dev/null +++ b/services/support/internal/server/supportServer.go @@ -0,0 +1,25 @@ +package server + +import ( + "context" + + support "lone-services/rpc/support/pb" + "lone-services/services/support/internal/logic" + "lone-services/services/support/internal/svc" +) + +type SupportServer struct { + svcCtx *svc.ServiceContext + support.UnimplementedSupportServer +} + +func NewSupportServer(svcCtx *svc.ServiceContext) *SupportServer { + return &SupportServer{ + svcCtx: svcCtx, + } +} + +func (s *SupportServer) Call(ctx context.Context, in *support.CallReq) (*support.Response, error) { + l := logic.NewCallLogic(ctx, s.svcCtx) + return l.Call(in) +} diff --git a/services/support/internal/svc/serviceContext.go b/services/support/internal/svc/serviceContext.go new file mode 100644 index 0000000..7c92181 --- /dev/null +++ b/services/support/internal/svc/serviceContext.go @@ -0,0 +1,22 @@ +package svc + +import ( + "lone-services/pkg/utils" + "lone-services/services/support/internal/config" + + "gorm.io/gorm" +) + +type ServiceContext struct { + Config config.Config + DB *gorm.DB + Prefix string +} + +func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext { + return &ServiceContext{ + Config: c, + DB: db, + Prefix: utils.GetConfigString("mysql.prefix"), + } +} diff --git a/services/support/run.toml b/services/support/run.toml new file mode 100644 index 0000000..27a3cca --- /dev/null +++ b/services/support/run.toml @@ -0,0 +1,48 @@ +[base] + login_out_time=43200 + login_refresh_out_time=83200 + name = "support-service" + listenOn = "0.0.0.0:11600" + mode = "dev" +[log] + path = "logs" + serviceName = "support-service" + mode = "file" + encoding = "plain" + level = "info" + keepDays = 7 + maxSize = 50 + maxBackups = 5 + compress = false + +[mysql] + host = '39.106.171.204' + port = 33066 + user = 'root' + password = 'MOLXRZNOU4Y4' + database = 'dms-support' + charset = 'utf8mb4' + prefix = '' + debug = true +[mysql_read] + host = '39.106.171.204' + port = 33066 + user = 'root' + password = 'MOLXRZNOU4Y4' + database = 'dms-support' + charset = 'utf8mb4' + prefix = '' + +[redis] + host = '39.106.171.204' + password = 'lLMLcuPpzSj' + port = 6379 + db = 0 +[log-redis] + host = '39.106.171.204' + password = 'lLMLcuPpzSj' + port = 6379 + db = 3 + +[encrypt] + data_key = "u2t9T3luZtoRfhBstkFN6TiIMW38BA8a" diff --git a/services/support/support.go b/services/support/support.go new file mode 100644 index 0000000..d4173d3 --- /dev/null +++ b/services/support/support.go @@ -0,0 +1,152 @@ +package main + +import ( + "flag" + "net" + "os" + "strconv" + + "lone-services/pkg/discovery" + "lone-services/pkg/modelbase" + "lone-services/pkg/mysql" + "lone-services/pkg/redis" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + support "lone-services/rpc/support/pb" + "lone-services/services/support/internal/config" + "lone-services/services/support/internal/server" + "lone-services/services/support/internal/svc" + + "github.com/zeromicro/go-zero/core/conf" + "github.com/zeromicro/go-zero/core/logx" + "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/support.yaml", "the config file") + +func main() { + flag.Parse() + var c config.Config + conf.MustLoad(*configFile, &c) + + nacosParam := utils.NacosConfig{ + Hosts: c.Nacos.Hosts, + NamespaceId: c.Nacos.NamespaceId, + Group: c.Nacos.Group, + ConfigID: c.Nacos.ConfigID, + } + utils.InitConfig(nacosParam) + + logConf := logx.LogConf{ + ServiceName: utils.GetConfigString("log.serviceName"), + Mode: utils.GetConfigString("log.mode"), + Encoding: utils.GetConfigString("log.encoding"), + Level: utils.GetConfigString("log.level"), + Path: utils.GetConfigString("log.path"), + KeepDays: utils.GetConfigInt("log.keepDays"), + MaxSize: utils.GetConfigInt("log.maxSize"), + MaxBackups: utils.GetConfigInt("log.maxBackups"), + Compress: utils.GetConfigBool("log.compress"), + } + logx.SetUp(logConf) + logx.AddWriter(logx.NewWriter(os.Stdout)) + + listenOn := utils.GetConfigString("base.listenOn") + mode := utils.GetConfigString("base.mode") + serviceName := utils.GetConfigString("base.name") + + if err := discovery.Init(discovery.Config{ + Hosts: c.Nacos.Hosts, + NamespaceId: c.Nacos.NamespaceId, + Group: c.Nacos.Group, + }); err != nil { + logx.Errorf("nacos init: %v", err) + os.Exit(1) + } + + port, err := listenPort(listenOn) + if err != nil { + logx.Errorf("parse ListenOn: %v", err) + os.Exit(1) + } + + if err := discovery.Register(discovery.Instance{ + ServiceName: serviceName, + IP: c.Nacos.RegisterIP, + Port: port, + Group: c.Nacos.Group, + }); err != nil { + logx.Errorf("nacos register: %v", err) + os.Exit(1) + } + logx.Infof("服务注册成功: %s:%d", c.Nacos.RegisterIP, port) + + defer func() { + if err := discovery.Deregister(); err != nil { + logx.Errorf("nacos deregister: %v", err) + } + }() + + db, err := mysql.New(mysql.Config{ + Host: utils.GetConfigString("mysql.host"), + Port: utils.GetConfigInt("mysql.port"), + User: utils.GetConfigString("mysql.user"), + Password: utils.GetConfigString("mysql.password"), + Database: utils.GetConfigString("mysql.database"), + Charset: utils.GetConfigString("mysql.charset"), + Prefix: utils.GetConfigString("mysql.prefix"), + ReadHost: utils.GetConfigString("mysql_read.host"), + ReadPort: utils.GetConfigInt("mysql_read.port"), + ReadUser: utils.GetConfigString("mysql_read.user"), + ReadPassword: utils.GetConfigString("mysql_read.password"), + ReadDatabase: utils.GetConfigString("mysql_read.database"), + }) + if err != nil { + logx.Errorf("mysql init: %v", err) + os.Exit(1) + } + + if err := redis.Init(redis.Config{ + Host: utils.GetConfigString("redis.host"), + Port: utils.GetConfigInt("redis.port"), + Password: utils.GetConfigString("redis.password"), + DB: utils.GetConfigInt("redis.db"), + }); err != nil { + logx.Errorf("redis init: %v", err) + os.Exit(1) + } + + debug := utils.GetConfigBool("mysql.debug") + modelbase.Init(db, modelbase.Config{Prefix: utils.GetConfigString("mysql.prefix"), Debug: debug}) + + rpcConf := zrpc.RpcServerConf{ + ListenOn: listenOn, + } + rpcConf.Mode = mode + + ctx := svc.NewServiceContext(c, db) + + s := zrpc.MustNewServer(rpcConf, func(grpcServer *grpc.Server) { + support.RegisterSupportServer(grpcServer, server.NewSupportServer(ctx)) + if mode == service.DevMode || mode == service.TestMode { + reflection.Register(grpcServer) + } + }) + defer s.Stop() + + s.AddUnaryInterceptors(validate.UnaryServerInterceptor(validate.MustNew())) + + logx.Infof("Starting rpc server at %s...", listenOn) + s.Start() +} + +func listenPort(listenOn string) (uint64, error) { + _, portStr, err := net.SplitHostPort(listenOn) + if err != nil { + return 0, err + } + return strconv.ParseUint(portStr, 10, 64) +} diff --git a/services/support/supportClient/support.go b/services/support/supportClient/support.go new file mode 100644 index 0000000..fa1e502 --- /dev/null +++ b/services/support/supportClient/support.go @@ -0,0 +1,32 @@ +package supportClient + +import ( + "context" + + support "lone-services/rpc/support/pb" + + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" +) + +type ( + CallReq = support.CallReq + Response = support.Response + + Support interface { + Call(ctx context.Context, in *CallReq, opts ...grpc.CallOption) (*Response, error) + } + + defaultSupport struct { + cli zrpc.Client + } +) + +func NewSupport(cli zrpc.Client) Support { + return &defaultSupport{cli: cli} +} + +func (m *defaultSupport) Call(ctx context.Context, in *CallReq, opts ...grpc.CallOption) (*Response, error) { + client := support.NewSupportClient(m.cli.Conn()) + return client.Call(ctx, in, opts...) +} diff --git a/services/support/validator/call.go b/services/support/validator/call.go new file mode 100644 index 0000000..fc4c122 --- /dev/null +++ b/services/support/validator/call.go @@ -0,0 +1,25 @@ +package validator + +import "lone-services/pkg/validate" + +type CallValidator struct { + Action string `validate:"required,max=128"` + Version string `validate:"required,max=32"` + Request string `validate:"max=1024"` + A string `validate:"required,max=128"` + S string `validate:"required,max=128"` +} + +func (p CallValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Action.required": "action不能为空", + "Action.max": "action过长", + "Version.required": "version不能为空", + "Version.max": "version过长", + "Request.max": "request过长", + "A.required": "accessKeyId不能为空", + "A.max": "accessKeyId过长", + "S.required": "accessKeySecret不能为空", + "S.max": "accessKeySecret过长", + } +}