From ad8c7d2a62f263a04c5c6e14d73580cee6c2305c Mon Sep 17 00:00:00 2001 From: Lenni0451 <20379977+Lenni0451@users.noreply.github.com> Date: Thu, 12 Jan 2023 19:43:52 +0100 Subject: [PATCH] Added auto updater --- .../java/net/raphimc/viaproxy/ViaProxy.java | 61 ++------ .../viaproxy/tasks/AccountRefreshTask.java | 36 +++++ .../raphimc/viaproxy/tasks/LoaderTask.java | 31 ++++ .../viaproxy/tasks/UpdatedCheckTask.java | 117 ++++++++++++++ .../viaproxy/ui/popups/DownloadPopup.java | 145 ++++++++++++++++++ 5 files changed, 339 insertions(+), 51 deletions(-) create mode 100644 src/main/java/net/raphimc/viaproxy/tasks/AccountRefreshTask.java create mode 100644 src/main/java/net/raphimc/viaproxy/tasks/LoaderTask.java create mode 100644 src/main/java/net/raphimc/viaproxy/tasks/UpdatedCheckTask.java create mode 100644 src/main/java/net/raphimc/viaproxy/ui/popups/DownloadPopup.java diff --git a/src/main/java/net/raphimc/viaproxy/ViaProxy.java b/src/main/java/net/raphimc/viaproxy/ViaProxy.java index 7038afa..f0c1a05 100644 --- a/src/main/java/net/raphimc/viaproxy/ViaProxy.java +++ b/src/main/java/net/raphimc/viaproxy/ViaProxy.java @@ -17,8 +17,6 @@ */ package net.raphimc.viaproxy; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import io.netty.channel.Channel; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; @@ -36,20 +34,18 @@ import net.raphimc.netminecraft.netty.connection.NetServer; import net.raphimc.viaproxy.cli.ConsoleHandler; import net.raphimc.viaproxy.cli.options.Options; import net.raphimc.viaproxy.injection.Java17ToJava8; -import net.raphimc.viaproxy.plugins.PluginManager; -import net.raphimc.viaproxy.protocolhack.ProtocolHack; import net.raphimc.viaproxy.proxy.ProxyConnection; import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyChannelInitializer; import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyHandler; import net.raphimc.viaproxy.saves.SaveManager; +import net.raphimc.viaproxy.tasks.AccountRefreshTask; +import net.raphimc.viaproxy.tasks.LoaderTask; +import net.raphimc.viaproxy.tasks.UpdatedCheckTask; import net.raphimc.viaproxy.ui.ViaProxyUI; import net.raphimc.viaproxy.util.logging.Logger; import javax.swing.*; import java.awt.*; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; public class ViaProxy { @@ -58,6 +54,7 @@ public class ViaProxy { public static SaveManager saveManager; public static NetServer currentProxyServer; public static ChannelGroup c2pChannels; + public static ViaProxyUI ui; public static void main(String[] args) throws Throwable { final IClassProvider classProvider = new GuavaClassPathProvider(); @@ -81,60 +78,22 @@ public class ViaProxy { setNettyParameters(); MCPipeline.useOptimizedPipeline(); c2pChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); - Thread loaderThread = new Thread(() -> { - ProtocolHack.init(); - PluginManager.loadPlugins(); - }, "ViaProtocolHack-Loader"); - Thread accountRefreshThread = new Thread(() -> { - saveManager.accountsSave.refreshAccounts(); - saveManager.save(); - }, "AccountRefresh"); - Thread updateCheckThread = new Thread(() -> { - if (VERSION.startsWith("$")) return; // Dev env check - try { - URL url = new URL("https://api.github.com/repos/RaphiMC/ViaProxy/releases/latest"); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("GET"); - con.setRequestProperty("User-Agent", "ViaProxy/" + VERSION); - con.setConnectTimeout(5000); - con.setReadTimeout(5000); - - InputStream in = con.getInputStream(); - byte[] bytes = new byte[1024]; - int read; - StringBuilder builder = new StringBuilder(); - while ((read = in.read(bytes)) != -1) builder.append(new String(bytes, 0, read)); - con.disconnect(); - - JsonObject object = JsonParser.parseString(builder.toString()).getAsJsonObject(); - String latestVersion = object.get("tag_name").getAsString().substring(1); - if (!VERSION.equals(latestVersion)) { - Logger.LOGGER.warn("You are running an outdated version of ViaProxy! Latest version: " + latestVersion); - if (hasUI) { - SwingUtilities.invokeLater(() -> { - JFrame frontFrame = new JFrame(); - frontFrame.setAlwaysOnTop(true); - JOptionPane.showMessageDialog(frontFrame, "You are running an outdated version of ViaProxy!\nCurrent version: " + VERSION + "\nLatest version: " + latestVersion, "ViaProxy", JOptionPane.WARNING_MESSAGE); - }); - } - } - } catch (Throwable ignored) { - } - }, "UpdateCheck"); + Thread loaderThread = new Thread(new LoaderTask(), "ViaProtocolHack-Loader"); + Thread accountRefreshThread = new Thread(new AccountRefreshTask(saveManager), "AccountRefresh"); + Thread updateCheckThread = new Thread(new UpdatedCheckTask(hasUI), "UpdateCheck"); if (hasUI) { loaderThread.start(); accountRefreshThread.start(); - final ViaProxyUI[] ui = new ViaProxyUI[1]; - SwingUtilities.invokeLater(() -> ui[0] = new ViaProxyUI()); + SwingUtilities.invokeLater(() -> ui = new ViaProxyUI()); updateCheckThread.start(); loaderThread.join(); accountRefreshThread.join(); - while (ui[0] == null) { + while (ui == null) { Logger.LOGGER.info("Waiting for UI to be initialized..."); Thread.sleep(1000); } - ui[0].setReady(); + ui.setReady(); Logger.LOGGER.info("ViaProxy started successfully!"); return; } diff --git a/src/main/java/net/raphimc/viaproxy/tasks/AccountRefreshTask.java b/src/main/java/net/raphimc/viaproxy/tasks/AccountRefreshTask.java new file mode 100644 index 0000000..6fbedf1 --- /dev/null +++ b/src/main/java/net/raphimc/viaproxy/tasks/AccountRefreshTask.java @@ -0,0 +1,36 @@ +/* + * This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy + * Copyright (C) 2023 RK_01/RaphiMC and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.raphimc.viaproxy.tasks; + +import net.raphimc.viaproxy.saves.SaveManager; + +public class AccountRefreshTask implements Runnable { + + private final SaveManager saveManager; + + public AccountRefreshTask(final SaveManager saveManager) { + this.saveManager = saveManager; + } + + @Override + public void run() { + this.saveManager.accountsSave.refreshAccounts(); + this.saveManager.save(); + } + +} diff --git a/src/main/java/net/raphimc/viaproxy/tasks/LoaderTask.java b/src/main/java/net/raphimc/viaproxy/tasks/LoaderTask.java new file mode 100644 index 0000000..8aa320b --- /dev/null +++ b/src/main/java/net/raphimc/viaproxy/tasks/LoaderTask.java @@ -0,0 +1,31 @@ +/* + * This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy + * Copyright (C) 2023 RK_01/RaphiMC and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.raphimc.viaproxy.tasks; + +import net.raphimc.viaproxy.plugins.PluginManager; +import net.raphimc.viaproxy.protocolhack.ProtocolHack; + +public class LoaderTask implements Runnable { + + @Override + public void run() { + ProtocolHack.init(); + PluginManager.loadPlugins(); + } + +} diff --git a/src/main/java/net/raphimc/viaproxy/tasks/UpdatedCheckTask.java b/src/main/java/net/raphimc/viaproxy/tasks/UpdatedCheckTask.java new file mode 100644 index 0000000..8a39854 --- /dev/null +++ b/src/main/java/net/raphimc/viaproxy/tasks/UpdatedCheckTask.java @@ -0,0 +1,117 @@ +/* + * This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy + * Copyright (C) 2023 RK_01/RaphiMC and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.raphimc.viaproxy.tasks; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import net.raphimc.viaproxy.ViaProxy; +import net.raphimc.viaproxy.ui.popups.DownloadPopup; +import net.raphimc.viaproxy.util.logging.Logger; + +import javax.swing.*; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +import static net.raphimc.viaproxy.ViaProxy.VERSION; + +public class UpdatedCheckTask implements Runnable { + + private final boolean hasUI; + + public UpdatedCheckTask(final boolean hasUI) { + this.hasUI = hasUI; + } + + @Override + public void run() { + if (VERSION.startsWith("$")) return; // Dev env check + try { + URL url = new URL("https://api.github.com/repos/RaphiMC/ViaProxy/releases/latest"); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "ViaProxy/" + VERSION); + con.setConnectTimeout(5000); + con.setReadTimeout(5000); + + InputStream in = con.getInputStream(); + byte[] bytes = new byte[1024]; + int read; + StringBuilder builder = new StringBuilder(); + while ((read = in.read(bytes)) != -1) builder.append(new String(bytes, 0, read)); + con.disconnect(); + + JsonObject object = JsonParser.parseString(builder.toString()).getAsJsonObject(); + String latestVersion = object.get("tag_name").getAsString().substring(1); + if (!VERSION.equals(latestVersion)) { + Logger.LOGGER.warn("You are running an outdated version of ViaProxy! Latest version: " + latestVersion); + if (this.hasUI) { + JsonArray assets = object.getAsJsonArray("assets"); + boolean found = false; + for (JsonElement asset : assets) { + JsonObject assetObject = asset.getAsJsonObject(); + if (isViaProxyJar(object, assetObject)) { + found = true; + SwingUtilities.invokeLater(() -> this.showUpdateQuestion(assetObject.get("name").getAsString(), assetObject.get("browser_download_url").getAsString(), latestVersion)); + break; + } + } + if (!found) SwingUtilities.invokeLater(() -> this.showUpdateWarning(latestVersion)); + } + } + } catch (Throwable ignored) { + } + } + + private void showUpdateWarning(final String latestVersion) { + JOptionPane.showMessageDialog(ViaProxy.ui, "You are running an outdated version of ViaProxy!\nCurrent version: " + VERSION + "\nLatest version: " + latestVersion, "ViaProxy", JOptionPane.WARNING_MESSAGE); + } + + private void showUpdateQuestion(final String name, final String downloadUrl, final String latestVersion) { + int chosen = JOptionPane.showConfirmDialog(ViaProxy.ui, "You are running an outdated version of ViaProxy!\nCurrent version: " + VERSION + "\nLatest version: " + latestVersion + "\n\nDo you want to update?", "ViaProxy", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if (chosen == JOptionPane.YES_OPTION) { + File f = new File(name); + new DownloadPopup(ViaProxy.ui, downloadUrl, f, () -> { + SwingUtilities.invokeLater(() -> { + JOptionPane.showMessageDialog(ViaProxy.ui, "Downloaded the latest version of ViaProxy!\nPress OK to restart.", "ViaProxy", JOptionPane.INFORMATION_MESSAGE); + try { + Runtime.getRuntime().exec(new String[]{System.getProperty("java.home") + "/bin/java", "-jar", f.getAbsolutePath()}); + System.exit(0); + } catch (IOException e) { + Logger.LOGGER.error("Could not start the new ViaProxy jar", e); + ViaProxy.ui.showException(e); + } + }); + }, t -> { + if (t != null) { + Logger.LOGGER.error("Could not download the latest version of ViaProxy", t); + ViaProxy.ui.showException(t); + } + }); + } + } + + private boolean isViaProxyJar(final JsonObject root, final JsonObject assetObject) { + return assetObject.get("name").getAsString().equals(root.get("name").getAsString() + ".jar"); + } + +} diff --git a/src/main/java/net/raphimc/viaproxy/ui/popups/DownloadPopup.java b/src/main/java/net/raphimc/viaproxy/ui/popups/DownloadPopup.java new file mode 100644 index 0000000..1034f50 --- /dev/null +++ b/src/main/java/net/raphimc/viaproxy/ui/popups/DownloadPopup.java @@ -0,0 +1,145 @@ +/* + * This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy + * Copyright (C) 2023 RK_01/RaphiMC and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.raphimc.viaproxy.ui.popups; + +import net.raphimc.viaproxy.ViaProxy; +import net.raphimc.viaproxy.ui.ViaProxyUI; + +import javax.swing.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.function.Consumer; + +public class DownloadPopup extends JDialog { + + private final ViaProxyUI parent; + private final String url; + private final File file; + private final Runnable finishListener; + private final Consumer stopConsumer; + + private JProgressBar progressBar; + private Thread downloadThread; + + public DownloadPopup(final ViaProxyUI parent, final String url, final File file, final Runnable finishListener, final Consumer stopConsumer) { + super(parent, true); + this.parent = parent; + this.url = url; + this.file = file; + this.finishListener = finishListener; + this.stopConsumer = stopConsumer; + + this.initWindow(); + this.initComponents(); + this.setVisible(true); + } + + private void initWindow() { + this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + this.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + DownloadPopup.this.close(false); + } + }); + this.setTitle("Downloading..."); + this.setSize(400, 110); + this.setResizable(false); + this.setLocationRelativeTo(this.parent); + } + + private void initComponents() { + JPanel contentPane = new JPanel(); + contentPane.setLayout(null); + this.setContentPane(contentPane); + { + this.progressBar = new JProgressBar(); + this.progressBar.setBounds(10, 10, 365, 20); + this.progressBar.setStringPainted(true); + contentPane.add(this.progressBar); + } + { + JButton cancelButton = new JButton("Cancel"); + cancelButton.setBounds(10, 40, 365, 20); + cancelButton.addActionListener(e -> this.close(false)); + contentPane.add(cancelButton); + } + this.start(); + } + + private void start() { + this.downloadThread = new Thread(() -> { + try { + HttpURLConnection con = (HttpURLConnection) new URL(this.url).openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "Viaproxy/" + ViaProxy.VERSION); + con.setConnectTimeout(5000); + con.setReadTimeout(5000); + + int contentLength = con.getContentLength(); + int current = 0; + File tempFile = File.createTempFile("ViaProxy-download", ""); + InputStream is = con.getInputStream(); + FileOutputStream fos = new FileOutputStream(tempFile); + byte[] buffer = new byte[1024 * 1024]; + int len; + while ((len = is.read(buffer)) != -1) { + if (this.downloadThread.isInterrupted()) throw new InterruptedException(); + fos.write(buffer, 0, len); + + if (contentLength != -1) { + current += len; + this.progressBar.setValue((int) (100F / contentLength * current)); + } + } + fos.close(); + is.close(); + con.disconnect(); + + Files.move(tempFile.toPath(), this.file.toPath(), StandardCopyOption.REPLACE_EXISTING); + + this.close(true); + this.finishListener.run(); + } catch (InterruptedException ignored) { + } catch (Throwable t) { + this.close(false); + this.stopConsumer.accept(t); + } + }, "Download Popup Thread"); + this.downloadThread.setDaemon(true); + this.downloadThread.start(); + } + + private void close(final boolean success) { + if (!success && this.downloadThread != null && this.downloadThread.isAlive()) { + this.downloadThread.interrupt(); + this.stopConsumer.accept(null); + } + + this.setVisible(false); + this.dispose(); + } + +}