From 74b39797ce7ed108d2c0deee024479a1308139be Mon Sep 17 00:00:00 2001 From: Laurent Clouet <4409640-laurent.clouet@users.noreply.gitlab.com> Date: Thu, 11 Apr 2024 15:24:50 +0000 Subject: [PATCH] Fix: ui, set a global progress on the download --- src/main/java/com/sheepit/client/Client.java | 8 ++-- .../com/sheepit/client/DownloadManager.java | 21 ++++---- .../com/sheepit/client/DownloadProgress.java | 48 +++++++++++++++++++ src/main/java/com/sheepit/client/Gui.java | 4 +- src/main/java/com/sheepit/client/Server.java | 19 ++++---- .../sheepit/client/standalone/GuiSwing.java | 12 +++-- .../sheepit/client/standalone/GuiText.java | 19 ++++---- .../client/standalone/GuiTextOneLine.java | 24 +++++----- 8 files changed, 97 insertions(+), 58 deletions(-) create mode 100644 src/main/java/com/sheepit/client/DownloadProgress.java diff --git a/src/main/java/com/sheepit/client/Client.java b/src/main/java/com/sheepit/client/Client.java index 75d750a..8d906d2 100644 --- a/src/main/java/com/sheepit/client/Client.java +++ b/src/main/java/com/sheepit/client/Client.java @@ -24,7 +24,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; -import java.sql.Time; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -38,11 +37,9 @@ import java.util.TimerTask; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; @@ -795,6 +792,8 @@ import okhttp3.HttpUrl; ExecutorService executor = Executors.newFixedThreadPool(total); ArrayList> tasks = new ArrayList<>(); + this.gui.getDownloadProgress().reset("Downloading project"); + for (int i = 0; i < total; i++) { Chunk chunk = ajob_.getArchiveChunks().get(i); @@ -804,7 +803,6 @@ import okhttp3.HttpUrl; this.server, this.gui, this.log, - String.format(LOCALE, "chunk %d/%d", finalI + 1, total), this.directoryManager.getActualStoragePathFor(chunk), chunk.getMd5(), String.format(LOCALE, "%s?chunk=%s", this.server.getPage("download-chunk"), chunk.getId()) @@ -839,11 +837,11 @@ import okhttp3.HttpUrl; } protected Error.Type downloadExecutable(Job ajob) throws SheepItException { + this.gui.getDownloadProgress().reset("Downloading Blender"); return (new DownloadManager( this.server, this.gui, this.log, - "renderer", this.directoryManager.getActualStorageBinaryPathFor(ajob), ajob.getRendererMD5(), String.format(LOCALE, "%s?job=%s", this.server.getPage("download-binary"), ajob.getId()) diff --git a/src/main/java/com/sheepit/client/DownloadManager.java b/src/main/java/com/sheepit/client/DownloadManager.java index 8d1c4b2..be7a896 100644 --- a/src/main/java/com/sheepit/client/DownloadManager.java +++ b/src/main/java/com/sheepit/client/DownloadManager.java @@ -36,15 +36,13 @@ public class DownloadManager { private Log log; // task specific objects - private String gui_text; // what do display on the gui private String local_target; private String md5; // expected md5 of the file, for check purpose private String remote; // remote url - public DownloadManager(Server server, Gui gui, Log log, String gui_text, String local_target, String md5, String remote) { + public DownloadManager(Server server, Gui gui, Log log, String local_target, String md5, String remote) { this.server = server; this.gui = gui; - this.gui_text = gui_text; this.log = log; this.local_target = local_target; this.md5 = md5; @@ -61,15 +59,14 @@ public class DownloadManager { do { // if the binary or scene already exists in the cache if (local_path_file.exists()) { - this.gui.status("Reusing cached " + this.gui_text); + this.gui.status("Reusing cached"); return Error.Type.OK; } // if the binary or scene is being downloaded by another client else if (this.lockExists()) { // Wait and check every second for file download completion but only update the GUI every 10 seconds to minimise CPU load if (remaining % 10000 == 0) { - this.gui.status(String.format("Another client is downloading the %s. Cancel in %dmin %ds", - this.gui_text, + this.gui.status(String.format("Another client is downloading. Cancel in %dmin %ds", TimeUnit.MILLISECONDS.toMinutes(remaining), TimeUnit.MILLISECONDS.toSeconds(remaining) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(remaining)) )); @@ -100,16 +97,14 @@ public class DownloadManager { } } - this.gui.status(String.format("Downloading %s", this.gui_text)); + this.gui.status(String.format("Downloading")); return this.downloadActual(); } private Error.Type downloadActual() throws SheepItException { - String update_ui = "Downloading " + this.gui_text; - // must download the archive - Error.Type ret = this.server.HTTPGetFile(this.remote, this.local_target, this.gui, update_ui); + Error.Type ret = this.server.HTTPGetFile(this.remote, this.local_target, this.gui); if (ret == Error.Type.RENDERER_KILLED_BY_SERVER || ret == Error.Type.RENDERER_KILLED_BY_USER_OVER_TIME || ret == Error.Type.RENDERER_KILLED_BY_USER) { return ret; @@ -121,11 +116,11 @@ public class DownloadManager { while ((ret != Error.Type.OK || md5_check == false) && attempts < this.maxDownloadFileAttempts) { if (ret != Error.Type.OK) { - this.gui.error(String.format("Unable to download %s (error %s). Retrying now", this.gui_text, ret)); + this.gui.error(String.format("Unable to download (error %s). Retrying now", ret)); this.log.debug("DownloadManager::downloadActual problem with Server.HTTPGetFile (return: " + ret + ") removing local file (path: " + this.local_target + ")"); } else if (md5_check == false) { - this.gui.error(String.format("Verification of downloaded %s has failed. Retrying now", this.gui_text)); + this.gui.error(String.format("Verification of downloaded %s has failed. Retrying now")); this.log.debug("DownloadManager::downloadActual problem with Client::checkFile mismatch on md5, removing local file (path: " + this.local_target + ")"); } @@ -134,7 +129,7 @@ public class DownloadManager { this.log.debug("DownloadManager::downloadActual failed, let's try again (" + (attempts + 1) + "/" + this.maxDownloadFileAttempts + ") ..."); String partial_target = this.local_target + ".partial"; - ret = this.server.HTTPGetFile(this.remote, partial_target, this.gui, update_ui); + ret = this.server.HTTPGetFile(this.remote, partial_target, this.gui); md5_check = this.check(); attempts++; diff --git a/src/main/java/com/sheepit/client/DownloadProgress.java b/src/main/java/com/sheepit/client/DownloadProgress.java new file mode 100644 index 0000000..644a851 --- /dev/null +++ b/src/main/java/com/sheepit/client/DownloadProgress.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2024 Laurent CLOUET + * Author Laurent CLOUET + * + * 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; version 2 + * of the License. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package com.sheepit.client; + +public class DownloadProgress { + // global objects + private Gui gui; + + private String guiPattern = ""; + + private long total = 0; + private long partial = 0; + + public DownloadProgress(Gui gui) { + this.gui = gui; + } + + public synchronized void reset(String pattern) { + this.guiPattern = pattern; + this.total = 0; + this.partial = 0; + } + + public synchronized void addTotal(long size) { + this.total += size; + } + + public synchronized void addProgress(long progress) { + this.partial += progress; + gui.status(String.format(this.guiPattern + " %.0f %%", 100.0f * this.partial / this.total)); + } +} diff --git a/src/main/java/com/sheepit/client/Gui.java b/src/main/java/com/sheepit/client/Gui.java index 2bf9729..7f0dad8 100644 --- a/src/main/java/com/sheepit/client/Gui.java +++ b/src/main/java/com/sheepit/client/Gui.java @@ -30,8 +30,6 @@ public interface Gui { public void status(String msg_, int progress); - public void status(String msg_, int progress, long size); - public void updateTrayIcon(Integer percentage_); public void setRenderingProjectName(String name_); @@ -57,4 +55,6 @@ public interface Gui { public void setComputeMethod(String computeMethod_); public Client getClient(); + + public DownloadProgress getDownloadProgress(); } diff --git a/src/main/java/com/sheepit/client/Server.java b/src/main/java/com/sheepit/client/Server.java index d6d6b4f..c609687 100644 --- a/src/main/java/com/sheepit/client/Server.java +++ b/src/main/java/com/sheepit/client/Server.java @@ -491,7 +491,7 @@ public class Server extends Thread { } } - public Error.Type HTTPGetFile(String url_, String destination_, Gui gui_, String status_) throws SheepItException { + public Error.Type HTTPGetFile(String url_, String destination_, Gui gui_) throws SheepItException { this.log.debug("Server::HTTPGetFile destination: " + destination_); InputStream is = null; OutputStream output = null; @@ -508,10 +508,14 @@ public class Server extends Thread { output = new FileOutputStream(destination_ + ".partial"); long size = response.body().contentLength(); - byte[] buffer = new byte[8 * 1024]; + // only update the gui every 1MB + byte[] buffer = new byte[1024 * 1024]; int len = 0; long written = 0; - long lastUpd = 0; // last GUI progress update + + if (size != -1) { + gui_.getDownloadProgress().addTotal(size); + } this.log.debug("Downloading file from " + response.request().url().host()); LocalDateTime startRequestTime = LocalDateTime.now(); @@ -526,20 +530,13 @@ public class Server extends Thread { output.write(buffer, 0, len); written += len; - - if ((written - lastUpd) > 1000000) { // only update the gui every 1MB - if (size != -1) { // no header for contentlength - gui_.status(status_, (int) (100.0 * written / size), written); - } - lastUpd = written; - } + gui_.getDownloadProgress().addProgress(len); } LocalDateTime endRequestTime = LocalDateTime.now(); Duration duration = Duration.between(startRequestTime, endRequestTime); this.dlStats.calc(written, ((duration.getSeconds() * 1000) + (duration.getNano() / 1000000))); gui_.displayTransferStats(dlStats, ulStats); - gui_.status(status_, 100, size); this.log.debug(String.format("File downloaded at %s/s, written %d bytes", new TransferStats(size, duration.toMillis() + 1).getAverageSessionSpeed(), written)); diff --git a/src/main/java/com/sheepit/client/standalone/GuiSwing.java b/src/main/java/com/sheepit/client/standalone/GuiSwing.java index 0a60bf3..8fc410e 100644 --- a/src/main/java/com/sheepit/client/standalone/GuiSwing.java +++ b/src/main/java/com/sheepit/client/standalone/GuiSwing.java @@ -24,6 +24,7 @@ import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLightLaf; import com.sheepit.client.Client; import com.sheepit.client.Configuration; +import com.sheepit.client.DownloadProgress; import com.sheepit.client.Gui; import com.sheepit.client.SettingsLoader; import com.sheepit.client.Stats; @@ -132,6 +133,7 @@ public class GuiSwing extends JFrame implements Gui { private boolean waitingForAuthentication; private Client client; + private DownloadProgress downloadProgress; private BufferedImage iconSprites; private BufferedImage[] trayIconSprites; @@ -141,6 +143,7 @@ public class GuiSwing extends JFrame implements Gui { private ThreadClient threadClient; public GuiSwing(boolean useSysTray_, String title_) { + downloadProgress = new DownloadProgress(this); framesRendered = 0; useSysTray = useSysTray_; title = title_; @@ -272,10 +275,6 @@ public class GuiSwing extends JFrame implements Gui { } } - @Override public void status(String msg, int progress, long size) { - this.status(msg, progress); - } - @Override public void setRenderingProjectName(String name_) { if (activityWorking != null) { this.activityWorking.setRenderingProjectName(name_); @@ -329,6 +328,10 @@ public class GuiSwing extends JFrame implements Gui { return client; } + @Override public DownloadProgress getDownloadProgress() { + return downloadProgress; + } + @Override public void setClient(Client cli) { client = cli; } @@ -496,5 +499,4 @@ public class GuiSwing extends JFrame implements Gui { } } } - } diff --git a/src/main/java/com/sheepit/client/standalone/GuiText.java b/src/main/java/com/sheepit/client/standalone/GuiText.java index 2abf35f..9a3b286 100644 --- a/src/main/java/com/sheepit/client/standalone/GuiText.java +++ b/src/main/java/com/sheepit/client/standalone/GuiText.java @@ -20,6 +20,7 @@ package com.sheepit.client.standalone; import com.sheepit.client.Client; +import com.sheepit.client.DownloadProgress; import com.sheepit.client.Gui; import com.sheepit.client.Log; import com.sheepit.client.Stats; @@ -46,8 +47,10 @@ public class GuiText implements Gui { private String eta; private Client client; + private DownloadProgress downloadProgress; public GuiText() { + this.downloadProgress = new DownloadProgress(this); this.framesRendered = 0; this.log = Log.getInstance(null); this.df = new SimpleDateFormat("MMM dd HH:mm:ss"); @@ -117,12 +120,8 @@ public class GuiText implements Gui { } @Override public void status(String msg, int progress) { - this.status(msg, progress, 0); - } - - @Override public void status(String msg, int progress, long size) { System.out.print("\r"); - System.out.print(String.format("%s %s", this.df.format(new Date()), showProgress(msg, progress, size))); + System.out.print(String.format("%s %s", this.df.format(new Date()), showProgress(msg, progress))); } @Override public void error(String err_) { @@ -178,11 +177,15 @@ public class GuiText implements Gui { return client; } + @Override public DownloadProgress getDownloadProgress() { + return downloadProgress; + } + @Override public void successfulAuthenticationEvent(String publickey) { } - private String showProgress(String message, int progress, long size) { + private String showProgress(String message, int progress) { StringBuilder progressBar = new StringBuilder(140); if (progress < 100) { @@ -196,10 +199,6 @@ public class GuiText implements Gui { .append(String.join("", Collections.nCopies(20 - (int)(progress / 5), " "))) .append(']'); - if (size > 0) { - progressBar.append(String.format(" %dMB", (size / 1024 / 1024))); - } - if (!this.eta.equals("")) { progressBar.append(String.format(" ETA %s", this.eta)); } diff --git a/src/main/java/com/sheepit/client/standalone/GuiTextOneLine.java b/src/main/java/com/sheepit/client/standalone/GuiTextOneLine.java index 7e6947f..ef69ea7 100644 --- a/src/main/java/com/sheepit/client/standalone/GuiTextOneLine.java +++ b/src/main/java/com/sheepit/client/standalone/GuiTextOneLine.java @@ -20,6 +20,7 @@ package com.sheepit.client.standalone; import com.sheepit.client.Client; +import com.sheepit.client.DownloadProgress; import com.sheepit.client.Gui; import com.sheepit.client.Stats; import com.sheepit.client.TransferStats; @@ -55,8 +56,10 @@ public class GuiTextOneLine implements Gui { private boolean exiting = false; private Client client; + private DownloadProgress downloadProgress; public GuiTextOneLine() { + downloadProgress = new DownloadProgress(this); project = ""; rendered = 0; remaining = 0; @@ -118,22 +121,19 @@ public class GuiTextOneLine implements Gui { @Override public void status(String msg_, boolean overwriteSuspendedMsg) { if (client != null && client.isSuspended()) { if (overwriteSuspendedMsg) { - status = msg_; + status = msg_.replace("%", "%%"); // escape % updateLine(); } } else { - status = msg_; + status = msg_.replace("%", "%%"); // escape % updateLine(); } + } @Override public void status(String msg, int progress) { - this.status(msg, progress, 0); - } - - @Override public void status(String msg, int progress, long size) { - status = showProgress(msg, progress, size); + status = showProgress(msg, progress); updateLine(); } @@ -186,6 +186,10 @@ public class GuiTextOneLine implements Gui { client = cli; } + @Override public DownloadProgress getDownloadProgress() { + return downloadProgress; + } + @Override public void setComputeMethod(String computeMethod_) { computeMethod = computeMethod_; } @@ -224,7 +228,7 @@ public class GuiTextOneLine implements Gui { } } - private String showProgress(String message, int progress, long size) { + private String showProgress(String message, int progress) { StringBuilder progressBar = new StringBuilder(140); progressBar .append(message) @@ -235,10 +239,6 @@ public class GuiTextOneLine implements Gui { .append(String.join("", Collections.nCopies(10 - (int) (progress / 10), " "))) .append(']'); - if (size > 0) { - progressBar.append(String.format(" %dMB", (size / 1024 / 1024))); - } - if (!this.eta.equals("")) { progressBar.append(String.format(" ETA %s", this.eta)); }