diff --git a/java_console/io/src/main/java/com/rusefi/io/tcp/BinaryProtocolProxy.java b/java_console/io/src/main/java/com/rusefi/io/tcp/BinaryProtocolProxy.java index ffc7a46b59..1797ba3a9b 100644 --- a/java_console/io/src/main/java/com/rusefi/io/tcp/BinaryProtocolProxy.java +++ b/java_console/io/src/main/java/com/rusefi/io/tcp/BinaryProtocolProxy.java @@ -16,7 +16,6 @@ import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.net.Socket; -import java.util.concurrent.atomic.AtomicInteger; import static com.devexperts.logging.Logging.getLogging; import static com.rusefi.config.generated.Fields.TS_PROTOCOL; @@ -31,12 +30,12 @@ public class BinaryProtocolProxy { */ public static final int USER_IO_TIMEOUT = 10 * Timeouts.MINUTE; - public static ServerSocketReference createProxy(IoStream targetEcuSocket, int serverProxyPort, AtomicInteger relayCommandCounter) throws IOException { + public static ServerSocketReference createProxy(IoStream targetEcuSocket, int serverProxyPort, ClientApplicationActivityListener clientApplicationActivityListener) throws IOException { CompatibleFunction clientSocketRunnableFactory = clientSocket -> () -> { TcpIoStream clientStream = null; try { clientStream = new TcpIoStream("[[proxy]] ", clientSocket); - runProxy(targetEcuSocket, clientStream, relayCommandCounter, USER_IO_TIMEOUT); + runProxy(targetEcuSocket, clientStream, clientApplicationActivityListener, USER_IO_TIMEOUT); } catch (IOException e) { log.error("BinaryProtocolProxy::run " + e); close(clientStream); @@ -45,7 +44,14 @@ public class BinaryProtocolProxy { return BinaryProtocolServer.tcpServerSocket(serverProxyPort, "proxy", clientSocketRunnableFactory, Listener.empty()); } - public static void runProxy(IoStream targetEcu, IoStream clientStream, AtomicInteger relayCommandCounter, int timeoutMs) throws IOException { + public interface ClientApplicationActivityListener { + ClientApplicationActivityListener VOID = () -> { + }; + + void onActivity(); + } + + public static void runProxy(IoStream targetEcu, IoStream clientStream, ClientApplicationActivityListener listener, int timeoutMs) throws IOException { /* * Each client socket is running on it's own thread */ @@ -60,6 +66,7 @@ public class BinaryProtocolProxy { byte[] packet = clientRequest.getPacket(); if (packet.length > 1 && packet[0] == Fields.TS_ONLINE_PROTOCOL && packet[1] == NetworkConnector.DISCONNECT) throw new IOException("User requested disconnect"); + listener.onActivity(); /** * Two reasons for synchronization: @@ -70,7 +77,6 @@ public class BinaryProtocolProxy { synchronized (targetEcu) { sendToTarget(targetEcu, clientRequest); controllerResponse = targetEcu.readPacket(); - relayCommandCounter.incrementAndGet(); } log.info("Relaying controller response length=" + controllerResponse.getPacket().length); diff --git a/java_console/io/src/main/java/com/rusefi/proxy/client/LocalApplicationProxy.java b/java_console/io/src/main/java/com/rusefi/proxy/client/LocalApplicationProxy.java index ddef9449fe..6cc09abb09 100644 --- a/java_console/io/src/main/java/com/rusefi/proxy/client/LocalApplicationProxy.java +++ b/java_console/io/src/main/java/com/rusefi/proxy/client/LocalApplicationProxy.java @@ -12,7 +12,6 @@ import com.rusefi.io.tcp.BinaryProtocolProxy; import com.rusefi.io.tcp.ServerSocketReference; import com.rusefi.io.tcp.TcpIoStream; import com.rusefi.proxy.NetworkConnector; -import com.rusefi.proxy.NetworkConnectorContext; import com.rusefi.server.ApplicationRequest; import com.rusefi.server.rusEFISSLContext; import com.rusefi.tools.online.HttpUtil; @@ -31,16 +30,17 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import static com.devexperts.logging.Logging.getLogging; +import static com.rusefi.Timeouts.SECOND; import static com.rusefi.binaryprotocol.BinaryProtocol.sleep; /** * Remote user process which facilitates connection between local tuning application and real ECU via rusEFI proxy service */ public class LocalApplicationProxy implements Closeable { - private static final ThreadFactory THREAD_FACTORY = new NamedThreadFactory("gauge poking"); + private static final ThreadFactory THREAD_FACTORY = new NamedThreadFactory("gauge poking", true); private static final Logging log = getLogging(LocalApplicationProxy.class); public static final int SERVER_PORT_FOR_APPLICATIONS = HttpUtil.getIntProperty("applications.port", 8002); private final ApplicationRequest applicationRequest; @@ -101,26 +101,29 @@ public class LocalApplicationProxy implements Closeable { AbstractIoStream authenticatorToProxyStream = new TcpIoStream("authenticatorToProxyStream ", rusEFISSLContext.getSSLSocket(HttpUtil.RUSEFI_PROXY_HOSTNAME, context.serverPortForRemoteApplications()), disconnectListener); LocalApplicationProxy.sendHello(authenticatorToProxyStream, applicationRequest); - AtomicInteger relayCommandCounter = new AtomicInteger(); + AtomicLong lastActivity = new AtomicLong(System.currentTimeMillis()); + BinaryProtocolProxy.ClientApplicationActivityListener clientApplicationActivityListener = () -> lastActivity.set(System.currentTimeMillis()); /** * We need to entertain proxy server and remote controller while user has already connected to proxy but has not yet started TunerStudio */ THREAD_FACTORY.newThread(() -> { - long start = System.currentTimeMillis(); try { - while (relayCommandCounter.get() < 4 && !isTimeForApplicationToConnect(context, start)) { + while (true) { sleep(context.gaugePokingPeriod()); - byte[] commandPacket = GetOutputsCommand.createRequest(); + if (isTimeForApplicationToConnect(lastActivity.get(), SECOND * 5)) { + byte[] commandPacket = GetOutputsCommand.createRequest(); + // we do not really need the data, we just need to take response from the socket + authenticatorToProxyStream.sendAndGetPacket(commandPacket, "Gauge Poker", false); + } - // we do not really need the data, we just need to take response from the socket - authenticatorToProxyStream.sendAndGetPacket(commandPacket, "Gauge Poker", false); + if (isTimeForApplicationToConnect(lastActivity.get(), context.startUpIdle())) { + // we should not keep controller blocked since we are not connecting application, time to auto-disconnect + authenticatorToProxyStream.close(); + disconnectListener.onDisconnect("Giving up connection"); + } } - if (isTimeForApplicationToConnect(context, start) && relayCommandCounter.get() < 4) { - // we should not keep controller blocked since we are not connecting application, time to auto-disconnect - authenticatorToProxyStream.close(); - } } catch (IOException e) { log.error("Gauge poker", e); @@ -128,14 +131,14 @@ public class LocalApplicationProxy implements Closeable { }).start(); - ServerSocketReference serverHolder = BinaryProtocolProxy.createProxy(authenticatorToProxyStream, context.authenticatorPort(), relayCommandCounter); + ServerSocketReference serverHolder = BinaryProtocolProxy.createProxy(authenticatorToProxyStream, context.authenticatorPort(), clientApplicationActivityListener); LocalApplicationProxy localApplicationProxy = new LocalApplicationProxy(applicationRequest, serverHolder, authenticatorToProxyStream); connectionListener.onConnected(localApplicationProxy, authenticatorToProxyStream); return serverHolder; } - private static boolean isTimeForApplicationToConnect(LocalApplicationProxyContext context, long start) { - return System.currentTimeMillis() - start > context.startUpIdle(); + private static boolean isTimeForApplicationToConnect(long start, int idle) { + return System.currentTimeMillis() - start > idle; } public static void sendHello(IoStream authenticatorToProxyStream, ApplicationRequest applicationRequest) throws IOException { diff --git a/java_console/ui/src/test/java/com/rusefi/io/TcpCommunicationIntegrationTest.java b/java_console/ui/src/test/java/com/rusefi/io/TcpCommunicationIntegrationTest.java index cb1c3a4a19..75ec22f902 100644 --- a/java_console/ui/src/test/java/com/rusefi/io/TcpCommunicationIntegrationTest.java +++ b/java_console/ui/src/test/java/com/rusefi/io/TcpCommunicationIntegrationTest.java @@ -95,7 +95,8 @@ public class TcpCommunicationIntegrationTest { // connect proxy to virtual controller IoStream targetEcuSocket = TestHelper.connectToLocalhost(controllerPort, LOGGER); - BinaryProtocolProxy.createProxy(targetEcuSocket, proxyPort, new AtomicInteger()); + final AtomicInteger relayCommandCounter = new AtomicInteger(); + BinaryProtocolProxy.createProxy(targetEcuSocket, proxyPort, () -> relayCommandCounter.incrementAndGet()); CountDownLatch connectionEstablishedCountDownLatch = new CountDownLatch(1); 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 0e7a732900..bf73d40476 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 @@ -203,7 +203,7 @@ public class Backend implements Closeable { applications.add(applicationConnectionState); } - BinaryProtocolProxy.runProxy(state.getStream(), applicationClientStream, new AtomicInteger(), BinaryProtocolProxy.USER_IO_TIMEOUT); + BinaryProtocolProxy.runProxy(state.getStream(), applicationClientStream, BinaryProtocolProxy.ClientApplicationActivityListener.VOID, BinaryProtocolProxy.USER_IO_TIMEOUT); } catch (Throwable e) { log.info("Application Connector: Got error " + e); 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 68e8f9ea9a..3a6a166f61 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 @@ -320,7 +320,7 @@ public class RemoteTab { TcpIoStream.DisconnectListener disconnectListener = message -> SwingUtilities.invokeLater(() -> { System.out.println("Disconnected " + message); - setStatus("Disconnected"); + setStatus("Disconnected: " + message); RemoteTabController.INSTANCE.setState(RemoteTabController.State.NOT_CONNECTED); ServerSocketReference serverHolder = serverHolderAtomicReference.get(); if (serverHolder != null)