视频下载 添加 调用日志上报
This commit is contained in:
parent
ddd13510a8
commit
5003b1268b
@ -0,0 +1,17 @@
|
||||
package cn.skcks.docking.gb28181.wvp.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "report")
|
||||
public class ReportConfig {
|
||||
private Boolean enabled = false;
|
||||
private String url;
|
||||
private Map<String, String> customHeaders = new HashMap<>();
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package cn.skcks.docking.gb28181.wvp.dto.report;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Schema(description = "上报信息")
|
||||
public class ReportReq {
|
||||
@Schema(description = "上报消息id")
|
||||
private String id;
|
||||
@Schema(description = "设备编码")
|
||||
private String deviceCode;
|
||||
@Schema(description = "设备id/通道id")
|
||||
private String deviceId;
|
||||
@Schema(description = "点播时长")
|
||||
private String durationTime;
|
||||
@Schema(description = "点播时长")
|
||||
private TimeRange timeRange;
|
||||
|
||||
@DateTimeFormat(pattern= DatePattern.NORM_DATETIME_PATTERN)
|
||||
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@Schema(description = "日志记录时间")
|
||||
private Date logTime;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class TimeRange {
|
||||
@Schema(description = "开始时间")
|
||||
private Date startTime;
|
||||
@Schema(description = "结束时间")
|
||||
private Date endTime;
|
||||
}
|
||||
|
||||
@Schema(description = "文件大小, 未知大小为 -1")
|
||||
private String fileSize;
|
||||
}
|
@ -231,7 +231,7 @@ public class Gb28181DownloadService {
|
||||
writeErrorToResponse(asyncResponse, JsonResponse.error("下载失败"));
|
||||
} else if (wvpProxyConfig.getUseFfmpeg()) {
|
||||
log.info("开始 ffmpeg 录制, deviceCode {}, startTime {}, endTime {}", deviceCode, DateUtil.formatDateTime(startTime), DateUtil.formatDateTime(endTime));
|
||||
videoService.ffmpegRecord(asyncResponse, videoInfo.getUrl(), DateUtil.between(startTime, endTime, DateUnit.SECOND), videoInfo.getDevice(), videoInfo.getCallId());
|
||||
videoService.ffmpegRecord(request, asyncResponse, videoInfo.getUrl(), DateUtil.between(startTime, endTime, DateUnit.SECOND), videoInfo.getDevice(), videoInfo.getCallId());
|
||||
DateTime end = DateUtil.date();
|
||||
asyncContext.complete();
|
||||
log.info("下载总耗时: {}, deviceCode {}, startTime {}, endTime {}", DateUtil.between(start, end, DateUnit.SECOND), deviceCode, DateUtil.formatDateTime(startTime), DateUtil.formatDateTime(endTime));
|
||||
@ -376,7 +376,7 @@ public class Gb28181DownloadService {
|
||||
writeErrorToResponse(asyncResponse, JsonResponse.error("下载失败"));
|
||||
} else if(wvpProxyConfig.getUseFfmpeg()){
|
||||
log.info("开始 ffmpeg 录制, deviceCode {}, startTime {}, endTime {}", deviceCode, DateUtil.formatDateTime(startTime), DateUtil.formatDateTime(endTime));
|
||||
videoService.ffmpegRecord(asyncResponse, videoInfo.getUrl(), DateUtil.between(startTime, endTime, DateUnit.SECOND), videoInfo.getDevice(), videoInfo.getCallId());
|
||||
videoService.ffmpegRecord(request, asyncResponse, videoInfo.getUrl(), DateUtil.between(startTime, endTime, DateUnit.SECOND), videoInfo.getDevice(), videoInfo.getCallId());
|
||||
DateTime end = DateUtil.date();
|
||||
asyncContext.complete();
|
||||
log.info("下载总耗时: {}, deviceCode {}, startTime {}, endTime {}", DateUtil.between(start, end, DateUnit.SECOND), deviceCode, DateUtil.formatDateTime(startTime), DateUtil.formatDateTime(endTime));
|
||||
|
@ -0,0 +1,20 @@
|
||||
package cn.skcks.docking.gb28181.wvp.service.report;
|
||||
|
||||
import cn.skcks.docking.gb28181.common.json.JsonResponse;
|
||||
import cn.skcks.docking.gb28181.media.feign.IgnoreSSLFeignClientConfig;
|
||||
import cn.skcks.docking.gb28181.wvp.dto.report.ReportReq;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
|
||||
@FeignClient(
|
||||
name = "ReportServiceProxy",
|
||||
url = "${report.url}",
|
||||
configuration = {IgnoreSSLFeignClientConfig.class}
|
||||
)
|
||||
public interface ReportApi {
|
||||
@PostMapping
|
||||
JsonResponse<?> report(@RequestHeader MultiValueMap<String, String> headers, @RequestBody ReportReq body);
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package cn.skcks.docking.gb28181.wvp.service.report;
|
||||
|
||||
import cn.hutool.core.date.BetweenFormatter;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.unit.DataSizeUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.skcks.docking.gb28181.wvp.config.ReportConfig;
|
||||
import cn.skcks.docking.gb28181.wvp.dto.report.ReportReq;
|
||||
import cn.skcks.docking.gb28181.wvp.orm.mybatis.dynamic.model.WvpProxyDevice;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ReportService {
|
||||
private final ReportApi reportApi;
|
||||
private final ReportConfig reportConfig;
|
||||
|
||||
public void report(HttpServletRequest request, WvpProxyDevice device, Date startTime, Date endTime, long fileSize) {
|
||||
if(!reportConfig.getEnabled()){
|
||||
return;
|
||||
}
|
||||
|
||||
ReportReq reportReq = new ReportReq(IdUtil.fastUUID(),
|
||||
device.getDeviceCode(),
|
||||
device.getGbDeviceChannelId(),
|
||||
DateUtil.formatBetween(startTime, endTime, BetweenFormatter.Level.SECOND),
|
||||
new ReportReq.TimeRange(startTime, endTime),
|
||||
DateUtil.date(),
|
||||
DataSizeUtil.format(fileSize));
|
||||
LinkedMultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
||||
reportConfig.getCustomHeaders().forEach(headers::add);
|
||||
request.getHeaderNames().asIterator().forEachRemaining(headerKey -> {
|
||||
String header = request.getHeader(headerKey);
|
||||
headers.add(headerKey, header);
|
||||
});
|
||||
log.info("上报调用信息 {}", reportReq);
|
||||
reportApi.report(headers, reportReq);
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import cn.skcks.docking.gb28181.wvp.orm.mybatis.dynamic.model.WvpProxyDevice;
|
||||
import cn.skcks.docking.gb28181.wvp.orm.mybatis.dynamic.model.WvpProxyDocking;
|
||||
import cn.skcks.docking.gb28181.wvp.service.docking.DockingService;
|
||||
import cn.skcks.docking.gb28181.wvp.service.ffmpeg.FfmpegSupportService;
|
||||
import cn.skcks.docking.gb28181.wvp.service.report.ReportService;
|
||||
import cn.skcks.docking.gb28181.wvp.sip.request.SipRequestBuilder;
|
||||
import cn.skcks.docking.gb28181.wvp.sip.sender.SipSender;
|
||||
import jakarta.servlet.AsyncContext;
|
||||
@ -51,6 +52,7 @@ public class VideoService {
|
||||
private final DockingService dockingService;
|
||||
private final SipSender sender;
|
||||
private final FfmpegConfig ffmpegConfig;
|
||||
private final ReportService reportService;
|
||||
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
/**
|
||||
@ -231,7 +233,7 @@ public class VideoService {
|
||||
* @param time 录制时长 (单位: 秒)
|
||||
*/
|
||||
@SneakyThrows
|
||||
public void ffmpegRecord(ServletResponse response, String url, long time, WvpProxyDevice device,String callId){
|
||||
public void ffmpegRecord(HttpServletRequest request, ServletResponse response, String url, long time, WvpProxyDevice device,String callId){
|
||||
String tmpDir = ffmpegConfig.getTmpDir();
|
||||
String fileName = callId + ".mp4";
|
||||
File file = new File(tmpDir, fileName);
|
||||
@ -274,7 +276,9 @@ public class VideoService {
|
||||
log.info("临时文件 {}(大小 {})", file.getAbsolutePath(), file.length());
|
||||
IoUtil.copy(new FileInputStream(file), servletOutputStream);
|
||||
response.flushBuffer();
|
||||
reportService.report(request, device, startTime, endTime, file.length());
|
||||
} catch (Exception e){
|
||||
reportService.report(request, device, startTime, endTime, -1);
|
||||
log.error("写入 http 响应异常: {}", e.getMessage());
|
||||
} finally {
|
||||
System.gc();
|
||||
@ -284,6 +288,8 @@ public class VideoService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 录制视频 并写入 异步响应
|
||||
* @param response AsyncContext.getResponse 异步响应
|
||||
|
@ -28,6 +28,7 @@ import cn.skcks.docking.gb28181.wvp.proxy.WvpProxyClient;
|
||||
import cn.skcks.docking.gb28181.wvp.service.device.DeviceService;
|
||||
import cn.skcks.docking.gb28181.wvp.service.docking.DockingService;
|
||||
import cn.skcks.docking.gb28181.wvp.service.download.DownloadService;
|
||||
import cn.skcks.docking.gb28181.wvp.service.report.ReportService;
|
||||
import cn.skcks.docking.gb28181.wvp.service.video.VideoService;
|
||||
import cn.skcks.docking.gb28181.wvp.utils.RetryUtil;
|
||||
import com.github.rholder.retry.*;
|
||||
@ -65,6 +66,8 @@ public class WvpService {
|
||||
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||
private final ConcurrentMap<String, ScheduledFuture<?>> playing = new ConcurrentHashMap<>();
|
||||
|
||||
private final ReportService reportService;
|
||||
|
||||
public void header(HttpServletResponse response) {
|
||||
response.setContentType("video/mp4");
|
||||
response.setHeader("Accept-Ranges", "none");
|
||||
@ -113,6 +116,7 @@ public class WvpService {
|
||||
String reason = MessageFormat.format("调用 wvp api 查询设备({0})历史失败, 异常: {1}", deviceCode, e.getMessage());
|
||||
writeErrorToResponse(asyncResponse, JsonResponse.error(reason));
|
||||
} finally {
|
||||
reportService.report(request,wvpProxyDevice, startTime, endTime,-1);
|
||||
log.info("asyncContext 结束");
|
||||
asyncContext.complete();
|
||||
}
|
||||
|
@ -9,7 +9,8 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
@EnableFeignClients(basePackages = {
|
||||
"cn.skcks.docking.gb28181.media",
|
||||
"cn.skcks.docking.gb28181.wvp.proxy"
|
||||
"cn.skcks.docking.gb28181.wvp.proxy",
|
||||
"cn.skcks.docking.gb28181.wvp.service.report"
|
||||
})
|
||||
@SpringBootApplication
|
||||
@ComponentScan(basePackages = {
|
||||
|
@ -105,3 +105,9 @@ ffmpeg-support:
|
||||
# [可选] 日志配置, 一般不需要改
|
||||
logging:
|
||||
config: classpath:logback.xml
|
||||
|
||||
report:
|
||||
enabled: false
|
||||
url: http://127.0.0.1:8080/api/report
|
||||
custom-headers:
|
||||
agent: gb28181-proxy
|
@ -99,3 +99,10 @@ ffmpeg-support:
|
||||
# [可选] 日志配置, 一般不需要改
|
||||
logging:
|
||||
config: classpath:logback.xml
|
||||
|
||||
|
||||
report:
|
||||
enabled: false
|
||||
url: http://127.0.0.1:8080/api/report
|
||||
custom-headers:
|
||||
agent: gb28181-proxy
|
||||
|
Loading…
Reference in New Issue
Block a user