提交 3ef1f2ab 作者: duanxincheng

生成纪要压测

父级 b855e0ea
......@@ -97,7 +97,7 @@ public class CmeetingJob {
}
// @Scheduled(fixedRate = 20 * 60 * 1000,initialDelay = 2 * 60 * 1000)
@Scheduled(fixedRate = 20 * 60 * 1000)
// @Scheduled(fixedRate = 20 * 60 * 1000)
public void execute() {
// 定义时间格式化器
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
......
package com.cmeeting.service.impl;
import com.cmeeting.service.StressTestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class StressTestServiceImpl implements StressTestService {
@Override
public void minutesGenerate() {
}
}
package com.cmeeting.controller;
package controller;
import com.cmeeting.service.StressTestService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import service.StressTestService;
import javax.annotation.Resource;
......
package service;
import com.cmeeting.dto.UserDTO;
import com.cmeeting.mapper.primary.MeetingInfoMapper;
import com.cmeeting.mapper.primary.TecentMeetingMapper;
import com.cmeeting.mapper.primary.UserIdMapper;
import com.cmeeting.pojo.MeetingInfo;
import com.cmeeting.pojo.TencentMeetingUser;
import com.cmeeting.pojo.UserId;
import com.cmeeting.service.FileProcessProducer;
import com.cmeeting.service.MeetingRecordTemplateService;
import com.cmeeting.service.TencentMeetingService;
import com.cmeeting.util.SignatureUtil;
import com.cmeeting.vo.CorpRecordsVO;
import com.cmeeting.vo.TencentMeetingVO;
import com.google.gson.*;
import com.tencentcloudapi.wemeet.Client;
import com.tencentcloudapi.wemeet.core.authenticator.AuthenticatorBuilder;
import com.tencentcloudapi.wemeet.core.authenticator.JWTAuthenticator;
import com.tencentcloudapi.wemeet.service.meetings.api.MeetingsApi;
import com.tencentcloudapi.wemeet.service.meetings.model.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@Service
@Slf4j
public class StressTestServiceImpl implements StressTestService {
@Resource
private UserIdMapper userIdMapper;
@Autowired
private TencentMeetingService tencentMeetingService;
@Autowired
private FileProcessProducer producer;
@Autowired
private MeetingRecordTemplateService meetingRecordTemplateService;
@Value(value = "${tencent.appId}")
private String tencentAppId;
@Value(value = "${tencent.sdkId}")
private String tencentSdkId;
@Value(value = "${tencent.secretId}")
private String tencentSecretId;
@Value(value = "${tencent.secretKey}")
private String tencentSecretKey;
@Value(value = "${tencent.admin.userId}")
private String tencentAdminUserId;
@Value(value = "${permission.applicationId}")
private String permissionApplicationId;
@Value(value = "${permission.tenantId}")
private String permissionTenantId;
@Resource
private MeetingInfoMapper meetingInfoMapper;
@Resource
private TecentMeetingMapper tecentMeetingMapper;
@Override
public void minutesGenerate() {
//查出企微id和腾会id的关联关系
List<UserId> userIdRelations = userIdMapper.selectList(null);
Map<String,String> widTidRelations = userIdRelations.stream().collect(Collectors.toMap(UserId::getWid,UserId::getTid));
Map<String,String> tidWidRelations = userIdRelations.stream().collect(Collectors.toMap(UserId::getTid,UserId::getWid));
// List<TencentMeetingVO.RecordFile> meetingFiles = tencentMeetingService.getMeetingFiles(50);
//
// // 提交处理任务
// producer.submitBatchTasks(meetingFiles,authorizedUsers,tidWidRelations,Boolean.FALSE);
}
public List<TencentMeetingVO.RecordFile> getMeetingFiles(List<UserDTO> accessUserIds) {
Client client = new Client.Builder()
.withAppId(tencentAppId).withSdkId(tencentSdkId)
.withSecret(tencentSecretId,tencentSecretKey)
.build();
List<TencentMeetingVO.RecordFile> meetingFiles = new ArrayList<>();
List<TencentMeetingVO.RecordFile> recordFileUrlList = new ArrayList<>();
List<MeetingInfo> meetingSaveList = new ArrayList<>();
// 查询近两天的会议录制列表
try {
ZonedDateTime now = ZonedDateTime.now();
long startTime = now.minusDays(2).toEpochSecond();
long endTime = now.toEpochSecond();
AtomicInteger currentPage = new AtomicInteger(1);
//获取总页数
CorpRecordsVO firstData = fetchMeetingRecords(tencentAdminUserId, 1, startTime, endTime, 1, 20);
Integer totalPage = firstData.getTotalPage();
//目前已存储的会议id
List<TencentMeetingVO.SimpleMeetingInfo> meetingIds = meetingInfoMapper.getAllMeetingIds();
List<TencentMeetingUser> meetingUsers = tecentMeetingMapper.getAlluser();
Map<String, String> meetingMap = meetingUsers.stream().collect(Collectors.toMap(TencentMeetingUser::getUserId, TencentMeetingUser::getUserName));
while (currentPage.intValue() <= totalPage){
CorpRecordsVO data = fetchMeetingRecords(tencentAdminUserId, 1, startTime, endTime, currentPage.getAndIncrement(), 20);
//设置总页数
if (data != null && data.getRecordMeetings() != null && !data.getRecordMeetings().isEmpty()) {
List<CorpRecordsVO.RecordMeeting> meetings = data.getRecordMeetings();
//录制状态:
//1:录制中
//2:转码中
//3:转码完成
for (CorpRecordsVO.RecordMeeting meeting : meetings) {
//录制文件未转码完成,跳过
if(meeting.getState() != 3){
// processLogService.log(meeting.getMeetingId(),null,"会议未结束,跳过生成");
continue;
}
log.info("【会议检索】转录文件的meetingId->{},recordFileId->{}",meeting.getMeetingId(),meeting.getMeetingRecordId());
//查询会议详情
String meetingId = meeting.getMeetingId();
String subMeetingId = null;
LocalDateTime mediaStartTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.valueOf(meeting.getMediaStartTime())), ZoneId.systemDefault());
try {
String userid = meeting.getUserid();
log.info("【周期会议扫描】:查询用户的已结束会议列表...meetingCode->{},userId->{}",meeting.getMeetingCode(), userid);
//获取子会议id
MeetingsApi.ApiV1HistoryMeetingsUseridGetRequest historyMeetingRequest =
new MeetingsApi.ApiV1HistoryMeetingsUseridGetRequest.Builder(userid)
.pageSize("20")
.page("1")
.meetingCode(meeting.getMeetingCode())
.startTime(String.valueOf(mediaStartTime.toLocalDate().atStartOfDay().atZone(ZoneId.systemDefault()).toEpochSecond()))
.endTime(String.valueOf(mediaStartTime.toLocalDate().atStartOfDay().plusDays(1).atZone(ZoneId.systemDefault()).toEpochSecond()))
.build();
MeetingsApi.ApiV1HistoryMeetingsUseridGetResponse historyMeetingResponse =
client.meetings().v1HistoryMeetingsUseridGet(historyMeetingRequest, new JWTAuthenticator.Builder()
.nonce(BigInteger.valueOf(Math.abs((new SecureRandom()).nextInt()))).timestamp(String.valueOf(System.currentTimeMillis() / 1000L)));
V1HistoryMeetingsUseridGet200Response historyMeetingResponseData = historyMeetingResponse.getData();
List<V1HistoryMeetingsUseridGet200ResponseMeetingInfoListInner> historyMeetingInfoList = historyMeetingResponseData.getMeetingInfoList();
if(CollectionUtils.isEmpty(historyMeetingInfoList)){
log.error("会议未结束,获取子会议id信息失败");
continue;
}
V1HistoryMeetingsUseridGet200ResponseMeetingInfoListInner historyMeeting = historyMeetingInfoList.get(0);
//如果是周期会议
if(historyMeeting.getMeetingType() == 1){
subMeetingId = historyMeeting.getSubMeetingId();
}
//如果数据库中已有相同会议id的记录,跳过同步
String finalSubMeetingId = subMeetingId;
if(!meetingIds.stream().anyMatch(item->item.getMeetingId().equals(meetingId) && Objects.equals(item.getSubMeetingId(), finalSubMeetingId))){
log.info("【会议检索】新的会议meetingId->{}",meeting.getMeetingId());
List<CorpRecordsVO.RecordFile> recordFiles = meeting.getRecordFiles();
//按转录文件时间升序,便于后续的内容拼接
List<String> recordFileIdList = recordFiles.stream().sorted(Comparator.comparingLong(CorpRecordsVO.RecordFile::getRecordStartTime))
.map(CorpRecordsVO.RecordFile::getRecordFileId).collect(Collectors.toList());
TencentMeetingVO.RecordFile recordFileItem = TencentMeetingVO.RecordFile.builder()
.recordFileIdList(recordFileIdList).meetingId(meetingId).subMeetingId(subMeetingId).build();
String hostId;
String hostName;
//优先使用会议列表中已有的主持人字段
if(StringUtils.isNotEmpty(meeting.getHostUserId())){
hostId = meeting.getHostUserId();
hostName = meetingMap.containsKey(hostId) ? meetingMap.get(hostId) :null;
log.info("从会议列表中成功获取到主持人信息");
}else{
//判断主持人是否存在,如果主持人未参会,是查不到主持人的
//如果主持人未参会,使用会议详情中的创建人作为主持人
MeetingsApi.ApiV1MeetingsMeetingIdGetRequest meetingRequest =
new MeetingsApi.ApiV1MeetingsMeetingIdGetRequest.Builder(meetingId)
.operatorId(tencentAdminUserId)
.operatorIdType("1")
.instanceid("0")
.build();
MeetingsApi.ApiV1MeetingsMeetingIdGetResponse meetingResponse =
client.meetings().v1MeetingsMeetingIdGet(meetingRequest, new JWTAuthenticator.Builder()
.nonce(BigInteger.valueOf(Math.abs((new SecureRandom()).nextInt())))
.timestamp(String.valueOf(System.currentTimeMillis() / 1000L)));
V1MeetingsMeetingIdGet200Response meetingResponseData = meetingResponse.getData();
List<V1MeetingsMeetingIdGet200ResponseMeetingInfoListInner> meetingInfoList = meetingResponseData.getMeetingInfoList();
V1MeetingsMeetingIdGet200ResponseMeetingInfoListInner meetingInfo = meetingInfoList.get(0);
//会议详情中有主持人信息
if(!CollectionUtils.isEmpty(meetingInfo.getCurrentHosts())){
log.info("尝试从会议详情中获取主持人信息");
hostId = meetingInfo.getCurrentHosts().get(0).getUserid();
hostName = meetingMap.containsKey(hostId) ? meetingMap.get(hostId) :null;
// processLogService.log(meeting.getMeetingId(),subMeetingId,"未找到主持人,默认会议创建人为主持人");
}else{
log.info("尝试从参会人员列表中获取主持人信息");
// 获取参会成员明细
MeetingsApi.ApiV1MeetingsMeetingIdParticipantsGetRequest participantsRequest =
new MeetingsApi.ApiV1MeetingsMeetingIdParticipantsGetRequest
.Builder(meetingId).subMeetingId(subMeetingId).operatorId(tencentAdminUserId).operatorIdType("1").build();
AuthenticatorBuilder<JWTAuthenticator> participantsAuthenticatorBuilder =
new JWTAuthenticator.Builder()
.nonce(BigInteger.valueOf(Math.abs((new SecureRandom()).nextInt())))
.timestamp(String.valueOf(System.currentTimeMillis() / 1000L));
//主持人角色,以下角色都可以表示主持人
//用户角色:
//0:普通成员角色
//1:创建者角色
//2:主持人
//3:创建者+主持人
//4:游客
//5:游客+主持人
//6:联席主持人
//7:创建者+联席主持人
List<Long> hostRoleList = Arrays.asList(2L,3L,5L,6L,7L);
MeetingsApi.ApiV1MeetingsMeetingIdParticipantsGetResponse participantsResponse =
client.meetings().v1MeetingsMeetingIdParticipantsGet(participantsRequest, participantsAuthenticatorBuilder);
V1MeetingsMeetingIdParticipantsGet200Response participantsData = participantsResponse.getData();
List<V1MeetingsMeetingIdParticipantsGet200ResponseParticipantsInner> participants = participantsData.getParticipants();
Optional<V1MeetingsMeetingIdParticipantsGet200ResponseParticipantsInner> host = participants.stream().filter(item -> hostRoleList.contains(item.getUserRole())).findFirst();
if(host.isPresent()) {
hostId = host.get().getUserid();
hostName = new String(Base64.getDecoder().decode(host.get().getUserName()));
}else{
log.error("未找到主持人,默认没有生成纪要权限");
// processLogService.log(meeting.getMeetingId(),subMeetingId,"未找到主持人,默认没有生成纪要权限");
continue;
}
}
}
String email;
//判断是否有权限生成纪要
boolean generateAccess = accessUserIds.stream().anyMatch(item -> item.getTid().equals(hostId));
if(!generateAccess){
log.error("【权限校验】主持人{}没有生成纪要权限,跳过生成",hostId);
// processLogService.log(meeting.getMeetingId(),subMeetingId,"【权限校验】主持人"+hostId+"没有生成纪要权限,跳过生成");
continue;
}
log.info("【权限校验】主持人{}允许生成纪要",hostId);
// processLogService.log(meeting.getMeetingId(),subMeetingId,"【权限校验】主持人"+hostId+"允许生成纪要");
UserDTO userDTO = accessUserIds.stream().filter(item -> item.getTid().equals(hostId)).findFirst().get();
email = userDTO.getEmail();
//会议基本信息保存
MeetingInfo meetingItem = MeetingInfo.builder().meetingId(meetingId).meetingCode(meeting.getMeetingCode())
.subject(meeting.getSubject())
.startTime(mediaStartTime)
// .endTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(Long.valueOf(meeting.getEndTime())), ZoneId.systemDefault()))
.isGenerated(Boolean.FALSE).emailPushAccess(Boolean.TRUE).isPushed(Boolean.FALSE).syncTime(LocalDateTime.now())
.subMeetingId(subMeetingId).generateRetry(Boolean.FALSE).pushRetry(Boolean.FALSE)
.host(hostName)
.hostUid(hostId)
// .participantUsers(participants.stream()
// .map(item->new String(Base64.getDecoder().decode(item.getUserName()))).distinct().collect(Collectors.joining("、")))
.recordFileId(recordFileIdList.stream().collect(Collectors.joining(",")))
.email(email)
.build();
recordFileUrlList.add(recordFileItem);
meetingSaveList.add(meetingItem);
}
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
}
if(meetingSaveList.size() > 0){
Map<String, List<MeetingInfo>> meetingSaveMap = meetingSaveList.stream().collect(Collectors.groupingBy(
item -> item.getMeetingId() + "_" +
(item.getSubMeetingId() != null ? item.getSubMeetingId() : "null")));
List<MeetingInfo> finalSaveList = new ArrayList<>();
for (Map.Entry<String, List<MeetingInfo>> entry : meetingSaveMap.entrySet()) {
MeetingInfo meetingInfo = entry.getValue().get(0);
List<String> recordFileIdList = entry.getValue().stream().flatMap(s -> Arrays.stream(s.getRecordFileId().split(","))).collect(Collectors.toList());
meetingInfo.setRecordFileId(recordFileIdList.stream().collect(Collectors.joining(",")));
finalSaveList.add(meetingInfo);
meetingFiles.add(TencentMeetingVO.RecordFile.builder()
.meetingId(meetingInfo.getMeetingId())
.subMeetingId(meetingInfo.getSubMeetingId())
.recordFileIdList(recordFileIdList).build());
}
meetingInfoMapper.batchInsert(finalSaveList);
}
} catch (Exception e) {
log.error(e.getMessage());
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
throw new RuntimeException(e.getMessage());
}
return meetingFiles;
}
/**
* 拉取账户级的会议记录列表
* @param operatorId
* @param operatorIdType
* @param startTime
* @param endTime
* @param page
* @param pageSize
* @throws Exception
*/
public CorpRecordsVO fetchMeetingRecords(String operatorId, int operatorIdType, long startTime, long endTime, int page, int pageSize)
throws Exception {
String uri = String.format(
"/v1/corp/records?start_time=%d&end_time=%d&page=%d&page_size=%d&operator_id=%s&operator_id_type=%d",
startTime, endTime, page, pageSize, operatorId, operatorIdType
);
String httpMethod = "GET";
String nonce = String.valueOf(new Random().nextInt(100000));
String timestamp = String.valueOf(Instant.now().getEpochSecond());
// 3. 生成签名
String signature = SignatureUtil.generateSignature(tencentSecretId, tencentSecretKey, httpMethod, nonce, timestamp, uri, "");
// 4. 发送请求
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpGet request = new HttpGet("https://api.meeting.qq.com" + uri);
request.setHeader("X-TC-Key", tencentSecretId);
request.setHeader("X-TC-Timestamp", timestamp);
request.setHeader("X-TC-Nonce", nonce);
request.setHeader("X-TC-Signature", signature);
request.setHeader("AppId", tencentAppId);
request.setHeader("SdkId", tencentSdkId);
// 5. 解析响应
String response = EntityUtils.toString(httpClient.execute(request).getEntity());
JsonObject jsonResponse = JsonParser.parseString(response).getAsJsonObject();
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create();
// 将 JsonObject 转换为实体类
CorpRecordsVO corpRecords = gson.fromJson(jsonResponse, CorpRecordsVO.class);
return corpRecords;
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论