package userclient import ( "context" "time" "hyapp-admin-server/internal/appctx" userv1 "hyapp.local/api/proto/user/v1" "google.golang.org/grpc" ) type Client interface { GetUser(ctx context.Context, req GetUserRequest) (*User, error) ResolveDisplayUserID(ctx context.Context, req ResolveDisplayUserIDRequest) (*UserIdentity, error) ListCountries(ctx context.Context, req ListCountriesRequest) ([]*Country, error) UpdateCountry(ctx context.Context, req UpdateCountryRequest) (*Country, error) ListRegions(ctx context.Context, req ListRegionsRequest) ([]*Region, error) GetRegion(ctx context.Context, req GetRegionRequest) (*Region, error) UpdateRegion(ctx context.Context, req UpdateRegionRequest) (*Region, error) ReplaceRegionCountries(ctx context.Context, req ReplaceRegionCountriesRequest) (*Region, error) CreateBDLeader(ctx context.Context, req CreateBDLeaderRequest) (*BDProfile, error) CreateBD(ctx context.Context, req CreateBDRequest) (*BDProfile, error) SetBDStatus(ctx context.Context, req SetBDStatusRequest) (*BDProfile, error) CreateCoinSeller(ctx context.Context, req CreateCoinSellerRequest) (*CoinSellerProfile, error) SetCoinSellerStatus(ctx context.Context, req SetCoinSellerStatusRequest) (*CoinSellerProfile, error) GetCoinSellerProfile(ctx context.Context, req GetCoinSellerProfileRequest) (*CoinSellerProfile, error) CreateAgency(ctx context.Context, req CreateAgencyRequest) (*CreateAgencyResult, error) CloseAgency(ctx context.Context, req CloseAgencyRequest) (*Agency, error) SetAgencyJoinEnabled(ctx context.Context, req SetAgencyJoinEnabledRequest) (*Agency, error) } type GetUserRequest struct { RequestID string Caller string UserID int64 } type ResolveDisplayUserIDRequest struct { RequestID string Caller string DisplayUserID string } type UserIdentity struct { UserID int64 `json:"userId,string"` DisplayUserID string `json:"displayUserId"` Status string `json:"status"` DefaultDisplayUserID string `json:"defaultDisplayUserId"` DisplayUserIDKind string `json:"displayUserIdKind"` DisplayUserIDExpiresAtMs int64 `json:"displayUserIdExpiresAtMs"` AppCode string `json:"appCode"` } type User struct { UserID int64 `json:"userId,string"` Status string `json:"status"` CreatedAtMs int64 `json:"createdAtMs"` UpdatedAtMs int64 `json:"updatedAtMs"` DisplayUserID string `json:"displayUserId"` DefaultDisplayUserID string `json:"defaultDisplayUserId"` DisplayUserIDKind string `json:"displayUserIdKind"` DisplayUserIDExpiresAtMs int64 `json:"displayUserIdExpiresAtMs"` Username string `json:"username"` Gender string `json:"gender"` Country string `json:"country"` Avatar string `json:"avatar"` Birth string `json:"birth"` Language string `json:"language"` CountryID int64 `json:"countryId"` CountryName string `json:"countryName"` CountryDisplayName string `json:"countryDisplayName"` RegionID int64 `json:"regionId"` RegionCode string `json:"regionCode"` RegionName string `json:"regionName"` ProfileCompleted bool `json:"profileCompleted"` ProfileCompletedAtMs int64 `json:"profileCompletedAtMs"` OnboardingStatus string `json:"onboardingStatus"` ISONumeric string `json:"isoNumeric"` PhoneCountryCode string `json:"phoneCountryCode"` CountryEnabled bool `json:"countryEnabled"` } type GRPCClient struct { client userv1.UserServiceClient identityClient userv1.UserIdentityServiceClient countryClient userv1.CountryAdminServiceClient regionClient userv1.RegionAdminServiceClient hostClient userv1.UserHostServiceClient hostAdminClient userv1.UserHostAdminServiceClient } func NewGRPC(conn grpc.ClientConnInterface) *GRPCClient { return &GRPCClient{ client: userv1.NewUserServiceClient(conn), identityClient: userv1.NewUserIdentityServiceClient(conn), countryClient: userv1.NewCountryAdminServiceClient(conn), regionClient: userv1.NewRegionAdminServiceClient(conn), hostClient: userv1.NewUserHostServiceClient(conn), hostAdminClient: userv1.NewUserHostAdminServiceClient(conn), } } func (c *GRPCClient) GetUser(ctx context.Context, req GetUserRequest) (*User, error) { resp, err := c.client.GetUser(ctx, &userv1.GetUserRequest{ Meta: &userv1.RequestMeta{ RequestId: req.RequestID, Caller: req.Caller, SentAtMs: time.Now().UnixMilli(), AppCode: appctx.FromContext(ctx), }, UserId: req.UserID, }) if err != nil { return nil, err } return fromProtoUser(resp.GetUser()), nil } func (c *GRPCClient) ResolveDisplayUserID(ctx context.Context, req ResolveDisplayUserIDRequest) (*UserIdentity, error) { resp, err := c.identityClient.ResolveDisplayUserID(ctx, &userv1.ResolveDisplayUserIDRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), DisplayUserId: req.DisplayUserID, }) if err != nil { return nil, err } return fromProtoUserIdentity(resp.GetIdentity()), nil } func fromProtoUser(user *userv1.User) *User { if user == nil { return nil } return &User{ UserID: user.GetUserId(), Status: user.GetStatus().String(), CreatedAtMs: user.GetCreatedAtMs(), UpdatedAtMs: user.GetUpdatedAtMs(), DisplayUserID: user.GetDisplayUserId(), DefaultDisplayUserID: user.GetDefaultDisplayUserId(), DisplayUserIDKind: user.GetDisplayUserIdKind(), DisplayUserIDExpiresAtMs: user.GetDisplayUserIdExpiresAtMs(), Username: user.GetUsername(), Gender: user.GetGender(), Country: user.GetCountry(), Avatar: user.GetAvatar(), Birth: user.GetBirth(), Language: user.GetLanguage(), CountryID: user.GetCountryId(), CountryName: user.GetCountryName(), CountryDisplayName: user.GetCountryDisplayName(), RegionID: user.GetRegionId(), RegionCode: user.GetRegionCode(), RegionName: user.GetRegionName(), ProfileCompleted: user.GetProfileCompleted(), ProfileCompletedAtMs: user.GetProfileCompletedAtMs(), OnboardingStatus: user.GetOnboardingStatus(), ISONumeric: user.GetIsoNumeric(), PhoneCountryCode: user.GetPhoneCountryCode(), CountryEnabled: user.GetCountryEnabled(), } } func fromProtoUserIdentity(identity *userv1.UserIdentity) *UserIdentity { if identity == nil { return nil } return &UserIdentity{ UserID: identity.GetUserId(), DisplayUserID: identity.GetDisplayUserId(), Status: identity.GetStatus(), DefaultDisplayUserID: identity.GetDefaultDisplayUserId(), DisplayUserIDKind: identity.GetDisplayUserIdKind(), DisplayUserIDExpiresAtMs: identity.GetDisplayUserIdExpiresAtMs(), AppCode: identity.GetAppCode(), } } type CreateBDLeaderRequest struct { RequestID string Caller string CommandID string AdminUserID int64 RegionID int64 TargetUserID int64 Reason string } type CreateBDRequest struct { RequestID string Caller string CommandID string AdminUserID int64 TargetUserID int64 ParentLeaderUserID int64 Reason string } type SetBDStatusRequest struct { RequestID string Caller string CommandID string AdminUserID int64 TargetUserID int64 Status string Reason string } type CreateCoinSellerRequest struct { RequestID string Caller string CommandID string AdminUserID int64 TargetUserID int64 Reason string } type SetCoinSellerStatusRequest struct { RequestID string Caller string CommandID string AdminUserID int64 TargetUserID int64 Status string Reason string } type GetCoinSellerProfileRequest struct { RequestID string Caller string UserID int64 } type CreateAgencyRequest struct { RequestID string Caller string CommandID string AdminUserID int64 OwnerUserID int64 ParentBDUserID int64 Name string JoinEnabled bool MaxHosts int32 Reason string } type CloseAgencyRequest struct { RequestID string Caller string CommandID string AdminUserID int64 AgencyID int64 Reason string } type SetAgencyJoinEnabledRequest struct { RequestID string Caller string CommandID string AdminUserID int64 AgencyID int64 JoinEnabled bool Reason string } type BDProfile struct { UserID int64 `json:"userId,string"` Role string `json:"role"` RegionID int64 `json:"regionId"` ParentLeaderUserID int64 `json:"parentLeaderUserId,string"` Status string `json:"status"` CreatedByUserID int64 `json:"createdByUserId"` CreatedAtMs int64 `json:"createdAtMs"` UpdatedAtMs int64 `json:"updatedAtMs"` DisplayUserID string `json:"displayUserId"` Username string `json:"username"` Avatar string `json:"avatar"` RegionName string `json:"regionName"` ParentLeaderDisplayID string `json:"parentLeaderDisplayUserId"` ParentLeaderUsername string `json:"parentLeaderUsername"` ParentLeaderAvatar string `json:"parentLeaderAvatar"` CreatedByDisplayUserID string `json:"createdByDisplayUserId"` CreatedByUsername string `json:"createdByUsername"` CreatedByAvatar string `json:"createdByAvatar"` SubBDCount int64 `json:"subBdCount"` } type Agency struct { AgencyID int64 `json:"agencyId"` OwnerUserID int64 `json:"ownerUserId,string"` RegionID int64 `json:"regionId"` ParentBDUserID int64 `json:"parentBdUserId,string"` Name string `json:"name"` Status string `json:"status"` JoinEnabled bool `json:"joinEnabled"` MaxHosts int32 `json:"maxHosts"` CreatedByUserID int64 `json:"createdByUserId"` CreatedAtMs int64 `json:"createdAtMs"` UpdatedAtMs int64 `json:"updatedAtMs"` OwnerDisplayUserID string `json:"ownerDisplayUserId"` OwnerUsername string `json:"ownerUsername"` OwnerAvatar string `json:"ownerAvatar"` ParentBDDisplayUserID string `json:"parentBdDisplayUserId"` ParentBDUsername string `json:"parentBdUsername"` ParentBDAvatar string `json:"parentBdAvatar"` RegionName string `json:"regionName"` } type HostProfile struct { UserID int64 `json:"userId,string"` Status string `json:"status"` RegionID int64 `json:"regionId"` CurrentAgencyID int64 `json:"currentAgencyId"` CurrentMembershipID int64 `json:"currentMembershipId"` Source string `json:"source"` FirstBecameHostAtMs int64 `json:"firstBecameHostAtMs"` CreatedAtMs int64 `json:"createdAtMs"` UpdatedAtMs int64 `json:"updatedAtMs"` DisplayUserID string `json:"displayUserId"` Username string `json:"username"` Avatar string `json:"avatar"` RegionName string `json:"regionName"` CurrentAgencyName string `json:"currentAgencyName"` } type CoinSellerProfile struct { UserID int64 `json:"userId,string"` Status string `json:"status"` MerchantAssetType string `json:"merchantAssetType"` CreatedByUserID int64 `json:"createdByUserId"` CreatedAtMs int64 `json:"createdAtMs"` UpdatedAtMs int64 `json:"updatedAtMs"` } type AgencyMembership struct { MembershipID int64 `json:"membershipId"` AgencyID int64 `json:"agencyId"` HostUserID int64 `json:"hostUserId,string"` RegionID int64 `json:"regionId"` MembershipType string `json:"membershipType"` Status string `json:"status"` JoinedAtMs int64 `json:"joinedAtMs"` EndedAtMs int64 `json:"endedAtMs"` EndedByUserID int64 `json:"endedByUserId,string"` EndedReason string `json:"endedReason"` CreatedAtMs int64 `json:"createdAtMs"` UpdatedAtMs int64 `json:"updatedAtMs"` } type CreateAgencyResult struct { Agency *Agency `json:"agency"` HostProfile *HostProfile `json:"hostProfile"` Membership *AgencyMembership `json:"membership"` } func (c *GRPCClient) CreateBDLeader(ctx context.Context, req CreateBDLeaderRequest) (*BDProfile, error) { resp, err := c.hostAdminClient.CreateBDLeader(ctx, &userv1.CreateBDLeaderRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), CommandId: req.CommandID, AdminUserId: req.AdminUserID, RegionId: req.RegionID, TargetUserId: req.TargetUserID, Reason: req.Reason, }) if err != nil { return nil, err } return fromProtoBDProfile(resp.GetBdProfile()), nil } func (c *GRPCClient) CreateBD(ctx context.Context, req CreateBDRequest) (*BDProfile, error) { resp, err := c.hostAdminClient.CreateBD(ctx, &userv1.CreateBDRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), CommandId: req.CommandID, AdminUserId: req.AdminUserID, TargetUserId: req.TargetUserID, ParentLeaderUserId: req.ParentLeaderUserID, Reason: req.Reason, }) if err != nil { return nil, err } return fromProtoBDProfile(resp.GetBdProfile()), nil } func (c *GRPCClient) SetBDStatus(ctx context.Context, req SetBDStatusRequest) (*BDProfile, error) { resp, err := c.hostAdminClient.SetBDStatus(ctx, &userv1.SetBDStatusRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), CommandId: req.CommandID, AdminUserId: req.AdminUserID, TargetUserId: req.TargetUserID, Status: req.Status, Reason: req.Reason, }) if err != nil { return nil, err } return fromProtoBDProfile(resp.GetBdProfile()), nil } func (c *GRPCClient) CreateCoinSeller(ctx context.Context, req CreateCoinSellerRequest) (*CoinSellerProfile, error) { resp, err := c.hostAdminClient.CreateCoinSeller(ctx, &userv1.CreateCoinSellerRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), CommandId: req.CommandID, AdminUserId: req.AdminUserID, TargetUserId: req.TargetUserID, Reason: req.Reason, }) if err != nil { return nil, err } return fromProtoCoinSellerProfile(resp.GetCoinSellerProfile()), nil } func (c *GRPCClient) SetCoinSellerStatus(ctx context.Context, req SetCoinSellerStatusRequest) (*CoinSellerProfile, error) { resp, err := c.hostAdminClient.SetCoinSellerStatus(ctx, &userv1.SetCoinSellerStatusRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), CommandId: req.CommandID, AdminUserId: req.AdminUserID, TargetUserId: req.TargetUserID, Status: req.Status, Reason: req.Reason, }) if err != nil { return nil, err } return fromProtoCoinSellerProfile(resp.GetCoinSellerProfile()), nil } func (c *GRPCClient) GetCoinSellerProfile(ctx context.Context, req GetCoinSellerProfileRequest) (*CoinSellerProfile, error) { resp, err := c.hostClient.GetCoinSellerProfile(ctx, &userv1.GetCoinSellerProfileRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), UserId: req.UserID, }) if err != nil { return nil, err } return fromProtoCoinSellerProfile(resp.GetCoinSellerProfile()), nil } func (c *GRPCClient) CreateAgency(ctx context.Context, req CreateAgencyRequest) (*CreateAgencyResult, error) { resp, err := c.hostAdminClient.CreateAgency(ctx, &userv1.CreateAgencyRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), CommandId: req.CommandID, AdminUserId: req.AdminUserID, OwnerUserId: req.OwnerUserID, ParentBdUserId: req.ParentBDUserID, Name: req.Name, JoinEnabled: req.JoinEnabled, MaxHosts: req.MaxHosts, Reason: req.Reason, }) if err != nil { return nil, err } return &CreateAgencyResult{ Agency: fromProtoAgency(resp.GetAgency()), HostProfile: fromProtoHostProfile(resp.GetHostProfile()), Membership: fromProtoAgencyMembership(resp.GetMembership()), }, nil } func (c *GRPCClient) CloseAgency(ctx context.Context, req CloseAgencyRequest) (*Agency, error) { resp, err := c.hostAdminClient.CloseAgency(ctx, &userv1.CloseAgencyRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), CommandId: req.CommandID, AdminUserId: req.AdminUserID, AgencyId: req.AgencyID, Reason: req.Reason, }) if err != nil { return nil, err } return fromProtoAgency(resp.GetAgency()), nil } func (c *GRPCClient) SetAgencyJoinEnabled(ctx context.Context, req SetAgencyJoinEnabledRequest) (*Agency, error) { resp, err := c.hostAdminClient.SetAgencyJoinEnabled(ctx, &userv1.SetAgencyJoinEnabledRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), CommandId: req.CommandID, AdminUserId: req.AdminUserID, AgencyId: req.AgencyID, JoinEnabled: req.JoinEnabled, Reason: req.Reason, }) if err != nil { return nil, err } return fromProtoAgency(resp.GetAgency()), nil } func requestMeta(ctx context.Context, requestID string, caller string) *userv1.RequestMeta { return &userv1.RequestMeta{ RequestId: requestID, Caller: caller, SentAtMs: time.Now().UnixMilli(), AppCode: appctx.FromContext(ctx), } } func fromProtoBDProfile(profile *userv1.BDProfile) *BDProfile { if profile == nil { return nil } return &BDProfile{ UserID: profile.GetUserId(), Role: profile.GetRole(), RegionID: profile.GetRegionId(), ParentLeaderUserID: profile.GetParentLeaderUserId(), Status: profile.GetStatus(), CreatedByUserID: profile.GetCreatedByUserId(), CreatedAtMs: profile.GetCreatedAtMs(), UpdatedAtMs: profile.GetUpdatedAtMs(), } } func fromProtoAgency(agency *userv1.Agency) *Agency { if agency == nil { return nil } return &Agency{ AgencyID: agency.GetAgencyId(), OwnerUserID: agency.GetOwnerUserId(), RegionID: agency.GetRegionId(), ParentBDUserID: agency.GetParentBdUserId(), Name: agency.GetName(), Status: agency.GetStatus(), JoinEnabled: agency.GetJoinEnabled(), MaxHosts: agency.GetMaxHosts(), CreatedByUserID: agency.GetCreatedByUserId(), CreatedAtMs: agency.GetCreatedAtMs(), UpdatedAtMs: agency.GetUpdatedAtMs(), } } func fromProtoHostProfile(profile *userv1.HostProfile) *HostProfile { if profile == nil { return nil } return &HostProfile{ UserID: profile.GetUserId(), Status: profile.GetStatus(), RegionID: profile.GetRegionId(), CurrentAgencyID: profile.GetCurrentAgencyId(), CurrentMembershipID: profile.GetCurrentMembershipId(), Source: profile.GetSource(), FirstBecameHostAtMs: profile.GetFirstBecameHostAtMs(), CreatedAtMs: profile.GetCreatedAtMs(), UpdatedAtMs: profile.GetUpdatedAtMs(), } } func fromProtoCoinSellerProfile(profile *userv1.CoinSellerProfile) *CoinSellerProfile { if profile == nil { return nil } return &CoinSellerProfile{ UserID: profile.GetUserId(), Status: profile.GetStatus(), MerchantAssetType: profile.GetMerchantAssetType(), CreatedByUserID: profile.GetCreatedByUserId(), CreatedAtMs: profile.GetCreatedAtMs(), UpdatedAtMs: profile.GetUpdatedAtMs(), } } func fromProtoAgencyMembership(membership *userv1.AgencyMembership) *AgencyMembership { if membership == nil { return nil } return &AgencyMembership{ MembershipID: membership.GetMembershipId(), AgencyID: membership.GetAgencyId(), HostUserID: membership.GetHostUserId(), RegionID: membership.GetRegionId(), MembershipType: membership.GetMembershipType(), Status: membership.GetStatus(), JoinedAtMs: membership.GetJoinedAtMs(), EndedAtMs: membership.GetEndedAtMs(), EndedByUserID: membership.GetEndedByUserId(), EndedReason: membership.GetEndedReason(), CreatedAtMs: membership.GetCreatedAtMs(), UpdatedAtMs: membership.GetUpdatedAtMs(), } }