package com.rusefi.core.net; import javax.net.ssl.*; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.util.Objects; import java.util.Properties; public class ConnectionAndMeta { public static final String BASE_URL_RELEASE = "https://github.com/rusefi/rusefi/releases/latest/download/"; private static final String AUTOUPDATE = "/autoupdate/"; public static final String BASE_URL_LTS = "https://rusefi.com/build_server/lts/%s/autoupdate/"; private static final int BUFFER_SIZE = 32 * 1024; public static final int CENTUM = 100; public static final String IO_PROPERTIES = "/shared_io.properties"; private final String zipFileName; private HttpsURLConnection httpConnection; private long completeFileSize; private long lastModified; public ConnectionAndMeta(String zipFileName) { this.zipFileName = zipFileName; } public static String getBaseUrl() { Properties props = new Properties(); try { InputStream stream = ConnectionAndMeta.class.getResourceAsStream(IO_PROPERTIES); Objects.requireNonNull(stream, "Error reading " + IO_PROPERTIES); props.load(stream); } catch (IOException e) { throw new RuntimeException(e); } String result = props.getProperty("auto_update_root_url"); System.out.println(ConnectionAndMeta.class + ": got [" + result + "]"); return result + AUTOUPDATE; } public static void downloadFile(String localTargetFileName, ConnectionAndMeta connectionAndMeta, DownloadProgressListener listener) throws IOException { HttpURLConnection httpConnection = connectionAndMeta.getHttpConnection(); long completeFileSize = connectionAndMeta.getCompleteFileSize(); Objects.requireNonNull(httpConnection, "httpConnection"); BufferedInputStream in = new BufferedInputStream(httpConnection.getInputStream()); FileOutputStream fos = new FileOutputStream(localTargetFileName); BufferedOutputStream bout = new BufferedOutputStream(fos, BUFFER_SIZE); byte[] data = new byte[BUFFER_SIZE]; long downloadedFileSize = 0; int newDataSize; int printedPercentage = 0; while ((newDataSize = in.read(data, 0, BUFFER_SIZE)) >= 0) { downloadedFileSize += newDataSize; // calculate progress int currentPercentage = (int) (CENTUM * downloadedFileSize / completeFileSize); if (currentPercentage > printedPercentage + 5) { System.out.println("Downloaded " + currentPercentage + "%"); printedPercentage = currentPercentage; listener.onPercentage(currentPercentage); } bout.write(data, 0, newDataSize); } bout.close(); in.close(); new File(localTargetFileName).setLastModified(connectionAndMeta.getLastModified()); } public HttpURLConnection getHttpConnection() { return httpConnection; } public long getCompleteFileSize() { return completeFileSize; } public long getLastModified() { return lastModified; } public ConnectionAndMeta invoke(String baseUrl) throws IOException { // user can have java with expired certificates or funny proxy, we shall accept any certificate :( SSLContext ctx = null; try { ctx = SSLContext.getInstance("TLS"); ctx.init(new KeyManager[0], new TrustManager[]{new AcceptAnyCertificateTrustManager()}, new SecureRandom()); } catch (NoSuchAlgorithmException | KeyManagementException e) { throw new IOException("TLS exception", e); } URL url = new URL(baseUrl + zipFileName); System.out.println("Connecting to " + url); httpConnection = (HttpsURLConnection) url.openConnection(); httpConnection.setSSLSocketFactory(ctx.getSocketFactory()); completeFileSize = httpConnection.getContentLength(); lastModified = httpConnection.getLastModified(); return this; } public interface DownloadProgressListener { void onPercentage(int currentPercentage); } private static class AcceptAnyCertificateTrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] arg0, String arg1) { } @Override public void checkServerTrusted(X509Certificate[] arg0, String arg1) { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } } }