diff --git a/api/proto/gateway.pb.go b/api/proto/gateway.pb.go deleted file mode 100644 index 9269487..0000000 --- a/api/proto/gateway.pb.go +++ /dev/null @@ -1,645 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.34.2 -// protoc v5.29.2 -// source: gateway.proto - -package gatewaypb - -import ( - 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 LoginRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - LoginType string `protobuf:"bytes,1,opt,name=login_type,json=loginType,proto3" json:"login_type,omitempty"` - Account string `protobuf:"bytes,2,opt,name=account,proto3" json:"account,omitempty"` - Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"` - CountryCode string `protobuf:"bytes,4,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"` - VerifyCode string `protobuf:"bytes,5,opt,name=verify_code,json=verifyCode,proto3" json:"verify_code,omitempty"` - Provider string `protobuf:"bytes,6,opt,name=provider,proto3" json:"provider,omitempty"` - ProviderToken string `protobuf:"bytes,7,opt,name=provider_token,json=providerToken,proto3" json:"provider_token,omitempty"` - DeviceId string `protobuf:"bytes,8,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` - Platform string `protobuf:"bytes,9,opt,name=platform,proto3" json:"platform,omitempty"` - AppVersion string `protobuf:"bytes,10,opt,name=app_version,json=appVersion,proto3" json:"app_version,omitempty"` -} - -func (x *LoginRequest) Reset() { - *x = LoginRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_gateway_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *LoginRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*LoginRequest) ProtoMessage() {} - -func (x *LoginRequest) ProtoReflect() protoreflect.Message { - mi := &file_gateway_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 LoginRequest.ProtoReflect.Descriptor instead. -func (*LoginRequest) Descriptor() ([]byte, []int) { - return file_gateway_proto_rawDescGZIP(), []int{0} -} - -func (x *LoginRequest) GetLoginType() string { - if x != nil { - return x.LoginType - } - return "" -} - -func (x *LoginRequest) GetAccount() string { - if x != nil { - return x.Account - } - return "" -} - -func (x *LoginRequest) GetPassword() string { - if x != nil { - return x.Password - } - return "" -} - -func (x *LoginRequest) GetCountryCode() string { - if x != nil { - return x.CountryCode - } - return "" -} - -func (x *LoginRequest) GetVerifyCode() string { - if x != nil { - return x.VerifyCode - } - return "" -} - -func (x *LoginRequest) GetProvider() string { - if x != nil { - return x.Provider - } - return "" -} - -func (x *LoginRequest) GetProviderToken() string { - if x != nil { - return x.ProviderToken - } - return "" -} - -func (x *LoginRequest) GetDeviceId() string { - if x != nil { - return x.DeviceId - } - return "" -} - -func (x *LoginRequest) GetPlatform() string { - if x != nil { - return x.Platform - } - return "" -} - -func (x *LoginRequest) GetAppVersion() string { - if x != nil { - return x.AppVersion - } - return "" -} - -type UserProfile struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` - AvatarUrl string `protobuf:"bytes,3,opt,name=avatar_url,json=avatarUrl,proto3" json:"avatar_url,omitempty"` -} - -func (x *UserProfile) Reset() { - *x = UserProfile{} - if protoimpl.UnsafeEnabled { - mi := &file_gateway_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UserProfile) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UserProfile) ProtoMessage() {} - -func (x *UserProfile) ProtoReflect() protoreflect.Message { - mi := &file_gateway_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 UserProfile.ProtoReflect.Descriptor instead. -func (*UserProfile) Descriptor() ([]byte, []int) { - return file_gateway_proto_rawDescGZIP(), []int{1} -} - -func (x *UserProfile) GetUserId() string { - if x != nil { - return x.UserId - } - return "" -} - -func (x *UserProfile) GetNickname() string { - if x != nil { - return x.Nickname - } - return "" -} - -func (x *UserProfile) GetAvatarUrl() string { - if x != nil { - return x.AvatarUrl - } - return "" -} - -type LoginResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - AccessToken string `protobuf:"bytes,2,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"` - RefreshToken string `protobuf:"bytes,3,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"` - ExpiresIn int64 `protobuf:"varint,4,opt,name=expires_in,json=expiresIn,proto3" json:"expires_in,omitempty"` - IsNewUser bool `protobuf:"varint,5,opt,name=is_new_user,json=isNewUser,proto3" json:"is_new_user,omitempty"` - Profile *UserProfile `protobuf:"bytes,6,opt,name=profile,proto3" json:"profile,omitempty"` -} - -func (x *LoginResponse) Reset() { - *x = LoginResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_gateway_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *LoginResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*LoginResponse) ProtoMessage() {} - -func (x *LoginResponse) ProtoReflect() protoreflect.Message { - mi := &file_gateway_proto_msgTypes[2] - 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 LoginResponse.ProtoReflect.Descriptor instead. -func (*LoginResponse) Descriptor() ([]byte, []int) { - return file_gateway_proto_rawDescGZIP(), []int{2} -} - -func (x *LoginResponse) GetUserId() string { - if x != nil { - return x.UserId - } - return "" -} - -func (x *LoginResponse) GetAccessToken() string { - if x != nil { - return x.AccessToken - } - return "" -} - -func (x *LoginResponse) GetRefreshToken() string { - if x != nil { - return x.RefreshToken - } - return "" -} - -func (x *LoginResponse) GetExpiresIn() int64 { - if x != nil { - return x.ExpiresIn - } - return 0 -} - -func (x *LoginResponse) GetIsNewUser() bool { - if x != nil { - return x.IsNewUser - } - return false -} - -func (x *LoginResponse) GetProfile() *UserProfile { - if x != nil { - return x.Profile - } - return nil -} - -type QueryOrderRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - OrderNo string `protobuf:"bytes,1,opt,name=order_no,json=orderNo,proto3" json:"order_no,omitempty"` -} - -func (x *QueryOrderRequest) Reset() { - *x = QueryOrderRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_gateway_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *QueryOrderRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*QueryOrderRequest) ProtoMessage() {} - -func (x *QueryOrderRequest) ProtoReflect() protoreflect.Message { - mi := &file_gateway_proto_msgTypes[3] - 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 QueryOrderRequest.ProtoReflect.Descriptor instead. -func (*QueryOrderRequest) Descriptor() ([]byte, []int) { - return file_gateway_proto_rawDescGZIP(), []int{3} -} - -func (x *QueryOrderRequest) GetOrderNo() string { - if x != nil { - return x.OrderNo - } - return "" -} - -type QueryOrderResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - OrderNo string `protobuf:"bytes,1,opt,name=order_no,json=orderNo,proto3" json:"order_no,omitempty"` - UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` - Amount string `protobuf:"bytes,4,opt,name=amount,proto3" json:"amount,omitempty"` - Currency string `protobuf:"bytes,5,opt,name=currency,proto3" json:"currency,omitempty"` - Subject string `protobuf:"bytes,6,opt,name=subject,proto3" json:"subject,omitempty"` - PayMethod string `protobuf:"bytes,7,opt,name=pay_method,json=payMethod,proto3" json:"pay_method,omitempty"` - PaidAt string `protobuf:"bytes,8,opt,name=paid_at,json=paidAt,proto3" json:"paid_at,omitempty"` -} - -func (x *QueryOrderResponse) Reset() { - *x = QueryOrderResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_gateway_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *QueryOrderResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*QueryOrderResponse) ProtoMessage() {} - -func (x *QueryOrderResponse) ProtoReflect() protoreflect.Message { - mi := &file_gateway_proto_msgTypes[4] - 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 QueryOrderResponse.ProtoReflect.Descriptor instead. -func (*QueryOrderResponse) Descriptor() ([]byte, []int) { - return file_gateway_proto_rawDescGZIP(), []int{4} -} - -func (x *QueryOrderResponse) GetOrderNo() string { - if x != nil { - return x.OrderNo - } - return "" -} - -func (x *QueryOrderResponse) GetUserId() string { - if x != nil { - return x.UserId - } - return "" -} - -func (x *QueryOrderResponse) GetStatus() string { - if x != nil { - return x.Status - } - return "" -} - -func (x *QueryOrderResponse) GetAmount() string { - if x != nil { - return x.Amount - } - return "" -} - -func (x *QueryOrderResponse) GetCurrency() string { - if x != nil { - return x.Currency - } - return "" -} - -func (x *QueryOrderResponse) GetSubject() string { - if x != nil { - return x.Subject - } - return "" -} - -func (x *QueryOrderResponse) GetPayMethod() string { - if x != nil { - return x.PayMethod - } - return "" -} - -func (x *QueryOrderResponse) GetPaidAt() string { - if x != nil { - return x.PaidAt - } - return "" -} - -var File_gateway_proto protoreflect.FileDescriptor - -var file_gateway_proto_rawDesc = []byte{ - 0x0a, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x19, 0x63, 0x68, 0x61, 0x74, 0x61, 0x70, 0x70, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x76, 0x31, 0x22, 0xc4, 0x02, 0x0a, 0x0c, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, - 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, - 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, - 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x63, 0x6f, - 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, - 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x22, 0x61, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, - 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, - 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x5f, - 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x76, 0x61, 0x74, 0x61, - 0x72, 0x55, 0x72, 0x6c, 0x22, 0xf1, 0x01, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, - 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, - 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, - 0x65, 0x73, 0x5f, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x65, 0x73, 0x49, 0x6e, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x6e, 0x65, 0x77, - 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x4e, - 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x12, 0x40, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x61, 0x70, - 0x70, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, - 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x2e, 0x0a, 0x11, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, - 0x08, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x6e, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x4e, 0x6f, 0x22, 0xe6, 0x01, 0x0a, 0x12, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x19, 0x0a, 0x08, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x6e, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x4e, 0x6f, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, - 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x79, - 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, - 0x61, 0x79, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x61, 0x69, 0x64, - 0x5f, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x69, 0x64, 0x41, - 0x74, 0x32, 0x69, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x74, 0x41, 0x70, 0x70, 0x55, 0x73, 0x65, 0x72, - 0x12, 0x5a, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x27, 0x2e, 0x63, 0x68, 0x61, 0x74, - 0x61, 0x70, 0x70, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x61, 0x70, 0x70, 0x67, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x77, 0x0a, 0x0a, - 0x43, 0x68, 0x61, 0x74, 0x41, 0x70, 0x70, 0x50, 0x61, 0x79, 0x12, 0x69, 0x0a, 0x0a, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x2c, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x61, - 0x70, 0x70, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x61, 0x70, 0x70, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, - 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x24, 0x5a, 0x22, 0x63, 0x68, 0x61, 0x74, 0x61, 0x70, 0x70, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x3b, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, -} - -var ( - file_gateway_proto_rawDescOnce sync.Once - file_gateway_proto_rawDescData = file_gateway_proto_rawDesc -) - -func file_gateway_proto_rawDescGZIP() []byte { - file_gateway_proto_rawDescOnce.Do(func() { - file_gateway_proto_rawDescData = protoimpl.X.CompressGZIP(file_gateway_proto_rawDescData) - }) - return file_gateway_proto_rawDescData -} - -var file_gateway_proto_msgTypes = make([]protoimpl.MessageInfo, 5) -var file_gateway_proto_goTypes = []any{ - (*LoginRequest)(nil), // 0: chatappgateway.gateway.v1.LoginRequest - (*UserProfile)(nil), // 1: chatappgateway.gateway.v1.UserProfile - (*LoginResponse)(nil), // 2: chatappgateway.gateway.v1.LoginResponse - (*QueryOrderRequest)(nil), // 3: chatappgateway.gateway.v1.QueryOrderRequest - (*QueryOrderResponse)(nil), // 4: chatappgateway.gateway.v1.QueryOrderResponse -} -var file_gateway_proto_depIdxs = []int32{ - 1, // 0: chatappgateway.gateway.v1.LoginResponse.profile:type_name -> chatappgateway.gateway.v1.UserProfile - 0, // 1: chatappgateway.gateway.v1.ChatAppUser.Login:input_type -> chatappgateway.gateway.v1.LoginRequest - 3, // 2: chatappgateway.gateway.v1.ChatAppPay.QueryOrder:input_type -> chatappgateway.gateway.v1.QueryOrderRequest - 2, // 3: chatappgateway.gateway.v1.ChatAppUser.Login:output_type -> chatappgateway.gateway.v1.LoginResponse - 4, // 4: chatappgateway.gateway.v1.ChatAppPay.QueryOrder:output_type -> chatappgateway.gateway.v1.QueryOrderResponse - 3, // [3:5] is the sub-list for method output_type - 1, // [1:3] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name -} - -func init() { file_gateway_proto_init() } -func file_gateway_proto_init() { - if File_gateway_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_gateway_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*LoginRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_gateway_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*UserProfile); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_gateway_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*LoginResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_gateway_proto_msgTypes[3].Exporter = func(v any, i int) any { - switch v := v.(*QueryOrderRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_gateway_proto_msgTypes[4].Exporter = func(v any, i int) any { - switch v := v.(*QueryOrderResponse); 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_gateway_proto_rawDesc, - NumEnums: 0, - NumMessages: 5, - NumExtensions: 0, - NumServices: 2, - }, - GoTypes: file_gateway_proto_goTypes, - DependencyIndexes: file_gateway_proto_depIdxs, - MessageInfos: file_gateway_proto_msgTypes, - }.Build() - File_gateway_proto = out.File - file_gateway_proto_rawDesc = nil - file_gateway_proto_goTypes = nil - file_gateway_proto_depIdxs = nil -} diff --git a/api/proto/gateway.proto b/api/proto/gateway.proto deleted file mode 100644 index b7c22c8..0000000 --- a/api/proto/gateway.proto +++ /dev/null @@ -1,56 +0,0 @@ -syntax = "proto3"; - -package chatappgateway.gateway.v1; - -option go_package = "chatappgateway/api/proto;gatewaypb"; - -service ChatAppUser { - rpc Login(LoginRequest) returns (LoginResponse); -} - -service ChatAppPay { - rpc QueryOrder(QueryOrderRequest) returns (QueryOrderResponse); -} - -message LoginRequest { - string login_type = 1; - string account = 2; - string password = 3; - string country_code = 4; - string verify_code = 5; - string provider = 6; - string provider_token = 7; - string device_id = 8; - string platform = 9; - string app_version = 10; -} - -message UserProfile { - string user_id = 1; - string nickname = 2; - string avatar_url = 3; -} - -message LoginResponse { - string user_id = 1; - string access_token = 2; - string refresh_token = 3; - int64 expires_in = 4; - bool is_new_user = 5; - UserProfile profile = 6; -} - -message QueryOrderRequest { - string order_no = 1; -} - -message QueryOrderResponse { - string order_no = 1; - string user_id = 2; - string status = 3; - string amount = 4; - string currency = 5; - string subject = 6; - string pay_method = 7; - string paid_at = 8; -} diff --git a/api/proto/gateway_grpc.pb.go b/api/proto/gateway_grpc.pb.go deleted file mode 100644 index 511b5cd..0000000 --- a/api/proto/gateway_grpc.pb.go +++ /dev/null @@ -1,223 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.5.1 -// - protoc v5.29.2 -// source: gateway.proto - -package gatewaypb - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.64.0 or later. -const _ = grpc.SupportPackageIsVersion9 - -const ( - ChatAppUser_Login_FullMethodName = "/chatappgateway.gateway.v1.ChatAppUser/Login" -) - -// ChatAppUserClient is the client API for ChatAppUser 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 ChatAppUserClient interface { - Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error) -} - -type chatAppUserClient struct { - cc grpc.ClientConnInterface -} - -func NewChatAppUserClient(cc grpc.ClientConnInterface) ChatAppUserClient { - return &chatAppUserClient{cc} -} - -func (c *chatAppUserClient) Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(LoginResponse) - err := c.cc.Invoke(ctx, ChatAppUser_Login_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -// ChatAppUserServer is the server API for ChatAppUser service. -// All implementations must embed UnimplementedChatAppUserServer -// for forward compatibility. -type ChatAppUserServer interface { - Login(context.Context, *LoginRequest) (*LoginResponse, error) - mustEmbedUnimplementedChatAppUserServer() -} - -// UnimplementedChatAppUserServer must be embedded to have -// forward compatible implementations. -// -// NOTE: this should be embedded by value instead of pointer to avoid a nil -// pointer dereference when methods are called. -type UnimplementedChatAppUserServer struct{} - -func (UnimplementedChatAppUserServer) Login(context.Context, *LoginRequest) (*LoginResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Login not implemented") -} -func (UnimplementedChatAppUserServer) mustEmbedUnimplementedChatAppUserServer() {} -func (UnimplementedChatAppUserServer) testEmbeddedByValue() {} - -// UnsafeChatAppUserServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to ChatAppUserServer will -// result in compilation errors. -type UnsafeChatAppUserServer interface { - mustEmbedUnimplementedChatAppUserServer() -} - -func RegisterChatAppUserServer(s grpc.ServiceRegistrar, srv ChatAppUserServer) { - // If the following call pancis, it indicates UnimplementedChatAppUserServer was - // embedded by pointer and is nil. This will cause panics if an - // unimplemented method is ever invoked, so we test this at initialization - // time to prevent it from happening at runtime later due to I/O. - if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { - t.testEmbeddedByValue() - } - s.RegisterService(&ChatAppUser_ServiceDesc, srv) -} - -func _ChatAppUser_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(LoginRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ChatAppUserServer).Login(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: ChatAppUser_Login_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ChatAppUserServer).Login(ctx, req.(*LoginRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// ChatAppUser_ServiceDesc is the grpc.ServiceDesc for ChatAppUser service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var ChatAppUser_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "chatappgateway.gateway.v1.ChatAppUser", - HandlerType: (*ChatAppUserServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Login", - Handler: _ChatAppUser_Login_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "gateway.proto", -} - -const ( - ChatAppPay_QueryOrder_FullMethodName = "/chatappgateway.gateway.v1.ChatAppPay/QueryOrder" -) - -// ChatAppPayClient is the client API for ChatAppPay 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 ChatAppPayClient interface { - QueryOrder(ctx context.Context, in *QueryOrderRequest, opts ...grpc.CallOption) (*QueryOrderResponse, error) -} - -type chatAppPayClient struct { - cc grpc.ClientConnInterface -} - -func NewChatAppPayClient(cc grpc.ClientConnInterface) ChatAppPayClient { - return &chatAppPayClient{cc} -} - -func (c *chatAppPayClient) QueryOrder(ctx context.Context, in *QueryOrderRequest, opts ...grpc.CallOption) (*QueryOrderResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(QueryOrderResponse) - err := c.cc.Invoke(ctx, ChatAppPay_QueryOrder_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -// ChatAppPayServer is the server API for ChatAppPay service. -// All implementations must embed UnimplementedChatAppPayServer -// for forward compatibility. -type ChatAppPayServer interface { - QueryOrder(context.Context, *QueryOrderRequest) (*QueryOrderResponse, error) - mustEmbedUnimplementedChatAppPayServer() -} - -// UnimplementedChatAppPayServer must be embedded to have -// forward compatible implementations. -// -// NOTE: this should be embedded by value instead of pointer to avoid a nil -// pointer dereference when methods are called. -type UnimplementedChatAppPayServer struct{} - -func (UnimplementedChatAppPayServer) QueryOrder(context.Context, *QueryOrderRequest) (*QueryOrderResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method QueryOrder not implemented") -} -func (UnimplementedChatAppPayServer) mustEmbedUnimplementedChatAppPayServer() {} -func (UnimplementedChatAppPayServer) testEmbeddedByValue() {} - -// UnsafeChatAppPayServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to ChatAppPayServer will -// result in compilation errors. -type UnsafeChatAppPayServer interface { - mustEmbedUnimplementedChatAppPayServer() -} - -func RegisterChatAppPayServer(s grpc.ServiceRegistrar, srv ChatAppPayServer) { - // If the following call pancis, it indicates UnimplementedChatAppPayServer was - // embedded by pointer and is nil. This will cause panics if an - // unimplemented method is ever invoked, so we test this at initialization - // time to prevent it from happening at runtime later due to I/O. - if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { - t.testEmbeddedByValue() - } - s.RegisterService(&ChatAppPay_ServiceDesc, srv) -} - -func _ChatAppPay_QueryOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryOrderRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ChatAppPayServer).QueryOrder(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: ChatAppPay_QueryOrder_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ChatAppPayServer).QueryOrder(ctx, req.(*QueryOrderRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// ChatAppPay_ServiceDesc is the grpc.ServiceDesc for ChatAppPay service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var ChatAppPay_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "chatappgateway.gateway.v1.ChatAppPay", - HandlerType: (*ChatAppPayServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "QueryOrder", - Handler: _ChatAppPay_QueryOrder_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "gateway.proto", -} diff --git a/docs/ai/第一版 prompt.md b/docs/ai/第一版 prompt.md index 7b169de..9ccd711 100644 --- a/docs/ai/第一版 prompt.md +++ b/docs/ai/第一版 prompt.md @@ -6,9 +6,9 @@ - `ChatAppGateway` 不是纯反向代理网关,而是 BFF / 聚合编排服务。 - 对客户端暴露 HTTP JSON API。 -- 对内通过 gRPC 调用: - - `ChatAppUser.Login` - - `ChatAppPay.QueryOrder` +- 对内通过 `Common` 里的 proto 调用: + - `ChatAppUserService.Register` + - `ChatAppPayService.Pay` - 自身不实现用户域认证规则,也不实现支付域核心规则,只做参数校验、字段归一化、协议适配、统一错误响应、日志与 trace。 ## 目标能力 @@ -17,8 +17,8 @@ 1. `GET /health` 2. `GET /ready` -3. `POST /api/v1/auth/login` -4. `GET /api/v1/pay/orders/{order_no}` +3. `POST /api/v1/users/register` +4. `POST /api/v1/pay` ## 配置要求 @@ -51,7 +51,7 @@ grpc: ## 登录接口要求 -`POST /api/v1/auth/login` +`POST /api/v1/users/register` 请求 DTO 至少包含: @@ -77,16 +77,14 @@ grpc: 网关职责: -- 只做模式校验和字段归一化 -- 将请求映射到 `ChatAppUser.Login` +- 做基础参数校验和字段归一化 +- 将请求映射到 `ChatAppUserService.Register` - 接收用户服务返回后再统一包装给客户端 -`ChatAppUser.Login` 返回至少包含: +`ChatAppUserService.Register` 返回至少包含: - `user_id` - `access_token` -- `refresh_token` -- `expires_in` - `is_new_user` - `profile` @@ -98,24 +96,25 @@ grpc: ## 支付查询接口要求 -`GET /api/v1/pay/orders/{order_no}` +`POST /api/v1/pay` 网关职责: - 校验 `order_no` 非空 -- 调用 `ChatAppPay.QueryOrder` +- 调用 `ChatAppPayService.Pay` - 把支付服务返回的订单结果转成统一 HTTP JSON 响应 返回字段至少包含: +- `payment_id` - `order_no` - `user_id` - `status` - `amount` - `currency` -- `subject` - `pay_method` -- `paid_at` +- `subject` +- `created_at` ## 健康检查要求 @@ -148,7 +147,7 @@ grpc: ## 错误码和状态码要求 - 参数错误:`400` -- 登录失败或凭证错误:`401` +- 注册失败或凭证错误:`401` - 订单不存在:`404` - 下游 gRPC 超时:`504` - 下游 gRPC 不可用或内部异常:`502` diff --git a/go.mod b/go.mod index 258d28e..dd9c820 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,17 @@ module chatappgateway go 1.23.1 require ( + gitea.haiyihy.com/hy/chatappcommon v0.0.0 google.golang.org/grpc v1.67.3 - google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 ) require ( - golang.org/x/net v0.35.0 // indirect + golang.org/x/net v0.28.0 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/text v0.22.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/protobuf v1.36.11 // indirect ) + +replace gitea.haiyihy.com/hy/chatappcommon => ../Common diff --git a/go.sum b/go.sum index 374ae13..f1e95eb 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= diff --git a/internal/app/app.go b/internal/app/app.go index b0fe2b3..e3cc813 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -6,13 +6,13 @@ import ( "io" "log/slog" - gatewaypb "chatappgateway/api/proto" "chatappgateway/internal/config" "chatappgateway/internal/integration/paygrpc" "chatappgateway/internal/integration/usergrpc" "chatappgateway/internal/service/auth" "chatappgateway/internal/service/pay" httpserver "chatappgateway/internal/transport/http" + commonpb "gitea.haiyihy.com/hy/chatappcommon/proto" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -37,8 +37,8 @@ func New(ctx context.Context, cfg config.Config, logger *slog.Logger) (*Applicat return nil, fmt.Errorf("dial ChatAppPay: %w", err) } - userClient := usergrpc.New(gatewaypb.NewChatAppUserClient(userConn), cfg.GRPC.User.Timeout) - payClient := paygrpc.New(gatewaypb.NewChatAppPayClient(payConn), cfg.GRPC.Pay.Timeout) + userClient := usergrpc.New(commonpb.NewChatAppUserServiceClient(userConn), cfg.GRPC.User.Timeout) + payClient := paygrpc.New(commonpb.NewChatAppPayServiceClient(payConn), cfg.GRPC.Pay.Timeout) authService := auth.New(userClient) payService := pay.New(payClient) diff --git a/internal/integration/paygrpc/client.go b/internal/integration/paygrpc/client.go index 175a4ea..09afad4 100644 --- a/internal/integration/paygrpc/client.go +++ b/internal/integration/paygrpc/client.go @@ -4,27 +4,27 @@ import ( "context" "time" - gatewaypb "chatappgateway/api/proto" + commonpb "gitea.haiyihy.com/hy/chatappcommon/proto" ) // Client 封装支付服务 gRPC client,并统一超时控制。 type Client struct { timeout time.Duration - client gatewaypb.ChatAppPayClient + client commonpb.ChatAppPayServiceClient } // New 根据底层 gRPC client 构造支付服务调用器。 -func New(client gatewaypb.ChatAppPayClient, timeout time.Duration) *Client { +func New(client commonpb.ChatAppPayServiceClient, timeout time.Duration) *Client { return &Client{ timeout: timeout, client: client, } } -// QueryOrder 调用支付服务最小订单查询接口。 -func (c *Client) QueryOrder(ctx context.Context, request *gatewaypb.QueryOrderRequest) (*gatewaypb.QueryOrderResponse, error) { +// Pay 调用支付服务最小支付接口。 +func (c *Client) Pay(ctx context.Context, request *commonpb.PayRequest) (*commonpb.PayResponse, error) { callCtx, cancel := context.WithTimeout(ctx, c.timeout) defer cancel() - return c.client.QueryOrder(callCtx, request) + return c.client.Pay(callCtx, request) } diff --git a/internal/integration/usergrpc/client.go b/internal/integration/usergrpc/client.go index 385fe37..361b8dc 100644 --- a/internal/integration/usergrpc/client.go +++ b/internal/integration/usergrpc/client.go @@ -4,27 +4,27 @@ import ( "context" "time" - gatewaypb "chatappgateway/api/proto" + commonpb "gitea.haiyihy.com/hy/chatappcommon/proto" ) // Client 封装用户服务 gRPC client,并统一超时控制。 type Client struct { timeout time.Duration - client gatewaypb.ChatAppUserClient + client commonpb.ChatAppUserServiceClient } // New 根据底层 gRPC client 构造用户服务调用器。 -func New(client gatewaypb.ChatAppUserClient, timeout time.Duration) *Client { +func New(client commonpb.ChatAppUserServiceClient, timeout time.Duration) *Client { return &Client{ timeout: timeout, client: client, } } -// Login 调用用户服务登录接口。 -func (c *Client) Login(ctx context.Context, request *gatewaypb.LoginRequest) (*gatewaypb.LoginResponse, error) { +// Register 调用用户服务注册接口。 +func (c *Client) Register(ctx context.Context, request *commonpb.RegisterRequest) (*commonpb.RegisterResponse, error) { callCtx, cancel := context.WithTimeout(ctx, c.timeout) defer cancel() - return c.client.Login(callCtx, request) + return c.client.Register(callCtx, request) } diff --git a/internal/service/auth/service.go b/internal/service/auth/service.go index 489fe7c..418b509 100644 --- a/internal/service/auth/service.go +++ b/internal/service/auth/service.go @@ -4,103 +4,76 @@ import ( "context" "strings" - gatewaypb "chatappgateway/api/proto" "chatappgateway/internal/apperr" + commonpb "gitea.haiyihy.com/hy/chatappcommon/proto" ) // Client 定义用户服务 gRPC 客户端能力。 type Client interface { - Login(ctx context.Context, request *gatewaypb.LoginRequest) (*gatewaypb.LoginResponse, error) + Register(ctx context.Context, request *commonpb.RegisterRequest) (*commonpb.RegisterResponse, error) } -// Service 负责登录参数校验、字段归一化和下游调用。 +// Service 负责注册参数校验、字段归一化和下游调用。 type Service struct { client Client } -// LoginRequest 描述 HTTP 层的登录入参。 -type LoginRequest struct { - LoginType string `json:"login_type"` - Account string `json:"account"` - Password string `json:"password"` - CountryCode string `json:"country_code"` - VerifyCode string `json:"verify_code"` - Provider string `json:"provider"` - ProviderToken string `json:"provider_token"` - DeviceID string `json:"device_id"` - Platform string `json:"platform"` - AppVersion string `json:"app_version"` +// RegisterRequest 描述 HTTP 层的注册入参。 +type RegisterRequest struct { + Account string `json:"account"` + Password string `json:"password"` + CountryCode string `json:"country_code"` + VerifyCode string `json:"verify_code"` + Nickname string `json:"nickname"` + DeviceID string `json:"device_id"` + Platform string `json:"platform"` + AppVersion string `json:"app_version"` } -// New 创建登录服务。 +// New 创建注册服务。 func New(client Client) *Service { return &Service{client: client} } -// Login 校验客户端请求并转成 gRPC 请求。 -func (s *Service) Login(ctx context.Context, request LoginRequest) (*gatewaypb.LoginResponse, error) { +// Register 校验客户端请求并转成 gRPC 请求。 +func (s *Service) Register(ctx context.Context, request RegisterRequest) (*commonpb.RegisterResponse, error) { normalized, err := normalize(request) if err != nil { return nil, err } - return s.client.Login(ctx, &gatewaypb.LoginRequest{ - LoginType: normalized.LoginType, - Account: normalized.Account, - Password: normalized.Password, - CountryCode: normalized.CountryCode, - VerifyCode: normalized.VerifyCode, - Provider: normalized.Provider, - ProviderToken: normalized.ProviderToken, - DeviceId: normalized.DeviceID, - Platform: normalized.Platform, - AppVersion: normalized.AppVersion, + return s.client.Register(ctx, &commonpb.RegisterRequest{ + Account: normalized.Account, + Password: normalized.Password, + CountryCode: normalized.CountryCode, + VerifyCode: normalized.VerifyCode, + Nickname: normalized.Nickname, + DeviceId: normalized.DeviceID, + Platform: normalized.Platform, + AppVersion: normalized.AppVersion, }) } -func normalize(request LoginRequest) (LoginRequest, error) { - normalized := LoginRequest{ - LoginType: strings.ToLower(strings.TrimSpace(request.LoginType)), - Account: strings.TrimSpace(request.Account), - Password: request.Password, - CountryCode: strings.TrimSpace(request.CountryCode), - VerifyCode: strings.TrimSpace(request.VerifyCode), - Provider: strings.ToLower(strings.TrimSpace(request.Provider)), - ProviderToken: strings.TrimSpace(request.ProviderToken), - DeviceID: strings.TrimSpace(request.DeviceID), - Platform: strings.TrimSpace(request.Platform), - AppVersion: strings.TrimSpace(request.AppVersion), +func normalize(request RegisterRequest) (RegisterRequest, error) { + normalized := RegisterRequest{ + Account: strings.TrimSpace(request.Account), + Password: strings.TrimSpace(request.Password), + CountryCode: strings.TrimSpace(request.CountryCode), + VerifyCode: strings.TrimSpace(request.VerifyCode), + Nickname: strings.TrimSpace(request.Nickname), + DeviceID: strings.TrimSpace(request.DeviceID), + Platform: strings.TrimSpace(request.Platform), + AppVersion: strings.TrimSpace(request.AppVersion), } - switch normalized.LoginType { - case "": - return LoginRequest{}, apperr.New(400, "bad_request", "login_type is required") - case "password": - if normalized.Account == "" { - return LoginRequest{}, apperr.New(400, "bad_request", "account is required") - } - if strings.TrimSpace(normalized.Password) == "" { - return LoginRequest{}, apperr.New(400, "bad_request", "password is required") - } - case "sms_code": - if normalized.CountryCode == "" { - return LoginRequest{}, apperr.New(400, "bad_request", "country_code is required") - } - if normalized.Account == "" { - return LoginRequest{}, apperr.New(400, "bad_request", "account is required") - } - if normalized.VerifyCode == "" { - return LoginRequest{}, apperr.New(400, "bad_request", "verify_code is required") - } - case "oauth": - if normalized.Provider == "" { - return LoginRequest{}, apperr.New(400, "bad_request", "provider is required") - } - if normalized.ProviderToken == "" { - return LoginRequest{}, apperr.New(400, "bad_request", "provider_token is required") - } - default: - return LoginRequest{}, apperr.New(400, "bad_request", "login_type must be one of password, sms_code, oauth") + if normalized.Account == "" { + return RegisterRequest{}, apperr.New(400, "bad_request", "account is required") + } + if normalized.Password == "" { + return RegisterRequest{}, apperr.New(400, "bad_request", "password is required") + } + if normalized.Nickname == "" { + normalized.Nickname = normalized.Account } return normalized, nil diff --git a/internal/service/pay/service.go b/internal/service/pay/service.go index 2b62af7..dec5cb4 100644 --- a/internal/service/pay/service.go +++ b/internal/service/pay/service.go @@ -4,16 +4,26 @@ import ( "context" "strings" - gatewaypb "chatappgateway/api/proto" "chatappgateway/internal/apperr" + commonpb "gitea.haiyihy.com/hy/chatappcommon/proto" ) // Client 定义支付服务 gRPC 客户端能力。 type Client interface { - QueryOrder(ctx context.Context, request *gatewaypb.QueryOrderRequest) (*gatewaypb.QueryOrderResponse, error) + Pay(ctx context.Context, request *commonpb.PayRequest) (*commonpb.PayResponse, error) } -// Service 负责订单号校验和下游支付查询。 +// Request 描述客户端发起支付的请求。 +type Request struct { + OrderNo string `json:"order_no"` + UserID string `json:"user_id"` + Amount string `json:"amount"` + Currency string `json:"currency"` + PayMethod string `json:"pay_method"` + Subject string `json:"subject"` +} + +// Service 负责支付请求校验和下游支付调用。 type Service struct { client Client } @@ -23,14 +33,33 @@ func New(client Client) *Service { return &Service{client: client} } -// QueryOrder 校验订单号并调用支付服务。 -func (s *Service) QueryOrder(ctx context.Context, orderNo string) (*gatewaypb.QueryOrderResponse, error) { - normalized := strings.TrimSpace(orderNo) - if normalized == "" { - return nil, apperr.New(400, "bad_request", "order_no is required") +// Pay 校验支付请求并调用支付服务。 +func (s *Service) Pay(ctx context.Context, request Request) (*commonpb.PayResponse, error) { + normalized := Request{ + OrderNo: strings.TrimSpace(request.OrderNo), + UserID: strings.TrimSpace(request.UserID), + Amount: strings.TrimSpace(request.Amount), + Currency: strings.TrimSpace(request.Currency), + PayMethod: strings.TrimSpace(request.PayMethod), + Subject: strings.TrimSpace(request.Subject), } - return s.client.QueryOrder(ctx, &gatewaypb.QueryOrderRequest{ - OrderNo: normalized, + if normalized.OrderNo == "" { + return nil, apperr.New(400, "bad_request", "order_no is required") + } + if normalized.UserID == "" { + return nil, apperr.New(400, "bad_request", "user_id is required") + } + if normalized.Amount == "" { + return nil, apperr.New(400, "bad_request", "amount is required") + } + + return s.client.Pay(ctx, &commonpb.PayRequest{ + OrderNo: normalized.OrderNo, + UserId: normalized.UserID, + Amount: normalized.Amount, + Currency: normalized.Currency, + PayMethod: normalized.PayMethod, + Subject: normalized.Subject, }) } diff --git a/internal/transport/http/server.go b/internal/transport/http/server.go index 1bd30ed..14079f7 100644 --- a/internal/transport/http/server.go +++ b/internal/transport/http/server.go @@ -14,23 +14,22 @@ import ( "sync/atomic" "time" - gatewaypb "chatappgateway/api/proto" "chatappgateway/internal/apperr" "chatappgateway/internal/service/auth" + payservice "chatappgateway/internal/service/pay" + commonpb "gitea.haiyihy.com/hy/chatappcommon/proto" ) -const orderPrefix = "/api/v1/pay/orders/" - type requestIDKey struct{} -// AuthService 定义 HTTP 层依赖的登录业务能力。 +// AuthService 定义 HTTP 层依赖的用户注册能力。 type AuthService interface { - Login(ctx context.Context, request auth.LoginRequest) (*gatewaypb.LoginResponse, error) + Register(ctx context.Context, request auth.RegisterRequest) (*commonpb.RegisterResponse, error) } -// PayService 定义 HTTP 层依赖的支付查询能力。 +// PayService 定义 HTTP 层依赖的支付下单能力。 type PayService interface { - QueryOrder(ctx context.Context, orderNo string) (*gatewaypb.QueryOrderResponse, error) + Pay(ctx context.Context, request payservice.Request) (*commonpb.PayResponse, error) } // ReadinessChecker 定义就绪检查能力,只有可接流量时才返回 nil。 @@ -104,9 +103,10 @@ func (s *Server) Run(ctx context.Context) error { func (s *Server) routes() http.Handler { mux := http.NewServeMux() mux.HandleFunc("/health", s.handleHealth) + mux.HandleFunc("/heath", s.handleHealth) mux.HandleFunc("/ready", s.handleReady) - mux.HandleFunc("/api/v1/auth/login", s.handleLogin) - mux.HandleFunc(orderPrefix, s.handleQueryOrder) + mux.HandleFunc("/api/v1/users/register", s.handleRegister) + mux.HandleFunc("/api/v1/pay", s.handlePay) mux.HandleFunc("/", s.handleNotFound) return mux } @@ -139,13 +139,13 @@ func (s *Server) handleReady(w http.ResponseWriter, r *http.Request) { }) } -func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) { +func (s *Server) handleRegister(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeError(w, requestIDFromContext(r.Context()), apperr.New(http.StatusMethodNotAllowed, "method_not_allowed", "method not allowed")) return } - var request auth.LoginRequest + var request auth.RegisterRequest decoder := json.NewDecoder(r.Body) decoder.DisallowUnknownFields() if err := decoder.Decode(&request); err != nil { @@ -153,7 +153,7 @@ func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) { return } - response, err := s.authService.Login(r.Context(), request) + response, err := s.authService.Register(r.Context(), request) if err != nil { writeError(w, requestIDFromContext(r.Context()), err) return @@ -162,19 +162,21 @@ func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) { writeEnvelope(w, http.StatusOK, requestIDFromContext(r.Context()), response) } -func (s *Server) handleQueryOrder(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodGet { +func (s *Server) handlePay(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { writeError(w, requestIDFromContext(r.Context()), apperr.New(http.StatusMethodNotAllowed, "method_not_allowed", "method not allowed")) return } - orderNo, ok := extractOrderNo(r.URL.Path) - if !ok { - writeError(w, requestIDFromContext(r.Context()), apperr.New(http.StatusNotFound, "not_found", "order not found")) + var request payservice.Request + decoder := json.NewDecoder(r.Body) + decoder.DisallowUnknownFields() + if err := decoder.Decode(&request); err != nil { + writeError(w, requestIDFromContext(r.Context()), apperr.New(http.StatusBadRequest, "bad_request", "invalid json body")) return } - response, err := s.payService.QueryOrder(r.Context(), orderNo) + response, err := s.payService.Pay(r.Context(), request) if err != nil { writeError(w, requestIDFromContext(r.Context()), err) return @@ -234,17 +236,6 @@ func writeJSON(w http.ResponseWriter, statusCode int, payload any) { _ = json.NewEncoder(w).Encode(payload) } -func extractOrderNo(path string) (string, bool) { - if !strings.HasPrefix(path, orderPrefix) { - return "", false - } - orderNo := strings.TrimPrefix(path, orderPrefix) - if orderNo == "" || strings.Contains(orderNo, "/") { - return "", false - } - return orderNo, true -} - func requestIDFromContext(ctx context.Context) string { requestID, _ := ctx.Value(requestIDKey{}).(string) return requestID diff --git a/internal/transport/http/server_test.go b/internal/transport/http/server_test.go index 75aa65d..b1a84d1 100644 --- a/internal/transport/http/server_test.go +++ b/internal/transport/http/server_test.go @@ -15,12 +15,12 @@ import ( "testing" "time" - gatewaypb "chatappgateway/api/proto" "chatappgateway/internal/integration/paygrpc" "chatappgateway/internal/integration/usergrpc" "chatappgateway/internal/service/auth" - "chatappgateway/internal/service/pay" + payservice "chatappgateway/internal/service/pay" httpserver "chatappgateway/internal/transport/http" + commonpb "gitea.haiyihy.com/hy/chatappcommon/proto" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -78,16 +78,16 @@ func TestReady(t *testing.T) { env := newTestEnv(t, 200*time.Millisecond, 200*time.Millisecond) defer env.Close() - env.readinessChecker.err = errors.New("redis not ready") + env.readinessChecker.err = errors.New("chatappuser not ready") resp, responseBody := doRequest(t, env.server.Client(), http.MethodGet, env.server.URL+"/ready", nil) defer resp.Body.Close() - assertErrorResponse(t, resp.StatusCode, responseBody, http.StatusServiceUnavailable, "redis not ready") + assertErrorResponse(t, resp.StatusCode, responseBody, http.StatusServiceUnavailable, "chatappuser not ready") }) } -func TestLoginValidation(t *testing.T) { +func TestRegisterValidation(t *testing.T) { t.Parallel() env := newTestEnv(t, 200*time.Millisecond, 200*time.Millisecond) @@ -99,26 +99,21 @@ func TestLoginValidation(t *testing.T) { message string }{ { - name: "password missing account", - body: `{"login_type":"password","password":"secret"}`, + name: "missing account", + body: `{"password":"secret"}`, message: "account is required", }, { - name: "sms_code missing verify_code", - body: `{"login_type":"sms_code","country_code":"+86","account":"13800138000"}`, - message: "verify_code is required", - }, - { - name: "oauth missing provider_token", - body: `{"login_type":"oauth","provider":"google"}`, - message: "provider_token is required", + name: "missing password", + body: `{"account":"demo@example.com"}`, + message: "password is required", }, } for _, testCase := range testCases { testCase := testCase t.Run(testCase.name, func(t *testing.T) { - resp, body := doRequest(t, env.server.Client(), http.MethodPost, env.server.URL+"/api/v1/auth/login", strings.NewReader(testCase.body)) + resp, body := doRequest(t, env.server.Client(), http.MethodPost, env.server.URL+"/api/v1/users/register", strings.NewReader(testCase.body)) defer resp.Body.Close() if resp.StatusCode != http.StatusBadRequest { @@ -134,25 +129,19 @@ func TestLoginValidation(t *testing.T) { } }) } - - if env.userServer.CallCount() != 0 { - t.Fatalf("expected user service not to be called, got %d", env.userServer.CallCount()) - } } -func TestLoginDelegatesToUserGRPC(t *testing.T) { +func TestRegisterDelegatesToUserGRPC(t *testing.T) { t.Parallel() env := newTestEnv(t, 200*time.Millisecond, 200*time.Millisecond) defer env.Close() - env.userServer.response = &gatewaypb.LoginResponse{ - UserId: "u-100", - AccessToken: "access-token", - RefreshToken: "refresh-token", - ExpiresIn: 7200, - IsNewUser: true, - Profile: &gatewaypb.UserProfile{ + env.userServer.response = &commonpb.RegisterResponse{ + UserId: "u-100", + AccessToken: "access-token", + IsNewUser: true, + Profile: &commonpb.UserProfile{ UserId: "u-100", Nickname: "Neo", AvatarUrl: "https://example.com/avatar.png", @@ -160,22 +149,22 @@ func TestLoginDelegatesToUserGRPC(t *testing.T) { } body := `{ - "login_type":" PASSWORD ", "account":" demo@example.com ", - "password":"secret", + "password":" secret ", + "nickname":" Neo ", "device_id":" dev-1 ", "platform":" ios ", "app_version":" 1.0.0 " }` - resp, responseBody := doRequest(t, env.server.Client(), http.MethodPost, env.server.URL+"/api/v1/auth/login", strings.NewReader(body)) + resp, responseBody := doRequest(t, env.server.Client(), http.MethodPost, env.server.URL+"/api/v1/users/register", strings.NewReader(body)) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("unexpected status: %d body=%s", resp.StatusCode, string(responseBody)) } - var payload successResponse[gatewaypb.LoginResponse] + var payload successResponse[commonpb.RegisterResponse] if err := json.Unmarshal(responseBody, &payload); err != nil { t.Fatalf("Unmarshal returned error: %v", err) } @@ -187,45 +176,90 @@ func TestLoginDelegatesToUserGRPC(t *testing.T) { if request == nil { t.Fatal("expected request to be captured") } - if request.LoginType != "password" { - t.Fatalf("unexpected login type: %s", request.LoginType) - } if request.Account != "demo@example.com" { t.Fatalf("unexpected account: %q", request.Account) } - if request.DeviceId != "dev-1" { - t.Fatalf("unexpected device id: %q", request.DeviceId) - } - if request.Platform != "ios" { - t.Fatalf("unexpected platform: %q", request.Platform) + if request.Nickname != "Neo" { + t.Fatalf("unexpected nickname: %q", request.Nickname) } } -func TestQueryOrderDelegatesToPayGRPC(t *testing.T) { +func TestPayValidation(t *testing.T) { t.Parallel() env := newTestEnv(t, 200*time.Millisecond, 200*time.Millisecond) defer env.Close() - env.payServer.response = &gatewaypb.QueryOrderResponse{ - OrderNo: "order-001", - UserId: "u-100", - Status: "paid", - Amount: "9.99", - Currency: "USD", - Subject: "VIP", - PayMethod: "apple_pay", - PaidAt: "2026-04-04T12:00:00Z", + testCases := []struct { + name string + body string + message string + }{ + { + name: "missing order_no", + body: `{"user_id":"u-1","amount":"9.99"}`, + message: "order_no is required", + }, + { + name: "missing user_id", + body: `{"order_no":"ord-1","amount":"9.99"}`, + message: "user_id is required", + }, + { + name: "missing amount", + body: `{"order_no":"ord-1","user_id":"u-1"}`, + message: "amount is required", + }, } - resp, responseBody := doRequest(t, env.server.Client(), http.MethodGet, env.server.URL+"/api/v1/pay/orders/order-001", nil) + for _, testCase := range testCases { + testCase := testCase + t.Run(testCase.name, func(t *testing.T) { + resp, body := doRequest(t, env.server.Client(), http.MethodPost, env.server.URL+"/api/v1/pay", strings.NewReader(testCase.body)) + defer resp.Body.Close() + + if resp.StatusCode != http.StatusBadRequest { + t.Fatalf("unexpected status: %d", resp.StatusCode) + } + + var payload errorResponse + if err := json.Unmarshal(body, &payload); err != nil { + t.Fatalf("Unmarshal returned error: %v", err) + } + if payload.Message != testCase.message { + t.Fatalf("unexpected message: %s", payload.Message) + } + }) + } +} + +func TestPayDelegatesToPayGRPC(t *testing.T) { + t.Parallel() + + env := newTestEnv(t, 200*time.Millisecond, 200*time.Millisecond) + defer env.Close() + + env.payServer.response = &commonpb.PayResponse{ + PaymentId: "pay-001", + OrderNo: "order-001", + UserId: "u-100", + Status: "processing", + Amount: "9.99", + Currency: "USD", + PayMethod: "apple_pay", + Subject: "vip", + CreatedAt: "2026-04-04T12:00:00Z", + } + + body := `{"order_no":"order-001","user_id":"u-100","amount":"9.99","currency":"USD","pay_method":"apple_pay","subject":"vip"}` + resp, responseBody := doRequest(t, env.server.Client(), http.MethodPost, env.server.URL+"/api/v1/pay", strings.NewReader(body)) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("unexpected status: %d body=%s", resp.StatusCode, string(responseBody)) } - var payload successResponse[gatewaypb.QueryOrderResponse] + var payload successResponse[commonpb.PayResponse] if err := json.Unmarshal(responseBody, &payload); err != nil { t.Fatalf("Unmarshal returned error: %v", err) } @@ -242,37 +276,25 @@ func TestQueryOrderDelegatesToPayGRPC(t *testing.T) { func TestErrorMapping(t *testing.T) { t.Parallel() - t.Run("login unauthorized", func(t *testing.T) { + t.Run("register unauthorized", func(t *testing.T) { env := newTestEnv(t, 200*time.Millisecond, 200*time.Millisecond) defer env.Close() - env.userServer.err = status.Error(codes.Unauthenticated, "invalid credentials") + env.userServer.err = status.Error(codes.Unauthenticated, "register denied") - resp, responseBody := doRequest(t, env.server.Client(), http.MethodPost, env.server.URL+"/api/v1/auth/login", strings.NewReader(`{"login_type":"password","account":"demo","password":"wrong"}`)) + resp, responseBody := doRequest(t, env.server.Client(), http.MethodPost, env.server.URL+"/api/v1/users/register", strings.NewReader(`{"account":"demo","password":"secret"}`)) defer resp.Body.Close() - assertErrorResponse(t, resp.StatusCode, responseBody, http.StatusUnauthorized, "invalid credentials") + assertErrorResponse(t, resp.StatusCode, responseBody, http.StatusUnauthorized, "register denied") }) - t.Run("pay not found", func(t *testing.T) { - env := newTestEnv(t, 200*time.Millisecond, 200*time.Millisecond) + t.Run("pay timeout", func(t *testing.T) { + env := newTestEnv(t, 200*time.Millisecond, 20*time.Millisecond) defer env.Close() - env.payServer.err = status.Error(codes.NotFound, "order not found") + env.payServer.delay = 150 * time.Millisecond - resp, responseBody := doRequest(t, env.server.Client(), http.MethodGet, env.server.URL+"/api/v1/pay/orders/missing-order", nil) - defer resp.Body.Close() - - assertErrorResponse(t, resp.StatusCode, responseBody, http.StatusNotFound, "order not found") - }) - - t.Run("login timeout", func(t *testing.T) { - env := newTestEnv(t, 20*time.Millisecond, 200*time.Millisecond) - defer env.Close() - - env.userServer.delay = 150 * time.Millisecond - - resp, responseBody := doRequest(t, env.server.Client(), http.MethodPost, env.server.URL+"/api/v1/auth/login", strings.NewReader(`{"login_type":"password","account":"demo","password":"secret"}`)) + resp, responseBody := doRequest(t, env.server.Client(), http.MethodPost, env.server.URL+"/api/v1/pay", strings.NewReader(`{"order_no":"ord-1","user_id":"u-1","amount":"9.99"}`)) defer resp.Body.Close() assertErrorResponse(t, resp.StatusCode, responseBody, http.StatusGatewayTimeout, "upstream request timeout") @@ -284,7 +306,7 @@ func TestErrorMapping(t *testing.T) { env.payServer.err = status.Error(codes.Unavailable, "pay service unavailable") - resp, responseBody := doRequest(t, env.server.Client(), http.MethodGet, env.server.URL+"/api/v1/pay/orders/order-001", nil) + resp, responseBody := doRequest(t, env.server.Client(), http.MethodPost, env.server.URL+"/api/v1/pay", strings.NewReader(`{"order_no":"ord-1","user_id":"u-1","amount":"9.99"}`)) defer resp.Body.Close() assertErrorResponse(t, resp.StatusCode, responseBody, http.StatusBadGateway, "pay service unavailable") @@ -320,37 +342,37 @@ func newTestEnv(t *testing.T, userTimeout time.Duration, payTimeout time.Duratio t.Helper() userServer := &mockUserServer{ - response: &gatewaypb.LoginResponse{ - UserId: "default-user", - AccessToken: "default-access", - RefreshToken: "default-refresh", - ExpiresIn: 3600, - Profile: &gatewaypb.UserProfile{ + response: &commonpb.RegisterResponse{ + UserId: "default-user", + AccessToken: "default-access", + IsNewUser: true, + Profile: &commonpb.UserProfile{ UserId: "default-user", Nickname: "default", }, }, } payServer := &mockPayServer{ - response: &gatewaypb.QueryOrderResponse{ - OrderNo: "default-order", - UserId: "default-user", - Status: "pending", - Amount: "0", - Currency: "USD", + response: &commonpb.PayResponse{ + PaymentId: "default-pay", + OrderNo: "default-order", + UserId: "default-user", + Status: "processing", + Amount: "9.99", + Currency: "USD", }, } userConn, userClose := newBufConnClient(t, func(server *grpc.Server) { - gatewaypb.RegisterChatAppUserServer(server, userServer) + commonpb.RegisterChatAppUserServiceServer(server, userServer) }) payConn, payClose := newBufConnClient(t, func(server *grpc.Server) { - gatewaypb.RegisterChatAppPayServer(server, payServer) + commonpb.RegisterChatAppPayServiceServer(server, payServer) }) logger := slog.New(slog.NewTextHandler(io.Discard, nil)) - authService := auth.New(usergrpc.New(gatewaypb.NewChatAppUserClient(userConn), userTimeout)) - payService := pay.New(paygrpc.New(gatewaypb.NewChatAppPayClient(payConn), payTimeout)) + authService := auth.New(usergrpc.New(commonpb.NewChatAppUserServiceClient(userConn), userTimeout)) + payService := payservice.New(paygrpc.New(commonpb.NewChatAppPayServiceClient(payConn), payTimeout)) readinessChecker := &mockReadinessChecker{} handler := httpserver.New("chatappgateway", ":0", 2*time.Second, logger, authService, payService, readinessChecker).Handler() @@ -453,19 +475,17 @@ type errorResponse struct { } type mockUserServer struct { - gatewaypb.UnimplementedChatAppUserServer + commonpb.UnimplementedChatAppUserServiceServer - mu sync.Mutex - callCount int - lastReq *gatewaypb.LoginRequest - response *gatewaypb.LoginResponse - err error - delay time.Duration + mu sync.Mutex + lastReq *commonpb.RegisterRequest + response *commonpb.RegisterResponse + err error + delay time.Duration } -func (s *mockUserServer) Login(ctx context.Context, request *gatewaypb.LoginRequest) (*gatewaypb.LoginResponse, error) { +func (s *mockUserServer) Register(ctx context.Context, request *commonpb.RegisterRequest) (*commonpb.RegisterResponse, error) { s.mu.Lock() - s.callCount++ copied := *request s.lastReq = &copied response := s.response @@ -487,13 +507,7 @@ func (s *mockUserServer) Login(ctx context.Context, request *gatewaypb.LoginRequ return response, nil } -func (s *mockUserServer) CallCount() int { - s.mu.Lock() - defer s.mu.Unlock() - return s.callCount -} - -func (s *mockUserServer) LastRequest() *gatewaypb.LoginRequest { +func (s *mockUserServer) LastRequest() *commonpb.RegisterRequest { s.mu.Lock() defer s.mu.Unlock() if s.lastReq == nil { @@ -504,16 +518,16 @@ func (s *mockUserServer) LastRequest() *gatewaypb.LoginRequest { } type mockPayServer struct { - gatewaypb.UnimplementedChatAppPayServer + commonpb.UnimplementedChatAppPayServiceServer mu sync.Mutex - lastReq *gatewaypb.QueryOrderRequest - response *gatewaypb.QueryOrderResponse + lastReq *commonpb.PayRequest + response *commonpb.PayResponse err error delay time.Duration } -func (s *mockPayServer) QueryOrder(ctx context.Context, request *gatewaypb.QueryOrderRequest) (*gatewaypb.QueryOrderResponse, error) { +func (s *mockPayServer) Pay(ctx context.Context, request *commonpb.PayRequest) (*commonpb.PayResponse, error) { s.mu.Lock() copied := *request s.lastReq = &copied @@ -536,7 +550,7 @@ func (s *mockPayServer) QueryOrder(ctx context.Context, request *gatewaypb.Query return response, nil } -func (s *mockPayServer) LastRequest() *gatewaypb.QueryOrderRequest { +func (s *mockPayServer) LastRequest() *commonpb.PayRequest { s.mu.Lock() defer s.mu.Unlock() if s.lastReq == nil {