package com.faforever.client.mod; import com.faforever.client.i18n.I18n; import com.faforever.client.io.ByteCopier; import com.faforever.client.io.Unzipper; import com.faforever.client.preferences.PreferencesService; import com.faforever.client.task.CompletableTask; import com.faforever.client.task.ResourceLocks; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Resource; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.invoke.MethodHandles; import java.net.URL; import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; import java.util.zip.ZipInputStream; import static com.faforever.client.task.CompletableTask.Priority.HIGH; public class InstallModTask extends CompletableTask<Void> { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @Resource PreferencesService preferencesService; @Resource I18n i18n; private URL url; public InstallModTask() { super(HIGH); } @Override protected Void call() throws Exception { Objects.requireNonNull(url, "url has not been set"); Path tempFile = Files.createTempFile(preferencesService.getCacheDirectory(), "mod", null); logger.info("Downloading mod {} to {}", url, tempFile); updateTitle(i18n.get("downloadingModTask.downloading", url)); Files.createDirectories(tempFile.getParent()); URLConnection urlConnection = url.openConnection(); int contentLength = urlConnection.getContentLength(); try (InputStream inputStream = urlConnection.getInputStream(); OutputStream outputStream = Files.newOutputStream(tempFile)) { ResourceLocks.acquireDownloadLock(); ByteCopier.from(inputStream) .to(outputStream) .listener(this::updateProgress) .totalBytes(contentLength) .copy(); extractMod(tempFile); } finally { ResourceLocks.freeDownloadLock(); try { Files.deleteIfExists(tempFile); } catch (IOException e) { logger.warn("Could not delete temporary file: " + tempFile.toAbsolutePath(), e); } } return null; } private void extractMod(Path tempFile) throws IOException { Path modsDirectory = preferencesService.getPreferences().getForgedAlliance().getModsDirectory(); updateTitle(i18n.get("downloadingModTask.unzipping", modsDirectory)); logger.info("Unzipping {} to {}", tempFile, modsDirectory); try (ZipInputStream zipInputStream = new ZipInputStream(Files.newInputStream(tempFile))) { ResourceLocks.acquireDiskLock(); Unzipper.from(zipInputStream) .to(modsDirectory) .listener(this::updateProgress) .totalBytes(Files.size(tempFile)) .unzip(); } finally { ResourceLocks.freeDiskLock(); } } public void setUrl(URL url) { this.url = url; } }