/* * This file is part of Spoutcraft. * * Copyright (c) 2011 SpoutcraftDev <http://spoutcraft.org/> * Spoutcraft is licensed under the GNU Lesser General Public License. * * Spoutcraft is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Spoutcraft 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.spoutcraft.client.io; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.HashSet; import java.util.Iterator; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicLong; public class FileDownloadThread extends Thread { private static FileDownloadThread instance = null; private final ConcurrentLinkedQueue<Download> downloads = new ConcurrentLinkedQueue<Download>(); private final ConcurrentLinkedQueue<Runnable> actions = new ConcurrentLinkedQueue<Runnable>(); private final HashSet<String> failedUrls = new HashSet<String>(); private final byte[] buffer = new byte[1024*1024]; private volatile String activeDownload = null; private boolean spoutDebug = false; public static AtomicLong preCacheCompleted = new AtomicLong(0L); protected FileDownloadThread() { super("File Download Thread"); } public static FileDownloadThread getInstance() { if (instance == null) { instance = new FileDownloadThread(); instance.start(); } return instance; } public void addToDownloadQueue(Download download) { downloads.add(download); } public boolean isDownloading(String url) { Iterator<Download> i = downloads.iterator(); while (i.hasNext()) { Download download = i.next(); if (download.getDownloadUrl().equals(url)) { return true; } } return false; } public void onTick() { if (!actions.isEmpty()) { Iterator<Runnable> i = actions.iterator(); while (i.hasNext()) { Runnable action = i.next(); try { action.run(); } catch(Exception e) { System.out.println("Could not run Runnable for download finish:"); e.printStackTrace(); } i.remove(); } } } public void abort() { this.interrupt(); downloads.clear(); actions.clear(); failedUrls.clear(); } public String getActiveDownload() { return activeDownload; } public int getDownloadsRemaining() { return downloads.size(); } public void run() { while (true) { Download next = downloads.poll(); if (next != null && !failedUrls.contains(next.getDownloadUrl())) { try { if (!next.isDownloaded()) { if (spoutDebug) { System.out.println("Downloading File: " + next.getDownloadUrl()); } activeDownload = FileUtil.getFileName(next.getDownloadUrl()); URL url = new URL(next.getDownloadUrl()); URLConnection conn = url.openConnection(); conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2"); conn.setReadTimeout(10000); //10s timeout InputStream in = conn.getInputStream(); FileOutputStream fos = new FileOutputStream(next.getTempFile()); BufferedOutputStream bos = new BufferedOutputStream(fos); long length = conn.getContentLength(); int bytes; long totalBytes = 0; long last = 0; long step = Math.max(1024*1024, length / 8); while ((bytes = in.read(buffer)) >= 0) { bos.write(buffer, 0, bytes); totalBytes += bytes; next.setProgress((int) (((double)totalBytes / (double)length) * 100)); if (length > 0 && totalBytes > (last + step)) { last = totalBytes; long mb = totalBytes/(1024*1024); if (spoutDebug) { System.out.println("Downloading: " + next.getDownloadUrl() + " " + mb + "MB/" + (length/(1024*1024))); } } try { Thread.sleep(25); } catch (InterruptedException e) { } } in.close(); bos.close(); next.move(); if (spoutDebug) { System.out.println("File moved to: " + next.directory.getCanonicalPath()); } try { sleep(10); // Cool off after heavy network useage } catch (InterruptedException e) {} } if (next.getCompletedAction() != null) { actions.add(next.getCompletedAction()); } } catch (Exception e) { failedUrls.add(next.getDownloadUrl()); if (spoutDebug) { System.out.println("Download of " + next.getDownloadUrl() + " Failed!"); } } activeDownload = null; } else { try { sleep(100); } catch (InterruptedException e) {} } } } }