package org.limewire.http.webservice;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.limewire.core.api.download.DownloadItem;
import org.limewire.core.api.library.LibraryManager;
import org.limewire.core.api.search.SearchManager;
import org.limewire.core.impl.download.CoreDownloadListManager;
import org.limewire.core.impl.search.SearchManagerImpl.SearchWithResults;
import org.limewire.io.GUID;
import com.limegroup.gnutella.URN;
public class PartialDownloadStreamServlet extends HttpServlet {
private CoreDownloadListManager downloadManager;
private LibraryManager libraryManager;
private SearchManager searchManager;
public PartialDownloadStreamServlet(CoreDownloadListManager downloadManager, SearchManager searchManager, LibraryManager libraryManager) {
this.downloadManager = downloadManager;
this.libraryManager = libraryManager;
this.searchManager = searchManager;
}
@Override
protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
throws ServletException, IOException {
URN urn = URN.createSHA1Urn("urn:sha1:"+httpServletRequest.getParameter("urn"));
GUID guid = new GUID(httpServletRequest.getParameter("guid"));
SearchWithResults searchWithResults = searchManager.getSearchByGuid(guid);
if(libraryManager.getLibraryManagedList().contains(urn)) {
// File is already in the library; just use that
File libraryFile = libraryManager.getLibraryManagedList().getFileDescsByURN(urn).get(0).getFile();
// Send library file to client
this.streamFile(libraryFile, null, httpServletResponse, (int) libraryFile.length());
} else {
// First try to retrieve the in-progress download
DownloadItem download = downloadManager.getDownloadItem(urn);
// If there wasn't an in-progress download, see if we can start one
if(download == null) {
if(searchWithResults != null) {
// File hasn't been downloaded yet, initiate download
download = downloadManager.addDownload(searchWithResults.getSearch(), searchWithResults.getSearchResultsFromUrn(urn));
} else {
// Nothing found, bail
System.out.println("No file found from library, download, or search result!");
httpServletResponse.getOutputStream().close();
return;
}
}
// Wait until we have some data
waitForDownload(download);
// Send data to client
this.streamFile(null, download, httpServletResponse, (int) download.getTotalSize());
}
httpServletResponse.getOutputStream().close();
}
private void waitForDownload(DownloadItem downloadItem) {
int tries = 20;
while(downloadItem.getLaunchableFile() == null && tries > 0) {
System.out.println("Stream not ready yet, sleeping 500ms");
try { Thread.sleep(500); } catch (InterruptedException e) {}
tries--;
}
}
private void streamFile(File file, DownloadItem downloadItem, HttpServletResponse response, int totalSize) throws IOException {
response.setContentLength(totalSize);
String contentType = "application/octet-stream";
String ext = "";
if(file != null) {
ext = file.toString().substring(file.toString().lastIndexOf('.')+1, file.toString().length()).toLowerCase();
} else {
String filename = downloadItem.getFileName();
ext = filename.toString().substring(filename.lastIndexOf('.')+1, filename.length()).toLowerCase();
}
System.out.println(ext);
if(ext != "") {
if(ext.equals("mp4") || ext.equals("flv") || ext.equals("mov") || ext.equals("m4a") ||
ext.equals("mp4v") || ext.equals("3gp") || ext.equals("3g2")) {
contentType = "video/"+ext;
} else {
contentType = "audio/mpeg";
}
}
response.setContentType(contentType);
response.flushBuffer();
System.out.println("Total size is " + totalSize);
ServletOutputStream outputStream = response.getOutputStream();
int offset = 0;
while(offset < totalSize) {
File partial = file;
if(downloadItem != null) {
partial = downloadItem.getLaunchableFile();
}
if(partial.length() - offset < 1024) {
try {
System.out.println("File is still " + offset + " bytes, sleeping 500ms...");
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
byte data[] = new byte[1024];
int read = 0; // Amount read in this session
// Get data from the partial file
FileInputStream stream = new FileInputStream(partial);
stream.skip(offset);
while((read = stream.read(data)) != -1) {
outputStream.write(data, 0, read);
outputStream.flush();
}
// Next time, start from where we left off
offset = (int) partial.length();
System.out.println("Read "+partial.length()+" bytes, next time starting at " + offset + " bytes.");
}
}
}
}