parent
e23e95c511
commit
e96fcc42ed
|
|
@ -81,4 +81,6 @@ public interface BusinessConstant {
|
|||
String DRC = "drc_";
|
||||
String FILE_PATH = "file/";
|
||||
String IMAGE_PATH = "image/";
|
||||
String VIDEO_PATH = "video/";
|
||||
String VIDEO_COVER_SUFFIX = "_cover.jpeg";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import com.multictrl.common.page.PageData;
|
|||
import com.multictrl.common.utils.Result;
|
||||
import com.multictrl.common.validator.AssertUtils;
|
||||
import com.multictrl.modules.business.dto.FlightTaskDTO;
|
||||
import com.multictrl.modules.business.dto.MediaFileDTO;
|
||||
import com.multictrl.modules.business.entity.SrsRecordEntity;
|
||||
import com.multictrl.modules.business.service.FlightTaskService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
|
@ -38,11 +40,15 @@ public class FlightTaskController {
|
|||
@Operation(summary = "分页")
|
||||
@Parameters({
|
||||
@Parameter(name = Constant.PAGE, description = "当前页码,从1开始"),
|
||||
@Parameter(name = Constant.LIMIT, description = "每页显示记录数")
|
||||
@Parameter(name = Constant.LIMIT, description = "每页显示记录数"),
|
||||
@Parameter(name = "key", description = "机库/航线名称"),
|
||||
@Parameter(name = "taskType", description = "任务类型 1:航线飞行 2:手动飞行 3:定时飞行"),
|
||||
@Parameter(name = "routeType", description = "航线类型 航点waypoint"),
|
||||
@Parameter(name = "taskStatus", description = "任务状态 0:进行中 -1:失败 1:完成 2:阻飞")
|
||||
})
|
||||
@RequiresPermissions("bus:task:page")
|
||||
public Result<PageData<FlightTaskDTO>> page(@Parameter(hidden = true) @RequestParam Map<String, Object> params) {
|
||||
PageData<FlightTaskDTO> page = flightTaskService.page(params);
|
||||
PageData<FlightTaskDTO> page = flightTaskService.pageList(params);
|
||||
|
||||
return new Result<PageData<FlightTaskDTO>>().ok(page);
|
||||
}
|
||||
|
|
@ -76,4 +82,22 @@ public class FlightTaskController {
|
|||
|
||||
return new Result<List<JSONObject>>().ok(data);
|
||||
}
|
||||
|
||||
@GetMapping("/getTaskMedia/{taskId}")
|
||||
@Operation(summary = "媒体文件")
|
||||
@RequiresPermissions("bus:task:taskMedia")
|
||||
public Result<List<MediaFileDTO>> getTaskMedia(@PathVariable("taskId") String taskId) {
|
||||
List<MediaFileDTO> data = flightTaskService.getTaskMedia(taskId);
|
||||
|
||||
return new Result<List<MediaFileDTO>>().ok(data);
|
||||
}
|
||||
|
||||
@GetMapping("/getFlightVideo/{taskId}")
|
||||
@Operation(summary = "飞行视频")
|
||||
@RequiresPermissions("bus:task:flightVideo")
|
||||
public Result<List<SrsRecordEntity>> getFlightVideo(@PathVariable("taskId") String taskId) {
|
||||
List<SrsRecordEntity> data = flightTaskService.getFlightVideo(taskId);
|
||||
|
||||
return new Result<List<SrsRecordEntity>>().ok(data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ public class SrsController {
|
|||
@PostMapping("/on_dvr")
|
||||
public String onDvr(@RequestBody SrsCallBackDTO srsCallBack) {
|
||||
// log.info("on_dvr {}", srsCallBack);
|
||||
|
||||
srsService.saveSrsRecord(srsCallBack);
|
||||
return "0";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,15 @@ import org.apache.ibatis.annotations.Mapper;
|
|||
/**
|
||||
* 飞行架次
|
||||
*
|
||||
* @author Sdy
|
||||
* @author Sdy
|
||||
* @since 1.0.0 2026-05-02
|
||||
*/
|
||||
@Mapper
|
||||
public interface FlightTaskDao extends BaseDao<FlightTaskEntity> {
|
||||
|
||||
|
||||
//获取最新的任务
|
||||
FlightTaskEntity getLatestRouteTask(String dockSn);
|
||||
|
||||
//获取当前任务的上一条任务
|
||||
FlightTaskEntity getPreviousTask(String taskId, String dockSn);
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.multictrl.modules.business.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
|
|
@ -67,4 +68,8 @@ public class MediaFileDTO implements Serializable {
|
|||
|
||||
@Schema(description = "事件收到时间")
|
||||
private Date createTime;
|
||||
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
@Schema(description = "媒体路径")
|
||||
private String url;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,4 +43,11 @@ public class SrsRecordEntity {
|
|||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createDate;
|
||||
|
||||
@TableField(exist = false)
|
||||
private String url;
|
||||
@TableField(exist = false)
|
||||
private String fileName;
|
||||
@TableField(exist = false)
|
||||
private String cover;
|
||||
}
|
||||
|
|
@ -1,12 +1,16 @@
|
|||
package com.multictrl.modules.business.service;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.multictrl.common.page.PageData;
|
||||
import com.multictrl.common.service.CrudService;
|
||||
import com.multictrl.modules.business.dto.FlightTaskDTO;
|
||||
import com.multictrl.modules.business.dto.MediaFileDTO;
|
||||
import com.multictrl.modules.business.entity.FlightTaskEntity;
|
||||
import com.multictrl.modules.business.entity.SrsRecordEntity;
|
||||
import com.multictrl.modules.business.influxdb.UavReport;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 飞行架次
|
||||
|
|
@ -16,6 +20,9 @@ import java.util.List;
|
|||
*/
|
||||
public interface FlightTaskService extends CrudService<FlightTaskEntity, FlightTaskDTO> {
|
||||
|
||||
//分页列表
|
||||
PageData<FlightTaskDTO> pageList(Map<String, Object> params);
|
||||
|
||||
//新增架次信息
|
||||
void addRouteTask(String taskId, String dockSn, Long routeId);//航线任务
|
||||
|
||||
|
|
@ -29,4 +36,13 @@ public interface FlightTaskService extends CrudService<FlightTaskEntity, FlightT
|
|||
|
||||
//获取飞行轨迹
|
||||
List<JSONObject> getFlightTrack(String taskId);
|
||||
|
||||
//获取架次媒体
|
||||
List<MediaFileDTO> getTaskMedia(String taskId);
|
||||
|
||||
//飞行视频
|
||||
List<SrsRecordEntity> getFlightVideo(String taskId);
|
||||
|
||||
//获取上一条任务
|
||||
FlightTaskDTO getPreviousTask(String taskId, String dockSn);
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.multictrl.modules.business.service;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
import com.multictrl.modules.business.dao.SrsRecordDao;
|
||||
import com.multictrl.modules.business.dto.SrsCallBackDTO;
|
||||
import com.multictrl.modules.business.entity.SrsRecordEntity;
|
||||
|
||||
|
|
@ -26,4 +27,7 @@ public interface SrsService {
|
|||
|
||||
//获取飞机推流地址
|
||||
String getUavPushLiveUrl(String dockSn);
|
||||
|
||||
//获取dao
|
||||
SrsRecordDao getDao();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.multictrl.modules.business.service.impl;
|
|||
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.google.common.collect.Maps;
|
||||
|
|
@ -9,20 +10,16 @@ import com.multictrl.common.constant.BusinessConstant;
|
|||
import com.multictrl.common.constant.FlightTaskStatus;
|
||||
import com.multictrl.common.exception.ErrorCode;
|
||||
import com.multictrl.common.exception.RenException;
|
||||
import com.multictrl.common.page.PageData;
|
||||
import com.multictrl.common.service.impl.CrudServiceImpl;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.multictrl.common.utils.CacheUtils;
|
||||
import com.multictrl.common.utils.ConvertUtils;
|
||||
import com.multictrl.common.utils.DateUtils;
|
||||
import com.multictrl.common.utils.Spatial4jUtils;
|
||||
import com.multictrl.common.utils.*;
|
||||
import com.multictrl.modules.business.dao.DockDeviceDao;
|
||||
import com.multictrl.modules.business.dao.FlightTaskDao;
|
||||
import com.multictrl.modules.business.dto.FlightTaskDTO;
|
||||
import com.multictrl.modules.business.dto.MediaFileDTO;
|
||||
import com.multictrl.modules.business.dto.RouteDTO;
|
||||
import com.multictrl.modules.business.entity.DockDeviceEntity;
|
||||
import com.multictrl.modules.business.entity.DockEntity;
|
||||
import com.multictrl.modules.business.entity.FlightTaskEntity;
|
||||
import com.multictrl.modules.business.entity.MediaFileEntity;
|
||||
import com.multictrl.modules.business.entity.*;
|
||||
import com.multictrl.modules.business.influxdb.UavReport;
|
||||
import com.multictrl.modules.business.service.*;
|
||||
import com.multictrl.modules.security.user.SecurityUser;
|
||||
|
|
@ -45,17 +42,44 @@ public class FlightTaskServiceImpl extends CrudServiceImpl<FlightTaskDao, Flight
|
|||
private final InfluxService influxService;
|
||||
private final MediaFileService mediaFileService;
|
||||
private final DockDeviceDao dockDeviceDao;
|
||||
private final SrsService srsService;
|
||||
|
||||
@Override
|
||||
public QueryWrapper<FlightTaskEntity> getWrapper(Map<String, Object> params) {
|
||||
String id = (String) params.get("id");
|
||||
String key = (String) params.get("key");
|
||||
String taskType = (String) params.get("taskType");
|
||||
String routeType = (String) params.get("routeType");
|
||||
String taskStatus = (String) params.get("taskStatus");
|
||||
|
||||
QueryWrapper<FlightTaskEntity> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq(StrUtil.isNotBlank(id), "id", id);
|
||||
wrapper.and(StrUtil.isNotBlank(key), v ->
|
||||
v.like("dock_name", key).or().like("route_name", key));
|
||||
if (StrUtil.isNotBlank(taskType)) {
|
||||
wrapper.eq("task_type", Integer.parseInt(taskType));
|
||||
}
|
||||
if (StrUtil.isNotBlank(taskStatus)) {
|
||||
wrapper.eq("task_status", Integer.parseInt(taskStatus));
|
||||
}
|
||||
wrapper.eq(StrUtil.isNotBlank(routeType), "route_type", routeType);
|
||||
wrapper.orderByDesc("create_date");
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageData<FlightTaskDTO> pageList(Map<String, Object> params) {
|
||||
PageData<FlightTaskDTO> page = page(params);
|
||||
for (FlightTaskDTO dto : page.getList()) {
|
||||
if (dto.getMediaNum() == null || dto.getMediaNum() == 0) {
|
||||
Long mediaNum = mediaFileService.getDao().selectCount(new QueryWrapper<MediaFileEntity>().eq("task_id", dto.getTaskId()));
|
||||
dto.setMediaNum(mediaNum.intValue());
|
||||
}
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRouteTask(String taskId, String dockSn, Long routeId) {
|
||||
FlightTaskEntity entity = new FlightTaskEntity();
|
||||
|
|
@ -221,6 +245,48 @@ public class FlightTaskServiceImpl extends CrudServiceImpl<FlightTaskDao, Flight
|
|||
return filledList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MediaFileDTO> getTaskMedia(String taskId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("taskId", taskId);
|
||||
List<MediaFileDTO> list = mediaFileService.list(params);
|
||||
for (MediaFileDTO dto : list) {
|
||||
String objectKey = dto.getObjectKey();
|
||||
dto.setUrl(BusinessConstant.IMAGE_PATH + BusinessConstant.DOCK_MEDIA_BUCKET + "/" + objectKey);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SrsRecordEntity> getFlightVideo(String taskId) {
|
||||
FlightTaskEntity entity = baseDao.selectById(taskId);
|
||||
QueryWrapper<SrsRecordEntity> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("app", entity.getDockSn());
|
||||
FlightTaskDTO previousTask = this.getPreviousTask(taskId, entity.getDockSn());
|
||||
if (previousTask == null) {
|
||||
wrapper.gt("record_date", DateUtils.getBeforeHour(entity.getCreateDate(), -8));
|
||||
} else {
|
||||
wrapper.between("record_date", DateUtils.getBeforeHour(entity.getCreateDate(), -8),
|
||||
DateUtils.getBeforeHour(previousTask.getCreateDate(), -8));
|
||||
}
|
||||
wrapper.ne("stream", "dock");
|
||||
wrapper.orderByAsc("record_date");
|
||||
List<SrsRecordEntity> list = srsService.getDao().selectList(wrapper);
|
||||
for (SrsRecordEntity srsRecordEntity : list) {
|
||||
srsRecordEntity.setRecordDate(DateUtils.getBeforeHour(srsRecordEntity.getRecordDate(), 8));
|
||||
srsRecordEntity.setUrl(BusinessConstant.VIDEO_PATH + srsRecordEntity.getFile());
|
||||
srsRecordEntity.setCover(BusinessConstant.IMAGE_PATH + getVideoCover(srsRecordEntity.getFile(), srsRecordEntity.getStreamUrl()));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlightTaskDTO getPreviousTask(String taskId, String dockSn) {
|
||||
FlightTaskEntity previousTask = baseDao.getPreviousTask(taskId, dockSn);
|
||||
return ConvertUtils.sourceToTarget(previousTask, FlightTaskDTO.class);
|
||||
}
|
||||
|
||||
//添加dock信息
|
||||
private void addDockInfo(FlightTaskEntity entity, String dockSn) {
|
||||
entity.setDockSn(dockSn);
|
||||
|
|
@ -231,4 +297,13 @@ public class FlightTaskServiceImpl extends CrudServiceImpl<FlightTaskDao, Flight
|
|||
entity.setDockModel(dockEntity.getDockModel());
|
||||
}
|
||||
}
|
||||
|
||||
//使用ffmpeg 用视频提取封面
|
||||
private String getVideoCover(String file, String streamUrl) {
|
||||
String fileName = file.replace("live_record" + streamUrl + "/", "");
|
||||
String videoCoverPath = "live_record" + streamUrl + "/" + FileUtil.getPrefix(fileName) + BusinessConstant.VIDEO_COVER_SUFFIX;
|
||||
FfmpegUtils.generateVideoCover(file, "/" + videoCoverPath);
|
||||
|
||||
return videoCoverPath;
|
||||
}
|
||||
}
|
||||
|
|
@ -23,9 +23,12 @@ public class MediaFileServiceImpl extends CrudServiceImpl<MediaFileDao, MediaFil
|
|||
@Override
|
||||
public QueryWrapper<MediaFileEntity> getWrapper(Map<String, Object> params) {
|
||||
String id = (String) params.get("id");
|
||||
String taskId = (String) params.get("taskId");
|
||||
|
||||
QueryWrapper<MediaFileEntity> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq(StrUtil.isNotBlank(id), "id", id);
|
||||
wrapper.eq(StrUtil.isNotBlank(taskId), "task_id", taskId);
|
||||
wrapper.orderByDesc("created_time");
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,14 +36,19 @@ public class SrsServiceImpl implements SrsService {
|
|||
@Override
|
||||
public void saveSrsRecord(SrsCallBackDTO srsCallBack) {
|
||||
try {
|
||||
if (StrUtil.isNotBlank(srsCallBack.getFile()) && !srsCallBack.getFile().contains("/out")
|
||||
&& !srsCallBack.getFile().contains("/in")) {
|
||||
String callBackFile = srsCallBack.getFile();
|
||||
if (StrUtil.isNotBlank(callBackFile) &&
|
||||
(callBackFile.contains("/dock") || callBackFile.contains("/uav"))) {
|
||||
SrsRecordEntity srsRecordEntity = new SrsRecordEntity();
|
||||
srsRecordEntity.setApp(srsCallBack.getApp());
|
||||
srsRecordEntity.setStream(srsCallBack.getStream());
|
||||
srsRecordEntity.setFile(srsCallBack.getFile());
|
||||
if (callBackFile.startsWith("/")) {
|
||||
srsRecordEntity.setFile(callBackFile.substring(1));
|
||||
} else {
|
||||
srsRecordEntity.setFile(callBackFile);
|
||||
}
|
||||
srsRecordEntity.setStreamUrl(srsCallBack.getStream_url());
|
||||
String file = srsCallBack.getFile();
|
||||
String file = callBackFile;
|
||||
// /live_record/aaa/bbb/2025-04-03_16-33-43-404.mp4
|
||||
String dateTime = (file = file.substring(file.lastIndexOf("/") + 1))
|
||||
.substring(0, file.indexOf("."));
|
||||
|
|
@ -133,4 +138,9 @@ public class SrsServiceImpl implements SrsService {
|
|||
|
||||
return RTMP_PROTOCOL + srsConfig.getIp() + ":" + srsConfig.getRtmpPort() + "/" + dockSn + "/uav?token=" + srsConfig.getRtmpToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SrsRecordDao getDao() {
|
||||
return srsRecordDao;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.multictrl.modules.business.dao.FlightTaskDao">
|
||||
|
||||
<select id="getLatestRouteTask" resultType="com.multictrl.modules.business.entity.FlightTaskEntity">
|
||||
SELECT *
|
||||
FROM bus_flight_task
|
||||
where dock_sn = #{dockSn}
|
||||
order by create_date desc limit 1
|
||||
</select>
|
||||
|
||||
<select id="getPreviousTask" resultType="com.multictrl.modules.business.entity.FlightTaskEntity">
|
||||
SELECT *
|
||||
FROM bus_flight_task
|
||||
WHERE create_date > (SELECT create_date FROM uav_route_task WHERE task_id = #{param1})
|
||||
<if test="param2 != null and param2.trim() != ''">
|
||||
and dock_sn = #{param2}
|
||||
</if>
|
||||
ORDER BY create_date ASC LIMIT 1;
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
@ -55,6 +55,16 @@ cp ./file/wait/wait-for-it.sh /root/dj_multictrl_data/wait/wait-for-it.sh
|
|||
|
||||
mkdir -p /root/dj_multictrl_data/mongodb/data
|
||||
|
||||
mkdir -p /root/dj_multictrl_data/script
|
||||
mkdir -p /root/dj_multictrl_data/script/logs
|
||||
cp ./file/script/cleanup_srs_record_videos.sh /root/dj_multictrl_data/script/
|
||||
chmod +x /root/dj_multictrl_data/script/cleanup_srs_record_videos.sh
|
||||
crontab -l > cron.cron
|
||||
echo '*/30 * * * * /root/dj_multictrl_data/script/cleanup_srs_record_videos.sh' >> cron.cron
|
||||
#echo '0 2 * * * /usr/bin/docker restart aros-api-srs' >> cron.cron
|
||||
#echo '0 */1 * * * /usr/bin/pkill ffmpeg' >> cron.cron
|
||||
crontab cron.cron
|
||||
|
||||
chmod -R 777 /root/dj_multictrl_data
|
||||
|
||||
docker-compose --compatibility up
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#!/bin/bash
|
||||
|
||||
# 配置项
|
||||
TARGET_DIR="/data/dj_multictrl_data/live_record"
|
||||
MAX_SIZE_GB=5
|
||||
LOG_FILE="/root/dj_multictrl_data/script/logs/cleanup.log"
|
||||
|
||||
# 转换为 KB (1GB = 1048576KB)
|
||||
MAX_SIZE_KB=$((MAX_SIZE_GB * 1048576))
|
||||
|
||||
# 获取当前目录总大小(KB)
|
||||
CURRENT_SIZE_KB=$(du -sk "$TARGET_DIR" | cut -f1)
|
||||
|
||||
# 如果超过最大大小,开始清理
|
||||
if [ "$CURRENT_SIZE_KB" -gt "$MAX_SIZE_KB" ]; then
|
||||
echo "$(date): 当前大小 ${CURRENT_SIZE_KB}KB 超过限制 ${MAX_SIZE_KB}KB,开始清理..." >> "$LOG_FILE"
|
||||
|
||||
# 循环删除最旧的文件,直到空间达标
|
||||
while [ "$(du -sk "$TARGET_DIR" | cut -f1)" -gt "$MAX_SIZE_KB" ]; do
|
||||
# 查找整个目录(包括子目录)中最旧的文件
|
||||
OLDEST_FILE=$(find "$TARGET_DIR" -type f -printf '%T+ %p\n' | sort | head -n 1 | cut -d' ' -f2-)
|
||||
|
||||
if [ -n "$OLDEST_FILE" ]; then
|
||||
echo "正在删除最旧的文件: $OLDEST_FILE" >> "$LOG_FILE"
|
||||
rm -f "$OLDEST_FILE"
|
||||
|
||||
# 检查是否删除成功
|
||||
if [ ! -f "$OLDEST_FILE" ]; then
|
||||
echo "删除成功" >> "$LOG_FILE"
|
||||
else
|
||||
echo "删除失败,可能权限不足" >> "$LOG_FILE"
|
||||
break # 避免无限循环
|
||||
fi
|
||||
else
|
||||
echo "没有可删除的文件(可能只剩下空目录)" >> "$LOG_FILE"
|
||||
break
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "$(date): 当前大小 ${CURRENT_SIZE_KB}KB,未超过限制 ${MAX_SIZE_KB}KB" >> "$LOG_FILE"
|
||||
fi
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#!/bin/bash
|
||||
|
||||
# 要检查的目录
|
||||
TARGET_DIR="/data/dj_multictrl_data"
|
||||
|
||||
# 最低剩余容量(单位 GiB)
|
||||
THRESHOLD=50
|
||||
|
||||
# 当空间不足时,每次清理几个文件(按最旧)
|
||||
DELETE_COUNT=5
|
||||
|
||||
# 当前剩余容量(GiB)
|
||||
AVAILABLE=$(df -BG "$TARGET_DIR" | awk 'NR==2 {gsub("G","",$4); print $4}')
|
||||
|
||||
# 日志文件
|
||||
LOG_FILE="/var/log/disk_cleanup.log"
|
||||
|
||||
echo "$(date '+%F %T') 当前剩余空间: ${AVAILABLE}G" >> "$LOG_FILE"
|
||||
|
||||
if [ "$AVAILABLE" -lt "$THRESHOLD" ]; then
|
||||
echo "$(date '+%F %T') 空间低于 ${THRESHOLD}G,开始清理..." >> "$LOG_FILE"
|
||||
|
||||
# 找出最旧的文件并删除
|
||||
find "$TARGET_DIR" -type f -printf "%T@ %p\n" \
|
||||
| sort -n \
|
||||
| head -n "$DELETE_COUNT" \
|
||||
| awk '{print $2}' \
|
||||
| while read FILE; do
|
||||
echo "$(date '+%F %T') 删除文件: $FILE" >> "$LOG_FILE"
|
||||
rm -f "$FILE"
|
||||
done
|
||||
|
||||
echo "$(date '+%F %T') 清理结束" >> "$LOG_FILE"
|
||||
else
|
||||
echo "$(date '+%F %T') 空间充足,无需清理" >> "$LOG_FILE"
|
||||
fi
|
||||
Loading…
Reference in New Issue