修复幸运礼物和系统推送
This commit is contained in:
parent
4396f34b3b
commit
1fd196094d
@ -88,5 +88,14 @@ public class SysPushRecordLogQryCmd extends PageCommand {
|
|||||||
*/
|
*/
|
||||||
private Integer successQuantity;
|
private Integer successQuantity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间.
|
||||||
|
*/
|
||||||
|
private Long startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束时间.
|
||||||
|
*/
|
||||||
|
private Long endTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
package com.red.circle.other.inner.model.cmd.sys;
|
package com.red.circle.other.inner.model.cmd.sys;
|
||||||
|
|
||||||
|
import com.red.circle.framework.core.dto.PageCommand;
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,8 +15,9 @@ import lombok.experimental.Accessors;
|
|||||||
* @since 2022-10-20
|
* @since 2022-10-20
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class SysPushTaskQryCmd implements Serializable {
|
public class SysPushTaskQryCmd extends PageCommand {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|||||||
@ -1,9 +1,22 @@
|
|||||||
package com.red.circle.console.adapter.app.sys;
|
package com.red.circle.console.adapter.app.sys;
|
||||||
|
|
||||||
|
import com.red.circle.console.app.dto.clienobject.sys.SysPushRecordLogCO;
|
||||||
|
import com.red.circle.console.app.dto.clienobject.sys.SysPushTaskCO;
|
||||||
import com.red.circle.console.app.service.app.sys.SysPushService;
|
import com.red.circle.console.app.service.app.sys.SysPushService;
|
||||||
|
import com.red.circle.console.infra.annotations.OpsOperationReqLog;
|
||||||
|
import com.red.circle.framework.dto.PageResult;
|
||||||
import com.red.circle.framework.web.controller.BaseController;
|
import com.red.circle.framework.web.controller.BaseController;
|
||||||
|
import com.red.circle.other.inner.model.cmd.sys.CreateRecordCmd;
|
||||||
|
import com.red.circle.other.inner.model.cmd.sys.SysPushRecordLogQryCmd;
|
||||||
|
import com.red.circle.other.inner.model.cmd.sys.SysPushTaskCmd;
|
||||||
|
import com.red.circle.other.inner.model.cmd.sys.SysPushTaskQryCmd;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@ -13,16 +26,17 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
* @author pengliang
|
* @author pengliang
|
||||||
* @since 2020-02-07
|
* @since 2020-02-07
|
||||||
*/
|
*/
|
||||||
|
@Validated
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(value = "/push", produces = MediaType.APPLICATION_JSON_VALUE)
|
@RequestMapping(value = "/push", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public class PushRestController extends BaseController {
|
public class PushRestController extends BaseController {
|
||||||
|
|
||||||
private final SysPushService sysPushService;
|
private final SysPushService sysPushService;
|
||||||
/*
|
|
||||||
*//**
|
/**
|
||||||
* 后台推送分页列表.
|
* 后台推送分页列表.
|
||||||
*//*
|
*/
|
||||||
@GetMapping("/page")
|
@GetMapping("/page")
|
||||||
public PageResult<SysPushRecordLogCO> pageSysPushBack(SysPushRecordLogQryCmd query) {
|
public PageResult<SysPushRecordLogCO> pageSysPushBack(SysPushRecordLogQryCmd query) {
|
||||||
return sysPushService.pageLogs(query);
|
return sysPushService.pageLogs(query);
|
||||||
@ -32,9 +46,6 @@ public class PushRestController extends BaseController {
|
|||||||
@PostMapping
|
@PostMapping
|
||||||
public void saveAndPush(@RequestBody CreateRecordCmd param) {
|
public void saveAndPush(@RequestBody CreateRecordCmd param) {
|
||||||
param.setCreateUser(param.getReqUserId());
|
param.setCreateUser(param.getReqUserId());
|
||||||
// 设置代理,上线去除
|
|
||||||
// System.setProperty("proxyHost", "localhost");
|
|
||||||
// System.setProperty("proxyPort", "10809");
|
|
||||||
sysPushService.create(param);
|
sysPushService.create(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,21 +56,20 @@ public class PushRestController extends BaseController {
|
|||||||
sysPushService.saveTask(param);
|
sysPushService.saveTask(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
*//**
|
/**
|
||||||
* 定时推送任务列表.
|
* 定时推送任务列表.
|
||||||
*//*
|
*/
|
||||||
@GetMapping("/task/page")
|
@GetMapping("/task/page")
|
||||||
public PageResult<SysPushTaskCO> pageTask(SysPushTaskQryCmd query) {
|
public PageResult<SysPushTaskCO> pageTask(SysPushTaskQryCmd query) {
|
||||||
return sysPushService.pageTask(query);
|
return sysPushService.pageTask(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
*//**
|
/**
|
||||||
* 定时推送任务列表.
|
* 删除定时推送任务.
|
||||||
*//*
|
*/
|
||||||
@GetMapping("/task/delete/{id}")
|
@GetMapping("/task/delete/{id}")
|
||||||
public void deletePushTask(@PathVariable("id") Long id) {
|
public void deletePushTask(@PathVariable("id") Long id) {
|
||||||
sysPushService.deletePushTask(id);
|
sysPushService.deletePushTask(id);
|
||||||
|
}
|
||||||
}*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,44 +1,102 @@
|
|||||||
package com.red.circle.console.app.service.app.sys;
|
package com.red.circle.console.app.service.app.sys;
|
||||||
|
|
||||||
|
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||||
|
import com.red.circle.console.app.dto.clienobject.sys.SysPushRecordLogCO;
|
||||||
|
import com.red.circle.console.app.dto.clienobject.sys.SysPushTaskCO;
|
||||||
|
import com.red.circle.console.infra.database.rds.entity.sys.SysPushRecordLog;
|
||||||
import com.red.circle.console.infra.database.rds.service.admin.UserService;
|
import com.red.circle.console.infra.database.rds.service.admin.UserService;
|
||||||
|
import com.red.circle.console.infra.database.rds.service.sys.SysPushRecordLogService;
|
||||||
|
import com.red.circle.external.inner.endpoint.push.GoogleFirebasePushClient;
|
||||||
|
import com.red.circle.external.inner.model.cmd.message.google.GooglePushCmd;
|
||||||
|
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||||
|
import com.red.circle.framework.core.dto.PageCommand;
|
||||||
|
import com.red.circle.framework.core.response.CommonErrorCode;
|
||||||
|
import com.red.circle.framework.core.response.ResponseErrorCode;
|
||||||
|
import com.red.circle.framework.dto.PageQuery;
|
||||||
|
import com.red.circle.framework.dto.PageResult;
|
||||||
|
import com.red.circle.other.inner.endpoint.user.device.RegisterDeviceClient;
|
||||||
|
import com.red.circle.other.inner.enums.sys.MessageBusinessSceneEnum;
|
||||||
|
import com.red.circle.other.inner.model.cmd.sys.CreateRecordCmd;
|
||||||
|
import com.red.circle.other.inner.model.cmd.sys.SysPushRecordLogQryCmd;
|
||||||
|
import com.red.circle.other.inner.model.cmd.sys.SysPushTaskCmd;
|
||||||
|
import com.red.circle.other.inner.model.cmd.sys.SysPushTaskQryCmd;
|
||||||
|
import com.red.circle.other.inner.model.cmd.user.device.PageLatestMobileDeviceQryCmd;
|
||||||
|
import com.red.circle.other.inner.model.dto.user.UserLatestMobileDeviceHistoryDTO;
|
||||||
|
import com.red.circle.tool.core.collection.CollectionUtils;
|
||||||
|
import com.red.circle.tool.core.date.TimestampUtils;
|
||||||
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author pengliang
|
* 后台 Push 服务.
|
||||||
* @since 2020/3/6 15:53
|
*
|
||||||
|
* <p>旧的推送实现已经失效,这里按当前可用的设备查询与推送客户端重建最小闭环:
|
||||||
|
* 发送 Push、记录 Push 日志、为未迁移的定时任务返回明确的不可用状态。</p>
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Service
|
@Service
|
||||||
public class SysPushServiceImpl implements SysPushService {
|
public class SysPushServiceImpl implements SysPushService {
|
||||||
|
|
||||||
|
private static final int DEFAULT_PAGE_LIMIT = 20;
|
||||||
|
private static final int DEVICE_PAGE_LIMIT = 500;
|
||||||
|
private static final String PUSH_ORIGIN_BACK = "BACK";
|
||||||
|
private static final String PUSH_STATUS_SUCCESS = "SUCCESS";
|
||||||
|
private static final String PUSH_STATUS_FAIL = "FAIL";
|
||||||
|
private static final Set<String> PUSH_FAIL_STATUSES = Set.of(
|
||||||
|
"UNKNOWN",
|
||||||
|
PUSH_STATUS_FAIL,
|
||||||
|
"IOS_FAIL",
|
||||||
|
"ANDROID_FAIL");
|
||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
/*private final ISysPushTaskService sysPushTaskService;
|
private final RegisterDeviceClient registerDeviceClient;
|
||||||
private final IUserBaseInfoService userBaseInfoService;
|
private final GoogleFirebasePushClient googleFirebasePushClient;
|
||||||
private final ISysPushRecordLogService sysPushRecordLogService;
|
private final SysPushRecordLogService sysPushRecordLogService;
|
||||||
private final GoogleFirebasePushService googleFirebasePushService;
|
|
||||||
private final ISysPushUserRecordLogService sysPushUserRecordLogService;
|
|
||||||
private final IUserLatestMobileDeviceService userLatestMobileDeviceService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void create(CreateRecordCmd createRecordParam) {
|
public void create(CreateRecordCmd createRecordParam) {
|
||||||
|
validateCreateParam(createRecordParam);
|
||||||
|
|
||||||
if (StringUtils.isBlank(createRecordParam.getSysOrigin())) {
|
List<UserLatestMobileDeviceHistoryDTO> targetDevices = listTargetDevices(createRecordParam);
|
||||||
return;
|
if (CollectionUtils.isEmpty(targetDevices)) {
|
||||||
|
ResponseAssert.failure(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||||
|
"No matching push devices.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (createRecordParam.isGoogleDevice()) {
|
SysPushRecordLog pushLog = buildPushLog(createRecordParam);
|
||||||
|
try {
|
||||||
pushGoogle(createRecordParam);
|
pushGoogle(createRecordParam, targetDevices);
|
||||||
|
pushLog.setPushStatus(PUSH_STATUS_SUCCESS);
|
||||||
|
pushLog.setSuccessQuantity(targetDevices.size());
|
||||||
|
pushLog.setFailQuantity(0);
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
pushLog.setPushStatus(PUSH_STATUS_FAIL);
|
||||||
|
pushLog.setSuccessQuantity(0);
|
||||||
|
pushLog.setFailQuantity(targetDevices.size());
|
||||||
|
log.warn("Push broadcast failed, sysOrigin={}, title={}", createRecordParam.getSysOrigin(),
|
||||||
|
createRecordParam.getTitle(), ex);
|
||||||
|
throw ex;
|
||||||
|
} finally {
|
||||||
|
ResponseAssert.isTrue(CommonErrorCode.OPERATING_FAILURE, !sysPushRecordLogService.save(pushLog));
|
||||||
|
createRecordParam.setId(pushLog.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<SysPushRecordLogCO> pageLogs(SysPushRecordLogQryCmd query) {
|
public PageResult<SysPushRecordLogCO> pageLogs(SysPushRecordLogQryCmd query) {
|
||||||
|
PageResult<SysPushRecordLog> page = sysPushRecordLogService.query()
|
||||||
IPage<SysPushRecordLog> sysPushRecordLogPage = sysPushRecordLogService.query()
|
|
||||||
.eq(StringUtils.isNotBlank(query.getBusinessScene()), SysPushRecordLog::getBusinessScene,
|
.eq(StringUtils.isNotBlank(query.getBusinessScene()), SysPushRecordLog::getBusinessScene,
|
||||||
query.getBusinessScene())
|
query.getBusinessScene())
|
||||||
.eq(StringUtils.isNotBlank(query.getPlatform()), SysPushRecordLog::getPlatform,
|
.eq(StringUtils.isNotBlank(query.getPlatform()), SysPushRecordLog::getPlatform,
|
||||||
@ -47,209 +105,315 @@ public class SysPushServiceImpl implements SysPushService {
|
|||||||
query.getDeviceType())
|
query.getDeviceType())
|
||||||
.eq(StringUtils.isNotBlank(query.getSysOrigin()), SysPushRecordLog::getSysOrigin,
|
.eq(StringUtils.isNotBlank(query.getSysOrigin()), SysPushRecordLog::getSysOrigin,
|
||||||
query.getSysOrigin())
|
query.getSysOrigin())
|
||||||
.ge(Objects.nonNull(query.getStartCreateDate()), SysPushRecordLog::getCreateTime,
|
.ge(Objects.nonNull(query.getStartTime()), SysPushRecordLog::getCreateTime,
|
||||||
query.getStartCreateDate())
|
new Timestamp(query.getStartTime()))
|
||||||
.le(Objects.nonNull(query.getEndCreateDate()), SysPushRecordLog::getCreateTime,
|
.le(Objects.nonNull(query.getEndTime()), SysPushRecordLog::getCreateTime,
|
||||||
query.getEndCreateDate())
|
new Timestamp(query.getEndTime()))
|
||||||
.eq(Objects.nonNull(query.getPushStatus()) && query.isSuccess(),
|
.eq(isSuccessStatusQuery(query.getPushStatus()), SysPushRecordLog::getPushStatus,
|
||||||
SysPushRecordLog::getPushStatus, ResultStatusEnum.SUCCESS)
|
PUSH_STATUS_SUCCESS)
|
||||||
.in(Objects.nonNull(query.getPushStatus()) && !query.isSuccess(),
|
.in(isFailStatusQuery(query.getPushStatus()), SysPushRecordLog::getPushStatus,
|
||||||
SysPushRecordLog::getPushStatus, ResultStatusEnum.getFailKeys())
|
PUSH_FAIL_STATUSES)
|
||||||
.orderByDesc(SysPushRecordLog::getId)
|
.orderByDesc(SysPushRecordLog::getId)
|
||||||
.page(query);
|
.page(ensurePageQuery(query));
|
||||||
|
|
||||||
if (CollectionUtil.isEmpty(sysPushRecordLogPage.getRecords())) {
|
if (CollectionUtils.isEmpty(page.getRecords())) {
|
||||||
return sysPushRecordLogPage
|
return page.convert(this::toPushLogCO);
|
||||||
.convert(sysPushRecordLog -> sysPushRecordLog.convert(SysPushRecordLogCO.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Long, User> userMap = userService.mapBackUser(getBackUserIds(sysPushRecordLogPage));
|
Map<Long, String> sendUserNameMap = userService.mapBackUserNickname(
|
||||||
Map<Long, UserBaseInfo> userBaseInfoMap = userBaseInfoService
|
page.getRecords().stream()
|
||||||
.mapByIds(getAppUserIds(sysPushRecordLogPage));
|
.map(SysPushRecordLog::getCreateUser)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toSet()));
|
||||||
|
|
||||||
return sysPushRecordLogPage.convert(sysPushRecordLog -> {
|
return page.convert(record -> toPushLogCO(record, sendUserNameMap));
|
||||||
SysPushRecordLogCO sysPushRecordLogVO = sysPushRecordLog.convert(SysPushRecordLogCO.class);
|
|
||||||
sysPushRecordLogVO
|
|
||||||
.setBusinessScene(MessageBusinessSceneEnum.getDesc(sysPushRecordLog.getBusinessScene()));
|
|
||||||
sysPushRecordLogVO.setPushStatus(ResultStatusEnum.getDesc(sysPushRecordLog.getPushStatus()));
|
|
||||||
|
|
||||||
if (PushOriginEnum.isBack(sysPushRecordLog.getOrigin())) {
|
|
||||||
User user = userMap.get(sysPushRecordLog.getCreateUser());
|
|
||||||
if (Objects.nonNull(user)) {
|
|
||||||
sysPushRecordLogVO.setSendUserName(user.getNickname());
|
|
||||||
}
|
|
||||||
return sysPushRecordLogVO;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserBaseInfo userBaseInfo = userBaseInfoMap.get(sysPushRecordLog.getCreateUser());
|
|
||||||
if (Objects.nonNull(userBaseInfo)) {
|
|
||||||
sysPushRecordLogVO.setSendUserName(userBaseInfo.getUserNickname());
|
|
||||||
}
|
|
||||||
return sysPushRecordLogVO;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<SysPushTaskCO> pageTask(SysPushTaskQryCmd query) {
|
public PageResult<SysPushTaskCO> pageTask(SysPushTaskQryCmd query) {
|
||||||
return sysPushTaskService.pageTask(query);
|
return PageResult.newPageResult(resolvePageLimit(ensurePageQuery(query)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveTask(SysPushTaskCmd param) {
|
public void saveTask(SysPushTaskCmd param) {
|
||||||
sysPushTaskService.saveTask(param);
|
ResponseAssert.failure(CommonErrorCode.API_DEPRECATED,
|
||||||
|
"Push task is not available in the migrated admin yet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deletePushTask(Long id) {
|
public void deletePushTask(Long id) {
|
||||||
sysPushTaskService.deletePushTask(id);
|
ResponseAssert.failure(CommonErrorCode.API_DEPRECATED,
|
||||||
|
"Push task is not available in the migrated admin yet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Long> getBackUserIds(PageResult<SysPushRecordLogCO> sysPushRecordLogPage) {
|
private void validateCreateParam(CreateRecordCmd createRecordParam) {
|
||||||
return sysPushRecordLogPage.getRecords().stream().filter(sysPushRecordLog ->
|
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR, createRecordParam.getTitle());
|
||||||
PushOriginEnum.isBack(sysPushRecordLog.getOrigin()) && sysPushRecordLog.getCreateUser() > 0
|
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||||
).map(SysPushRecordLog::getCreateUser).collect(Collectors.toList());
|
createRecordParam.getContent());
|
||||||
|
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||||
|
createRecordParam.getSysOrigin());
|
||||||
|
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||||
|
createRecordParam.getDeviceType());
|
||||||
|
ResponseAssert.notNull(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||||
|
SysOriginPlatformEnum.toEnum(createRecordParam.getSysOrigin()));
|
||||||
|
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||||
|
!createRecordParam.isGoogleDevice());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<Long> getAppUserIds(IPage<SysPushRecordLog> sysPushRecordLogPage) {
|
private void pushGoogle(CreateRecordCmd createRecordParam,
|
||||||
return sysPushRecordLogPage.getRecords().stream().filter(sysPushRecordLog ->
|
List<UserLatestMobileDeviceHistoryDTO> targetDevices) {
|
||||||
PushOriginEnum.isApp(sysPushRecordLog.getOrigin()) && sysPushRecordLog.getCreateUser() > 0
|
GooglePushCmd pushCmd = new GooglePushCmd()
|
||||||
).map(SysPushRecordLog::getCreateUser).collect(Collectors.toSet());
|
.setSysOrigin(SysOriginPlatformEnum.toEnum(createRecordParam.getSysOrigin()))
|
||||||
}
|
.setTitle(createRecordParam.getTitle())
|
||||||
|
.setBody(createRecordParam.getContent());
|
||||||
|
|
||||||
|
for (UserLatestMobileDeviceHistoryDTO device : targetDevices) {
|
||||||
*//**
|
if (isIosPlatform(device.getRequestClient())) {
|
||||||
* 推送谷歌
|
pushCmd.addIosDevice(device.getDeviceId());
|
||||||
*//*
|
|
||||||
private void pushGoogle(CreateRecordCmd createRecordParam) {
|
|
||||||
|
|
||||||
List<UserLatestMobileDevicePushDTO> users = userLatestMobileDeviceService
|
|
||||||
.listPushUserByCondition(createRecordParam);
|
|
||||||
|
|
||||||
if (CollectionUtils.isEmpty(users)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadPoolManager.getInstance().execute("pushGoogle", () -> {
|
|
||||||
|
|
||||||
List<String> deviceIds = users.stream().map(UserLatestMobileDevicePushDTO::getDeviceId)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
//推送并处理结果
|
|
||||||
processPush(createRecordParam, users, googleFirebasePushService.sendMulticast(
|
|
||||||
PushParam.builder()
|
|
||||||
.sysOrigin(SysOriginPlatformEnum.valueOf(createRecordParam.getSysOrigin()))
|
|
||||||
.androidDevices(deviceIds)
|
|
||||||
.title(createRecordParam.getTitle())
|
|
||||||
.body(createRecordParam.getContent())
|
|
||||||
.build()
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processPush(CreateRecordCmd createRecordParam,
|
|
||||||
List<UserLatestMobileDevicePushDTO> users,
|
|
||||||
FirebaseResponses responses) {
|
|
||||||
|
|
||||||
if (Objects.isNull(responses) || Objects.equals(responses.getFailCount(), users.size())) {
|
|
||||||
//全部失败
|
|
||||||
allPushFail(createRecordParam, users);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
createRecordParam.setPushStatus(ResultStatusEnum.SUCCESS.name());
|
|
||||||
createRecordParam.setFailQuantity(responses.getFailCount());
|
|
||||||
createRecordParam.setSuccessQuantity(responses.getSuccessCount());
|
|
||||||
addPushLog(createRecordParam);
|
|
||||||
//处理成功或失败
|
|
||||||
processPushResult(createRecordParam.getId(), users, responses);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processPushResult(Long pushId, List<UserLatestMobileDevicePushDTO> users,
|
|
||||||
FirebaseResponses responses) {
|
|
||||||
|
|
||||||
List<String> successTokens = responses.getSuccessDevicesString();
|
|
||||||
List<String> failTokens = responses.getFailDevicesString();
|
|
||||||
|
|
||||||
List<SysPushUserRecordLog> saveData = Lists.newArrayList();
|
|
||||||
Timestamp date = TimestampUtils.now();
|
|
||||||
|
|
||||||
for (UserLatestMobileDevicePushDTO user : users) {
|
|
||||||
|
|
||||||
SysPushUserRecordLog pushUserRecord = new SysPushUserRecordLog();
|
|
||||||
pushUserRecord.setId(IdWorkerUtils.getId());
|
|
||||||
pushUserRecord.setPushId(pushId);
|
|
||||||
pushUserRecord.setPushToken(user.getDeviceId());
|
|
||||||
pushUserRecord.setUserId(user.getUserId());
|
|
||||||
pushUserRecord.setCreateTime(date);
|
|
||||||
pushUserRecord.setUpdateTime(date);
|
|
||||||
|
|
||||||
Boolean isSuccess = isSuccess(successTokens, failTokens, user);
|
|
||||||
if (Objects.isNull(isSuccess)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
pushCmd.addAndroidDevice(device.getDeviceId());
|
||||||
pushUserRecord.setSuccess(isSuccess);
|
|
||||||
saveData.add(pushUserRecord);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<List<SysPushUserRecordLog>> logList = Lists.partition(saveData, 200);
|
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||||
logList.forEach(sysPushUserRecordLogService::saveBatch);
|
!pushCmd.isNotEmptyAndroidDevices() && !pushCmd.isNotEmptyIosDevices());
|
||||||
|
ResponseAssert.checkSuccess(googleFirebasePushClient.broadcast(pushCmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Boolean isSuccess(List<String> successTokens, List<String> failTokens,
|
private List<UserLatestMobileDeviceHistoryDTO> listTargetDevices(CreateRecordCmd createRecordParam) {
|
||||||
UserLatestMobileDevicePushDTO user) {
|
List<UserLatestMobileDeviceHistoryDTO> devices = createRecordParam.isFixedUserIdSend()
|
||||||
|
? listFixedTargetDevices(createRecordParam)
|
||||||
|
: listBroadcastTargetDevices(createRecordParam);
|
||||||
|
return distinctByDeviceId(devices);
|
||||||
|
}
|
||||||
|
|
||||||
for (String successToken : successTokens) {
|
private List<UserLatestMobileDeviceHistoryDTO> listFixedTargetDevices(
|
||||||
if (Objects.equals(user.getDeviceId(), successToken)) {
|
CreateRecordCmd createRecordParam) {
|
||||||
return Boolean.TRUE;
|
List<Long> fixedUserIds = createRecordParam.getQualifiedFixedUserIdList();
|
||||||
|
if (CollectionUtils.isEmpty(fixedUserIds)) {
|
||||||
|
return CollectionUtils.newArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<UserLatestMobileDeviceHistoryDTO> devices = new ArrayList<>(fixedUserIds.size());
|
||||||
|
for (Long userId : fixedUserIds) {
|
||||||
|
PageLatestMobileDeviceQryCmd query = buildDeviceQuery(createRecordParam);
|
||||||
|
query.setUserId(userId);
|
||||||
|
PageResult<UserLatestMobileDeviceHistoryDTO> page = ResponseAssert.requiredSuccess(
|
||||||
|
registerDeviceClient.pageLatestMobileDevice(query));
|
||||||
|
if (CollectionUtils.isEmpty(page.getRecords())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
UserLatestMobileDeviceHistoryDTO latestDevice = page.getRecords().iterator().next();
|
||||||
|
if (matchesDevice(latestDevice, createRecordParam, true)) {
|
||||||
|
devices.add(latestDevice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
for (String failToken : failTokens) {
|
private List<UserLatestMobileDeviceHistoryDTO> listBroadcastTargetDevices(
|
||||||
if (Objects.equals(user.getDeviceId(), failToken)) {
|
CreateRecordCmd createRecordParam) {
|
||||||
return Boolean.FALSE;
|
List<UserLatestMobileDeviceHistoryDTO> devices = new ArrayList<>();
|
||||||
|
PageLatestMobileDeviceQryCmd query = buildDeviceQuery(createRecordParam);
|
||||||
|
PageQuery pageQuery = query.getPageQuery();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
PageResult<UserLatestMobileDeviceHistoryDTO> page = ResponseAssert.requiredSuccess(
|
||||||
|
registerDeviceClient.pageLatestMobileDevice(query));
|
||||||
|
Collection<UserLatestMobileDeviceHistoryDTO> records = page.getRecords();
|
||||||
|
if (CollectionUtils.isEmpty(records)) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
records.stream()
|
||||||
|
.filter(device -> matchesDevice(device, createRecordParam, false))
|
||||||
|
.forEach(devices::add);
|
||||||
|
|
||||||
|
if (records.size() < resolvePageLimit(pageQuery)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pageQuery.setCursor(pageQuery.getCursor() + 1);
|
||||||
|
}
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PageLatestMobileDeviceQryCmd buildDeviceQuery(CreateRecordCmd createRecordParam) {
|
||||||
|
PageLatestMobileDeviceQryCmd query = new PageLatestMobileDeviceQryCmd();
|
||||||
|
query.setSysOrigin(createRecordParam.getSysOrigin());
|
||||||
|
PageQuery pageQuery = new PageQuery();
|
||||||
|
pageQuery.setCursor(1);
|
||||||
|
pageQuery.setLimit(DEVICE_PAGE_LIMIT);
|
||||||
|
query.setPageQuery(pageQuery);
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<UserLatestMobileDeviceHistoryDTO> distinctByDeviceId(
|
||||||
|
List<UserLatestMobileDeviceHistoryDTO> devices) {
|
||||||
|
if (CollectionUtils.isEmpty(devices)) {
|
||||||
|
return CollectionUtils.newArrayList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
Map<String, UserLatestMobileDeviceHistoryDTO> distinctMap = new LinkedHashMap<>();
|
||||||
|
for (UserLatestMobileDeviceHistoryDTO device : devices) {
|
||||||
|
if (Objects.isNull(device) || StringUtils.isBlank(device.getDeviceId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
distinctMap.putIfAbsent(device.getDeviceId(), device);
|
||||||
|
}
|
||||||
|
return new ArrayList<>(distinctMap.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void allPushFail(CreateRecordCmd createRecordParam,
|
private boolean matchesDevice(UserLatestMobileDeviceHistoryDTO device,
|
||||||
List<UserLatestMobileDevicePushDTO> users) {
|
CreateRecordCmd createRecordParam, boolean ignoreLanguage) {
|
||||||
|
if (Objects.isNull(device) || StringUtils.isBlank(device.getDeviceId())) {
|
||||||
createRecordParam.setPushStatus(ResultStatusEnum.FAIL.name());
|
return false;
|
||||||
createRecordParam.setFailQuantity(users.size());
|
}
|
||||||
createRecordParam.setSuccessQuantity(0);
|
if (StringUtils.isNotBlank(createRecordParam.getDeviceType())
|
||||||
addPushLog(createRecordParam);
|
&& !equalsIgnoreCase(createRecordParam.getDeviceType(), device.getDeviceType())) {
|
||||||
|
return false;
|
||||||
Timestamp date = TimestampUtils.now();
|
}
|
||||||
|
if (StringUtils.isNotBlank(createRecordParam.getPlatform())
|
||||||
List<SysPushUserRecordLog> logs = users.stream().map(user -> {
|
&& !isSamePlatform(createRecordParam.getPlatform(), device.getRequestClient())) {
|
||||||
|
return false;
|
||||||
SysPushUserRecordLog pushUserRecord = new SysPushUserRecordLog();
|
}
|
||||||
pushUserRecord.setPushId(createRecordParam.getId());
|
return ignoreLanguage || StringUtils.isBlank(createRecordParam.getLanguage())
|
||||||
pushUserRecord.setPushToken(user.getDeviceId());
|
|| equalsIgnoreCase(createRecordParam.getLanguage(), device.getLanguage());
|
||||||
pushUserRecord.setUserId(user.getUserId());
|
|
||||||
pushUserRecord.setSuccess(Boolean.FALSE);
|
|
||||||
pushUserRecord.setCreateTime(date);
|
|
||||||
pushUserRecord.setUpdateTime(date);
|
|
||||||
pushUserRecord.setCreateUser(createRecordParam.getCreateUser());
|
|
||||||
return pushUserRecord;
|
|
||||||
|
|
||||||
}).collect(Collectors.toList());
|
|
||||||
|
|
||||||
List<List<SysPushUserRecordLog>> logList = Lists.partition(logs, 200);
|
|
||||||
logList.forEach(sysPushUserRecordLogService::saveBatch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPushLog(CreateRecordCmd newPushDTO) {
|
private boolean isSuccessStatusQuery(String pushStatus) {
|
||||||
SysPushRecordLog sysPushRecordLog = newPushDTO.convert(SysPushRecordLog.class);
|
String normalized = normalizeStatusQuery(pushStatus);
|
||||||
sysPushRecordLog.setOrigin(PushOriginEnum.BACK.name());
|
return Objects.equals(normalized, "0") || Objects.equals(normalized,
|
||||||
sysPushRecordLogService.save(sysPushRecordLog);
|
PUSH_STATUS_SUCCESS);
|
||||||
newPushDTO.setId(sysPushRecordLog.getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
private boolean isFailStatusQuery(String pushStatus) {
|
||||||
|
String normalized = normalizeStatusQuery(pushStatus);
|
||||||
|
return Objects.equals(normalized, "1")
|
||||||
|
|| (StringUtils.isNotBlank(normalized) && !Objects.equals(normalized,
|
||||||
|
PUSH_STATUS_SUCCESS));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeStatusQuery(String pushStatus) {
|
||||||
|
if (StringUtils.isBlank(pushStatus)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String normalized = pushStatus.trim();
|
||||||
|
if (Objects.equals(normalized, "0")) {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
if (Objects.equals(normalized, "1")) {
|
||||||
|
return "1";
|
||||||
|
}
|
||||||
|
return normalized.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSamePlatform(String expected, String actual) {
|
||||||
|
return Objects.equals(normalizePlatform(expected), normalizePlatform(actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIosPlatform(String platform) {
|
||||||
|
return Objects.equals(normalizePlatform(platform), "ios");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizePlatform(String platform) {
|
||||||
|
if (StringUtils.isBlank(platform)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String normalized = platform.trim().toLowerCase();
|
||||||
|
if (Objects.equals(normalized, "ios")) {
|
||||||
|
return "ios";
|
||||||
|
}
|
||||||
|
if (Objects.equals(normalized, "android")) {
|
||||||
|
return "android";
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean equalsIgnoreCase(String left, String right) {
|
||||||
|
if (StringUtils.isBlank(left) || StringUtils.isBlank(right)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Objects.equals(left.trim().toUpperCase(), right.trim().toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
private SysPushRecordLog buildPushLog(CreateRecordCmd createRecordParam) {
|
||||||
|
Timestamp now = TimestampUtils.now();
|
||||||
|
SysPushRecordLog pushLog = new SysPushRecordLog();
|
||||||
|
pushLog.setTitle(createRecordParam.getTitle());
|
||||||
|
pushLog.setContent(createRecordParam.getContent());
|
||||||
|
pushLog.setPlatform(createRecordParam.getPlatform());
|
||||||
|
pushLog.setSysOrigin(createRecordParam.getSysOrigin());
|
||||||
|
pushLog.setBusinessScene(createRecordParam.getBusinessScene());
|
||||||
|
pushLog.setDeviceType(createRecordParam.getDeviceType());
|
||||||
|
pushLog.setFixedUserIds(createRecordParam.getFixedUserIds());
|
||||||
|
pushLog.setLink(createRecordParam.getLink());
|
||||||
|
pushLog.setOrigin(PUSH_ORIGIN_BACK);
|
||||||
|
pushLog.setCreateUser(createRecordParam.getCreateUser());
|
||||||
|
pushLog.setUpdateUser(createRecordParam.getCreateUser());
|
||||||
|
pushLog.setCreateTime(now);
|
||||||
|
pushLog.setUpdateTime(now);
|
||||||
|
return pushLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SysPushRecordLogCO toPushLogCO(SysPushRecordLog record) {
|
||||||
|
return toPushLogCO(record, CollectionUtils.newHashMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
private SysPushRecordLogCO toPushLogCO(SysPushRecordLog record, Map<Long, String> sendUserNameMap) {
|
||||||
|
SysPushRecordLogCO result = new SysPushRecordLogCO();
|
||||||
|
result.setId(record.getId());
|
||||||
|
result.setTitle(record.getTitle());
|
||||||
|
result.setContent(record.getContent());
|
||||||
|
result.setSysOrigin(record.getSysOrigin());
|
||||||
|
result.setPlatform(record.getPlatform());
|
||||||
|
result.setBusinessScene(getBusinessSceneDesc(record.getBusinessScene()));
|
||||||
|
result.setFixedUserIds(record.getFixedUserIds());
|
||||||
|
result.setLink(record.getLink());
|
||||||
|
result.setOrigin(record.getOrigin());
|
||||||
|
result.setPushStatus(getPushStatusDesc(record.getPushStatus()));
|
||||||
|
result.setDeviceType(record.getDeviceType());
|
||||||
|
result.setFailQuantity(record.getFailQuantity());
|
||||||
|
result.setSuccessQuantity(record.getSuccessQuantity());
|
||||||
|
result.setSendUserName(sendUserNameMap.get(record.getCreateUser()));
|
||||||
|
result.setCreateTime(record.getCreateTime());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getBusinessSceneDesc(String businessScene) {
|
||||||
|
String desc = MessageBusinessSceneEnum.getDesc(businessScene);
|
||||||
|
return StringUtils.isBlank(desc) ? businessScene : desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPushStatusDesc(String pushStatus) {
|
||||||
|
if (Objects.equals(PUSH_STATUS_SUCCESS, pushStatus)) {
|
||||||
|
return "成功";
|
||||||
|
}
|
||||||
|
if (PUSH_FAIL_STATUSES.contains(pushStatus)) {
|
||||||
|
return "失败";
|
||||||
|
}
|
||||||
|
return pushStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PageQuery ensurePageQuery(PageCommand pageCommand) {
|
||||||
|
PageQuery pageQuery = pageCommand.getPageQuery();
|
||||||
|
if (Objects.isNull(pageQuery)) {
|
||||||
|
pageQuery = new PageQuery();
|
||||||
|
pageCommand.setPageQuery(pageQuery);
|
||||||
|
}
|
||||||
|
if (Objects.isNull(pageQuery.getCursor()) || pageQuery.getCursor() < 1) {
|
||||||
|
pageQuery.setCursor(1);
|
||||||
|
}
|
||||||
|
if (Objects.isNull(pageQuery.getLimit()) || pageQuery.getLimit() < 1) {
|
||||||
|
pageQuery.setLimit(DEFAULT_PAGE_LIMIT);
|
||||||
|
}
|
||||||
|
return pageQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int resolvePageLimit(PageQuery pageQuery) {
|
||||||
|
if (Objects.isNull(pageQuery) || Objects.isNull(pageQuery.getLimit())
|
||||||
|
|| pageQuery.getLimit() < 1) {
|
||||||
|
return DEFAULT_PAGE_LIMIT;
|
||||||
|
}
|
||||||
|
return pageQuery.getLimit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
|||||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.sql.Timestamp;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
@ -94,4 +95,9 @@ public class SysPushRecordLogCO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String sendUserName;
|
private String sendUserName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间.
|
||||||
|
*/
|
||||||
|
private Timestamp createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
package com.red.circle.console.app.service.app.sys;
|
package com.red.circle.console.app.service.app.sys;
|
||||||
|
|
||||||
|
import com.red.circle.console.app.dto.clienobject.sys.SysPushRecordLogCO;
|
||||||
|
import com.red.circle.console.app.dto.clienobject.sys.SysPushTaskCO;
|
||||||
|
import com.red.circle.framework.dto.PageResult;
|
||||||
|
import com.red.circle.other.inner.model.cmd.sys.CreateRecordCmd;
|
||||||
|
import com.red.circle.other.inner.model.cmd.sys.SysPushRecordLogQryCmd;
|
||||||
|
import com.red.circle.other.inner.model.cmd.sys.SysPushTaskCmd;
|
||||||
|
import com.red.circle.other.inner.model.cmd.sys.SysPushTaskQryCmd;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统推送服务.
|
* 系统推送服务.
|
||||||
@ -8,29 +15,29 @@ package com.red.circle.console.app.service.app.sys;
|
|||||||
* @since 2020/3/6 15:53
|
* @since 2020/3/6 15:53
|
||||||
*/
|
*/
|
||||||
public interface SysPushService {
|
public interface SysPushService {
|
||||||
/*
|
|
||||||
*//**
|
/**
|
||||||
* 创建推送.
|
* 创建推送.
|
||||||
*//*
|
*/
|
||||||
void create(CreateRecordCmd createRecordParam);
|
void create(CreateRecordCmd createRecordParam);
|
||||||
|
|
||||||
*//**
|
/**
|
||||||
* 获取push日志分页列表
|
* 获取push日志分页列表.
|
||||||
*//*
|
*/
|
||||||
PageResult<SysPushRecordLogCO> pageLogs(SysPushRecordLogQryCmd query);
|
PageResult<SysPushRecordLogCO> pageLogs(SysPushRecordLogQryCmd query);
|
||||||
|
|
||||||
*//**
|
/**
|
||||||
* 定时推送任务分页列表
|
* 定时推送任务分页列表.
|
||||||
*//*
|
*/
|
||||||
PageResult<SysPushTaskCO> pageTask(SysPushTaskQryCmd query);
|
PageResult<SysPushTaskCO> pageTask(SysPushTaskQryCmd query);
|
||||||
|
|
||||||
*//**
|
/**
|
||||||
* 保存推送任务
|
* 保存推送任务.
|
||||||
*//*
|
*/
|
||||||
void saveTask(SysPushTaskCmd param);
|
void saveTask(SysPushTaskCmd param);
|
||||||
|
|
||||||
*//**
|
/**
|
||||||
* 删除任务
|
* 删除任务.
|
||||||
*//*
|
*/
|
||||||
void deletePushTask(Long id);*/
|
void deletePushTask(Long id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.red.circle.console.infra.database.rds.dao.sys;
|
||||||
|
|
||||||
|
import com.red.circle.console.infra.database.rds.entity.sys.SysPushRecordLog;
|
||||||
|
import com.red.circle.framework.mybatis.dao.BaseDAO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push 日志 DAO.
|
||||||
|
*/
|
||||||
|
public interface SysPushRecordLogDAO extends BaseDAO<SysPushRecordLog> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
package com.red.circle.console.infra.database.rds.entity.sys;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push 日志.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("sys_push_record_log")
|
||||||
|
public class SysPushRecordLog extends TimestampBaseEntity implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@TableField("title")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@TableField("content")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@TableField("sys_origin")
|
||||||
|
private String sysOrigin;
|
||||||
|
|
||||||
|
@TableField("platform")
|
||||||
|
private String platform;
|
||||||
|
|
||||||
|
@TableField("business_scene")
|
||||||
|
private String businessScene;
|
||||||
|
|
||||||
|
@TableField("fixed_user_ids")
|
||||||
|
private String fixedUserIds;
|
||||||
|
|
||||||
|
@TableField("link")
|
||||||
|
private String link;
|
||||||
|
|
||||||
|
@TableField("origin")
|
||||||
|
private String origin;
|
||||||
|
|
||||||
|
@TableField("push_status")
|
||||||
|
private String pushStatus;
|
||||||
|
|
||||||
|
@TableField("device_type")
|
||||||
|
private String deviceType;
|
||||||
|
|
||||||
|
@TableField("fail_quantity")
|
||||||
|
private Integer failQuantity;
|
||||||
|
|
||||||
|
@TableField("success_quantity")
|
||||||
|
private Integer successQuantity;
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.red.circle.console.infra.database.rds.service.sys;
|
||||||
|
|
||||||
|
import com.red.circle.console.infra.database.rds.entity.sys.SysPushRecordLog;
|
||||||
|
import com.red.circle.framework.mybatis.service.BaseService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push 日志服务.
|
||||||
|
*/
|
||||||
|
public interface SysPushRecordLogService extends BaseService<SysPushRecordLog> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package com.red.circle.console.infra.database.rds.service.sys.impl;
|
||||||
|
|
||||||
|
import com.red.circle.console.infra.database.rds.dao.sys.SysPushRecordLogDAO;
|
||||||
|
import com.red.circle.console.infra.database.rds.entity.sys.SysPushRecordLog;
|
||||||
|
import com.red.circle.console.infra.database.rds.service.sys.SysPushRecordLogService;
|
||||||
|
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push 日志服务实现.
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class SysPushRecordLogServiceImpl extends
|
||||||
|
BaseServiceImpl<SysPushRecordLogDAO, SysPushRecordLog> implements SysPushRecordLogService {
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,11 +2,15 @@ package com.red.circle;
|
|||||||
|
|
||||||
import com.red.circle.component.redis.RedisAutoConfiguration;
|
import com.red.circle.component.redis.RedisAutoConfiguration;
|
||||||
import com.red.circle.framework.cloud.annotation.RedCircleCloudApplication;
|
import com.red.circle.framework.cloud.annotation.RedCircleCloudApplication;
|
||||||
|
import com.red.circle.live.adapter.app.LiveMicRestController;
|
||||||
|
import com.red.circle.live.adapter.app.LiveRoomRestController;
|
||||||
|
import com.red.circle.live.adapter.app.LiveUserRestController;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,6 +21,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
|||||||
@EnableDiscoveryClient
|
@EnableDiscoveryClient
|
||||||
@EnableFeignClients
|
@EnableFeignClients
|
||||||
@SpringBootApplication(exclude = RedisAutoConfiguration.class)
|
@SpringBootApplication(exclude = RedisAutoConfiguration.class)
|
||||||
|
@Import({LiveMicRestController.class, LiveRoomRestController.class, LiveUserRestController.class})
|
||||||
public class LiveServiceApplication {
|
public class LiveServiceApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@ -131,6 +131,7 @@ public class GameLuckyGiftCommon {
|
|||||||
private final RoomMemberService roomMemberService;
|
private final RoomMemberService roomMemberService;
|
||||||
private final RedisService redisService;
|
private final RedisService redisService;
|
||||||
private final RoomProfileManagerService roomProfileManagerService;
|
private final RoomProfileManagerService roomProfileManagerService;
|
||||||
|
private final LuckyGiftSendMetricsService luckyGiftSendMetricsService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送幸运礼物抽奖mq.
|
* 发送幸运礼物抽奖mq.
|
||||||
@ -290,6 +291,16 @@ public class GameLuckyGiftCommon {
|
|||||||
|
|
||||||
Integer totalAwardAmount = apiResult.getOrderResults().stream().mapToInt(OrderResult::getRewardNum).sum();
|
Integer totalAwardAmount = apiResult.getOrderResults().stream().mapToInt(OrderResult::getRewardNum).sum();
|
||||||
|
|
||||||
|
GiftConfigDTO giftConfigDTO = getGiftConfigDTO(cmd.getGiftId());
|
||||||
|
luckyGiftSendMetricsService.settle(
|
||||||
|
"legacy:" + cmd.getId(),
|
||||||
|
cmd.getRoomId(),
|
||||||
|
cmd.getUserId(),
|
||||||
|
giftConfigDTO.getGiftCandy(),
|
||||||
|
cmd.getQuantity(),
|
||||||
|
Objects.isNull(cmd.getAcceptUserId()) ? Collections.emptyList() : List.of(cmd.getAcceptUserId())
|
||||||
|
);
|
||||||
|
|
||||||
// 保存幸运礼物流水
|
// 保存幸运礼物流水
|
||||||
Long rewardAmount = Long.valueOf(String.valueOf(totalAwardAmount));
|
Long rewardAmount = Long.valueOf(String.valueOf(totalAwardAmount));
|
||||||
saveLuckGiftCount(param, rewardAmount);
|
saveLuckGiftCount(param, rewardAmount);
|
||||||
@ -306,7 +317,6 @@ public class GameLuckyGiftCommon {
|
|||||||
sendMsg(param, multiple, balance, rewardAmount);
|
sendMsg(param, multiple, balance, rewardAmount);
|
||||||
|
|
||||||
// 魔法礼物中奖后处理
|
// 魔法礼物中奖后处理
|
||||||
GiftConfigDTO giftConfigDTO = getGiftConfigDTO(cmd.getGiftId());
|
|
||||||
if (GiftTabEnum.MAGIC.name().equals(giftConfigDTO.getGiftTab())) {
|
if (GiftTabEnum.MAGIC.name().equals(giftConfigDTO.getGiftTab())) {
|
||||||
String timeId = IdWorker.getIdStr();
|
String timeId = IdWorker.getIdStr();
|
||||||
GiveAwayGiftBatchEvent giftBatchEvent = buildGiftBatchEvent(cmd, timeId, param, giftConfigDTO);
|
GiveAwayGiftBatchEvent giftBatchEvent = buildGiftBatchEvent(cmd, timeId, param, giftConfigDTO);
|
||||||
|
|||||||
@ -58,6 +58,7 @@ public class LuckyGiftResultProcessor {
|
|||||||
private final RedisService redisService;
|
private final RedisService redisService;
|
||||||
private final RoomProfileManagerService roomProfileManagerService;
|
private final RoomProfileManagerService roomProfileManagerService;
|
||||||
private final GameLuckyGiftCommon gameLuckyGiftCommon;
|
private final GameLuckyGiftCommon gameLuckyGiftCommon;
|
||||||
|
private final LuckyGiftSendMetricsService luckyGiftSendMetricsService;
|
||||||
|
|
||||||
public void process(GameLuckyGiftBusinessEvent event, LuckyGiftGoClient.LuckyGiftGoDrawResponse response) {
|
public void process(GameLuckyGiftBusinessEvent event, LuckyGiftGoClient.LuckyGiftGoDrawResponse response) {
|
||||||
GiftConfigDTO giftConfig = giftCacheService.getById(event.getGiftId());
|
GiftConfigDTO giftConfig = giftCacheService.getById(event.getGiftId());
|
||||||
@ -85,6 +86,18 @@ public class LuckyGiftResultProcessor {
|
|||||||
long payAmount = resolvePayAmount(event, giftUnitPrice);
|
long payAmount = resolvePayAmount(event, giftUnitPrice);
|
||||||
BigDecimal balanceAfter = BigDecimal.valueOf(Objects.requireNonNullElse(response.getBalanceAfter(), 0L));
|
BigDecimal balanceAfter = BigDecimal.valueOf(Objects.requireNonNullElse(response.getBalanceAfter(), 0L));
|
||||||
|
|
||||||
|
luckyGiftSendMetricsService.settle(
|
||||||
|
event.getBusinessId(),
|
||||||
|
event.getRoomId(),
|
||||||
|
event.getUserId(),
|
||||||
|
giftUnitPrice,
|
||||||
|
event.getQuantity(),
|
||||||
|
Optional.ofNullable(event.getUsers()).orElse(Collections.emptyList()).stream()
|
||||||
|
.map(GameLuckyGiftUser::getAcceptUserId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.toList()
|
||||||
|
);
|
||||||
|
|
||||||
for (LuckyGiftGoClient.LuckyGiftGoDrawResult result : response.getResults()) {
|
for (LuckyGiftGoClient.LuckyGiftGoDrawResult result : response.getResults()) {
|
||||||
GameLuckyGiftUser user = userMap.get(result.getId());
|
GameLuckyGiftUser user = userMap.get(result.getId());
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
|
|||||||
@ -0,0 +1,149 @@
|
|||||||
|
package com.red.circle.other.app.common.gift;
|
||||||
|
|
||||||
|
import com.red.circle.component.redis.service.RedisService;
|
||||||
|
import com.red.circle.other.domain.enums.VipBenefitType;
|
||||||
|
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||||
|
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
|
||||||
|
import com.red.circle.other.domain.model.user.ability.RegionConfig;
|
||||||
|
import com.red.circle.other.infra.common.team.TeamTargetCommon;
|
||||||
|
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
|
||||||
|
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
|
||||||
|
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
|
||||||
|
import com.red.circle.other.infra.database.rds.service.user.user.ConsumptionLevelService;
|
||||||
|
import com.red.circle.tool.core.collection.CollectionUtils;
|
||||||
|
import com.red.circle.tool.core.num.ArithmeticUtils;
|
||||||
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 幸运礼物送出后的统计补偿.
|
||||||
|
* 只补房间流水、魅力值、主播收礼积分,固定按 10% 结算。
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LuckyGiftSendMetricsService {
|
||||||
|
|
||||||
|
private static final String PROCESSED_KEY_PREFIX = "lucky_gift:send:metrics:processed:";
|
||||||
|
private static final BigDecimal LUCKY_GIFT_METRIC_RATIO = new BigDecimal("0.1");
|
||||||
|
|
||||||
|
private final RedisService redisService;
|
||||||
|
private final TeamTargetCommon teamTargetCommon;
|
||||||
|
private final TeamMemberService teamMemberService;
|
||||||
|
private final UserRegionGateway userRegionGateway;
|
||||||
|
private final UserProfileGateway userProfileGateway;
|
||||||
|
private final ConsumptionLevelService consumptionLevelService;
|
||||||
|
private final RoomProfileManagerService roomProfileManagerService;
|
||||||
|
|
||||||
|
public void settle(
|
||||||
|
String idempotencyKey,
|
||||||
|
Long roomId,
|
||||||
|
Long sendUserId,
|
||||||
|
BigDecimal giftUnitPrice,
|
||||||
|
Integer quantity,
|
||||||
|
List<Long> acceptUserIds
|
||||||
|
) {
|
||||||
|
if (StringUtils.isBlank(idempotencyKey) || sendUserId == null || giftUnitPrice == null
|
||||||
|
|| quantity == null || quantity <= 0 || CollectionUtils.isEmpty(acceptUserIds)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!redisService.setIfAbsent(PROCESSED_KEY_PREFIX + idempotencyKey, "1", 7,
|
||||||
|
TimeUnit.DAYS)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal singleGiftAmount = giftUnitPrice.multiply(BigDecimal.valueOf(quantity));
|
||||||
|
BigDecimal singleMetricAmount = calculateMetricAmount(singleGiftAmount);
|
||||||
|
if (ArithmeticUtils.lteZero(singleMetricAmount)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
settleRoomValue(roomId, sendUserId, singleGiftAmount, acceptUserIds.size());
|
||||||
|
settleCharm(acceptUserIds, singleMetricAmount);
|
||||||
|
settleHostPoints(sendUserId, acceptUserIds, singleMetricAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void settleRoomValue(Long roomId, Long sendUserId, BigDecimal singleGiftAmount,
|
||||||
|
int acceptSize) {
|
||||||
|
if (roomId == null || acceptSize <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomProfile roomProfile = roomProfileManagerService.getProfileById(roomId);
|
||||||
|
if (roomProfile == null || !Objects.equals(roomProfile.getUserId(), sendUserId)
|
||||||
|
|| teamMemberService.getByMemberId(sendUserId) == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal roomMetricAmount = calculateMetricAmount(
|
||||||
|
singleGiftAmount.multiply(BigDecimal.valueOf(acceptSize)));
|
||||||
|
if (ArithmeticUtils.lteZero(roomMetricAmount)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
teamTargetCommon.incrementRoomValue(sendUserId, roomMetricAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void settleCharm(List<Long> acceptUserIds, BigDecimal singleMetricAmount) {
|
||||||
|
for (Long acceptUserId : acceptUserIds) {
|
||||||
|
if (acceptUserId == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal vipBenefit = Objects.requireNonNullElse(
|
||||||
|
userProfileGateway.getUserVipBenefit(acceptUserId, VipBenefitType.XP_RATE),
|
||||||
|
VipBenefitType.XP_RATE.getDefaultValue()
|
||||||
|
);
|
||||||
|
BigDecimal charmAmount = singleMetricAmount.multiply(vipBenefit)
|
||||||
|
.setScale(0, RoundingMode.DOWN);
|
||||||
|
if (ArithmeticUtils.lteZero(charmAmount)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
consumptionLevelService.incrConsumptionDiamond(acceptUserId, charmAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void settleHostPoints(Long sendUserId, List<Long> acceptUserIds,
|
||||||
|
BigDecimal singleMetricAmount) {
|
||||||
|
RegionConfig sendRegion = userRegionGateway.getRegionConfigByUserId(sendUserId);
|
||||||
|
if (sendRegion == null || StringUtils.isBlank(sendRegion.getRegionCode())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Long> anchorUserIds = new HashSet<>(
|
||||||
|
teamMemberService.listMemberIds(new HashSet<>(acceptUserIds)));
|
||||||
|
for (Long acceptUserId : acceptUserIds) {
|
||||||
|
if (acceptUserId == null || !anchorUserIds.contains(acceptUserId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegionConfig acceptRegion = userRegionGateway.getRegionConfigByUserId(acceptUserId);
|
||||||
|
if (acceptRegion == null || StringUtils.isBlank(acceptRegion.getRegionCode())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userRegionGateway.checkBusinessRegionCode(sendRegion.getRegionCode(),
|
||||||
|
acceptRegion.getRegionCode())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
teamTargetCommon.incrementGiftValue(acceptUserId, singleMetricAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal calculateMetricAmount(BigDecimal amount) {
|
||||||
|
if (ArithmeticUtils.lteZero(amount)) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
return amount.multiply(LUCKY_GIFT_METRIC_RATIO).setScale(0, RoundingMode.DOWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,205 @@
|
|||||||
|
package com.red.circle.other.app.common.gift;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import com.red.circle.component.redis.service.RedisService;
|
||||||
|
import com.red.circle.external.inner.endpoint.message.ImGroupClient;
|
||||||
|
import com.red.circle.mq.rocket.business.producer.GiftMqMessage;
|
||||||
|
import com.red.circle.mq.rocket.business.service.MessageSenderService;
|
||||||
|
import com.red.circle.other.app.convertor.material.GiftAppConvertor;
|
||||||
|
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
|
||||||
|
import com.red.circle.other.app.service.activity.ActivityRechargeTicketService;
|
||||||
|
import com.red.circle.other.app.service.activity.RankingActivityService;
|
||||||
|
import com.red.circle.other.app.service.game.BaishunRuntimeConfigResolver;
|
||||||
|
import com.red.circle.other.app.service.task.RoomDailyTaskProgressService;
|
||||||
|
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||||
|
import com.red.circle.other.domain.model.user.UserProfile;
|
||||||
|
import com.red.circle.other.infra.config.LuckyGiftApiConfig;
|
||||||
|
import com.red.circle.other.infra.database.cache.entity.game.luckgift.GameLuckyGiftInventoryCache;
|
||||||
|
import com.red.circle.other.infra.database.cache.entity.game.luckgift.LuckyGiftInventoryTemplateCache;
|
||||||
|
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
|
||||||
|
import com.red.circle.other.infra.database.cache.service.other.GameLuckyGiftCacheService;
|
||||||
|
import com.red.circle.other.infra.database.cache.service.other.GiftCacheService;
|
||||||
|
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
|
||||||
|
import com.red.circle.other.infra.database.rds.entity.game.GameLuckyGiftCount;
|
||||||
|
import com.red.circle.other.infra.database.rds.service.game.GameLuckyGiftCountService;
|
||||||
|
import com.red.circle.other.infra.database.rds.service.game.GameLuckyGiftRuleConfigService;
|
||||||
|
import com.red.circle.other.infra.database.rds.service.game.LuckyGiftProbabilityDetailsService;
|
||||||
|
import com.red.circle.other.infra.database.rds.service.game.LuckyGiftProbabilityService;
|
||||||
|
import com.red.circle.other.infra.database.rds.service.live.RoomMemberService;
|
||||||
|
import com.red.circle.other.infra.database.rds.service.sys.EnumConfigService;
|
||||||
|
import com.red.circle.other.inner.model.dto.material.GiftConfigDTO;
|
||||||
|
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||||
|
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
|
class GameLuckyGiftCommonTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void run_shouldSettleLegacyMetricsWhenAwardIsZero() {
|
||||||
|
TestFixture fixture = new TestFixture();
|
||||||
|
fixture.mockGiftAndSender();
|
||||||
|
|
||||||
|
GameLuckyGiftParamCmd cmd = fixture.newCmd().setAcceptUserId(3001L);
|
||||||
|
|
||||||
|
fixture.common.run(cmd);
|
||||||
|
|
||||||
|
verify(fixture.luckyGiftSendMetricsService).settle(
|
||||||
|
"legacy:9001",
|
||||||
|
1001L,
|
||||||
|
2001L,
|
||||||
|
BigDecimal.valueOf(100),
|
||||||
|
2,
|
||||||
|
List.of(3001L)
|
||||||
|
);
|
||||||
|
|
||||||
|
ArgumentCaptor<GameLuckyGiftCount> countCaptor = ArgumentCaptor.forClass(GameLuckyGiftCount.class);
|
||||||
|
verify(fixture.gameLuckyGiftCountService).save(countCaptor.capture());
|
||||||
|
assertEquals(Long.valueOf(0), countCaptor.getValue().getAwardAmount());
|
||||||
|
assertEquals(Long.valueOf(200), countCaptor.getValue().getPayAmount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void run_shouldHandleNullAcceptUserIdWhenAwardIsZero() {
|
||||||
|
TestFixture fixture = new TestFixture();
|
||||||
|
fixture.mockGiftAndSender();
|
||||||
|
|
||||||
|
GameLuckyGiftParamCmd cmd = fixture.newCmd().setAcceptUserId(null);
|
||||||
|
|
||||||
|
assertDoesNotThrow(() -> fixture.common.run(cmd));
|
||||||
|
verify(fixture.luckyGiftSendMetricsService).settle(
|
||||||
|
"legacy:9001",
|
||||||
|
1001L,
|
||||||
|
2001L,
|
||||||
|
BigDecimal.valueOf(100),
|
||||||
|
2,
|
||||||
|
Collections.emptyList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class TestFixture {
|
||||||
|
|
||||||
|
private final MessageSenderService senderService = mock(MessageSenderService.class);
|
||||||
|
private final ImGroupClient imGroupClient = mock(ImGroupClient.class);
|
||||||
|
private final WalletGoldClient walletGoldClient = mock(WalletGoldClient.class);
|
||||||
|
private final GiftCacheService giftCacheService = mock(GiftCacheService.class);
|
||||||
|
private final EnumConfigService enumConfigService = mock(EnumConfigService.class);
|
||||||
|
private final UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
|
||||||
|
private final EnumConfigCacheService enumConfigCacheService = mock(EnumConfigCacheService.class);
|
||||||
|
private final UserProfileAppConvertor userProfileAppConvertor = mock(UserProfileAppConvertor.class);
|
||||||
|
private final GameLuckyGiftCountService gameLuckyGiftCountService = mock(GameLuckyGiftCountService.class);
|
||||||
|
private final GameLuckyGiftCacheService gameLuckyGiftCacheService = mock(GameLuckyGiftCacheService.class);
|
||||||
|
private final LuckyGiftProbabilityService luckyGiftProbabilityService = mock(
|
||||||
|
LuckyGiftProbabilityService.class);
|
||||||
|
private final GameLuckyGiftRuleConfigService gameLuckyGiftRuleConfigService = mock(
|
||||||
|
GameLuckyGiftRuleConfigService.class);
|
||||||
|
private final LuckyGiftProbabilityDetailsService luckyGiftProbabilityDetailsService = mock(
|
||||||
|
LuckyGiftProbabilityDetailsService.class);
|
||||||
|
private final LuckyGiftApiConfig luckyGiftApiConfig = mock(LuckyGiftApiConfig.class);
|
||||||
|
private final BaishunRuntimeConfigResolver baishunRuntimeConfigResolver = mock(
|
||||||
|
BaishunRuntimeConfigResolver.class);
|
||||||
|
private final RankingActivityService rankingActivityService = mock(RankingActivityService.class);
|
||||||
|
private final GiftMqMessage giftMqMessage = mock(GiftMqMessage.class);
|
||||||
|
private final GiftAppConvertor giftAppConvertor = mock(GiftAppConvertor.class);
|
||||||
|
private final ActivityRechargeTicketService activityRechargeTicketService = mock(
|
||||||
|
ActivityRechargeTicketService.class);
|
||||||
|
private final RoomDailyTaskProgressService roomDailyTaskProgressService = mock(
|
||||||
|
RoomDailyTaskProgressService.class);
|
||||||
|
private final RoomMemberService roomMemberService = mock(RoomMemberService.class);
|
||||||
|
private final RedisService redisService = mock(RedisService.class);
|
||||||
|
private final RoomProfileManagerService roomProfileManagerService = mock(
|
||||||
|
RoomProfileManagerService.class);
|
||||||
|
private final LuckyGiftSendMetricsService luckyGiftSendMetricsService = mock(
|
||||||
|
LuckyGiftSendMetricsService.class);
|
||||||
|
|
||||||
|
private final GameLuckyGiftCommon common = new GameLuckyGiftCommon(
|
||||||
|
senderService,
|
||||||
|
imGroupClient,
|
||||||
|
walletGoldClient,
|
||||||
|
giftCacheService,
|
||||||
|
enumConfigService,
|
||||||
|
userProfileGateway,
|
||||||
|
enumConfigCacheService,
|
||||||
|
userProfileAppConvertor,
|
||||||
|
gameLuckyGiftCountService,
|
||||||
|
gameLuckyGiftCacheService,
|
||||||
|
luckyGiftProbabilityService,
|
||||||
|
gameLuckyGiftRuleConfigService,
|
||||||
|
luckyGiftProbabilityDetailsService,
|
||||||
|
luckyGiftApiConfig,
|
||||||
|
baishunRuntimeConfigResolver,
|
||||||
|
rankingActivityService,
|
||||||
|
giftMqMessage,
|
||||||
|
giftAppConvertor,
|
||||||
|
activityRechargeTicketService,
|
||||||
|
roomDailyTaskProgressService,
|
||||||
|
roomMemberService,
|
||||||
|
redisService,
|
||||||
|
roomProfileManagerService,
|
||||||
|
luckyGiftSendMetricsService
|
||||||
|
);
|
||||||
|
|
||||||
|
private void mockGiftAndSender() {
|
||||||
|
GiftConfigDTO giftConfig = new GiftConfigDTO()
|
||||||
|
.setId(11L)
|
||||||
|
.setStandardId(99L)
|
||||||
|
.setGiftCandy(BigDecimal.valueOf(100))
|
||||||
|
.setGiftPhoto("gift.png");
|
||||||
|
when(giftCacheService.getById(11L)).thenReturn(giftConfig);
|
||||||
|
|
||||||
|
LuckyGiftInventoryTemplateCache template = new LuckyGiftInventoryTemplateCache()
|
||||||
|
.setGiftGiveTotal(0)
|
||||||
|
.setComboLoss(0)
|
||||||
|
.setCaches(List.of(new GameLuckyGiftInventoryCache().setMultiple(1).setQuantity(1)));
|
||||||
|
when(gameLuckyGiftCacheService.getInventoryTemplate(99L, 2)).thenReturn(template);
|
||||||
|
|
||||||
|
UserProfile senderProfile = new UserProfile();
|
||||||
|
senderProfile.setId(2001L);
|
||||||
|
senderProfile.setAccount("sender001");
|
||||||
|
when(userProfileGateway.getByUserId(2001L)).thenReturn(senderProfile);
|
||||||
|
|
||||||
|
UserProfileDTO senderProfileDTO = new UserProfileDTO();
|
||||||
|
senderProfileDTO.setId(2001L);
|
||||||
|
senderProfileDTO.setAccount("sender001");
|
||||||
|
senderProfileDTO.setUserNickname("sender");
|
||||||
|
senderProfileDTO.setUserAvatar("sender.png");
|
||||||
|
when(userProfileAppConvertor.toUserProfileDTO(senderProfile)).thenReturn(senderProfileDTO);
|
||||||
|
|
||||||
|
LuckyGiftApiConfig.ApiAccount apiAccount = new LuckyGiftApiConfig.ApiAccount();
|
||||||
|
apiAccount.setUrl("http://127.0.0.1:1");
|
||||||
|
apiAccount.setAppId("test-app");
|
||||||
|
apiAccount.setAppChannel("test-channel");
|
||||||
|
apiAccount.setAppKey("test-key");
|
||||||
|
when(baishunRuntimeConfigResolver.resolveLuckyGiftApiAccount("LIKEI", 99L))
|
||||||
|
.thenReturn(apiAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private GameLuckyGiftParamCmd newCmd() {
|
||||||
|
return new GameLuckyGiftParamCmd()
|
||||||
|
.setId(9001L)
|
||||||
|
.setUserId(2001L)
|
||||||
|
.setRoomId(1001L)
|
||||||
|
.setRoomAccount("room-account")
|
||||||
|
.setSysOrigin("LIKEI")
|
||||||
|
.setGiftId(11L)
|
||||||
|
.setQuantity(2)
|
||||||
|
.setGiftCombos(0)
|
||||||
|
.setRegionCode("SA")
|
||||||
|
.setGiftsCount(0)
|
||||||
|
.setComboLossCount(0)
|
||||||
|
.setOpenComboLoss(false)
|
||||||
|
.setSysComboLoss(0)
|
||||||
|
.setOpenGiftGiveTotal(false)
|
||||||
|
.setSysGiftGiveTotal(0)
|
||||||
|
.setStandardId(99L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -41,6 +41,7 @@ class LuckyGiftResultProcessorTest {
|
|||||||
RedisService redisService = mock(RedisService.class);
|
RedisService redisService = mock(RedisService.class);
|
||||||
RoomProfileManagerService roomProfileManagerService = mock(RoomProfileManagerService.class);
|
RoomProfileManagerService roomProfileManagerService = mock(RoomProfileManagerService.class);
|
||||||
GameLuckyGiftCommon gameLuckyGiftCommon = mock(GameLuckyGiftCommon.class);
|
GameLuckyGiftCommon gameLuckyGiftCommon = mock(GameLuckyGiftCommon.class);
|
||||||
|
LuckyGiftSendMetricsService luckyGiftSendMetricsService = mock(LuckyGiftSendMetricsService.class);
|
||||||
LuckyGiftResultProcessor processor = new LuckyGiftResultProcessor(
|
LuckyGiftResultProcessor processor = new LuckyGiftResultProcessor(
|
||||||
gameLuckyGiftCountService,
|
gameLuckyGiftCountService,
|
||||||
giftCacheService,
|
giftCacheService,
|
||||||
@ -51,7 +52,8 @@ class LuckyGiftResultProcessorTest {
|
|||||||
roomMemberService,
|
roomMemberService,
|
||||||
redisService,
|
redisService,
|
||||||
roomProfileManagerService,
|
roomProfileManagerService,
|
||||||
gameLuckyGiftCommon
|
gameLuckyGiftCommon,
|
||||||
|
luckyGiftSendMetricsService
|
||||||
);
|
);
|
||||||
|
|
||||||
GiftConfigDTO giftConfig = new GiftConfigDTO()
|
GiftConfigDTO giftConfig = new GiftConfigDTO()
|
||||||
@ -110,6 +112,15 @@ class LuckyGiftResultProcessorTest {
|
|||||||
|
|
||||||
processor.process(event, response);
|
processor.process(event, response);
|
||||||
|
|
||||||
|
verify(luckyGiftSendMetricsService).settle(
|
||||||
|
"biz-001",
|
||||||
|
3003L,
|
||||||
|
1001L,
|
||||||
|
BigDecimal.valueOf(173),
|
||||||
|
4,
|
||||||
|
List.of(2002L)
|
||||||
|
);
|
||||||
|
|
||||||
ArgumentCaptor<GameLuckyGiftCount> countCaptor = ArgumentCaptor.forClass(GameLuckyGiftCount.class);
|
ArgumentCaptor<GameLuckyGiftCount> countCaptor = ArgumentCaptor.forClass(GameLuckyGiftCount.class);
|
||||||
verify(gameLuckyGiftCountService).saveOrUpdate(countCaptor.capture());
|
verify(gameLuckyGiftCountService).saveOrUpdate(countCaptor.capture());
|
||||||
GameLuckyGiftCount saved = countCaptor.getValue();
|
GameLuckyGiftCount saved = countCaptor.getValue();
|
||||||
|
|||||||
@ -0,0 +1,127 @@
|
|||||||
|
package com.red.circle.other.app.common.gift;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import com.red.circle.component.redis.service.RedisService;
|
||||||
|
import com.red.circle.other.domain.enums.VipBenefitType;
|
||||||
|
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||||
|
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
|
||||||
|
import com.red.circle.other.domain.model.user.ability.RegionConfig;
|
||||||
|
import com.red.circle.other.infra.common.team.TeamTargetCommon;
|
||||||
|
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
|
||||||
|
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMember;
|
||||||
|
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
|
||||||
|
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
|
||||||
|
import com.red.circle.other.infra.database.rds.service.user.user.ConsumptionLevelService;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class LuckyGiftSendMetricsServiceTest {
|
||||||
|
|
||||||
|
private static final long ROOM_ID = 1001L;
|
||||||
|
private static final long SEND_USER_ID = 2001L;
|
||||||
|
private static final long ACCEPT_ANCHOR_ID = 3001L;
|
||||||
|
private static final long ACCEPT_OTHER_ANCHOR_ID = 3002L;
|
||||||
|
|
||||||
|
private RedisService redisService;
|
||||||
|
private TeamTargetCommon teamTargetCommon;
|
||||||
|
private TeamMemberService teamMemberService;
|
||||||
|
private UserRegionGateway userRegionGateway;
|
||||||
|
private UserProfileGateway userProfileGateway;
|
||||||
|
private ConsumptionLevelService consumptionLevelService;
|
||||||
|
private RoomProfileManagerService roomProfileManagerService;
|
||||||
|
private LuckyGiftSendMetricsService service;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
redisService = mock(RedisService.class);
|
||||||
|
teamTargetCommon = mock(TeamTargetCommon.class);
|
||||||
|
teamMemberService = mock(TeamMemberService.class);
|
||||||
|
userRegionGateway = mock(UserRegionGateway.class);
|
||||||
|
userProfileGateway = mock(UserProfileGateway.class);
|
||||||
|
consumptionLevelService = mock(ConsumptionLevelService.class);
|
||||||
|
roomProfileManagerService = mock(RoomProfileManagerService.class);
|
||||||
|
service = new LuckyGiftSendMetricsService(
|
||||||
|
redisService,
|
||||||
|
teamTargetCommon,
|
||||||
|
teamMemberService,
|
||||||
|
userRegionGateway,
|
||||||
|
userProfileGateway,
|
||||||
|
consumptionLevelService,
|
||||||
|
roomProfileManagerService
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void settle_shouldAddRoomValueCharmAndHostPointsWithTenPercent() {
|
||||||
|
when(redisService.setIfAbsent("lucky_gift:send:metrics:processed:biz-1", "1", 7,
|
||||||
|
TimeUnit.DAYS)).thenReturn(true);
|
||||||
|
|
||||||
|
RoomProfile roomProfile = new RoomProfile();
|
||||||
|
roomProfile.setId(ROOM_ID);
|
||||||
|
roomProfile.setUserId(SEND_USER_ID);
|
||||||
|
when(roomProfileManagerService.getProfileById(ROOM_ID)).thenReturn(roomProfile);
|
||||||
|
when(teamMemberService.getByMemberId(SEND_USER_ID)).thenReturn(new TeamMember());
|
||||||
|
when(teamMemberService.listMemberIds(Set.of(ACCEPT_ANCHOR_ID, ACCEPT_OTHER_ANCHOR_ID)))
|
||||||
|
.thenReturn(List.of(ACCEPT_ANCHOR_ID, ACCEPT_OTHER_ANCHOR_ID));
|
||||||
|
|
||||||
|
when(userProfileGateway.getUserVipBenefit(ACCEPT_ANCHOR_ID, VipBenefitType.XP_RATE))
|
||||||
|
.thenReturn(new BigDecimal("1.25"));
|
||||||
|
when(userProfileGateway.getUserVipBenefit(ACCEPT_OTHER_ANCHOR_ID, VipBenefitType.XP_RATE))
|
||||||
|
.thenReturn(BigDecimal.ONE);
|
||||||
|
|
||||||
|
RegionConfig sendRegion = new RegionConfig().setRegionCode("SA");
|
||||||
|
RegionConfig sameRegion = new RegionConfig().setRegionCode("SA");
|
||||||
|
RegionConfig diffRegion = new RegionConfig().setRegionCode("PK");
|
||||||
|
when(userRegionGateway.getRegionConfigByUserId(SEND_USER_ID)).thenReturn(sendRegion);
|
||||||
|
when(userRegionGateway.getRegionConfigByUserId(ACCEPT_ANCHOR_ID)).thenReturn(sameRegion);
|
||||||
|
when(userRegionGateway.getRegionConfigByUserId(ACCEPT_OTHER_ANCHOR_ID)).thenReturn(diffRegion);
|
||||||
|
when(userRegionGateway.checkBusinessRegionCode("SA", "SA")).thenReturn(true);
|
||||||
|
when(userRegionGateway.checkBusinessRegionCode("SA", "PK")).thenReturn(false);
|
||||||
|
|
||||||
|
service.settle(
|
||||||
|
"biz-1",
|
||||||
|
ROOM_ID,
|
||||||
|
SEND_USER_ID,
|
||||||
|
BigDecimal.valueOf(100),
|
||||||
|
2,
|
||||||
|
List.of(ACCEPT_ANCHOR_ID, ACCEPT_OTHER_ANCHOR_ID)
|
||||||
|
);
|
||||||
|
|
||||||
|
verify(teamTargetCommon).incrementRoomValue(SEND_USER_ID, BigDecimal.valueOf(40));
|
||||||
|
verify(consumptionLevelService).incrConsumptionDiamond(ACCEPT_ANCHOR_ID,
|
||||||
|
BigDecimal.valueOf(25));
|
||||||
|
verify(consumptionLevelService).incrConsumptionDiamond(ACCEPT_OTHER_ANCHOR_ID,
|
||||||
|
BigDecimal.valueOf(20));
|
||||||
|
verify(teamTargetCommon).incrementGiftValue(ACCEPT_ANCHOR_ID, BigDecimal.valueOf(20));
|
||||||
|
verify(teamTargetCommon, never()).incrementGiftValue(ACCEPT_OTHER_ANCHOR_ID,
|
||||||
|
BigDecimal.valueOf(20));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void settle_shouldSkipWhenAlreadyProcessed() {
|
||||||
|
when(redisService.setIfAbsent("lucky_gift:send:metrics:processed:biz-2", "1", 7,
|
||||||
|
TimeUnit.DAYS)).thenReturn(false);
|
||||||
|
|
||||||
|
service.settle(
|
||||||
|
"biz-2",
|
||||||
|
ROOM_ID,
|
||||||
|
SEND_USER_ID,
|
||||||
|
BigDecimal.valueOf(100),
|
||||||
|
1,
|
||||||
|
List.of(ACCEPT_ANCHOR_ID)
|
||||||
|
);
|
||||||
|
|
||||||
|
verify(teamTargetCommon, never()).incrementRoomValue(SEND_USER_ID, BigDecimal.TEN);
|
||||||
|
verify(consumptionLevelService, never()).incrConsumptionDiamond(ACCEPT_ANCHOR_ID,
|
||||||
|
BigDecimal.TEN);
|
||||||
|
verify(teamTargetCommon, never()).incrementGiftValue(ACCEPT_ANCHOR_ID, BigDecimal.TEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user