From 811b44dae739ad7e1f85e0921f791546f522fb4e Mon Sep 17 00:00:00 2001 From: rusefi Date: Wed, 22 Jul 2020 15:22:56 -0400 Subject: [PATCH] proxy progress --- .../java/com/rusefi/app/AndroidSerial.java | 15 +------ .../binaryprotocol/IncomingDataBuffer.java | 9 ++++- .../src/main/java/com/rusefi/io/IoStream.java | 3 ++ .../rusefi/io/serial/AbstractIoStream.java | 27 +++++++++++++ .../com/rusefi/tools/online/ProxyClient.java | 9 +++-- .../test/java/com/rusefi/FullServerTest.java | 2 + .../src/test/java/com/rusefi/ServerTest.java | 37 +++++++++++++++--- .../main/java/com/rusefi/server/Backend.java | 39 +++++++++++-------- .../java/com/rusefi/ts_plugin/RemoteTab.java | 4 +- 9 files changed, 101 insertions(+), 44 deletions(-) diff --git a/android/app/src/main/java/com/rusefi/app/AndroidSerial.java b/android/app/src/main/java/com/rusefi/app/AndroidSerial.java index f3742b1dfd..629cd0577f 100644 --- a/android/app/src/main/java/com/rusefi/app/AndroidSerial.java +++ b/android/app/src/main/java/com/rusefi/app/AndroidSerial.java @@ -12,16 +12,15 @@ import com.opensr5.io.DataListener; import com.rusefi.binaryprotocol.IncomingDataBuffer; import com.rusefi.dfu.DfuLogic; import com.rusefi.io.ByteReader; -import com.rusefi.io.IoStream; +import com.rusefi.io.serial.AbstractIoStream; import java.io.IOException; import java.util.List; -public class AndroidSerial implements IoStream { +public class AndroidSerial extends AbstractIoStream { private static final int ST_CDC = 0x5740; private final IncomingDataBuffer dataBuffer; - private boolean isClosed; private UsbSerialPort usbSerialPort; static List findUsbSerial(UsbManager usbManager) { @@ -53,16 +52,6 @@ public class AndroidSerial implements IoStream { ByteReader.runReaderLoop("", listener, reader, Logger.CONSOLE); } - @Override - public boolean isClosed() { - return isClosed; - } - - @Override - public void close() { - isClosed = true; - } - @Override public void write(byte[] bytes) throws IOException { usbSerialPort.write(bytes, 1000); diff --git a/java_console/io/src/main/java/com/rusefi/binaryprotocol/IncomingDataBuffer.java b/java_console/io/src/main/java/com/rusefi/binaryprotocol/IncomingDataBuffer.java index e02449fe06..65372d0a0e 100644 --- a/java_console/io/src/main/java/com/rusefi/binaryprotocol/IncomingDataBuffer.java +++ b/java_console/io/src/main/java/com/rusefi/binaryprotocol/IncomingDataBuffer.java @@ -4,12 +4,14 @@ import com.opensr5.Logger; import com.rusefi.Timeouts; import com.rusefi.config.generated.Fields; import com.rusefi.io.IoStream; +import com.rusefi.io.serial.AbstractIoStream; import etch.util.CircularByteBuffer; import net.jcip.annotations.ThreadSafe; import java.io.EOFException; import java.io.IOException; import java.util.Arrays; +import java.util.Objects; import static com.rusefi.binaryprotocol.IoHelper.*; @@ -28,15 +30,17 @@ public class IncomingDataBuffer { */ private final CircularByteBuffer cbb; private final Logger logger; + private final AbstractIoStream.StreamStats streamStats; - public IncomingDataBuffer(Logger logger) { + public IncomingDataBuffer(Logger logger, AbstractIoStream.StreamStats streamStats) { + this.streamStats = Objects.requireNonNull(streamStats, "streamStats"); this.cbb = new CircularByteBuffer(BUFFER_SIZE); this.logger = logger; } public static IncomingDataBuffer createDataBuffer(String loggingPrefix, IoStream stream, Logger logger) { IncomingDataBuffer.loggingPrefix = loggingPrefix; - IncomingDataBuffer incomingData = new IncomingDataBuffer(logger); + IncomingDataBuffer incomingData = new IncomingDataBuffer(logger, stream.getStreamStats()); stream.setInputListener(incomingData::addData); return incomingData; } @@ -71,6 +75,7 @@ public class IncomingDataBuffer { logger.trace(String.format("%x", actualCrc) + " vs " + String.format("%x", packetCrc)); return null; } + streamStats.onPacketArrived(); logger.trace("packet " + Arrays.toString(packet) + ": crc OK"); return packet; diff --git a/java_console/io/src/main/java/com/rusefi/io/IoStream.java b/java_console/io/src/main/java/com/rusefi/io/IoStream.java index 1cd0227003..fdfc27ae8d 100644 --- a/java_console/io/src/main/java/com/rusefi/io/IoStream.java +++ b/java_console/io/src/main/java/com/rusefi/io/IoStream.java @@ -6,6 +6,7 @@ import com.opensr5.io.WriteStream; import com.rusefi.binaryprotocol.BinaryProtocol; import com.rusefi.binaryprotocol.IncomingDataBuffer; import com.rusefi.binaryprotocol.IoHelper; +import com.rusefi.io.serial.AbstractIoStream; import com.rusefi.io.tcp.BinaryProtocolServer; import org.jetbrains.annotations.NotNull; @@ -64,6 +65,8 @@ public interface IoStream extends WriteStream { boolean isClosed(); + AbstractIoStream.StreamStats getStreamStats(); + void close(); String getLoggingPrefix(); diff --git a/java_console/io/src/main/java/com/rusefi/io/serial/AbstractIoStream.java b/java_console/io/src/main/java/com/rusefi/io/serial/AbstractIoStream.java index b89b0c6dde..8e60f71759 100644 --- a/java_console/io/src/main/java/com/rusefi/io/serial/AbstractIoStream.java +++ b/java_console/io/src/main/java/com/rusefi/io/serial/AbstractIoStream.java @@ -5,6 +5,13 @@ import com.rusefi.io.IoStream; public abstract class AbstractIoStream implements IoStream { private boolean isClosed; + protected StreamStats streamStats = new StreamStats(); + + @Override + public StreamStats getStreamStats() { + return streamStats; + } + @Override public void close() { isClosed = true; @@ -14,4 +21,24 @@ public abstract class AbstractIoStream implements IoStream { public boolean isClosed() { return isClosed; } + + public class StreamStats { + private long previousPacketArrivalTime; + private int maxPacketGap; + + /** + * @return maximum time in MS between full valid packets received via this stream + */ + public int getMaxPacketGap() { + return maxPacketGap; + } + + public void onPacketArrived() { + long now = System.currentTimeMillis(); + if (previousPacketArrivalTime != 0) { + maxPacketGap = (int) Math.max(maxPacketGap, now - previousPacketArrivalTime); + } + previousPacketArrivalTime = now; + } + } } diff --git a/java_console/io/src/main/java/com/rusefi/tools/online/ProxyClient.java b/java_console/io/src/main/java/com/rusefi/tools/online/ProxyClient.java index cfaa73e6e3..d81e6a0cbb 100644 --- a/java_console/io/src/main/java/com/rusefi/tools/online/ProxyClient.java +++ b/java_console/io/src/main/java/com/rusefi/tools/online/ProxyClient.java @@ -13,14 +13,15 @@ import java.util.ArrayList; import java.util.List; public class ProxyClient { - public static final String LIST_PATH = "/list_online"; + public static final String LIST_CONTROLLERS_PATH = "/list_controllers"; + public static final String LIST_APPLICATIONS_PATH = "/list_applications"; - public static List getOnlineUsers(int httpPort) throws IOException { - return getOnlineUsers(HttpUtil.RUSEFI_PROXY_JSON_API_PREFIX + ":" + httpPort + LIST_PATH); + public static List getOnlineApplications(int httpPort) throws IOException { + return getOnlineApplications(HttpUtil.RUSEFI_PROXY_JSON_API_PREFIX + ":" + httpPort + LIST_CONTROLLERS_PATH); } @NotNull - public static List getOnlineUsers(String url) throws IOException { + public static List getOnlineApplications(String url) throws IOException { HttpResponse httpResponse = HttpUtil.executeGet(url); List userLists = new ArrayList<>(); diff --git a/java_console/ui/src/test/java/com/rusefi/FullServerTest.java b/java_console/ui/src/test/java/com/rusefi/FullServerTest.java index 8af2ccf4e2..1a559d1e3d 100644 --- a/java_console/ui/src/test/java/com/rusefi/FullServerTest.java +++ b/java_console/ui/src/test/java/com/rusefi/FullServerTest.java @@ -99,6 +99,8 @@ public class FullServerTest { ConfigurationImage clientImage = clientStreamState.getControllerConfiguration(); String clientValue = iniField.getValue(clientImage); assertEquals(Double.toString(value), clientValue); + + // now let's test that application connector would be terminated by server due to inactivity } } diff --git a/java_console/ui/src/test/java/com/rusefi/ServerTest.java b/java_console/ui/src/test/java/com/rusefi/ServerTest.java index 230484f3ec..2bc5bc932c 100644 --- a/java_console/ui/src/test/java/com/rusefi/ServerTest.java +++ b/java_console/ui/src/test/java/com/rusefi/ServerTest.java @@ -1,9 +1,11 @@ package com.rusefi; +import com.opensr5.ConfigurationImage; import com.opensr5.Logger; import com.rusefi.config.generated.Fields; import com.rusefi.io.IoStream; import com.rusefi.io.commands.HelloCommand; +import com.rusefi.proxy.NetworkConnector; import com.rusefi.server.*; import com.rusefi.tools.online.HttpUtil; import com.rusefi.tools.online.ProxyClient; @@ -18,6 +20,7 @@ import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import static com.rusefi.Timeouts.READ_IMAGE_TIMEOUT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -84,10 +87,10 @@ public class ServerTest { assertTrue("onConnected", onConnected.await(30, TimeUnit.SECONDS)); - List clients = backend.getClients(); + List clients = backend.getControllers(); assertEquals(2, clients.size()); - List onlineUsers = ProxyClient.getOnlineUsers(HttpUtil.RUSEFI_PROXY_JSON_PROTOCOL + TestHelper.LOCALHOST + ":" + httpPort + ProxyClient.LIST_PATH); + List onlineUsers = ProxyClient.getOnlineApplications(HttpUtil.RUSEFI_PROXY_JSON_PROTOCOL + TestHelper.LOCALHOST + ":" + httpPort + ProxyClient.LIST_CONTROLLERS_PATH); assertEquals(2, onlineUsers.size()); allConnected.countDown(); @@ -97,17 +100,41 @@ public class ServerTest { } @Test - public void testApplicationTimeout() throws InterruptedException { + public void testApplicationTimeout() throws InterruptedException, IOException { int serverPortForRemoteUsers = 6999; - int serverPortForControllers = 6997; int httpPort = 6998; + int serverPortForControllers = 6997; + int controllerPort = 6996; + int userId = 7; - try (Backend backend = new Backend(createTestUserResolver(), httpPort, logger)) { + + UserDetailsResolver userDetailsResolver = authToken -> new UserDetails(authToken.substring(0, 5), userId); + + CountDownLatch controllerRegistered = new CountDownLatch(1); + try (Backend backend = new Backend(userDetailsResolver, httpPort, logger) { + @Override + protected void onRegister(ControllerConnectionState controllerConnectionState) { + super.onRegister(controllerConnectionState); + controllerRegistered.countDown(); + } + }) { TestHelper.runApplicationConnectorBlocking(backend, serverPortForRemoteUsers); TestHelper.runControllerConnectorBlocking(backend, serverPortForControllers); + // create virtual controller to which "rusEFI network connector" connects to + TestHelper.createVirtualController(controllerPort, new ConfigurationImage(Fields.TOTAL_CONFIG_SIZE), logger); + + // start "rusEFI network connector" to connect controller with backend since in real life controller has only local serial port it does not have network + SessionDetails deviceSessionDetails = NetworkConnector.runNetworkConnector(MockRusEfiDevice.TEST_TOKEN_1, TestHelper.LOCALHOST + ":" + controllerPort, serverPortForControllers); + + assertTrue(controllerRegistered.await(READ_IMAGE_TIMEOUT, TimeUnit.MILLISECONDS)); + + SessionDetails authenticatorSessionDetails = new SessionDetails(deviceSessionDetails.getControllerInfo(), MockRusEfiDevice.TEST_TOKEN_3, deviceSessionDetails.getOneTimeToken()); + ApplicationRequest applicationRequest = new ApplicationRequest(authenticatorSessionDetails, userId); + + } } diff --git a/java_tools/proxy_server/src/main/java/com/rusefi/server/Backend.java b/java_tools/proxy_server/src/main/java/com/rusefi/server/Backend.java index 66495bf163..787711fe8e 100644 --- a/java_tools/proxy_server/src/main/java/com/rusefi/server/Backend.java +++ b/java_tools/proxy_server/src/main/java/com/rusefi/server/Backend.java @@ -35,13 +35,16 @@ public class Backend implements Closeable { public static final String BACKEND_VERSION = "0.0001"; public static final int SERVER_PORT_FOR_CONTROLLERS = 8003; - private final FkRegex showOnlineUsers = new FkRegex(ProxyClient.LIST_PATH, - (Take) req -> getUsersOnline() + private final FkRegex showOnlineControllers = new FkRegex(ProxyClient.LIST_CONTROLLERS_PATH, + (Take) req -> getControllersOnline() + ); + private final FkRegex showOnlineApplications = new FkRegex(ProxyClient.LIST_CONTROLLERS_PATH, + (Take) req -> getControllersOnline() ); private boolean isClosed; // guarded by own monitor - private final Set clients = new HashSet<>(); + private final Set controllers = new HashSet<>(); // guarded by clients private HashMap byId = new HashMap<>(); // private final int clientTimeout; @@ -62,7 +65,7 @@ public class Backend implements Closeable { System.out.println("Starting http backend on " + httpPort); try { new FtBasic( - new TkFork(showOnlineUsers, + new TkFork(showOnlineControllers, new Monitoring(this).showStatistics, new FkRegex(VERSION_PATH, BACKEND_VERSION), new FkRegex("/", new RsHtml("\n" + @@ -70,7 +73,8 @@ public class Backend implements Closeable { "
\n" + "Status\n" + "
\n" + - "List\n" + + "Controllers\n" + + "Applications\n" + "
\n" + "
\n" + "\n")) @@ -121,7 +125,7 @@ public class Backend implements Closeable { ControllerKey controllerKey = new ControllerKey(applicationRequest.getTargetUserId(), applicationRequest.getSessionDetails().getControllerInfo()); ControllerConnectionState state; - synchronized (clients) { + synchronized (controllers) { state = byId.get(controllerKey); } if (state == null) { @@ -178,9 +182,9 @@ public class Backend implements Closeable { } @NotNull - private RsJson getUsersOnline() throws IOException { + private RsJson getControllersOnline() throws IOException { JsonArrayBuilder builder = Json.createArrayBuilder(); - List clients = getClients(); + List clients = getControllers(); for (ControllerConnectionState client : clients) { JsonObject clientObject = Json.createObjectBuilder() @@ -190,6 +194,7 @@ public class Backend implements Closeable { .add(ControllerInfo.VEHICLE_NAME, client.getSessionDetails().getControllerInfo().getVehicleName()) .add(ControllerInfo.ENGINE_MAKE, client.getSessionDetails().getControllerInfo().getEngineMake()) .add(ControllerInfo.ENGINE_CODE, client.getSessionDetails().getControllerInfo().getEngineCode()) + .add("MAX_PACKET_GAP", client.getStream().getStreamStats().getMaxPacketGap()) .build(); builder.add(clientObject); } @@ -219,8 +224,8 @@ public class Backend implements Closeable { public void register(ControllerConnectionState controllerConnectionState) { Objects.requireNonNull(controllerConnectionState.getControllerKey(), "ControllerKey"); - synchronized (clients) { - clients.add(controllerConnectionState); + synchronized (controllers) { + controllers.add(controllerConnectionState); byId.put(controllerConnectionState.getControllerKey(), controllerConnectionState); } onRegister(controllerConnectionState); @@ -231,9 +236,9 @@ public class Backend implements Closeable { public void close(ControllerConnectionState inactiveClient) { inactiveClient.close(); - synchronized (clients) { + synchronized (controllers) { // in case of exception in the initialization phase we do not even add client into the the collection - clients.remove(inactiveClient); + controllers.remove(inactiveClient); byId.remove(inactiveClient.getControllerKey()); } } @@ -243,15 +248,15 @@ public class Backend implements Closeable { isClosed = true; } - public List getClients() { - synchronized (clients) { - return new ArrayList<>(clients); + public List getControllers() { + synchronized (controllers) { + return new ArrayList<>(controllers); } } public int getCount() { - synchronized (clients) { - return clients.size(); + synchronized (controllers) { + return controllers.size(); } } diff --git a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/RemoteTab.java b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/RemoteTab.java index ac8f887e9e..cfeffe11b5 100644 --- a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/RemoteTab.java +++ b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/RemoteTab.java @@ -53,11 +53,9 @@ public class RemoteTab { listDownloadExecutor.execute(new Runnable() { @Override public void run() { - String url = HttpUtil.RUSEFI_PROXY_JSON_API_PREFIX + "/list_online"; - List userDetails; try { - userDetails = ProxyClient.getOnlineUsers(HttpUtil.HTTP_PORT); + userDetails = ProxyClient.getOnlineApplications(HttpUtil.HTTP_PORT); SwingUtilities.invokeLater(new Runnable() { @Override public void run() {