rusefi/java_console/io/src/main/java/com/rusefi/proxy/NetworkConnector.java

239 lines
9.7 KiB
Java
Raw Normal View History

2020-07-17 19:46:07 -07:00
package com.rusefi.proxy;
2020-07-17 17:19:52 -07:00
2020-07-25 07:32:23 -07:00
import com.devexperts.logging.Logging;
import com.opensr5.ConfigurationImage;
import com.rusefi.Timeouts;
2020-07-21 21:03:03 -07:00
import com.rusefi.binaryprotocol.BinaryProtocol;
import com.rusefi.config.generated.Fields;
2020-07-25 07:46:59 -07:00
import com.rusefi.io.AbstractConnectionStateListener;
2020-07-17 17:19:52 -07:00
import com.rusefi.io.IoStream;
import com.rusefi.io.LinkManager;
2020-07-17 17:19:52 -07:00
import com.rusefi.io.commands.HelloCommand;
import com.rusefi.io.tcp.BinaryProtocolServer;
import com.rusefi.io.tcp.TcpIoStream;
2020-08-14 17:22:17 -07:00
import com.rusefi.rusEFIVersion;
2020-07-17 17:19:52 -07:00
import com.rusefi.server.ControllerInfo;
import com.rusefi.server.SessionDetails;
import com.rusefi.server.rusEFISSLContext;
2020-08-14 17:22:17 -07:00
import com.rusefi.tools.VehicleToken;
2020-07-18 10:59:08 -07:00
import com.rusefi.tools.online.HttpUtil;
2020-07-17 17:19:52 -07:00
import org.jetbrains.annotations.NotNull;
import java.io.Closeable;
2020-07-17 17:19:52 -07:00
import java.io.IOException;
import java.net.Socket;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
2020-07-17 17:19:52 -07:00
import static com.rusefi.binaryprotocol.BinaryProtocol.sleep;
2020-07-17 17:19:52 -07:00
/**
* Connector between rusEFI ECU and rusEFI server
* see NetworkConnectorStartup
2020-07-17 17:19:52 -07:00
*/
public class NetworkConnector implements Closeable {
2020-08-15 12:34:50 -07:00
public static final byte DISCONNECT = 14;
2020-08-14 20:46:31 -07:00
public static final byte UPDATE_CONNECTOR_SOFTWARE = 15;
public static final byte UPDATE_FIRMWARE = 16;
2020-07-25 07:32:23 -07:00
private final static Logging log = Logging.getLogging(NetworkConnector.class);
private boolean isClosed;
2020-08-15 21:17:31 -07:00
public NetworkConnectorResult start(Implementation implementation, String authToken, String controllerPort, NetworkConnectorContext context) {
return start(implementation, authToken, controllerPort, context, ReconnectListener.VOID);
2020-07-26 21:48:04 -07:00
}
2020-08-15 21:17:31 -07:00
public NetworkConnectorResult start(Implementation implementation, String authToken, String controllerPort, NetworkConnectorContext context, ReconnectListener reconnectListener) {
2020-07-25 07:01:46 -07:00
LinkManager controllerConnector = new LinkManager()
.setCompositeLogicEnabled(false)
.setNeedPullData(false);
CountDownLatch onConnected = new CountDownLatch(1);
2020-07-25 07:46:59 -07:00
controllerConnector.startAndConnect(controllerPort, new AbstractConnectionStateListener() {
@Override
public void onConnectionEstablished() {
onConnected.countDown();
}
});
2020-07-25 07:32:23 -07:00
log.info("Connecting to controller...");
try {
onConnected.await(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
if (onConnected.getCount() != 0) {
2020-07-25 07:32:23 -07:00
log.info("Connection to controller failed");
return NetworkConnectorResult.ERROR;
}
2020-08-16 19:10:05 -07:00
return start(implementation, authToken, context, reconnectListener, controllerConnector, ActivityListener.VOID);
2020-08-15 17:37:56 -07:00
}
2020-08-16 19:10:05 -07:00
public NetworkConnectorResult start(Implementation implementation, String authToken, NetworkConnectorContext context, ReconnectListener reconnectListener, LinkManager linkManager, ActivityListener activityListener) {
ControllerInfo controllerInfo;
try {
2020-08-15 19:03:43 -07:00
controllerInfo = getControllerInfo(linkManager, linkManager.getConnector().getBinaryProtocol().getStream());
} catch (IOException e) {
return NetworkConnectorResult.ERROR;
}
2020-08-14 17:22:17 -07:00
int vehicleToken = VehicleToken.getOrCreate();
BinaryProtocolServer.getThreadFactory("Proxy Reconnect").newThread(() -> {
Semaphore proxyReconnectSemaphore = new Semaphore(1);
try {
while (!isClosed) {
proxyReconnectSemaphore.acquire();
try {
2020-08-15 21:17:31 -07:00
start(implementation,
2020-08-16 19:10:05 -07:00
activityListener,
2020-08-15 21:17:31 -07:00
context.serverPortForControllers(), linkManager, authToken, (String message) -> {
log.error(message + " Disconnect from proxy server detected, now sleeping " + context.reconnectDelay() + " seconds");
sleep(context.reconnectDelay() * Timeouts.SECOND);
log.debug("Releasing semaphore");
proxyReconnectSemaphore.release();
reconnectListener.onReconnect();
}, vehicleToken, controllerInfo, context);
} catch (IOException e) {
log.error("IO error", e);
}
}
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}).start();
2020-08-14 17:22:17 -07:00
return new NetworkConnectorResult(controllerInfo, vehicleToken);
}
2020-07-17 19:46:07 -07:00
2020-07-17 17:19:52 -07:00
@NotNull
2020-08-16 19:10:05 -07:00
private static SessionDetails start(Implementation implementation, ActivityListener activityListener, int serverPortForControllers, LinkManager linkManager, String authToken, final TcpIoStream.DisconnectListener disconnectListener, int oneTimeToken, ControllerInfo controllerInfo, final NetworkConnectorContext context) throws IOException {
IoStream targetEcuSocket = linkManager.getConnector().getBinaryProtocol().getStream();
2020-07-17 17:19:52 -07:00
2020-08-15 21:17:31 -07:00
SessionDetails deviceSessionDetails = new SessionDetails(implementation, controllerInfo, authToken, oneTimeToken, rusEFIVersion.CONSOLE_VERSION);
2020-07-17 17:19:52 -07:00
Socket socket;
try {
2020-07-26 12:17:29 -07:00
log.info("Connecting to proxy server " + HttpUtil.RUSEFI_PROXY_HOSTNAME + " " + serverPortForControllers);
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("on socket open");
return deviceSessionDetails;
}
BaseBroadcastingThread baseBroadcastingThread = new BaseBroadcastingThread(socket,
2020-07-17 17:19:52 -07:00
deviceSessionDetails,
disconnectListener, context) {
2020-07-17 17:19:52 -07:00
@Override
protected void handleCommand(BinaryProtocolServer.Packet packet, TcpIoStream stream) throws IOException {
super.handleCommand(packet, stream);
2020-08-14 20:34:53 -07:00
byte command = packet.getPacket()[0];
if (command == Fields.TS_ONLINE_PROTOCOL) {
byte connectorCommand = packet.getPacket()[1];
log.info("Got connector command " + packet.getPacket());
2020-08-14 20:46:31 -07:00
if (connectorCommand == NetworkConnector.UPDATE_CONNECTOR_SOFTWARE) {
2020-08-14 20:34:53 -07:00
context.onConnectorSoftwareUpdateRequest();
2020-08-14 20:54:26 -07:00
} else if (connectorCommand == NetworkConnector.UPDATE_FIRMWARE) {
2020-08-14 20:34:53 -07:00
}
return;
}
log.info("Relaying request to controller " + BinaryProtocol.findCommand(command));
2020-07-17 17:19:52 -07:00
targetEcuSocket.sendPacket(packet);
BinaryProtocolServer.Packet response = targetEcuSocket.readPacket();
2020-07-25 07:32:23 -07:00
log.info("Relaying response to proxy size=" + response.getPacket().length);
2020-07-17 17:19:52 -07:00
stream.sendPacket(response);
2020-08-16 19:10:05 -07:00
activityListener.onActivity(targetEcuSocket);
2020-07-17 17:19:52 -07:00
}
};
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);
}
@Override
public void close() {
isClosed = true;
}
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;
}
2020-08-16 15:01:39 -07:00
@Override
public String toString() {
return "NetworkConnectorResult{" +
"controllerInfo=" + controllerInfo +
'}';
}
}
public interface ReconnectListener {
ReconnectListener VOID = new ReconnectListener() {
@Override
public void onReconnect() {
}
};
2020-08-14 20:34:53 -07:00
void onReconnect();
}
2020-08-16 19:10:05 -07:00
public interface ActivityListener {
ActivityListener VOID = new ActivityListener() {
@Override
public void onActivity(IoStream targetEcuSocket) {
}
};
void onActivity(IoStream targetEcuSocket);
}
2020-08-15 21:17:31 -07:00
public enum Implementation {
Android,
Plugin,
SBC,
Unknown;
public static Implementation find(String name) {
for (Implementation implementation : values()) {
if (implementation.name().equalsIgnoreCase(name))
return implementation;
}
return Unknown;
}
}
2020-07-17 17:19:52 -07:00
}