From 24f6ead04bd4e40e5605005a0772c5a301d1ec47 Mon Sep 17 00:00:00 2001 From: rusefi Date: Sun, 30 Aug 2020 00:21:34 -0400 Subject: [PATCH] remote tab misc progress --- .../java/com/rusefi/NamedThreadFactory.java | 3 +- .../server/JsonUserDetailsResolver.java | 0 .../com/rusefi/server/SessionDetails.java | 6 +- .../rusefi/server/UserDetailsResolver.java | 0 .../com/rusefi/tools/online/ProxyClient.java | 4 +- .../rusefi/tools/online/PublicSession.java | 8 +- .../src/com/rusefi/ui/AuthTokenPanel.java | 8 +- .../test/java/com/rusefi/FullServerTest.java | 2 +- .../main/java/com/rusefi/server/Backend.java | 5 +- .../java/com/rusefi/server/Monitoring.java | 2 +- .../com/rusefi/server/SessionDetailsTest.java | 4 +- .../main/java/com/rusefi/SignatureHelper.java | 8 +- .../com/rusefi/ts_plugin/PluginEntry.java | 14 +++ .../java/com/rusefi/ts_plugin/RemoteTab.java | 96 +++++++++++-------- .../com/rusefi/ts_plugin/TuneUploadTab.java | 8 +- .../com/rusefi/ts_plugin/UploadQueue.java | 6 +- .../ts_plugin/auth/InstanceAuthContext.java | 44 +++++++++ .../com/rusefi/ts_plugin/auth/SelfInfo.java | 33 +++++++ .../java/com/rusefi/SignatureHelperTest.java | 2 +- 19 files changed, 189 insertions(+), 64 deletions(-) rename {java_tools/proxy_server => java_console/io}/src/main/java/com/rusefi/server/JsonUserDetailsResolver.java (100%) rename {java_tools/proxy_server => java_console/io}/src/main/java/com/rusefi/server/UserDetailsResolver.java (100%) create mode 100644 java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/auth/InstanceAuthContext.java create mode 100644 java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/auth/SelfInfo.java diff --git a/java_console/io/src/main/java/com/rusefi/NamedThreadFactory.java b/java_console/io/src/main/java/com/rusefi/NamedThreadFactory.java index cc9457076d..674f2d60d9 100644 --- a/java_console/io/src/main/java/com/rusefi/NamedThreadFactory.java +++ b/java_console/io/src/main/java/com/rusefi/NamedThreadFactory.java @@ -8,7 +8,7 @@ import java.util.concurrent.atomic.AtomicInteger; public class NamedThreadFactory implements ThreadFactory { private final AtomicInteger counter = new AtomicInteger(); - private String name; + private final String name; private final boolean isDaemon; public NamedThreadFactory(String name) { @@ -20,7 +20,6 @@ public class NamedThreadFactory implements ThreadFactory { this.isDaemon = isDaemon; } - @Override public Thread newThread(@NotNull Runnable r) { Thread t = Executors.defaultThreadFactory().newThread(r); diff --git a/java_tools/proxy_server/src/main/java/com/rusefi/server/JsonUserDetailsResolver.java b/java_console/io/src/main/java/com/rusefi/server/JsonUserDetailsResolver.java similarity index 100% rename from java_tools/proxy_server/src/main/java/com/rusefi/server/JsonUserDetailsResolver.java rename to java_console/io/src/main/java/com/rusefi/server/JsonUserDetailsResolver.java diff --git a/java_console/io/src/main/java/com/rusefi/server/SessionDetails.java b/java_console/io/src/main/java/com/rusefi/server/SessionDetails.java index 14716cddcf..7c56bc99cc 100644 --- a/java_console/io/src/main/java/com/rusefi/server/SessionDetails.java +++ b/java_console/io/src/main/java/com/rusefi/server/SessionDetails.java @@ -15,6 +15,7 @@ public class SessionDetails { public static final String AUTH_TOKEN = "authToken"; public static final String CONNECTOR_VERSION = "connectorVersion"; public static final String IMPLEMENTATION = "implementation"; + public static final String AGE = "age"; private static final String CONTROLLER = "controller"; private static final String HARDCODED_ONE_TIME_CODE = System.getProperty("ONE_TIME_CODE"); @@ -74,11 +75,12 @@ public class SessionDetails { JSONObject jsonObject = HttpUtil.parse(jsonString); String authToken = (String) jsonObject.get(AUTH_TOKEN); - long oneTimeCode = (Long)jsonObject.get(VEHICLE_TOKEN); + long oneTimeCode = (Long) jsonObject.get(VEHICLE_TOKEN); long connectorVersion = (long) jsonObject.get(CONNECTOR_VERSION); + String age = (String) jsonObject.get(AGE); NetworkConnector.Implementation implementation = NetworkConnector.Implementation.find((String) jsonObject.get(IMPLEMENTATION)); - ControllerInfo controllerInfo = ControllerInfo.valueOf((String) jsonObject.get(CONTROLLER)); + ControllerInfo controllerInfo = ControllerInfo.valueOf((String) jsonObject.get(CONTROLLER)); return new SessionDetails(implementation, controllerInfo, authToken, (int) oneTimeCode, (int) connectorVersion); } diff --git a/java_tools/proxy_server/src/main/java/com/rusefi/server/UserDetailsResolver.java b/java_console/io/src/main/java/com/rusefi/server/UserDetailsResolver.java similarity index 100% rename from java_tools/proxy_server/src/main/java/com/rusefi/server/UserDetailsResolver.java rename to java_console/io/src/main/java/com/rusefi/server/UserDetailsResolver.java 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 abb05aaa4c..03d0c8c6d7 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 @@ -2,6 +2,7 @@ package com.rusefi.tools.online; import com.rusefi.proxy.client.LocalApplicationProxy; import com.rusefi.server.ControllerInfo; +import com.rusefi.server.SessionDetails; import com.rusefi.server.UserDetails; import org.jetbrains.annotations.NotNull; import org.json.simple.JSONArray; @@ -54,7 +55,8 @@ public class ProxyClient { UserDetails vehicleOwner = UserDetails.valueOf(element); boolean isUsed = (Boolean) element.get(IS_USED); String ownerName = (String) element.get(OWNER); - userLists.add(new PublicSession(vehicleOwner, ci, isUsed, ownerName)); + String age = (String) element.get(SessionDetails.AGE); + userLists.add(new PublicSession(vehicleOwner, ci, isUsed, ownerName, age)); } System.out.println("object=" + array); diff --git a/java_console/io/src/main/java/com/rusefi/tools/online/PublicSession.java b/java_console/io/src/main/java/com/rusefi/tools/online/PublicSession.java index 8f383d576e..b2fc0f0347 100644 --- a/java_console/io/src/main/java/com/rusefi/tools/online/PublicSession.java +++ b/java_console/io/src/main/java/com/rusefi/tools/online/PublicSession.java @@ -14,12 +14,18 @@ public class PublicSession { * Person currently in control of tuning session */ private final String tunerName; + private final String age; - public PublicSession(UserDetails vehicleOwner, ControllerInfo controllerInfo, boolean isUsed, String tunerName) { + public PublicSession(UserDetails vehicleOwner, ControllerInfo controllerInfo, boolean isUsed, String tunerName, String age) { this.vehicleOwner = vehicleOwner; this.controllerInfo = controllerInfo; this.isUsed = isUsed; this.tunerName = tunerName; + this.age = age; + } + + public String getAge() { + return age; } public UserDetails getVehicleOwner() { diff --git a/java_console/shared_ui/src/com/rusefi/ui/AuthTokenPanel.java b/java_console/shared_ui/src/com/rusefi/ui/AuthTokenPanel.java index 01e2c9691e..a4bc45eb49 100644 --- a/java_console/shared_ui/src/com/rusefi/ui/AuthTokenPanel.java +++ b/java_console/shared_ui/src/com/rusefi/ui/AuthTokenPanel.java @@ -1,5 +1,6 @@ package com.rusefi.ui; +import com.devexperts.logging.Logging; import com.rusefi.auth.AuthTokenUtil; import com.rusefi.ui.storage.PersistentConfiguration; import com.rusefi.ui.util.URLLabel; @@ -16,6 +17,7 @@ import java.io.IOException; import static com.rusefi.ui.storage.PersistentConfiguration.getConfig; public class AuthTokenPanel { + private final static Logging log = Logging.getLogging(AuthTokenPanel.class); private final JPanel content = new JPanel(new BorderLayout()); private final JTextField authTokenTestField = new JTextField(); @@ -105,18 +107,18 @@ public class AuthTokenPanel { String data = (String) clipboard.getData(DataFlavor.stringFlavor); paste.setEnabled(AuthTokenUtil.isToken(data)); } catch (IOException | IllegalStateException | UnsupportedFlavorException ex) { - // ignoring this exception + log.info("Ignoring " + ex); } } - private void grabText() { + private void persistToken() { setAuthToken(AuthTokenPanel.this.authTokenTestField.getText()); PersistentConfiguration.getConfig().save(); } private void onTextChange() { if (AuthTokenUtil.isToken(authTokenTestField.getText())) { - grabText(); + persistToken(); } } 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 252409267f..a07ab9fdd4 100644 --- a/java_console/ui/src/test/java/com/rusefi/FullServerTest.java +++ b/java_console/ui/src/test/java/com/rusefi/FullServerTest.java @@ -116,7 +116,7 @@ public class FullServerTest { TestHelper.assertLatch("controllerRegistered", controllerRegistered); - SessionDetails authenticatorSessionDetails = new SessionDetails(NetworkConnector.Implementation.Unknown, controllerInfo, TEST_TOKEN_3, networkConnectorResult.getOneTimeToken(), rusEFIVersion.CONSOLE_VERSION); + SessionDetails authenticatorSessionDetails = new SessionDetails(NetworkConnector.Implementation.Unknown, controllerInfo, TEST_TOKEN_3, networkConnectorResult.getOneTimeToken(), rusEFIVersion.CONSOLE_VERSION, ""); ApplicationRequest applicationRequest = new ApplicationRequest(authenticatorSessionDetails, userDetailsResolver.apply(TestHelper.TEST_TOKEN_1)); // start authenticator 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 4e2ccc4fb5..48783ed047 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 @@ -59,7 +59,6 @@ public class Backend implements Closeable { * @see BinaryProtocolProxy#USER_IO_TIMEOUT */ private static final int APPLICATION_INACTIVITY_TIMEOUT = 3 * Timeouts.MINUTE; - static final String AGE = "age"; private static final ThreadFactory APPLICATION_CONNECTION_CLEANUP = new NamedThreadFactory("rusEFI Application connections Cleanup"); private static final ThreadFactory GAUGE_POKER = new NamedThreadFactory("rusEFI gauge poker"); @@ -277,7 +276,7 @@ public class Backend implements Closeable { JsonObjectBuilder b = Json.createObjectBuilder() .add(UserDetails.USER_ID, application.getUserDetails().getUserId()) .add(UserDetails.USERNAME, application.getUserDetails().getUserName()) - .add(AGE, application.getBirthday().getDuration()) + .add(SessionDetails.AGE, application.getBirthday().getDuration()) ; JsonObject applicationObject = addStreamStats(b, application.getClientStream()) .build(); @@ -308,7 +307,7 @@ public class Backend implements Closeable { JsonObjectBuilder objectBuilder = Json.createObjectBuilder() .add(UserDetails.USER_ID, client.getUserDetails().getUserId()) .add(UserDetails.USERNAME, client.getUserDetails().getUserName()) - .add(AGE, client.getBirthday().getDuration()) + .add(SessionDetails.AGE, client.getBirthday().getDuration()) .add("OUTPUT_ROUND_TRIP", client.getOutputRoundAroundDuration()) .add(ProxyClient.IS_USED, client.getTwoKindSemaphore().isUsed()) .add(ControllerStateDetails.RPM, rpm) diff --git a/java_tools/proxy_server/src/main/java/com/rusefi/server/Monitoring.java b/java_tools/proxy_server/src/main/java/com/rusefi/server/Monitoring.java index c19e30d3b9..f3bebc1b05 100644 --- a/java_tools/proxy_server/src/main/java/com/rusefi/server/Monitoring.java +++ b/java_tools/proxy_server/src/main/java/com/rusefi/server/Monitoring.java @@ -74,7 +74,7 @@ public class Monitoring { builder.add("framework version", rusEFIVersion.CONSOLE_VERSION); builder.add("compiled", new Date(rusEFIVersion.classBuildTimeMillis()).toString()); builder.add("now", System.currentTimeMillis()); - builder.add(Backend.AGE, birthday.getDuration()); + builder.add(SessionDetails.AGE, birthday.getDuration()); return new RsJson(builder.build()); } diff --git a/java_tools/proxy_server/src/test/java/com/rusefi/server/SessionDetailsTest.java b/java_tools/proxy_server/src/test/java/com/rusefi/server/SessionDetailsTest.java index c7f48d8705..0ce0869567 100644 --- a/java_tools/proxy_server/src/test/java/com/rusefi/server/SessionDetailsTest.java +++ b/java_tools/proxy_server/src/test/java/com/rusefi/server/SessionDetailsTest.java @@ -11,7 +11,7 @@ public class SessionDetailsTest { @Test public void testSerialization() { - SessionDetails sd = new SessionDetails(NetworkConnector.Implementation.Unknown, TestHelper.CONTROLLER_INFO, "auth", 123, rusEFIVersion.CONSOLE_VERSION); + SessionDetails sd = new SessionDetails(NetworkConnector.Implementation.Unknown, TestHelper.CONTROLLER_INFO, "auth", 123, rusEFIVersion.CONSOLE_VERSION, ""); String json = sd.toJson(); SessionDetails fromJson = SessionDetails.valueOf(json); @@ -20,7 +20,7 @@ public class SessionDetailsTest { @Test public void testApplicationRequest() { - SessionDetails sd = new SessionDetails(NetworkConnector.Implementation.Unknown, TestHelper.CONTROLLER_INFO, "auth", 123, rusEFIVersion.CONSOLE_VERSION); + SessionDetails sd = new SessionDetails(NetworkConnector.Implementation.Unknown, TestHelper.CONTROLLER_INFO, "auth", 123, rusEFIVersion.CONSOLE_VERSION, ""); ApplicationRequest ar = new ApplicationRequest(sd, new UserDetails("", 321)); String json = ar.toJson(); diff --git a/java_tools/ts_plugin/src/main/java/com/rusefi/SignatureHelper.java b/java_tools/ts_plugin/src/main/java/com/rusefi/SignatureHelper.java index bbd4271ca6..77605285d5 100644 --- a/java_tools/ts_plugin/src/main/java/com/rusefi/SignatureHelper.java +++ b/java_tools/ts_plugin/src/main/java/com/rusefi/SignatureHelper.java @@ -1,10 +1,13 @@ package com.rusefi; +import com.rusefi.core.Pair; + public class SignatureHelper { public static final String PREFIX = "rusEFI "; + public static final char SLASH = '/'; - public static String getUrl(String signature) { + public static Pair getUrl(String signature) { if (!signature.startsWith(PREFIX)) return null; signature = signature.substring(PREFIX.length()).trim(); @@ -18,6 +21,7 @@ public class SignatureHelper { String bundle = elements[3]; String hash = elements[4]; - return "https://rusefi.com/online/ini/rusefi/" + year + "/" + month + "/" + day + "/" + bundle + "/" + hash + ".ini"; + String fileName = hash + ".ini"; + return new Pair("https://rusefi.com/online/ini/rusefi/" + year + SLASH + month + SLASH + day + SLASH + bundle + SLASH + fileName, fileName); } } diff --git a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/PluginEntry.java b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/PluginEntry.java index e10c4844d6..dd6e4aac6f 100644 --- a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/PluginEntry.java +++ b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/PluginEntry.java @@ -2,6 +2,7 @@ package com.rusefi.ts_plugin; import com.efiAnalytics.plugin.ecu.ControllerAccess; import com.rusefi.autoupdate.AutoupdateUtil; +import com.rusefi.ts_plugin.auth.InstanceAuthContext; import com.rusefi.ts_plugin.util.ManifestHelper; import com.rusefi.tune.xml.Constant; @@ -12,6 +13,7 @@ import java.util.function.Supplier; /** * {@link TsPluginLauncher} creates an instance of this class via reflection. + * * @see TuneUploadTab upload tune & TODO upload logs * @see RemoteTab remote ECU access & control * @see BroadcastTab offer your ECU for remove access & control @@ -52,6 +54,18 @@ public class PluginEntry implements TsPluginBody { tabbedPane.addTab("Remote ECU", remoteTab.getContent()); tabbedPane.addTab("Read SD Card", new SdCardReader(controllerAccessSupplier).getContent()); content.add(tabbedPane); + + InstanceAuthContext.startup(); + } + + public static String getNonDaemonThreads() { + StringBuilder sb = new StringBuilder(); + for (Thread thread : Thread.getAllStackTraces().keySet()) { + // Daemon thread will not prevent the JVM from exiting + if (!thread.isDaemon()) + sb.append(thread.getName() + "\n"); + } + return sb.toString(); } private boolean isLauncherTooOld() { 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 c912f35709..30dc22244c 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 @@ -4,6 +4,7 @@ import com.rusefi.NamedThreadFactory; import com.rusefi.SignatureHelper; import com.rusefi.Timeouts; import com.rusefi.autoupdate.AutoupdateUtil; +import com.rusefi.core.Pair; import com.rusefi.io.serial.StreamStatistics; import com.rusefi.io.tcp.ServerSocketReference; import com.rusefi.io.tcp.TcpIoStream; @@ -18,6 +19,8 @@ import com.rusefi.server.UserDetails; import com.rusefi.tools.online.HttpUtil; import com.rusefi.tools.online.ProxyClient; import com.rusefi.tools.online.PublicSession; +import com.rusefi.ts_plugin.auth.InstanceAuthContext; +import com.rusefi.ts_plugin.auth.SelfInfo; import com.rusefi.ui.AuthTokenPanel; import com.rusefi.ui.util.URLLabel; import org.jetbrains.annotations.NotNull; @@ -45,6 +48,8 @@ public class RemoteTab { private static final String APPLICATION_PORT = "application_port"; public static final String HOWTO_REMOTE_TUNING = "https://github.com/rusefi/rusefi/wiki/HOWTO-Remote-Tuning"; private final JComponent content = new JPanel(new BorderLayout()); + private final JScrollPane scroll = new JScrollPane(content, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + private final JPanel list = new JPanel(new VerticalFlowLayout()); private final JTextField oneTimePasswordControl = new JTextField("0") { @@ -61,18 +66,18 @@ public class RemoteTab { private final JButton disconnect = new JButton("Disconnect"); - private final Executor listDownloadExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("online list downloader")); + private final Executor listDownloadExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("online list downloader", true)); public RemoteTab() { - JButton refresh = new JButton("Refresh List"); - refresh.addActionListener(e -> requestListDownload()); + JButton refresh = new JButton("Refresh Remote Controllers List"); + refresh.addActionListener(e -> requestControllersList()); disconnect.addActionListener(e -> { LocalApplicationProxy localApplicationProxy = RemoteTabController.INSTANCE.getLocalApplicationProxy(); if (localApplicationProxy != null) localApplicationProxy.close(); RemoteTabController.INSTANCE.setState(RemoteTabController.State.NOT_CONNECTED); - requestListDownload(); + requestControllersList(); }); @@ -100,24 +105,23 @@ public class RemoteTab { JPanel topLines = new JPanel(new VerticalFlowLayout()); - - JPanel topPanel = new JPanel(new FlowLayout()); - topPanel.add(refresh); - topPanel.add(new JLabel(" Local Port: ")); - topPanel.add(applicationPort); - topPanel.add(new JLabel(" One time password:")); - topPanel.add(oneTimePasswordControl); - - topLines.add(topPanel); topLines.add(new URLLabel(HOWTO_REMOTE_TUNING)); + topLines.add(new SelfInfo().getContent()); + topLines.add(refresh); + topLines.add(new JLabel("Local Port for tuning software")); + topLines.add(applicationPort); + topLines.add(new JLabel("One time password:")); + topLines.add(oneTimePasswordControl); content.add(topLines, BorderLayout.NORTH); content.add(list, BorderLayout.CENTER); list.add(new JLabel("Requesting list of ECUs")); + InstanceAuthContext.listeners.add(userDetails -> requestControllersList()); + LocalApplicationProxy currentState = RemoteTabController.INSTANCE.getLocalApplicationProxy(); if (currentState == null) { - requestListDownload(); + requestControllersList(); } else { setConnectedStatus(currentState.getApplicationRequest().getVehicleOwner(), null, currentState.getApplicationRequest().getSessionDetails().getControllerInfo()); @@ -128,15 +132,13 @@ public class RemoteTab { return getConfig().getRoot().getProperty(APPLICATION_PORT, "29001"); } - private void requestListDownload() { + private void requestControllersList() { listDownloadExecutor.execute(() -> { - List userDetails; try { - userDetails = ProxyClient.getOnlineApplications(HttpUtil.PROXY_JSON_API_HTTP_PORT); + List userDetails = ProxyClient.getOnlineApplications(HttpUtil.PROXY_JSON_API_HTTP_PORT); SwingUtilities.invokeLater(() -> showList(userDetails)); } catch (IOException e) { e.printStackTrace(); - return; } }); } @@ -150,20 +152,20 @@ public class RemoteTab { } else { JPanel verticalPanel = new JPanel(new VerticalFlowLayout()); - JScrollPane scroll = new JScrollPane(verticalPanel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - list.add(scroll); + list.add(verticalPanel); for (PublicSession user : userDetails) { - verticalPanel.add(createSessionControl(user)); + verticalPanel.add(createControllerRow(user)); } } AutoupdateUtil.trueLayout(list); } - private JComponent createSessionControl(PublicSession publicSession) { + private JComponent createControllerRow(PublicSession publicSession) { + ControllerInfo controllerInfo = publicSession.getControllerInfo(); + JComponent topLine = new JPanel(new FlowLayout()); topLine.add(new JLabel(publicSession.getVehicleOwner().getUserName())); - ControllerInfo controllerInfo = publicSession.getControllerInfo(); topLine.add(new JLabel(controllerInfo.getVehicleName() + " " + controllerInfo.getEngineMake() + " " + controllerInfo.getEngineCode())); JPanel bottomPanel = new JPanel(new FlowLayout()); @@ -175,26 +177,34 @@ public class RemoteTab { connect.addActionListener(event -> connectToProxy(publicSession)); bottomPanel.add(connect); - JButton updateSoftware = new JButton("Update Connector"); - updateSoftware.addActionListener(new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - try { - LocalApplicationProxy.requestSoftwareUpdate(HttpUtil.PROXY_JSON_API_HTTP_PORT, - getApplicationRequest(publicSession)); - } catch (IOException ioException) { - ioException.printStackTrace(); + if (InstanceAuthContext.isOurController(publicSession.getVehicleOwner().getUserId())) { + JButton updateSoftware = new JButton("Update Connector"); + updateSoftware.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + try { + LocalApplicationProxy.requestSoftwareUpdate(HttpUtil.PROXY_JSON_API_HTTP_PORT, + getApplicationRequest(publicSession)); + } catch (IOException ioException) { + ioException.printStackTrace(); + } } - } - }); - bottomPanel.add(updateSoftware); + }); + bottomPanel.add(updateSoftware); + } } JPanel userPanel = new JPanel(new BorderLayout()); + + JPanel infoLine = new JPanel(new FlowLayout()); + infoLine.add(new JLabel("Age " + publicSession.getAge())); + infoLine.add(getSignatureDownload(controllerInfo)); + + userPanel.add(topLine, BorderLayout.NORTH); - userPanel.add(new URLLabel(SignatureHelper.getUrl(controllerInfo.getSignature())), BorderLayout.CENTER); + userPanel.add(infoLine, BorderLayout.CENTER); userPanel.add(bottomPanel, BorderLayout.SOUTH); userPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK)); @@ -202,6 +212,13 @@ public class RemoteTab { return userPanel; } + @NotNull + private URLLabel getSignatureDownload(ControllerInfo controllerInfo) { + Pair url = SignatureHelper.getUrl(controllerInfo.getSignature()); + + return new URLLabel(url.second, url.first); + } + private void connectToProxy(PublicSession publicSession) { RemoteTabController.INSTANCE.setState(RemoteTabController.State.CONNECTING); setStatus("Connecting to " + publicSession.getVehicleOwner().getUserName()); @@ -228,7 +245,7 @@ public class RemoteTab { setStatus("Connected to " + userDetails.getUserName(), new JLabel("You can now connect your TunerStudio to IP address localhost and port " + getLocalPort()), - new URLLabel(SignatureHelper.getUrl(controllerInfo.getSignature())), + new URLLabel(SignatureHelper.getUrl(controllerInfo.getSignature()).first), disconnect, streamStatusControl == null ? null : streamStatusControl.getContent()); } @@ -280,11 +297,10 @@ public class RemoteTab { publicSession.getControllerInfo(), AuthTokenPanel.getAuthToken(), Integer.parseInt(oneTimePasswordControl.getText()), rusEFIVersion.CONSOLE_VERSION); - ApplicationRequest applicationRequest = new ApplicationRequest(sessionDetails, publicSession.getVehicleOwner()); - return applicationRequest; + return new ApplicationRequest(sessionDetails, publicSession.getVehicleOwner()); } public JComponent getContent() { - return content; + return scroll; } } diff --git a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/TuneUploadTab.java b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/TuneUploadTab.java index c9e3a2c0a1..7d933b04b3 100644 --- a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/TuneUploadTab.java +++ b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/TuneUploadTab.java @@ -24,7 +24,7 @@ import java.util.Map; import java.util.function.Supplier; /** - * + * @see PluginBodySandbox */ public class TuneUploadTab { private final JComponent content = new JPanel(new VerticalFlowLayout()); @@ -69,7 +69,7 @@ public class TuneUploadTab { }; upload.setBackground(new Color(0x90EE90)); - new Thread(new Runnable() { + Thread t = new Thread(new Runnable() { @Override public void run() { while (true) { @@ -97,7 +97,9 @@ public class TuneUploadTab { } } } - }).start(); + }); + t.setDaemon(true); + t.start(); upload.addActionListener(new AbstractAction() { @Override diff --git a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/UploadQueue.java b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/UploadQueue.java index f0e81d75b2..fdfb497baf 100644 --- a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/UploadQueue.java +++ b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/UploadQueue.java @@ -26,13 +26,15 @@ public class UploadQueue { return; isStarted = true; readOutbox(); - new Thread(() -> { + Thread t = new Thread(() -> { try { uploadLoop(); } catch (InterruptedException e) { throw new IllegalStateException(e); } - }, "Positing Thread").start(); + }, "Posting Thread"); + t.setDaemon(true); + t.start(); } private static void readOutbox() { diff --git a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/auth/InstanceAuthContext.java b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/auth/InstanceAuthContext.java new file mode 100644 index 0000000000..e3ecc2f58b --- /dev/null +++ b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/auth/InstanceAuthContext.java @@ -0,0 +1,44 @@ +package com.rusefi.ts_plugin.auth; + +import com.devexperts.logging.Logging; +import com.rusefi.server.JsonUserDetailsResolver; +import com.rusefi.server.UserDetails; +import com.rusefi.ui.AuthTokenPanel; + +import java.util.concurrent.CopyOnWriteArrayList; + +public class InstanceAuthContext { + private final static Logging log = Logging.getLogging(InstanceAuthContext.class); + + private static boolean isInitialized; + + public static CopyOnWriteArrayList listeners = new CopyOnWriteArrayList<>(); + + public static UserDetails self; + + public synchronized static void startup() { + if (isInitialized) + return; + if (!AuthTokenPanel.hasToken()) { + // exiting without marking initialized - UI has a chance to re-start the process once token is provided + return; + } + log.info("Startup"); + isInitialized = true; + new Thread(() -> { + self = new JsonUserDetailsResolver().apply(AuthTokenPanel.getAuthToken()); + for (Listener listener : listeners) + listener.onUserDetails(self); + }).start(); + } + + public static boolean isOurController(int userId) { + if (self == null) + return false; + return self.getUserId() == userId; + } + + public interface Listener { + void onUserDetails(UserDetails userDetails); + } +} diff --git a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/auth/SelfInfo.java b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/auth/SelfInfo.java new file mode 100644 index 0000000000..4b389ccd91 --- /dev/null +++ b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/auth/SelfInfo.java @@ -0,0 +1,33 @@ +package com.rusefi.ts_plugin.auth; + +import com.rusefi.server.UserDetails; + +import javax.swing.*; +import java.awt.*; + +public class SelfInfo { + private final JLabel jLabel = new JLabel(); + + public SelfInfo() { + InstanceAuthContext.listeners.add(new InstanceAuthContext.Listener() { + @Override + public void onUserDetails(UserDetails userDetails) { + setInfo(); + } + }); + setInfo(); + } + + private void setInfo() { + UserDetails userDetails = InstanceAuthContext.self; + if (userDetails == null) { + jLabel.setText("Authorizing..."); + } else { + jLabel.setText("Logged in as " + userDetails.getUserName()); + } + } + + public Component getContent() { + return jLabel; + } +} diff --git a/java_tools/ts_plugin/src/test/java/com/rusefi/SignatureHelperTest.java b/java_tools/ts_plugin/src/test/java/com/rusefi/SignatureHelperTest.java index f67e02a7ab..a09477900e 100644 --- a/java_tools/ts_plugin/src/test/java/com/rusefi/SignatureHelperTest.java +++ b/java_tools/ts_plugin/src/test/java/com/rusefi/SignatureHelperTest.java @@ -7,7 +7,7 @@ import static org.junit.Assert.assertEquals; public class SignatureHelperTest { @Test public void test() { - String url = SignatureHelper.getUrl("rusEFI 2020.07.06.frankenso_na6.2468827536"); + String url = SignatureHelper.getUrl("rusEFI 2020.07.06.frankenso_na6.2468827536").first; assertEquals("https://rusefi.com/online/ini/rusefi/2020/07/06/frankenso_na6/2468827536.ini", url); } }