From c56b914a7246b5763a31da4c00b14b9c9b4e5ebc Mon Sep 17 00:00:00 2001 From: Teletha Date: Thu, 11 Jan 2024 23:49:30 +0900 Subject: [PATCH] progress --- src/main/java/bee/api/Loader.java | 239 ++++++++++++++++++++++++++ src/main/java/bee/api/Repository.java | 2 +- src/main/java/bee/api/Transfers.java | 197 --------------------- src/main/java/bee/bun/Bun.java | 31 +--- 4 files changed, 242 insertions(+), 227 deletions(-) create mode 100644 src/main/java/bee/api/Loader.java delete mode 100644 src/main/java/bee/api/Transfers.java diff --git a/src/main/java/bee/api/Loader.java b/src/main/java/bee/api/Loader.java new file mode 100644 index 000000000..88b547910 --- /dev/null +++ b/src/main/java/bee/api/Loader.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2024 Nameless Production Committee + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://opensource.org/licenses/mit-license.php + */ +package bee.api; + +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.http.HttpHeaders; +import java.net.http.HttpResponse; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.aether.AbstractRepositoryListener; +import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.eclipse.aether.transfer.TransferEvent; +import org.eclipse.aether.transfer.TransferEvent.RequestType; +import org.eclipse.aether.transfer.TransferListener; + +import bee.Platform; +import bee.UserInterface; +import bee.util.Inputs; +import kiss.I; +import kiss.Managed; +import kiss.Singleton; +import kiss.WiseConsumer; +import psychopath.File; +import psychopath.Locator; + +/** + * Data transfer manager. + */ +@Managed(Singleton.class) +public class Loader extends AbstractRepositoryListener implements TransferListener { + + /** The user notifier. */ + private final UserInterface ui; + + /** + * @param ui + */ + private Loader(UserInterface ui) { + this.ui = ui; + } + + /** + * {@inheritDoc} + */ + @Override + public void artifactInstalled(RepositoryEvent event) { + ui.info("Install " + event.getArtifact() + " to " + event.getFile()); + } + + /** The progress event interval. (ms) */ + private static final long interval = 200 * 1000 * 1000; + + /** The last progress event time. */ + private long last = 0; + + /** The downloading items. */ + private Map downloading = new ConcurrentHashMap(); + + /** The uploading items. */ + private Map uploading = new ConcurrentHashMap(); + + /** + * {@inheritDoc} + */ + @Override + public void transferInitiated(TransferEvent event) { + boolean download = event.getRequestType() != RequestType.PUT; + Map resources = download ? downloading : uploading; + resources.put(event.getResource().getResourceName(), new Resource(event)); + } + + /** + * {@inheritDoc} + */ + @Override + public void transferStarted(TransferEvent event) throws TransferCancelledException { + } + + /** + * {@inheritDoc} + */ + @Override + public void transferProgressed(TransferEvent event) { + transferProgressed(new Resource(event)); + } + + private void transferProgressed(Resource resource) { + boolean download = resource.type != RequestType.PUT; + Map resources = download ? downloading : uploading; + resources.put(resource.name, resource); + + long now = System.nanoTime(); + if (interval < now - last) { + last = now; // update last event time + + StringBuilder message = new StringBuilder(); + for (Entry entry : resources.entrySet().stream().limit(5).toList()) { + if (!message.isEmpty()) message.append(Platform.EOL); + message.append(buildMessage(download ? "Downloading" : "Uploading", entry.getValue(), true)); + } + ui.trace(message); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void transferSucceeded(TransferEvent event) { + transferSucceeded(new Resource(event)); + } + + private void transferSucceeded(Resource resource) { + boolean download = resource.type != RequestType.PUT; + Map resources = download ? downloading : uploading; + resources.remove(resource.name); + + ui.info(buildMessage(download ? "Downloaded" : "Uploaded", resource, false)); + } + + /** + * {@inheritDoc} + */ + @Override + public void transferFailed(TransferEvent event) { + boolean download = event.getRequestType() != RequestType.PUT; + Map resources = download ? downloading : uploading; + resources.remove(event.getResource().getResourceName()); + } + + /** + * {@inheritDoc} + */ + @Override + public void transferCorrupted(TransferEvent event) { + ui.error(event.getException()); + } + + /** + * Build item transfering message. + * + * @param action + * @param resource + * @param progress + * @return + */ + private static String buildMessage(String action, Resource resource, boolean progress) { + StringBuilder message = new StringBuilder(action).append(" : ").append(name(resource.name)).append(" ("); + if (progress && 0 < resource.size) { + message.append(Inputs.formatAsSize(resource.current, false)).append('/').append(Inputs.formatAsSize(resource.size)); + } else { + message.append(Inputs.formatAsSize(resource.current)); + } + message.append(" @ ").append(resource.repository).append(") "); + + return message.toString(); + } + + /** + * Compute readable resource name. + * + * @param resourceName + * @return + */ + private static String name(String resourceName) { + int last = resourceName.lastIndexOf('/'); + String name = resourceName.substring(last + 1); + + if (name.equals("maven-metadata.xml")) { + return name + " for " + resourceName.substring(resourceName.lastIndexOf('/', last - 1) + 1, last); + } else { + return name; + } + } + + private record Resource(RequestType type, String name, String repository, long size, long current) { + Resource(TransferEvent e) { + this(e.getRequestType(), e.getResource().getResourceName(), e.getResource().getRepositoryId(), e.getDataLength(), e + .getTransferredBytes()); + } + } + + /** + * Download file from the specified uri. + * + * @param uri + * @return The temporary downloaded file. + */ + public static File download(String uri) { + File temp = Locator.temporaryFile(); + donwload(uri, temp); + return temp; + } + + /** + * Download file from the specified uri. + * + * @param uri + * @param file + */ + public static void donwload(String uri, File file) { + I.http(uri, HttpResponse.class).waitForTerminate().to((WiseConsumer) res -> { + String host = URI.create(uri).getHost(); + + // analyze header + HttpHeaders headers = res.headers(); + long total = headers.firstValueAsLong("Content-Length").orElse(0); + + // transfer data + try (InputStream in = (InputStream) res.body(); OutputStream out = new FileOutputStream(file.asJavaFile())) { + int passed = 0; + Loader transfers = I.make(Loader.class); + transfers.transferProgressed(new Resource(RequestType.GET, uri, host, total, passed)); + + int read = -1; + byte[] buffer = new byte[1024 * 32]; + while (0 < (read = in.read(buffer))) { + passed += read; + out.write(buffer, 0, read); + transfers.transferProgressed(new Resource(RequestType.GET, uri, host, total, passed)); + } + transfers.transferSucceeded(new Resource(RequestType.GET, uri, host, total, passed)); + } + }); + } +} \ No newline at end of file diff --git a/src/main/java/bee/api/Repository.java b/src/main/java/bee/api/Repository.java index ab83b8c97..9e14ac6ce 100644 --- a/src/main/java/bee/api/Repository.java +++ b/src/main/java/bee/api/Repository.java @@ -250,7 +250,7 @@ private static final void addRemoteRepository(String name, String url) { session.setConfigProperty("maven.artifact.threads", 24); // event listener - Transfers transfers = I.make(Transfers.class); + Loader transfers = I.make(Loader.class); session.setTransferListener(transfers); session.setRepositoryListener(transfers); diff --git a/src/main/java/bee/api/Transfers.java b/src/main/java/bee/api/Transfers.java deleted file mode 100644 index 3aa42911f..000000000 --- a/src/main/java/bee/api/Transfers.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2024 Nameless Production Committee - * - * Licensed under the MIT License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://opensource.org/licenses/mit-license.php - */ -package bee.api; - -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; - -import org.eclipse.aether.AbstractRepositoryListener; -import org.eclipse.aether.RepositoryEvent; -import org.eclipse.aether.transfer.TransferCancelledException; -import org.eclipse.aether.transfer.TransferEvent; -import org.eclipse.aether.transfer.TransferEvent.RequestType; -import org.eclipse.aether.transfer.TransferListener; - -import bee.Platform; -import bee.UserInterface; -import bee.util.Inputs; -import kiss.Managed; -import kiss.Singleton; - -/** - * Data transfer manager. - */ -@Managed(Singleton.class) -public class Transfers extends AbstractRepositoryListener implements TransferListener { - - /** The user notifier. */ - private final UserInterface ui; - - /** - * @param ui - */ - private Transfers(UserInterface ui) { - this.ui = ui; - } - - /** - * {@inheritDoc} - */ - @Override - public void artifactInstalled(RepositoryEvent event) { - ui.info("Install " + event.getArtifact() + " to " + event.getFile()); - } - - /** The progress event interval. (ms) */ - private static final long interval = 200 * 1000 * 1000; - - /** The last progress event time. */ - private long last = 0; - - /** The downloading items. */ - private Map downloading = new ConcurrentHashMap(); - - /** The uploading items. */ - private Map uploading = new ConcurrentHashMap(); - - /** - * {@inheritDoc} - */ - @Override - public void transferInitiated(TransferEvent event) { - boolean download = event.getRequestType() != RequestType.PUT; - Map resources = download ? downloading : uploading; - resources.put(event.getResource().getResourceName(), event); - } - - /** - * {@inheritDoc} - */ - @Override - public void transferStarted(TransferEvent event) throws TransferCancelledException { - } - - /** - * {@inheritDoc} - */ - @Override - public void transferProgressed(TransferEvent event) { - boolean download = event.getRequestType() != RequestType.PUT; - Map resources = download ? downloading : uploading; - resources.put(event.getResource().getResourceName(), event); - - long now = System.nanoTime(); - if (interval < now - last) { - last = now; // update last event time - - StringBuilder message = new StringBuilder(); - for (Entry entry : resources.entrySet().stream().limit(5).toList()) { - if (!message.isEmpty()) message.append(Platform.EOL); - message.append(buildMessage(download ? "Downloading" : "Uploading", entry.getValue(), true)); - } - ui.trace(message); - } - } - - public void transferProgressed(String resourceName, RequestType type, long current, long total) { - boolean download = type != RequestType.PUT; - Map resources = download ? downloading : uploading; - resources.put(resourceName, event); - - long now = System.nanoTime(); - if (interval < now - last) { - last = now; // update last event time - - StringBuilder message = new StringBuilder(); - for (Entry entry : resources.entrySet().stream().limit(5).toList()) { - if (!message.isEmpty()) message.append(Platform.EOL); - message.append(buildMessage(download ? "Downloading" : "Uploading", entry.getValue(), true)); - } - ui.trace(message); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void transferSucceeded(TransferEvent event) { - boolean download = event.getRequestType() != RequestType.PUT; - Map resources = download ? downloading : uploading; - resources.remove(event.getResource().getResourceName()); - - ui.info(buildMessage(download ? "Downloaded" : "Uploaded", event, false)); - } - - /** - * {@inheritDoc} - */ - @Override - public void transferFailed(TransferEvent event) { - boolean download = event.getRequestType() != RequestType.PUT; - Map resources = download ? downloading : uploading; - resources.remove(event.getResource().getResourceName()); - } - - /** - * {@inheritDoc} - */ - @Override - public void transferCorrupted(TransferEvent event) { - ui.error(event.getException()); - } - - /** - * @param string - * @param event - * @param b - * @return - */ - private static String buildMessage(String type, TransferEvent event, boolean progress) { - return buildMessage(event.getResource().getResourceName()); - } - - /** - * Build item transfering message. - * - * @param type - * @param event - * @return - */ - private static String buildMessage(String resourceName, String type, long size, long current, String repositoryId, boolean progress) { - StringBuilder message = new StringBuilder(type).append(" : ").append(name(resourceName)).append(" ("); - if (progress && 0 < size) { - message.append(Inputs.formatAsSize(current, false)).append('/').append(Inputs.formatAsSize(size)); - } else { - message.append(Inputs.formatAsSize(current)); - } - message.append(" @ ").append(repositoryId).append(") "); - - return message.toString(); - } - - /** - * Compute readable resource name. - * - * @param resourceName - * @return - */ - private static String name(String resourceName) { - int last = resourceName.lastIndexOf('/'); - String name = resourceName.substring(last + 1); - - if (name.equals("maven-metadata.xml")) { - return name + " for " + resourceName.substring(resourceName.lastIndexOf('/', last - 1) + 1, last); - } else { - return name; - } - } -} \ No newline at end of file diff --git a/src/main/java/bee/bun/Bun.java b/src/main/java/bee/bun/Bun.java index 8b4171dd1..b14869cf9 100644 --- a/src/main/java/bee/bun/Bun.java +++ b/src/main/java/bee/bun/Bun.java @@ -9,22 +9,14 @@ */ package bee.bun; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.http.HttpHeaders; -import java.net.http.HttpResponse; import java.util.Objects; -import java.util.OptionalLong; import bee.Platform; +import bee.api.Loader; import bee.api.Project; -import bee.api.Transfers; import kiss.I; -import kiss.WiseConsumer; import psychopath.Directory; import psychopath.File; -import psychopath.Locator; public class Bun { @@ -74,26 +66,7 @@ public void install() { : Platform.isLinux() ? "https://github.com/oven-sh/bun/releases/download/bun-v" + version + "/bun-linux-x64.zip" : "https://github.com/oven-sh/bun/releases/download/bun-v" + version + "/bun-darwin-x64.zip"; - File zip = Locator.temporaryFile(); - - I.http(uri, HttpResponse.class).waitForTerminate().to((WiseConsumer) res -> { - // analyze header - HttpHeaders headers = res.headers(); - OptionalLong length = headers.firstValueAsLong("Content-Length"); - - // transfer data - try (InputStream in = (InputStream) res.body(); OutputStream out = new FileOutputStream(zip.asJavaFile())) { - Transfers transfers = I.make(Transfers.class); - transfers.transferProgressed(0, length.orElse(0)); - - int read = -1; - byte[] buffer = new byte[1024 * 32]; - while (0 < (read = in.read(buffer))) { - out.write(buffer, 0, read); - transfers.transferProgressed(read, length.orElse(0)); - } - } - }); + Loader.download(uri).unpackTo(home); } }