feat 结构调整

This commit is contained in:
2025-12-20 15:39:25 +08:00
parent 55c5d4cc18
commit ff1bd1d0b6
96 changed files with 4904 additions and 350 deletions

View File

@@ -0,0 +1,224 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.32.0
// protoc v4.25.1
// source: service_user.proto
package grpc_pb
import (
_ "common/proto/ss/ss_common"
_ "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"
)
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 LoginReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Phone string `protobuf:"bytes,1,opt,name=Phone,json=phone,proto3" json:"Phone,omitempty"` // 手机号
Code string `protobuf:"bytes,2,opt,name=Code,json=code,proto3" json:"Code,omitempty"` // 验证码
}
func (x *LoginReq) Reset() {
*x = LoginReq{}
if protoimpl.UnsafeEnabled {
mi := &file_service_user_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *LoginReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LoginReq) ProtoMessage() {}
func (x *LoginReq) ProtoReflect() protoreflect.Message {
mi := &file_service_user_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LoginReq.ProtoReflect.Descriptor instead.
func (*LoginReq) Descriptor() ([]byte, []int) {
return file_service_user_proto_rawDescGZIP(), []int{0}
}
func (x *LoginReq) GetPhone() string {
if x != nil {
return x.Phone
}
return ""
}
func (x *LoginReq) GetCode() string {
if x != nil {
return x.Code
}
return ""
}
type LoginResp struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
UID int32 `protobuf:"varint,1,opt,name=UID,json=uid,proto3" json:"UID,omitempty"` // 用户ID
}
func (x *LoginResp) Reset() {
*x = LoginResp{}
if protoimpl.UnsafeEnabled {
mi := &file_service_user_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *LoginResp) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LoginResp) ProtoMessage() {}
func (x *LoginResp) ProtoReflect() protoreflect.Message {
mi := &file_service_user_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LoginResp.ProtoReflect.Descriptor instead.
func (*LoginResp) Descriptor() ([]byte, []int) {
return file_service_user_proto_rawDescGZIP(), []int{1}
}
func (x *LoginResp) GetUID() int32 {
if x != nil {
return x.UID
}
return 0
}
var File_service_user_proto protoreflect.FileDescriptor
var file_service_user_proto_rawDesc = []byte{
0x0a, 0x12, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0f, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70,
0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0x34, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12,
0x14, 0x0a, 0x05, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
0x70, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x1d, 0x0a, 0x09, 0x4c, 0x6f, 0x67,
0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, 0x44, 0x18, 0x01, 0x20,
0x01, 0x28, 0x05, 0x52, 0x03, 0x75, 0x69, 0x64, 0x32, 0x3e, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72,
0x12, 0x36, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x09, 0x2e, 0x4c, 0x6f, 0x67, 0x69,
0x6e, 0x52, 0x65, 0x71, 0x1a, 0x0a, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70,
0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, 0x22, 0x0b, 0x2f, 0x75, 0x73,
0x65, 0x72, 0x2f, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x42, 0x19, 0x5a, 0x17, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x73, 0x2f, 0x67, 0x72, 0x70, 0x63,
0x5f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_service_user_proto_rawDescOnce sync.Once
file_service_user_proto_rawDescData = file_service_user_proto_rawDesc
)
func file_service_user_proto_rawDescGZIP() []byte {
file_service_user_proto_rawDescOnce.Do(func() {
file_service_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_service_user_proto_rawDescData)
})
return file_service_user_proto_rawDescData
}
var file_service_user_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_service_user_proto_goTypes = []interface{}{
(*LoginReq)(nil), // 0: LoginReq
(*LoginResp)(nil), // 1: LoginResp
}
var file_service_user_proto_depIdxs = []int32{
0, // 0: User.Login:input_type -> LoginReq
1, // 1: User.Login:output_type -> LoginResp
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_service_user_proto_init() }
func file_service_user_proto_init() {
if File_service_user_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_service_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_service_user_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginResp); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_service_user_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_service_user_proto_goTypes,
DependencyIndexes: file_service_user_proto_depIdxs,
MessageInfos: file_service_user_proto_msgTypes,
}.Build()
File_service_user_proto = out.File
file_service_user_proto_rawDesc = nil
file_service_user_proto_goTypes = nil
file_service_user_proto_depIdxs = nil
}

View File

