package com.doumee.jtt808.web.service;
|
|
import io.netty.buffer.ByteBuf;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Service;
|
import org.yzh.commons.util.DateUtils;
|
import org.yzh.commons.util.IOUtils;
|
import org.yzh.commons.util.StrUtils;
|
import org.yzh.protocol.jsatl12.DataPacket;
|
import org.yzh.protocol.jsatl12.T1210;
|
import org.yzh.protocol.jsatl12.T1211;
|
import org.yzh.protocol.t808.T0200;
|
import org.yzh.protocol.t808.T0801;
|
import com.doumee.jtt808.web.model.entity.DeviceDO;
|
import com.doumee.jtt808.web.model.enums.SessionKey;
|
|
import java.io.*;
|
import java.nio.ByteBuffer;
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.Comparator;
|
import java.util.List;
|
|
|
@Service
|
public class FileService {
|
|
private static final Logger log = LoggerFactory.getLogger(FileService.class.getSimpleName());
|
|
private static final Comparator<long[]> comparator = Comparator.comparingLong((long[] a) -> a[0]).thenComparingLong(a -> a[1]);
|
|
@Value("${jt-server.alarm-file.path}")
|
private String workDirPath;
|
|
@Value("${jt-server.jt808.media-file.path}")
|
private String mediaFileRoot;
|
|
private String getDir(T1210 alarmId) {
|
StringBuilder sb = new StringBuilder(80);
|
sb.append(workDirPath).append('/');
|
sb.append(alarmId.getClientId()).append('_');
|
DateUtils.yyMMddHHmmss.formatTo(alarmId.getDateTime(), sb);
|
sb.append('_').append(alarmId.getSerialNo()).append('/');
|
return sb.toString();
|
}
|
|
/** 创建报警目录及 附件列表日志 */
|
public void createDir(T1210 alarmId) {
|
String dirPath = getDir(alarmId);
|
new File(dirPath).mkdirs();
|
|
List<T1210.Item> items = alarmId.getItems();
|
StringBuilder fileList = new StringBuilder(items.size() * 50);
|
fileList.append(dirPath).append(IOUtils.Separator);
|
|
for (T1210.Item item : items)
|
fileList.append(item.getName()).append('\t').append(item.getSize()).append(IOUtils.Separator);
|
|
IOUtils.write(fileList.toString(), new File(dirPath, "fs.txt"));
|
}
|
|
/** 将数据块写入到报警文件,并记录日志 */
|
public void writeFile(T1210 alarmId, DataPacket fileData) {
|
String dir = getDir(alarmId);
|
String name = dir + fileData.getName().trim();
|
|
int offset = fileData.getOffset();
|
int length = fileData.getLength();
|
|
byte[] buffer = ByteBuffer.allocate(8)
|
.putInt(offset).putInt(length).array();
|
|
RandomAccessFile file = null;
|
FileOutputStream filelog = null;
|
ByteBuf data = fileData.getData();
|
try {
|
file = new RandomAccessFile(name + ".tmp", "rw");
|
filelog = new FileOutputStream(name + ".log", true);
|
|
data.readBytes(file.getChannel(), offset, data.readableBytes());
|
filelog.write(buffer);
|
} catch (IOException e) {
|
log.error("写入报警文件", e);
|
} finally {
|
IOUtils.close(file, filelog);
|
}
|
}
|
|
public void writeFileSingle(T1210 alarmId, DataPacket fileData) {
|
String dir = getDir(alarmId);
|
String name = dir + fileData.getName().trim();
|
|
int offset = fileData.getOffset();
|
|
RandomAccessFile file = null;
|
ByteBuf data = fileData.getData();
|
try {
|
file = new RandomAccessFile(name, "rw");
|
data.readBytes(file.getChannel(), offset, data.readableBytes());
|
} catch (IOException e) {
|
log.error("写入报警文件", e);
|
} finally {
|
IOUtils.close(file);
|
}
|
}
|
|
/** 根据日志检查文件完整性,并返回缺少的数据块信息 */
|
public int[] checkFile(T1210 alarmId, T1211 fileInfo) {
|
String dir = getDir(alarmId);
|
File logFile = new File(dir + fileInfo.getName() + ".log");
|
|
byte[] bytes;
|
FileInputStream in = null;
|
try {
|
in = new FileInputStream(logFile);
|
bytes = new byte[in.available()];
|
in.read(bytes);
|
} catch (FileNotFoundException e) {
|
return null;
|
} catch (IOException e) {
|
log.error("检查文件完整性", e);
|
return null;
|
} finally {
|
IOUtils.close(in);
|
}
|
|
int size = bytes.length / 8;
|
long[][] items = new long[size + 2][2];
|
items[size + 1][0] = fileInfo.getSize();
|
|
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
for (int i = 1; i <= size; i++) {
|
items[i][0] = buffer.getInt();
|
items[i][1] = buffer.getInt();
|
}
|
|
List<Integer> result = new ArrayList<>(items.length);
|
int len = items.length - 1;
|
Arrays.sort(items, 1, len, comparator);
|
|
for (int i = 0; i < len; ) {
|
long a = items[i][0] + items[i][1];
|
long b = items[++i][0] - a;
|
if (b > 0) {
|
result.add((int) a);
|
result.add((int) b);
|
}
|
}
|
|
if (result.isEmpty()) {
|
File file = new File(dir + fileInfo.getName() + ".tmp");
|
File dest = new File(dir + fileInfo.getName());
|
if (file.renameTo(dest)) {
|
logFile.delete();
|
}
|
return null;
|
}
|
return StrUtils.toArray(result);
|
}
|
|
/** 多媒体数据上传 */
|
public boolean saveMediaFile(T0801 message) {
|
DeviceDO device = SessionKey.getDevice(message.getSession());
|
T0200 location = message.getLocation();
|
|
StringBuilder filename = new StringBuilder(32);
|
filename.append(type(message.getType())).append('_');
|
DateUtils.yyMMddHHmmss.formatTo(location.getDeviceTime(), filename);
|
filename.append('_');
|
filename.append(message.getChannelId()).append('_');
|
filename.append(message.getEvent()).append('_');
|
filename.append(message.getId()).append('.');
|
filename.append(suffix(message.getFormat()));
|
|
String deviceId;
|
if (device == null)
|
deviceId = message.getClientId();
|
else
|
deviceId = device.getDeviceId();
|
|
File dir = new File(mediaFileRoot + '/' + deviceId);
|
dir.mkdirs();
|
|
ByteBuf packet = message.getPacket();
|
FileOutputStream fos = null;
|
try {
|
fos = new FileOutputStream(new File(dir, filename.toString()));
|
packet.readBytes(fos.getChannel(), 0, packet.readableBytes());
|
return true;
|
} catch (IOException e) {
|
log.error("多媒体数据保存失败", e);
|
return false;
|
} finally {
|
IOUtils.close(fos);
|
packet.release();
|
}
|
}
|
|
private static String type(int type) {
|
switch (type) {
|
case 0:
|
return "image";
|
case 1:
|
return "audio";
|
case 2:
|
return "video";
|
default:
|
return "unknown";
|
}
|
}
|
|
private static String suffix(int format) {
|
switch (format) {
|
case 0:
|
return "jpg";
|
case 1:
|
return "tif";
|
case 2:
|
return "mp3";
|
case 3:
|
return "wav";
|
case 4:
|
return "wmv";
|
default:
|
return "bin";
|
}
|
}
|
}
|