|
|
|
@ -60,6 +60,15 @@ public class VaaSyncService { |
|
|
|
private String downloadPath; |
|
|
|
@Value("${vaa-sync.retain-days:10}") |
|
|
|
private int retainDays; |
|
|
|
/** 这些地市的录音保持原始编码上传,不执行 G.729 转码(逗号分隔) */ |
|
|
|
@Value("${vaa-sync.transcode-excluded-city-codes:}") |
|
|
|
private String transcodeExcludedCityCodes; |
|
|
|
/** 需要扩大历史回看范围的地市编码(逗号分隔) */ |
|
|
|
@Value("${vaa-sync.extended-lookback-city-codes:}") |
|
|
|
private String extendedLookbackCityCodes; |
|
|
|
/** 上述地市每次同步向前回看的天数 */ |
|
|
|
@Value("${vaa-sync.extended-lookback-days:7}") |
|
|
|
private int extendedLookbackDays; |
|
|
|
|
|
|
|
/** |
|
|
|
* 定时同步任务 |
|
|
|
@ -197,7 +206,7 @@ public class VaaSyncService { |
|
|
|
// 8. 上传OSS(复用原OSS文件名覆盖,业务表无需更新)
|
|
|
|
String ossFileName = extractOssFileName(record.getRecordingFilePath(), fileName); |
|
|
|
String ossPath = "voice/" + cityCode + "/" + new SimpleDateFormat("yyyy-MM-dd").format(callStartTime) + "/"; |
|
|
|
OssFileResponse ossResponse = uploadRecording(localFile.toFile(), ossFileName, ossPath); |
|
|
|
OssFileResponse ossResponse = uploadRecording(localFile.toFile(), ossFileName, ossPath, cityCode); |
|
|
|
String previewUrl = ossResponse.getFileUrl(); |
|
|
|
if (previewUrl == null || previewUrl.trim().isEmpty()) { |
|
|
|
throw new IllegalStateException("OSS上传成功但未返回文件地址: " + ossFileName); |
|
|
|
@ -227,14 +236,19 @@ public class VaaSyncService { |
|
|
|
* @param localFile 本地录音文件 |
|
|
|
* @param fileName OSS 上的文件名(保持原文件名,业务表无需更新) |
|
|
|
* @param ossPath OSS 存储目录 |
|
|
|
* @param cityCode 地市编码,用于判断该地市是否禁用转码 |
|
|
|
* @return OSS 上传结果 |
|
|
|
*/ |
|
|
|
private OssFileResponse uploadRecording(File localFile, String fileName, String ossPath) { |
|
|
|
private OssFileResponse uploadRecording(File localFile, String fileName, String ossPath, String cityCode) { |
|
|
|
File uploadFile = localFile; |
|
|
|
File transcodedFile = null; |
|
|
|
boolean uploadSucceeded = false; |
|
|
|
try { |
|
|
|
if (g729Converter.isG729(localFile)) { |
|
|
|
boolean skipTranscode = isTranscodeExcluded(cityCode); |
|
|
|
if (skipTranscode) { |
|
|
|
logger.info("【录音】地市 {} 已配置跳过转码,直接上传原始文件: {} ({} 字节)", |
|
|
|
cityCode, fileName, localFile.length()); |
|
|
|
} else if (g729Converter.isG729(localFile)) { |
|
|
|
try { |
|
|
|
transcodedFile = new File(localFile.getParentFile(), localFile.getName() + ".pcm.wav"); |
|
|
|
if (transcodedFile.isFile()) { |
|
|
|
@ -270,6 +284,31 @@ public class VaaSyncService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** 判断当前地市是否配置为跳过录音转码。 */ |
|
|
|
private boolean isTranscodeExcluded(String cityCode) { |
|
|
|
if (!StringUtils.hasText(cityCode) || !StringUtils.hasText(transcodeExcludedCityCodes)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
for (String configuredCityCode : transcodeExcludedCityCodes.split(",")) { |
|
|
|
if (cityCode.equals(configuredCityCode.trim())) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
/** 默认回看1天,配置的地市使用扩展天数。 */ |
|
|
|
private int resolveLookbackDays(String cityCode) { |
|
|
|
if (StringUtils.hasText(cityCode) && StringUtils.hasText(extendedLookbackCityCodes)) { |
|
|
|
for (String configuredCityCode : extendedLookbackCityCodes.split(",")) { |
|
|
|
if (cityCode.equals(configuredCityCode.trim())) { |
|
|
|
return Math.max(1, extendedLookbackDays); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 从 call_record_id(格式:设备编号_录音ID)中提取录音盒上的录音ID |
|
|
|
*/ |
|
|
|
@ -373,9 +412,12 @@ public class VaaSyncService { |
|
|
|
Map<String, String> extNumbers = getExtensionNumbers(deviceHost, authToken); |
|
|
|
|
|
|
|
// 步骤3:计算同步时间范围
|
|
|
|
// 每次回看到昨天00:00,兼容录音盒延迟生成/延迟可见的录音。
|
|
|
|
// 默认回看到昨天00:00;配置了扩展回看的地市可向前查询更多天。
|
|
|
|
// 已入库数据由 call_record_id 批量去重,不会重复下载和入库。
|
|
|
|
Date lastSyncTime = startOfYesterday(); |
|
|
|
int lookbackDays = resolveLookbackDays(cityCode); |
|
|
|
Date lastSyncTime = startOfDaysAgo(lookbackDays); |
|
|
|
logger.info("【设备】录音查询回看范围: cityCode={}, lookbackDays={}, startTime={}", |
|
|
|
cityCode, lookbackDays, lastSyncTime); |
|
|
|
Date savedSyncTime = SyncTimeUtil.readLastSyncTime(downloadPath, deviceId); |
|
|
|
// 若历史上有失败记录尚未跨过,保留更早的补拉起点,直到后续处理成功。
|
|
|
|
if (savedSyncTime != null && savedSyncTime.before(lastSyncTime)) { |
|
|
|
@ -549,7 +591,7 @@ public class VaaSyncService { |
|
|
|
|
|
|
|
// 上传到OSS(地市+日期目录);上传失败时整条处理失败,下轮重新拉取。
|
|
|
|
String ossPath = "voice/" + cityCode + "/" + new SimpleDateFormat("yyyy-MM-dd").format(callStartTime) + "/"; |
|
|
|
OssFileResponse ossResponse = uploadRecording(localFile.toFile(), fileName, ossPath); |
|
|
|
OssFileResponse ossResponse = uploadRecording(localFile.toFile(), fileName, ossPath, cityCode); |
|
|
|
String previewUrl = ossResponse.getFileUrl(); |
|
|
|
if (previewUrl == null || previewUrl.trim().isEmpty()) { |
|
|
|
throw new IllegalStateException("OSS上传成功但未返回文件地址: " + fileName); |
|
|
|
@ -694,12 +736,10 @@ public class VaaSyncService { |
|
|
|
return candidate; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 返回服务器当地时区的昨天00:00:00。 |
|
|
|
*/ |
|
|
|
private Date startOfYesterday() { |
|
|
|
/** 返回服务器当地时区指定天数前的00:00:00。 */ |
|
|
|
private Date startOfDaysAgo(int days) { |
|
|
|
Calendar calendar = Calendar.getInstance(); |
|
|
|
calendar.add(Calendar.DAY_OF_MONTH, -1); |
|
|
|
calendar.add(Calendar.DAY_OF_MONTH, -Math.max(1, days)); |
|
|
|
calendar.set(Calendar.HOUR_OF_DAY, 0); |
|
|
|
calendar.set(Calendar.MINUTE, 0); |
|
|
|
calendar.set(Calendar.SECOND, 0); |
|
|
|
|