271 lines
10 KiB
Go
271 lines
10 KiB
Go
package grpc
|
|
|
|
import (
|
|
"context"
|
|
|
|
activityv1 "hyapp.local/api/proto/activity/v1"
|
|
"hyapp/pkg/appcode"
|
|
"hyapp/pkg/xerr"
|
|
taskdomain "hyapp/services/activity-service/internal/domain/task"
|
|
taskservice "hyapp/services/activity-service/internal/service/task"
|
|
)
|
|
|
|
// TaskServer 把任务查询、事件消费和领奖用例适配为 activity-service gRPC。
|
|
type TaskServer struct {
|
|
activityv1.UnimplementedTaskServiceServer
|
|
|
|
svc *taskservice.Service
|
|
}
|
|
|
|
// NewTaskServer 创建 App 任务服务 gRPC adapter。
|
|
func NewTaskServer(svc *taskservice.Service) *TaskServer {
|
|
return &TaskServer{svc: svc}
|
|
}
|
|
|
|
// ListUserTasks 返回当前用户 daily/exclusive 任务页。
|
|
func (s *TaskServer) ListUserTasks(ctx context.Context, req *activityv1.ListUserTasksRequest) (*activityv1.ListUserTasksResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
result, err := s.svc.ListUserTasks(ctx, req.GetUserId())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return taskListToProto(result), nil
|
|
}
|
|
|
|
// ClaimTaskReward 领取已完成任务奖励,金币入账仍由 wallet-service 完成。
|
|
func (s *TaskServer) ClaimTaskReward(ctx context.Context, req *activityv1.ClaimTaskRewardRequest) (*activityv1.ClaimTaskRewardResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
claim, err := s.svc.ClaimTaskReward(ctx, taskdomain.ClaimCommand{
|
|
UserID: req.GetUserId(),
|
|
TaskID: req.GetTaskId(),
|
|
TaskType: req.GetTaskType(),
|
|
CycleKey: req.GetTaskDay(),
|
|
CommandID: req.GetCommandId(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return claimToProto(claim), nil
|
|
}
|
|
|
|
// ConsumeTaskEvent 消费由 outbox worker 投递的服务端事实事件。
|
|
func (s *TaskServer) ConsumeTaskEvent(ctx context.Context, req *activityv1.ConsumeTaskEventRequest) (*activityv1.ConsumeTaskEventResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
result, err := s.svc.ConsumeTaskEvent(ctx, taskdomain.Event{
|
|
EventID: req.GetEventId(),
|
|
EventType: req.GetEventType(),
|
|
SourceService: req.GetSourceService(),
|
|
UserID: req.GetUserId(),
|
|
MetricType: req.GetMetricType(),
|
|
Value: req.GetValue(),
|
|
OccurredAtMS: req.GetOccurredAtMs(),
|
|
DimensionsJSON: req.GetDimensionsJson(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &activityv1.ConsumeTaskEventResponse{
|
|
EventId: result.EventID,
|
|
Status: result.Status,
|
|
MatchedTaskCount: result.MatchedTaskCount,
|
|
}, nil
|
|
}
|
|
|
|
// AdminTaskServer 暴露后台任务配置管理入口。
|
|
type AdminTaskServer struct {
|
|
activityv1.UnimplementedAdminTaskServiceServer
|
|
|
|
svc *taskservice.Service
|
|
}
|
|
|
|
// NewAdminTaskServer 创建后台任务配置 gRPC adapter。
|
|
func NewAdminTaskServer(svc *taskservice.Service) *AdminTaskServer {
|
|
return &AdminTaskServer{svc: svc}
|
|
}
|
|
|
|
// ListTaskDefinitions 返回后台任务定义列表。
|
|
func (s *AdminTaskServer) ListTaskDefinitions(ctx context.Context, req *activityv1.ListTaskDefinitionsRequest) (*activityv1.ListTaskDefinitionsResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
items, total, err := s.svc.ListTaskDefinitions(ctx, taskdomain.DefinitionQuery{
|
|
TaskType: req.GetTaskType(),
|
|
Category: req.GetCategory(),
|
|
Status: req.GetStatus(),
|
|
Keyword: req.GetKeyword(),
|
|
Page: req.GetPage(),
|
|
PageSize: req.GetPageSize(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &activityv1.ListTaskDefinitionsResponse{Tasks: make([]*activityv1.TaskDefinition, 0, len(items)), Total: total}
|
|
for _, item := range items {
|
|
resp.Tasks = append(resp.Tasks, definitionToProto(item))
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// UpsertTaskDefinition 创建或编辑任务配置。
|
|
func (s *AdminTaskServer) UpsertTaskDefinition(ctx context.Context, req *activityv1.UpsertTaskDefinitionRequest) (*activityv1.UpsertTaskDefinitionResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
item, created, err := s.svc.UpsertTaskDefinition(ctx, taskdomain.DefinitionCommand{
|
|
TaskID: req.GetTaskId(),
|
|
TaskType: req.GetTaskType(),
|
|
Category: req.GetCategory(),
|
|
MetricType: req.GetMetricType(),
|
|
Title: req.GetTitle(),
|
|
Description: req.GetDescription(),
|
|
AudienceType: req.GetAudienceType(),
|
|
IconKey: req.GetIconKey(),
|
|
IconURL: req.GetIconUrl(),
|
|
ActionType: req.GetActionType(),
|
|
ActionParam: req.GetActionParam(),
|
|
ActionPayloadJSON: req.GetActionPayloadJson(),
|
|
DimensionFilterJSON: req.GetDimensionFilterJson(),
|
|
TargetValue: req.GetTargetValue(),
|
|
TargetUnit: req.GetTargetUnit(),
|
|
RewardCoinAmount: req.GetRewardCoinAmount(),
|
|
RewardAssetType: req.GetRewardAssetType(),
|
|
Status: req.GetStatus(),
|
|
SortOrder: req.GetSortOrder(),
|
|
EffectiveFromMS: req.GetEffectiveFromMs(),
|
|
EffectiveToMS: req.GetEffectiveToMs(),
|
|
OperatorAdminID: req.GetOperatorAdminId(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &activityv1.UpsertTaskDefinitionResponse{Task: definitionToProto(item), Created: created}, nil
|
|
}
|
|
|
|
// SetTaskDefinitionStatus 启停或归档任务。
|
|
func (s *AdminTaskServer) SetTaskDefinitionStatus(ctx context.Context, req *activityv1.SetTaskDefinitionStatusRequest) (*activityv1.SetTaskDefinitionStatusResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
item, err := s.svc.SetTaskDefinitionStatus(ctx, req.GetTaskId(), req.GetStatus(), req.GetOperatorAdminId())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &activityv1.SetTaskDefinitionStatusResponse{Task: definitionToProto(item)}, nil
|
|
}
|
|
|
|
// PublishTaskRewardPolicy 写入 policy instance 编译后的 activity 运行侧任务奖励默认资产。
|
|
func (s *AdminTaskServer) PublishTaskRewardPolicy(ctx context.Context, req *activityv1.PublishTaskRewardPolicyRequest) (*activityv1.PublishTaskRewardPolicyResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
command := taskdomain.RewardPolicyCommand{
|
|
InstanceCode: req.GetInstanceCode(),
|
|
TemplateCode: req.GetTemplateCode(),
|
|
TemplateVersion: req.GetTemplateVersion(),
|
|
Status: req.GetStatus(),
|
|
RewardAssetType: req.GetRewardAssetType(),
|
|
RuleJSON: req.GetRuleJson(),
|
|
OperatorAdminID: int64(req.GetOperatorAdminId()),
|
|
PublishedAtMS: req.GetPublishedAtMs(),
|
|
}
|
|
if err := s.svc.PublishTaskRewardPolicy(ctx, command); err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &activityv1.PublishTaskRewardPolicyResponse{
|
|
AppCode: appcode.FromContext(ctx),
|
|
InstanceCode: command.InstanceCode,
|
|
Status: command.Status,
|
|
RewardAssetType: command.RewardAssetType,
|
|
PublishedAtMs: command.PublishedAtMS,
|
|
}, nil
|
|
}
|
|
|
|
func taskListToProto(result taskdomain.ListResult) *activityv1.ListUserTasksResponse {
|
|
resp := &activityv1.ListUserTasksResponse{
|
|
Sections: make([]*activityv1.TaskSection, 0, len(result.Sections)),
|
|
ServerTimeMs: result.ServerTimeMS,
|
|
NextRefreshAtMs: result.NextRefreshAtMS,
|
|
}
|
|
for _, section := range result.Sections {
|
|
target := &activityv1.TaskSection{
|
|
Section: section.Section,
|
|
Items: make([]*activityv1.TaskItem, 0, len(section.Items)),
|
|
ServerTimeMs: section.ServerTimeMS,
|
|
NextRefreshAtMs: section.NextRefreshAtMS,
|
|
}
|
|
for _, item := range section.Items {
|
|
target.Items = append(target.Items, itemToProto(item))
|
|
}
|
|
resp.Sections = append(resp.Sections, target)
|
|
}
|
|
return resp
|
|
}
|
|
|
|
func itemToProto(item taskdomain.Item) *activityv1.TaskItem {
|
|
return &activityv1.TaskItem{
|
|
TaskId: item.TaskID,
|
|
TaskType: item.TaskType,
|
|
Category: item.Category,
|
|
MetricType: item.MetricType,
|
|
Title: item.Title,
|
|
Description: item.Description,
|
|
AudienceType: item.AudienceType,
|
|
IconKey: item.IconKey,
|
|
IconUrl: item.IconURL,
|
|
ActionType: item.ActionType,
|
|
ActionParam: item.ActionParam,
|
|
ActionPayloadJson: item.ActionPayloadJSON,
|
|
DimensionFilterJson: item.DimensionFilterJSON,
|
|
TargetValue: item.TargetValue,
|
|
TargetUnit: item.TargetUnit,
|
|
ProgressValue: item.ProgressValue,
|
|
RewardCoinAmount: item.RewardCoinAmount,
|
|
RewardAssetType: item.RewardAssetType,
|
|
Status: item.UserStatus,
|
|
Claimable: item.Claimable,
|
|
TaskDay: item.TaskDay,
|
|
ServerTimeMs: item.ServerTimeMS,
|
|
NextRefreshAtMs: item.NextRefreshAtMS,
|
|
SortOrder: item.SortOrder,
|
|
Version: item.Version,
|
|
}
|
|
}
|
|
|
|
func claimToProto(claim taskdomain.Claim) *activityv1.ClaimTaskRewardResponse {
|
|
return &activityv1.ClaimTaskRewardResponse{
|
|
ClaimId: claim.ClaimID,
|
|
TaskId: claim.TaskID,
|
|
TaskType: claim.TaskType,
|
|
TaskDay: claim.CycleKey,
|
|
RewardCoinAmount: claim.RewardCoinAmount,
|
|
RewardAssetType: claim.RewardAssetType,
|
|
Status: claim.Status,
|
|
WalletTransactionId: claim.WalletTransactionID,
|
|
GrantedAtMs: claim.UpdatedAtMS,
|
|
Claimed: claim.Status == taskdomain.ClaimStatusGranted,
|
|
}
|
|
}
|
|
|
|
func definitionToProto(item taskdomain.Definition) *activityv1.TaskDefinition {
|
|
return &activityv1.TaskDefinition{
|
|
TaskId: item.TaskID,
|
|
TaskType: item.TaskType,
|
|
Category: item.Category,
|
|
MetricType: item.MetricType,
|
|
Title: item.Title,
|
|
Description: item.Description,
|
|
AudienceType: item.AudienceType,
|
|
IconKey: item.IconKey,
|
|
IconUrl: item.IconURL,
|
|
ActionType: item.ActionType,
|
|
ActionParam: item.ActionParam,
|
|
ActionPayloadJson: item.ActionPayloadJSON,
|
|
DimensionFilterJson: item.DimensionFilterJSON,
|
|
TargetValue: item.TargetValue,
|
|
TargetUnit: item.TargetUnit,
|
|
RewardCoinAmount: item.RewardCoinAmount,
|
|
RewardAssetType: item.RewardAssetType,
|
|
Status: item.Status,
|
|
SortOrder: item.SortOrder,
|
|
Version: item.Version,
|
|
EffectiveFromMs: item.EffectiveFromMS,
|
|
EffectiveToMs: item.EffectiveToMS,
|
|
CreatedByAdminId: item.CreatedByAdminID,
|
|
UpdatedByAdminId: item.UpdatedByAdminID,
|
|
CreatedAtMs: item.CreatedAtMS,
|
|
UpdatedAtMs: item.UpdatedAtMS,
|
|
}
|
|
}
|