network connector to reconnect on proxy disconnect

This commit is contained in:
rusefi 2020-07-25 13:40:52 -04:00
parent 5457287b2d
commit c531127309
5 changed files with 108 additions and 30 deletions

View File

@ -0,0 +1,11 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Launcher network connector" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="com.rusefi.Launcher" />
<module name="ui" />
<option name="PROGRAM_PARAMETERS" value="network_connector" />
<option name="VM_PARAMETERS" value="-Dini_file_path=../firmware/tunerstudio -Dshow_etb_pane=true -Dhigh_speed_logger_rpm=10000" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -2,16 +2,12 @@ package com.rusefi.tools;
import com.rusefi.auth.AutoTokenUtil;
import com.rusefi.autodetect.PortDetector;
import com.rusefi.io.tcp.TcpIoStream;
import com.rusefi.proxy.NetworkConnector;
import com.rusefi.server.Backend;
import com.rusefi.server.SessionDetails;
import com.rusefi.ui.AuthTokenPanel;
import java.io.IOException;
public class NetworkConnectorStartup {
public static void start() throws IOException, InterruptedException {
public static void start() {
String authToken = AuthTokenPanel.getAuthToken();
if (!AutoTokenUtil.isToken(authToken)) {
System.err.println("Please configure authentication token using 'set_auth_token' command");
@ -24,10 +20,7 @@ public class NetworkConnectorStartup {
return;
}
SessionDetails sessionDetails = NetworkConnector.runNetworkConnector(authToken, autoDetectedPort, Backend.SERVER_PORT_FOR_CONTROLLERS, () -> {
System.err.println("Disconnect detected");
System.exit(-1);
});
System.out.println("Running with " + sessionDetails.getOneTimeToken());
NetworkConnector.NetworkConnectorResult networkConnectorResult = NetworkConnector.runNetworkConnector(authToken, autoDetectedPort, Backend.SERVER_PORT_FOR_CONTROLLERS);
System.out.println("Running with " + networkConnectorResult.getOneTimeToken());
}
}

View File

@ -72,11 +72,12 @@ 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
SessionDetails deviceSessionDetails = NetworkConnector.runNetworkConnector(MockRusEfiDevice.TEST_TOKEN_1, TestHelper.LOCALHOST + ":" + controllerPort, serverPortForControllers, TcpIoStream.DisconnectListener.VOID);
NetworkConnector.NetworkConnectorResult networkConnectorResult = NetworkConnector.runNetworkConnector(MockRusEfiDevice.TEST_TOKEN_1, TestHelper.LOCALHOST + ":" + controllerPort, serverPortForControllers);
ControllerInfo controllerInfo = networkConnectorResult.getControllerInfo();
assertTrue("controllerRegistered", controllerRegistered.await(READ_IMAGE_TIMEOUT, TimeUnit.MILLISECONDS));
SessionDetails authenticatorSessionDetails = new SessionDetails(deviceSessionDetails.getControllerInfo(), MockRusEfiDevice.TEST_TOKEN_3, deviceSessionDetails.getOneTimeToken());
SessionDetails authenticatorSessionDetails = new SessionDetails(controllerInfo, MockRusEfiDevice.TEST_TOKEN_3, networkConnectorResult.getOneTimeToken());
ApplicationRequest applicationRequest = new ApplicationRequest(authenticatorSessionDetails, userId);
// start authenticator

View File

@ -2,6 +2,7 @@ package com.rusefi.proxy;
import com.devexperts.logging.Logging;
import com.rusefi.NamedThreadFactory;
import com.rusefi.Timeouts;
import com.rusefi.binaryprotocol.IncomingDataBuffer;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.commands.HelloCommand;
@ -31,9 +32,16 @@ public class BaseBroadcastingThread {
try {
boolean isFirstHello = true;
while (true) {
int ioTimeout;
if (isFirstHello) {
log.info("Waiting for proxy server to request session details");
ioTimeout = Timeouts.CMD_TIMEOUT;
} else {
ioTimeout = BinaryProtocolProxy.USER_IO_TIMEOUT;
}
int length = getPacketLength(in, () -> {
throw new UnsupportedOperationException();
}, BinaryProtocolProxy.USER_IO_TIMEOUT);
}, ioTimeout);
BinaryProtocolServer.Packet packet = readPromisedBytes(in, length);
byte[] payload = packet.getPacket();

View File

@ -2,6 +2,7 @@ package com.rusefi.proxy;
import com.devexperts.logging.Logging;
import com.opensr5.ConfigurationImage;
import com.rusefi.Timeouts;
import com.rusefi.binaryprotocol.BinaryProtocol;
import com.rusefi.config.generated.Fields;
import com.rusefi.io.AbstractConnectionStateListener;
@ -18,15 +19,20 @@ import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import static com.rusefi.binaryprotocol.BinaryProtocol.sleep;
/**
* Connector between rusEFI ECU and rusEFI server
* see NetworkConnectorStartup
*/
public class NetworkConnector {
private final static Logging log = Logging.getLogging(NetworkConnector.class);
public static SessionDetails runNetworkConnector(String authToken, String controllerPort, int serverPortForControllers, TcpIoStream.DisconnectListener disconnectListener) throws InterruptedException, IOException {
public static final int RECONNECT_DELAY = 15;
public static NetworkConnectorResult runNetworkConnector(String authToken, String controllerPort, int serverPortForControllers) {
LinkManager controllerConnector = new LinkManager()
.setCompositeLogicEnabled(false)
.setNeedPullData(false);
@ -40,31 +46,55 @@ public class NetworkConnector {
});
log.info("Connecting to controller...");
onConnected.await(1, TimeUnit.MINUTES);
try {
onConnected.await(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
if (onConnected.getCount() != 0) {
log.info("Connection to controller failed");
return null;
return NetworkConnectorResult.ERROR;
}
return runNetworkConnector(serverPortForControllers, controllerConnector, authToken, disconnectListener);
ControllerInfo controllerInfo;
try {
controllerInfo = getControllerInfo(controllerConnector, controllerConnector.getConnector().getBinaryProtocol().getStream());
} catch (IOException e) {
return NetworkConnectorResult.ERROR;
}
int oneTimeToken = SessionDetails.createOneTimeCode();
new Thread(() -> {
Semaphore proxyReconnectSemaphore = new Semaphore(1);
try {
while (true) {
log.info("Connecting to proxy server");
proxyReconnectSemaphore.acquire();
try {
runNetworkConnector(serverPortForControllers, controllerConnector, authToken, () -> {
log.error("Disconnect from proxy server detected, now sleeping " + RECONNECT_DELAY + " seconds");
sleep(RECONNECT_DELAY * Timeouts.SECOND);
proxyReconnectSemaphore.release();
}, oneTimeToken, controllerInfo);
} catch (IOException e) {
log.error("IO error", e);
}
}
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}, "Proxy Reconnect").start();
return new NetworkConnectorResult(controllerInfo, oneTimeToken);
}
@NotNull
private static SessionDetails runNetworkConnector(int serverPortForControllers, LinkManager linkManager, String authToken, final TcpIoStream.DisconnectListener disconnectListener) throws IOException {
private static SessionDetails runNetworkConnector(int serverPortForControllers, LinkManager linkManager, String authToken, final TcpIoStream.DisconnectListener disconnectListener, int oneTimeToken, ControllerInfo controllerInfo) throws IOException {
IoStream targetEcuSocket = linkManager.getConnector().getBinaryProtocol().getStream();
HelloCommand.send(targetEcuSocket);
String helloResponse = HelloCommand.getHelloResponse(targetEcuSocket.getDataBuffer());
if (helloResponse == null)
throw new IOException("Error getting hello response");
String controllerSignature = helloResponse.trim();
ConfigurationImage image = linkManager.getConnector().getBinaryProtocol().getControllerConfiguration();
String vehicleName = Fields.VEHICLENAME.getStringValue(image);
String engineMake = Fields.ENGINEMAKE.getStringValue(image);
String engineCode = Fields.ENGINECODE.getStringValue(image);
ControllerInfo ci = new ControllerInfo(vehicleName, engineMake, engineCode, controllerSignature);
SessionDetails deviceSessionDetails = new SessionDetails(ci, authToken, SessionDetails.createOneTimeCode());
SessionDetails deviceSessionDetails = new SessionDetails(controllerInfo, authToken, oneTimeToken);
BaseBroadcastingThread baseBroadcastingThread = new BaseBroadcastingThread(rusEFISSLContext.getSSLSocket(HttpUtil.RUSEFI_PROXY_HOSTNAME, serverPortForControllers),
deviceSessionDetails,
@ -83,4 +113,39 @@ public class NetworkConnector {
baseBroadcastingThread.start();
return deviceSessionDetails;
}
@NotNull
private static ControllerInfo getControllerInfo(LinkManager linkManager, IoStream targetEcuSocket) throws IOException {
HelloCommand.send(targetEcuSocket);
String helloResponse = HelloCommand.getHelloResponse(targetEcuSocket.getDataBuffer());
if (helloResponse == null)
throw new IOException("Error getting hello response");
String controllerSignature = helloResponse.trim();
ConfigurationImage image = linkManager.getConnector().getBinaryProtocol().getControllerConfiguration();
String vehicleName = Fields.VEHICLENAME.getStringValue(image);
String engineMake = Fields.ENGINEMAKE.getStringValue(image);
String engineCode = Fields.ENGINECODE.getStringValue(image);
return new ControllerInfo(vehicleName, engineMake, engineCode, controllerSignature);
}
public static class NetworkConnectorResult {
static NetworkConnectorResult ERROR = new NetworkConnectorResult(null, 0);
private final ControllerInfo controllerInfo;
private final int oneTimeToken;
public NetworkConnectorResult(ControllerInfo controllerInfo, int oneTimeToken) {
this.controllerInfo = controllerInfo;
this.oneTimeToken = oneTimeToken;
}
public ControllerInfo getControllerInfo() {
return controllerInfo;
}
public int getOneTimeToken() {
return oneTimeToken;
}
}
}