From c927be5b135a154ef63d3ba326a3ed48933903bb Mon Sep 17 00:00:00 2001 From: Jesse Hills Date: Wed, 31 Jul 2019 09:45:54 +1200 Subject: Add leafspy app protocol and decoder --- setup/default.xml | 1 + .../java/org/traccar/protocol/LeafSpyProtocol.java | 40 ++++++ .../traccar/protocol/LeafSpyProtocolDecoder.java | 146 +++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/LeafSpyProtocol.java create mode 100644 src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java diff --git a/setup/default.xml b/setup/default.xml index 3d968397f..bddface92 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -269,5 +269,6 @@ 5190 5191 5192 + 5193 diff --git a/src/main/java/org/traccar/protocol/LeafSpyProtocol.java b/src/main/java/org/traccar/protocol/LeafSpyProtocol.java new file mode 100644 index 000000000..05f63a2d7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/LeafSpyProtocol.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 Jesse Hills (jesserockz@gmail.com) + * + * 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.protocol; + +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class LeafSpyProtocol extends BaseProtocol { + + public LeafSpyProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(16384)); + pipeline.addLast(new LeafSpyProtocolDecoder(LeafSpyProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java b/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java new file mode 100644 index 000000000..434c8a858 --- /dev/null +++ b/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java @@ -0,0 +1,146 @@ +/* + * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 Jesse Hills (jesserockz@gmail.com) + * + * 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.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.QueryStringDecoder; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateUtil; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; +import org.traccar.NetworkMessage; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Map; + +public class LeafSpyProtocolDecoder extends BaseHttpProtocolDecoder { + + public LeafSpyProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + QueryStringDecoder decoder = new QueryStringDecoder(request.uri()); + Map> params = decoder.parameters(); + if (params.isEmpty()) { + decoder = new QueryStringDecoder(request.content().toString(StandardCharsets.US_ASCII), false); + params = decoder.parameters(); + } + + Position position = new Position(getProtocolName()); + position.setValid(true); + + for (Map.Entry> entry : params.entrySet()) { + for (String value : entry.getValue()) { + switch (entry.getKey()) { + case "pass": + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, value); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + break; + case "Lat": + position.setLatitude(Double.parseDouble(value)); + break; + case "Long": + position.setLongitude(Double.parseDouble(value)); + break; + case "RPM": + position.set(Position.KEY_RPM, Integer.parseInt(value)); + position.setSpeed(convertSpeed(Double.parseDouble(value) / 63, "kmh")); + break; + case "Elv": + position.setAltitude(Double.parseDouble(value)); + break; + case "DevBat": + position.set(Position.KEY_BATTERY_LEVEL, Double.parseDouble(value)); + break; + case "user": + position.set(Position.KEY_DRIVER_UNIQUE_ID, value); + break; + case "SOC": + position.set(Position.KEY_CHARGE, Double.parseDouble(value)); + break; + case "Odo": + position.set(Position.KEY_OBD_ODOMETER, Integer.parseInt(value)); + break; + default: + try { + position.set(entry.getKey(), Double.parseDouble(value)); + } catch (NumberFormatException e) { + switch (value) { + case "true": + position.set(entry.getKey(), true); + break; + case "false": + position.set(entry.getKey(), false); + break; + default: + position.set(entry.getKey(), value); + break; + } + } + break; + } + } + } + + if (position.getFixTime() == null) { + position.setTime(new Date()); + } + + if (position.getLatitude() == 0 && position.getLongitude() == 0) { + getLastLocation(position, position.getDeviceTime()); + } + + if (position.getDeviceId() != 0) { + HttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.OK, + Unpooled.copiedBuffer("\"status\":\"0\"", StandardCharsets.US_ASCII)); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + return position; + } else { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + } + +} -- cgit v1.2.3