@@ -0,0 +1,154 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: service_user.proto
/*
Package grpc_pb is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package grpc_pb
import (
"context"
"errors"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
var (
_ codes.Code
_ io.Reader
_ status.Status
_ = errors.New
_ = runtime.String
_ = utilities.NewDoubleArray
_ = metadata.Join
)
func request_User_Login_0(ctx context.Context, marshaler runtime.Marshaler, client UserClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq LoginReq
metadata runtime.ServerMetadata
)
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.Login(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_User_Login_0(ctx context.Context, marshaler runtime.Marshaler, server UserServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq LoginReq
metadata runtime.ServerMetadata
)
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.Login(ctx, &protoReq)
return msg, metadata, err
}
// RegisterUserHandlerServer registers the http handlers for service User to "mux".
// UnaryRPC :call UserServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterUserHandlerFromEndpoint instead.
// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call.
func RegisterUserHandlerServer(ctx context.Context, mux *runtime.ServeMux, server UserServer) error {
mux.Handle(http.MethodPost, pattern_User_Login_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/.User/Login", runtime.WithHTTPPathPattern("/user/login"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_User_Login_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_User_Login_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterUserHandlerFromEndpoint is same as RegisterUserHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterUserHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.NewClient(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterUserHandler(ctx, mux, conn)
}
// RegisterUserHandler registers the http handlers for service User to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterUserHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterUserHandlerClient(ctx, mux, NewUserClient(conn))
}
// RegisterUserHandlerClient registers the http handlers for service User
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "UserClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "UserClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "UserClient" to call the correct interceptors. This client ignores the HTTP middlewares.
func RegisterUserHandlerClient(ctx context.Context, mux *runtime.ServeMux, client UserClient) error {
mux.Handle(http.MethodPost, pattern_User_Login_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/.User/Login", runtime.WithHTTPPathPattern("/user/login"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_User_Login_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_User_Login_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_User_Login_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"user", "login"}, ""))
)
var (
forward_User_Login_0 = runtime.ForwardResponseMessage
)

View File

@@ -0,0 +1,105 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v4.25.1
// source: service_user.proto
package grpc_pb
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.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// 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 {
Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*LoginResp, error)
}
type userClient struct {
cc grpc.ClientConnInterface
}
func NewUserClient(cc grpc.ClientConnInterface) UserClient {
return &userClient{cc}
}
func (c *userClient) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*LoginResp, error) {
out := new(LoginResp)
err := c.cc.Invoke(ctx, "/User/Login", in, out, opts...)
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 {
Login(context.Context, *LoginReq) (*LoginResp, error)
mustEmbedUnimplementedUserServer()
}
// UnimplementedUserServer must be embedded to have forward compatible implementations.
type UnimplementedUserServer struct {
}
func (UnimplementedUserServer) Login(context.Context, *LoginReq) (*LoginResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method Login not implemented")
}
func (UnimplementedUserServer) mustEmbedUnimplementedUserServer() {}
// 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) {
s.RegisterService(&User_ServiceDesc, srv)
}
func _User_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(LoginReq)
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",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserServer).Login(ctx, req.(*LoginReq))
}
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",
HandlerType: (*UserServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Login",
Handler: _User_Login_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "service_user.proto",
}

View File

@@ -10,6 +10,7 @@ import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
@@ -19,16 +20,89 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ErrorInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"`
}
func (x *ErrorInfo) Reset() {
*x = ErrorInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_ss_common_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ErrorInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ErrorInfo) ProtoMessage() {}
func (x *ErrorInfo) ProtoReflect() protoreflect.Message {
mi := &file_ss_common_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ErrorInfo.ProtoReflect.Descriptor instead.
func (*ErrorInfo) Descriptor() ([]byte, []int) {
return file_ss_common_proto_rawDescGZIP(), []int{0}
}
func (x *ErrorInfo) GetCode() int32 {
if x != nil {
return x.Code
}
return 0
}
func (x *ErrorInfo) GetMsg() string {
if x != nil {
return x.Msg
}
return ""
}
var File_ss_common_proto protoreflect.FileDescriptor
var file_ss_common_proto_rawDesc = []byte{
0x0a, 0x0f, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x42, 0x1b, 0x5a, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2f, 0x73, 0x73, 0x2f, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6f, 0x22, 0x31, 0x0a, 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12,
0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f,
0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x6d, 0x73, 0x67, 0x42, 0x1b, 0x5a, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x73, 0x2f, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var file_ss_common_proto_goTypes = []interface{}{}
var (
file_ss_common_proto_rawDescOnce sync.Once
file_ss_common_proto_rawDescData = file_ss_common_proto_rawDesc
)
func file_ss_common_proto_rawDescGZIP() []byte {
file_ss_common_proto_rawDescOnce.Do(func() {
file_ss_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_ss_common_proto_rawDescData)
})
return file_ss_common_proto_rawDescData
}
var file_ss_common_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_ss_common_proto_goTypes = []interface{}{
(*ErrorInfo)(nil), // 0: ErrorInfo
}
var file_ss_common_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
@@ -42,18 +116,33 @@ func file_ss_common_proto_init() {
if File_ss_common_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_ss_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ErrorInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_ss_common_proto_rawDesc,
NumEnums: 0,
NumMessages: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ss_common_proto_goTypes,
DependencyIndexes: file_ss_common_proto_depIdxs,
MessageInfos: file_ss_common_proto_msgTypes,
}.Build()
File_ss_common_proto = out.File
file_ss_common_proto_rawDesc = nil

View File

@@ -0,0 +1,52 @@
{
"swagger": "2.0",
"info": {
"title": "service_gateway.proto",
"version": "version not set"
},
"tags": [
{
"name": "Gateway"
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {},
"definitions": {
"ToClientResp": {
"type": "object"
},
"protobufAny": {
"type": "object",
"properties": {
"@type": {
"type": "string"
}
},
"additionalProperties": {}
},
"rpcStatus": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/protobufAny"
}
}
}
}
}
}

View File

@@ -0,0 +1,80 @@
{
"swagger": "2.0",
"info": {
"title": "service_scene.proto",
"version": "version not set"
},
"tags": [
{
"name": "Scene"
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {},
"definitions": {
"ActionResp": {
"type": "object"
},
"EnterResp": {
"type": "object",
"properties": {
"SceneSID": {
"type": "string",
"format": "int64",
"title": "场景服务ID"
},
"UniqueNo": {
"type": "string",
"format": "int64",
"title": "副本唯一编号"
},
"MessageID": {
"type": "integer",
"format": "int32",
"title": "发送给客户端的消息ID"
},
"Payload": {
"type": "string",
"format": "byte",
"title": "消息负载"
}
}
},
"LeaveResp": {
"type": "object"
},
"protobufAny": {
"type": "object",
"properties": {
"@type": {
"type": "string"
}
},
"additionalProperties": {}
},
"rpcStatus": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/protobufAny"
}
}
}
}
}
}

View File

@@ -0,0 +1,105 @@
{
"swagger": "2.0",
"info": {
"title": "service_user.proto",
"version": "version not set"
},
"tags": [
{
"name": "User"
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/user/login": {
"post": {
"operationId": "User_Login",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/LoginResp"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/LoginReq"
}
}
],
"tags": [
"User"
]
}
}
},
"definitions": {
"LoginReq": {
"type": "object",
"properties": {
"phone": {
"type": "string",
"title": "手机号"
},
"code": {
"type": "string",
"title": "验证码"
}
}
},
"LoginResp": {
"type": "object",
"properties": {
"uid": {
"type": "integer",
"format": "int32",
"title": "用户ID"
}
}
},
"protobufAny": {
"type": "object",
"properties": {
"@type": {
"type": "string"
}
},
"additionalProperties": {}
},
"rpcStatus": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/protobufAny"
}
}
}
}
}
}

View File

@@ -0,0 +1,44 @@
{
"swagger": "2.0",
"info": {
"title": "ss_common.proto",
"version": "version not set"
},
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {},
"definitions": {
"protobufAny": {
"type": "object",
"properties": {
"@type": {
"type": "string"
}
},
"additionalProperties": {}
},
"rpcStatus": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/protobufAny"
}
}
}
}
}
}

View File

@@ -4,5 +4,11 @@ if not exist "./gen" (
mkdir "./gen"
)
protoc --proto_path=./sources --go_out=./gen --go-grpc_out=./gen ./sources/*.proto
protoc ^
--proto_path=./sources ^
--go_out=./gen ^
--go-grpc_out=./gen ^
--grpc-gateway_out=./gen ^
--openapiv2_out=./gen ^
./sources/*.proto
xcopy "./gen/common" "../../../Server/common" /E /I /Y /Q

View File

@@ -0,0 +1,31 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package google.api;
import "google/api/http.proto";
import "google/protobuf/descriptor.proto";
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
option java_multiple_files = true;
option java_outer_classname = "AnnotationsProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";
extend google.protobuf.MethodOptions {
// See `HttpRule`.
HttpRule http = 72295728;
}

View File

@@ -0,0 +1,370 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package google.api;
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
option java_multiple_files = true;
option java_outer_classname = "HttpProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";
// Defines the HTTP configuration for an API service. It contains a list of
// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method
// to one or more HTTP REST API methods.
message Http {
// A list of HTTP configuration rules that apply to individual API methods.
//
// **NOTE:** All service configuration rules follow "last one wins" order.
repeated HttpRule rules = 1;
// When set to true, URL path parameters will be fully URI-decoded except in
// cases of single segment matches in reserved expansion, where "%2F" will be
// left encoded.
//
// The default behavior is to not decode RFC 6570 reserved characters in multi
// segment matches.
bool fully_decode_reserved_expansion = 2;
}
// gRPC Transcoding
//
// gRPC Transcoding is a feature for mapping between a gRPC method and one or
// more HTTP REST endpoints. It allows developers to build a single API service
// that supports both gRPC APIs and REST APIs. Many systems, including [Google
// APIs](https://github.com/googleapis/googleapis),
// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC
// Gateway](https://github.com/grpc-ecosystem/grpc-gateway),
// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature
// and use it for large scale production services.
//
// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies
// how different portions of the gRPC request message are mapped to the URL
// path, URL query parameters, and HTTP request body. It also controls how the
// gRPC response message is mapped to the HTTP response body. `HttpRule` is
// typically specified as an `google.api.http` annotation on the gRPC method.
//
// Each mapping specifies a URL path template and an HTTP method. The path
// template may refer to one or more fields in the gRPC request message, as long
// as each field is a non-repeated field with a primitive (non-message) type.
// The path template controls how fields of the request message are mapped to
// the URL path.
//
// Example:
//
// service Messaging {
// rpc GetMessage(GetMessageRequest) returns (Message) {
// option (google.api.http) = {
// get: "/v1/{name=messages/*}"
// };
// }
// }
// message GetMessageRequest {
// string name = 1; // Mapped to URL path.
// }
// message Message {
// string text = 1; // The resource content.
// }
//
// This enables an HTTP REST to gRPC mapping as below:
//
// - HTTP: `GET /v1/messages/123456`
// - gRPC: `GetMessage(name: "messages/123456")`
//
// Any fields in the request message which are not bound by the path template
// automatically become HTTP query parameters if there is no HTTP request body.
// For example:
//
// service Messaging {
// rpc GetMessage(GetMessageRequest) returns (Message) {
// option (google.api.http) = {
// get:"/v1/messages/{message_id}"
// };
// }
// }
// message GetMessageRequest {
// message SubMessage {
// string subfield = 1;
// }
// string message_id = 1; // Mapped to URL path.
// int64 revision = 2; // Mapped to URL query parameter `revision`.
// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`.
// }
//
// This enables a HTTP JSON to RPC mapping as below:
//
// - HTTP: `GET /v1/messages/123456?revision=2&sub.subfield=foo`
// - gRPC: `GetMessage(message_id: "123456" revision: 2 sub:
// SubMessage(subfield: "foo"))`
//
// Note that fields which are mapped to URL query parameters must have a
// primitive type or a repeated primitive type or a non-repeated message type.
// In the case of a repeated type, the parameter can be repeated in the URL
// as `...?param=A&param=B`. In the case of a message type, each field of the
// message is mapped to a separate parameter, such as
// `...?foo.a=A&foo.b=B&foo.c=C`.
//
// For HTTP methods that allow a request body, the `body` field
// specifies the mapping. Consider a REST update method on the
// message resource collection:
//
// service Messaging {
// rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
// option (google.api.http) = {
// patch: "/v1/messages/{message_id}"
// body: "message"
// };
// }
// }
// message UpdateMessageRequest {
// string message_id = 1; // mapped to the URL
// Message message = 2; // mapped to the body
// }
//
// The following HTTP JSON to RPC mapping is enabled, where the
// representation of the JSON in the request body is determined by
// protos JSON encoding:
//
// - HTTP: `PATCH /v1/messages/123456 { "text": "Hi!" }`
// - gRPC: `UpdateMessage(message_id: "123456" message { text: "Hi!" })`
//
// The special name `*` can be used in the body mapping to define that
// every field not bound by the path template should be mapped to the
// request body. This enables the following alternative definition of
// the update method:
//
// service Messaging {
// rpc UpdateMessage(Message) returns (Message) {
// option (google.api.http) = {
// patch: "/v1/messages/{message_id}"
// body: "*"
// };
// }
// }
// message Message {
// string message_id = 1;
// string text = 2;
// }
//
//
// The following HTTP JSON to RPC mapping is enabled:
//
// - HTTP: `PATCH /v1/messages/123456 { "text": "Hi!" }`
// - gRPC: `UpdateMessage(message_id: "123456" text: "Hi!")`
//
// Note that when using `*` in the body mapping, it is not possible to
// have HTTP parameters, as all fields not bound by the path end in
// the body. This makes this option more rarely used in practice when
// defining REST APIs. The common usage of `*` is in custom methods
// which don't use the URL at all for transferring data.
//
// It is possible to define multiple HTTP methods for one RPC by using
// the `additional_bindings` option. Example:
//
// service Messaging {
// rpc GetMessage(GetMessageRequest) returns (Message) {
// option (google.api.http) = {
// get: "/v1/messages/{message_id}"
// additional_bindings {
// get: "/v1/users/{user_id}/messages/{message_id}"
// }
// };
// }
// }
// message GetMessageRequest {
// string message_id = 1;
// string user_id = 2;
// }
//
// This enables the following two alternative HTTP JSON to RPC mappings:
//
// - HTTP: `GET /v1/messages/123456`
// - gRPC: `GetMessage(message_id: "123456")`
//
// - HTTP: `GET /v1/users/me/messages/123456`
// - gRPC: `GetMessage(user_id: "me" message_id: "123456")`
//
// Rules for HTTP mapping
//
// 1. Leaf request fields (recursive expansion nested messages in the request
// message) are classified into three categories:
// - Fields referred by the path template. They are passed via the URL path.
// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They
// are passed via the HTTP
// request body.
// - All other fields are passed via the URL query parameters, and the
// parameter name is the field path in the request message. A repeated
// field can be represented as multiple query parameters under the same
// name.
// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL
// query parameter, all fields
// are passed via URL path and HTTP request body.
// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP
// request body, all
// fields are passed via URL path and URL query parameters.
//
// Path template syntax
//
// Template = "/" Segments [ Verb ] ;
// Segments = Segment { "/" Segment } ;
// Segment = "*" | "**" | LITERAL | Variable ;
// Variable = "{" FieldPath [ "=" Segments ] "}" ;
// FieldPath = IDENT { "." IDENT } ;
// Verb = ":" LITERAL ;
//
// The syntax `*` matches a single URL path segment. The syntax `**` matches
// zero or more URL path segments, which must be the last part of the URL path
// except the `Verb`.
//
// The syntax `Variable` matches part of the URL path as specified by its
// template. A variable template must not contain other variables. If a variable
// matches a single path segment, its template may be omitted, e.g. `{var}`
// is equivalent to `{var=*}`.
//
// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL`
// contains any reserved character, such characters should be percent-encoded
// before the matching.
//
// If a variable contains exactly one path segment, such as `"{var}"` or
// `"{var=*}"`, when such a variable is expanded into a URL path on the client
// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The
// server side does the reverse decoding. Such variables show up in the
// [Discovery
// Document](https://developers.google.com/discovery/v1/reference/apis) as
// `{var}`.
//
// If a variable contains multiple path segments, such as `"{var=foo/*}"`
// or `"{var=**}"`, when such a variable is expanded into a URL path on the
// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded.
// The server side does the reverse decoding, except "%2F" and "%2f" are left
// unchanged. Such variables show up in the
// [Discovery
// Document](https://developers.google.com/discovery/v1/reference/apis) as
// `{+var}`.
//
// Using gRPC API Service Configuration
//
// gRPC API Service Configuration (service config) is a configuration language
// for configuring a gRPC service to become a user-facing product. The
// service config is simply the YAML representation of the `google.api.Service`
// proto message.
//
// As an alternative to annotating your proto file, you can configure gRPC
// transcoding in your service config YAML files. You do this by specifying a
// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same
// effect as the proto annotation. This can be particularly useful if you
// have a proto that is reused in multiple services. Note that any transcoding
// specified in the service config will override any matching transcoding
// configuration in the proto.
//
// The following example selects a gRPC method and applies an `HttpRule` to it:
//
// http:
// rules:
// - selector: example.v1.Messaging.GetMessage
// get: /v1/messages/{message_id}/{sub.subfield}
//
// Special notes
//
// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the
// proto to JSON conversion must follow the [proto3
// specification](https://developers.google.com/protocol-buffers/docs/proto3#json).
//
// While the single segment variable follows the semantics of
// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String
// Expansion, the multi segment variable **does not** follow RFC 6570 Section
// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion
// does not expand special characters like `?` and `#`, which would lead
// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding
// for multi segment variables.
//
// The path variables **must not** refer to any repeated or mapped field,
// because client libraries are not capable of handling such variable expansion.
//
// The path variables **must not** capture the leading "/" character. The reason
// is that the most common use case "{var}" does not capture the leading "/"
// character. For consistency, all path variables must share the same behavior.
//
// Repeated message fields must not be mapped to URL query parameters, because
// no client library can support such complicated mapping.
//
// If an API needs to use a JSON array for request or response body, it can map
// the request or response body to a repeated field. However, some gRPC
// Transcoding implementations may not support this feature.
message HttpRule {
// Selects a method to which this rule applies.
//
// Refer to [selector][google.api.DocumentationRule.selector] for syntax
// details.
string selector = 1;
// Determines the URL pattern is matched by this rules. This pattern can be
// used with any of the {get|put|post|delete|patch} methods. A custom method
// can be defined using the 'custom' field.
oneof pattern {
// Maps to HTTP GET. Used for listing and getting information about
// resources.
string get = 2;
// Maps to HTTP PUT. Used for replacing a resource.
string put = 3;
// Maps to HTTP POST. Used for creating a resource or performing an action.
string post = 4;
// Maps to HTTP DELETE. Used for deleting a resource.
string delete = 5;
// Maps to HTTP PATCH. Used for updating a resource.
string patch = 6;
// The custom pattern is used for specifying an HTTP method that is not
// included in the `pattern` field, such as HEAD, or "*" to leave the
// HTTP method unspecified for this rule. The wild-card rule is useful
// for services that provide content to Web (HTML) clients.
CustomHttpPattern custom = 8;
}
// The name of the request field whose value is mapped to the HTTP request
// body, or `*` for mapping all request fields not captured by the path
// pattern to the HTTP body, or omitted for not having any HTTP request body.
//
// NOTE: the referred field must be present at the top-level of the request
// message type.
string body = 7;
// Optional. The name of the response field whose value is mapped to the HTTP
// response body. When omitted, the entire response message will be used
// as the HTTP response body.
//
// NOTE: The referred field must be present at the top-level of the response
// message type.
string response_body = 12;
// Additional HTTP bindings for the selector. Nested bindings must
// not contain an `additional_bindings` field themselves (that is,
// the nesting may only be one level deep).
repeated HttpRule additional_bindings = 11;
}
// A custom pattern is used for defining custom HTTP verb.
message CustomHttpPattern {
// The name of this custom HTTP verb.
string kind = 1;
// The path matched by this custom verb.
string path = 2;
}

View File

@@ -0,0 +1,162 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option go_package = "google.golang.org/protobuf/types/known/anypb";
option java_package = "com.google.protobuf";
option java_outer_classname = "AnyProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
// `Any` contains an arbitrary serialized protocol buffer message along with a
// URL that describes the type of the serialized message.
//
// Protobuf library provides support to pack/unpack Any values in the form
// of utility functions or additional generated methods of the Any type.
//
// Example 1: Pack and unpack a message in C++.
//
// Foo foo = ...;
// Any any;
// any.PackFrom(foo);
// ...
// if (any.UnpackTo(&foo)) {
// ...
// }
//
// Example 2: Pack and unpack a message in Java.
//
// Foo foo = ...;
// Any any = Any.pack(foo);
// ...
// if (any.is(Foo.class)) {
// foo = any.unpack(Foo.class);
// }
// // or ...
// if (any.isSameTypeAs(Foo.getDefaultInstance())) {
// foo = any.unpack(Foo.getDefaultInstance());
// }
//
// Example 3: Pack and unpack a message in Python.
//
// foo = Foo(...)
// any = Any()
// any.Pack(foo)
// ...
// if any.Is(Foo.DESCRIPTOR):
// any.Unpack(foo)
// ...
//
// Example 4: Pack and unpack a message in Go
//
// foo := &pb.Foo{...}
// any, err := anypb.New(foo)
// if err != nil {
// ...
// }
// ...
// foo := &pb.Foo{}
// if err := any.UnmarshalTo(foo); err != nil {
// ...
// }
//
// The pack methods provided by protobuf library will by default use
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
// methods only use the fully qualified type name after the last '/'
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
// name "y.z".
//
// JSON
// ====
// The JSON representation of an `Any` value uses the regular
// representation of the deserialized, embedded message, with an
// additional field `@type` which contains the type URL. Example:
//
// package google.profile;
// message Person {
// string first_name = 1;
// string last_name = 2;
// }
//
// {
// "@type": "type.googleapis.com/google.profile.Person",
// "firstName": <string>,
// "lastName": <string>
// }
//
// If the embedded message type is well-known and has a custom JSON
// representation, that representation will be embedded adding a field
// `value` which holds the custom JSON in addition to the `@type`
// field. Example (for message [google.protobuf.Duration][]):
//
// {
// "@type": "type.googleapis.com/google.protobuf.Duration",
// "value": "1.212s"
// }
//
message Any {
// A URL/resource name that uniquely identifies the type of the serialized
// protocol buffer message. This string must contain at least
// one "/" character. The last segment of the URL's path must represent
// the fully qualified name of the type (as in
// `path/google.protobuf.Duration`). The name should be in a canonical form
// (e.g., leading "." is not accepted).
//
// In practice, teams usually precompile into the binary all types that they
// expect it to use in the context of Any. However, for URLs which use the
// scheme `http`, `https`, or no scheme, one can optionally set up a type
// server that maps type URLs to message definitions as follows:
//
// * If no scheme is provided, `https` is assumed.
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
// URL, or have them precompiled into a binary to avoid any
// lookup. Therefore, binary compatibility needs to be preserved
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
// Note: this functionality is not currently available in the official
// protobuf release, and it is not used for type URLs beginning with
// type.googleapis.com. As of May 2023, there are no widely used type server
// implementations and no plans to implement one.
//
// Schemes other than `http`, `https` (or the empty scheme) might be
// used with implementation specific semantics.
//
string type_url = 1;
// Must be a valid serialized protocol buffer of the above specified type.
bytes value = 2;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
syntax = "proto3";
option go_package = "common/proto/ss/grpc_pb";
import "ss_common.proto";
import "google/api/annotations.proto";
service User {
rpc Login(LoginReq) returns (LoginResp) {
option (google.api.http) = {
post: "/user/login"
body: "*"
};
}
}
message LoginReq {
string Phone = 1 [json_name = "phone"]; // 手机号
string Code = 2 [json_name = "code"]; // 验证码
}
message LoginResp {
int32 UID = 1 [json_name = "uid"]; // 用户ID
}

View File

@@ -1,3 +1,8 @@
syntax = "proto3";
option go_package = "common/proto/ss/ss_common";
option go_package = "common/proto/ss/ss_common";
message ErrorInfo {
int32 code = 1;
string msg = 2;
}

View File

@@ -0,0 +1,16 @@
# gen.ps1 - 极简版
& .\gentool.exe `
-dsn "root:gR9pV4tY7zR6qL3e@tcp(47.108.184.184:3306)/user_db?charset=utf8mb4&parseTime=True&loc=Local" `
-fieldSignable `
-outPath "./user_db/query"
Get-ChildItem ./user_db/model/*.gen.go | ForEach-Object {
$c = Get-Content $_.FullName -Raw -Encoding UTF8
if ($c -match '\bSn\s+int64\b' -and $c -notmatch 'BeforeCreate') {
$c -match 'type\s+(\w+)\s+struct' | Out-Null
$n = $matches[1]
$c = $c -replace '(?s)(import\s*\([^)]*)', "`$1`t`"common/utils`"`n"
$hook = "`n`n// auto sn`nfunc (m *$n) BeforeCreate(_ *gorm.DB) error {`n`tif m.Sn == 0 {`n`t`tm.Sn = utils.SnowflakeInstance().Generate().Int64()`n`t}`n`treturn nil`n}"
Set-Content $_.FullName ($c.TrimEnd() + $hook) -Encoding UTF8
}
}

View File

@@ -1,5 +0,0 @@
@echo off
gentool ^
-dsn "root:gR9pV4tY7zR6qL3e@tcp(47.108.184.184:3306)/point?charset=utf8mb4&parseTime=True&loc=Local" ^
-fieldSignable

View File

@@ -1,4 +1,4 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
@@ -8,15 +8,17 @@ import (
"time"
"gorm.io/gorm"
"common/utils"
)
const TableNameUser = "users"
// User mapped from table <users>
type User struct {
ID int64 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
Sn string `gorm:"column:sn;not null;comment:业务唯一编号" json:"sn"` // 业务唯一编号
ID uint64 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
Sn int64 `gorm:"column:sn;not null;comment:业务唯一编号" json:"sn"` // 业务唯一编号
Name string `gorm:"column:name;not null" json:"name"`
Phone string `gorm:"column:phone;not null" json:"phone"`
CreatedAt time.Time `gorm:"column:created_at;not null" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;not null" json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at" json:"deleted_at"`
@@ -26,3 +28,11 @@ type User struct {
func (*User) TableName() string {
return TableNameUser
}
// auto sn
func (m *User) BeforeCreate(_ *gorm.DB) error {
if m.Sn == 0 {
m.Sn = utils.SnowflakeInstance().Generate().Int64()
}
return nil
}

View File

@@ -25,9 +25,10 @@ func newUser(db *gorm.DB, opts ...gen.DOOption) user {
tableName := _user.userDo.TableName()
_user.ALL = field.NewAsterisk(tableName)
_user.ID = field.NewInt64(tableName, "id")
_user.Sn = field.NewString(tableName, "sn")
_user.ID = field.NewUint64(tableName, "id")
_user.Sn = field.NewInt64(tableName, "sn")
_user.Name = field.NewString(tableName, "name")
_user.Phone = field.NewString(tableName, "phone")
_user.CreatedAt = field.NewTime(tableName, "created_at")
_user.UpdatedAt = field.NewTime(tableName, "updated_at")
_user.DeletedAt = field.NewField(tableName, "deleted_at")
@@ -41,9 +42,10 @@ type user struct {
userDo userDo
ALL field.Asterisk
ID field.Int64
Sn field.String // 业务唯一编号
ID field.Uint64
Sn field.Int64 // 业务唯一编号
Name field.String
Phone field.String
CreatedAt field.Time
UpdatedAt field.Time
DeletedAt field.Field
@@ -63,9 +65,10 @@ func (u user) As(alias string) *user {
func (u *user) updateTableName(table string) *user {
u.ALL = field.NewAsterisk(table)
u.ID = field.NewInt64(table, "id")
u.Sn = field.NewString(table, "sn")
u.ID = field.NewUint64(table, "id")
u.Sn = field.NewInt64(table, "sn")
u.Name = field.NewString(table, "name")
u.Phone = field.NewString(table, "phone")
u.CreatedAt = field.NewTime(table, "created_at")
u.UpdatedAt = field.NewTime(table, "updated_at")
u.DeletedAt = field.NewField(table, "deleted_at")
@@ -93,10 +96,11 @@ func (u *user) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
}
func (u *user) fillFieldMap() {
u.fieldMap = make(map[string]field.Expr, 6)
u.fieldMap = make(map[string]field.Expr, 7)
u.fieldMap["id"] = u.ID
u.fieldMap["sn"] = u.Sn
u.fieldMap["name"] = u.Name
u.fieldMap["phone"] = u.Phone
u.fieldMap["created_at"] = u.CreatedAt
u.fieldMap["updated_at"] = u.UpdatedAt
u.fieldMap["deleted_at"] = u.DeletedAt

View File

@@ -10,4 +10,7 @@ go mod tidy
cd ../scene
go mod tidy
cd ../user
go mod tidy
Pause

View File

@@ -2,9 +2,7 @@ package mysql
import (
"common/config"
pointQuery "common/db/mysql/point/query"
"common/log"
"database/sql"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
@@ -13,23 +11,14 @@ import (
type DBName string
const (
DBNamePoint DBName = "point"
)
var dbs = make(map[DBName]*sql.DB)
var queryS = make(map[DBName]interface{})
var dbs = make(map[DBName]*gorm.DB)
func Init(cfg map[string]*config.MySQLConfig) error {
for name, oneConfig := range cfg {
switch DBName(name) {
case DBNamePoint:
if db, err := initOneDB(oneConfig); err != nil {
return err
} else {
dbs[DBNamePoint], _ = db.DB()
queryS[DBNamePoint] = pointQuery.Use(db)
}
if db, err := initOneDB(oneConfig); err != nil {
return err
} else {
dbs[DBName(name)] = db
}
}
return nil
@@ -73,15 +62,12 @@ func parseLogLevel(logLevel string) logger.LogLevel {
return logger.Info
}
func GetPointDB() *pointQuery.Query {
return getQuery[*pointQuery.Query](DBNamePoint)
}
func getQuery[T any](dbName DBName) (result T) {
if q, ok := queryS[dbName]; ok {
result, _ = q.(T)
func GetDB(dbName DBName) *gorm.DB {
if q, ok := dbs[dbName]; ok {
return q
}
return
log.Errorf("db %s not found", dbName)
return nil
}
func Close() error {
@@ -89,8 +75,10 @@ func Close() error {
return nil
}
for name, db := range dbs {
if err := db.Close(); err != nil {
log.Errorf("close db %s error: %v", name, err)
if sqlDB, _ := db.DB(); sqlDB != nil {
if err := sqlDB.Close(); err != nil {
log.Errorf("close db %s error: %v", name, err)
}
}
}
return nil

View File

@@ -16,9 +16,15 @@ var (
)
var (
KeyDiscoverGateway = KeyDiscoverService + "/gateway" // 网关服
KeyDiscoverDatabase = KeyDiscoverService + "/database" // 数据
KeyDiscoverScene = KeyDiscoverService + "/scene" // 场景服
KeyDiscoverServiceNameGateway = "gateway" // 网关服
KeyDiscoverServiceNameScene = "scene" // 场景
KeyDiscoverServiceNameUser = "user" // 用户中心
)
var (
KeyDiscoverGateway = KeyDiscoverService + "/" + KeyDiscoverServiceNameGateway // 网关服
KeyDiscoverScene = KeyDiscoverService + "/" + KeyDiscoverServiceNameScene // 场景服
KeyDiscoverUser = KeyDiscoverService + "/" + KeyDiscoverServiceNameUser // 用户中心
)
// ServiceProvider 服务提供者

View File

@@ -5,6 +5,7 @@ go 1.23.1
require (
github.com/bwmarrin/snowflake v0.3.0
github.com/gobwas/ws v1.4.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/panjf2000/gnet/v2 v2.9.1
github.com/redis/go-redis/v9 v9.10.0
@@ -12,6 +13,7 @@ require (
go.etcd.io/etcd/api/v3 v3.6.1
go.etcd.io/etcd/client/v3 v3.6.1
go.uber.org/zap v1.27.0
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb
google.golang.org/grpc v1.71.1
google.golang.org/protobuf v1.36.5
gorm.io/driver/mysql v1.6.0
@@ -35,7 +37,6 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/panjf2000/ants/v2 v2.11.3 // indirect
@@ -56,7 +57,6 @@ require (
golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/tools v0.35.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect

View File

@@ -3,6 +3,7 @@ package grpc_conn
import (
"common/log"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/keepalive"
"time"
)
@@ -18,7 +19,7 @@ func NewGrpcConnection(sid int64, address string) (*GrpcConnection, error) {
}
conn, err := grpc.NewClient(
address,
grpc.WithInsecure(),
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithKeepaliveParams(
keepalive.ClientParameters{
Time: 30 * time.Second, // 保活探测包发送的时间间隔

View File

@@ -1,45 +0,0 @@
package grpc_conn
import (
"context"
"fmt"
"google.golang.org/grpc/stats"
)
// 1. 实现 stats.Handler 接口
type StatsHandler struct{}
func (h *StatsHandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context {
// 给 RPC 调用打标签(例如记录方法名)
return context.WithValue(ctx, "rpc_method", info.FullMethodName)
}
func (h *StatsHandler) HandleRPC(ctx context.Context, s stats.RPCStats) {
// 处理 RPC 统计信息
switch t := s.(type) {
case *stats.Begin:
fmt.Printf("RPC started: %s\n", ctx.Value("rpc_method"))
case *stats.End:
fmt.Printf("RPC finished: %s (duration: %v)\n",
ctx.Value("rpc_method"), t.EndTime.Sub(t.BeginTime))
case *stats.InPayload:
fmt.Printf("Received %d bytes\n", t.WireLength)
case *stats.OutPayload:
fmt.Printf("Sent %d bytes\n", t.WireLength)
}
}
func (h *StatsHandler) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context {
// 给连接打标签
return ctx
}
func (h *StatsHandler) HandleConn(ctx context.Context, s stats.ConnStats) {
// 处理连接事件
switch s.(type) {
case *stats.ConnBegin:
fmt.Println("Connection established")
case *stats.ConnEnd:
fmt.Println("Connection closed")
}
}

View File

@@ -0,0 +1,30 @@
package resolver
import (
"common/log"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/keepalive"
"time"
)
func NewGrpcConnection(target string) (*grpc.ClientConn, error) {
cc, err := grpc.NewClient(
target,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultServiceConfig(`{"loadBalancingConfig": [{"round_robin": {}}]}`),
grpc.WithKeepaliveParams(
keepalive.ClientParameters{
Time: 30 * time.Second, // 保活探测包发送的时间间隔
Timeout: 10 * time.Second, // 保活探测包的超时时间
PermitWithoutStream: true,
},
),
//grpc.WithStatsHandler(&StatsHandler{}),
)
if err != nil {
log.Errorf("create grpc err: %v, target: %v", err, target)
return nil, err
}
return cc, nil
}

View File

@@ -0,0 +1,84 @@
package resolver
import (
"common/db/etcd"
"common/discover/common"
"common/log"
"context"
"go.etcd.io/etcd/client/v3"
"google.golang.org/grpc/resolver"
"strings"
)
const etcdSchema = "etcd"
func init() {
resolver.Register(&etcdBuilder{})
}
type etcdBuilder struct{}
func (*etcdBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
serviceName := strings.TrimPrefix(target.URL.Path, "/")
r := &etcdResolver{
serviceName: serviceName,
cc: cc,
}
r.start()
return r, nil
}
func (*etcdBuilder) Scheme() string { return etcdSchema }
type etcdResolver struct {
serviceName string
cc resolver.ClientConn
ctx context.Context
cancel context.CancelFunc
}
func (r *etcdResolver) start() {
r.ctx, r.cancel = context.WithCancel(context.Background())
r.update()
go r.watch()
}
func (r *etcdResolver) getPrefix() string {
return common.KeyDiscoverService + "/" + r.serviceName
}
func (r *etcdResolver) update() {
resp, err := etcd.GetClient().Get(r.getPrefix(), clientv3.WithPrefix())
if err != nil {
log.Errorf("etcd resolver get error: %v", err)
return
}
var addrArray []resolver.Address
for _, kv := range resp.Kvs {
addr := string(kv.Value)
if addr != "" {
addrArray = append(addrArray, resolver.Address{Addr: addr})
}
}
_ = r.cc.UpdateState(resolver.State{Addresses: addrArray})
}
func (r *etcdResolver) watch() {
watchCh := etcd.GetClient().Watch(r.getPrefix(), clientv3.WithPrefix())
for w := range watchCh {
if w.Err() != nil {
continue
}
r.update()
}
}
func (r *etcdResolver) ResolveNow(resolver.ResolveNowOptions) {
r.update()
}
func (r *etcdResolver) Close() {
r.cancel()
}

View File

@@ -0,0 +1,35 @@
package resolver
import (
"google.golang.org/grpc"
"sync"
)
var (
mu = sync.RWMutex{}
conn = make(map[string]*grpc.ClientConn)
)
func GetGrpcClientConn(target string) (*grpc.ClientConn, error) {
mu.RLock()
if c, ok := conn[target]; ok && c != nil {
mu.RUnlock()
return c, nil
}
mu.RUnlock()
mu.Lock()
defer mu.Unlock()
if c, ok := conn[target]; ok && c != nil {
return c, nil
}
newConn, err := NewGrpcConnection(target)
if err != nil {
return nil, err
}
conn[target] = newConn
return newConn, nil
}

View File

@@ -3,6 +3,7 @@ package service
import (
"common/discover"
"common/discover/common"
"common/net/grpc/resolver"
"common/proto/ss/grpc_pb"
)
@@ -14,6 +15,14 @@ func SceneNewClient(sid ...int64) (grpc_pb.SceneClient, error) {
return grpc_pb.NewSceneClient(c), nil
}
func SceneNewClientLB() (grpc_pb.SceneClient, error) {
c, err := resolver.GetGrpcClientConn("etcd:///" + common.KeyDiscoverServiceNameScene)
if err != nil {
return nil, err
}
return grpc_pb.NewSceneClient(c), nil
}
func SceneNewBroadcastClient() map[int64]grpc_pb.SceneClient {
clientM := make(map[int64]grpc_pb.SceneClient)
connM := discover.FindServerAll(common.KeyDiscoverScene)

View File

@@ -0,0 +1,24 @@
package service
import (
"common/discover"
"common/discover/common"
"common/net/grpc/resolver"
"common/proto/ss/grpc_pb"
)
func UserNewClient(sid ...int64) (grpc_pb.UserClient, error) {
c, err := discover.FindServer(common.KeyDiscoverUser, sid...)
if err != nil {
return nil, err
}
return grpc_pb.NewUserClient(c), nil
}
func UserNewClientLB() (grpc_pb.UserClient, error) {
c, err := resolver.GetGrpcClientConn("etcd:///" + common.KeyDiscoverServiceNameUser)
if err != nil {
return nil, err
}
return grpc_pb.NewUserClient(c), nil
}

View File

@@ -7,7 +7,9 @@ import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/status"
"net"
"sync"
"time"
@@ -51,6 +53,7 @@ func (s *Base) Init(addr string, port int32) {
defer func() {
if r := recover(); r != nil {
log.Errorf("server Panic: %v", r)
err = status.Error(codes.Internal, fmt.Sprintf("%v", r))
}
}()
resp, err = handler(ctx, req)

View File

@@ -0,0 +1,46 @@
package http_resp
import (
"common/proto/ss/ss_common"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var (
OK = NewCode(0, "OK")
Failed = NewCode(1, "Failed")
ParamError = NewCode(1001, "参数错误")
NameEmpty = NewCode(1002, "名称不能为空")
NameDuplicate = NewCode(1003, "名称或编号不能重复")
ListEmpty = NewCode(1004, "列表不能为空")
RepeatCommit = NewCode(1005, "请勿重复提交")
)
type Code struct {
code int
error string
}
func NewCode(code int, error string) *Code {
return &Code{
code: code,
error: error,
}
}
func (c *Code) Code() int {
return c.code
}
func (c *Code) Error() string {
return c.error
}
func (c *Code) Wrap() error {
st := status.New(codes.Unknown, c.Error())
st, _ = st.WithDetails(&ss_common.ErrorInfo{
Code: int32(c.Code()),
Msg: c.Error(),
})
return st.Err()
}

View File

@@ -0,0 +1,22 @@
package http_resp
type RespJsonData struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data,omitempty"`
}
func Success(data interface{}) *RespJsonData {
return &RespJsonData{
Code: OK.Code(),
Msg: OK.Error(),
Data: data,
}
}
func Error(code int, message string) *RespJsonData {
return &RespJsonData{
Code: code,
Msg: message,
}
}

View File

@@ -0,0 +1,224 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.32.0
// protoc v4.25.1
// source: service_user.proto
package grpc_pb
import (
_ "common/proto/ss/ss_common"
_ "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"
)
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 LoginReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Phone string `protobuf:"bytes,1,opt,name=Phone,json=phone,proto3" json:"Phone,omitempty"` // 手机号
Code string `protobuf:"bytes,2,opt,name=Code,json=code,proto3" json:"Code,omitempty"` // 验证码
}
func (x *LoginReq) Reset() {
*x = LoginReq{}
if protoimpl.UnsafeEnabled {
mi := &file_service_user_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *LoginReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LoginReq) ProtoMessage() {}
func (x *LoginReq) ProtoReflect() protoreflect.Message {
mi := &file_service_user_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LoginReq.ProtoReflect.Descriptor instead.
func (*LoginReq) Descriptor() ([]byte, []int) {
return file_service_user_proto_rawDescGZIP(), []int{0}
}
func (x *LoginReq) GetPhone() string {
if x != nil {
return x.Phone
}
return ""
}
func (x *LoginReq) GetCode() string {
if x != nil {
return x.Code
}
return ""
}
type LoginResp struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
UID int32 `protobuf:"varint,1,opt,name=UID,json=uid,proto3" json:"UID,omitempty"` // 用户ID
}
func (x *LoginResp) Reset() {
*x = LoginResp{}
if protoimpl.UnsafeEnabled {
mi := &file_service_user_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *LoginResp) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LoginResp) ProtoMessage() {}
func (x *LoginResp) ProtoReflect() protoreflect.Message {
mi := &file_service_user_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LoginResp.ProtoReflect.Descriptor instead.
func (*LoginResp) Descriptor() ([]byte, []int) {
return file_service_user_proto_rawDescGZIP(), []int{1}
}
func (x *LoginResp) GetUID() int32 {
if x != nil {
return x.UID
}
return 0
}
var File_service_user_proto protoreflect.FileDescriptor
var file_service_user_proto_rawDesc = []byte{
0x0a, 0x12, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0f, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70,
0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0x34, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12,
0x14, 0x0a, 0x05, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
0x70, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x1d, 0x0a, 0x09, 0x4c, 0x6f, 0x67,
0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, 0x44, 0x18, 0x01, 0x20,
0x01, 0x28, 0x05, 0x52, 0x03, 0x75, 0x69, 0x64, 0x32, 0x3e, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72,
0x12, 0x36, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x09, 0x2e, 0x4c, 0x6f, 0x67, 0x69,
0x6e, 0x52, 0x65, 0x71, 0x1a, 0x0a, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70,
0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, 0x22, 0x0b, 0x2f, 0x75, 0x73,
0x65, 0x72, 0x2f, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x42, 0x19, 0x5a, 0x17, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x73, 0x2f, 0x67, 0x72, 0x70, 0x63,
0x5f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_service_user_proto_rawDescOnce sync.Once
file_service_user_proto_rawDescData = file_service_user_proto_rawDesc
)
func file_service_user_proto_rawDescGZIP() []byte {
file_service_user_proto_rawDescOnce.Do(func() {
file_service_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_service_user_proto_rawDescData)
})
return file_service_user_proto_rawDescData
}
var file_service_user_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_service_user_proto_goTypes = []interface{}{
(*LoginReq)(nil), // 0: LoginReq
(*LoginResp)(nil), // 1: LoginResp
}
var file_service_user_proto_depIdxs = []int32{
0, // 0: User.Login:input_type -> LoginReq
1, // 1: User.Login:output_type -> LoginResp
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_service_user_proto_init() }
func file_service_user_proto_init() {
if File_service_user_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_service_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_service_user_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginResp); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_service_user_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_service_user_proto_goTypes,
DependencyIndexes: file_service_user_proto_depIdxs,
MessageInfos: file_service_user_proto_msgTypes,
}.Build()
File_service_user_proto = out.File
file_service_user_proto_rawDesc = nil
file_service_user_proto_goTypes = nil
file_service_user_proto_depIdxs = nil
}

View File

@@ -0,0 +1,154 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: service_user.proto
/*
Package grpc_pb is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package grpc_pb
import (
"context"
"errors"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
var (
_ codes.Code
_ io.Reader
_ status.Status
_ = errors.New
_ = runtime.String
_ = utilities.NewDoubleArray
_ = metadata.Join
)
func request_User_Login_0(ctx context.Context, marshaler runtime.Marshaler, client UserClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq LoginReq
metadata runtime.ServerMetadata
)
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.Login(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_User_Login_0(ctx context.Context, marshaler runtime.Marshaler, server UserServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq LoginReq
metadata runtime.ServerMetadata
)
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.Login(ctx, &protoReq)
return msg, metadata, err
}
// RegisterUserHandlerServer registers the http handlers for service User to "mux".
// UnaryRPC :call UserServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterUserHandlerFromEndpoint instead.
// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call.
func RegisterUserHandlerServer(ctx context.Context, mux *runtime.ServeMux, server UserServer) error {
mux.Handle(http.MethodPost, pattern_User_Login_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/.User/Login", runtime.WithHTTPPathPattern("/user/login"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_User_Login_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_User_Login_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterUserHandlerFromEndpoint is same as RegisterUserHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterUserHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.NewClient(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterUserHandler(ctx, mux, conn)
}
// RegisterUserHandler registers the http handlers for service User to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterUserHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterUserHandlerClient(ctx, mux, NewUserClient(conn))
}
// RegisterUserHandlerClient registers the http handlers for service User
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "UserClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "UserClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "UserClient" to call the correct interceptors. This client ignores the HTTP middlewares.
func RegisterUserHandlerClient(ctx context.Context, mux *runtime.ServeMux, client UserClient) error {
mux.Handle(http.MethodPost, pattern_User_Login_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/.User/Login", runtime.WithHTTPPathPattern("/user/login"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_User_Login_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_User_Login_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_User_Login_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"user", "login"}, ""))
)
var (
forward_User_Login_0 = runtime.ForwardResponseMessage
)

View File

@@ -0,0 +1,105 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v4.25.1
// source: service_user.proto
package grpc_pb
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.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// 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 {
Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*LoginResp, error)
}
type userClient struct {
cc grpc.ClientConnInterface
}
func NewUserClient(cc grpc.ClientConnInterface) UserClient {
return &userClient{cc}
}
func (c *userClient) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*LoginResp, error) {
out := new(LoginResp)
err := c.cc.Invoke(ctx, "/User/Login", in, out, opts...)
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 {
Login(context.Context, *LoginReq) (*LoginResp, error)
mustEmbedUnimplementedUserServer()
}
// UnimplementedUserServer must be embedded to have forward compatible implementations.
type UnimplementedUserServer struct {
}
func (UnimplementedUserServer) Login(context.Context, *LoginReq) (*LoginResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method Login not implemented")
}
func (UnimplementedUserServer) mustEmbedUnimplementedUserServer() {}
// 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) {
s.RegisterService(&User_ServiceDesc, srv)
}
func _User_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(LoginReq)
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",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserServer).Login(ctx, req.(*LoginReq))
}
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",
HandlerType: (*UserServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Login",
Handler: _User_Login_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "service_user.proto",
}

View File

@@ -10,6 +10,7 @@ import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
@@ -19,16 +20,89 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ErrorInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"`
}
func (x *ErrorInfo) Reset() {
*x = ErrorInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_ss_common_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ErrorInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ErrorInfo) ProtoMessage() {}
func (x *ErrorInfo) ProtoReflect() protoreflect.Message {
mi := &file_ss_common_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ErrorInfo.ProtoReflect.Descriptor instead.
func (*ErrorInfo) Descriptor() ([]byte, []int) {
return file_ss_common_proto_rawDescGZIP(), []int{0}
}
func (x *ErrorInfo) GetCode() int32 {
if x != nil {
return x.Code
}
return 0
}
func (x *ErrorInfo) GetMsg() string {
if x != nil {
return x.Msg
}
return ""
}
var File_ss_common_proto protoreflect.FileDescriptor
var file_ss_common_proto_rawDesc = []byte{
0x0a, 0x0f, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x42, 0x1b, 0x5a, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2f, 0x73, 0x73, 0x2f, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6f, 0x22, 0x31, 0x0a, 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12,
0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f,
0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x6d, 0x73, 0x67, 0x42, 0x1b, 0x5a, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x73, 0x2f, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var file_ss_common_proto_goTypes = []interface{}{}
var (
file_ss_common_proto_rawDescOnce sync.Once
file_ss_common_proto_rawDescData = file_ss_common_proto_rawDesc
)
func file_ss_common_proto_rawDescGZIP() []byte {
file_ss_common_proto_rawDescOnce.Do(func() {
file_ss_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_ss_common_proto_rawDescData)
})
return file_ss_common_proto_rawDescData
}
var file_ss_common_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_ss_common_proto_goTypes = []interface{}{
(*ErrorInfo)(nil), // 0: ErrorInfo
}
var file_ss_common_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
@@ -42,18 +116,33 @@ func file_ss_common_proto_init() {
if File_ss_common_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_ss_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ErrorInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_ss_common_proto_rawDesc,
NumEnums: 0,
NumMessages: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_ss_common_proto_goTypes,
DependencyIndexes: file_ss_common_proto_depIdxs,
MessageInfos: file_ss_common_proto_msgTypes,
}.Build()
File_ss_common_proto = out.File
file_ss_common_proto_rawDesc = nil

View File

@@ -22,7 +22,7 @@ func (p *Program) Init(_ svc.Environment) error {
p.moduleList = append(p.moduleList, &ModuleBase{})
p.moduleList = append(p.moduleList, &ModuleDB{})
p.moduleList = append(p.moduleList, &ModulePrometheus{})
p.moduleList = append(p.moduleList, &ModuleWebServer{})
p.moduleList = append(p.moduleList, &ModuleGrpcGateway{})
p.moduleList = append(p.moduleList, &ModuleWebsocketServer{})
p.moduleList = append(p.moduleList, &ModuleGrpcServer{})

View File

@@ -3,7 +3,7 @@ package app
import (
"common/net/grpc/service"
"gateway/config"
"gateway/grpc_server/server"
"gateway/internal/grpc_server/server"
)
// ModuleGrpcServer Grpc服务模块

View File

@@ -0,0 +1,63 @@
package app
import (
"common/log"
"common/net/grpc/service"
"common/proto/ss/grpc_pb"
"context"
"errors"
"fmt"
"gateway/config"
"gateway/internal/net/http_gateway"
"net/http"
"sync"
)
// ModuleGrpcGateway GrpcGateway服务模块
type ModuleGrpcGateway struct {
wg *sync.WaitGroup
// 微服务列表
services []service.IService
server *http.Server
}
func (m *ModuleGrpcGateway) init() error {
m.wg = &sync.WaitGroup{}
return nil
}
func (m *ModuleGrpcGateway) start() error {
m.wg.Add(1)
go func() {
defer m.wg.Done()
conn, err := service.UserNewClientLB()
if err != nil {
log.Errorf("get user conn failed: %v", err)
return
}
gwMux := http_gateway.InitServeMux()
if err = grpc_pb.RegisterUserHandlerClient(context.Background(), gwMux, conn); err != nil {
log.Errorf("RegisterUserHandlerClient err: %v", err)
return
}
m.server = &http.Server{
Addr: fmt.Sprintf("%v:%v", config.Get().Serve.Http.Address, config.Get().Serve.Http.Port),
Handler: http_gateway.InitRouter(gwMux),
}
if err := m.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Errorf("http server failed: %v", err.Error())
}
log.Infof("http server stop.")
}()
return nil
}
func (m *ModuleGrpcGateway) stop() error {
if err := m.server.Shutdown(context.Background()); err != nil {
log.Errorf("stop http server failed: %v", err)
}
m.wg.Wait()
return nil
}

View File

@@ -1,50 +0,0 @@
package app
import (
"common/log"
"context"
"errors"
"fmt"
"gateway/config"
"gateway/net/http_gateway"
"github.com/gin-gonic/gin"
"net/http"
"sync"
)
// ModuleWebServer Web服务模块
type ModuleWebServer struct {
wg *sync.WaitGroup
server *http.Server
router *gin.Engine
}
func (m *ModuleWebServer) init() error {
m.wg = &sync.WaitGroup{}
m.router = http_gateway.InitRouter()
return nil
}
func (m *ModuleWebServer) start() error {
m.wg.Add(1)
go func() {
defer m.wg.Done()
m.server = &http.Server{
Addr: fmt.Sprintf("%v:%v", config.Get().Serve.Http.Address, config.Get().Serve.Http.Port),
Handler: m.router,
}
if err := m.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Errorf("http server failed: %v", err.Error())
}
log.Infof("http server stop.")
}()
return nil
}
func (m *ModuleWebServer) stop() error {
if err := m.server.Shutdown(context.Background()); err != nil {
log.Errorf("stop http server failed: %v", err)
}
m.wg.Wait()
return nil
}

View File

@@ -5,7 +5,7 @@ import (
"common/net/socket/websocket"
"fmt"
"gateway/config"
"gateway/net/ws_gateway"
"gateway/internal/net/ws_gateway"
"sync"
"time"
)

View File

@@ -16,14 +16,6 @@ monitor:
db:
etcd:
endpoints: [ "10.0.40.9:2379" ]
mysql:
user:
dsn: "root:gR9pV4tY7zR6qL3e@tcp(47.108.184.184:3306)/point?charset=utf8mb4&parseTime=True&loc=Local"
max_open_conn: 50
max_idle_conn: 20
conn_max_lifetime_sec: 600
conn_max_idle_time_sec: 180
log_level: "warn"
serve:
grpc:

View File

@@ -16,14 +16,6 @@ monitor:
db:
etcd:
endpoints: [ "172.18.28.0:2379" ]
mysql:
user:
dsn: "root:gR9pV4tY7zR6qL3e@tcp(47.108.184.184:3306)/point?charset=utf8mb4&parseTime=True&loc=Local"
max_open_conn: 50
max_idle_conn: 20
conn_max_lifetime_sec: 600
conn_max_idle_time_sec: 180
log_level: "warn"
serve:
grpc:

View File

@@ -6,6 +6,7 @@ require (
common v0.0.0-00010101000000-000000000000
github.com/gin-contrib/cors v1.7.6
github.com/gin-gonic/gin v1.10.1
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3
github.com/judwhite/go-svc v1.2.1
github.com/prometheus/client_golang v1.20.5
go.uber.org/zap v1.27.0
@@ -38,7 +39,6 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect

View File

@@ -1,18 +0,0 @@
package helper
type Pagination struct {
Page int `json:"page"` // 页
Size int `json:"size"` // 页大小
}
//func SetBaseQuery(page *Pagination, order string) func(db *gorm.DB) *gorm.DB {
// return func(db *gorm.DB) *gorm.DB {
// if page != nil {
// db = db.Offset((page.Page - 1) * page.Size).Limit(page.Size)
// }
// if len(order) > 0 {
// db = db.Order(order)
// }
// return db
// }
//}

View File

@@ -1,31 +0,0 @@
package render
var (
OK = NewCode(0, "成功")
Failed = NewCode(1, "失败")
ParamError = NewCode(1001, "参数错误")
NameEmpty = NewCode(1002, "名称不能为空")
NameDuplicate = NewCode(1003, "名称或编号不能重复")
ListEmpty = NewCode(1004, "列表不能为空")
RepeatCommit = NewCode(1005, "请勿重复提交")
)
type Code struct {
code int
message string
}
func NewCode(code int, message string) *Code {
return &Code{
code: code,
message: message,
}
}
func (c *Code) Code() int {
return c.code
}
func (c *Code) Message() string {
return c.message
}

View File

@@ -1,39 +0,0 @@
package render
import (
"github.com/gin-gonic/gin"
"net/http"
)
type RespJsonData struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}
func Json(c *gin.Context, code *Code, data interface{}) {
result := &RespJsonData{
Code: code.Code(),
Msg: code.Message(),
Data: data,
}
c.JSON(http.StatusOK, result)
}
func JsonByStatus(c *gin.Context, status int, code *Code, data interface{}) {
result := &RespJsonData{
Code: code.Code(),
Msg: code.Message(),
Data: data,
}
c.JSON(status, result)
}
func AbortJson(c *gin.Context, code *Code, data interface{}) {
result := &RespJsonData{
Code: code.Code(),
Msg: code.Message(),
Data: data,
}
c.AbortWithStatusJSON(http.StatusOK, result)
}

View File

@@ -1,16 +0,0 @@
package http_handler
import (
"common/utils"
"gateway/handler/http_handler/helper/render"
"github.com/gin-gonic/gin"
)
type UniqueIDResp struct {
ID string `json:"id"`
}
// GenSnowflake 生成雪花ID
func GenSnowflake(c *gin.Context) {
render.Json(c, render.OK, &UniqueIDResp{ID: utils.SnowflakeInstance().Generate().String()})
}

View File

@@ -4,7 +4,7 @@ import (
"common/log"
"common/proto/sc/sc_pb"
"common/proto/ss/grpc_pb"
"gateway/handler/ws_handler"
"gateway/internal/handler/ws_handler"
"google.golang.org/protobuf/proto"
"sync"
)

View File

@@ -4,7 +4,7 @@ import (
"common/discover/common"
"common/net/grpc/service"
"common/proto/ss/grpc_pb"
"gateway/handler/ws_handler"
"gateway/internal/handler/ws_handler"
"google.golang.org/grpc"
)

View File

@@ -4,7 +4,7 @@ import (
"common/net/grpc/service"
"common/proto/sc/sc_pb"
"common/proto/ss/grpc_pb"
"gateway/grpc_server/stream_client"
"gateway/internal/grpc_server/stream_client"
"google.golang.org/protobuf/proto"
"time"
)
@@ -42,7 +42,7 @@ func (c *Client) handle(event Event) {
}
func (c *Client) onEnter(msg *sc_pb.C2S_EnterInstance) {
client, err := service.SceneNewClient()
client, err := service.SceneNewClientLB()
if err != nil {
c.logger.Errorf("SceneNewClient err: %v", err)
return

View File

@@ -0,0 +1,54 @@
package http_gateway
import (
"common/log"
"common/net/http/http_resp"
wrapper2 "gateway/internal/net/http_gateway/wrapper"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/protobuf/encoding/protojson"
"net/http"
)
func InitServeMux() *runtime.ServeMux {
baseMarshaler := &runtime.JSONPb{
MarshalOptions: protojson.MarshalOptions{
UseProtoNames: false,
EmitUnpopulated: true,
},
UnmarshalOptions: protojson.UnmarshalOptions{
DiscardUnknown: true,
},
}
unifiedMarshaler := wrapper2.NewWrappedMarshaler(baseMarshaler)
mux := runtime.NewServeMux(
runtime.WithMarshalerOption(runtime.MIMEWildcard, unifiedMarshaler),
runtime.WithErrorHandler(wrapper2.ErrorHandler),
)
return mux
}
func InitRouter(mux *runtime.ServeMux) *gin.Engine {
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.Use(
gin.Recovery(),
ginLogger(log.GetLogger().Named("GIN")),
cors.New(corsConfig()),
)
r.HandleMethodNotAllowed = true
r.NoMethod(func(c *gin.Context) {
c.JSON(http.StatusMethodNotAllowed, http_resp.Error(http_resp.Failed.Code(), "Method Not Allowed"))
})
r.NoRoute(func(c *gin.Context) {
c.JSON(http.StatusNotFound, http_resp.Error(http_resp.Failed.Code(), "Endpoint Not Found"))
})
r.Any("/*any", gin.WrapH(mux))
return r
}

View File

@@ -0,0 +1,53 @@
package wrapper
import (
"common/net/http/http_resp"
"common/proto/ss/ss_common"
"context"
"encoding/json"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"net/http"
)
// ErrorHandler 将 gRPC 错误转为统一 JSON 格式
func ErrorHandler(_ context.Context, _ *runtime.ServeMux, _ runtime.Marshaler, w http.ResponseWriter, _ *http.Request, err error) {
st, ok := status.FromError(err)
if !ok {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
_ = json.NewEncoder(w).Encode(http_resp.Error(http_resp.Failed.Code(), http_resp.Failed.Error()))
return
}
code, msg := 0, ""
for _, detail := range st.Details() {
if errorInfo, ok := detail.(*ss_common.ErrorInfo); ok {
code = int(errorInfo.Code)
msg = errorInfo.Msg
break
}
}
if code == 0 {
code = http_resp.Failed.Code()
msg = http_resp.Failed.Error()
}
if st.Code() == codes.Unknown {
msg = st.Message()
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(grpcCodeToHTTPCode(st.Code()))
_ = json.NewEncoder(w).Encode(http_resp.Error(code, msg))
}
// 这里定义 Internal 属于业务错误,其他的属于 500 报错
func grpcCodeToHTTPCode(c codes.Code) int {
switch c {
case codes.OK, codes.Unknown:
return http.StatusOK
default:
return http.StatusInternalServerError
}
}

View File

@@ -0,0 +1,42 @@
package wrapper
import (
"common/net/http/http_resp"
"encoding/json"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"io"
)
// WrappedMarshaler 自动包装响应为 { code, message, data }
type WrappedMarshaler struct {
inner runtime.Marshaler
}
func NewWrappedMarshaler(inner runtime.Marshaler) *WrappedMarshaler {
return &WrappedMarshaler{inner: inner}
}
// Marshal 将 gRPC 响应包装成统一格式
func (w *WrappedMarshaler) Marshal(v interface{}) ([]byte, error) {
dataBytes, err := w.inner.Marshal(v)
if err != nil {
return json.Marshal(http_resp.Error(http_resp.Failed.Code(), http_resp.Failed.Error()))
}
return json.Marshal(http_resp.Success(json.RawMessage(dataBytes)))
}
func (w *WrappedMarshaler) Unmarshal(data []byte, v interface{}) error {
return w.inner.Unmarshal(data, v)
}
func (w *WrappedMarshaler) NewDecoder(r io.Reader) runtime.Decoder {
return w.inner.NewDecoder(r)
}
func (w *WrappedMarshaler) NewEncoder(wr io.Writer) runtime.Encoder {
return w.inner.NewEncoder(wr)
}
func (w *WrappedMarshaler) ContentType(v interface{}) string {
return "application/json"
}

View File

@@ -4,7 +4,7 @@ import (
"common/log"
"common/net/socket"
"fmt"
"gateway/handler/ws_handler"
ws_handler2 "gateway/internal/handler/ws_handler"
"go.uber.org/zap"
"strconv"
"time"
@@ -30,29 +30,29 @@ func (g *GatewayWsServer) OnHandShake(conn socket.ISocketConn) {
if err != nil {
_ = conn.Close()
}
if oldClient := ws_handler.UserMgr.GetByUID(int32(t)); oldClient != nil {
if oldClient := ws_handler2.UserMgr.GetByUID(int32(t)); oldClient != nil {
oldClient.CloseClient()
}
client := ws_handler.NewClient(int32(t), conn)
ws_handler.UserMgr.Add(int32(t), client)
client := ws_handler2.NewClient(int32(t), conn)
ws_handler2.UserMgr.Add(int32(t), client)
conn.SetParam("client", client)
}
func (g *GatewayWsServer) OnMessage(conn socket.ISocketConn, bytes []byte) socket.Action {
client, ok := conn.GetParam("client").(*ws_handler.Client)
client, ok := conn.GetParam("client").(*ws_handler2.Client)
if !ok || client.UID == 0 {
return socket.Close
}
client.OnEvent(&ws_handler.ClientEvent{Msg: bytes})
client.OnEvent(&ws_handler2.ClientEvent{Msg: bytes})
return socket.None
}
func (g *GatewayWsServer) OnPong(conn socket.ISocketConn) {
client, ok := conn.GetParam("client").(*ws_handler.Client)
client, ok := conn.GetParam("client").(*ws_handler2.Client)
if !ok || client.UID == 0 {
return
}
client.OnEvent(&ws_handler.PongEvent{})
client.OnEvent(&ws_handler2.PongEvent{})
}
func (g *GatewayWsServer) OnClose(_ socket.ISocketConn, _ error) socket.Action {

View File

@@ -1,37 +0,0 @@
package http_gateway
import (
"common/log"
"gateway/handler/http_handler"
"gateway/handler/http_handler/helper/render"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"net/http"
)
func InitRouter() *gin.Engine {
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.Use(
gin.Recovery(),
ginLogger(log.GetLogger().Named("GIN")),
cors.New(corsConfig()),
)
r.HandleMethodNotAllowed = true
r.NoMethod(func(c *gin.Context) {
render.JsonByStatus(c, http.StatusMethodNotAllowed, render.Failed, "Method Not Allowed")
})
r.NoRoute(func(c *gin.Context) {
render.JsonByStatus(c, http.StatusNotFound, render.Failed, "Endpoint Not Found")
})
initBaseRouter(r)
return r
}
func initBaseRouter(router *gin.Engine) {
g := router.Group("/b")
g.POST("/snowflake", http_handler.GenSnowflake) // 生成雪花
}

View File

@@ -3,7 +3,7 @@ package app
import (
"fmt"
"robot/config"
"robot/ws"
"robot/internal/ws"
)
// ModuleWebsocket Websocket客户端模块

View File

@@ -3,7 +3,7 @@ package app
import (
"common/net/grpc/service"
"scene/config"
"scene/grpc_server/server"
"scene/internal/grpc_server/server"
)
// ModuleGrpcServer Grpc服务模块

View File

@@ -6,17 +6,17 @@ import (
"common/proto/ss/grpc_pb"
"context"
"google.golang.org/protobuf/proto"
"scene/instance"
instance2 "scene/internal/instance"
"sync"
)
func (s *Server) Enter(ctx context.Context, req *grpc_pb.EnterReq) (*grpc_pb.EnterResp, error) {
var i *instance.Instance
if len(instance.Mgr.GetAll()) == 0 {
i = instance.NewScene(s.SID, req.InstanceID)
var i *instance2.Instance
if len(instance2.Mgr.GetAll()) == 0 {
i = instance2.NewScene(s.SID, req.InstanceID)
i.Start(s.EtcdTTL)
} else {
for _, v := range instance.Mgr.GetAll() {
for _, v := range instance2.Mgr.GetAll() {
i = v
break
}
@@ -39,7 +39,7 @@ func (s *Server) Enter(ctx context.Context, req *grpc_pb.EnterReq) (*grpc_pb.Ent
}
func (s *Server) Leave(ctx context.Context, req *grpc_pb.LeaveReq) (*grpc_pb.LeaveResp, error) {
if i := instance.Mgr.GetByUniqueNo(req.UniqueNo); i != nil {
if i := instance2.Mgr.GetByUniqueNo(req.UniqueNo); i != nil {
i.EventIn <- req
}
return &grpc_pb.LeaveResp{}, nil
@@ -59,7 +59,7 @@ func (s *Server) Action(server grpc_pb.Scene_ActionServer) error {
if args, err := server.Recv(); err != nil {
return
} else {
if ins := instance.Mgr.GetByUniqueNo(args.UniqueNo); ins != nil {
if ins := instance2.Mgr.GetByUniqueNo(args.UniqueNo); ins != nil {
select {
case ins.EventIn <- args:
default:

View File

@@ -11,8 +11,8 @@ import (
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
"runtime/debug"
"scene/grpc_server/stream_client"
"scene/npc"
"scene/internal/grpc_server/stream_client"
"scene/internal/npc"
"sync"
"time"
)

11
Server/user/Dockerfile Normal file
View File

@@ -0,0 +1,11 @@
FROM alpine:latest
RUN apk add --no-cache tzdata && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
COPY user/ /app/
RUN chmod 777 /app/server-user
WORKDIR /app
CMD ["./server-user"]

58
Server/user/app/app.go Normal file
View File

@@ -0,0 +1,58 @@
package app
import (
"common/discover"
"common/log"
"fmt"
"github.com/judwhite/go-svc"
"user/config"
)
type Program struct {
moduleList []Module // 模块列表
}
type Module interface {
init() error
start() error
stop() error
}
func (p *Program) Init(_ svc.Environment) error {
p.moduleList = append(p.moduleList, &ModuleBase{})
p.moduleList = append(p.moduleList, &ModuleDB{})
p.moduleList = append(p.moduleList, &ModuleGrpcServer{})
for _, module := range p.moduleList {
if err := module.init(); err != nil {
return err
}
}
log.Infof(fmt.Sprintf("%v Init successful...", config.Get().App.Name))
return nil
}
func (p *Program) Start() error {
for _, module := range p.moduleList {
if err := module.start(); err != nil {
return err
}
}
discover.Listen()
log.Infof(fmt.Sprintf("%v Start successful...", config.Get().App.Name))
return nil
}
func (p *Program) Stop() error {
discover.Close()
for i := len(p.moduleList) - 1; i >= 0; i-- {
module := p.moduleList[i]
if err := module.stop(); err != nil {
log.Errorf("module stop error: %v", err)
}
}
log.Infof(fmt.Sprintf("%v Stop successful...", config.Get().App.Name))
return nil
}

33
Server/user/app/base.go Normal file
View File

@@ -0,0 +1,33 @@
package app
import (
"common/log"
"common/utils"
"math/rand"
"user/config"
)
// ModuleBase 基础模块,或者一些零散的模块
type ModuleBase struct {
}
func (p *ModuleBase) init() error {
// 配置
if err := config.LoadConfig(); err != nil {
return err
}
cfg := config.Get()
// 日志
log.Init(cfg.Log.Debug, cfg.Log.MaxSize, cfg.Log.MaxBackups, cfg.Log.MaxAge, cfg.Log.Level)
// 雪花
utils.InitSnowflake(int64(rand.Intn(1000)))
return nil
}
func (p *ModuleBase) start() error {
return nil
}
func (p *ModuleBase) stop() error {
return nil
}

23
Server/user/app/db.go Normal file
View File

@@ -0,0 +1,23 @@
package app
import (
"common/db"
"user/config"
)
// ModuleDB 数据库模块
type ModuleDB struct {
dbModule *db.ModuleDB
}
func (p *ModuleDB) init() error {
return p.dbModule.Init(config.Get().DB)
}
func (p *ModuleDB) start() error {
return nil
}
func (p *ModuleDB) stop() error {
return p.dbModule.Stop()
}

27
Server/user/app/grpc.go Normal file
View File

@@ -0,0 +1,27 @@
package app
import (
"common/net/grpc/service"
"user/config"
"user/internal/grpc_server/server"
)
// ModuleGrpcServer Grpc服务模块
type ModuleGrpcServer struct {
server service.IService
}
func (m *ModuleGrpcServer) init() error {
return nil
}
func (m *ModuleGrpcServer) start() error {
m.server = server.NewServer(config.Get().Serve.Grpc.TTL)
m.server.Init(config.Get().Serve.Grpc.Address, config.Get().Serve.Grpc.Port)
return nil
}
func (m *ModuleGrpcServer) stop() error {
m.server.Close()
return nil
}

View File

@@ -0,0 +1,27 @@
app:
name: "user-dev"
log:
debug: true
level: "debug"
maxSize: 10
maxBackups: 100
maxAge: 7
db:
etcd:
endpoints: [ "10.0.40.9:2379" ]
mysql:
user_db:
dsn: "root:gR9pV4tY7zR6qL3e@tcp(47.108.184.184:3306)/user_db?charset=utf8mb4&parseTime=True&loc=Local"
max_open_conn: 50
max_idle_conn: 20
conn_max_lifetime_sec: 600
conn_max_idle_time_sec: 180
log_level: "warn"
serve:
grpc:
address: "127.0.0.1"
port: 8602
ttl: 20

View File

@@ -0,0 +1,25 @@
package config
import "common/config"
const path = "./config"
type Config struct {
App *config.AppConfig `yaml:"app"`
Log *config.LogConfig `yaml:"log"`
DB *config.DBConfig `yaml:"db"`
Serve *config.ServeConfig `yaml:"serve"`
}
var cfg *Config
// LoadConfig 加载应用配置
func LoadConfig() error {
c, err := config.LoadConfig(path, cfg)
cfg = c
return err
}
func Get() *Config {
return cfg
}

View File

@@ -0,0 +1,27 @@
app:
name: "user-prod"
log:
debug: false
level: "debug"
maxSize: 10
maxBackups: 100
maxAge: 7
db:
etcd:
endpoints: [ "172.18.28.0:2379" ]
mysql:
user_db:
dsn: "root:gR9pV4tY7zR6qL3e@tcp(47.108.184.184:3306)/user_db?charset=utf8mb4&parseTime=True&loc=Local"
max_open_conn: 50
max_idle_conn: 20
conn_max_lifetime_sec: 600
conn_max_idle_time_sec: 180
log_level: "warn"
serve:
grpc:
address: "172.18.28.0"
port: 8602
ttl: 20

57
Server/user/go.mod Normal file
View File

@@ -0,0 +1,57 @@
module user
go 1.23.1
require (
common v0.0.0-00010101000000-000000000000
github.com/judwhite/go-svc v1.2.1
google.golang.org/grpc v1.71.1
google.golang.org/protobuf v1.36.6
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/bwmarrin/snowflake v0.3.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/natefinch/lumberjack v2.0.0+incompatible // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/spf13/viper v1.21.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.etcd.io/etcd/api/v3 v3.6.1 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.1 // indirect
go.etcd.io/etcd/client/v3 v3.6.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/mod v0.26.0 // indirect
golang.org/x/net v0.42.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/tools v0.35.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
gorm.io/datatypes v1.2.4 // indirect
gorm.io/driver/mysql v1.6.0 // indirect
gorm.io/gen v0.3.27 // indirect
gorm.io/gorm v1.31.1 // indirect
gorm.io/hints v1.1.0 // indirect
gorm.io/plugin/dbresolver v1.6.2 // indirect
)
replace common => ../common

199
Server/user/go.sum Normal file
View File

@@ -0,0 +1,199 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
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/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/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
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-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
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-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
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.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/judwhite/go-svc v1.2.1 h1:a7fsJzYUa33sfDJRF2N/WXhA+LonCEEY8BJb1tuS5tA=
github.com/judwhite/go-svc v1.2.1/go.mod h1:mo/P2JNX8C07ywpP9YtO2gnBgnUiFTHqtsZekJrUuTk=
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/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
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/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
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/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/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/etcd/api/v3 v3.6.1 h1:yJ9WlDih9HT457QPuHt/TH/XtsdN2tubyxyQHSHPsEo=
go.etcd.io/etcd/api/v3 v3.6.1/go.mod h1:lnfuqoGsXMlZdTJlact3IB56o3bWp1DIlXPIGKRArto=
go.etcd.io/etcd/client/pkg/v3 v3.6.1 h1:CxDVv8ggphmamrXM4Of8aCC8QHzDM4tGcVr9p2BSoGk=
go.etcd.io/etcd/client/pkg/v3 v3.6.1/go.mod h1:aTkCp+6ixcVTZmrJGa7/Mc5nMNs59PEgBbq+HCmWyMc=
go.etcd.io/etcd/client/v3 v3.6.1 h1:KelkcizJGsskUXlsxjVrSmINvMMga0VWwFF0tSPGEP0=
go.etcd.io/etcd/client/v3 v3.6.1/go.mod h1:fCbPUdjWNLfx1A6ATo9syUmFVxqHH9bCnPLBZmnLmMY=
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/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.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.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
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.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
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.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
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.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
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.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
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.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
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.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
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-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
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/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
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=
gorm.io/datatypes v1.2.4 h1:uZmGAcK/QZ0uyfCuVg0VQY1ZmV9h1fuG0tMwKByO1z4=
gorm.io/datatypes v1.2.4/go.mod h1:f4BsLcFAX67szSv8svwLRjklArSHAvHLeE3pXAS5DZI=
gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U=
gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A=
gorm.io/driver/sqlite v1.1.6/go.mod h1:W8LmC/6UvVbHKah0+QOC7Ja66EaZXHwUTjgXY8YNWX8=
gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0=
gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig=
gorm.io/gen v0.3.27 h1:ziocAFLpE7e0g4Rum69pGfB9S6DweTxK8gAun7cU8as=
gorm.io/gen v0.3.27/go.mod h1:9zquz2xD1f3Eb/eHq4oLn2z6vDVvQlCY5S3uMBLv4EA=
gorm.io/gorm v1.21.15/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.22.2/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
gorm.io/hints v1.1.0 h1:Lp4z3rxREufSdxn4qmkK3TLDltrM10FLTHiuqwDPvXw=
gorm.io/hints v1.1.0/go.mod h1:lKQ0JjySsPBj3uslFzY3JhYDtqEwzm+G1hv8rWujB6Y=
gorm.io/plugin/dbresolver v1.6.2 h1:F4b85TenghUeITqe3+epPSUtHH7RIk3fXr5l83DF8Pc=
gorm.io/plugin/dbresolver v1.6.2/go.mod h1:tctw63jdrOezFR9HmrKnPkmig3m5Edem9fdxk9bQSzM=

View File

@@ -5,18 +5,19 @@
package model
import (
"time"
"common/utils"
"gorm.io/gorm"
"time"
)
const TableNameUser = "users"
// User mapped from table <users>
type User struct {
ID int64 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
Sn string `gorm:"column:sn;not null;comment:业务唯一编号" json:"sn"` // 业务唯一编号
ID uint64 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
Sn int64 `gorm:"column:sn;not null;comment:业务唯一编号" json:"sn"` // 业务唯一编号
Name string `gorm:"column:name;not null" json:"name"`
Phone string `gorm:"column:phone;not null" json:"phone"`
CreatedAt time.Time `gorm:"column:created_at;not null" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;not null" json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at" json:"deleted_at"`
@@ -26,3 +27,11 @@ type User struct {
func (*User) TableName() string {
return TableNameUser
}
// auto sn
func (m *User) BeforeCreate(_ *gorm.DB) error {
if m.Sn == 0 {
m.Sn = utils.SnowflakeInstance().Generate().Int64()
}
return nil
}

View File

@@ -5,8 +5,8 @@
package query
import (
"common/db/mysql/point/model"
"context"
"user/internal/dao/model"
"gorm.io/gorm"
"gorm.io/gorm/clause"
@@ -26,9 +26,10 @@ func newUser(db *gorm.DB, opts ...gen.DOOption) user {
tableName := _user.userDo.TableName()
_user.ALL = field.NewAsterisk(tableName)
_user.ID = field.NewInt64(tableName, "id")
_user.Sn = field.NewString(tableName, "sn")
_user.ID = field.NewUint64(tableName, "id")
_user.Sn = field.NewInt64(tableName, "sn")
_user.Name = field.NewString(tableName, "name")
_user.Phone = field.NewString(tableName, "phone")
_user.CreatedAt = field.NewTime(tableName, "created_at")
_user.UpdatedAt = field.NewTime(tableName, "updated_at")
_user.DeletedAt = field.NewField(tableName, "deleted_at")
@@ -42,9 +43,10 @@ type user struct {
userDo userDo
ALL field.Asterisk
ID field.Int64
Sn field.String // 业务唯一编号
ID field.Uint64
Sn field.Int64 // 业务唯一编号
Name field.String
Phone field.String
CreatedAt field.Time
UpdatedAt field.Time
DeletedAt field.Field
@@ -64,9 +66,10 @@ func (u user) As(alias string) *user {
func (u *user) updateTableName(table string) *user {
u.ALL = field.NewAsterisk(table)
u.ID = field.NewInt64(table, "id")
u.Sn = field.NewString(table, "sn")
u.ID = field.NewUint64(table, "id")
u.Sn = field.NewInt64(table, "sn")
u.Name = field.NewString(table, "name")
u.Phone = field.NewString(table, "phone")
u.CreatedAt = field.NewTime(table, "created_at")
u.UpdatedAt = field.NewTime(table, "updated_at")
u.DeletedAt = field.NewField(table, "deleted_at")
@@ -94,10 +97,11 @@ func (u *user) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
}
func (u *user) fillFieldMap() {
u.fieldMap = make(map[string]field.Expr, 6)
u.fieldMap = make(map[string]field.Expr, 7)
u.fieldMap["id"] = u.ID
u.fieldMap["sn"] = u.Sn
u.fieldMap["name"] = u.Name
u.fieldMap["phone"] = u.Phone
u.fieldMap["created_at"] = u.CreatedAt
u.fieldMap["updated_at"] = u.UpdatedAt
u.fieldMap["deleted_at"] = u.DeletedAt

View File

@@ -0,0 +1,40 @@
package repository
import (
"common/db/mysql"
"context"
"user/internal/dao/model"
"user/internal/dao/query"
)
type UserDao struct {
ctx context.Context
query *query.Query
}
func NewUserDao(ctx context.Context) *UserDao {
return &UserDao{
ctx: ctx,
query: query.Use(mysql.GetDB("user_db")),
}
}
func (d *UserDao) FindBySn(sn int64) (*model.User, error) {
first, err := d.query.User.WithContext(d.ctx).
Where(d.query.User.Sn.Eq(sn)).
First()
if err != nil {
return nil, err
}
return first, nil
}
func (d *UserDao) FindByPhone(phone string) (*model.User, error) {
first, err := d.query.User.WithContext(d.ctx).
Where(d.query.User.Phone.Eq(phone)).
First()
if err != nil {
return nil, err
}
return first, nil
}

View File

@@ -0,0 +1,21 @@
package server
import (
"common/log"
"common/proto/ss/grpc_pb"
"context"
"user/internal/dao/repository"
)
func (s *Server) Login(ctx context.Context, req *grpc_pb.LoginReq) (*grpc_pb.LoginResp, error) {
log.Infof("Login req: %+v", req)
user, err := repository.NewUserDao(ctx).FindBySn(857527344353)
if err != nil {
return nil, err
}
return &grpc_pb.LoginResp{
UID: int32(user.Sn),
}, nil
}

View File

@@ -0,0 +1,32 @@
package server
import (
"common/discover/common"
"common/net/grpc/service"
"common/proto/ss/grpc_pb"
"google.golang.org/grpc"
)
type Server struct {
grpc_pb.UnimplementedUserServer
service.Base
}
func NewServer(ttl int64) *Server {
s := &Server{
Base: service.Base{
Target: common.KeyDiscoverUser,
EtcdTTL: ttl,
},
}
s.Base.OnInit = s.OnInit
s.Base.OnClose = s.OnClose
return s
}
func (s *Server) OnInit(serve *grpc.Server) {
grpc_pb.RegisterUserServer(serve, s)
}
func (s *Server) OnClose() {
}

View File

@@ -0,0 +1,65 @@
package stream_client
import (
"common/log"
"common/net/grpc/service"
"context"
"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
)
var gatewayServerM map[int64]map[GatewayFun]grpc.ClientStream // map[sid]map[方法名]流连接
type GatewayFun int
const (
FunToClient GatewayFun = iota
)
func init() {
gatewayServerM = make(map[int64]map[GatewayFun]grpc.ClientStream)
}
func FindGatewayBySID(sid int64, fun GatewayFun) (grpc.ClientStream, error) {
g := gatewayServerM[sid]
if g == nil {
g = make(map[GatewayFun]grpc.ClientStream)
gatewayServerM[sid] = g
}
gatewayLink := g[fun]
if gatewayLink == nil {
gatewayClient, err := service.GatewayNewClient(sid)
if err != nil {
log.Errorf("cannot find gatewayClient: %v", err)
return nil, err
}
var link grpc.ClientStream
switch fun {
case FunToClient:
link, err = gatewayClient.ToClient(context.Background())
}
if err != nil {
log.Errorf("FindGatewayBySID %v err: %v, sid: %v", fun, err, sid)
return nil, err
}
g[fun] = link
gatewayLink = link
}
return gatewayLink, nil
}
func SendMessageToGateway(sid int64, fun GatewayFun, msg proto.Message, re ...bool) error {
stream, err := FindGatewayBySID(sid, fun)
if err != nil {
return err
}
if err = stream.SendMsg(msg); err != nil {
if re == nil || !re[0] {
_ = stream.CloseSend()
delete(gatewayServerM[sid], fun)
return SendMessageToGateway(sid, fun, msg, true)
}
return err
}
return nil
}

14
Server/user/main.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import (
"fmt"
"github.com/judwhite/go-svc"
"syscall"
"user/app"
)
func main() {
if err := svc.Run(&app.Program{}, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL); err != nil {
fmt.Println(err)
}
}

176
Server/指导方针.md Normal file
View File

@@ -0,0 +1,176 @@
太棒了!你已经抓住了微服务的核心痛点(数据库隔离、分层架构、服务边界),接下来我们系统性地梳理 **构建真正可靠、可维护、可演进的微服务架构必须遵守的关键原则**
---
## ✅ 微服务十大核心原则(实战导向)
> 这些不是理论教条,而是无数团队踩坑后总结出的“生存法则”。
---
### 1. **单一职责 & 高内聚Single Responsibility**
- 每个微服务应围绕 **一个明确的业务能力**(如“用户管理”、“支付”、“通知”)。
- ❌ 不要按技术分层拆服务(如“所有 DB 服务”、“所有 API 服务”)。
- ✅ 建议用 **DDD领域驱动设计** 划分限界上下文Bounded Context
> 📌 口诀:**“一个服务,一个事”**
---
### 2. **自治性Autonomy**
- 服务应能 **独立开发、测试、部署、扩展、故障恢复**
- 依赖越少越好;跨服务调用必须有 **降级、熔断、超时** 机制。
- 使用 **契约测试Contract Testing** 保证接口兼容(如 Pact
> 🔧 工具推荐:
> - gRPC + Protobuf强契约
> - OpenAPIREST
> - WireMock / Pact契约测试
---
### 3. **数据私有Database per Service** ← 你已掌握!
- 每个服务独占数据存储,**禁止跨服务直连数据库**。
- 跨服务数据交互靠:
- **同步**APIgRPC/HTTP
- **异步**事件Kafka / RabbitMQ / Pulsar
> 💡 技巧:用 **事件溯源Event Sourcing + CQRS** 构建复杂查询视图。
---
### 4. **无状态Stateless**
- 服务实例本身不保存会话或状态(状态存 Redis / DB / Cookie
- 好处:**水平扩展容易**K8s 可随意扩缩容。
> ⚠️ 例外:批处理、流计算等有状态场景可用 StatefulSet但要谨慎。
---
### 5. **可观测性Observability三件套**
微服务没有可观测性 = 盲人开车!
| 组件 | 作用 | 工具推荐 |
|------|------|--------|
| **Logging** | 记录结构化日志 | Zap / Logrus + Loki / ELK |
| **Metrics** | 监控性能指标 | Prometheus + Grafana |
| Assistant | 追踪请求链路 | Jaeger / Zipkin / OpenTelemetry |
> ✅ 必做:
> - 所有日志带 `trace_id`
> - 所有 gRPC 调用自动埋点
> - 关键路径加自定义指标(如“登录成功率”)
---
### 6. **弹性设计Resilience**
网络不可靠!必须假设:
- 其他服务会宕机
- 网络会延迟或丢包
✅ 必备机制:
- **超时Timeout**:每个调用设上限(如 1s
- **重试Retry**:带退避策略(指数退避)
- **熔断Circuit Breaker**:失败太多就短路(如 Hystrix / Sentinel
- **限流Rate Limiting**:保护自己不被压垮
- **降级Fallback**:返回默认值或缓存数据
> 🛠 Go 推荐库:
> - `go-resiliency`
> - `sony/gobreaker`
> - 自研中间件(结合 context + retry
---
### 7. **API 优先API-First Design**
- 先定义 `.proto`gRPC或 OpenAPIREST再写代码。
- 客户端 SDK 自动生成(如 `protoc-gen-go`)。
- 版本管理:**向后兼容优先**,避免频繁改接口。
> 📁 目录建议:
> ```
> api/
> ├── user/v1/user.proto
> └── order/v1/order.proto
> ```
---
### 8. **基础设施即代码IaC & GitOps**
- 数据库、K8s、网关配置全部代码化Terraform / Helm / Kustomize
- 所有变更通过 Git PR 触发自动化部署。
- 环境一致性dev / staging / prod 配置几乎相同。
> ✅ 好处:**“一键重建整个环境”**
---
### 9. **安全内建Security by Default**
- **mTLS**服务间通信加密Istio / Linkerd
- **RBAC**:基于角色的访问控制
- **敏感信息**:用 Vault / K8s Secret 管理,不硬编码
- **输入校验**:所有 API 参数严格验证(如 `validator.v10`
> 🔒 原则:**“零信任网络”** —— 不信任任何内部流量。
---
### 10. **演进式设计Evolutionary Architecture**
- 不追求“一次性完美架构”
-**Strangler Fig Pattern绞杀者模式** 逐步替换旧系统
- 定期做 **架构重构****技术债清理**
> 🌱 微服务是“种出来的”,不是“画出来的”。
---
## 🧱 推荐架构分层Go 微服务)
```
user-service/
├── api/ # .proto 文件(对外契约)
├── cmd/ # main 入口
├── internal/
│ ├── handler/ # gRPC/HTTP handlers薄层
│ ├── service/ # 业务逻辑(核心)
│ ├── repository/ # 数据访问(接口 + mysql 实现)
│ └── model/ # 领域模型(与 DB 解耦)
├── pkg/ # 可共享工具(谨慎!)
├── deploy/ # K8s / Docker 配置
└── go.mod
```
> 🔑 关键:`internal/` 禁止被外部 import强制通过 API 交互。
---
## 🚫 微服务常见反模式(务必避开!)
| 反模式 | 后果 |
|-------|------|
| 分布式单体 | 失去微服务所有优势 |
| 共享数据库 | 强耦合,无法独立演进 |
| 同步调用链过长A→B→C→D | 故障放大,雪崩风险 |
| 无监控无告警 | 出问题找不到原因 |
| 手动部署 | 发布慢,易出错 |
---
## ✅ 最后建议:从小做起,逐步完善
1. **先保证“能跑”**:一个服务 + 独立 DB + gRPC API
2. **加上可观测性**:日志 + Metrics + Tracing
3. **加上弹性机制**:超时 + 重试
4. **加上 CI/CD**:自动化测试 & 部署
5. **再考虑事件驱动、CQRS、Service Mesh...**
> 🌟 **好的微服务架构不是设计出来的,而是在约束和实践中演化出来的。**
---
如果你愿意,我可以:
- 帮你画一张 **典型微服务架构图**
- 提供一个 **Go 微服务模板项目结构**
- 推荐 **K8s + Istio + Prometheus 的最小可行部署方案**
祝你打造出**真正可靠、优雅、可演进**的微服务系统!🚀