Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-server into master-zy
This commit is contained in:
commit
50129e0e87
@ -1,10 +1,10 @@
|
||||
FROM openjdk:17
|
||||
|
||||
ADD target/xian-ncc-da-0.1.jar app.jar
|
||||
ADD target/xian-ncc-da-0.1.jar xian-ncc-da.jar
|
||||
|
||||
EXPOSE 9000 19000/tcp
|
||||
EXPOSE 9081
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
CMD java -jar -Dfile.encoding=UTF-8 -Dspring.profiles.active=dev /app.jar
|
||||
CMD java -jar -Dfile.encoding=UTF-8 -Dspring.profiles.active=dev /xian-ncc-da.jar
|
||||
|
@ -46,112 +46,115 @@ public enum MessageId {
|
||||
DEPOT_PLAN(0x0007, () -> new DepotPlanResponse()),
|
||||
|
||||
/**
|
||||
* 列车报点
|
||||
* 2.7.8 列车报点消息
|
||||
*/
|
||||
TRAIN_RECORD(0x0008, () -> new TrainRecordResponse()),
|
||||
/**
|
||||
* 列车信息全体
|
||||
* 2.7.9 列车信息全体消息
|
||||
*/
|
||||
TRAIN_INDICATION_INIT(0x0009, () -> new TrainIndicationInitResponse()),
|
||||
/**
|
||||
* 列车信息更新
|
||||
* 2.7.10 列车信息更新消息[增加/更新]
|
||||
*/
|
||||
TRAIN_INDICATION_UPDATE(0x0010, () -> new TrainIndicationUpdateResponse()),
|
||||
/**
|
||||
* 列车信息删除
|
||||
* 2.7.11 列车信息删除消息
|
||||
*/
|
||||
TRAIN_INDICATION_REMOVE(0x0011, () -> new TrainIndicationRemoveResponse()),
|
||||
/**
|
||||
* 统计信息查询
|
||||
* 2.8.1 统计信息查询消息
|
||||
*/
|
||||
REPORT_ASK(0x0012, null),
|
||||
/**
|
||||
* 车组运行里程报告
|
||||
* 2.8.4 车组运行里程报告消息
|
||||
*/
|
||||
GROUP_RUNNING_REPORT(0x0013, () -> new GroupRunningReportResponse()),
|
||||
/**
|
||||
* 司机驾驶里程报告
|
||||
*2.8.5 司机驾驶里程报告消息
|
||||
*/
|
||||
DRIVER_DISTANCE_REPORT(0x0014, () -> new DriverDistanceReportResponse()),
|
||||
/**
|
||||
* 调度日志报告
|
||||
* 2.8.6 调度日志报告消息
|
||||
*/
|
||||
DISPATCHER_REPORT(0x0015, null),
|
||||
DISPATCHER_REPORT(0x0015, ()->new DispatcherReportResponse()),
|
||||
/**
|
||||
* 存备车报告
|
||||
* 2.8.7 存备车报告消息
|
||||
*/
|
||||
GROUP_BAK_REPORT(0x0016, null),
|
||||
GROUP_BAK_REPORT(0x0016, ()->new GroupBakReportResponse()),
|
||||
/**
|
||||
* 列车整备状态报告
|
||||
* 2.8.8 列车整备状态报告消息
|
||||
*/
|
||||
GROUP_STATUS_REPORT(0x0017, null),
|
||||
GROUP_STATUS_REPORT(0x0017, ()->new GroupStatusReportResponse()),
|
||||
/**
|
||||
* 事件及告警信息请求
|
||||
* 2.8.9 事件及告警信息请求消息
|
||||
*/
|
||||
ALARM_ASK(0x0018, () -> new AlarmAckRequest()),
|
||||
/**
|
||||
* 操作命令
|
||||
* 2.8.10 操作命令消息
|
||||
*/
|
||||
ACTION_REPORT(0x0019, () -> new ActionReportResponse()),
|
||||
/**
|
||||
* 列车信息、系统事件
|
||||
* 2.8.11 列车信息、系统事件消息
|
||||
*/
|
||||
ALARM_REPORT(0x0020, () -> new AlarmReportResponse()),
|
||||
/**
|
||||
* 历史运行图申请
|
||||
* 2.8.13 历史运行图申请消息
|
||||
*/
|
||||
LOAD_HISTORY_TG_DATA(0x0021, () -> new LoadHistoryTGDataRequest()),
|
||||
/**
|
||||
* 计划列车运行图消息
|
||||
* 2.8.14 计划列车运行图消息
|
||||
*/
|
||||
INUSED_SCHEDULE(0x0022, () -> new InusedScheduleResponse()),
|
||||
/**
|
||||
* 实际列车运行图消息
|
||||
* 2.8.15 实际列车运行图消息
|
||||
*/
|
||||
HISTORY_SCHEDULE(0x0023, () -> new HistoryScheduleResponse()),
|
||||
/**
|
||||
* 断电续传申请
|
||||
* 2.9.3.1 断点续传申请消息
|
||||
*/
|
||||
Resume_ASK(0x0024, null),
|
||||
/**
|
||||
* 断点续传开始
|
||||
* 2.9.3.2 断点续传开始消息
|
||||
*/
|
||||
Resume_Begin_ACK(0x0025, null),
|
||||
Resume_Begin_ACK(0x0025, ()->new ResumeBeginAckResponse()),
|
||||
/**
|
||||
* 断点续传结束
|
||||
* 2.9.3.4 断点续传结束消息
|
||||
*/
|
||||
Resume_END_ACK(0x0026, null),
|
||||
Resume_END_ACK(0x0026, ()->new ResumeEndAckResponse()),
|
||||
/**
|
||||
* 查询无结果消息
|
||||
* 2.8.12 查询无结果消息
|
||||
*/
|
||||
REPORT_NACK(0x0027, null),
|
||||
/**
|
||||
* 查询结果开始消息
|
||||
* 2.8.2 查询结果开始消息
|
||||
*/
|
||||
REPORT_BEGIN(0x0028, () -> new ReportBeginResponse()),
|
||||
/**
|
||||
* 查询结果结束消息
|
||||
* 2.8.3 查询结果结束消息
|
||||
*/
|
||||
REPORT_END(0x0029, () -> new ReportEndResponse()),
|
||||
/**
|
||||
* 断点续传数据消息
|
||||
* 2.9.3.3 断点续传数据消息
|
||||
*/
|
||||
Resume_DATA(0x0030, null),
|
||||
Resume_DATA(0x0030, ()->new ResumeDataResponse()),
|
||||
/**
|
||||
* 实时报警事件消息
|
||||
* 2.7.12 实时报警事件消息
|
||||
*/
|
||||
MESSAGE_ALARM(0x0031, () -> new MessageAlarmResponse()),
|
||||
/**
|
||||
* 列车阻塞消息
|
||||
* 2.7.13 列车阻塞消息
|
||||
*/
|
||||
TRAIN_BLOCK_INFO(0x0032, () -> new TrainBlockInfoResponse()),
|
||||
/**
|
||||
* 当天计划运行图参数消息
|
||||
* 2.7.14 当天计划运行图参数消息
|
||||
*/
|
||||
INUSED_SCHEDULE_PARAMETER(0x0033, () -> new InUsedScheduleParameterResponse()),
|
||||
;
|
||||
|
||||
int val;
|
||||
public int idValue(){
|
||||
return this.val;
|
||||
}
|
||||
/**
|
||||
* 消息对象创建接口
|
||||
*/
|
||||
@ -167,6 +170,15 @@ public enum MessageId {
|
||||
this.omc = omc;
|
||||
}
|
||||
|
||||
public MessageData create() {
|
||||
return null != this.omc ? this.omc.create() : null;
|
||||
}
|
||||
|
||||
public MessageResponse createResponse() {
|
||||
final MessageData messageData = create();
|
||||
if(null==messageData) return null;
|
||||
return messageData instanceof MessageResponse ? (MessageResponse) messageData : null;
|
||||
}
|
||||
public static MessageId of(int val) {
|
||||
for (MessageId messageId : MessageId.values()) {
|
||||
if (messageId.val == val) {
|
||||
|
@ -9,9 +9,9 @@ import java.util.List;
|
||||
|
||||
public class OccMessageDecoder extends ByteToMessageDecoder {
|
||||
|
||||
final TcpClientConnection connection;
|
||||
final OccTcpClientConnection connection;
|
||||
|
||||
public OccMessageDecoder(TcpClientConnection connection) {
|
||||
public OccMessageDecoder(OccTcpClientConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
|
@ -9,9 +9,9 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
public class OccMessageEncoder extends MessageToByteEncoder<List<MessageData>> {
|
||||
|
||||
final TcpClientConnection connection;
|
||||
final OccTcpClientConnection connection;
|
||||
|
||||
public OccMessageEncoder(TcpClientConnection connection) {
|
||||
public OccMessageEncoder(OccTcpClientConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ public class OccMessageManage implements ApplicationRunner {
|
||||
// 读取数据配置,创建客户端
|
||||
this.registerClient(new XianOccMessagingClient(3, "localhost"));
|
||||
for (XianOccMessagingClient client : this.clientMap.values()) {
|
||||
client.connection.connect();
|
||||
client.connect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,14 +7,13 @@ import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class TcpClientConnection {
|
||||
public class OccTcpClientConnection {
|
||||
|
||||
|
||||
XianOccMessagingClient client;
|
||||
@ -24,11 +23,14 @@ public class TcpClientConnection {
|
||||
|
||||
final EventLoopGroup group;
|
||||
final Bootstrap bootstrap;
|
||||
volatile boolean connected;
|
||||
/**
|
||||
* 连接管道
|
||||
* 连接状态
|
||||
*/
|
||||
volatile boolean connected;
|
||||
Channel channel;
|
||||
/**
|
||||
* 心跳超时重连处理器
|
||||
*/
|
||||
HeartBeatTimeoutHandler timeoutHandler;
|
||||
|
||||
/**
|
||||
@ -36,13 +38,13 @@ public class TcpClientConnection {
|
||||
*/
|
||||
volatile long lastReceiveMessageTime;
|
||||
|
||||
public TcpClientConnection(XianOccMessagingClient client, String host, int port) {
|
||||
public OccTcpClientConnection(XianOccMessagingClient client, String host, int port) {
|
||||
this.client = client;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.group = new NioEventLoopGroup();
|
||||
this.group = new NioEventLoopGroup(1);
|
||||
this.bootstrap = new Bootstrap();
|
||||
TcpClientConnection self = this;
|
||||
OccTcpClientConnection self = this;
|
||||
bootstrap.group(group)
|
||||
.channel(NioSocketChannel.class)
|
||||
.handler(new ChannelInitializer<>() {
|
||||
@ -65,30 +67,28 @@ public class TcpClientConnection {
|
||||
}
|
||||
|
||||
public synchronized void connect() {
|
||||
try {
|
||||
ChannelFuture channelFuture = bootstrap.connect(this.host, this.port);
|
||||
channelFuture.addListener(future1 -> {
|
||||
if (future1.isSuccess()) {
|
||||
log.info("连接到OCC服务: host={}, port={}", this.host, this.port);
|
||||
this.connected = true;
|
||||
log.info("连接到OCC服务: {}", this.hostPortInfo());
|
||||
this.lastReceiveMessageTime = System.currentTimeMillis();
|
||||
this.channel = channelFuture.channel();
|
||||
// 启动心跳超时监测
|
||||
this.timeoutHandler.start();
|
||||
this.connected = true;
|
||||
}
|
||||
});
|
||||
channelFuture.channel().closeFuture().addListener(listener -> {
|
||||
log.info("与服务断连,尝试重连");
|
||||
this.timeoutHandler.stop();
|
||||
if (listener.isSuccess()) {
|
||||
log.info("与服务断连,尝试重连: {}", this.hostPortInfo());
|
||||
this.connected = false;
|
||||
this.channel = null;
|
||||
|
||||
Thread.sleep(3000);
|
||||
connect();
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("与OCC服务连接异常,尝试重连", e);
|
||||
connect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
String hostPortInfo() {
|
||||
return String.format("host=%s, port=%s", this.host, this.port);
|
||||
}
|
||||
|
||||
static class HeartBeatTimeoutHandler {
|
||||
@ -99,34 +99,22 @@ public class TcpClientConnection {
|
||||
final int HeartBeatTimeout = 15 * 1000;
|
||||
static final int Period = 2;
|
||||
|
||||
TcpClientConnection connection;
|
||||
boolean running;
|
||||
OccTcpClientConnection connection;
|
||||
static final ScheduledExecutorService Executor = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
public HeartBeatTimeoutHandler(TcpClientConnection connection) {
|
||||
public HeartBeatTimeoutHandler(OccTcpClientConnection connection) {
|
||||
this.connection = connection;
|
||||
Executor.scheduleAtFixedRate(() -> {
|
||||
if (running) {
|
||||
if (connection.connected) {
|
||||
long ctm = System.currentTimeMillis();
|
||||
if (connection.lastReceiveMessageTime + HeartBeatTimeout < ctm) {
|
||||
log.info("超时未收到OCC消息,尝试重连: host={}, port={}", connection.host,
|
||||
connection.port);
|
||||
log.info("超时未收到OCC消息,尝试断开重连");
|
||||
connection.reconnect();
|
||||
}
|
||||
}
|
||||
}, Period, Period, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
void start() {
|
||||
// log.info("心跳超时监控启动");
|
||||
this.running = true;
|
||||
connection.lastReceiveMessageTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
void stop() {
|
||||
// log.info("心跳超时监控stop");
|
||||
this.running = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -13,51 +13,34 @@ public class XianOccMessagingClient {
|
||||
*/
|
||||
final int lineId;
|
||||
final String host;
|
||||
/**
|
||||
* 实时端口号
|
||||
*/
|
||||
final int realTimePort;
|
||||
/**
|
||||
* 非实时端口号
|
||||
*/
|
||||
final int nonRealTimePort;
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
final int Version = 0x01;
|
||||
/**
|
||||
* 心跳发送间隔
|
||||
*/
|
||||
final int heartbeatInterval = 10;
|
||||
/**
|
||||
* 心跳超时
|
||||
*/
|
||||
final int heartbeatTimeout = 15;
|
||||
|
||||
final TcpClientConnection connection;
|
||||
/**
|
||||
* 实时消息的连接
|
||||
*/
|
||||
private final OccTcpClientConnection rtConnection;
|
||||
/**
|
||||
* 非实时消息的连接
|
||||
*/
|
||||
private final OccTcpClientConnection nrtConnection;
|
||||
|
||||
|
||||
public XianOccMessagingClient(int lineId, String host) {
|
||||
this.host = host;
|
||||
this.lineId = lineId;
|
||||
this.realTimePort = realTimePortBase + lineId;
|
||||
this.nonRealTimePort = nonRealTimePortBase + lineId;
|
||||
// 创建实时消息连接
|
||||
this.connection = new TcpClientConnection(this, host, this.realTimePort);
|
||||
final int realTimePort = realTimePortBase + lineId;
|
||||
final int nonRealTimePort = nonRealTimePortBase + lineId;
|
||||
// 创建实时和非实时消息连接
|
||||
this.rtConnection = new OccTcpClientConnection(this, host, realTimePort);
|
||||
this.nrtConnection = new OccTcpClientConnection(this, host, nonRealTimePort);
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接实时消息服务
|
||||
* 连接OCC服务
|
||||
*/
|
||||
public void rtMessageConnect() {
|
||||
|
||||
public void connect() {
|
||||
// 实时消息连接
|
||||
this.rtConnection.connect();
|
||||
// 非实时消息连接
|
||||
this.nrtConnection.connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接非实时消息服务
|
||||
*/
|
||||
public void nrtMessageConnect() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,4 +24,25 @@ public class DateTimeUtil {
|
||||
buf.writeByte(from.getMinute());
|
||||
buf.writeByte(from.getSecond());
|
||||
}
|
||||
/**
|
||||
* 例如,传送2001年9月21日15时29分30秒,则年、月、日、时、分、秒各单元的值分别为:20、01、9、21、15、29、30
|
||||
*/
|
||||
public static byte[]convert(final LocalDateTime from){
|
||||
final byte[] to = new byte[7];
|
||||
convert(from,to);
|
||||
return to;
|
||||
}
|
||||
/**
|
||||
* 例如,传送2001年9月21日15时29分30秒,则01年、2月、3日、4时、5分、6秒各单元的值分别为:20、01、9、21、15、29、30
|
||||
*/
|
||||
public static LocalDateTime convert(final byte[]from){
|
||||
if (null == from || from.length != 7) throw new RuntimeException("数组from的长度须为7");
|
||||
final int year = Integer.valueOf(String.format("%s%s",String.format("%d",from[0]),String.format("%02d",from[1])));
|
||||
final int month = from[2];
|
||||
final int day = from[3];
|
||||
final int hour = from[4];
|
||||
final int minute = from[5];
|
||||
final int second = from[6];
|
||||
return LocalDateTime.of(year,month,day,hour,minute,second);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,75 @@
|
||||
package club.joylink.xiannccda.ats.message.line3;
|
||||
|
||||
import club.joylink.xiannccda.ats.message.MessageResponse;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 2.8.6 调度日志报告消息
|
||||
*/
|
||||
public class DispatcherReportResponse extends MessageResponse {
|
||||
|
||||
/**
|
||||
* 线路号(2)
|
||||
*/
|
||||
private Short lineId;
|
||||
/**
|
||||
* 查询标识号(2)<br>
|
||||
* 同一时间多个查询的report_id不允许重复,答复消息中的report_id值跟查询消息中的相同
|
||||
*/
|
||||
private Short reportId;
|
||||
/**
|
||||
* 消息总数(2)
|
||||
*/
|
||||
private Short totalMessage;
|
||||
/**
|
||||
* 本消息的顺序号(2)
|
||||
*/
|
||||
private Short messageSequence;
|
||||
/**
|
||||
* 记录条数(2)
|
||||
*/
|
||||
private Short count;
|
||||
/**
|
||||
* 调度日志报告列表
|
||||
*/
|
||||
private List<LogCell> logs;
|
||||
|
||||
@Override
|
||||
public void decode2(ByteBuf buf) throws Exception {
|
||||
this.lineId=buf.readShort();
|
||||
this.reportId=buf.readShort();
|
||||
this.totalMessage=buf.readShort();
|
||||
this.messageSequence=buf.readShort();
|
||||
this.count=buf.readShort();
|
||||
this.logs=new ArrayList<>(this.count);
|
||||
for(int i=0;i<this.count;i++){
|
||||
this.logs.add(new LogCell().decode(buf));
|
||||
}
|
||||
}
|
||||
|
||||
public static class LogCell {
|
||||
|
||||
/**
|
||||
* 日期(7)
|
||||
*/
|
||||
private byte[] reportTime = new byte[7];
|
||||
/**
|
||||
* 调度员(32)
|
||||
*/
|
||||
private byte[] userName = new byte[32];
|
||||
/**
|
||||
* 记录内容(256)
|
||||
*/
|
||||
private byte[] logItem = new byte[256];
|
||||
|
||||
public LogCell decode(final ByteBuf buf) {
|
||||
buf.readBytes(this.reportTime);
|
||||
buf.readBytes(this.userName);
|
||||
buf.readBytes(this.logItem);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package club.joylink.xiannccda.ats.message.line3;
|
||||
|
||||
import club.joylink.xiannccda.ats.message.MessageResponse;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 2.8.7 存备车报告消息
|
||||
*/
|
||||
public class GroupBakReportResponse extends MessageResponse {
|
||||
|
||||
/**
|
||||
* 线路号(2)
|
||||
*/
|
||||
private Short lineId;
|
||||
/**
|
||||
* 查询标识号(2)<br>
|
||||
* 同一时间多个查询的report_id不允许重复,答复消息中的report_id值跟查询消息中的相同
|
||||
*/
|
||||
private Short reportId;
|
||||
/**
|
||||
* 消息总数(2)
|
||||
*/
|
||||
private Short totalMessage;
|
||||
/**
|
||||
* 本消息的顺序号(2)
|
||||
*/
|
||||
private Short messageSequence;
|
||||
/**
|
||||
* 记录条数(2)
|
||||
*/
|
||||
private Short count;
|
||||
/**
|
||||
* 存备车报告列表
|
||||
*/
|
||||
private List<GroupBakCell> groups;
|
||||
|
||||
@Override
|
||||
public void decode2(ByteBuf buf) throws Exception {
|
||||
this.lineId=buf.readShort();
|
||||
this.reportId=buf.readShort();
|
||||
this.totalMessage=buf.readShort();
|
||||
this.messageSequence=buf.readShort();
|
||||
this.count=buf.readShort();
|
||||
this.groups=new ArrayList<>(this.count);
|
||||
for(int i=0;i<this.count;i++){
|
||||
this.groups.add(new GroupBakCell().decode(buf));
|
||||
}
|
||||
}
|
||||
public static class GroupBakCell{
|
||||
/**
|
||||
* 车组号(9)
|
||||
*/
|
||||
private byte[] groupId = new byte[9];
|
||||
/**
|
||||
* 存备车状态(1)<br>
|
||||
* 0x01:上线运营<br>
|
||||
* 0x02:备车<br>
|
||||
* 0x03:维修 <br>
|
||||
*/
|
||||
private byte status;
|
||||
/**
|
||||
* 所处位置(1)<br>
|
||||
* 0x01:车辆段1<br>
|
||||
* 0x02:停车场1<br>
|
||||
* 0x04:车辆段2<br>
|
||||
* 0x08:停车场2<br>
|
||||
*/
|
||||
private byte depot;
|
||||
/**
|
||||
* 所在轨道名称(20)
|
||||
*/
|
||||
private byte[] trackName = new byte[20];
|
||||
|
||||
public GroupBakCell decode(final ByteBuf buf){
|
||||
buf.readBytes(this.groupId);
|
||||
this.status=buf.readByte();
|
||||
this.depot=buf.readByte();
|
||||
buf.readBytes(this.trackName);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package club.joylink.xiannccda.ats.message.line3;
|
||||
|
||||
import club.joylink.xiannccda.ats.message.MessageResponse;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 2.8.8 列车整备状态报告消息
|
||||
*/
|
||||
public class GroupStatusReportResponse extends MessageResponse {
|
||||
|
||||
/**
|
||||
* 线路号(2)
|
||||
*/
|
||||
private Short lineId;
|
||||
/**
|
||||
* 查询标识号(2)<br>
|
||||
* 同一时间多个查询的report_id不允许重复,答复消息中的report_id值跟查询消息中的相同
|
||||
*/
|
||||
private Short reportId;
|
||||
/**
|
||||
* 消息总数(2)
|
||||
*/
|
||||
private Short totalMessage;
|
||||
/**
|
||||
* 本消息的顺序号(2)
|
||||
*/
|
||||
private Short messageSequence;
|
||||
/**
|
||||
* 记录条数(2)
|
||||
*/
|
||||
private Short count;
|
||||
/**
|
||||
* 列车整备状态列表
|
||||
*/
|
||||
private List<GroupStatusCell> groups;
|
||||
|
||||
@Override
|
||||
public void decode2(ByteBuf buf) throws Exception {
|
||||
this.lineId = buf.readShort();
|
||||
this.reportId = buf.readShort();
|
||||
this.totalMessage = buf.readShort();
|
||||
this.messageSequence = buf.readShort();
|
||||
this.count = buf.readShort();
|
||||
this.groups = new ArrayList<>(this.count);
|
||||
for (int i = 0; i < this.count; i++) {
|
||||
this.groups.add(new GroupStatusCell().decode(buf));
|
||||
}
|
||||
}
|
||||
|
||||
public static class GroupStatusCell {
|
||||
|
||||
/**
|
||||
* 车组号(9)
|
||||
*/
|
||||
private byte[] groupId = new byte[9];
|
||||
/**
|
||||
* 列车位置(1)<br>
|
||||
* 0x01:车辆段/停车场<br>
|
||||
* 0x02: 正线<br>
|
||||
*/
|
||||
private byte depot;
|
||||
/**
|
||||
* 整备状态(42)
|
||||
*/
|
||||
private byte[] status = new byte[42];
|
||||
|
||||
public GroupStatusCell decode(final ByteBuf buf) {
|
||||
buf.readBytes(this.groupId);
|
||||
this.depot = buf.readByte();
|
||||
buf.readBytes(this.status);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package club.joylink.xiannccda.ats.message.line3;
|
||||
|
||||
import club.joylink.xiannccda.ats.message.MessageId;
|
||||
import club.joylink.xiannccda.ats.message.MessageRequest;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 2.9.3.1 断点续传申请消息<br>
|
||||
* 时间范围说明:<br>
|
||||
* 申请消息的时间范围(结束时间与开始时间之差)不超过1小时。<br>
|
||||
*/
|
||||
public class ResumeAskRequest extends MessageRequest {
|
||||
|
||||
/**
|
||||
* 线路号(2)
|
||||
*/
|
||||
private Short lineId;
|
||||
/**
|
||||
* 开始时间(7)
|
||||
*/
|
||||
private byte[] beginTime;
|
||||
/**
|
||||
* 结束时间(7)
|
||||
*/
|
||||
private byte[] endTime;
|
||||
|
||||
public ResumeAskRequest(Short lineId, LocalDateTime begin, LocalDateTime end) {
|
||||
super(MessageId.Resume_ASK, 2 + 7 + 7);
|
||||
this.lineId = lineId;
|
||||
this.beginTime = new byte[7];
|
||||
Arrays.fill(this.beginTime, (byte) 0);
|
||||
DateTimeUtil.convert(begin, this.beginTime);
|
||||
this.endTime = new byte[7];
|
||||
Arrays.fill(this.endTime, (byte) 0);
|
||||
DateTimeUtil.convert(end, this.endTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode2(ByteBuf buf) {
|
||||
buf.writeShort(this.lineId);
|
||||
buf.writeBytes(this.beginTime);
|
||||
buf.writeBytes(this.endTime);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package club.joylink.xiannccda.ats.message.line3;
|
||||
|
||||
import club.joylink.xiannccda.ats.message.MessageResponse;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* 2.9.3.2 断点续传开始消息
|
||||
*/
|
||||
public class ResumeBeginAckResponse extends MessageResponse {
|
||||
|
||||
/**
|
||||
* 线路号(2)
|
||||
*/
|
||||
private Short lineId;
|
||||
/**
|
||||
* 开始时间(7)
|
||||
*/
|
||||
private byte[] beginTime = new byte[7];
|
||||
/**
|
||||
* 结束时间(7)
|
||||
*/
|
||||
private byte[] endTime = new byte[7];
|
||||
|
||||
@Override
|
||||
public void decode2(ByteBuf buf) throws Exception {
|
||||
this.lineId = buf.readShort();
|
||||
buf.readBytes(this.beginTime);
|
||||
buf.readBytes(this.endTime);
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package club.joylink.xiannccda.ats.message.line3;
|
||||
|
||||
import club.joylink.xiannccda.ats.message.MessageId;
|
||||
import club.joylink.xiannccda.ats.message.MessageResponse;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 2.9.3.3 断点续传数据消息
|
||||
*/
|
||||
public class ResumeDataResponse extends MessageResponse {
|
||||
|
||||
/**
|
||||
* 线路号(2)
|
||||
*/
|
||||
private Short lineId;
|
||||
/**
|
||||
* 消息总数(2)
|
||||
*/
|
||||
private Short totalMessage;
|
||||
/**
|
||||
* 本消息的顺序号(2)
|
||||
*/
|
||||
private Short messageSequence;
|
||||
/**
|
||||
* 消息message_data的数量(2)
|
||||
*/
|
||||
private Short msgCnt;
|
||||
/**
|
||||
* 补传的消息(全部为响应类消息)。消息格式、内容和本接口协议定义的消息格式一致,时间戳保持与实时发送时的一致
|
||||
*/
|
||||
private List<MessageResponse> messageData;
|
||||
|
||||
@Override
|
||||
public void decode2(ByteBuf buf) throws Exception {
|
||||
this.lineId = buf.readShort();
|
||||
this.totalMessage = buf.readShort();
|
||||
this.messageSequence = buf.readShort();
|
||||
this.msgCnt = buf.readShort();
|
||||
this.messageData = new ArrayList<>(this.msgCnt);
|
||||
//
|
||||
for (int i = 0; i < this.msgCnt; i++) {
|
||||
final int _readIndex = buf.readerIndex();
|
||||
buf.skipBytes(8);
|
||||
final MessageId messageId = MessageId.of(buf.readShort());
|
||||
buf.readerIndex(_readIndex);
|
||||
final MessageResponse messageResponse = messageId.createResponse();
|
||||
messageResponse.decode(buf);
|
||||
this.messageData.add(messageResponse);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package club.joylink.xiannccda.ats.message.line3;
|
||||
|
||||
import club.joylink.xiannccda.ats.message.MessageResponse;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* 2.9.3.4 断点续传结束消息
|
||||
*/
|
||||
public class ResumeEndAckResponse extends MessageResponse {
|
||||
/**
|
||||
* 线路号(2)
|
||||
*/
|
||||
private Short lineId;
|
||||
/**
|
||||
* 开始时间(7)
|
||||
*/
|
||||
private byte[] beginTime = new byte[7];
|
||||
/**
|
||||
* 结束时间(7)
|
||||
*/
|
||||
private byte[] endTime = new byte[7];
|
||||
@Override
|
||||
public void decode2(ByteBuf buf) throws Exception {
|
||||
this.lineId = buf.readShort();
|
||||
buf.readBytes(this.beginTime);
|
||||
buf.readBytes(this.endTime);
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@ import club.joylink.xiannccda.exception.BusinessException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ProblemDetail;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
@ -20,6 +22,15 @@ public class ResponseExceptionHandler {
|
||||
return problemDetail;
|
||||
}
|
||||
|
||||
@ExceptionHandler({HttpMessageNotReadableException.class, MethodArgumentNotValidException.class})
|
||||
public ProblemDetail messageReadExceptionHandler(Exception e) {
|
||||
log.error("客户端参数异常", e);
|
||||
ProblemDetail problemDetail = ProblemDetail.forStatus(HttpStatus.PAYMENT_REQUIRED);
|
||||
problemDetail.setProperty("code", HttpStatus.PAYMENT_REQUIRED);
|
||||
problemDetail.setTitle(e.getMessage());
|
||||
return problemDetail;
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统未处理异常捕获
|
||||
*
|
||||
|
@ -5,14 +5,14 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 前端控制器
|
||||
* 线路信息 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author walker-sheng
|
||||
* @since 2023-06-06
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/lineInfo")
|
||||
@RequestMapping("/api/lineInfo")
|
||||
public class LineInfoController {
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package club.joylink.xiannccda.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 发布图形界面 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author walker-sheng
|
||||
* @since 2023-06-08
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/publishedGi")
|
||||
public class PublishedGiController {
|
||||
|
||||
}
|
@ -21,7 +21,7 @@ import lombok.experimental.Accessors;
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@Schema(name = "Drafting", description = "$!{table.comment}")
|
||||
@Schema(name = "Drafting", description = "图形界面草稿数据")
|
||||
public class Drafting {
|
||||
|
||||
@Schema(description = "id")
|
||||
@ -32,6 +32,10 @@ public class Drafting {
|
||||
@NotBlank(message = "草稿图名称不能为空", groups = {Creation.class, SaveAs.class})
|
||||
private String name;
|
||||
|
||||
@Schema(description = "草稿图类型", example = "Line/LineNetwork")
|
||||
@NotBlank(message = "草稿图类型不能为空", groups = {Creation.class})
|
||||
private String type;
|
||||
|
||||
@Schema(description = "绘图数据")
|
||||
@NotNull(message = "数据不能为空", groups = {SaveData.class, SaveAs.class})
|
||||
private byte[] proto;
|
||||
|
@ -21,7 +21,7 @@ import lombok.experimental.Accessors;
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("line_info")
|
||||
@Schema(name = "LineInfo", description = "$!{table.comment}")
|
||||
@Schema(name = "LineInfo", description = "线路信息数据")
|
||||
public class LineInfo {
|
||||
|
||||
@Schema(description = "id")
|
||||
|
59
src/main/java/club/joylink/xiannccda/entity/PublishedGi.java
Normal file
59
src/main/java/club/joylink/xiannccda/entity/PublishedGi.java
Normal file
@ -0,0 +1,59 @@
|
||||
package club.joylink.xiannccda.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.time.LocalDateTime;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author walker-sheng
|
||||
* @since 2023-06-08
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("published_gi")
|
||||
@Schema(name = "PublishedGi", description = "发布的图形界面数据")
|
||||
public class PublishedGi {
|
||||
|
||||
@Schema(description = "id")
|
||||
private Integer id;
|
||||
|
||||
@Schema(description = "发布图形界面名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "图形界面类型")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "关联的线路号(line_info表中line_id字段)")
|
||||
private Integer lineId;
|
||||
|
||||
@Schema(description = "图形界面数据")
|
||||
private byte[] proto;
|
||||
|
||||
@Schema(description = "发布用户id")
|
||||
private Integer userId;
|
||||
|
||||
@Schema(description = "发布时间")
|
||||
private LocalDateTime publishAt;
|
||||
|
||||
public static final String ID = "id";
|
||||
|
||||
public static final String NAME = "name";
|
||||
|
||||
public static final String TYPE = "type";
|
||||
|
||||
public static final String LINE_ID = "line_id";
|
||||
|
||||
public static final String PROTO = "proto";
|
||||
|
||||
public static final String USER_ID = "user_id";
|
||||
|
||||
public static final String PUBLISH_AT = "publish_at";
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package club.joylink.xiannccda.mapper;
|
||||
|
||||
import club.joylink.xiannccda.entity.PublishedGi;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author walker-sheng
|
||||
* @since 2023-06-08
|
||||
*/
|
||||
@Mapper
|
||||
public interface PublishedGiMapper extends BaseMapper<PublishedGi> {
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
<?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="club.joylink.xiannccda.mapper.PublishedGiMapper">
|
||||
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="BaseResultMap" type="club.joylink.xiannccda.entity.PublishedGi">
|
||||
<id column="id" property="id" />
|
||||
<result column="name" property="name" />
|
||||
<result column="type" property="type" />
|
||||
<result column="line_id" property="lineId" />
|
||||
<result column="proto" property="proto" />
|
||||
<result column="user_id" property="userId" />
|
||||
<result column="publish_at" property="publishAt" />
|
||||
</resultMap>
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, name, type, line_id, proto, user_id, publish_at
|
||||
</sql>
|
||||
|
||||
</mapper>
|
@ -0,0 +1,16 @@
|
||||
package club.joylink.xiannccda.repository;
|
||||
|
||||
import club.joylink.xiannccda.entity.PublishedGi;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author walker-sheng
|
||||
* @since 2023-06-08
|
||||
*/
|
||||
public interface IPublishedGiRepository extends IService<PublishedGi> {
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package club.joylink.xiannccda.repository.impl;
|
||||
|
||||
import club.joylink.xiannccda.entity.PublishedGi;
|
||||
import club.joylink.xiannccda.mapper.PublishedGiMapper;
|
||||
import club.joylink.xiannccda.repository.IPublishedGiRepository;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author walker-sheng
|
||||
* @since 2023-06-08
|
||||
*/
|
||||
@Service
|
||||
public class PublishedGiRepository extends ServiceImpl<PublishedGiMapper, PublishedGi> implements IPublishedGiRepository {
|
||||
|
||||
}
|
@ -8,4 +8,5 @@ spring:
|
||||
logging:
|
||||
level:
|
||||
root: "info"
|
||||
|
||||
file:
|
||||
path: /usr/local/joylink/logs/xianncc
|
||||
|
@ -14,13 +14,12 @@ import io.netty.handler.logging.LoggingHandler;
|
||||
public class OccServer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
final int PORT = 2603;
|
||||
final int RtPort = 2603;
|
||||
final int NrtPort = 2703;
|
||||
// Configure the server.
|
||||
//创建两个EventLoopGroup对象
|
||||
EventLoopGroup bossGroup = new NioEventLoopGroup(1);//创建boos线程组,用于服务端接受客户端的连接
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();//创建worker线程组,用于进行SocketChannel的数据读写,处理业务逻辑
|
||||
//创建Handler
|
||||
try {
|
||||
//创建ServerBootstrap对象
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
b.group(bossGroup, workerGroup)//设置EventLoopGroup
|
||||
@ -34,20 +33,30 @@ public class OccServer {
|
||||
p.addLast(new OccHandler());
|
||||
}
|
||||
});
|
||||
|
||||
//创建Handler
|
||||
try {
|
||||
// Start the server.
|
||||
//绑定端口,并同步等待成功,即启动服务端
|
||||
ChannelFuture f = b.bind(PORT).addListener(listener -> {
|
||||
ChannelFuture f1 = b.bind(RtPort).addListener(listener -> {
|
||||
if (listener.isSuccess()) {
|
||||
System.out.println("OCC测试服务启动...");
|
||||
System.out.println("OCC测试实时服务启动...");
|
||||
}
|
||||
});
|
||||
//绑定端口,并同步等待成功,即启动服务端
|
||||
ChannelFuture f2 = b.bind(NrtPort).addListener(listener -> {
|
||||
if (listener.isSuccess()) {
|
||||
System.out.println("OCC测试非实时服务启动...");
|
||||
}
|
||||
});
|
||||
|
||||
// Wait until the server socket is closed.
|
||||
//监听服务端关闭,并阻塞等待
|
||||
//这里并不是关闭服务器,而是“监听”服务端关闭
|
||||
f.channel().closeFuture().addListener(listener -> {
|
||||
System.out.println("OCC测试服务关闭");
|
||||
f1.channel().closeFuture().addListener(listener -> {
|
||||
System.out.println("OCC测试实时服务关闭");
|
||||
});
|
||||
f2.channel().closeFuture().addListener(listener -> {
|
||||
System.out.println("OCC测试非实时服务关闭");
|
||||
}).sync();
|
||||
} catch (Exception e) {
|
||||
System.err.println("OCC测试服务异常");
|
||||
|
@ -0,0 +1,38 @@
|
||||
package club.joylink.xiannccda.protocal.x;
|
||||
|
||||
import club.joylink.xiannccda.ats.message.MessageId;
|
||||
import club.joylink.xiannccda.ats.message.line3.DateTimeUtil;
|
||||
import club.joylink.xiannccda.ats.message.line3.DispatcherReportResponse;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class TestDispatcherReportResponse {
|
||||
public static void main(String[]args){
|
||||
final DispatcherReportResponse response = new DispatcherReportResponse();
|
||||
final ByteBufAllocator allocator = UnpooledByteBufAllocator.DEFAULT;
|
||||
final ByteBuf body = allocator.buffer(1024);
|
||||
body.writeInt((int) (System.currentTimeMillis() / 1000));
|
||||
body.writeShort(0xff);
|
||||
body.writeShort(MessageId.DISPATCHER_REPORT.idValue());
|
||||
body.writeShort(3);
|
||||
body.writeShort(110);
|
||||
body.writeShort(2);
|
||||
body.writeShort(1);
|
||||
body.writeShort(2);//Count
|
||||
body.readBytes(DateTimeUtil.convert(LocalDateTime.now()));
|
||||
//
|
||||
final byte[]userName = new byte[32];
|
||||
Arrays.fill(userName, (byte) '\0');
|
||||
final ByteBuf userNameBuf = Unpooled.wrappedBuffer(userName);
|
||||
userNameBuf.readBytes("调度员1".getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
Subproject commit 86de0cff9ee560f0c7e670184d5baccfdb28ee44
|
||||
Subproject commit 2e001eddeeeaea3aa9c607df72d2196572a717da
|
Loading…
Reference in New Issue
Block a user