Skip to content

Commit

Permalink
Merge branch 'traccar:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
gpproton authored Jan 3, 2024
2 parents 7740679 + 4959d90 commit aa1b994
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 125 deletions.
6 changes: 5 additions & 1 deletion src/main/java/org/traccar/BasePipelineFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,11 @@ protected void initChannel(Channel channel) {
pipeline.addLast(handler);
}
pipeline.addLast(new NetworkMessageHandler());
pipeline.addLast(new StandardLoggingHandler(protocol));

var loggingHandler = new StandardLoggingHandler(protocol);
injector.injectMembers(loggingHandler);
pipeline.addLast(loggingHandler);

if (!connector.isDatagram() && !config.getBoolean(Keys.SERVER_INSTANT_ACKNOWLEDGEMENT)) {
pipeline.addLast(new AcknowledgementHandler());
}
Expand Down
40 changes: 28 additions & 12 deletions src/main/java/org/traccar/api/AsyncSocket.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,16 +22,17 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.helper.model.PositionUtil;
import org.traccar.session.ConnectionManager;
import org.traccar.model.Device;
import org.traccar.model.Event;
import org.traccar.model.LogRecord;
import org.traccar.model.Position;
import org.traccar.session.ConnectionManager;
import org.traccar.storage.Storage;
import org.traccar.storage.StorageException;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.UpdateListener {
Expand All @@ -41,12 +42,15 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U
private static final String KEY_DEVICES = "devices";
private static final String KEY_POSITIONS = "positions";
private static final String KEY_EVENTS = "events";
private static final String KEY_LOGS = "logs";

private final ObjectMapper objectMapper;
private final ConnectionManager connectionManager;
private final Storage storage;
private final long userId;

private boolean includeLogs;

public AsyncSocket(ObjectMapper objectMapper, ConnectionManager connectionManager, Storage storage, long userId) {
this.objectMapper = objectMapper;
this.connectionManager = connectionManager;
Expand Down Expand Up @@ -75,30 +79,42 @@ public void onWebSocketClose(int statusCode, String reason) {
connectionManager.removeListener(userId, this);
}

@Override
public void onWebSocketText(String message) {
super.onWebSocketText(message);

try {
includeLogs = objectMapper.readTree(message).get("logs").asBoolean();
} catch (JsonProcessingException e) {
LOGGER.warn("Socket JSON parsing error", e);
}
}

@Override
public void onKeepalive() {
sendData(new HashMap<>());
}

@Override
public void onUpdateDevice(Device device) {
Map<String, Collection<?>> data = new HashMap<>();
data.put(KEY_DEVICES, Collections.singletonList(device));
sendData(data);
sendData(Map.of(KEY_DEVICES, List.of(device)));
}

@Override
public void onUpdatePosition(Position position) {
Map<String, Collection<?>> data = new HashMap<>();
data.put(KEY_POSITIONS, Collections.singletonList(position));
sendData(data);
sendData(Map.of(KEY_POSITIONS, List.of(position)));
}

@Override
public void onUpdateEvent(Event event) {
Map<String, Collection<?>> data = new HashMap<>();
data.put(KEY_EVENTS, Collections.singletonList(event));
sendData(data);
sendData(Map.of(KEY_EVENTS, List.of(event)));
}

@Override
public void onUpdateLog(LogRecord record) {
if (includeLogs) {
sendData(Map.of(KEY_LOGS, List.of(record)));
}
}

private void sendData(Map<String, Collection<?>> data) {
Expand Down
65 changes: 35 additions & 30 deletions src/main/java/org/traccar/handler/StandardLoggingHandler.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2019 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,68 +20,73 @@
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import jakarta.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.NetworkMessage;
import org.traccar.helper.NetworkUtil;
import org.traccar.model.LogRecord;
import org.traccar.session.ConnectionManager;

import java.net.InetSocketAddress;
import java.net.SocketAddress;

public class StandardLoggingHandler extends ChannelDuplexHandler {

private static final Logger LOGGER = LoggerFactory.getLogger(StandardLoggingHandler.class);

private final String protocol;
private ConnectionManager connectionManager;

public StandardLoggingHandler(String protocol) {
this.protocol = protocol;
}

@Inject
public void setConnectionManager(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;
}

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log(ctx, false, msg);
LogRecord record = createLogRecord(msg);
log(ctx, false, record);
super.channelRead(ctx, msg);
if (record != null) {
connectionManager.updateLog(record);
}
}

@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
log(ctx, true, msg);
log(ctx, true, createLogRecord(msg));
super.write(ctx, msg, promise);
}

public void log(ChannelHandlerContext ctx, boolean downstream, Object o) {
if (o instanceof NetworkMessage) {
NetworkMessage networkMessage = (NetworkMessage) o;
private LogRecord createLogRecord(Object msg) {
if (msg instanceof NetworkMessage) {
NetworkMessage networkMessage = (NetworkMessage) msg;
if (networkMessage.getMessage() instanceof ByteBuf) {
log(ctx, downstream, networkMessage.getRemoteAddress(), (ByteBuf) networkMessage.getMessage());
LogRecord record = new LogRecord();
record.setAddress((InetSocketAddress) networkMessage.getRemoteAddress());
record.setProtocol(protocol);
record.setData(ByteBufUtil.hexDump((ByteBuf) networkMessage.getMessage()));
return record;
}
} else if (o instanceof ByteBuf) {
log(ctx, downstream, ctx.channel().remoteAddress(), (ByteBuf) o);
}
return null;
}

public void log(ChannelHandlerContext ctx, boolean downstream, SocketAddress remoteAddress, ByteBuf buf) {
StringBuilder message = new StringBuilder();

message.append("[").append(NetworkUtil.session(ctx.channel())).append(": ");
message.append(protocol);
if (downstream) {
message.append(" > ");
} else {
message.append(" < ");
private void log(ChannelHandlerContext ctx, boolean downstream, LogRecord record) {
if (record != null) {
StringBuilder message = new StringBuilder();
message.append("[").append(NetworkUtil.session(ctx.channel())).append(": ");
message.append(protocol);
message.append(downstream ? " > " : " < ");
message.append(record.getAddress().getHostString());
message.append("] ");
message.append(record.getData());
LOGGER.info(message.toString());
}

if (remoteAddress instanceof InetSocketAddress) {
message.append(((InetSocketAddress) remoteAddress).getHostString());
} else {
message.append("unknown");
}
message.append("] ");

message.append(ByteBufUtil.hexDump(buf));

LOGGER.info(message.toString());
}

}
79 changes: 79 additions & 0 deletions src/main/java/org/traccar/model/LogRecord.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.model;

import com.fasterxml.jackson.annotation.JsonIgnore;

import java.net.InetSocketAddress;

public class LogRecord {

private InetSocketAddress address;

public void setAddress(InetSocketAddress address) {
this.address = address;
}

@JsonIgnore
public InetSocketAddress getAddress() {
return address;
}

public String getHost() {
return address.getHostString();
}

private String protocol;

public String getProtocol() {
return protocol;
}

public void setProtocol(String protocol) {
this.protocol = protocol;
}

private String uniqueId;

public String getUniqueId() {
return uniqueId;
}

public void setUniqueId(String uniqueId) {
this.uniqueId = uniqueId;
}

private long deviceId;

public long getDeviceId() {
return deviceId;
}

public void setDeviceId(long deviceId) {
this.deviceId = deviceId;
}

private String data;

public String getData() {
return data;
}

public void setData(String data) {
this.data = data;
}

}
18 changes: 11 additions & 7 deletions src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1405,15 +1405,19 @@ private Object decodeOther(Channel channel, SocketAddress remoteAddress, String
.number("(d{15}|x{14}),") // imei
.any()
.text(",")
.number("(d{1,2})?,") // hdop
.number("(d{1,3}.d)?,") // speed
.number("(d{1,3})?,") // course
.number("(-?d{1,5}.d)?,") // altitude
.number("(-?d{1,3}.d{6})?,") // longitude
.number("(-?d{1,2}.d{6})?,") // latitude
.number("(d{1,2}),") // hdop
.groupBegin()
.number("(d{1,3}.d),") // speed
.number("(d{1,3}),") // course
.number("(-?d{1,5}.d),") // altitude
.number("(-?d{1,3}.d{6}),") // longitude
.number("(-?d{1,2}.d{6}),") // latitude
.number("(dddd)(dd)(dd)") // date (yyyymmdd)
.number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
.number("(dd)(dd)(dd)") // time (hhmmss)
.text(",")
.or()
.text(",,,,,,")
.groupEnd()
.number("(d+),") // mcc
.number("(d+),") // mnc
.number("(x+),") // lac
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,10 @@ private String decodeAlarm(long value) {
if (BitUtil.check(value, 8)) {
return Position.ALARM_POWER_OFF;
}
if (BitUtil.check(value, 17)) {
if (BitUtil.check(value, 15)) {
return Position.ALARM_VIBRATION;
}
if (BitUtil.check(value, 16) || BitUtil.check(value, 17)) {
return Position.ALARM_TAMPERING;
}
if (BitUtil.check(value, 20)) {
Expand All @@ -140,7 +143,7 @@ private String decodeAlarm(long value) {
if (BitUtil.check(value, 28)) {
return Position.ALARM_MOVEMENT;
}
if (BitUtil.check(value, 29)) {
if (BitUtil.check(value, 29) || BitUtil.check(value, 30)) {
return Position.ALARM_ACCIDENT;
}
return null;
Expand Down Expand Up @@ -488,6 +491,14 @@ private Position decodeLocation(DeviceSession deviceSession, ByteBuf buf) {
position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 10);
buf.readUnsignedByte(); // reserved
break;
case 0x57:
int alarm = buf.readUnsignedShort();
position.set(Position.KEY_ALARM, BitUtil.check(alarm, 8) ? Position.ALARM_ACCELERATION : null);
position.set(Position.KEY_ALARM, BitUtil.check(alarm, 9) ? Position.ALARM_BRAKING : null);
position.set(Position.KEY_ALARM, BitUtil.check(alarm, 10) ? Position.ALARM_CORNERING : null);
buf.readUnsignedShort(); // external switch state
buf.skipBytes(4); // reserved
break;
case 0x60:
int event = buf.readUnsignedShort();
position.set(Position.KEY_EVENT, event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,9 @@ private List<Position> decodeBinaryE(Channel channel, SocketAddress remoteAddres
case 0xA2:
position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedIntLE() * 0.01);
break;
case 0xFEF4:
position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 60000);
break;
default:
buf.readUnsignedIntLE();
break;
Expand Down
Loading

0 comments on commit aa1b994

Please sign in to comment.