Eric Kok
12 years ago
6 changed files with 834 additions and 4 deletions
@ -0,0 +1,238 @@
@@ -0,0 +1,238 @@
|
||||
/* |
||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java,v 1.19 2004/04/18 23:51:37 jsdever Exp $
|
||||
* $Revision: 480424 $ |
||||
* $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $ |
||||
* |
||||
* ==================================================================== |
||||
* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* ==================================================================== |
||||
* |
||||
* This software consists of voluntary contributions made by many |
||||
* individuals on behalf of the Apache Software Foundation. For more |
||||
* information on the Apache Software Foundation, please see |
||||
* <http://www.apache.org/>.
|
||||
* |
||||
*/ |
||||
|
||||
package com.android.internalcopy.http.multipart; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileNotFoundException; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.OutputStream; |
||||
import org.apache.http.util.EncodingUtils; |
||||
|
||||
/** |
||||
* This class implements a part of a Multipart post object that |
||||
* consists of a file. |
||||
* |
||||
* @author <a href="mailto:mattalbright@yahoo.com">Matthew Albright</a> |
||||
* @author <a href="mailto:jsdever@apache.org">Jeff Dever</a> |
||||
* @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a> |
||||
* @author <a href="mailto:becke@u.washington.edu">Michael Becke</a> |
||||
* @author <a href="mailto:mdiggory@latte.harvard.edu">Mark Diggory</a> |
||||
* @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> |
||||
* @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a> |
||||
* |
||||
* @since 2.0 |
||||
* |
||||
*/ |
||||
public class BitCometFilePart extends PartBase { |
||||
|
||||
/** Default content encoding of file attachments. */ |
||||
public static final String DEFAULT_CONTENT_TYPE = "application/x-bittorrent"; |
||||
|
||||
/** Attachment's file name */ |
||||
protected static final String FILE_NAME = "; filename="; |
||||
|
||||
/** Attachment's file name as a byte array */ |
||||
private static final byte[] FILE_NAME_BYTES = |
||||
EncodingUtils.getAsciiBytes(FILE_NAME); |
||||
|
||||
/** Source of the file part. */ |
||||
private PartSource source; |
||||
|
||||
/** |
||||
* FilePart Constructor. |
||||
* |
||||
* @param name the name for this part |
||||
* @param partSource the source for this part |
||||
* @param contentType the content type for this part, if <code>null</code> the |
||||
* {@link #DEFAULT_CONTENT_TYPE default} is used |
||||
* @param charset the charset encoding for this part, if <code>null</code> the |
||||
* {@link #DEFAULT_CHARSET default} is used |
||||
*/ |
||||
public BitCometFilePart(String name, PartSource partSource, String contentType, String charset) { |
||||
|
||||
super( |
||||
name, |
||||
contentType == null ? DEFAULT_CONTENT_TYPE : contentType, |
||||
charset == null ? "ISO-8859-1" : charset, |
||||
null |
||||
); |
||||
|
||||
if (partSource == null) { |
||||
throw new IllegalArgumentException("Source may not be null"); |
||||
} |
||||
this.source = partSource; |
||||
} |
||||
|
||||
/** |
||||
* FilePart Constructor. |
||||
* |
||||
* @param name the name for this part |
||||
* @param partSource the source for this part |
||||
*/ |
||||
public BitCometFilePart(String name, PartSource partSource) { |
||||
this(name, partSource, null, null); |
||||
} |
||||
|
||||
/** |
||||
* FilePart Constructor. |
||||
* |
||||
* @param name the name of the file part |
||||
* @param file the file to post |
||||
* |
||||
* @throws FileNotFoundException if the <i>file</i> is not a normal |
||||
* file or if it is not readable. |
||||
*/ |
||||
public BitCometFilePart(String name, File file) |
||||
throws FileNotFoundException { |
||||
this(name, new FilePartSource(file), null, null); |
||||
} |
||||
|
||||
/** |
||||
* FilePart Constructor. |
||||
* |
||||
* @param name the name of the file part |
||||
* @param file the file to post |
||||
* @param contentType the content type for this part, if <code>null</code> the |
||||
* {@link #DEFAULT_CONTENT_TYPE default} is used |
||||
* @param charset the charset encoding for this part, if <code>null</code> the |
||||
* {@link #DEFAULT_CHARSET default} is used |
||||
* |
||||
* @throws FileNotFoundException if the <i>file</i> is not a normal |
||||
* file or if it is not readable. |
||||
*/ |
||||
public BitCometFilePart(String name, File file, String contentType, String charset) |
||||
throws FileNotFoundException { |
||||
this(name, new FilePartSource(file), contentType, charset); |
||||
} |
||||
|
||||
/** |
||||
* FilePart Constructor. |
||||
* |
||||
* @param name the name of the file part |
||||
* @param fileName the file name |
||||
* @param file the file to post |
||||
* |
||||
* @throws FileNotFoundException if the <i>file</i> is not a normal |
||||
* file or if it is not readable. |
||||
*/ |
||||
public BitCometFilePart(String name, String fileName, File file) |
||||
throws FileNotFoundException { |
||||
this(name, new FilePartSource(fileName, file), null, null); |
||||
} |
||||
|
||||
/** |
||||
* FilePart Constructor. |
||||
* |
||||
* @param name the name of the file part |
||||
* @param fileName the file name |
||||
* @param file the file to post |
||||
* @param contentType the content type for this part, if <code>null</code> the |
||||
* {@link #DEFAULT_CONTENT_TYPE default} is used |
||||
* @param charset the charset encoding for this part, if <code>null</code> the |
||||
* {@link #DEFAULT_CHARSET default} is used |
||||
* |
||||
* @throws FileNotFoundException if the <i>file</i> is not a normal |
||||
* file or if it is not readable. |
||||
*/ |
||||
public BitCometFilePart(String name, String fileName, File file, String contentType, String charset) |
||||
throws FileNotFoundException { |
||||
this(name, new FilePartSource(fileName, file), contentType, charset); |
||||
} |
||||
|
||||
/** |
||||
* Write the disposition header to the output stream |
||||
* @param out The output stream |
||||
* @throws IOException If an IO problem occurs |
||||
* @see Part#sendDispositionHeader(OutputStream) |
||||
*/ |
||||
@Override |
||||
protected void sendDispositionHeader(OutputStream out) |
||||
throws IOException { |
||||
super.sendDispositionHeader(out); |
||||
String filename = this.source.getFileName(); |
||||
if (filename != null) { |
||||
out.write(FILE_NAME_BYTES); |
||||
out.write(QUOTE_BYTES); |
||||
out.write(EncodingUtils.getAsciiBytes(filename)); |
||||
out.write(QUOTE_BYTES); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Write the data in "source" to the specified stream. |
||||
* @param out The output stream. |
||||
* @throws IOException if an IO problem occurs. |
||||
* @see Part#sendData(OutputStream) |
||||
*/ |
||||
@Override |
||||
protected void sendData(OutputStream out) throws IOException { |
||||
if (lengthOfData() == 0) { |
||||
|
||||
// this file contains no data, so there is nothing to send.
|
||||
// we don't want to create a zero length buffer as this will
|
||||
// cause an infinite loop when reading.
|
||||
return; |
||||
} |
||||
|
||||
byte[] tmp = new byte[4096]; |
||||
InputStream instream = source.createInputStream(); |
||||
try { |
||||
int len; |
||||
while ((len = instream.read(tmp)) >= 0) { |
||||
out.write(tmp, 0, len); |
||||
} |
||||
} finally { |
||||
// we're done with the stream, close it
|
||||
instream.close(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the source of the file part. |
||||
* |
||||
* @return The source. |
||||
*/ |
||||
protected PartSource getSource() { |
||||
return this.source; |
||||
} |
||||
|
||||
/** |
||||
* Return the length of the data. |
||||
* @return The length. |
||||
* @see Part#lengthOfData() |
||||
*/ |
||||
@Override |
||||
protected long lengthOfData() { |
||||
return source.getLength(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
package com.android.internalcopy.http.multipart; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
import org.apache.http.util.EncodingUtils; |
||||
|
||||
public class Utf8StringPart extends PartBase { |
||||
|
||||
/** Contents of this StringPart. */ |
||||
private byte[] content; |
||||
|
||||
/** The String value of this part. */ |
||||
private String value; |
||||
|
||||
public Utf8StringPart(String name, String value) { |
||||
super(name, null, null, null); |
||||
this.value = value; |
||||
} |
||||
|
||||
/** |
||||
* Gets the content in bytes. Bytes are lazily created to allow the charset to be changed |
||||
* after the part is created. |
||||
* |
||||
* @return the content in bytes |
||||
*/ |
||||
private byte[] getContent() { |
||||
if (content == null) { |
||||
content = EncodingUtils.getBytes(value, "utf-8"); |
||||
} |
||||
return content; |
||||
} |
||||
|
||||
@Override |
||||
protected void sendData(OutputStream out) throws IOException { |
||||
out.write(getContent()); |
||||
} |
||||
|
||||
@Override |
||||
protected long lengthOfData() throws IOException { |
||||
return getContent().length; |
||||
} |
||||
} |
@ -0,0 +1,536 @@
@@ -0,0 +1,536 @@
|
||||
/* |
||||
* This file is part of Transdroid <http://www.transdroid.org>
|
||||
* |
||||
* Transdroid is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* Transdroid 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 General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
|
||||
* |
||||
*/ |
||||
package org.transdroid.daemon.BitComet; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileNotFoundException; |
||||
import java.io.UnsupportedEncodingException; |
||||
import java.net.URI; |
||||
import java.text.DateFormat; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.ArrayList; |
||||
import java.util.Date; |
||||
import java.util.List; |
||||
|
||||
import org.apache.http.HttpEntity; |
||||
import org.apache.http.HttpResponse; |
||||
import org.apache.http.HttpStatus; |
||||
import org.apache.http.NameValuePair; |
||||
import org.apache.http.client.entity.UrlEncodedFormEntity; |
||||
import org.apache.http.client.methods.HttpGet; |
||||
import org.apache.http.client.methods.HttpPost; |
||||
import org.apache.http.impl.client.DefaultHttpClient; |
||||
import org.apache.http.message.BasicNameValuePair; |
||||
import org.apache.http.protocol.HTTP; |
||||
import org.transdroid.daemon.Daemon; |
||||
import org.transdroid.daemon.DaemonException; |
||||
import org.transdroid.daemon.DaemonSettings; |
||||
import org.transdroid.daemon.IDaemonAdapter; |
||||
import org.transdroid.daemon.Priority; |
||||
import org.transdroid.daemon.Torrent; |
||||
import org.transdroid.daemon.TorrentFile; |
||||
import org.transdroid.daemon.TorrentStatus; |
||||
import org.transdroid.daemon.DaemonException.ExceptionType; |
||||
import org.transdroid.daemon.task.AddByFileTask; |
||||
import org.transdroid.daemon.task.AddByUrlTask; |
||||
import org.transdroid.daemon.task.AddByMagnetUrlTask; |
||||
import org.transdroid.daemon.task.DaemonTask; |
||||
import org.transdroid.daemon.task.DaemonTaskFailureResult; |
||||
import org.transdroid.daemon.task.DaemonTaskResult; |
||||
import org.transdroid.daemon.task.DaemonTaskSuccessResult; |
||||
import org.transdroid.daemon.task.GetFileListTask; |
||||
import org.transdroid.daemon.task.GetFileListTaskSuccessResult; |
||||
import org.transdroid.daemon.task.RemoveTask; |
||||
import org.transdroid.daemon.task.RetrieveTask; |
||||
import org.transdroid.daemon.task.RetrieveTaskSuccessResult; |
||||
import org.transdroid.daemon.util.DLog; |
||||
import org.transdroid.daemon.util.HttpHelper; |
||||
|
||||
import com.android.internalcopy.http.multipart.Part; |
||||
import com.android.internalcopy.http.multipart.MultipartEntity; |
||||
import com.android.internalcopy.http.multipart.BitCometFilePart; |
||||
import com.android.internalcopy.http.multipart.Utf8StringPart; |
||||
|
||||
/** |
||||
* The daemon adapter for the BitComet torrent client. |
||||
* |
||||
* @author SeNS (sensboston) |
||||
* |
||||
*/ |
||||
public class BitCometAdapter implements IDaemonAdapter { |
||||
|
||||
private static final String LOG_NAME = "BitComet daemon"; |
||||
|
||||
private DaemonSettings settings; |
||||
private DefaultHttpClient httpclient; |
||||
|
||||
public BitCometAdapter(DaemonSettings settings) { |
||||
this.settings = settings; |
||||
} |
||||
|
||||
@Override |
||||
public DaemonTaskResult executeTask(DaemonTask task) { |
||||
|
||||
try { |
||||
switch (task.getMethod()) { |
||||
case Retrieve: |
||||
|
||||
// Request all torrents from server
|
||||
String result = makeRequest("/panel/task_list"); |
||||
return new RetrieveTaskSuccessResult((RetrieveTask) task, parseHttpTorrents(result), null); |
||||
|
||||
case GetFileList: |
||||
|
||||
// Request files listing for a specific torrent
|
||||
String fhash = ((GetFileListTask)task).getTargetTorrent().getUniqueID(); |
||||
result = makeRequest("/panel/task_detail", new BasicNameValuePair("id", fhash), new BasicNameValuePair("show", "files")); |
||||
return new GetFileListTaskSuccessResult((GetFileListTask) task, parseHttpTorrentFiles(result, fhash)); |
||||
|
||||
case AddByFile: |
||||
|
||||
// Upload a local .torrent file
|
||||
String ufile = ((AddByFileTask)task).getFile(); |
||||
makeFileUploadRequest("/panel/task_add_bt_result", ufile); |
||||
return new DaemonTaskSuccessResult(task); |
||||
|
||||
case AddByUrl: |
||||
|
||||
// Request to add a torrent by URL
|
||||
String url = ((AddByUrlTask)task).getUrl(); |
||||
makeUploadUrlRequest("/panel/task_add_httpftp_result", url); |
||||
return new DaemonTaskSuccessResult(task); |
||||
|
||||
case AddByMagnetUrl: |
||||
|
||||
// Request to add a torrent by URL
|
||||
String magnetUrl = ((AddByMagnetUrlTask)task).getUrl(); |
||||
makeUploadUrlRequest("/panel/task_add_httpftp_result", magnetUrl); |
||||
return new DaemonTaskSuccessResult(task); |
||||
|
||||
case Remove: |
||||
|
||||
// Remove a torrent
|
||||
RemoveTask removeTask = (RemoveTask) task; |
||||
makeRequest("/panel/task_delete", new BasicNameValuePair("id", removeTask.getTargetTorrent().getUniqueID()), |
||||
new BasicNameValuePair("action", (removeTask.includingData()? "delete_all": "delete_task"))); |
||||
return new DaemonTaskSuccessResult(task); |
||||
|
||||
case Pause: |
||||
|
||||
// Pause a torrent
|
||||
makeRequest("/panel/task_action", new BasicNameValuePair("id", task.getTargetTorrent().getUniqueID()), new BasicNameValuePair("action", "stop")); |
||||
return new DaemonTaskSuccessResult(task); |
||||
|
||||
case Resume: |
||||
|
||||
// Resume a torrent
|
||||
makeRequest("/panel/task_action", new BasicNameValuePair("id", task.getTargetTorrent().getUniqueID()), new BasicNameValuePair("action", "start")); |
||||
return new DaemonTaskSuccessResult(task); |
||||
|
||||
default: |
||||
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported, task.getMethod() + " is not supported by " + getType())); |
||||
} |
||||
} |
||||
catch (DaemonException e) { |
||||
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.ParsingFailed, e.toString())); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Instantiates an HTTP client with proper credentials that can be used for all Buffalo NAS requests. |
||||
* @param connectionTimeout The connection timeout in milliseconds |
||||
* @throws DaemonException On conflicting or missing settings |
||||
*/ |
||||
private void initialise(int connectionTimeout) throws DaemonException { |
||||
|
||||
httpclient = HttpHelper.createStandardHttpClient(settings, true); |
||||
} |
||||
|
||||
/** |
||||
* Build the URL of the http request from the user settings |
||||
* @return The URL to request |
||||
*/ |
||||
private String buildWebUIUrl(String path) { |
||||
return (settings.getSsl() ? "https://" : "http://") + settings.getAddress() + ":" + settings.getPort() + path; |
||||
} |
||||
|
||||
private String makeRequest(String url, NameValuePair... params) throws DaemonException { |
||||
|
||||
try { |
||||
|
||||
// Initialize the HTTP client
|
||||
if (httpclient == null) { |
||||
initialise(HttpHelper.DEFAULT_CONNECTION_TIMEOUT); |
||||
} |
||||
|
||||
// Add the parameters to the query string
|
||||
boolean first = true; |
||||
for (NameValuePair param : params) { |
||||
if (first) { |
||||
url += "?"; |
||||
first = false; |
||||
} else { |
||||
url += "&"; |
||||
} |
||||
url += param.getName() + "=" + param.getValue(); |
||||
} |
||||
|
||||
// Make the request
|
||||
HttpResponse response = httpclient.execute(new HttpGet(buildWebUIUrl(url))); |
||||
HttpEntity entity = response.getEntity(); |
||||
if (entity != null) { |
||||
|
||||
// Read JSON response
|
||||
java.io.InputStream instream = entity.getContent(); |
||||
String result = HttpHelper.ConvertStreamToString(instream); |
||||
instream.close(); |
||||
|
||||
// Return raw result
|
||||
return result; |
||||
} |
||||
|
||||
DLog.d(LOG_NAME, "Error: No entity in HTTP response"); |
||||
throw new DaemonException(ExceptionType.UnexpectedResponse, "No HTTP entity object in response."); |
||||
|
||||
} catch (UnsupportedEncodingException e) { |
||||
throw new DaemonException(ExceptionType.ConnectionError, e.toString()); |
||||
} catch (Exception e) { |
||||
DLog.d(LOG_NAME, "Error: " + e.toString()); |
||||
throw new DaemonException(ExceptionType.ConnectionError, e.toString()); |
||||
} |
||||
|
||||
} |
||||
|
||||
private boolean makeFileUploadRequest(String path, String file) throws DaemonException { |
||||
|
||||
try { |
||||
|
||||
// Initialize the HTTP client
|
||||
if (httpclient == null) { |
||||
initialise(HttpHelper.DEFAULT_CONNECTION_TIMEOUT); |
||||
} |
||||
|
||||
// Get default download file location first
|
||||
HttpResponse response = httpclient.execute(new HttpGet(buildWebUIUrl("/panel/task_add_bt"))); |
||||
HttpEntity entity = response.getEntity(); |
||||
if (entity != null) { |
||||
|
||||
// Read BitComet response
|
||||
java.io.InputStream instream = entity.getContent(); |
||||
String result = HttpHelper.ConvertStreamToString(instream); |
||||
instream.close(); |
||||
|
||||
int idx = result.indexOf("save_path' value='")+18; |
||||
String defaultPath = result.substring(idx, result.indexOf("'>", idx)); |
||||
|
||||
// Setup request using POST
|
||||
HttpPost httppost = new HttpPost(buildWebUIUrl(path)); |
||||
File upload = new File(URI.create(file)); |
||||
Part[] parts = { new BitCometFilePart("torrent_file", upload), new Utf8StringPart("save_path", defaultPath) }; |
||||
httppost.setEntity(new MultipartEntity(parts, httppost.getParams())); |
||||
|
||||
// Make the request
|
||||
response = httpclient.execute(httppost); |
||||
|
||||
entity = response.getEntity(); |
||||
if (entity != null) { |
||||
// Check BitComet response
|
||||
instream = entity.getContent(); |
||||
result = HttpHelper.ConvertStreamToString(instream); |
||||
instream.close(); |
||||
if (result.indexOf("failed!") > 0) throw new Exception("Adding torrent file failed"); |
||||
} |
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK; |
||||
} |
||||
return false; |
||||
|
||||
} catch (FileNotFoundException e) { |
||||
throw new DaemonException(ExceptionType.FileAccessError, e.toString()); |
||||
} catch (Exception e) { |
||||
DLog.d(LOG_NAME, "Error: " + e.toString()); |
||||
throw new DaemonException(ExceptionType.ConnectionError, e.toString()); |
||||
} |
||||
} |
||||
|
||||
private boolean makeUploadUrlRequest(String path, String url) throws DaemonException { |
||||
|
||||
try { |
||||
|
||||
// Initialize the HTTP client
|
||||
if (httpclient == null) { |
||||
initialise(HttpHelper.DEFAULT_CONNECTION_TIMEOUT); |
||||
} |
||||
|
||||
// Get default download file location first
|
||||
HttpResponse response = httpclient.execute(new HttpGet(buildWebUIUrl("/panel/task_add_httpftp"))); |
||||
HttpEntity entity = response.getEntity(); |
||||
if (entity != null) { |
||||
|
||||
// Read BitComet response
|
||||
java.io.InputStream instream = entity.getContent(); |
||||
String result = HttpHelper.ConvertStreamToString(instream); |
||||
instream.close(); |
||||
|
||||
int idx = result.indexOf("save_path' value='")+18; |
||||
String defaultPath = result.substring(idx, result.indexOf("'>", idx)); |
||||
|
||||
// Setup form fields and post request
|
||||
HttpPost httppost = new HttpPost(buildWebUIUrl(path)); |
||||
|
||||
List<NameValuePair> params = new ArrayList<NameValuePair>(); |
||||
params.add(new BasicNameValuePair("url", url)); |
||||
params.add(new BasicNameValuePair("save_path", defaultPath)); |
||||
params.add(new BasicNameValuePair("connection", "5")); |
||||
params.add(new BasicNameValuePair("ReferPage", "")); |
||||
params.add(new BasicNameValuePair("textSpeedLimit", "0")); |
||||
httppost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); |
||||
|
||||
// Make the request
|
||||
response = httpclient.execute(httppost); |
||||
|
||||
entity = response.getEntity(); |
||||
if (entity != null) { |
||||
// Check BitComet response
|
||||
instream = entity.getContent(); |
||||
result = HttpHelper.ConvertStreamToString(instream); |
||||
instream.close(); |
||||
if (result.indexOf("failed!") > 0) { |
||||
throw new Exception("Adding URL failed"); |
||||
} |
||||
} |
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK; |
||||
} |
||||
return false; |
||||
} catch (Exception e) { |
||||
DLog.d(LOG_NAME, "Error: " + e.toString()); |
||||
throw new DaemonException(ExceptionType.ConnectionError, e.toString()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Parse BitComet HTML page (http response) |
||||
* @param response |
||||
* @return |
||||
* @throws DaemonException |
||||
*/ |
||||
private ArrayList<Torrent> parseHttpTorrents(String response) throws DaemonException { |
||||
|
||||
ArrayList<Torrent> torrents = new ArrayList<Torrent>(); |
||||
|
||||
try { |
||||
|
||||
String[] parts = response.substring(response.indexOf("<TABLE"),response.indexOf("</TABLE>")).replaceAll("</td>", "").replaceAll("</tr>", "").replaceAll("\n", "").split("<tr>"); |
||||
|
||||
for (int i=2; i<parts.length; i++) { |
||||
|
||||
String[] subParts = parts[i].replaceAll("<td>", "<td").split("<td"); |
||||
|
||||
if (subParts.length == 10 && subParts[1].contains("BT") ) { |
||||
|
||||
String name = subParts[2].substring(subParts[2].indexOf("/panel/task_detail")); |
||||
name = name.substring(name.indexOf(">")+1, name.indexOf("<")); |
||||
|
||||
TorrentStatus status = parseStatus(subParts[3]); |
||||
String percenDoneStr = subParts[6]; |
||||
String downloadRateStr = subParts[7]; |
||||
String uploadRateStr = subParts[8]; |
||||
|
||||
long size = convertSize(subParts[5]); |
||||
float percentDone = Float.parseFloat(percenDoneStr.substring(0, percenDoneStr.indexOf("%"))); |
||||
long sizeDone = (long) (size * percentDone / 100 ); |
||||
|
||||
int rateUp = 1000 * Integer.parseInt(uploadRateStr.substring(0, uploadRateStr.indexOf("kB/s"))); |
||||
int rateDown = 1000 * Integer.parseInt(downloadRateStr.substring(0, downloadRateStr.indexOf("kB/s"))); |
||||
|
||||
// Unfortunately, there is no info for above values providing by BitComet now,
|
||||
// so we may only send additional request for that
|
||||
int leechers = 0; |
||||
int seeders = 0; |
||||
int knownLeechers = 0; |
||||
int knownSeeders = 0; |
||||
int distributed_copies = 0; |
||||
long sizeUp = 0; |
||||
String comment = ""; |
||||
Date dateAdded = new Date(); |
||||
|
||||
// Comment code below to speedup torrent listing
|
||||
// P.S. feature request to extend torrents info is already sent to the BitComet developers
|
||||
//*
|
||||
try { |
||||
// Lets make summary request and parse details
|
||||
String summary = makeRequest("/panel/task_detail", new BasicNameValuePair("id", ""+(i-2)), new BasicNameValuePair("show", "summary")); |
||||
|
||||
String[] sumParts = summary.substring(summary.indexOf("<div align=\"left\">Value</div></th>")).split("<tr><td>"); |
||||
comment = sumParts[7].substring(sumParts[7].indexOf("<td>")+4, sumParts[7].indexOf("</td></tr>")); |
||||
|
||||
// Indexes for date and uploaded size
|
||||
int idx = 9; |
||||
int sizeIdx = 12; |
||||
|
||||
if (status == TorrentStatus.Downloading) { |
||||
seeders = Integer.parseInt(sumParts[9].substring(sumParts[9].indexOf("Seeds:")+6, sumParts[9].indexOf("(Max possible"))); |
||||
leechers = Integer.parseInt(sumParts[9].substring(sumParts[9].indexOf("Peers:")+6, sumParts[9].lastIndexOf("(Max possible"))); |
||||
knownSeeders = Integer.parseInt(sumParts[9].substring(sumParts[9].indexOf("(Max possible:")+14, sumParts[9].indexOf(")"))); |
||||
knownLeechers = Integer.parseInt(sumParts[9].substring(sumParts[9].lastIndexOf("(Max possible:")+14, sumParts[9].lastIndexOf(")"))); |
||||
idx = 13; |
||||
sizeIdx = 16; |
||||
} |
||||
|
||||
DateFormat df = new SimpleDateFormat("yyyy-mm-dd kk:mm:ss"); |
||||
dateAdded = df.parse(sumParts[idx].substring(sumParts[idx].indexOf("<td>")+4, sumParts[idx].indexOf("</td></tr>"))); |
||||
//sizeDone = convertSize(sumParts[sizeIdx].substring(sumParts[sizeIdx].indexOf("<td>")+4, sumParts[sizeIdx].indexOf(" (")));
|
||||
sizeUp = convertSize(sumParts[sizeIdx+1].substring(sumParts[sizeIdx+1].indexOf("<td>")+4, sumParts[sizeIdx+1].indexOf(" ("))); |
||||
} |
||||
catch (Exception e) {} |
||||
//*
|
||||
|
||||
// Add the parsed torrent to the list
|
||||
torrents.add(new Torrent( |
||||
(long)i-2, |
||||
null, |
||||
name, |
||||
status, |
||||
null, |
||||
rateDown, |
||||
rateUp, |
||||
leechers, |
||||
seeders, |
||||
knownLeechers, |
||||
knownSeeders, |
||||
(rateDown == 0? -1: (int) ((size - sizeDone) / rateDown)), |
||||
sizeDone, |
||||
sizeUp, |
||||
size, |
||||
percentDone / 100, |
||||
distributed_copies, |
||||
comment, |
||||
dateAdded, |
||||
null)); |
||||
} |
||||
} |
||||
} |
||||
catch (Exception e) { |
||||
throw new DaemonException(ExceptionType.UnexpectedResponse, "Invalid BitComet HTTP response."); |
||||
} |
||||
|
||||
return torrents; |
||||
} |
||||
|
||||
/** |
||||
* Parse BitComet HTML page (http response) |
||||
* @param response |
||||
* @return |
||||
* @throws DaemonException |
||||
*/ |
||||
private ArrayList<TorrentFile> parseHttpTorrentFiles(String response, String hash) throws DaemonException { |
||||
|
||||
// Parse response
|
||||
ArrayList<TorrentFile> torrentfiles = new ArrayList<TorrentFile>(); |
||||
|
||||
try { |
||||
|
||||
String[] files = response.substring(response.indexOf("Operation Method</div></th>")+27, response.lastIndexOf("</TABLE>")).replaceAll("</td>", "").replaceAll("</tr>", "").split("<tr>"); |
||||
|
||||
for (int i = 1; i < files.length; i++) { |
||||
|
||||
String[] fileDetails = files[i].replace(">","").split("<td"); |
||||
|
||||
long size = convertSize(fileDetails[4].substring(fileDetails[4].indexOf("   ")+11)); |
||||
long sizeDone = 0; |
||||
if (!fileDetails[2].contains("--")) { |
||||
double percentDone = Double.parseDouble(fileDetails[2].substring(0, fileDetails[2].indexOf("%"))); |
||||
sizeDone = (long) ( size / 100.0 * percentDone); |
||||
} |
||||
|
||||
torrentfiles.add(new TorrentFile( |
||||
hash, |
||||
fileDetails[3], |
||||
fileDetails[3], |
||||
settings.getDownloadDir() + fileDetails[3], |
||||
size, |
||||
sizeDone, |
||||
parsePriority(fileDetails[1]))); |
||||
} |
||||
} |
||||
catch (Exception e) { |
||||
throw new DaemonException(ExceptionType.UnexpectedResponse, "Invalid BitComet HTTP response."); |
||||
} |
||||
|
||||
// Return the list
|
||||
return torrentfiles; |
||||
} |
||||
|
||||
/** |
||||
* Returns the size of the torrent, as parsed form some string |
||||
* @param size The size in a string format, i.e. '691 MB' |
||||
* @return The size in number of kB |
||||
*/ |
||||
private static long convertSize(String size) { |
||||
try { |
||||
if (size.endsWith("GB")) { |
||||
return (long)(Float.parseFloat(size.substring(0, size.indexOf("GB"))) * 1024 * 1024 * 1024); |
||||
} else if (size.endsWith("MB")) { |
||||
return (long)(Float.parseFloat(size.substring(0, size.indexOf("MB"))) * 1024 * 1024); |
||||
} else if (size.endsWith("kB")) { |
||||
return (long)(Float.parseFloat(size.substring(0, size.indexOf("kB"))) * 1024); |
||||
} else if (size.endsWith("B")) { |
||||
return (long)(Float.parseFloat(size.substring(0, size.indexOf("B")))); |
||||
} |
||||
} |
||||
catch (Exception e) { } |
||||
return 0; |
||||
} |
||||
|
||||
/** |
||||
* Parse BitComet torrent files priority |
||||
**/ |
||||
private Priority parsePriority(String priority) { |
||||
if (priority.equals("Very High") || priority.equals("High")) { |
||||
return Priority.High; |
||||
} else if (priority.equals("Normal")) { |
||||
return Priority.Normal; |
||||
} |
||||
return Priority.Off; |
||||
} |
||||
|
||||
/** |
||||
* Parse BitComet torrent status |
||||
**/ |
||||
private TorrentStatus parseStatus(String state) { |
||||
// Status is given as a descriptive string and an indication if the torrent was stopped/paused
|
||||
if (state.equals("stopped")) { |
||||
return TorrentStatus.Paused; |
||||
} else if (state.equals("running")) { |
||||
return TorrentStatus.Downloading; |
||||
} |
||||
return TorrentStatus.Unknown; |
||||
} |
||||
|
||||
@Override |
||||
public Daemon getType() { |
||||
return settings.getType(); |
||||
} |
||||
|
||||
@Override |
||||
public DaemonSettings getSettings() { |
||||
return this.settings; |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue