diff --git a/java_console/io/src/main/java/com/rusefi/proxy/BaseBroadcastingThread.java b/java_console/io/src/main/java/com/rusefi/proxy/BaseBroadcastingThread.java index e3f62d310b..b25cc05dee 100644 --- a/java_console/io/src/main/java/com/rusefi/proxy/BaseBroadcastingThread.java +++ b/java_console/io/src/main/java/com/rusefi/proxy/BaseBroadcastingThread.java @@ -17,6 +17,7 @@ import java.net.Socket; import static com.devexperts.logging.Logging.getLogging; import static com.rusefi.io.tcp.BinaryProtocolServer.getPacketLength; import static com.rusefi.io.tcp.BinaryProtocolServer.readPromisedBytes; +import static com.rusefi.shared.FileUtil.close; public class BaseBroadcastingThread { private static final Logging log = getLogging(BaseBroadcastingThread.class); @@ -25,11 +26,12 @@ public class BaseBroadcastingThread { @SuppressWarnings("InfiniteLoopStatement") public BaseBroadcastingThread(Socket socket, SessionDetails sessionDetails, TcpIoStream.DisconnectListener disconnectListener) throws IOException { - TcpIoStream stream = new TcpIoStream("[broadcast] ", socket, disconnectListener); - IncomingDataBuffer in = stream.getDataBuffer(); thread = BASE_BROADCASTING_THREAD.newThread(() -> { + TcpIoStream stream = null; try { + stream = new TcpIoStream("[broadcast] ", socket, disconnectListener); + IncomingDataBuffer in = stream.getDataBuffer(); boolean isFirstHello = true; while (true) { int ioTimeout; @@ -59,7 +61,7 @@ public class BaseBroadcastingThread { } } catch (IOException e) { log.error("exiting thread " + e); - stream.close(); + close(stream); } }); } diff --git a/java_console/io/src/main/java/com/rusefi/proxy/NetworkConnector.java b/java_console/io/src/main/java/com/rusefi/proxy/NetworkConnector.java index 2ccdbf019f..ed608f04c9 100644 --- a/java_console/io/src/main/java/com/rusefi/proxy/NetworkConnector.java +++ b/java_console/io/src/main/java/com/rusefi/proxy/NetworkConnector.java @@ -18,6 +18,7 @@ import com.rusefi.tools.online.HttpUtil; import org.jetbrains.annotations.NotNull; import java.io.IOException; +import java.net.Socket; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -31,7 +32,7 @@ import static com.rusefi.binaryprotocol.BinaryProtocol.sleep; public class NetworkConnector { private final static Logging log = Logging.getLogging(NetworkConnector.class); - public static NetworkConnectorResult runNetworkConnector(String authToken, String controllerPort, NetworkConnectorContext context) { + public static NetworkConnectorResult runNetworkConnector(String authToken, String controllerPort, NetworkConnectorContext context, ReconnectListener reconnectListener) { LinkManager controllerConnector = new LinkManager() .setCompositeLogicEnabled(false) .setNeedPullData(false); @@ -76,6 +77,7 @@ public class NetworkConnector { log.error("Disconnect from proxy server detected, now sleeping " + context.reconnectDelay() + " seconds"); sleep(context.reconnectDelay() * Timeouts.SECOND); proxyReconnectSemaphore.release(); + reconnectListener.onReconnect(); }, oneTimeToken, controllerInfo); } catch (IOException e) { log.error("IO error", e); @@ -95,7 +97,15 @@ public class NetworkConnector { SessionDetails deviceSessionDetails = new SessionDetails(controllerInfo, authToken, oneTimeToken); - BaseBroadcastingThread baseBroadcastingThread = new BaseBroadcastingThread(rusEFISSLContext.getSSLSocket(HttpUtil.RUSEFI_PROXY_HOSTNAME, serverPortForControllers), + Socket socket; + try { + socket = rusEFISSLContext.getSSLSocket(HttpUtil.RUSEFI_PROXY_HOSTNAME, serverPortForControllers); + } catch (IOException e) { + // socket open exception is a special case and should be handled separately + disconnectListener.onDisconnect(); + return deviceSessionDetails; + } + BaseBroadcastingThread baseBroadcastingThread = new BaseBroadcastingThread(socket, deviceSessionDetails, disconnectListener) { @Override @@ -147,4 +157,14 @@ public class NetworkConnector { } } + public interface ReconnectListener { + ReconnectListener VOID = new ReconnectListener() { + @Override + public void onReconnect() { + + } + }; + void onReconnect(); + } + } diff --git a/java_console/ui/src/main/java/com/rusefi/tools/NetworkConnectorStartup.java b/java_console/ui/src/main/java/com/rusefi/tools/NetworkConnectorStartup.java index 2f01bde70d..f053ccdf3c 100644 --- a/java_console/ui/src/main/java/com/rusefi/tools/NetworkConnectorStartup.java +++ b/java_console/ui/src/main/java/com/rusefi/tools/NetworkConnectorStartup.java @@ -4,6 +4,7 @@ import com.devexperts.logging.Logging; import com.rusefi.auth.AutoTokenUtil; import com.rusefi.autodetect.PortDetector; import com.rusefi.proxy.NetworkConnector; +import com.rusefi.proxy.NetworkConnectorContext; import com.rusefi.tools.online.ProxyClient; import com.rusefi.ui.AuthTokenPanel; @@ -22,7 +23,9 @@ public class NetworkConnectorStartup { return; } - NetworkConnector.NetworkConnectorResult networkConnectorResult = NetworkConnector.runNetworkConnector(authToken, autoDetectedPort, ProxyClient.SERVER_PORT_FOR_CONTROLLERS); + NetworkConnectorContext connectorContext = new NetworkConnectorContext(); + + NetworkConnector.NetworkConnectorResult networkConnectorResult = NetworkConnector.runNetworkConnector(authToken, autoDetectedPort, connectorContext, NetworkConnector.ReconnectListener.VOID); log.info("Running with oneTimeToken=" + networkConnectorResult.getOneTimeToken()); } } 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 23c61bf37e..a1a8fe281c 100644 --- a/java_console/ui/src/test/java/com/rusefi/FullServerTest.java +++ b/java_console/ui/src/test/java/com/rusefi/FullServerTest.java @@ -98,7 +98,7 @@ public class FullServerTest { }; // start "rusEFI network connector" to connect controller with backend since in real life controller has only local serial port it does not have network - NetworkConnector.NetworkConnectorResult networkConnectorResult = NetworkConnector.runNetworkConnector(TestHelper.TEST_TOKEN_1, TestHelper.LOCALHOST + ":" + controllerPort, networkConnectorContext); + NetworkConnector.NetworkConnectorResult networkConnectorResult = NetworkConnector.runNetworkConnector(TestHelper.TEST_TOKEN_1, TestHelper.LOCALHOST + ":" + controllerPort, networkConnectorContext, NetworkConnector.ReconnectListener.VOID); ControllerInfo controllerInfo = networkConnectorResult.getControllerInfo(); assertTrue("controllerRegistered", controllerRegistered.await(READ_IMAGE_TIMEOUT, TimeUnit.MILLISECONDS)); diff --git a/java_console/ui/src/test/java/com/rusefi/proxy/NetworkConnectorTest.java b/java_console/ui/src/test/java/com/rusefi/proxy/NetworkConnectorTest.java index 830fb56fa4..57121d599e 100644 --- a/java_console/ui/src/test/java/com/rusefi/proxy/NetworkConnectorTest.java +++ b/java_console/ui/src/test/java/com/rusefi/proxy/NetworkConnectorTest.java @@ -7,6 +7,11 @@ import com.rusefi.config.generated.Fields; import com.rusefi.server.Backend; import org.junit.Test; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertTrue; + public class NetworkConnectorTest { @Test public void testReconnect() throws InterruptedException { @@ -30,8 +35,18 @@ public class NetworkConnectorTest { } }; + CountDownLatch reconnectCounter = new CountDownLatch(1); + // start "rusEFI network connector" to connect controller with backend since in real life controller has only local serial port it does not have network - NetworkConnector.NetworkConnectorResult networkConnectorResult = NetworkConnector.runNetworkConnector(TestHelper.TEST_TOKEN_1, TestHelper.LOCALHOST + ":" + controllerPort, connectorContext); + NetworkConnector.ReconnectListener reconnectListener = new NetworkConnector.ReconnectListener() { + @Override + public void onReconnect() { + reconnectCounter.countDown(); + } + }; + NetworkConnector.NetworkConnectorResult networkConnectorResult = NetworkConnector.runNetworkConnector(TestHelper.TEST_TOKEN_1, TestHelper.LOCALHOST + ":" + controllerPort, connectorContext, reconnectListener); + + assertTrue(reconnectCounter.await(30, TimeUnit.SECONDS)); Backend backend = new Backend(BackendTestHelper.createTestUserResolver(), httpPort);