mirror of
https://github.com/Rogiel/httpchannel
synced 2025-12-05 23:22:51 +00:00
Implements several services and improves API
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>httpchannel</artifactId>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>httpchannel-api</artifactId>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>httpchannel</artifactId>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>httpchannel-api</artifactId>
|
||||
<name>HttpChannel/API</name>
|
||||
<description>Module that defines the HttpChannel API. HttpChannels abstract complex download and upload steps into a simple and easy to use NIO Channel. NIO Channels can be wrapped into an InputStream or OutputStream and used in any way you may find possible to. Aside from that, Channels can be used natively in most next-gen libraries, meaning that you don't even need to wrap anything, just start writing or reading data to or from the channel wth a ByteBuffer.
|
||||
|
||||
|
||||
|
||||
Anyone using the library should try to rely on code from this module only and, only if necessary, on configuration classes that are implementation specific. Relying on any other resource or class is considered an error and should NOT be done.
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.captcha;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public interface Captcha {
|
||||
/**
|
||||
* Sets the captcha answer
|
||||
*
|
||||
* @param answer
|
||||
* the captcha answer
|
||||
*/
|
||||
void setAnswer(String answer);
|
||||
|
||||
/**
|
||||
* Returns the captcha answer. <code>null</code> if the service was not able
|
||||
* to resolve it automatically. In such case, {@link #setAnswer(String)}
|
||||
* must be used to set the correct answer.
|
||||
*
|
||||
* @return the captcha answer
|
||||
*/
|
||||
String getAnswer();
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if, and only if, the service was able to
|
||||
* automatically resolve the captcha result
|
||||
*/
|
||||
boolean wasAutomaticallyResolved();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.captcha;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface CaptchaResolver {
|
||||
/**
|
||||
* Tries to resolve the captcha
|
||||
*
|
||||
* @param captcha
|
||||
* the captcha
|
||||
* @return <code>true</code> if the captcha was resolve, <code>false</code>
|
||||
* to abort
|
||||
*/
|
||||
boolean resolve(Captcha captcha);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.captcha;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public interface CaptchaService<C extends Captcha> {
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.captcha;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public interface ImageCaptcha extends Captcha {
|
||||
/**
|
||||
* @return the captcha identifier
|
||||
*/
|
||||
String getID();
|
||||
|
||||
/**
|
||||
* @return the captcha image {@link URL}
|
||||
*/
|
||||
URL getImageURL();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.captcha;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public interface ImageCaptchaService<C extends ImageCaptcha> extends
|
||||
CaptchaService<C> {
|
||||
/**
|
||||
* Creates a new captcha from the given HTML content
|
||||
*
|
||||
* @param image
|
||||
* the image {@link URL}
|
||||
* @return a new captcha
|
||||
*/
|
||||
C create(String html);
|
||||
|
||||
/**
|
||||
* Tries to automatically resolve the captcha
|
||||
*
|
||||
* @param captcha
|
||||
* the captcha to be resolved
|
||||
* @return <code>true</code> if the captcha was successfully resolved
|
||||
*/
|
||||
boolean resolve(C captcha);
|
||||
}
|
||||
@@ -16,37 +16,18 @@
|
||||
*/
|
||||
package com.rogiel.httpchannel.service;
|
||||
|
||||
import com.rogiel.httpchannel.service.config.ServiceConfiguration;
|
||||
import com.rogiel.httpchannel.captcha.Captcha;
|
||||
import com.rogiel.httpchannel.captcha.CaptchaResolver;
|
||||
import com.rogiel.httpchannel.service.exception.UnresolvedCaptchaException;
|
||||
|
||||
/**
|
||||
* This is an abstract {@link Service} implementation.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @version 1.0
|
||||
* @param <T>
|
||||
* The {@link ServiceConfiguration} <b>interface</b> type used by the
|
||||
* {@link Service}. Note that this <b>must</b> be an interface!s
|
||||
* @see ServiceConfiguration ServiceConfiguration for details on the
|
||||
* configuration interface.
|
||||
*/
|
||||
public abstract class AbstractService<T extends ServiceConfiguration>
|
||||
implements Service {
|
||||
protected T configuration;
|
||||
|
||||
protected AbstractService(T configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getServiceConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setServiceConfiguration(ServiceConfiguration configuration) {
|
||||
this.configuration = (T) configuration;
|
||||
}
|
||||
public abstract class AbstractService implements Service {
|
||||
protected CaptchaResolver captchaResolver;
|
||||
|
||||
@Override
|
||||
public Service clone() {
|
||||
@@ -56,4 +37,20 @@ public abstract class AbstractService<T extends ServiceConfiguration>
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCaptchaResolver(CaptchaResolver captchaResolver) {
|
||||
this.captchaResolver = captchaResolver;
|
||||
}
|
||||
|
||||
protected boolean resolveCaptcha(Captcha captcha)
|
||||
throws UnresolvedCaptchaException {
|
||||
if (captchaResolver == null)
|
||||
throw new UnresolvedCaptchaException();
|
||||
if (!captchaResolver.resolve(captcha))
|
||||
throw new UnresolvedCaptchaException();
|
||||
if (captcha.getAnswer() == null)
|
||||
throw new UnresolvedCaptchaException();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,29 @@
|
||||
*/
|
||||
package com.rogiel.httpchannel.service;
|
||||
|
||||
import com.rogiel.httpchannel.service.Authenticator.AuthenticatorConfiguration;
|
||||
import com.rogiel.httpchannel.service.config.NullAuthenticatorConfiguration;
|
||||
|
||||
/**
|
||||
* Implements an service capable of authenticating into an account.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface AuthenticationService extends Service {
|
||||
public interface AuthenticationService<C extends AuthenticatorConfiguration>
|
||||
extends Service {
|
||||
/**
|
||||
* Creates {@link Authenticator} instance for this service. This instance is
|
||||
* attached to an {@link Credential} and to its parent {@link Service}.
|
||||
*
|
||||
* @param credential
|
||||
* the credential
|
||||
* @param configuration
|
||||
* the authenticator configuration
|
||||
* @return an new {@link Authenticator} instance
|
||||
*/
|
||||
Authenticator<C> getAuthenticator(Credential credential, C configuration);
|
||||
|
||||
/**
|
||||
* Creates {@link Authenticator} instance for this service. This instance is
|
||||
* attached to an {@link Credential} and to its parent {@link Service}.
|
||||
@@ -31,7 +47,17 @@ public interface AuthenticationService extends Service {
|
||||
* the credential
|
||||
* @return an new {@link Authenticator} instance
|
||||
*/
|
||||
Authenticator getAuthenticator(Credential credential);
|
||||
Authenticator<C> getAuthenticator(Credential credential);
|
||||
|
||||
/**
|
||||
* Creates a new configuration object. If a service does not support or
|
||||
* require configuration, {@link NullAuthenticatorConfiguration} should be
|
||||
* returned.
|
||||
*
|
||||
* @return a new configuration object or
|
||||
* {@link NullAuthenticatorConfiguration}
|
||||
*/
|
||||
C newAuthenticatorConfiguration();
|
||||
|
||||
/**
|
||||
* Return the matrix of capabilities for this {@link Authenticator}.
|
||||
|
||||
@@ -18,15 +18,18 @@ package com.rogiel.httpchannel.service;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.rogiel.httpchannel.captcha.CaptchaResolver;
|
||||
import com.rogiel.httpchannel.service.Authenticator.AuthenticatorConfiguration;
|
||||
import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException;
|
||||
import com.rogiel.httpchannel.service.exception.UnresolvedCaptchaException;
|
||||
|
||||
/**
|
||||
* This interfaces provides authentication for an service.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface Authenticator {
|
||||
public interface Authenticator<C extends AuthenticatorConfiguration> {
|
||||
/**
|
||||
* Login into the {@link Service}. Once the authentication is done, it is
|
||||
* persistent for the entire service's operation.<br>
|
||||
@@ -37,8 +40,13 @@ public interface Authenticator {
|
||||
* if any IO error occur
|
||||
* @throws AuthenticationInvalidCredentialException
|
||||
* if the credentials are not valid or cannot be used
|
||||
* @throws UnresolvedCaptchaException
|
||||
* if the service required captcha resolving but no
|
||||
* {@link CaptchaResolver} was available or the resolver did not
|
||||
* solve the challenge
|
||||
*/
|
||||
void login() throws IOException, AuthenticationInvalidCredentialException;
|
||||
void login() throws IOException, AuthenticationInvalidCredentialException,
|
||||
UnresolvedCaptchaException;
|
||||
|
||||
/**
|
||||
* Logout into the {@link Service}. The session is restored to an not
|
||||
@@ -48,4 +56,26 @@ public interface Authenticator {
|
||||
* if any IO error occur
|
||||
*/
|
||||
void logout() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns this {@link Authenticator} configuration.
|
||||
* <p>
|
||||
* <b>IMPORTANT NOTE</b>: You should not modify any configuration within
|
||||
* this configuration object once while the account is authenticated.
|
||||
* Depending on the service, changing any setting could result in an state
|
||||
* where the service cannot be logged out.
|
||||
*
|
||||
* @return this {@link Authenticator} configuration
|
||||
*/
|
||||
C getConfiguration();
|
||||
|
||||
/**
|
||||
* This interface must be implemented in order to allow authentication
|
||||
* configuration.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface AuthenticatorConfiguration {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.rogiel.httpchannel.service;
|
||||
/**
|
||||
* Capability an certain {@link Authenticator} can have.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public enum AuthenticatorCapability {
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.rogiel.httpchannel.service;
|
||||
/**
|
||||
* This is an utility class to help manage Capabilities of all the services.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @param <T>
|
||||
* the capability enumeration
|
||||
* @since 1.0
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.rogiel.httpchannel.service;
|
||||
/**
|
||||
* Pair of username-password used for authenticating into services.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public class Credential {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.rogiel.httpchannel.service;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.nio.channels.Channel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
|
||||
@@ -31,7 +32,7 @@ import java.nio.channels.ReadableByteChannel;
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface DownloadChannel extends ReadableByteChannel {
|
||||
public interface DownloadChannel extends ReadableByteChannel, Closeable {
|
||||
/**
|
||||
* @return the file size
|
||||
*/
|
||||
|
||||
@@ -20,7 +20,7 @@ package com.rogiel.httpchannel.service;
|
||||
* This listener keeps an track on the progress on an {@link Downloader}
|
||||
* service.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface DownloadListener {
|
||||
|
||||
@@ -20,13 +20,17 @@ import java.net.URL;
|
||||
|
||||
import javax.tools.FileObject;
|
||||
|
||||
import com.rogiel.httpchannel.service.Downloader.DownloaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.config.NullDownloaderConfiguration;
|
||||
|
||||
/**
|
||||
* Implements an service capable of downloading a file.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface DownloadService extends Service {
|
||||
public interface DownloadService<C extends DownloaderConfiguration> extends
|
||||
Service {
|
||||
/**
|
||||
* Creates a new instance of the {@link Downloader}. This instance will be
|
||||
* attached to the {@link URL}, {@link FileObject} provided through the the
|
||||
@@ -34,14 +38,34 @@ public interface DownloadService extends Service {
|
||||
*
|
||||
* @param url
|
||||
* the url to be downloaded
|
||||
* @param file
|
||||
* the destination file
|
||||
* @param configuration
|
||||
* the downloader configurationf
|
||||
* @return an new instance of {@link Downloader}
|
||||
*/
|
||||
Downloader getDownloader(URL url);
|
||||
Downloader<C> getDownloader(URL url, C configuration);
|
||||
|
||||
/**
|
||||
* Check if this {@link Service} can download from this URL. Implemtations
|
||||
* Creates a new instance of the {@link Downloader}. This instance will be
|
||||
* attached to the {@link URL}, {@link FileObject} provided through the the
|
||||
* arguments and the parent {@link Service} instance.
|
||||
*
|
||||
* @param url
|
||||
* the url to be downloaded
|
||||
* @return an new instance of {@link Downloader}
|
||||
*/
|
||||
Downloader<C> getDownloader(URL url);
|
||||
|
||||
/**
|
||||
* Creates a new configuration object. If a service does not support or
|
||||
* require configuration, {@link NullDownloaderConfiguration} should be
|
||||
* returned.
|
||||
*
|
||||
* @return a new configuration object or {@link NullDownloaderConfiguration}
|
||||
*/
|
||||
C newDownloaderConfiguration();
|
||||
|
||||
/**
|
||||
* Check if this {@link Service} can download from this URL. Implementations
|
||||
* might or might not perform network activity.
|
||||
* <p>
|
||||
* <b>Please note</b> that the value returned by this method may vary based
|
||||
|
||||
@@ -18,18 +18,21 @@ package com.rogiel.httpchannel.service;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.rogiel.httpchannel.captcha.CaptchaResolver;
|
||||
import com.rogiel.httpchannel.service.Downloader.DownloaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadLimitExceededException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadLinkNotFoundException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadNotAuthorizedException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadNotResumableException;
|
||||
import com.rogiel.httpchannel.service.exception.UnresolvedCaptchaException;
|
||||
|
||||
/**
|
||||
* This interfaces provides downloading for an service.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface Downloader {
|
||||
public interface Downloader<C extends DownloaderConfiguration> {
|
||||
/**
|
||||
* Opens a new {@link DownloadChannel} that will be immediately ready to
|
||||
* read data from the download stream.
|
||||
@@ -67,9 +70,105 @@ public interface Downloader {
|
||||
* @throws DownloadNotResumableException
|
||||
* if the download cannot be started at <tt>position</tt>. Will
|
||||
* only be thrown if <tt>position > 0</tt>.
|
||||
* @throws UnresolvedCaptchaException
|
||||
* if the service required captcha resolving but no
|
||||
* {@link CaptchaResolver} was available or the resolver did not
|
||||
* solve the challenge
|
||||
*/
|
||||
DownloadChannel download(DownloadListener listener, long position)
|
||||
DownloadChannel openChannel(DownloadListener listener, long position)
|
||||
throws IOException, DownloadLinkNotFoundException,
|
||||
DownloadLimitExceededException, DownloadNotAuthorizedException,
|
||||
DownloadNotResumableException;
|
||||
DownloadNotResumableException, UnresolvedCaptchaException;
|
||||
|
||||
/**
|
||||
* Opens a new {@link DownloadChannel} with not listener. For more details,
|
||||
* see {@link #openChannel(DownloadListener, long)}
|
||||
*
|
||||
* @param position
|
||||
* the download start position. If seek is supported by service.
|
||||
* If zero, download will start from the beginning.
|
||||
* @return the {@link DownloadChannel} instance
|
||||
* @throws IOException
|
||||
* if any IO error occur
|
||||
* @throws DownloadLinkNotFoundException
|
||||
* if the direct download link cannot be found (the file could
|
||||
* have been deleted)
|
||||
* @throws DownloadLimitExceededException
|
||||
* if the download limit has been exceed, most times thrown when
|
||||
* downloading as a non-premium user
|
||||
* @throws DownloadNotAuthorizedException
|
||||
* if the user (or guest) account does not have necessary rights
|
||||
* to download the file
|
||||
* @throws DownloadNotResumableException
|
||||
* if the download cannot be started at <tt>position</tt>. Will
|
||||
* only be thrown if <tt>position > 0</tt>.
|
||||
*/
|
||||
DownloadChannel openChannel(long position) throws IOException,
|
||||
DownloadLinkNotFoundException, DownloadLimitExceededException,
|
||||
DownloadNotAuthorizedException, DownloadNotResumableException;
|
||||
|
||||
/**
|
||||
* Opens a new {@link DownloadChannel} positioned at start. For more
|
||||
* details, see {@link #openChannel(DownloadListener, long)}
|
||||
*
|
||||
* @param listener
|
||||
* the listener to keep a track on the download progress
|
||||
* @return the {@link DownloadChannel} instance
|
||||
* @throws IOException
|
||||
* if any IO error occur
|
||||
* @throws DownloadLinkNotFoundException
|
||||
* if the direct download link cannot be found (the file could
|
||||
* have been deleted)
|
||||
* @throws DownloadLimitExceededException
|
||||
* if the download limit has been exceed, most times thrown when
|
||||
* downloading as a non-premium user
|
||||
* @throws DownloadNotAuthorizedException
|
||||
* if the user (or guest) account does not have necessary rights
|
||||
* to download the file
|
||||
*/
|
||||
DownloadChannel openChannel(DownloadListener listener) throws IOException,
|
||||
DownloadLinkNotFoundException, DownloadLimitExceededException,
|
||||
DownloadNotAuthorizedException;
|
||||
|
||||
/**
|
||||
* Opens a new {@link DownloadChannel} with not listener and positioned at
|
||||
* start. For more details, see {@link #openChannel(DownloadListener, long)}
|
||||
*
|
||||
* @return the {@link DownloadChannel} instance
|
||||
* @throws IOException
|
||||
* if any IO error occur
|
||||
* @throws DownloadLinkNotFoundException
|
||||
* if the direct download link cannot be found (the file could
|
||||
* have been deleted)
|
||||
* @throws DownloadLimitExceededException
|
||||
* if the download limit has been exceed, most times thrown when
|
||||
* downloading as a non-premium user
|
||||
* @throws DownloadNotAuthorizedException
|
||||
* if the user (or guest) account does not have necessary rights
|
||||
* to download the file
|
||||
*/
|
||||
DownloadChannel openChannel() throws IOException,
|
||||
DownloadLinkNotFoundException, DownloadLimitExceededException,
|
||||
DownloadNotAuthorizedException;
|
||||
|
||||
/**
|
||||
* Returns this {@link Downloader} configuration.
|
||||
* <p>
|
||||
* <b>IMPORTANT NOTE</b>: You should not modify any configuration within
|
||||
* this configuration object once the download has started. Doing so, could
|
||||
* result in a error.
|
||||
*
|
||||
* @return this {@link Downloader} configuration
|
||||
*/
|
||||
C getConfiguration();
|
||||
|
||||
/**
|
||||
* This interface must be implemented in order to allow download
|
||||
* configuration.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface DownloaderConfiguration {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.rogiel.httpchannel.service;
|
||||
/**
|
||||
* Capability an certain {@link Downloader} can have.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public enum DownloaderCapability {
|
||||
@@ -35,10 +35,21 @@ public enum DownloaderCapability {
|
||||
* Can download files while authenticated with premium account
|
||||
*/
|
||||
PREMIUM_ACCOUNT_DOWNLOAD,
|
||||
|
||||
/**
|
||||
* Resume interrupted downloads are possible and supported.
|
||||
* Can resume interrupted downloads even without authenticating
|
||||
*/
|
||||
RESUME,
|
||||
UNAUTHENTICATED_RESUME,
|
||||
/**
|
||||
* Can resume interrupted downloads but require to be logged with any
|
||||
* account
|
||||
*/
|
||||
NON_PREMIUM_ACCOUNT_RESUME,
|
||||
/**
|
||||
* Can resume interrupted downloads but requires an premium account
|
||||
*/
|
||||
PREMIUM_ACCOUNT_RESUME,
|
||||
|
||||
/**
|
||||
* Can check the status of the given link before starting download.
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package com.rogiel.httpchannel.service;
|
||||
|
||||
import com.rogiel.httpchannel.service.config.ServiceConfiguration;
|
||||
import com.rogiel.httpchannel.captcha.CaptchaResolver;
|
||||
|
||||
/**
|
||||
* Base interface for all the services. Whenever the operation suported by the
|
||||
@@ -27,7 +27,7 @@ import com.rogiel.httpchannel.service.config.ServiceConfiguration;
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface Service extends Cloneable {
|
||||
@@ -53,19 +53,13 @@ public interface Service extends Cloneable {
|
||||
int getMinorVersion();
|
||||
|
||||
/**
|
||||
* Returns this {@link ServiceConfiguration} instance
|
||||
* Sets this service captcha resolver. Resolvers are safe to be switched
|
||||
* even after an transfer has begun.
|
||||
*
|
||||
* @return the {@link ServiceConfiguration} instance
|
||||
* @param resolver
|
||||
* the captcha resolver
|
||||
*/
|
||||
ServiceConfiguration getServiceConfiguration();
|
||||
|
||||
/**
|
||||
* Sets this {@link ServiceConfiguration} instance
|
||||
*
|
||||
* @param configuration
|
||||
* the {@link ServiceConfiguration} instance
|
||||
*/
|
||||
void setServiceConfiguration(ServiceConfiguration configuration);
|
||||
void setCaptchaResolver(CaptchaResolver resolver);
|
||||
|
||||
/**
|
||||
* @return a cloned version of this service
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.rogiel.httpchannel.service;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.rogiel.httpchannel.service.helper.Services;
|
||||
|
||||
/**
|
||||
* An ID used to represent the given service
|
||||
*
|
||||
@@ -27,7 +29,7 @@ public class ServiceID implements Serializable, Cloneable {
|
||||
/**
|
||||
* This class serialization version UID
|
||||
*/
|
||||
private static final long serialVersionUID = -1078456596792552200L;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The raw ID
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
*/
|
||||
package com.rogiel.httpchannel.service;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
@@ -34,7 +36,7 @@ import com.rogiel.httpchannel.service.exception.UploadLinkNotFoundException;
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface UploadChannel extends WritableByteChannel {
|
||||
public interface UploadChannel extends WritableByteChannel, Closeable {
|
||||
/**
|
||||
* @return the file size
|
||||
*/
|
||||
@@ -52,7 +54,7 @@ public interface UploadChannel extends WritableByteChannel {
|
||||
*
|
||||
* @return the download link for this upload
|
||||
*/
|
||||
String getDownloadLink();
|
||||
URL getDownloadLink();
|
||||
|
||||
/**
|
||||
* @throws UploadLinkNotFoundException
|
||||
|
||||
@@ -16,13 +16,16 @@
|
||||
*/
|
||||
package com.rogiel.httpchannel.service;
|
||||
|
||||
import com.rogiel.httpchannel.service.Uploader.UploaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.config.NullUploaderConfiguration;
|
||||
|
||||
/**
|
||||
* Implements an service capable of uploading a file.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface UploadService extends Service {
|
||||
public interface UploadService<C extends UploaderConfiguration> extends Service {
|
||||
/**
|
||||
* Creates a new instance of {@link Uploader}. This instance is attached
|
||||
* with the parent {@link Service} instance.<br>
|
||||
@@ -32,11 +35,34 @@ public interface UploadService extends Service {
|
||||
* the name of the file to be uploaded
|
||||
* @param filesize
|
||||
* the size of the file to be uploaded. This must be exact.
|
||||
* @param description
|
||||
* the description of the upload. If supported.
|
||||
* @param configuration
|
||||
* the uploader configuration
|
||||
* @return the new {@link Uploader} instance
|
||||
*/
|
||||
Uploader getUploader(String filename, long filesize, String description);
|
||||
Uploader<C> getUploader(String filename, long filesize, C configuration);
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link Uploader}. This instance is attached
|
||||
* with the parent {@link Service} instance.<br>
|
||||
* <b>Note</b>: not all services might support <tt>description</tt>
|
||||
*
|
||||
* @param filename
|
||||
* the name of the file to be uploaded
|
||||
* @param filesize
|
||||
* the size of the file to be uploaded. This must be exact.
|
||||
* @return the new {@link Uploader} instance
|
||||
*/
|
||||
Uploader<C> getUploader(String filename, long filesize);
|
||||
|
||||
/**
|
||||
* Creates a new configuration object. If a service does not support or
|
||||
* require configuration, {@link NullUploaderConfiguration} should be
|
||||
* returned.
|
||||
*
|
||||
* @return a new configuration object or
|
||||
* {@link NullUploaderConfiguration}
|
||||
*/
|
||||
C newUploaderConfiguration();
|
||||
|
||||
/**
|
||||
* Get the maximum upload file size supported by this service.
|
||||
|
||||
@@ -18,13 +18,17 @@ package com.rogiel.httpchannel.service;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.rogiel.httpchannel.captcha.CaptchaResolver;
|
||||
import com.rogiel.httpchannel.service.Uploader.UploaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.exception.UnresolvedCaptchaException;
|
||||
|
||||
/**
|
||||
* This interfaces provides uploading for an service.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface Uploader {
|
||||
public interface Uploader<C extends UploaderConfiguration> {
|
||||
/**
|
||||
* Opens a new {@link UploadChannel} that will be immediately ready to
|
||||
* receive data to be sent to the upload stream.
|
||||
@@ -44,6 +48,52 @@ public interface Uploader {
|
||||
* @return the {@link UploadChannel} instance
|
||||
* @throws IOException
|
||||
* if any IO error occur
|
||||
* @throws UnresolvedCaptchaException
|
||||
* if the service required captcha resolving but no
|
||||
* {@link CaptchaResolver} was available or the resolver did not
|
||||
* solve the challenge
|
||||
*/
|
||||
UploadChannel upload() throws IOException;
|
||||
UploadChannel openChannel() throws IOException, UnresolvedCaptchaException;
|
||||
|
||||
/**
|
||||
* Returns this {@link Uploader} configuration.
|
||||
* <p>
|
||||
* <b>IMPORTANT NOTE</b>: You should not modify any configuration within
|
||||
* this configuration object once the upload has started. Doing so, could
|
||||
* result in a error.
|
||||
*
|
||||
* @return this {@link Uploader} configuration
|
||||
*/
|
||||
C getConfiguration();
|
||||
|
||||
/**
|
||||
* This interface must be implemented in order to allow upload
|
||||
* configuration.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface UploaderConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an {@link UploaderConfiguration} that can allow <b>at least</b>
|
||||
* an description field
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface DescriptionableUploaderConfiguration extends
|
||||
UploaderConfiguration {
|
||||
public static final String DEFAULT_DESCRIPTION = "Uploaded by httpchannel";
|
||||
|
||||
/**
|
||||
* @return the upload description
|
||||
*/
|
||||
String description();
|
||||
|
||||
/**
|
||||
* @param description
|
||||
* the upload description
|
||||
*/
|
||||
DescriptionableUploaderConfiguration description(String description);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.rogiel.httpchannel.service;
|
||||
/**
|
||||
* Capability an certain {@link Uploader} can have.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public enum UploaderCapability {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service.captcha;
|
||||
|
||||
/**
|
||||
* @author Rogiel
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface Captcha {
|
||||
String getAnswer();
|
||||
void setAnswer(String answer);
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service.captcha;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author Rogiel
|
||||
* @since 1.0
|
||||
*/
|
||||
public class ImageCaptcha implements Captcha {
|
||||
private URL url;
|
||||
|
||||
private String answer;
|
||||
|
||||
public URL getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(URL url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAnswer() {
|
||||
return answer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnswer(String answer) {
|
||||
this.answer = answer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.rogiel.httpchannel.service.config;
|
||||
|
||||
import com.rogiel.httpchannel.service.AuthenticationService;
|
||||
import com.rogiel.httpchannel.service.Authenticator.AuthenticatorConfiguration;
|
||||
|
||||
/**
|
||||
* An default {@link AuthenticatorConfiguration} implementation that is
|
||||
* generally returned by
|
||||
* {@link AuthenticationService#newAuthenticatorConfiguration()} when the
|
||||
* service does not support or require any kind of configuration.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public final class NullAuthenticatorConfiguration implements
|
||||
AuthenticatorConfiguration {
|
||||
public static final NullAuthenticatorConfiguration SHARED_INSTANCE = new NullAuthenticatorConfiguration();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.rogiel.httpchannel.service.config;
|
||||
|
||||
import com.rogiel.httpchannel.service.DownloadService;
|
||||
import com.rogiel.httpchannel.service.Downloader.DownloaderConfiguration;
|
||||
|
||||
/**
|
||||
* An default {@link DownloaderConfiguration} implementation that is generally
|
||||
* returned by {@link DownloadService#newDownloaderConfiguration()} when the
|
||||
* service does not support or require any kind of configuration.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public final class NullDownloaderConfiguration implements
|
||||
DownloaderConfiguration {
|
||||
public static final NullDownloaderConfiguration SHARED_INSTANCE = new NullDownloaderConfiguration();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.rogiel.httpchannel.service.config;
|
||||
|
||||
import com.rogiel.httpchannel.service.UploadService;
|
||||
import com.rogiel.httpchannel.service.Uploader.UploaderConfiguration;
|
||||
|
||||
/**
|
||||
* An default {@link UploaderConfiguration} implementation that is generally
|
||||
* returned by {@link UploadService#newUploaderConfiguration()} when the service
|
||||
* does not support or require any kind of configuration.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public final class NullUploaderConfiguration implements UploaderConfiguration {
|
||||
public static final NullUploaderConfiguration SHARED_INSTANCE = new NullUploaderConfiguration();
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service.config;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import com.rogiel.httpchannel.util.transformer.Transformer;
|
||||
|
||||
|
||||
/**
|
||||
* This is an flag interface to indicate that an certain Interface is the
|
||||
* configuration for the service.<br>
|
||||
* <br>
|
||||
* Every service must create an <tt>interface</tt> with the configuration
|
||||
* methods, additionally an Annotation informing the default value.
|
||||
* ServiceConfiguration implementations might use reflection ({@link Proxy}),
|
||||
* hard-coding or any other way for fetching the data.<br>
|
||||
* <br>
|
||||
* String data stored in the annotation is converted to Java Types using the
|
||||
* {@link Transformer} class.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @version 1.0
|
||||
* @see Transformer
|
||||
*/
|
||||
public interface ServiceConfiguration {
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.rogiel.httpchannel.util.transformer.TransformerFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class for {@link ServiceConfiguration} system.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @since 1.0
|
||||
*/
|
||||
public class ServiceConfigurationHelper {
|
||||
/**
|
||||
* Creates a Proxy Class that returns all the default values of
|
||||
* configuration interfaces. The values are mapped by
|
||||
* {@link ServiceConfigurationProperty} annotation.
|
||||
*
|
||||
* @param <T>
|
||||
* the interface extending {@link ServiceConfiguration}. Service
|
||||
* specific.
|
||||
* @param type
|
||||
* the type Class representing T.
|
||||
* @return the proxied {@link ServiceConfiguration} instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends ServiceConfiguration> T defaultConfiguration(
|
||||
Class<T> type) {
|
||||
return (T) Proxy.newProxyInstance(
|
||||
ServiceConfiguration.class.getClassLoader(),
|
||||
new Class<?>[] { type }, new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object object, Method method,
|
||||
Object[] arguments) throws Throwable {
|
||||
final ServiceConfigurationProperty property = method
|
||||
.getAnnotation(ServiceConfigurationProperty.class);
|
||||
if (property != null)
|
||||
return TransformerFactory.getTransformer(
|
||||
method.getReturnType()).transform(
|
||||
property.defaultValue());
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Proxy Class that returns all the default values of
|
||||
* configuration interfaces. The values are mapped by
|
||||
* {@link ServiceConfigurationProperty} annotation.
|
||||
*
|
||||
* @param <T>
|
||||
* the interface extending {@link ServiceConfiguration}. Service
|
||||
* specific.
|
||||
* @param type
|
||||
* the type Class representing T.
|
||||
* @return the proxied {@link ServiceConfiguration} instance.
|
||||
* @throws IOException
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends ServiceConfiguration> T file(Class<T> type,
|
||||
File file) throws FileNotFoundException, IOException {
|
||||
final Properties properties = new Properties();
|
||||
properties.load(new FileInputStream(file));
|
||||
|
||||
return (T) Proxy.newProxyInstance(
|
||||
ServiceConfiguration.class.getClassLoader(),
|
||||
new Class<?>[] { type }, new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object object, Method method,
|
||||
Object[] arguments) throws Throwable {
|
||||
final ServiceConfigurationProperty property = method
|
||||
.getAnnotation(ServiceConfigurationProperty.class);
|
||||
if (property != null)
|
||||
return TransformerFactory.getTransformer(
|
||||
method.getReturnType()).transform(
|
||||
get(property));
|
||||
return null;
|
||||
}
|
||||
|
||||
private String get(ServiceConfigurationProperty property) {
|
||||
String value = properties.getProperty(property.key());
|
||||
if (value == null)
|
||||
value = property.defaultValue();
|
||||
return value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service.config;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation that defines the default value for an {@link ServiceConfiguration}
|
||||
* method.<br>
|
||||
* <br>
|
||||
* <h1>Usage example</h1>
|
||||
*
|
||||
* <pre>
|
||||
* public interface DummyServiceConfiguration extends ServiceConfiguration {
|
||||
* @ServiceConfigurationProperty(defaultValue = "true")
|
||||
* boolean retryAllowed();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* The default implementation created by
|
||||
* {@link ServiceConfigurationHelper#defaultConfiguration()} will always return
|
||||
* the <tt>defaultValue</tt>.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @version 1.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
public @interface ServiceConfigurationProperty {
|
||||
String key();
|
||||
String defaultValue();
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package com.rogiel.httpchannel.service.exception;
|
||||
|
||||
import com.rogiel.httpchannel.service.captcha.CaptchaResolver;
|
||||
import com.rogiel.httpchannel.captcha.CaptchaResolver;
|
||||
|
||||
/**
|
||||
* Exception thrown if the {@link CaptchaResolver} has returned an invalid
|
||||
@@ -24,13 +24,13 @@ import com.rogiel.httpchannel.service.captcha.CaptchaResolver;
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class DownloadInvalidCaptchaException extends DownloadServiceException {
|
||||
public class InvalidCaptchaException extends ChannelServiceException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new empty instance of this exception
|
||||
*/
|
||||
public DownloadInvalidCaptchaException() {
|
||||
public InvalidCaptchaException() {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class DownloadInvalidCaptchaException extends DownloadServiceException {
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public DownloadInvalidCaptchaException(String message, Throwable cause) {
|
||||
public InvalidCaptchaException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class DownloadInvalidCaptchaException extends DownloadServiceException {
|
||||
* @param message
|
||||
* the message
|
||||
*/
|
||||
public DownloadInvalidCaptchaException(String message) {
|
||||
public InvalidCaptchaException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class DownloadInvalidCaptchaException extends DownloadServiceException {
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public DownloadInvalidCaptchaException(Throwable cause) {
|
||||
public InvalidCaptchaException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -14,42 +14,49 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.util.transformer;
|
||||
package com.rogiel.httpchannel.service.exception;
|
||||
|
||||
import com.rogiel.httpchannel.captcha.CaptchaResolver;
|
||||
|
||||
/**
|
||||
* @author Rogiel
|
||||
* @since 1.0
|
||||
* Exception thrown if the {@link CaptchaResolver} has returned an invalid
|
||||
* captcha
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class TransformationException extends Exception {
|
||||
public class UnresolvedCaptchaException extends ChannelServiceException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public TransformationException() {
|
||||
/**
|
||||
* Creates a new empty instance of this exception
|
||||
*/
|
||||
public UnresolvedCaptchaException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* the message
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public UnresolvedCaptchaException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* the message
|
||||
*/
|
||||
public TransformationException(String message) {
|
||||
public UnresolvedCaptchaException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* the cause
|
||||
* the root cause
|
||||
*/
|
||||
public TransformationException(Throwable cause) {
|
||||
public UnresolvedCaptchaException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* the message
|
||||
* @param cause
|
||||
* the cause
|
||||
*/
|
||||
public TransformationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service.helper;
|
||||
|
||||
import com.rogiel.httpchannel.service.AuthenticationService;
|
||||
import com.rogiel.httpchannel.service.Authenticator;
|
||||
import com.rogiel.httpchannel.service.Authenticator.AuthenticatorConfiguration;
|
||||
import com.rogiel.httpchannel.service.Credential;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class AuthenticationServices {
|
||||
public static <S extends AuthenticationService<C>, C extends AuthenticatorConfiguration> Authenticator<C> authenticate(
|
||||
S service, C configuration, String username, String password) {
|
||||
return service.getAuthenticator(new Credential(username, password),
|
||||
configuration);
|
||||
}
|
||||
|
||||
public static <S extends AuthenticationService<C>, C extends AuthenticatorConfiguration> Authenticator<C> authenticate(
|
||||
S service, String username, String password) {
|
||||
return service.getAuthenticator(new Credential(username, password));
|
||||
}
|
||||
}
|
||||
@@ -14,19 +14,19 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service.captcha;
|
||||
package com.rogiel.httpchannel.service.helper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
import com.rogiel.httpchannel.service.DownloadService;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public interface CaptchaResolver {
|
||||
/**
|
||||
* Passes an captcha by parameter and waits for the response of the
|
||||
* challenge.
|
||||
*
|
||||
* @param captcha
|
||||
* the captcha challenge
|
||||
*/
|
||||
String resolve(Captcha captcha);
|
||||
public class DownloadServices {
|
||||
public static boolean canDownload(DownloadService<?> service, URL url)
|
||||
throws IOException {
|
||||
return service.matchURL(url);
|
||||
}
|
||||
}
|
||||
@@ -14,12 +14,16 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service;
|
||||
package com.rogiel.httpchannel.service.helper;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Iterator;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
import com.rogiel.httpchannel.service.DownloadService;
|
||||
import com.rogiel.httpchannel.service.Service;
|
||||
import com.rogiel.httpchannel.service.ServiceID;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
@@ -43,12 +47,12 @@ public class Services {
|
||||
* the URL
|
||||
* @return the matched service
|
||||
*/
|
||||
public static DownloadService matchURL(URL url) {
|
||||
public static DownloadService<?> matchURL(URL url) {
|
||||
for (final Service service : iterate()) {
|
||||
if (!(service instanceof DownloadService))
|
||||
continue;
|
||||
if (((DownloadService) service).matchURL(url))
|
||||
return (DownloadService) service;
|
||||
if (((DownloadService<?>) service).matchURL(url))
|
||||
return (DownloadService<?>) service;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -14,37 +14,34 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service;
|
||||
package com.rogiel.httpchannel.service.helper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import com.rogiel.httpchannel.service.UploadService;
|
||||
import com.rogiel.httpchannel.service.Uploader;
|
||||
import com.rogiel.httpchannel.service.Uploader.UploaderConfiguration;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class ServiceHelper {
|
||||
private final Service service;
|
||||
|
||||
/**
|
||||
* @param service
|
||||
* the service
|
||||
*/
|
||||
public ServiceHelper(Service service) {
|
||||
this.service = service;
|
||||
public class UploadServices {
|
||||
public static <S extends UploadService<C>, C extends UploaderConfiguration> Uploader<C> upload(
|
||||
S service, C configuration, Path path) throws IOException {
|
||||
return service.getUploader(path.getFileName().toString(),
|
||||
Files.size(path), configuration);
|
||||
}
|
||||
|
||||
public UploadChannel upload(Path path, String description)
|
||||
throws IOException {
|
||||
return ((UploadService) service).getUploader(
|
||||
path.getFileName().toString(), Files.size(path), description)
|
||||
.upload();
|
||||
public static <S extends UploadService<C>, C extends UploaderConfiguration> Uploader<C> upload(
|
||||
S service, Path path) throws IOException {
|
||||
return service.getUploader(path.getFileName().toString(),
|
||||
Files.size(path));
|
||||
}
|
||||
|
||||
public UploadChannel upload(File file, String description)
|
||||
public static boolean canUpload(UploadService<?> service, Path path)
|
||||
throws IOException {
|
||||
return ((UploadService) service).getUploader(file.getName(),
|
||||
file.length(), description).upload();
|
||||
return service.getMaximumFilesize() >= Files.size(path);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.util.transformer;
|
||||
|
||||
/**
|
||||
* @author rogiel
|
||||
*
|
||||
*/
|
||||
public interface Transformer<O> {
|
||||
O transform(String data) throws TransformationException;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.util.transformer;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import com.rogiel.httpchannel.util.transformer.impl.BooleanTransformer;
|
||||
import com.rogiel.httpchannel.util.transformer.impl.IntegerTransformer;
|
||||
import com.rogiel.httpchannel.util.transformer.impl.LongTransformer;
|
||||
import com.rogiel.httpchannel.util.transformer.impl.StringTransformer;
|
||||
import com.rogiel.httpchannel.util.transformer.impl.URLTransformer;
|
||||
|
||||
|
||||
/**
|
||||
* @author Rogiel
|
||||
* @since 1.0
|
||||
*/
|
||||
public class TransformerFactory {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Transformer<T> getTransformer(Class<T> type) {
|
||||
if (String.class.isAssignableFrom(type)) {
|
||||
return (Transformer<T>) new StringTransformer();
|
||||
} else if (Boolean.class.isAssignableFrom(type) || type == Boolean.TYPE) {
|
||||
return (Transformer<T>) new BooleanTransformer();
|
||||
} else if (Integer.class.isAssignableFrom(type) || type == Integer.TYPE) {
|
||||
return (Transformer<T>) new IntegerTransformer();
|
||||
} else if (Long.class.isAssignableFrom(type) || type == Long.TYPE) {
|
||||
return (Transformer<T>) new LongTransformer();
|
||||
} else if (URL.class.isAssignableFrom(type)) {
|
||||
return (Transformer<T>) new URLTransformer();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.util.transformer.impl;
|
||||
|
||||
import com.rogiel.httpchannel.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* @author rogiel
|
||||
*
|
||||
*/
|
||||
public class BooleanTransformer implements Transformer<Boolean> {
|
||||
@Override
|
||||
public Boolean transform(String data) {
|
||||
return Boolean.parseBoolean(data);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.util.transformer.impl;
|
||||
|
||||
import com.rogiel.httpchannel.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* @author rogiel
|
||||
*
|
||||
*/
|
||||
public class IntegerTransformer implements Transformer<Integer> {
|
||||
@Override
|
||||
public Integer transform(String data) {
|
||||
return Integer.parseInt(data);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.util.transformer.impl;
|
||||
|
||||
import com.rogiel.httpchannel.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* @author rogiel
|
||||
*
|
||||
*/
|
||||
public class LongTransformer implements Transformer<Long> {
|
||||
@Override
|
||||
public Long transform(String data) {
|
||||
return Long.parseLong(data);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.util.transformer.impl;
|
||||
|
||||
import com.rogiel.httpchannel.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* @author rogiel
|
||||
*
|
||||
*/
|
||||
public class StringTransformer implements Transformer<String> {
|
||||
@Override
|
||||
public String transform(String data) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.util.transformer.impl;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import com.rogiel.httpchannel.util.transformer.TransformationException;
|
||||
import com.rogiel.httpchannel.util.transformer.Transformer;
|
||||
|
||||
|
||||
/**
|
||||
* @author rogiel
|
||||
*
|
||||
*/
|
||||
public class URLTransformer implements Transformer<URL> {
|
||||
@Override
|
||||
public URL transform(String data) throws TransformationException {
|
||||
try {
|
||||
return new URL(data);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new TransformationException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
httpchannel-capcha/httpchannel-captcha-recaptcha/pom.xml
Normal file
24
httpchannel-capcha/httpchannel-captcha-recaptcha/pom.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>httpchannel-capcha</artifactId>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>httpchannel-captcha-recaptcha</artifactId>
|
||||
<name>HttpChannel/CaptchaService/ReCaptcha</name>
|
||||
<description>This module provides captcha resolving for Google ReCaptcha</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<artifactId>httpchannel-api</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<artifactId>httpchannel-util</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.rogiel.httpchannel.captcha.impl;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import com.rogiel.httpchannel.captcha.AbstractImageCaptcha;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public class ReCaptcha extends AbstractImageCaptcha {
|
||||
public ReCaptcha(URL url, String ID) {
|
||||
super(url, ID);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.captcha.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.rogiel.httpchannel.captcha.AbstractImageCaptchaService;
|
||||
import com.rogiel.httpchannel.util.PatternUtils;
|
||||
import com.rogiel.httpchannel.util.htmlparser.HTMLPage;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public class ReCaptchaService extends AbstractImageCaptchaService<ReCaptcha> {
|
||||
// http://www.google.com/recaptcha/api/noscript?k=6LdRTL8SAAAAAE9UOdWZ4d0Ky-aeA7XfSqyWDM2m
|
||||
private static final Pattern CAPTCHA_URL_PATTERN = Pattern
|
||||
.compile("http://www\\.google\\.com/recaptcha/api/challenge\\?k=([0-9A-z|\\-]*)(&(.*))?");
|
||||
private static final Pattern CAPTCHA_IMAGE_PATTERN = Pattern
|
||||
.compile("challenge : '(.*)'");
|
||||
private static final String BASE_URL = "http://www.google.com/recaptcha/api/image?c=";
|
||||
|
||||
@Override
|
||||
public ReCaptcha create(HTMLPage page) throws IOException {
|
||||
final String url = page.findScriptSrc(CAPTCHA_URL_PATTERN);
|
||||
|
||||
if (url == null)
|
||||
return null;
|
||||
final String captchaPage = get(url).asString();
|
||||
|
||||
final String id = PatternUtils.find(CAPTCHA_IMAGE_PATTERN, captchaPage,
|
||||
1);
|
||||
return new ReCaptcha(new URL(BASE_URL + id), id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resolve(ReCaptcha captcha) {
|
||||
// not supported!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
16
httpchannel-capcha/pom.xml
Normal file
16
httpchannel-capcha/pom.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>httpchannel</artifactId>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>httpchannel-capcha</artifactId>
|
||||
<name>HttpChannel/CaptchaService</name>
|
||||
<description>This module provides implementations for captcha resolving</description>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>httpchannel-captcha-recaptcha</module>
|
||||
</modules>
|
||||
</project>
|
||||
31
httpchannel-channelcopy/pom.xml
Normal file
31
httpchannel-channelcopy/pom.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>httpchannel</artifactId>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>httpchannel-channelcopy</artifactId>
|
||||
<name>HttpChannel/ChannelCopy</name>
|
||||
<description>The HttpChannel ChannelCopy module provides an easy method to copy data from a single download channel into one or more upload channels.</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<artifactId>httpchannel-api</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.rogiel.httpchannel.services</groupId>
|
||||
<artifactId>httpchannel-service-megaupload</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.rogiel.httpchannel.services</groupId>
|
||||
<artifactId>httpchannel-service-multiupload</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,206 @@
|
||||
package com.rogiel.httpchannel.copy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.rogiel.httpchannel.copy.exception.NoServiceFoundException;
|
||||
import com.rogiel.httpchannel.service.DownloadChannel;
|
||||
import com.rogiel.httpchannel.service.DownloadService;
|
||||
import com.rogiel.httpchannel.service.UploadChannel;
|
||||
import com.rogiel.httpchannel.service.UploadService;
|
||||
import com.rogiel.httpchannel.service.Uploader.UploaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadLimitExceededException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadLinkNotFoundException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadNotAuthorizedException;
|
||||
import com.rogiel.httpchannel.service.exception.UploadLinkNotFoundException;
|
||||
import com.rogiel.httpchannel.service.helper.Services;
|
||||
|
||||
/**
|
||||
* This class provides an utility that copies the entire content of a
|
||||
* {@link ReadableByteChannel} (this can be an {@link DownloadChannel} or any
|
||||
* {@link Files#newByteChannel(Path, java.nio.file.OpenOption...)} opened with
|
||||
* {@link StandardOpenOption#READ READ}.
|
||||
* <p>
|
||||
* The input channel must be created or provided at construction time, but
|
||||
* several output channels can be added through
|
||||
* {@link #addOutput(UploadChannel)}, {@link #addOutput(UploadService)} or
|
||||
* {@link #addOutput(UploadService, UploaderConfiguration)}.
|
||||
* <p>
|
||||
* Once all output channels were set, {@link #call()} must be called in order to
|
||||
* start copying data. This class implements {@link Callable} and thus can be
|
||||
* executed inside an {@link Executor}.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class ChannelCopy implements Callable<List<URL>> {
|
||||
/**
|
||||
* The input channel
|
||||
*/
|
||||
private final ReadableByteChannel downloadChannel;
|
||||
/**
|
||||
* The filename
|
||||
*/
|
||||
private final String filename;
|
||||
/**
|
||||
* The filesise
|
||||
*/
|
||||
private final long filesize;
|
||||
|
||||
/**
|
||||
* The list of all channels to write data to
|
||||
*/
|
||||
private final List<UploadChannel> uploadChannels = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Initializes with an {@link ReadableByteChannel}, filename and filesize
|
||||
*
|
||||
* @param channel
|
||||
* the channel
|
||||
* @param filename
|
||||
* the file name
|
||||
* @param filesize
|
||||
* the file size
|
||||
*/
|
||||
public ChannelCopy(ReadableByteChannel channel, String filename,
|
||||
long filesize) {
|
||||
this.downloadChannel = channel;
|
||||
this.filename = filename;
|
||||
this.filesize = filesize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes with a {@link Path}. Will open a new channel.
|
||||
*
|
||||
* @param path
|
||||
* @throws IOException
|
||||
*/
|
||||
public ChannelCopy(Path path) throws IOException {
|
||||
this(Files.newByteChannel(path, StandardOpenOption.READ), path
|
||||
.getFileName().toString(), Files.size(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes with a {@link DownloadChannel}
|
||||
*
|
||||
* @param downloadChannel
|
||||
* the download channel
|
||||
*/
|
||||
public ChannelCopy(DownloadChannel downloadChannel) {
|
||||
this.downloadChannel = downloadChannel;
|
||||
this.filename = downloadChannel.getFilename();
|
||||
this.filesize = downloadChannel.getFilesize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes with an {@link URL}. First tries to open an
|
||||
* {@link DownloadChannel}, if no service is found,
|
||||
* {@link NoServiceFoundException} is thrown.
|
||||
*
|
||||
* @param url
|
||||
* the source {@link URL}
|
||||
* @throws DownloadLinkNotFoundException
|
||||
* if the download link could not be found
|
||||
* @throws DownloadLimitExceededException
|
||||
* if the download limit has been exceeded
|
||||
* @throws DownloadNotAuthorizedException
|
||||
* if the download was not authorized by the service
|
||||
* @throws NoServiceFoundException
|
||||
* if no service could be found for the {@link URL}
|
||||
* @throws IOException
|
||||
* if any IO error occur
|
||||
*/
|
||||
public ChannelCopy(URL url) throws DownloadLinkNotFoundException,
|
||||
DownloadLimitExceededException, DownloadNotAuthorizedException,
|
||||
IOException {
|
||||
final DownloadService<?> service = Services.matchURL(url);
|
||||
if (service == null)
|
||||
throw new NoServiceFoundException(url.toString());
|
||||
final DownloadChannel downloadChannel = service.getDownloader(url)
|
||||
.openChannel();
|
||||
|
||||
this.downloadChannel = downloadChannel;
|
||||
this.filename = downloadChannel.getFilename();
|
||||
this.filesize = downloadChannel.getFilesize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new output channel in which data should be written
|
||||
*
|
||||
* @param channel
|
||||
* the channel
|
||||
*/
|
||||
public void addOutput(UploadChannel channel) {
|
||||
uploadChannels.add(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new output in which data should be written. Creates a new
|
||||
* {@link UploadChannel} based on the {@link UploadService}.
|
||||
*
|
||||
* @param service
|
||||
* the upload service
|
||||
* @throws IOException
|
||||
* if any IO error occur
|
||||
*/
|
||||
public void addOutput(UploadService<?> service) throws IOException {
|
||||
addOutput(service.getUploader(filename, filesize).openChannel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new output in which data should be written. Creates a new
|
||||
* {@link UploadChannel} based on the {@link UploadService}.
|
||||
*
|
||||
* @param service
|
||||
* the upload service
|
||||
* @param configuration
|
||||
* the uploader configuration
|
||||
* @throws IOException
|
||||
* if any IO error occur
|
||||
*/
|
||||
public <S extends UploadService<C>, C extends UploaderConfiguration> void addOutput(
|
||||
S service, C configuration) throws IOException {
|
||||
addOutput(service.getUploader(filename, filesize, configuration)
|
||||
.openChannel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<URL> call() throws IOException {
|
||||
final ByteBuffer buffer = ByteBuffer.allocate(16 * 1024);
|
||||
try {
|
||||
while (downloadChannel.read(buffer) >= 0) {
|
||||
buffer.flip();
|
||||
final int limit = buffer.limit();
|
||||
final int position = buffer.position();
|
||||
for (final UploadChannel channel : uploadChannels) {
|
||||
channel.write(buffer);
|
||||
buffer.limit(limit).position(position);
|
||||
}
|
||||
buffer.clear();
|
||||
}
|
||||
} finally {
|
||||
downloadChannel.close();
|
||||
for (final UploadChannel channel : uploadChannels) {
|
||||
try {
|
||||
channel.close();
|
||||
} catch (UploadLinkNotFoundException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final List<URL> urls = new ArrayList<>();
|
||||
for (final UploadChannel channel : uploadChannels) {
|
||||
urls.add(channel.getDownloadLink());
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.rogiel.httpchannel.copy.exception;
|
||||
|
||||
import com.rogiel.httpchannel.service.exception.ChannelServiceException;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class ChannelCopyException extends ChannelServiceException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public ChannelCopyException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* the message
|
||||
* @param cause
|
||||
* the cause
|
||||
*/
|
||||
public ChannelCopyException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* the message
|
||||
*/
|
||||
public ChannelCopyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* the cause
|
||||
*/
|
||||
public ChannelCopyException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.rogiel.httpchannel.copy.exception;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class NoServiceFoundException extends ChannelCopyException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public NoServiceFoundException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* the message
|
||||
* @param cause
|
||||
* the cause
|
||||
*/
|
||||
public NoServiceFoundException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* the message
|
||||
*/
|
||||
public NoServiceFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* the cause
|
||||
*/
|
||||
public NoServiceFoundException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.rogiel.httpchannel.wirecopy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.rogiel.httpchannel.copy.ChannelCopy;
|
||||
import com.rogiel.httpchannel.service.impl.MegaUploadService;
|
||||
import com.rogiel.httpchannel.service.impl.MultiUploadService;
|
||||
|
||||
public class ChannelCopyTest {
|
||||
@Test
|
||||
public void testWireCopy() throws IOException {
|
||||
final ChannelCopy copy = new ChannelCopy(Paths.get("pom.xml"));
|
||||
copy.addOutput(new MegaUploadService());
|
||||
copy.addOutput(new MultiUploadService());
|
||||
System.out.println(copy.call());
|
||||
}
|
||||
}
|
||||
20
httpchannel-service/httpchannel-service-depositfiles/pom.xml
Normal file
20
httpchannel-service/httpchannel-service-depositfiles/pom.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>httpchannel-service</artifactId>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>httpchannel-service-depositfiles</artifactId>
|
||||
<groupId>com.rogiel.httpchannel.services</groupId>
|
||||
<name>HttpChannel/Service/DepositFiles</name>
|
||||
<description>Provides upload access to depositfiles.com</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<artifactId>httpchannel-captcha-recaptcha</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,212 @@
|
||||
package com.rogiel.httpchannel.service.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.rogiel.httpchannel.captcha.impl.ReCaptcha;
|
||||
import com.rogiel.httpchannel.captcha.impl.ReCaptchaService;
|
||||
import com.rogiel.httpchannel.service.AbstractAuthenticator;
|
||||
import com.rogiel.httpchannel.service.AbstractHttpService;
|
||||
import com.rogiel.httpchannel.service.AbstractUploader;
|
||||
import com.rogiel.httpchannel.service.AuthenticationService;
|
||||
import com.rogiel.httpchannel.service.Authenticator;
|
||||
import com.rogiel.httpchannel.service.AuthenticatorCapability;
|
||||
import com.rogiel.httpchannel.service.CapabilityMatrix;
|
||||
import com.rogiel.httpchannel.service.Credential;
|
||||
import com.rogiel.httpchannel.service.Service;
|
||||
import com.rogiel.httpchannel.service.ServiceID;
|
||||
import com.rogiel.httpchannel.service.UploadChannel;
|
||||
import com.rogiel.httpchannel.service.UploadService;
|
||||
import com.rogiel.httpchannel.service.Uploader;
|
||||
import com.rogiel.httpchannel.service.UploaderCapability;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel.LinkedUploadChannelCloseCallback;
|
||||
import com.rogiel.httpchannel.service.config.NullAuthenticatorConfiguration;
|
||||
import com.rogiel.httpchannel.service.config.NullUploaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException;
|
||||
import com.rogiel.httpchannel.service.exception.UnresolvedCaptchaException;
|
||||
import com.rogiel.httpchannel.util.htmlparser.HTMLPage;
|
||||
|
||||
/**
|
||||
* This service handles uploads to UploadKing.com.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com/">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public class DepositFilesService extends AbstractHttpService implements
|
||||
Service, UploadService<NullUploaderConfiguration>,
|
||||
AuthenticationService<NullAuthenticatorConfiguration> {
|
||||
/**
|
||||
* This service ID
|
||||
*/
|
||||
public static final ServiceID SERVICE_ID = ServiceID.create("depositfiles");
|
||||
|
||||
private static final Pattern UPLOAD_URL_PATTERN = Pattern
|
||||
.compile("http://fileshare([0-9]*)\\.depositfiles\\.com/(.*)/\\?X-Progress-ID=(.*)");
|
||||
private static final Pattern DOWNLOAD_URL_PATTERN = Pattern
|
||||
.compile("http://(www\\.)?depositfiles\\.com/files/([0-9A-z]*)");
|
||||
|
||||
private static final Pattern VALID_LOGIN_REDIRECT = Pattern
|
||||
.compile("window.location.href");
|
||||
|
||||
private final ReCaptchaService captchaService = new ReCaptchaService();
|
||||
|
||||
@Override
|
||||
public ServiceID getID() {
|
||||
return SERVICE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMajorVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinorVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uploader<NullUploaderConfiguration> getUploader(String filename,
|
||||
long filesize, NullUploaderConfiguration configuration) {
|
||||
return new UploadKingUploader(filename, filesize, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uploader<NullUploaderConfiguration> getUploader(String filename,
|
||||
long filesize) {
|
||||
return getUploader(filename, filesize, newUploaderConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NullUploaderConfiguration newUploaderConfiguration() {
|
||||
return NullUploaderConfiguration.SHARED_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaximumFilesize() {
|
||||
return 2 * 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedExtensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CapabilityMatrix<UploaderCapability> getUploadCapabilities() {
|
||||
return new CapabilityMatrix<UploaderCapability>(
|
||||
UploaderCapability.UNAUTHENTICATED_UPLOAD,
|
||||
UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD,
|
||||
UploaderCapability.PREMIUM_ACCOUNT_UPLOAD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator<NullAuthenticatorConfiguration> getAuthenticator(
|
||||
Credential credential, NullAuthenticatorConfiguration configuration) {
|
||||
return new UploadKingAuthenticator(credential, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator<NullAuthenticatorConfiguration> getAuthenticator(
|
||||
Credential credential) {
|
||||
return getAuthenticator(credential, newAuthenticatorConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NullAuthenticatorConfiguration newAuthenticatorConfiguration() {
|
||||
return NullAuthenticatorConfiguration.SHARED_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CapabilityMatrix<AuthenticatorCapability> getAuthenticationCapability() {
|
||||
return new CapabilityMatrix<AuthenticatorCapability>();
|
||||
}
|
||||
|
||||
protected class UploadKingUploader extends
|
||||
AbstractUploader<NullUploaderConfiguration> implements
|
||||
Uploader<NullUploaderConfiguration>,
|
||||
LinkedUploadChannelCloseCallback {
|
||||
private Future<HTMLPage> uploadFuture;
|
||||
|
||||
public UploadKingUploader(String filename, long filesize,
|
||||
NullUploaderConfiguration configuration) {
|
||||
super(filename, filesize, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UploadChannel openChannel() throws IOException {
|
||||
final HTMLPage page = get("http://www.depositfiles.com/").asPage();
|
||||
|
||||
final String url = page.findFormAction(UPLOAD_URL_PATTERN);
|
||||
final String uploadID = page.getInputValue("UPLOAD_IDENTIFIER");
|
||||
final String maxFileSize = page.getInputValue("MAX_FILE_SIZE");
|
||||
|
||||
final LinkedUploadChannel channel = createLinkedChannel(this);
|
||||
uploadFuture = multipartPost(url).parameter("files", channel)
|
||||
.parameter("go", true)
|
||||
.parameter("UPLOAD_IDENTIFIER", uploadID)
|
||||
.parameter("agree", true)
|
||||
.parameter("MAX_FILE_SIZE", maxFileSize).asPageAsync();
|
||||
return waitChannelLink(channel, uploadFuture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String finish() throws IOException {
|
||||
try {
|
||||
final String link = uploadFuture.get().findScript(
|
||||
DOWNLOAD_URL_PATTERN, 0);
|
||||
if (link == null)
|
||||
return null;
|
||||
return link;
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
} catch (ExecutionException e) {
|
||||
throw (IOException) e.getCause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected class UploadKingAuthenticator extends
|
||||
AbstractAuthenticator<NullAuthenticatorConfiguration> implements
|
||||
Authenticator<NullAuthenticatorConfiguration> {
|
||||
public UploadKingAuthenticator(Credential credential,
|
||||
NullAuthenticatorConfiguration configuration) {
|
||||
super(credential, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void login() throws IOException {
|
||||
HTMLPage page = post("http://depositfiles.com/login.php?return=%2F")
|
||||
.parameter("go", true)
|
||||
.parameter("login", credential.getUsername())
|
||||
.parameter("password", credential.getPassword()).asPage();
|
||||
|
||||
final ReCaptcha captcha = captchaService.create(page);
|
||||
if (captcha != null) {
|
||||
if (!resolveCaptcha(captcha))
|
||||
throw new UnresolvedCaptchaException();
|
||||
page = post("http://depositfiles.com/login.php?return=%2F")
|
||||
.parameter("go", true)
|
||||
.parameter("login", credential.getUsername())
|
||||
.parameter("password", credential.getPassword())
|
||||
.parameter("recaptcha_challenge_field", captcha.getID())
|
||||
.parameter("recaptcha_response_field",
|
||||
captcha.getAnswer()).asPage();
|
||||
}
|
||||
|
||||
if (!page.contains(VALID_LOGIN_REDIRECT))
|
||||
throw new AuthenticationInvalidCredentialException();
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() throws IOException {
|
||||
post("http://www.uploadking.com/login").parameter("do", "logout")
|
||||
.request();
|
||||
// TODO check logout status
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
com.rogiel.httpchannel.service.impl.MultiUploadService
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.rogiel.httpchannel.service.impl;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.rogiel.httpchannel.service.UploaderCapability;
|
||||
import com.rogiel.httpchannel.util.ChannelUtils;
|
||||
|
||||
public class DepositFilesServiceTest {
|
||||
private DepositFilesService service;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
service = new DepositFilesService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonLoguedInUploader() throws IOException {
|
||||
assertTrue(
|
||||
"This service does not have the capability UploadCapability.UNAUTHENTICATED_UPLOAD",
|
||||
service.getUploadCapabilities().has(
|
||||
UploaderCapability.UNAUTHENTICATED_UPLOAD));
|
||||
|
||||
final Path path = Paths.get("src/test/resources/upload-test-file.txt");
|
||||
final URL url = ChannelUtils.upload(service, path);
|
||||
|
||||
Assert.assertNotNull(url);
|
||||
System.out.println(url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
This is a simple upload test file.
|
||||
|
||||
This is for testing purposes only.
|
||||
@@ -7,4 +7,7 @@
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>httpchannel-service-hotfile</artifactId>
|
||||
<groupId>com.rogiel.httpchannel.services</groupId>
|
||||
<name>HttpChannel/Service/HotFile</name>
|
||||
<description>Provides download and upload access to hotfile.com</description>
|
||||
</project>
|
||||
@@ -25,12 +25,12 @@ import java.util.regex.Pattern;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.entity.mime.MultipartEntity;
|
||||
import org.apache.http.entity.mime.content.StringBody;
|
||||
import org.htmlparser.Tag;
|
||||
|
||||
import com.rogiel.httpchannel.service.AbstractDownloader;
|
||||
import com.rogiel.httpchannel.service.AbstractAuthenticator;
|
||||
import com.rogiel.httpchannel.service.AbstractHttpDownloader;
|
||||
import com.rogiel.httpchannel.service.AbstractHttpService;
|
||||
import com.rogiel.httpchannel.service.AbstractUploader;
|
||||
import com.rogiel.httpchannel.service.AuthenticationService;
|
||||
import com.rogiel.httpchannel.service.Authenticator;
|
||||
import com.rogiel.httpchannel.service.AuthenticatorCapability;
|
||||
@@ -50,23 +50,22 @@ import com.rogiel.httpchannel.service.UploaderCapability;
|
||||
import com.rogiel.httpchannel.service.channel.InputStreamDownloadChannel;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel.LinkedUploadChannelCloseCallback;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannelContentBody;
|
||||
import com.rogiel.httpchannel.service.config.ServiceConfiguration;
|
||||
import com.rogiel.httpchannel.service.config.ServiceConfigurationHelper;
|
||||
import com.rogiel.httpchannel.service.config.NullAuthenticatorConfiguration;
|
||||
import com.rogiel.httpchannel.service.config.NullDownloaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.config.NullUploaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException;
|
||||
import com.rogiel.httpchannel.service.impl.HotFileService.HotFileServiceConfiguration;
|
||||
import com.rogiel.httpchannel.util.ThreadUtils;
|
||||
import com.rogiel.httpchannel.util.htmlparser.HTMLPage;
|
||||
|
||||
/**
|
||||
* This service handles login, upload and download to HotFile.com.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public class HotFileService extends
|
||||
AbstractHttpService<HotFileServiceConfiguration> implements Service,
|
||||
UploadService, DownloadService, AuthenticationService {
|
||||
public class HotFileService extends AbstractHttpService implements Service,
|
||||
UploadService<NullUploaderConfiguration>,
|
||||
DownloadService<NullDownloaderConfiguration>,
|
||||
AuthenticationService<NullAuthenticatorConfiguration> {
|
||||
/**
|
||||
* This service ID
|
||||
*/
|
||||
@@ -85,11 +84,6 @@ public class HotFileService extends
|
||||
private static final Pattern DOWNLOAD_URL_PATTERN = Pattern
|
||||
.compile("http://hotfile\\.com/dl/([0-9]*)/([A-Za-z0-9]*)/(.*)");
|
||||
|
||||
public HotFileService() {
|
||||
super(ServiceConfigurationHelper
|
||||
.defaultConfiguration(HotFileServiceConfiguration.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServiceID getID() {
|
||||
return SERVICE_ID;
|
||||
@@ -106,9 +100,20 @@ public class HotFileService extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uploader getUploader(String filename, long filesize,
|
||||
String description) {
|
||||
return new HotFileUploader(filename, filesize);
|
||||
public Uploader<NullUploaderConfiguration> getUploader(String filename,
|
||||
long filesize, NullUploaderConfiguration configuration) {
|
||||
return new HotFileUploader(filename, filesize, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uploader<NullUploaderConfiguration> getUploader(String filename,
|
||||
long filesize) {
|
||||
return getUploader(filename, filesize, newUploaderConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NullUploaderConfiguration newUploaderConfiguration() {
|
||||
return NullUploaderConfiguration.SHARED_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -130,8 +135,19 @@ public class HotFileService extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public Downloader getDownloader(URL url) {
|
||||
return new HotFileDownloader(url);
|
||||
public Downloader<NullDownloaderConfiguration> getDownloader(URL url,
|
||||
NullDownloaderConfiguration configuration) {
|
||||
return new HotFileDownloader(url, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Downloader<NullDownloaderConfiguration> getDownloader(URL url) {
|
||||
return getDownloader(url, newDownloaderConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NullDownloaderConfiguration newDownloaderConfiguration() {
|
||||
return NullDownloaderConfiguration.SHARED_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -146,8 +162,20 @@ public class HotFileService extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator getAuthenticator(Credential credential) {
|
||||
return new HotFileAuthenticator(credential);
|
||||
public Authenticator<NullAuthenticatorConfiguration> getAuthenticator(
|
||||
Credential credential, NullAuthenticatorConfiguration configuration) {
|
||||
return new HotFileAuthenticator(credential, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator<NullAuthenticatorConfiguration> getAuthenticator(
|
||||
Credential credential) {
|
||||
return getAuthenticator(credential, newAuthenticatorConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NullAuthenticatorConfiguration newAuthenticatorConfiguration() {
|
||||
return NullAuthenticatorConfiguration.SHARED_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -155,36 +183,27 @@ public class HotFileService extends
|
||||
return new CapabilityMatrix<AuthenticatorCapability>();
|
||||
}
|
||||
|
||||
protected class HotFileUploader implements Uploader,
|
||||
protected class HotFileUploader extends
|
||||
AbstractUploader<NullUploaderConfiguration> implements
|
||||
Uploader<NullUploaderConfiguration>,
|
||||
LinkedUploadChannelCloseCallback {
|
||||
private final String filename;
|
||||
private final long filesize;
|
||||
|
||||
private Future<HTMLPage> uploadFuture;
|
||||
|
||||
public HotFileUploader(String filename, long filesize) {
|
||||
super();
|
||||
this.filename = filename;
|
||||
this.filesize = filesize;
|
||||
public HotFileUploader(String filename, long filesize,
|
||||
NullUploaderConfiguration configuration) {
|
||||
super(filename, filesize, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UploadChannel upload() throws IOException {
|
||||
final HTMLPage page = getAsPage("http://www.hotfile.com/");
|
||||
final String action = page.getFormAction(UPLOAD_URL_PATTERN);
|
||||
public UploadChannel openChannel() throws IOException {
|
||||
final HTMLPage page = get("http://www.hotfile.com/").asPage();
|
||||
final String action = page.findFormAction(UPLOAD_URL_PATTERN);
|
||||
|
||||
final LinkedUploadChannel channel = new LinkedUploadChannel(this,
|
||||
filesize, filename);
|
||||
final MultipartEntity entity = new MultipartEntity();
|
||||
final LinkedUploadChannel channel = createLinkedChannel(this);
|
||||
|
||||
entity.addPart("uploads[]", new LinkedUploadChannelContentBody(
|
||||
channel));
|
||||
|
||||
uploadFuture = postAsPageAsync(action, entity);
|
||||
while (!channel.isLinked() && !uploadFuture.isDone()) {
|
||||
ThreadUtils.sleep(100);
|
||||
}
|
||||
return channel;
|
||||
uploadFuture = multipartPost(action)
|
||||
.parameter("uploads[]", channel).asPageAsync();
|
||||
return waitChannelLink(channel, uploadFuture);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -199,17 +218,17 @@ public class HotFileService extends
|
||||
}
|
||||
}
|
||||
|
||||
protected class HotFileDownloader extends AbstractDownloader {
|
||||
private final URL url;
|
||||
|
||||
public HotFileDownloader(URL url) {
|
||||
this.url = url;
|
||||
protected class HotFileDownloader extends
|
||||
AbstractHttpDownloader<NullDownloaderConfiguration> {
|
||||
public HotFileDownloader(URL url,
|
||||
NullDownloaderConfiguration configuration) {
|
||||
super(url, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DownloadChannel download(DownloadListener listener, long position)
|
||||
throws IOException {
|
||||
final HTMLPage page = getAsPage(url.toString());
|
||||
public DownloadChannel openChannel(DownloadListener listener,
|
||||
long position) throws IOException {
|
||||
final HTMLPage page = get(url).asPage();
|
||||
|
||||
// // try to find timer
|
||||
// final String stringTimer = PatternUtils.find(DOWNLOAD_TIMER,
|
||||
@@ -224,11 +243,12 @@ public class HotFileService extends
|
||||
// }
|
||||
|
||||
final String downloadUrl = page
|
||||
.getLink(DOWNLOAD_DIRECT_LINK_PATTERN);
|
||||
.findLink(DOWNLOAD_DIRECT_LINK_PATTERN);
|
||||
// final String tmHash = PatternUtils.find(DOWNLOAD_TMHASH_PATTERN,
|
||||
// content);F
|
||||
if (downloadUrl != null && downloadUrl.length() > 0) {
|
||||
final HttpResponse downloadResponse = get(downloadUrl);
|
||||
final HttpResponse downloadResponse = get(downloadUrl)
|
||||
.request();
|
||||
|
||||
final String filename = FilenameUtils.getName(downloadUrl);
|
||||
long contentLength = getContentLength(downloadResponse);
|
||||
@@ -284,23 +304,21 @@ public class HotFileService extends
|
||||
}
|
||||
}
|
||||
|
||||
protected class HotFileAuthenticator implements Authenticator {
|
||||
private final Credential credential;
|
||||
|
||||
public HotFileAuthenticator(Credential credential) {
|
||||
this.credential = credential;
|
||||
protected class HotFileAuthenticator extends
|
||||
AbstractAuthenticator<NullAuthenticatorConfiguration> implements
|
||||
Authenticator<NullAuthenticatorConfiguration> {
|
||||
public HotFileAuthenticator(Credential credential,
|
||||
NullAuthenticatorConfiguration configuration) {
|
||||
super(credential, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void login() throws ClientProtocolException, IOException {
|
||||
final MultipartEntity entity = new MultipartEntity();
|
||||
HTMLPage page = post("http://www.hotfile.com/login.php")
|
||||
.parameter("returnto", "/index.php")
|
||||
.parameter("user", credential.getUsername())
|
||||
.parameter("pass", credential.getPassword()).asPage();
|
||||
|
||||
entity.addPart("returnto", new StringBody("/index.php"));
|
||||
entity.addPart("user", new StringBody(credential.getUsername()));
|
||||
entity.addPart("pass", new StringBody(credential.getPassword()));
|
||||
|
||||
HTMLPage page = postAsPage("http://www.hotfile.com/login.php",
|
||||
entity);
|
||||
final Tag accountTag = page.getTagByID("account");
|
||||
if (accountTag == null)
|
||||
throw new AuthenticationInvalidCredentialException();
|
||||
@@ -308,18 +326,12 @@ public class HotFileService extends
|
||||
|
||||
@Override
|
||||
public void logout() throws IOException {
|
||||
final MultipartEntity entity = new MultipartEntity();
|
||||
entity.addPart("logout", new StringBody("1"));
|
||||
|
||||
postAsString("http://www.megaupload.com/?c=account", entity);
|
||||
post("http://www.megaupload.com/?c=account").parameter("logout",
|
||||
true).request();
|
||||
// TODO check logout status
|
||||
}
|
||||
}
|
||||
|
||||
public static interface HotFileServiceConfiguration extends
|
||||
ServiceConfiguration {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getSimpleName() + " " + getMajorVersion() + "."
|
||||
|
||||
@@ -20,7 +20,7 @@ import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.rogiel.httpchannel.service.Services;
|
||||
import com.rogiel.httpchannel.service.helper.Services;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
|
||||
@@ -22,8 +22,6 @@ import static org.junit.Assert.assertTrue;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
@@ -38,23 +36,19 @@ import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.rogiel.httpchannel.service.AuthenticationService;
|
||||
import com.rogiel.httpchannel.service.Credential;
|
||||
import com.rogiel.httpchannel.service.DownloadChannel;
|
||||
import com.rogiel.httpchannel.service.DownloadService;
|
||||
import com.rogiel.httpchannel.service.Service;
|
||||
import com.rogiel.httpchannel.service.ServiceHelper;
|
||||
import com.rogiel.httpchannel.service.ServiceID;
|
||||
import com.rogiel.httpchannel.service.Services;
|
||||
import com.rogiel.httpchannel.service.UploadChannel;
|
||||
import com.rogiel.httpchannel.service.UploadService;
|
||||
import com.rogiel.httpchannel.service.UploaderCapability;
|
||||
import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException;
|
||||
import com.rogiel.httpchannel.service.helper.Services;
|
||||
import com.rogiel.httpchannel.service.helper.UploadServices;
|
||||
import com.rogiel.httpchannel.util.ChannelUtils;
|
||||
|
||||
public class HotFileServiceTest {
|
||||
private Service service;
|
||||
private ServiceHelper helper;
|
||||
private HotFileService service;
|
||||
|
||||
/**
|
||||
* See <b>src/test/resources/config/hotfile.properties</b>
|
||||
@@ -76,7 +70,6 @@ public class HotFileServiceTest {
|
||||
public void setUp() throws Exception {
|
||||
// MegaUploadServiceConfiguration.class;
|
||||
service = new HotFileService();
|
||||
helper = new ServiceHelper(service);
|
||||
|
||||
final Properties properties = new Properties();
|
||||
properties.load(new FileInputStream(
|
||||
@@ -87,33 +80,31 @@ public class HotFileServiceTest {
|
||||
|
||||
@Test
|
||||
public void testServiceId() {
|
||||
System.out.println("Service: " + service.toString());
|
||||
assertEquals(ServiceID.create("hotfile"), service.getID());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidAuthenticator() throws IOException {
|
||||
((AuthenticationService) service).getAuthenticator(
|
||||
new Credential(VALID_USERNAME, VALID_PASSWORD)).login();
|
||||
service.getAuthenticator(new Credential(VALID_USERNAME, VALID_PASSWORD))
|
||||
.login();
|
||||
}
|
||||
|
||||
@Test(expected = AuthenticationInvalidCredentialException.class)
|
||||
public void testInvalidAuthenticator() throws IOException {
|
||||
((AuthenticationService) service).getAuthenticator(
|
||||
service.getAuthenticator(
|
||||
new Credential(INVALID_USERNAME, INVALID_PASSWORD)).login();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonLoguedInUploader() throws IOException,
|
||||
URISyntaxException {
|
||||
public void testNonLoguedInUploader() throws IOException {
|
||||
assertTrue(
|
||||
"This service does not have the capability UploadCapability.FREE_UPLOAD",
|
||||
((UploadService) service).getUploadCapabilities().has(
|
||||
service.getUploadCapabilities().has(
|
||||
UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD));
|
||||
|
||||
final Path path = Paths.get("src/test/resources/upload-test-file.txt");
|
||||
final UploadChannel channel = helper.upload(path,
|
||||
"httpchannel test upload");
|
||||
final UploadChannel channel = UploadServices.upload(service, path)
|
||||
.openChannel();
|
||||
final SeekableByteChannel inChannel = Files.newByteChannel(path);
|
||||
|
||||
try {
|
||||
@@ -131,15 +122,15 @@ public class HotFileServiceTest {
|
||||
public void testLoguedInUploader() throws IOException {
|
||||
assertTrue(
|
||||
"This service does not have the capability UploadCapability.PREMIUM_UPLOAD",
|
||||
((UploadService) service).getUploadCapabilities().has(
|
||||
service.getUploadCapabilities().has(
|
||||
UploaderCapability.PREMIUM_ACCOUNT_UPLOAD));
|
||||
|
||||
((AuthenticationService) service).getAuthenticator(
|
||||
new Credential(VALID_USERNAME, VALID_PASSWORD)).login();
|
||||
service.getAuthenticator(new Credential(VALID_USERNAME, VALID_PASSWORD))
|
||||
.login();
|
||||
|
||||
final Path path = Paths.get("src/test/resources/upload-test-file.txt");
|
||||
final UploadChannel channel = helper.upload(path,
|
||||
"httpchannel test upload");
|
||||
final UploadChannel channel = UploadServices.upload(service, path)
|
||||
.openChannel();
|
||||
final SeekableByteChannel inChannel = Files.newByteChannel(path);
|
||||
|
||||
try {
|
||||
@@ -154,30 +145,29 @@ public class HotFileServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloader() throws IOException, MalformedURLException {
|
||||
public void testDownloader() throws IOException {
|
||||
final URL downloadUrl = new URL(
|
||||
"http://hotfile.com/dl/129251605/9b4faf2/simulado_2010_1_res_all.zip.htm");
|
||||
|
||||
final DownloadService service = Services.matchURL(downloadUrl);
|
||||
final DownloadService<?> service = Services.matchURL(downloadUrl);
|
||||
|
||||
final DownloadChannel channel = service.getDownloader(downloadUrl)
|
||||
.download(null, 0);
|
||||
.openChannel(null, 0);
|
||||
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
IOUtils.copy(Channels.newInputStream(channel), bout);
|
||||
System.out.println(bout.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoggedInDownloader() throws IOException,
|
||||
MalformedURLException {
|
||||
((AuthenticationService) service).getAuthenticator(
|
||||
new Credential(VALID_USERNAME, VALID_PASSWORD)).login();
|
||||
public void testLoggedInDownloader() throws IOException {
|
||||
service.getAuthenticator(new Credential(VALID_USERNAME, VALID_PASSWORD))
|
||||
.login();
|
||||
|
||||
final DownloadChannel channel = ((DownloadService) service)
|
||||
final DownloadChannel channel = service
|
||||
.getDownloader(
|
||||
new URL(
|
||||
"http://hotfile.com/dl/129251605/9b4faf2/simulado_2010_1_res_all.zip.html"))
|
||||
.download(null, 0);
|
||||
.openChannel(null, 0);
|
||||
|
||||
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
IOUtils.copy(Channels.newInputStream(channel), bout);
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service.impl;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.rogiel.httpchannel.service.Service;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public class ServiceCloningTest {
|
||||
@Test
|
||||
public void testDiscovery() {
|
||||
Service original = HotFileService.SERVICE_ID.getService();
|
||||
Service service = HotFileService.SERVICE_ID.getService().clone();
|
||||
|
||||
// set configuration to anything else
|
||||
service.setServiceConfiguration(null);
|
||||
|
||||
Assert.assertNotSame(service, original);
|
||||
Assert.assertNotSame(service.getServiceConfiguration(),
|
||||
original.getServiceConfiguration());
|
||||
}
|
||||
}
|
||||
@@ -7,4 +7,7 @@
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>httpchannel-service-megaupload</artifactId>
|
||||
<groupId>com.rogiel.httpchannel.services</groupId>
|
||||
<name>HttpChannel/Service/MegaUpload</name>
|
||||
<description>Provides upload and download access to megaupload.com</description>
|
||||
</project>
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.rogiel.httpchannel.service.impl;
|
||||
|
||||
import com.rogiel.httpchannel.service.Downloader.DownloaderConfiguration;
|
||||
|
||||
public class MegaUploadDownloaderConfiguration implements
|
||||
DownloaderConfiguration {
|
||||
private boolean respectWaitTime = true;
|
||||
|
||||
public boolean getRespectWaitTime() {
|
||||
return respectWaitTime;
|
||||
}
|
||||
|
||||
public void setRespectWaitTime(boolean respectWaitTime) {
|
||||
this.respectWaitTime = respectWaitTime;
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,6 @@ package com.rogiel.httpchannel.service.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -27,14 +25,11 @@ import java.util.regex.Pattern;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
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.entity.mime.MultipartEntity;
|
||||
import org.apache.http.entity.mime.content.StringBody;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
|
||||
import com.rogiel.httpchannel.service.AbstractDownloader;
|
||||
import com.rogiel.httpchannel.service.AbstractAuthenticator;
|
||||
import com.rogiel.httpchannel.service.AbstractHttpDownloader;
|
||||
import com.rogiel.httpchannel.service.AbstractHttpService;
|
||||
import com.rogiel.httpchannel.service.AbstractUploader;
|
||||
import com.rogiel.httpchannel.service.AuthenticationService;
|
||||
import com.rogiel.httpchannel.service.Authenticator;
|
||||
import com.rogiel.httpchannel.service.AuthenticatorCapability;
|
||||
@@ -51,32 +46,26 @@ import com.rogiel.httpchannel.service.UploadChannel;
|
||||
import com.rogiel.httpchannel.service.UploadService;
|
||||
import com.rogiel.httpchannel.service.Uploader;
|
||||
import com.rogiel.httpchannel.service.UploaderCapability;
|
||||
import com.rogiel.httpchannel.service.channel.InputStreamDownloadChannel;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel.LinkedUploadChannelCloseCallback;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannelContentBody;
|
||||
import com.rogiel.httpchannel.service.config.ServiceConfiguration;
|
||||
import com.rogiel.httpchannel.service.config.ServiceConfigurationHelper;
|
||||
import com.rogiel.httpchannel.service.config.ServiceConfigurationProperty;
|
||||
import com.rogiel.httpchannel.service.config.NullAuthenticatorConfiguration;
|
||||
import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadLimitExceededException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadLinkNotFoundException;
|
||||
import com.rogiel.httpchannel.service.exception.UploadLinkNotFoundException;
|
||||
import com.rogiel.httpchannel.service.impl.MegaUploadService.MegaUploadServiceConfiguration;
|
||||
import com.rogiel.httpchannel.util.HttpClientUtils;
|
||||
import com.rogiel.httpchannel.util.PatternUtils;
|
||||
import com.rogiel.httpchannel.util.ThreadUtils;
|
||||
import com.rogiel.httpchannel.util.htmlparser.HTMLPage;
|
||||
|
||||
/**
|
||||
* This service handles login, upload and download to MegaUpload.com.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public class MegaUploadService extends
|
||||
AbstractHttpService<MegaUploadServiceConfiguration> implements Service,
|
||||
UploadService, DownloadService, AuthenticationService {
|
||||
public class MegaUploadService extends AbstractHttpService implements Service,
|
||||
UploadService<MegaUploadUploaderConfiguration>,
|
||||
DownloadService<MegaUploadDownloaderConfiguration>,
|
||||
AuthenticationService<NullAuthenticatorConfiguration> {
|
||||
/**
|
||||
* This service ID
|
||||
*/
|
||||
@@ -98,11 +87,6 @@ public class MegaUploadService extends
|
||||
private static final Pattern LOGIN_USERNAME_PATTERN = Pattern
|
||||
.compile("flashvars\\.username = \"(.*)\";");
|
||||
|
||||
public MegaUploadService() {
|
||||
super(ServiceConfigurationHelper
|
||||
.defaultConfiguration(MegaUploadServiceConfiguration.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServiceID getID() {
|
||||
return SERVICE_ID;
|
||||
@@ -119,9 +103,21 @@ public class MegaUploadService extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uploader getUploader(String filename, long filesize,
|
||||
String description) {
|
||||
return new MegaUploadUploader(filename, filesize, description);
|
||||
public Uploader<MegaUploadUploaderConfiguration> getUploader(
|
||||
String filename, long filesize,
|
||||
MegaUploadUploaderConfiguration configuration) {
|
||||
return new MegaUploadUploader(filename, filesize, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uploader<MegaUploadUploaderConfiguration> getUploader(
|
||||
String filename, long filesize) {
|
||||
return getUploader(filename, filesize, newUploaderConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MegaUploadUploaderConfiguration newUploaderConfiguration() {
|
||||
return new MegaUploadUploaderConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -143,8 +139,19 @@ public class MegaUploadService extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public Downloader getDownloader(URL url) {
|
||||
return new MegaUploadDownloader(url);
|
||||
public Downloader<MegaUploadDownloaderConfiguration> getDownloader(URL url,
|
||||
MegaUploadDownloaderConfiguration configuration) {
|
||||
return new MegaUploadDownloader(url, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Downloader<MegaUploadDownloaderConfiguration> getDownloader(URL url) {
|
||||
return getDownloader(url, newDownloaderConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MegaUploadDownloaderConfiguration newDownloaderConfiguration() {
|
||||
return new MegaUploadDownloaderConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -156,13 +163,28 @@ public class MegaUploadService extends
|
||||
public CapabilityMatrix<DownloaderCapability> getDownloadCapabilities() {
|
||||
return new CapabilityMatrix<DownloaderCapability>(
|
||||
DownloaderCapability.UNAUTHENTICATED_DOWNLOAD,
|
||||
DownloaderCapability.UNAUTHENTICATED_RESUME,
|
||||
DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD,
|
||||
DownloaderCapability.PREMIUM_ACCOUNT_DOWNLOAD);
|
||||
DownloaderCapability.NON_PREMIUM_ACCOUNT_RESUME,
|
||||
DownloaderCapability.PREMIUM_ACCOUNT_DOWNLOAD,
|
||||
DownloaderCapability.PREMIUM_ACCOUNT_RESUME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator getAuthenticator(Credential credential) {
|
||||
return new MegaUploadAuthenticator(credential);
|
||||
public Authenticator<NullAuthenticatorConfiguration> getAuthenticator(
|
||||
Credential credential, NullAuthenticatorConfiguration configuration) {
|
||||
return new MegaUploadAuthenticator(credential, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator<NullAuthenticatorConfiguration> getAuthenticator(
|
||||
Credential credential) {
|
||||
return getAuthenticator(credential, newAuthenticatorConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NullAuthenticatorConfiguration newAuthenticatorConfiguration() {
|
||||
return NullAuthenticatorConfiguration.SHARED_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,50 +192,35 @@ public class MegaUploadService extends
|
||||
return new CapabilityMatrix<AuthenticatorCapability>();
|
||||
}
|
||||
|
||||
protected class MegaUploadUploader implements Uploader,
|
||||
protected class MegaUploadUploader extends
|
||||
AbstractUploader<MegaUploadUploaderConfiguration> implements
|
||||
Uploader<MegaUploadUploaderConfiguration>,
|
||||
LinkedUploadChannelCloseCallback {
|
||||
private final String filename;
|
||||
private final long filesize;
|
||||
private final String description;
|
||||
|
||||
private Future<String> uploadFuture;
|
||||
|
||||
public MegaUploadUploader(String filename, long filesize,
|
||||
String description) {
|
||||
this.filename = filename;
|
||||
this.filesize = filesize;
|
||||
this.description = (description != null ? description
|
||||
: configuration.getDefaultUploadDescription());
|
||||
MegaUploadUploaderConfiguration configuration) {
|
||||
super(filename, filesize, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UploadChannel upload() throws IOException {
|
||||
final HTMLPage page = getAsPage("http://www.megaupload.com/multiupload/");
|
||||
final String url = page.getFormAction(UPLOAD_URL_PATTERN);
|
||||
public UploadChannel openChannel() throws IOException {
|
||||
final HTMLPage page = get("http://www.megaupload.com/multiupload/")
|
||||
.asPage();
|
||||
final String url = page.findFormAction(UPLOAD_URL_PATTERN);
|
||||
|
||||
final LinkedUploadChannel channel = new LinkedUploadChannel(this,
|
||||
filesize, filename);
|
||||
final MultipartEntity entity = new MultipartEntity();
|
||||
|
||||
entity.addPart("multifile_0", new LinkedUploadChannelContentBody(
|
||||
channel));
|
||||
entity.addPart("multimessage_0", new StringBody(description));
|
||||
|
||||
uploadFuture = postAsStringAsync(url, entity);
|
||||
while (!channel.isLinked() && !uploadFuture.isDone()) {
|
||||
ThreadUtils.sleep(100);
|
||||
}
|
||||
return channel;
|
||||
final LinkedUploadChannel channel = createLinkedChannel(this);
|
||||
uploadFuture = multipartPost(url)
|
||||
.parameter("multimessage_0", configuration.description())
|
||||
.parameter("multifile_0", channel).asStringAsync();
|
||||
return waitChannelLink(channel, uploadFuture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String finish() throws IOException {
|
||||
try {
|
||||
String link = PatternUtils.find(DOWNLOAD_URL_PATTERN,
|
||||
return PatternUtils.find(DOWNLOAD_URL_PATTERN,
|
||||
uploadFuture.get());
|
||||
if (link == null)
|
||||
throw new UploadLinkNotFoundException();
|
||||
return link;
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
} catch (ExecutionException e) {
|
||||
@@ -222,17 +229,18 @@ public class MegaUploadService extends
|
||||
}
|
||||
}
|
||||
|
||||
protected class MegaUploadDownloader extends AbstractDownloader {
|
||||
private final URL url;
|
||||
|
||||
public MegaUploadDownloader(URL url) {
|
||||
this.url = url;
|
||||
protected class MegaUploadDownloader extends
|
||||
AbstractHttpDownloader<MegaUploadDownloaderConfiguration> implements
|
||||
Downloader<MegaUploadDownloaderConfiguration> {
|
||||
public MegaUploadDownloader(URL url,
|
||||
MegaUploadDownloaderConfiguration configuration) {
|
||||
super(url, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DownloadChannel download(DownloadListener listener, long position)
|
||||
throws IOException {
|
||||
HttpResponse response = get(url.toString());
|
||||
public DownloadChannel openChannel(DownloadListener listener,
|
||||
long position) throws IOException {
|
||||
HttpResponse response = get(url).request();
|
||||
|
||||
// disable direct downloads, we don't support them!
|
||||
if (response.getEntity().getContentType().getValue()
|
||||
@@ -240,30 +248,28 @@ public class MegaUploadService extends
|
||||
// close connection
|
||||
response.getEntity().getContent().close();
|
||||
|
||||
final List<NameValuePair> pairs = new ArrayList<NameValuePair>();
|
||||
pairs.add(new BasicNameValuePair("do", "directdownloads"));
|
||||
pairs.add(new BasicNameValuePair("accountupdate", "1"));
|
||||
pairs.add(new BasicNameValuePair("set_ddl", "0"));
|
||||
|
||||
// execute update
|
||||
postAsString("http://www.megaupload.com/?c=account",
|
||||
new UrlEncodedFormEntity(pairs));
|
||||
post("http://www.megaupload.com/?c=account")
|
||||
.parameter("do", "directdownloads")
|
||||
.parameter("accountupdate", "1")
|
||||
.parameter("set_ddl", "0").request();
|
||||
|
||||
// execute and re-request download
|
||||
response = get(url.toString());
|
||||
response = get(url).request();
|
||||
}
|
||||
|
||||
final HTMLPage page = HttpClientUtils.toPage(response);
|
||||
|
||||
// try to find timer
|
||||
int timer = page.findIntegerInScript(DOWNLOAD_TIMER, 1);
|
||||
if (timer > 0 && configuration.respectWaitTime()) {
|
||||
int timer = page.findScriptAsInt(DOWNLOAD_TIMER, 1);
|
||||
if (timer > 0 && configuration.getRespectWaitTime()) {
|
||||
timer(listener, timer * 1000);
|
||||
}
|
||||
final String downloadUrl = page
|
||||
.getLink(DOWNLOAD_DIRECT_LINK_PATTERN);
|
||||
.findLink(DOWNLOAD_DIRECT_LINK_PATTERN);
|
||||
if (downloadUrl != null && downloadUrl.length() > 0) {
|
||||
final HttpResponse downloadResponse = get(downloadUrl, position);
|
||||
final HttpResponse downloadResponse = get(downloadUrl)
|
||||
.position(position).request();
|
||||
if (downloadResponse.getStatusLine().getStatusCode() == HttpStatus.SC_FORBIDDEN
|
||||
|| downloadResponse.getStatusLine().getStatusCode() == HttpStatus.SC_SERVICE_UNAVAILABLE) {
|
||||
downloadResponse.getEntity().getContent().close();
|
||||
@@ -274,7 +280,7 @@ public class MegaUploadService extends
|
||||
final String filename = FilenameUtils.getName(downloadUrl);
|
||||
final long contentLength = getContentLength(downloadResponse);
|
||||
|
||||
return new InputStreamDownloadChannel(downloadResponse
|
||||
return createInputStreamChannel(downloadResponse
|
||||
.getEntity().getContent(), contentLength, filename);
|
||||
}
|
||||
} else {
|
||||
@@ -283,51 +289,34 @@ public class MegaUploadService extends
|
||||
}
|
||||
}
|
||||
|
||||
protected class MegaUploadAuthenticator implements Authenticator {
|
||||
private final Credential credential;
|
||||
|
||||
public MegaUploadAuthenticator(Credential credential) {
|
||||
this.credential = credential;
|
||||
protected class MegaUploadAuthenticator extends
|
||||
AbstractAuthenticator<NullAuthenticatorConfiguration> implements
|
||||
Authenticator<NullAuthenticatorConfiguration> {
|
||||
public MegaUploadAuthenticator(Credential credential,
|
||||
NullAuthenticatorConfiguration configuration) {
|
||||
super(credential, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void login() throws IOException {
|
||||
final MultipartEntity entity = new MultipartEntity();
|
||||
|
||||
entity.addPart("login", new StringBody("1"));
|
||||
entity.addPart("username", new StringBody(credential.getUsername()));
|
||||
entity.addPart("password", new StringBody(credential.getPassword()));
|
||||
|
||||
final HTMLPage page = postAsPage(
|
||||
"http://www.megaupload.com/?c=login", entity);
|
||||
String username = page.findInScript(LOGIN_USERNAME_PATTERN, 1);
|
||||
final HTMLPage page = post("http://www.megaupload.com/?c=login")
|
||||
.parameter("login", true)
|
||||
.parameter("username", credential.getUsername())
|
||||
.parameter("", credential.getPassword()).asPage();
|
||||
|
||||
String username = page.findScript(LOGIN_USERNAME_PATTERN, 1);
|
||||
if (username == null)
|
||||
throw new AuthenticationInvalidCredentialException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() throws IOException {
|
||||
final MultipartEntity entity = new MultipartEntity();
|
||||
entity.addPart("logout", new StringBody("1"));
|
||||
|
||||
postAsString("http://www.megaupload.com/?c=account", entity);
|
||||
post("http://www.megaupload.com/?c=account").parameter("logout",
|
||||
true).request();
|
||||
// TODO check logout status
|
||||
}
|
||||
}
|
||||
|
||||
public static interface MegaUploadServiceConfiguration extends
|
||||
ServiceConfiguration {
|
||||
@ServiceConfigurationProperty(key = "megaupload.wait", defaultValue = "true")
|
||||
boolean respectWaitTime();
|
||||
|
||||
@ServiceConfigurationProperty(key = "megaupload.port", defaultValue = "80")
|
||||
int getPreferedDownloadPort();
|
||||
|
||||
@ServiceConfigurationProperty(key = "megaupload.description", defaultValue = "Uploaded by seedbox-httpchannel")
|
||||
String getDefaultUploadDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getSimpleName() + " " + getMajorVersion() + "."
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.rogiel.httpchannel.service.impl;
|
||||
|
||||
import com.rogiel.httpchannel.service.Uploader.DescriptionableUploaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.Uploader.UploaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.impl.MegaUploadService.MegaUploadUploader;
|
||||
|
||||
/**
|
||||
* Describes an configuration for an {@link MegaUploadUploader}
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class MegaUploadUploaderConfiguration implements UploaderConfiguration,
|
||||
DescriptionableUploaderConfiguration {
|
||||
/**
|
||||
* The upload description
|
||||
*/
|
||||
private String description = DescriptionableUploaderConfiguration.DEFAULT_DESCRIPTION;
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MegaUploadUploaderConfiguration description(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.rogiel.httpchannel.service.Services;
|
||||
import com.rogiel.httpchannel.service.helper.Services;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
|
||||
@@ -20,10 +20,8 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
@@ -38,25 +36,18 @@ import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.rogiel.httpchannel.service.AuthenticationService;
|
||||
import com.rogiel.httpchannel.service.Credential;
|
||||
import com.rogiel.httpchannel.service.DownloadChannel;
|
||||
import com.rogiel.httpchannel.service.DownloadListener;
|
||||
import com.rogiel.httpchannel.service.DownloadService;
|
||||
import com.rogiel.httpchannel.service.Service;
|
||||
import com.rogiel.httpchannel.service.ServiceHelper;
|
||||
import com.rogiel.httpchannel.service.ServiceID;
|
||||
import com.rogiel.httpchannel.service.UploadChannel;
|
||||
import com.rogiel.httpchannel.service.UploadService;
|
||||
import com.rogiel.httpchannel.service.UploaderCapability;
|
||||
import com.rogiel.httpchannel.service.config.ServiceConfigurationHelper;
|
||||
import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException;
|
||||
import com.rogiel.httpchannel.service.impl.MegaUploadService.MegaUploadServiceConfiguration;
|
||||
import com.rogiel.httpchannel.service.helper.UploadServices;
|
||||
import com.rogiel.httpchannel.util.ChannelUtils;
|
||||
|
||||
public class MegaUploadServiceTest {
|
||||
private Service service;
|
||||
private ServiceHelper helper;
|
||||
private MegaUploadService service;
|
||||
|
||||
/**
|
||||
* See <b>src/test/resources/config/megaupload.properties</b>
|
||||
@@ -78,7 +69,6 @@ public class MegaUploadServiceTest {
|
||||
public void setUp() throws Exception {
|
||||
// MegaUploadServiceConfiguration.class;
|
||||
service = new MegaUploadService();
|
||||
helper = new ServiceHelper(service);
|
||||
|
||||
final Properties properties = new Properties();
|
||||
properties.load(new FileInputStream(
|
||||
@@ -89,19 +79,18 @@ public class MegaUploadServiceTest {
|
||||
|
||||
@Test
|
||||
public void testServiceId() {
|
||||
System.out.println("Service: " + service.toString());
|
||||
assertEquals(ServiceID.create("megaupload"), service.getID());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidAuthenticator() throws IOException {
|
||||
((AuthenticationService) service).getAuthenticator(
|
||||
new Credential(VALID_USERNAME, VALID_PASSWORD)).login();
|
||||
service.getAuthenticator(new Credential(VALID_USERNAME, VALID_PASSWORD))
|
||||
.login();
|
||||
}
|
||||
|
||||
@Test(expected = AuthenticationInvalidCredentialException.class)
|
||||
public void testInvalidAuthenticator() throws IOException {
|
||||
((AuthenticationService) service).getAuthenticator(
|
||||
service.getAuthenticator(
|
||||
new Credential(INVALID_USERNAME, INVALID_PASSWORD)).login();
|
||||
}
|
||||
|
||||
@@ -109,11 +98,11 @@ public class MegaUploadServiceTest {
|
||||
public void testNonLoguedInUploader() throws IOException {
|
||||
assertTrue(
|
||||
"This service does not have the capability UploadCapability.FREE_UPLOAD",
|
||||
((UploadService) service).getUploadCapabilities().has(
|
||||
service.getUploadCapabilities().has(
|
||||
UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD));
|
||||
final Path path = Paths.get("src/test/resources/upload-test-file.txt");
|
||||
final UploadChannel channel = helper.upload(path,
|
||||
"httpchannel test upload");
|
||||
final UploadChannel channel = UploadServices.upload(service, path)
|
||||
.openChannel();
|
||||
final SeekableByteChannel inChannel = Files.newByteChannel(path);
|
||||
|
||||
try {
|
||||
@@ -131,15 +120,15 @@ public class MegaUploadServiceTest {
|
||||
public void testLoguedInUploader() throws IOException {
|
||||
assertTrue(
|
||||
"This service does not have the capability UploadCapability.PREMIUM_UPLOAD",
|
||||
((UploadService) service).getUploadCapabilities().has(
|
||||
service.getUploadCapabilities().has(
|
||||
UploaderCapability.PREMIUM_ACCOUNT_UPLOAD));
|
||||
|
||||
((AuthenticationService) service).getAuthenticator(
|
||||
new Credential(VALID_USERNAME, VALID_PASSWORD)).login();
|
||||
service.getAuthenticator(new Credential(VALID_USERNAME, VALID_PASSWORD))
|
||||
.login();
|
||||
|
||||
final Path path = Paths.get("src/test/resources/upload-test-file.txt");
|
||||
final UploadChannel channel = helper.upload(path,
|
||||
"httpchannel test upload");
|
||||
final UploadChannel channel = UploadServices.upload(service, path)
|
||||
.openChannel();
|
||||
final SeekableByteChannel inChannel = Files.newByteChannel(path);
|
||||
|
||||
try {
|
||||
@@ -154,10 +143,10 @@ public class MegaUploadServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFreeDownloader() throws IOException, MalformedURLException {
|
||||
final DownloadChannel channel = ((DownloadService) service)
|
||||
.getDownloader(new URL("http://www.megaupload.com/?d=CVQKJ1KM"))
|
||||
.download(new DownloadListener() {
|
||||
public void testFreeDownloader() throws IOException {
|
||||
final DownloadChannel channel = service.getDownloader(
|
||||
new URL("http://www.megaupload.com/?d=CVQKJ1KM")).openChannel(
|
||||
new DownloadListener() {
|
||||
@Override
|
||||
public boolean timer(long time) {
|
||||
System.out.println("Waiting " + time);
|
||||
@@ -172,14 +161,13 @@ public class MegaUploadServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPremiumDownloader() throws IOException,
|
||||
MalformedURLException {
|
||||
((AuthenticationService) service).getAuthenticator(
|
||||
new Credential(VALID_USERNAME, VALID_PASSWORD)).login();
|
||||
public void testPremiumDownloader() throws IOException {
|
||||
service.getAuthenticator(new Credential(VALID_USERNAME, VALID_PASSWORD))
|
||||
.login();
|
||||
|
||||
final DownloadChannel channel = ((DownloadService) service)
|
||||
.getDownloader(new URL("http://www.megaupload.com/?d=CVQKJ1KM"))
|
||||
.download(new DownloadListener() {
|
||||
final DownloadChannel channel = service.getDownloader(
|
||||
new URL("http://www.megaupload.com/?d=CVQKJ1KM")).openChannel(
|
||||
new DownloadListener() {
|
||||
@Override
|
||||
public boolean timer(long time) {
|
||||
System.out.println("Waiting " + time);
|
||||
@@ -192,17 +180,18 @@ public class MegaUploadServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoWaitDownloader() throws IOException,
|
||||
MalformedURLException {
|
||||
public void testNoWaitDownloader() throws IOException {
|
||||
service = new MegaUploadService();
|
||||
service.setServiceConfiguration(ServiceConfigurationHelper.file(
|
||||
MegaUploadServiceConfiguration.class, new File(
|
||||
"src/test/resources/megaupload-nowait.properties")));
|
||||
// service.setServiceConfiguration(ServiceConfigurationHelper.file(
|
||||
// MegaUploadServiceConfiguration.class, new File(
|
||||
// "src/test/resources/megaupload-nowait.properties")));
|
||||
final MegaUploadDownloaderConfiguration config = new MegaUploadDownloaderConfiguration();
|
||||
config.setRespectWaitTime(false);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
final DownloadChannel channel = ((DownloadService) service)
|
||||
.getDownloader(new URL("http://www.megaupload.com/?d=CVQKJ1KM"))
|
||||
.download(new DownloadListener() {
|
||||
@SuppressWarnings({ "unused" })
|
||||
final DownloadChannel channel = service.getDownloader(
|
||||
new URL("http://www.megaupload.com/?d=CVQKJ1KM"), config)
|
||||
.openChannel(new DownloadListener() {
|
||||
@Override
|
||||
public boolean timer(long time) {
|
||||
System.out.println("Waiting " + time);
|
||||
|
||||
21
httpchannel-service/httpchannel-service-multiupload/pom.xml
Normal file
21
httpchannel-service/httpchannel-service-multiupload/pom.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>httpchannel-service</artifactId>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>httpchannel-service-multiupload</artifactId>
|
||||
<groupId>com.rogiel.httpchannel.services</groupId>
|
||||
<name>HttpChannel/Service/MultiUpload</name>
|
||||
<description>Provides upload access to multiupload.com</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<artifactId>httpchannel-tests</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,265 @@
|
||||
package com.rogiel.httpchannel.service.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.rogiel.httpchannel.http.PostMultipartRequest;
|
||||
import com.rogiel.httpchannel.service.AbstractAuthenticator;
|
||||
import com.rogiel.httpchannel.service.AbstractHttpDownloader;
|
||||
import com.rogiel.httpchannel.service.AbstractHttpService;
|
||||
import com.rogiel.httpchannel.service.AbstractUploader;
|
||||
import com.rogiel.httpchannel.service.AuthenticationService;
|
||||
import com.rogiel.httpchannel.service.Authenticator;
|
||||
import com.rogiel.httpchannel.service.AuthenticatorCapability;
|
||||
import com.rogiel.httpchannel.service.CapabilityMatrix;
|
||||
import com.rogiel.httpchannel.service.Credential;
|
||||
import com.rogiel.httpchannel.service.DownloadChannel;
|
||||
import com.rogiel.httpchannel.service.DownloadListener;
|
||||
import com.rogiel.httpchannel.service.DownloadService;
|
||||
import com.rogiel.httpchannel.service.Downloader;
|
||||
import com.rogiel.httpchannel.service.DownloaderCapability;
|
||||
import com.rogiel.httpchannel.service.Service;
|
||||
import com.rogiel.httpchannel.service.ServiceID;
|
||||
import com.rogiel.httpchannel.service.UploadChannel;
|
||||
import com.rogiel.httpchannel.service.UploadService;
|
||||
import com.rogiel.httpchannel.service.Uploader;
|
||||
import com.rogiel.httpchannel.service.UploaderCapability;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel.LinkedUploadChannelCloseCallback;
|
||||
import com.rogiel.httpchannel.service.config.NullAuthenticatorConfiguration;
|
||||
import com.rogiel.httpchannel.service.config.NullDownloaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadLimitExceededException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadLinkNotFoundException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadNotAuthorizedException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadNotResumableException;
|
||||
import com.rogiel.httpchannel.service.impl.MultiUploadUploaderConfiguration.MultiUploadMirrorService;
|
||||
import com.rogiel.httpchannel.util.PatternUtils;
|
||||
import com.rogiel.httpchannel.util.htmlparser.HTMLPage;
|
||||
|
||||
/**
|
||||
* This service handles uploads to MultiUpload.com.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com/">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public class MultiUploadService extends AbstractHttpService implements Service,
|
||||
UploadService<MultiUploadUploaderConfiguration>,
|
||||
DownloadService<NullDownloaderConfiguration>,
|
||||
AuthenticationService<NullAuthenticatorConfiguration> {
|
||||
/**
|
||||
* This service ID
|
||||
*/
|
||||
public static final ServiceID SERVICE_ID = ServiceID.create("multiupload");
|
||||
|
||||
// http://www52.multiupload.com/upload/?UPLOAD_IDENTIFIER=73132658610746
|
||||
private static final Pattern UPLOAD_URL_PATTERN = Pattern
|
||||
.compile("http://www([0-9]*)\\.multiupload\\.com/upload/\\?UPLOAD_IDENTIFIER=[0-9]*");
|
||||
private static final Pattern DOWNLOAD_ID_PATTERN = Pattern
|
||||
.compile("\"downloadid\":\"([0-9a-zA-Z]*)\"");
|
||||
private static final Pattern DOWNLOAD_LINK_PATTERN = Pattern
|
||||
.compile("http://(www\\.)?multiupload\\.com/([0-9a-zA-Z]*)");
|
||||
private static final Pattern DIRECT_DOWNLOAD_LINK_PATTERN = Pattern
|
||||
.compile("http://www[0-9]*\\.multiupload\\.com(:[0-9]*)?/files/([0-9a-zA-Z]*)/(.*)");
|
||||
|
||||
@Override
|
||||
public ServiceID getID() {
|
||||
return SERVICE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMajorVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinorVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uploader<MultiUploadUploaderConfiguration> getUploader(
|
||||
String filename, long filesize,
|
||||
MultiUploadUploaderConfiguration configuration) {
|
||||
if (configuration == null)
|
||||
configuration = new MultiUploadUploaderConfiguration();
|
||||
return new MultiUploadUploader(filename, filesize, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uploader<MultiUploadUploaderConfiguration> getUploader(
|
||||
String filename, long filesize) {
|
||||
return getUploader(filename, filesize, newUploaderConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiUploadUploaderConfiguration newUploaderConfiguration() {
|
||||
return new MultiUploadUploaderConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaximumFilesize() {
|
||||
return 1 * 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedExtensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CapabilityMatrix<UploaderCapability> getUploadCapabilities() {
|
||||
return new CapabilityMatrix<UploaderCapability>(
|
||||
UploaderCapability.UNAUTHENTICATED_UPLOAD,
|
||||
UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD,
|
||||
UploaderCapability.PREMIUM_ACCOUNT_UPLOAD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Downloader<NullDownloaderConfiguration> getDownloader(URL url,
|
||||
NullDownloaderConfiguration configuration) {
|
||||
return new MultiUploaderDownloader(url, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Downloader<NullDownloaderConfiguration> getDownloader(URL url) {
|
||||
return getDownloader(url, newDownloaderConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NullDownloaderConfiguration newDownloaderConfiguration() {
|
||||
return NullDownloaderConfiguration.SHARED_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchURL(URL url) {
|
||||
return DOWNLOAD_LINK_PATTERN.matcher(url.toString()).matches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CapabilityMatrix<DownloaderCapability> getDownloadCapabilities() {
|
||||
return new CapabilityMatrix<>(
|
||||
DownloaderCapability.UNAUTHENTICATED_DOWNLOAD,
|
||||
DownloaderCapability.UNAUTHENTICATED_RESUME,
|
||||
DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD,
|
||||
DownloaderCapability.NON_PREMIUM_ACCOUNT_RESUME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator<NullAuthenticatorConfiguration> getAuthenticator(
|
||||
Credential credential, NullAuthenticatorConfiguration configuration) {
|
||||
return new MultiUploadAuthenticator(credential, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator<NullAuthenticatorConfiguration> getAuthenticator(
|
||||
Credential credential) {
|
||||
return getAuthenticator(credential, newAuthenticatorConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NullAuthenticatorConfiguration newAuthenticatorConfiguration() {
|
||||
return NullAuthenticatorConfiguration.SHARED_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CapabilityMatrix<AuthenticatorCapability> getAuthenticationCapability() {
|
||||
return new CapabilityMatrix<AuthenticatorCapability>();
|
||||
}
|
||||
|
||||
protected class MultiUploadUploader extends
|
||||
AbstractUploader<MultiUploadUploaderConfiguration> implements
|
||||
Uploader<MultiUploadUploaderConfiguration>,
|
||||
LinkedUploadChannelCloseCallback {
|
||||
private Future<String> uploadFuture;
|
||||
|
||||
public MultiUploadUploader(String filename, long filesize,
|
||||
MultiUploadUploaderConfiguration configuration) {
|
||||
super(filename, filesize, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UploadChannel openChannel() throws IOException {
|
||||
final String url = get("http://www.multiupload.com/").asPage()
|
||||
.findFormAction(UPLOAD_URL_PATTERN);
|
||||
final LinkedUploadChannel channel = createLinkedChannel(this);
|
||||
|
||||
PostMultipartRequest request = multipartPost(url).parameter(
|
||||
"description_0", configuration.description()).parameter(
|
||||
"file_0", channel);
|
||||
for (final MultiUploadMirrorService mirror : configuration
|
||||
.uploadServices()) {
|
||||
request.parameter("service_" + mirror.id, 1);
|
||||
}
|
||||
|
||||
uploadFuture = request.asStringAsync();
|
||||
return waitChannelLink(channel, uploadFuture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String finish() throws IOException {
|
||||
try {
|
||||
final String linkId = PatternUtils.find(DOWNLOAD_ID_PATTERN,
|
||||
uploadFuture.get(), 1);
|
||||
if (linkId == null)
|
||||
return null;
|
||||
return new StringBuilder("http://www.multiupload.com/").append(
|
||||
linkId).toString();
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
} catch (ExecutionException e) {
|
||||
throw (IOException) e.getCause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected class MultiUploaderDownloader extends
|
||||
AbstractHttpDownloader<NullDownloaderConfiguration> implements
|
||||
Downloader<NullDownloaderConfiguration> {
|
||||
protected MultiUploaderDownloader(URL url,
|
||||
NullDownloaderConfiguration configuration) {
|
||||
super(url, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DownloadChannel openChannel(DownloadListener listener,
|
||||
long position) throws IOException,
|
||||
DownloadLinkNotFoundException, DownloadLimitExceededException,
|
||||
DownloadNotAuthorizedException, DownloadNotResumableException {
|
||||
final HTMLPage page = get(url).asPage();
|
||||
final String link = page.findLink(DIRECT_DOWNLOAD_LINK_PATTERN);
|
||||
if (link == null)
|
||||
throw new DownloadLinkNotFoundException();
|
||||
return download(get(link).position(position));
|
||||
}
|
||||
}
|
||||
|
||||
protected class MultiUploadAuthenticator extends
|
||||
AbstractAuthenticator<NullAuthenticatorConfiguration> implements
|
||||
Authenticator<NullAuthenticatorConfiguration> {
|
||||
public MultiUploadAuthenticator(Credential credential,
|
||||
NullAuthenticatorConfiguration configuration) {
|
||||
super(credential, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void login() throws IOException {
|
||||
final HTMLPage page = post("http://www.multiupload.com/login")
|
||||
.parameter("username", credential.getUsername())
|
||||
.parameter("password", credential.getPassword()).asPage();
|
||||
|
||||
if (!page.containsIgnoreCase(credential.getUsername()))
|
||||
throw new AuthenticationInvalidCredentialException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() throws IOException {
|
||||
post("http://www.multiupload.com/login").parameter("do", "logout")
|
||||
.request();
|
||||
// TODO check logout status
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.rogiel.httpchannel.service.impl;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import com.rogiel.httpchannel.service.Uploader.DescriptionableUploaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.Uploader.UploaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.impl.MultiUploadService.MultiUploadUploader;
|
||||
|
||||
/**
|
||||
* Describes an configuration for an {@link MultiUploadUploader}
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class MultiUploadUploaderConfiguration implements UploaderConfiguration,
|
||||
DescriptionableUploaderConfiguration {
|
||||
/**
|
||||
* The upload description
|
||||
*/
|
||||
private String description = DescriptionableUploaderConfiguration.DEFAULT_DESCRIPTION;
|
||||
/**
|
||||
* The services in which Multiupload should mirror the uploaded file
|
||||
*/
|
||||
private EnumSet<MultiUploadMirrorService> uploadServices = EnumSet
|
||||
.allOf(MultiUploadMirrorService.class);
|
||||
|
||||
/**
|
||||
* An enumeration containing all supported services for Multiupload
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public enum MultiUploadMirrorService {
|
||||
MEGAUPLOAD(1), UPLOADKING(16), DEPOSIT_FILES(7), HOTFILE(9), UPLOAD_HERE(
|
||||
17), ZSHARE(6), FILE_SONIC(15), FILE_SERVE(18), WUPLOAD(19);
|
||||
|
||||
/**
|
||||
* The internal multiupload id
|
||||
*/
|
||||
public final int id;
|
||||
|
||||
private MultiUploadMirrorService(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiUploadUploaderConfiguration description(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this service as an desired mirror
|
||||
*
|
||||
* @param service
|
||||
* the service
|
||||
*/
|
||||
public MultiUploadUploaderConfiguration uploadService(
|
||||
MultiUploadMirrorService... services) {
|
||||
for (final MultiUploadMirrorService service : services) {
|
||||
uploadServices.add(service);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the service is on the desired mirror list
|
||||
*
|
||||
* @param service
|
||||
* the service
|
||||
* @return <code>true</code> if the service is on the list
|
||||
*/
|
||||
public boolean containsUploadService(MultiUploadMirrorService service) {
|
||||
return uploadServices.contains(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes this service from the mirror list
|
||||
*
|
||||
* @param service
|
||||
* the service
|
||||
*/
|
||||
public MultiUploadUploaderConfiguration removeUploadService(
|
||||
MultiUploadMirrorService service) {
|
||||
uploadServices.remove(service);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all services from the mirror list
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public MultiUploadUploaderConfiguration clearUploadServices() {
|
||||
uploadServices.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the list of services of which MultiUpload should try to make
|
||||
* mirrors
|
||||
*/
|
||||
public EnumSet<MultiUploadMirrorService> uploadServices() {
|
||||
return uploadServices;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
com.rogiel.httpchannel.service.impl.MultiUploadService
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.rogiel.httpchannel.service.impl;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import com.rogiel.httpchannel.service.AbstractServiceTest;
|
||||
import com.rogiel.httpchannel.service.Credential;
|
||||
import com.rogiel.httpchannel.service.Service;
|
||||
|
||||
public class MultiUploadServiceTest extends AbstractServiceTest {
|
||||
@Override
|
||||
protected Service createService() {
|
||||
return new MultiUploadService();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URL createDownloadURL() throws MalformedURLException {
|
||||
return new URL("http://www.multiupload.com/QPDUXJDZZY");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Credential createValidCredential() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Credential createInvalidCredential() {
|
||||
return new Credential("invalid-"
|
||||
+ Double.toString(Math.random() * 1000), Double.toString(Math
|
||||
.random() * Integer.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
This is a simple upload test file.
|
||||
|
||||
This is for testing purposes only.
|
||||
13
httpchannel-service/httpchannel-service-uploadking/pom.xml
Normal file
13
httpchannel-service/httpchannel-service-uploadking/pom.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>httpchannel-service</artifactId>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>httpchannel-service-uploadking</artifactId>
|
||||
<groupId>com.rogiel.httpchannel.services</groupId>
|
||||
<name>HttpChannel/Service/UploadKing</name>
|
||||
<description>Provides upload access to uploadking.com</description>
|
||||
</project>
|
||||
@@ -0,0 +1,191 @@
|
||||
package com.rogiel.httpchannel.service.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.rogiel.httpchannel.service.AbstractAuthenticator;
|
||||
import com.rogiel.httpchannel.service.AbstractHttpService;
|
||||
import com.rogiel.httpchannel.service.AbstractUploader;
|
||||
import com.rogiel.httpchannel.service.AuthenticationService;
|
||||
import com.rogiel.httpchannel.service.Authenticator;
|
||||
import com.rogiel.httpchannel.service.AuthenticatorCapability;
|
||||
import com.rogiel.httpchannel.service.CapabilityMatrix;
|
||||
import com.rogiel.httpchannel.service.Credential;
|
||||
import com.rogiel.httpchannel.service.Service;
|
||||
import com.rogiel.httpchannel.service.ServiceID;
|
||||
import com.rogiel.httpchannel.service.UploadChannel;
|
||||
import com.rogiel.httpchannel.service.UploadService;
|
||||
import com.rogiel.httpchannel.service.Uploader;
|
||||
import com.rogiel.httpchannel.service.UploaderCapability;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel.LinkedUploadChannelCloseCallback;
|
||||
import com.rogiel.httpchannel.service.config.NullAuthenticatorConfiguration;
|
||||
import com.rogiel.httpchannel.service.config.NullUploaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException;
|
||||
import com.rogiel.httpchannel.util.PatternUtils;
|
||||
import com.rogiel.httpchannel.util.htmlparser.HTMLPage;
|
||||
|
||||
/**
|
||||
* This service handles uploads to UploadKing.com.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com/">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public class UploadKingService extends AbstractHttpService implements Service,
|
||||
UploadService<NullUploaderConfiguration>,
|
||||
AuthenticationService<NullAuthenticatorConfiguration> {
|
||||
/**
|
||||
* This service ID
|
||||
*/
|
||||
public static final ServiceID SERVICE_ID = ServiceID.create("uploadking");
|
||||
|
||||
private static final Pattern UPLOAD_URL_PATTERN = Pattern
|
||||
.compile("http://www([0-9]*)\\.uploadking\\.com/upload/\\?UPLOAD_IDENTIFIER=[0-9]*");
|
||||
private static final Pattern DOWNLOAD_ID_PATTERN = Pattern
|
||||
.compile("\"downloadid\":\"([0-9a-zA-Z]*)\"");
|
||||
|
||||
private static final String INVALID_LOGIN_STRING = "Incorrect username and/or password. Please try again!";
|
||||
|
||||
@Override
|
||||
public ServiceID getID() {
|
||||
return SERVICE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMajorVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinorVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uploader<NullUploaderConfiguration> getUploader(String filename,
|
||||
long filesize, NullUploaderConfiguration configuration) {
|
||||
return new UploadKingUploader(filename, filesize, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uploader<NullUploaderConfiguration> getUploader(String filename,
|
||||
long filesize) {
|
||||
return getUploader(filename, filesize, newUploaderConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NullUploaderConfiguration newUploaderConfiguration() {
|
||||
return NullUploaderConfiguration.SHARED_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaximumFilesize() {
|
||||
return 1 * 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedExtensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CapabilityMatrix<UploaderCapability> getUploadCapabilities() {
|
||||
return new CapabilityMatrix<UploaderCapability>(
|
||||
UploaderCapability.UNAUTHENTICATED_UPLOAD,
|
||||
UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD,
|
||||
UploaderCapability.PREMIUM_ACCOUNT_UPLOAD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator<NullAuthenticatorConfiguration> getAuthenticator(
|
||||
Credential credential, NullAuthenticatorConfiguration configuration) {
|
||||
return new UploadKingAuthenticator(credential, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator<NullAuthenticatorConfiguration> getAuthenticator(
|
||||
Credential credential) {
|
||||
return getAuthenticator(credential, newAuthenticatorConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NullAuthenticatorConfiguration newAuthenticatorConfiguration() {
|
||||
return NullAuthenticatorConfiguration.SHARED_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CapabilityMatrix<AuthenticatorCapability> getAuthenticationCapability() {
|
||||
return new CapabilityMatrix<AuthenticatorCapability>();
|
||||
}
|
||||
|
||||
protected class UploadKingUploader extends
|
||||
AbstractUploader<NullUploaderConfiguration> implements
|
||||
Uploader<NullUploaderConfiguration>,
|
||||
LinkedUploadChannelCloseCallback {
|
||||
private Future<String> uploadFuture;
|
||||
|
||||
public UploadKingUploader(String filename, long filesize,
|
||||
NullUploaderConfiguration configuration) {
|
||||
super(filename, filesize, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UploadChannel openChannel() throws IOException {
|
||||
final HTMLPage page = get("http://www.uploadking.com/").asPage();
|
||||
|
||||
final String userCookie = page.getInputValueById("usercookie");
|
||||
final String url = page.findFormAction(UPLOAD_URL_PATTERN);
|
||||
final String uploadID = page.getInputValue("UPLOAD_IDENTIFIER");
|
||||
|
||||
final LinkedUploadChannel channel = createLinkedChannel(this);
|
||||
uploadFuture = multipartPost(url).parameter("file_0", channel)
|
||||
.parameter("u", userCookie)
|
||||
.parameter("UPLOAD_IDENTIFIER", uploadID).asStringAsync();
|
||||
return waitChannelLink(channel, uploadFuture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String finish() throws IOException {
|
||||
try {
|
||||
final String linkId = PatternUtils.find(DOWNLOAD_ID_PATTERN,
|
||||
uploadFuture.get(), 1);
|
||||
if (linkId == null)
|
||||
return null;
|
||||
return new StringBuilder("http://www.uploadking.com/").append(
|
||||
linkId).toString();
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
} catch (ExecutionException e) {
|
||||
throw (IOException) e.getCause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected class UploadKingAuthenticator extends
|
||||
AbstractAuthenticator<NullAuthenticatorConfiguration> implements
|
||||
Authenticator<NullAuthenticatorConfiguration> {
|
||||
public UploadKingAuthenticator(Credential credential,
|
||||
NullAuthenticatorConfiguration configuration) {
|
||||
super(credential, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void login() throws IOException {
|
||||
final HTMLPage page = post("http://www.uploadking.com/login")
|
||||
.parameter("do", "login")
|
||||
.parameter("username", credential.getUsername())
|
||||
.parameter("password", credential.getPassword()).asPage();
|
||||
if (page.contains(INVALID_LOGIN_STRING))
|
||||
throw new AuthenticationInvalidCredentialException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() throws IOException {
|
||||
post("http://www.uploadking.com/login").parameter("do", "logout")
|
||||
.request();
|
||||
// TODO check logout status
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
com.rogiel.httpchannel.service.impl.MultiUploadService
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.rogiel.httpchannel.service.impl;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.rogiel.httpchannel.service.UploaderCapability;
|
||||
import com.rogiel.httpchannel.util.ChannelUtils;
|
||||
|
||||
public class UploadKingServiceTest {
|
||||
private UploadKingService service;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
service = new UploadKingService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonLoguedInUploader() throws IOException {
|
||||
assertTrue(
|
||||
"This service does not have the capability UploadCapability.UNAUTHENTICATED_UPLOAD",
|
||||
service.getUploadCapabilities().has(
|
||||
UploaderCapability.UNAUTHENTICATED_UPLOAD));
|
||||
|
||||
final Path path = Paths.get("src/test/resources/upload-test-file.txt");
|
||||
final URL url = ChannelUtils.upload(service, path);
|
||||
|
||||
Assert.assertNotNull(url);
|
||||
System.out.println(url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
This is a simple upload test file.
|
||||
|
||||
This is for testing purposes only.
|
||||
@@ -13,6 +13,7 @@
|
||||
<modules>
|
||||
<module>httpchannel-service-megaupload</module>
|
||||
<module>httpchannel-service-hotfile</module>
|
||||
<module>httpchannel-service-multiupload</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
@@ -27,4 +28,6 @@
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<name>HttpChannel/Service</name>
|
||||
<description>Parent module that all service implementations should inherit</description>
|
||||
</project>
|
||||
24
httpchannel-tests/pom.xml
Normal file
24
httpchannel-tests/pom.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>httpchannel</artifactId>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>httpchannel-tests</artifactId>
|
||||
<name>HttpChannel/Tests</name>
|
||||
<description>This module contains several test utilities</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<artifactId>httpchannel-api</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.rogiel.httpchannel</groupId>
|
||||
<artifactId>httpchannel-util</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException;
|
||||
import com.rogiel.httpchannel.util.ChannelUtils;
|
||||
import com.rogiel.httpchannel.util.ChecksumUtils;
|
||||
|
||||
public abstract class AbstractServiceTest {
|
||||
public static final Path TEST_UPLOAD_FILE = Paths
|
||||
.get("src/main/resources/upload-test-file.txt");
|
||||
public static final byte[] EXPECTED_FULL_CHECKSUM = new byte[] { 27, -93,
|
||||
-76, 6, 123, -31, -9, 1, -100, 103, 123, -108, -22, -3, 121, -54,
|
||||
-127, 27, 43, -8 };
|
||||
public static final byte[] EXPECTED_RESUME_CHECKSUM = new byte[] { 39, -29,
|
||||
-107, -76, -69, -122, -20, 78, -27, -60, 95, -23, 70, -127, -17,
|
||||
101, -39, -87, -2, -67 };
|
||||
|
||||
private Service service;
|
||||
|
||||
private URL downloadURL;
|
||||
|
||||
private Credential validCredential;
|
||||
private Credential invalidCredential;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.service = createService();
|
||||
downloadURL = createDownloadURL();
|
||||
validCredential = createValidCredential();
|
||||
invalidCredential = createInvalidCredential();
|
||||
}
|
||||
|
||||
protected abstract Service createService();
|
||||
|
||||
protected Credential createValidCredential() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Credential createInvalidCredential() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected URL createDownloadURL() throws MalformedURLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnauthenticatedUpload() throws IOException {
|
||||
if (!(service instanceof UploadService))
|
||||
return;
|
||||
assertTrue(
|
||||
"This service does not have the capability UploadCapability.UNAUTHENTICATED_UPLOAD",
|
||||
((UploadService<?>) service).getUploadCapabilities().has(
|
||||
UploaderCapability.UNAUTHENTICATED_UPLOAD));
|
||||
|
||||
final URL url = ChannelUtils.upload((UploadService<?>) service,
|
||||
TEST_UPLOAD_FILE);
|
||||
|
||||
Assert.assertNotNull(url);
|
||||
System.out.println("Uploaded file to " + url);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticatedUpload() throws IOException {
|
||||
if (validCredential == null)
|
||||
return;
|
||||
if (!(service instanceof UploadService))
|
||||
return;
|
||||
if (!(service instanceof AuthenticationService))
|
||||
fail("The servide does not support authentication!");
|
||||
|
||||
assertTrue(
|
||||
"This service does not have the capability UploadCapability.NON_PREMIUM_ACCOUNT_UPLOAD",
|
||||
((UploadService<?>) service).getUploadCapabilities().has(
|
||||
UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD));
|
||||
|
||||
((AuthenticationService<?>) service).getAuthenticator(validCredential)
|
||||
.login();
|
||||
|
||||
final URL url = ChannelUtils.upload((UploadService<?>) service,
|
||||
TEST_UPLOAD_FILE);
|
||||
|
||||
Assert.assertNotNull(url);
|
||||
System.out.println("Uploaded file to " + url);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnauthenticatedDownload() throws IOException,
|
||||
NoSuchAlgorithmException {
|
||||
if (!(service instanceof DownloadService))
|
||||
return;
|
||||
assertTrue(
|
||||
"This service does not have the capability DownloaderCapability.UNAUTHENTICATED_DOWNLOAD",
|
||||
((DownloadService<?>) service).getDownloadCapabilities().has(
|
||||
DownloaderCapability.UNAUTHENTICATED_DOWNLOAD));
|
||||
|
||||
final byte[] data = ChannelUtils
|
||||
.toByteArray(((DownloadService<?>) service).getDownloader(
|
||||
downloadURL).openChannel());
|
||||
ChecksumUtils.assertChecksum(
|
||||
"Downloaded data checksum did not matched", "SHA1", data,
|
||||
EXPECTED_FULL_CHECKSUM);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnauthenticatedDownloadResume() throws IOException,
|
||||
NoSuchAlgorithmException {
|
||||
if (!(service instanceof DownloadService))
|
||||
return;
|
||||
if (!((DownloadService<?>) service).getDownloadCapabilities().has(
|
||||
DownloaderCapability.UNAUTHENTICATED_RESUME))
|
||||
return;
|
||||
|
||||
assertTrue(
|
||||
"This service does not have the capability DownloaderCapability.UNAUTHENTICATED_DOWNLOAD",
|
||||
((DownloadService<?>) service).getDownloadCapabilities().has(
|
||||
DownloaderCapability.UNAUTHENTICATED_DOWNLOAD));
|
||||
|
||||
final byte[] data = ChannelUtils
|
||||
.toByteArray(((DownloadService<?>) service).getDownloader(
|
||||
downloadURL).openChannel(50));
|
||||
ChecksumUtils.assertChecksum(
|
||||
"Downloaded data checksum did not matched", "SHA1", data,
|
||||
EXPECTED_RESUME_CHECKSUM);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticatedDownload() throws IOException,
|
||||
NoSuchAlgorithmException {
|
||||
if (validCredential == null)
|
||||
return;
|
||||
if (!(service instanceof DownloadService))
|
||||
return;
|
||||
if (!(service instanceof AuthenticationService))
|
||||
fail("The service does not support authentication!");
|
||||
|
||||
assertTrue(
|
||||
"This service does not have the capability DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD",
|
||||
((DownloadService<?>) service).getDownloadCapabilities().has(
|
||||
DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD));
|
||||
|
||||
((AuthenticationService<?>) service).getAuthenticator(validCredential)
|
||||
.login();
|
||||
|
||||
final byte[] data = ChannelUtils
|
||||
.toByteArray(((DownloadService<?>) service).getDownloader(
|
||||
downloadURL).openChannel());
|
||||
ChecksumUtils.assertChecksum(
|
||||
"Downloaded data checksum did not matched", "SHA1", data,
|
||||
EXPECTED_FULL_CHECKSUM);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticatedDownloadResume() throws IOException,
|
||||
NoSuchAlgorithmException {
|
||||
if (validCredential == null)
|
||||
return;
|
||||
if (!(service instanceof DownloadService))
|
||||
return;
|
||||
if (!(service instanceof AuthenticationService))
|
||||
fail("The service does not support authentication!");
|
||||
if (!((DownloadService<?>) service).getDownloadCapabilities().has(
|
||||
DownloaderCapability.NON_PREMIUM_ACCOUNT_RESUME))
|
||||
return;
|
||||
|
||||
assertTrue(
|
||||
"This service does not have the capability DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD",
|
||||
((DownloadService<?>) service).getDownloadCapabilities().has(
|
||||
DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD));
|
||||
|
||||
((AuthenticationService<?>) service).getAuthenticator(validCredential)
|
||||
.login();
|
||||
|
||||
final byte[] data = ChannelUtils
|
||||
.toByteArray(((DownloadService<?>) service).getDownloader(
|
||||
downloadURL).openChannel(50));
|
||||
ChecksumUtils.assertChecksum(
|
||||
"Downloaded data checksum did not matched", "SHA1", data,
|
||||
EXPECTED_RESUME_CHECKSUM);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticatorWithValidCredential() throws IOException {
|
||||
if (validCredential == null)
|
||||
return;
|
||||
if (!(service instanceof AuthenticationService))
|
||||
return;
|
||||
|
||||
((AuthenticationService<?>) service).getAuthenticator(validCredential)
|
||||
.login();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticatorWithInvalidCredential() throws IOException {
|
||||
if (invalidCredential == null)
|
||||
return;
|
||||
if (!(service instanceof AuthenticationService))
|
||||
return;
|
||||
try {
|
||||
((AuthenticationService<?>) service).getAuthenticator(
|
||||
invalidCredential).login();
|
||||
} catch (AuthenticationInvalidCredentialException e) {
|
||||
return;
|
||||
}
|
||||
fail("This login attept should have failed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.rogiel.httpchannel.util;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
public class ChecksumUtils {
|
||||
public static void assertChecksum(String message, String algorithm,
|
||||
byte[] data, byte[] expected) throws NoSuchAlgorithmException {
|
||||
final MessageDigest md = MessageDigest.getInstance(algorithm);
|
||||
final byte[] actual = md.digest(data);
|
||||
Assert.assertArrayEquals(message, expected, actual);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
This is a simple upload test file.
|
||||
|
||||
This is for testing purposes only.
|
||||
@@ -59,8 +59,8 @@
|
||||
<groupId>org.htmlparser</groupId>
|
||||
<artifactId>htmlparser</artifactId>
|
||||
<version>2.1</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<name>HttpChannel/Service/Utilities</name>
|
||||
<description>Module providing several utilities to service implementations. Though this module is not required to implement services, it contains several shortcuts that can help implementing services.</description>
|
||||
</project>
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.captcha;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractImageCaptcha implements ImageCaptcha {
|
||||
private final URL imageURL;
|
||||
private final String ID;
|
||||
|
||||
private String answer;
|
||||
private boolean automaticallyResolved;
|
||||
|
||||
public AbstractImageCaptcha(URL imageURL, String ID) {
|
||||
this.imageURL = imageURL;
|
||||
this.ID = ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnswer(String answer) {
|
||||
this.answer = answer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAnswer() {
|
||||
return answer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wasAutomaticallyResolved() {
|
||||
return automaticallyResolved;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getImageURL() {
|
||||
return imageURL;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.captcha;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
import com.rogiel.httpchannel.http.GetRequest;
|
||||
import com.rogiel.httpchannel.http.HttpContext;
|
||||
import com.rogiel.httpchannel.http.PostMultipartRequest;
|
||||
import com.rogiel.httpchannel.http.PostRequest;
|
||||
import com.rogiel.httpchannel.util.htmlparser.HTMLPage;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractImageCaptchaService<C extends AbstractImageCaptcha>
|
||||
implements ImageCaptchaService<C> {
|
||||
protected final HttpContext http = new HttpContext();
|
||||
|
||||
@Override
|
||||
public final C create(String html) {
|
||||
try {
|
||||
return create(HTMLPage.parse(html));
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract C create(HTMLPage page) throws IOException;
|
||||
|
||||
@Override
|
||||
public boolean resolve(C captcha) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public GetRequest get(String url) {
|
||||
return http.get(url);
|
||||
}
|
||||
|
||||
public GetRequest get(URL url) {
|
||||
return http.get(url);
|
||||
}
|
||||
|
||||
public PostRequest post(String url) {
|
||||
return http.post(url);
|
||||
}
|
||||
|
||||
public PostMultipartRequest multipartPost(String url) {
|
||||
return http.multipartPost(url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.http;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
|
||||
public class GetRequest extends Request {
|
||||
private long position = 0;
|
||||
|
||||
public GetRequest(HttpContext ctx, String url) {
|
||||
super(ctx, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse request() throws IOException {
|
||||
final HttpGet get = new HttpGet(url);
|
||||
if (position > 0)
|
||||
get.addHeader("Range", "bytes=" + position + "-");
|
||||
return ctx.client.execute(get);
|
||||
}
|
||||
|
||||
public GetRequest position(long position) {
|
||||
this.position = position;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public class HttpContext {
|
||||
protected final ExecutorService threadPool = Executors
|
||||
.newCachedThreadPool();
|
||||
/**
|
||||
* The {@link HttpClient} instance for this service
|
||||
*/
|
||||
protected DefaultHttpClient client = new DefaultHttpClient();
|
||||
|
||||
public GetRequest get(String url) {
|
||||
return new GetRequest(this, url);
|
||||
}
|
||||
|
||||
public GetRequest get(URL url) {
|
||||
return get(url.toString());
|
||||
}
|
||||
|
||||
public PostRequest post(String url) {
|
||||
return new PostRequest(this, url);
|
||||
}
|
||||
|
||||
public PostMultipartRequest multipartPost(String url) {
|
||||
return new PostMultipartRequest(this, url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.mime.MultipartEntity;
|
||||
import org.apache.http.entity.mime.content.ContentBody;
|
||||
import org.apache.http.entity.mime.content.StringBody;
|
||||
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannelContentBody;
|
||||
|
||||
public class PostMultipartRequest extends PostRequest {
|
||||
private final MultipartEntity entity;
|
||||
|
||||
public PostMultipartRequest(HttpContext ctx, String url) {
|
||||
super(ctx, url);
|
||||
this.entity = new MultipartEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse request() throws IOException {
|
||||
final HttpPost post = new HttpPost(url);
|
||||
post.setEntity(entity);
|
||||
return ctx.client.execute(post);
|
||||
}
|
||||
|
||||
public PostMultipartRequest parameter(String name, ContentBody body) {
|
||||
entity.addPart(name, body);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PostMultipartRequest parameter(String name, String value)
|
||||
throws UnsupportedEncodingException {
|
||||
return parameter(name, new StringBody(value));
|
||||
}
|
||||
|
||||
public PostMultipartRequest parameter(String name,
|
||||
LinkedUploadChannel channel) {
|
||||
return parameter(name, new LinkedUploadChannelContentBody(channel));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
|
||||
public class PostRequest extends Request {
|
||||
protected final List<NameValuePair> params = new ArrayList<NameValuePair>();
|
||||
|
||||
public PostRequest(HttpContext ctx, String url) {
|
||||
super(ctx, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse request() throws IOException {
|
||||
final HttpPost post = new HttpPost(url);
|
||||
post.setEntity(new UrlEncodedFormEntity(params));
|
||||
return ctx.client.execute(post);
|
||||
}
|
||||
|
||||
public PostRequest parameter(String name, String value)
|
||||
throws UnsupportedEncodingException {
|
||||
params.add(new BasicNameValuePair(name, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public PostRequest parameter(String name, int value)
|
||||
throws UnsupportedEncodingException {
|
||||
return parameter(name, Integer.toString(value));
|
||||
}
|
||||
|
||||
public PostRequest parameter(String name, boolean value)
|
||||
throws UnsupportedEncodingException {
|
||||
return parameter(name, (value ? "1" : "0"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.rogiel.httpchannel.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
|
||||
import com.rogiel.httpchannel.util.HttpClientUtils;
|
||||
import com.rogiel.httpchannel.util.htmlparser.HTMLPage;
|
||||
|
||||
public abstract class Request {
|
||||
protected final HttpContext ctx;
|
||||
protected final String url;
|
||||
|
||||
public Request(HttpContext ctx, String url) {
|
||||
this.ctx = ctx;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public abstract HttpResponse request() throws IOException;
|
||||
|
||||
public Future<HttpResponse> requestAsync() throws IOException {
|
||||
return ctx.threadPool.submit(new Callable<HttpResponse>() {
|
||||
@Override
|
||||
public HttpResponse call() throws Exception {
|
||||
return request();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public String asString() throws ClientProtocolException, IOException {
|
||||
return HttpClientUtils.toString(request());
|
||||
}
|
||||
|
||||
public Future<String> asStringAsync() throws IOException {
|
||||
return ctx.threadPool.submit(new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
return asString();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public HTMLPage asPage() throws ClientProtocolException, IOException {
|
||||
return HTMLPage.parse(asString());
|
||||
}
|
||||
|
||||
public Future<HTMLPage> asPageAsync() throws IOException {
|
||||
return ctx.threadPool.submit(new Callable<HTMLPage>() {
|
||||
@Override
|
||||
public HTMLPage call() throws Exception {
|
||||
return asPage();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public String getURL() {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.rogiel.httpchannel.service;
|
||||
|
||||
import com.rogiel.httpchannel.service.Authenticator.AuthenticatorConfiguration;
|
||||
|
||||
/**
|
||||
* An abstract {@link Authenticator} that implements most of the general-purpose
|
||||
* methods
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <C>
|
||||
* the {@link Authenticator} configuration object type
|
||||
*/
|
||||
public abstract class AbstractAuthenticator<C extends AuthenticatorConfiguration>
|
||||
implements Authenticator<C> {
|
||||
protected final Credential credential;
|
||||
/**
|
||||
* The {@link Authenticator} configuration
|
||||
*/
|
||||
protected final C configuration;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param credential
|
||||
* the authentication credential
|
||||
* @param configuration
|
||||
* the configuration object
|
||||
*/
|
||||
protected AbstractAuthenticator(Credential credential, C configuration) {
|
||||
this.credential = credential;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public C getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +1,79 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import com.rogiel.httpchannel.util.ThreadUtils;
|
||||
import com.rogiel.httpchannel.service.Downloader.DownloaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.channel.InputStreamDownloadChannel;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadLimitExceededException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadLinkNotFoundException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadNotAuthorizedException;
|
||||
import com.rogiel.httpchannel.service.exception.DownloadNotResumableException;
|
||||
|
||||
/**
|
||||
* @author rogiel
|
||||
* An abstract {@link Downloader} that implements most of the general-purpose
|
||||
* methods
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <C>
|
||||
* the {@link Downloader} configuration object type
|
||||
*/
|
||||
public abstract class AbstractDownloader implements Downloader {
|
||||
protected int parseTimer(String stringTimer) {
|
||||
int timer = 0;
|
||||
if (stringTimer != null && stringTimer.length() > 0) {
|
||||
timer = Integer.parseInt(stringTimer);
|
||||
}
|
||||
return timer;
|
||||
public abstract class AbstractDownloader<C extends DownloaderConfiguration>
|
||||
implements Downloader<C> {
|
||||
/**
|
||||
* The download URL
|
||||
*/
|
||||
protected final URL url;
|
||||
|
||||
/**
|
||||
* The {@link Downloader} configuration
|
||||
*/
|
||||
protected final C configuration;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param url
|
||||
* the download url
|
||||
* @param configuration
|
||||
* the configuration object
|
||||
*/
|
||||
protected AbstractDownloader(URL url, C configuration) {
|
||||
this.url = url;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
protected long getContentLength(HttpResponse response) {
|
||||
final Header contentLengthHeader = response
|
||||
.getFirstHeader("Content-Length");
|
||||
long contentLength = -1;
|
||||
if (contentLengthHeader != null) {
|
||||
contentLength = Long.valueOf(contentLengthHeader.getValue());
|
||||
}
|
||||
return contentLength;
|
||||
@Override
|
||||
public DownloadChannel openChannel(long position) throws IOException,
|
||||
DownloadLinkNotFoundException, DownloadLimitExceededException,
|
||||
DownloadNotAuthorizedException, DownloadNotResumableException {
|
||||
return openChannel(null, position);
|
||||
}
|
||||
|
||||
protected void timer(DownloadListener listener, long timer) {
|
||||
if (listener != null) {
|
||||
listener.timer(timer);
|
||||
}
|
||||
ThreadUtils.sleep(timer);
|
||||
@Override
|
||||
public DownloadChannel openChannel(DownloadListener listener)
|
||||
throws IOException, DownloadLinkNotFoundException,
|
||||
DownloadLimitExceededException, DownloadNotAuthorizedException,
|
||||
DownloadNotResumableException {
|
||||
return openChannel(listener, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DownloadChannel openChannel() throws IOException,
|
||||
DownloadLinkNotFoundException, DownloadLimitExceededException,
|
||||
DownloadNotAuthorizedException, DownloadNotResumableException {
|
||||
return openChannel(null, 0);
|
||||
}
|
||||
|
||||
protected InputStreamDownloadChannel createInputStreamChannel(
|
||||
InputStream in, long length, String filename) {
|
||||
return new InputStreamDownloadChannel(in, length, filename);
|
||||
}
|
||||
|
||||
@Override
|
||||
public C getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file is part of seedbox <github.com/seedbox>.
|
||||
*
|
||||
* seedbox 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.
|
||||
*
|
||||
* seedbox 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 seedbox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rogiel.httpchannel.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpResponse;
|
||||
|
||||
import com.rogiel.httpchannel.http.Request;
|
||||
import com.rogiel.httpchannel.service.Downloader.DownloaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.channel.InputStreamDownloadChannel;
|
||||
import com.rogiel.httpchannel.util.ThreadUtils;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public abstract class AbstractHttpDownloader<C extends DownloaderConfiguration>
|
||||
extends AbstractDownloader<C> implements Downloader<C> {
|
||||
protected AbstractHttpDownloader(URL url, C configuration) {
|
||||
super(url, configuration);
|
||||
}
|
||||
|
||||
protected long getContentLength(HttpResponse response) {
|
||||
final Header contentLengthHeader = response
|
||||
.getFirstHeader("Content-Length");
|
||||
long contentLength = -1;
|
||||
if (contentLengthHeader != null) {
|
||||
contentLength = Long.valueOf(contentLengthHeader.getValue());
|
||||
}
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
protected void timer(DownloadListener listener, long timer) {
|
||||
if (listener != null) {
|
||||
if (!listener.timer(timer))
|
||||
return;
|
||||
}
|
||||
ThreadUtils.sleep(timer);
|
||||
}
|
||||
|
||||
protected InputStreamDownloadChannel download(Request request)
|
||||
throws IOException {
|
||||
final HttpResponse response = request.request();
|
||||
final String filename = FilenameUtils.getName(request.getURL());
|
||||
final long contentLength = getContentLength(response);
|
||||
return createInputStreamChannel(response.getEntity().getContent(),
|
||||
contentLength, filename);
|
||||
}
|
||||
}
|
||||
@@ -16,151 +16,47 @@
|
||||
*/
|
||||
package com.rogiel.httpchannel.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
|
||||
import com.rogiel.httpchannel.service.captcha.CaptchaResolver;
|
||||
import com.rogiel.httpchannel.service.config.ServiceConfiguration;
|
||||
import com.rogiel.httpchannel.util.AlwaysRedirectStrategy;
|
||||
import com.rogiel.httpchannel.util.HttpClientUtils;
|
||||
import com.rogiel.httpchannel.util.htmlparser.HTMLPage;
|
||||
import com.rogiel.httpchannel.http.GetRequest;
|
||||
import com.rogiel.httpchannel.http.HttpContext;
|
||||
import com.rogiel.httpchannel.http.PostMultipartRequest;
|
||||
import com.rogiel.httpchannel.http.PostRequest;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel;
|
||||
import com.rogiel.httpchannel.util.ThreadUtils;
|
||||
|
||||
/**
|
||||
* Abstract base service for HTTP enabled services.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public abstract class AbstractHttpService<T extends ServiceConfiguration>
|
||||
extends AbstractService<T> implements Service {
|
||||
private static final ExecutorService threadPool = Executors
|
||||
.newCachedThreadPool();
|
||||
public abstract class AbstractHttpService extends AbstractService implements
|
||||
Service {
|
||||
protected final HttpContext http = new HttpContext();
|
||||
|
||||
/**
|
||||
* The {@link HttpClient} instance for this service
|
||||
*/
|
||||
protected DefaultHttpClient client = new DefaultHttpClient();
|
||||
|
||||
/**
|
||||
* The captcha resolver
|
||||
*/
|
||||
protected CaptchaResolver captchaResolver;
|
||||
|
||||
protected AbstractHttpService(T configuration) {
|
||||
super(configuration);
|
||||
client.setRedirectStrategy(new AlwaysRedirectStrategy());
|
||||
// client.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS,
|
||||
// true);
|
||||
// client.getParams().setIntParameter(ClientPNames.MAX_REDIRECTS, 10);
|
||||
// client.setRedirectStrategy(new DefaultRedirectStrategy());
|
||||
protected LinkedUploadChannel waitChannelLink(LinkedUploadChannel channel,
|
||||
Future<?> future) {
|
||||
while (!channel.isLinked() && !future.isDone()) {
|
||||
ThreadUtils.sleep(100);
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
protected HttpResponse get(String url) throws ClientProtocolException,
|
||||
IOException {
|
||||
final HttpGet request = new HttpGet(url);
|
||||
return client.execute(request);
|
||||
public GetRequest get(String url) {
|
||||
return http.get(url);
|
||||
}
|
||||
|
||||
protected HttpResponse get(String url, long rangeStart)
|
||||
throws ClientProtocolException, IOException {
|
||||
final HttpGet request = new HttpGet(url);
|
||||
if (rangeStart >= 0)
|
||||
request.addHeader("Range", "bytes=" + rangeStart + "-");
|
||||
return client.execute(request);
|
||||
public GetRequest get(URL url) {
|
||||
return http.get(url);
|
||||
}
|
||||
|
||||
protected String getAsString(String url) throws ClientProtocolException,
|
||||
IOException {
|
||||
return HttpClientUtils.toString(get(url));
|
||||
public PostRequest post(String url) {
|
||||
return http.post(url);
|
||||
}
|
||||
|
||||
protected HTMLPage getAsPage(String url) throws ClientProtocolException,
|
||||
IOException {
|
||||
return HTMLPage.parse(getAsString(url));
|
||||
}
|
||||
|
||||
public Future<HttpResponse> getAsync(final String url) throws IOException {
|
||||
return threadPool.submit(new Callable<HttpResponse>() {
|
||||
@Override
|
||||
public HttpResponse call() throws Exception {
|
||||
return get(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Future<String> getAsStringAsync(final String url) throws IOException {
|
||||
return threadPool.submit(new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
return getAsString(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Future<HTMLPage> getAsPageAsync(final String url) throws IOException {
|
||||
return threadPool.submit(new Callable<HTMLPage>() {
|
||||
@Override
|
||||
public HTMLPage call() throws Exception {
|
||||
return getAsPage(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected HttpResponse post(String url, HttpEntity entity)
|
||||
throws ClientProtocolException, IOException {
|
||||
final HttpPost request = new HttpPost(url);
|
||||
request.setEntity(entity);
|
||||
return client.execute(request);
|
||||
}
|
||||
|
||||
protected String postAsString(String url, HttpEntity entity)
|
||||
throws ClientProtocolException, IOException {
|
||||
return HttpClientUtils.toString(post(url, entity));
|
||||
}
|
||||
|
||||
protected HTMLPage postAsPage(String url, HttpEntity entity)
|
||||
throws ClientProtocolException, IOException {
|
||||
return HTMLPage.parse(postAsString(url, entity));
|
||||
}
|
||||
|
||||
protected Future<HttpResponse> postAsync(final String url,
|
||||
final HttpEntity entity) throws IOException {
|
||||
return threadPool.submit(new Callable<HttpResponse>() {
|
||||
@Override
|
||||
public HttpResponse call() throws Exception {
|
||||
return post(url, entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected Future<String> postAsStringAsync(final String url,
|
||||
final HttpEntity entity) throws IOException {
|
||||
return threadPool.submit(new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
return postAsString(url, entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected Future<HTMLPage> postAsPageAsync(final String url,
|
||||
final HttpEntity entity) throws IOException {
|
||||
return threadPool.submit(new Callable<HTMLPage>() {
|
||||
@Override
|
||||
public HTMLPage call() throws Exception {
|
||||
return postAsPage(url, entity);
|
||||
}
|
||||
});
|
||||
public PostMultipartRequest multipartPost(String url) {
|
||||
return http.multipartPost(url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.rogiel.httpchannel.service;
|
||||
|
||||
import com.rogiel.httpchannel.service.Uploader.UploaderConfiguration;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel;
|
||||
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel.LinkedUploadChannelCloseCallback;
|
||||
|
||||
/**
|
||||
* An abstract {@link Uploader} that implements most of the general-purpose
|
||||
* methods
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <C>
|
||||
* the {@link Uploader} configuration object type
|
||||
*/
|
||||
public abstract class AbstractUploader<C extends UploaderConfiguration>
|
||||
implements Uploader<C> {
|
||||
protected final String filename;
|
||||
protected final long filesize;
|
||||
|
||||
/**
|
||||
* The {@link Uploader} configuration
|
||||
*/
|
||||
protected final C configuration;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param filename
|
||||
* the file name
|
||||
* @param filesize
|
||||
* the file size
|
||||
* @param configuration
|
||||
* the configuration object
|
||||
*/
|
||||
public AbstractUploader(String filename, long filesize, C configuration) {
|
||||
this.filename = filename;
|
||||
this.filesize = filesize;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new linked channel
|
||||
*
|
||||
* @param closeCallback
|
||||
* the close callback
|
||||
* @return a newly created {@link LinkedUploadChannel}
|
||||
*/
|
||||
protected LinkedUploadChannel createLinkedChannel(
|
||||
LinkedUploadChannelCloseCallback closeCallback) {
|
||||
return new LinkedUploadChannel(closeCallback, filesize, filename);
|
||||
}
|
||||
|
||||
@Override
|
||||
public C getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,12 @@
|
||||
package com.rogiel.httpchannel.service.channel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
import com.rogiel.httpchannel.service.UploadChannel;
|
||||
|
||||
import com.rogiel.httpchannel.service.exception.UploadLinkNotFoundException;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
@@ -33,7 +34,7 @@ public class LinkedUploadChannel implements UploadChannel {
|
||||
|
||||
private final long length;
|
||||
private final String filename;
|
||||
private String downloadLink;
|
||||
private URL downloadLink;
|
||||
|
||||
private boolean open = true;
|
||||
|
||||
@@ -59,7 +60,10 @@ public class LinkedUploadChannel implements UploadChannel {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
open = false;
|
||||
downloadLink = closeCallback.finish();
|
||||
final String downloadLink = closeCallback.finish();
|
||||
if (downloadLink == null)
|
||||
throw new UploadLinkNotFoundException();
|
||||
this.downloadLink = new URL(downloadLink);
|
||||
}
|
||||
|
||||
public interface LinkedUploadChannelCloseCallback {
|
||||
@@ -77,12 +81,12 @@ public class LinkedUploadChannel implements UploadChannel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadLink() {
|
||||
public URL getDownloadLink() {
|
||||
return downloadLink;
|
||||
}
|
||||
|
||||
public void linkChannel(WritableByteChannel channel) throws IOException {
|
||||
if(this.channel != null)
|
||||
if (this.channel != null)
|
||||
throw new IOException("This channel is already linked.");
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import com.rogiel.httpchannel.service.Uploader;
|
||||
/**
|
||||
* {@link ContentBody} used to upload files in {@link Uploader} implementations.
|
||||
*
|
||||
* @author Rogiel
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public class LinkedUploadChannelContentBody extends AbstractContentBody {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user