Merge branch 'fix/ui-download-progress' into 'master'
Fix/ui download progress See merge request sheepitrenderfarm/client!298
This commit is contained in:
@@ -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<Callable<Error.Type>> 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())
|
||||
|
||||
@@ -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++;
|
||||
|
||||
48
src/main/java/com/sheepit/client/DownloadProgress.java
Normal file
48
src/main/java/com/sheepit/client/DownloadProgress.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Laurent CLOUET
|
||||
* Author Laurent CLOUET <laurent.clouet@nopnop.net>
|
||||
*
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user