diff --git a/pom.xml b/pom.xml index 8db6204..ae78761 100644 --- a/pom.xml +++ b/pom.xml @@ -1,8 +1,39 @@ - - 4.0.0 - com.rogiel.seedbox - seedbox-httpchannel - 1.0.0 - Seedbox - HTTP Channel library - Library capable of downloading and uploading files from free servers using channels. + + 4.0.0 + com.rogiel.seedbox + seedbox-httpchannel + 1.0.0 + Seedbox - HTTP Channel library + Library capable of downloading and uploading files from free servers using channels. + + + junit + junit + 4.9 + jar + test + + + org.apache.httpcomponents + httpclient + 4.1.2 + jar + compile + + + org.apache.httpcomponents + httpmime + 4.1.2 + jar + compile + + + org.apache.commons + commons-io + 1.3.2 + jar + compile + + \ No newline at end of file diff --git a/src/main/java/com/rogiel/httpchannel/service/AbstractDownloader.java b/src/main/java/com/rogiel/httpchannel/service/AbstractDownloader.java new file mode 100644 index 0000000..03f5fd8 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/AbstractDownloader.java @@ -0,0 +1,45 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +import java.io.IOException; + +import com.rogiel.httpchannel.service.DownloadListener.TimerWaitReason; + +import net.sf.f2s.util.ThreadUtils; + +/** + * @author rogiel + * + */ +public abstract class AbstractDownloader implements Downloader { + protected void timer(DownloadListener listener, long timer) { + listener.timer(timer, TimerWaitReason.DOWNLOAD_TIMER); + ThreadUtils.sleep(timer); + } + + protected boolean cooldown(DownloadListener listener, long cooldown) + throws IOException { + if (listener.timer(cooldown, TimerWaitReason.COOLDOWN)) { + ThreadUtils.sleep(cooldown); + return true; + } else { + throw new IOException("Timer " + TimerWaitReason.COOLDOWN + + " aborted due to listener request"); + } + } +} diff --git a/src/main/java/com/rogiel/httpchannel/service/AbstractHttpService.java b/src/main/java/com/rogiel/httpchannel/service/AbstractHttpService.java new file mode 100644 index 0000000..0d80612 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/AbstractHttpService.java @@ -0,0 +1,41 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + + +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.DefaultHttpClient; + +import com.rogiel.httpchannel.service.config.ServiceConfiguration; + +/** + * Abstract base service for HTTP enabled services. + * + * @author Rogiel + * @since 1.0 + */ +public abstract class AbstractHttpService + extends AbstractService implements Service { + /** + * The {@link HttpClient} instance for this service + */ + protected HttpClient client = new DefaultHttpClient(); + + protected AbstractHttpService(T configuration) { + super(configuration); + } +} diff --git a/src/main/java/com/rogiel/httpchannel/service/AbstractService.java b/src/main/java/com/rogiel/httpchannel/service/AbstractService.java new file mode 100644 index 0000000..05eef1f --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/AbstractService.java @@ -0,0 +1,43 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +import com.rogiel.httpchannel.service.config.ServiceConfiguration; + +/** + * This is an abstract {@link Service} implementation. + * + * @author Rogiel + * @version 1.0 + * @param + * The {@link ServiceConfiguration} interface type used by the + * {@link Service}. Note that this must be an interface!s + * @see ServiceConfiguration ServiceConfiguration for details on the configuration interface. + */ +public abstract class AbstractService + implements Service { + protected final T configuration; + + protected AbstractService(T configuration) { + this.configuration = configuration; + } + + @Override + public T getServiceConfiguration() { + return configuration; + } +} diff --git a/src/main/java/com/rogiel/httpchannel/service/AuthenticationService.java b/src/main/java/com/rogiel/httpchannel/service/AuthenticationService.java new file mode 100644 index 0000000..4204a14 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/AuthenticationService.java @@ -0,0 +1,44 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +/** + * Implements an service capable of authenticating into an account. + * + * @author Rogiel + * @since 1.0 + */ +public interface AuthenticationService 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 + * @return an new {@link Authenticator} instance + */ + Authenticator getAuthenticator(Credential credential); + + /** + * Return the matrix of capabilities for this {@link Authenticator}. + * + * @return {@link CapabilityMatrix} with all capabilities of this + * {@link Authenticator}. + * @see AuthenticatorCapability + */ + CapabilityMatrix getAuthenticationCapability(); +} diff --git a/src/main/java/com/rogiel/httpchannel/service/Authenticator.java b/src/main/java/com/rogiel/httpchannel/service/Authenticator.java new file mode 100644 index 0000000..8cf42b6 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/Authenticator.java @@ -0,0 +1,47 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +import java.io.IOException; + +/** + * This interfaces provides authentication for an service. + * + * @author Rogiel + * @since 1.0 + */ +public interface Authenticator { + /** + * Login into the {@link Service}. Once the authentication is done, it is + * persistent for the entire service's operation.
+ * Note: If you want to logout the user, see + * {@link Authenticator#logout()} + * + * @param listener + * the listener do keep a track on the authentication progress + */ + void login(AuthenticatorListener listener) throws IOException; + + /** + * Logout into the {@link Service}. The session is restored to an not + * logged-in state. + * + * @param listener + * the listener do keep a track on the logout progress + */ + void logout(AuthenticatorListener listener) throws IOException; +} diff --git a/src/main/java/com/rogiel/httpchannel/service/AuthenticatorCapability.java b/src/main/java/com/rogiel/httpchannel/service/AuthenticatorCapability.java new file mode 100644 index 0000000..d9ae9c6 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/AuthenticatorCapability.java @@ -0,0 +1,30 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +/** + * Capability an certain {@link Authenticator} can have. + * + * @author Rogiel + * @since 1.0 + */ +public enum AuthenticatorCapability { + /** + * Mark an {@link Authenticator} capable of fetching account information. + */ + FETCH_ACCOUNT_INFORMATION; +} diff --git a/src/main/java/com/rogiel/httpchannel/service/AuthenticatorListener.java b/src/main/java/com/rogiel/httpchannel/service/AuthenticatorListener.java new file mode 100644 index 0000000..87e98bb --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/AuthenticatorListener.java @@ -0,0 +1,47 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +import java.io.IOException; + +/** + * This listener keeps an track on the Authentication process. + * + * @author Rogiel + * @since 1.0 + */ +public interface AuthenticatorListener { + /** + * The username and password informed was not valid. + * + * @param credential + * the authenticating credential + */ + void invalidCredentials(Credential credential); + + /** + * The username and password informed was valid. User is authenticated. + * + * @param credential + * the authenticating credential + */ + void loginSuccessful(Credential credential); + + void logout(Credential credential); + + void exception(IOException e) throws IOException; +} diff --git a/src/main/java/com/rogiel/httpchannel/service/CapabilityMatrix.java b/src/main/java/com/rogiel/httpchannel/service/CapabilityMatrix.java new file mode 100644 index 0000000..8265720 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/CapabilityMatrix.java @@ -0,0 +1,58 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +/** + * This is an utility class to help manage Capabilities of all the services. + * + * @author Rogiel + * @param + * the capability enumeration + * @since 1.0 + */ +public class CapabilityMatrix { + /** + * The list of all supported capabilities + */ + private final T[] matrix; + + /** + * Creates a new matrix of capabilities + * + * @param matrix + * all the capabilities this service support + */ + public CapabilityMatrix(T... matrix) { + this.matrix = matrix; + } + + /** + * Check whether an certatin capability is in the matrix or not. + * + * @param capability + * the capability being searched in the matrix + * @return true if existent, false otherwise + */ + public boolean has(T capability) { + for (final T capScan : matrix) { + if (capScan == capability) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/com/rogiel/httpchannel/service/Credential.java b/src/main/java/com/rogiel/httpchannel/service/Credential.java new file mode 100644 index 0000000..e91661e --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/Credential.java @@ -0,0 +1,59 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +/** + * Pair of username-password used for authenticating into services. + * + * @author Rogiel + * @since 1.0 + */ +public class Credential { + private final String username; + private final String password; + + /** + * Creates a new pair of username-password credential + * + * @param username + * the username + * @param password + * the password + */ + public Credential(String username, String password) { + this.username = username; + this.password = password; + } + + /** + * Get the username + * + * @return the username + */ + public String getUsername() { + return username; + } + + /** + * Get the password + * + * @return the password + */ + public String getPassword() { + return password; + } +} diff --git a/src/main/java/com/rogiel/httpchannel/DownloadChannel.java b/src/main/java/com/rogiel/httpchannel/service/DownloadChannel.java similarity index 91% rename from src/main/java/com/rogiel/httpchannel/DownloadChannel.java rename to src/main/java/com/rogiel/httpchannel/service/DownloadChannel.java index 59e2090..47f7bb2 100644 --- a/src/main/java/com/rogiel/httpchannel/DownloadChannel.java +++ b/src/main/java/com/rogiel/httpchannel/service/DownloadChannel.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with seedbox. If not, see . */ -package com.rogiel.httpchannel; +package com.rogiel.httpchannel.service; import java.nio.channels.ReadableByteChannel; @@ -22,5 +22,7 @@ import java.nio.channels.ReadableByteChannel; * @author Rogiel */ public interface DownloadChannel extends ReadableByteChannel { + long getLength(); + String getFilename(); } diff --git a/src/main/java/com/rogiel/httpchannel/service/DownloadListener.java b/src/main/java/com/rogiel/httpchannel/service/DownloadListener.java new file mode 100644 index 0000000..cf97ba3 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/DownloadListener.java @@ -0,0 +1,70 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +import com.rogiel.httpchannel.service.captcha.Captcha; + +/** + * This listener keeps an track on the progress on an {@link Downloader} + * service. + * + * @author Rogiel + * @since 1.0 + */ +public interface DownloadListener { + /** + * Inform that the downloader will be waiting for an certain amount of time + * due to an timer in the download site. + * + * @param time + * the time in ms in which the service will be be waiting. + * @param reason + * the reason why this timer is running + * @return true if desires to wait, false otherwise + */ + boolean timer(long time, TimerWaitReason reason); + + /** + * The reason why an certain timer is being ran. + * + * @author Rogiel + */ + public enum TimerWaitReason { + /** + * Normal download timer. An annoyance. + */ + DOWNLOAD_TIMER, + /** + * This IP has already download up to the limit, waiting for releasing + * of the block. + */ + COOLDOWN, + /** + * This is an unknown wait time. + */ + UNKNOWN; + } + + /** + * Passes an captcha by parameter and waits for the response of the + * challenge. + * + * @param captcha + * the captcha challenge + */ + String captcha(Captcha captcha); +} diff --git a/src/main/java/com/rogiel/httpchannel/service/DownloadService.java b/src/main/java/com/rogiel/httpchannel/service/DownloadService.java index 3c122cb..b16fb0b 100644 --- a/src/main/java/com/rogiel/httpchannel/service/DownloadService.java +++ b/src/main/java/com/rogiel/httpchannel/service/DownloadService.java @@ -16,42 +16,46 @@ */ package com.rogiel.httpchannel.service; -import java.io.IOException; -import java.net.URI; -import java.nio.ByteBuffer; -import java.nio.channels.ReadableByteChannel; +import java.net.URL; -import com.rogiel.httpchannel.DownloadChannel; +import javax.tools.FileObject; /** - * @author Rogiel + * Implements an service capable of downloading a file. * + * @author Rogiel + * @since 1.0 */ -public interface DownloadService { - DownloadChannel download(URI uri, CaptchaResolver captchaResolver); +public interface DownloadService 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 + * arguments and the parent {@link Service} instance. + * + * @param url + * the url to be downloaded + * @param file + * the destination file + * @return an new instance of {@link Downloader} + */ + Downloader getDownloader(URL url); /** - * Simple delegating implementation for {@link DownloadChannel}. + * Check if this {@link Service} can download from this URL. Implemtations + * might or might not perform network activity. * - * @author Rogiel + * @param url + * the url to be tested. + * @return true if supported, false otherwise. */ - public abstract class SimpleDownloadChannel implements DownloadChannel { - protected final ReadableByteChannel channel; + boolean matchURL(URL url); - public SimpleDownloadChannel(ReadableByteChannel channel) { - this.channel = channel; - } - - public int read(ByteBuffer dst) throws IOException { - return channel.read(dst); - } - - public boolean isOpen() { - return channel.isOpen(); - } - - public void close() throws IOException { - channel.close(); - } - } + /** + * Return the matrix of capabilities for this {@link Downloader}. + * + * @return {@link CapabilityMatrix} with all capabilities of this + * {@link Downloader}. + * @see DownloaderCapability + */ + CapabilityMatrix getDownloadCapabilities(); } diff --git a/src/main/java/com/rogiel/httpchannel/service/Downloader.java b/src/main/java/com/rogiel/httpchannel/service/Downloader.java new file mode 100644 index 0000000..fb2e683 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/Downloader.java @@ -0,0 +1,35 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +import java.io.IOException; + +/** + * This interfaces provides downloading for an service. + * + * @author Rogiel + * @since 1.0 + */ +public interface Downloader { + /** + * Starts the download process. + * + * @param listener + * the listener to keep a track on the download progress + */ + DownloadChannel download(DownloadListener listener) throws IOException; +} diff --git a/src/main/java/com/rogiel/httpchannel/service/DownloaderCapability.java b/src/main/java/com/rogiel/httpchannel/service/DownloaderCapability.java new file mode 100644 index 0000000..c7e45a2 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/DownloaderCapability.java @@ -0,0 +1,46 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +/** + * Capability an certain {@link Downloader} can have. + * + * @author Rogiel + * @since 1.0 + */ +public enum DownloaderCapability { + /** + * Can download files while not authenticated + */ + UNAUTHENTICATED_DOWNLOAD, + /** + * Can download files while authenticated with non-premium account + */ + NON_PREMIUM_ACCOUNT_DOWNLOAD, + /** + * Can download files while authenticated with premium account + */ + PREMIUM_ACCOUNT_DOWNLOAD, + /** + * Resume interrupted downloads are possible and supported. + */ + RESUME, + /** + * Can check the status of the given link before starting download. + */ + STATUS_CHECK; +} diff --git a/src/main/java/com/rogiel/httpchannel/service/Service.java b/src/main/java/com/rogiel/httpchannel/service/Service.java index 9383acd..8a33e61 100644 --- a/src/main/java/com/rogiel/httpchannel/service/Service.java +++ b/src/main/java/com/rogiel/httpchannel/service/Service.java @@ -16,10 +16,46 @@ */ package com.rogiel.httpchannel.service; +import com.rogiel.httpchannel.service.config.ServiceConfiguration; + /** - * @author Rogiel - * + * Base interface for all the services. Whenever the operation suported by the + * {@link Service} it must implement this interface. Most of implementations + * will benefit from abstract instances of this interface: + *
    + *
  • {@link AbstractHttpService}: provides an basic support for HTTP services. + *
  • + *
+ * + * @author Rogiel + * @since 1.0 */ public interface Service { + /** + * Get the ServiceID. + * + * @return the id of the service + */ + String getId(); + /** + * Get Major version of this service + * + * @return the major version + */ + int getMajorVersion(); + + /** + * Get the minor version of this service + * + * @return the minor version + */ + int getMinorVersion(); + + /** + * Returns this {@link ServiceConfiguration} instance + * + * @return the {@link ServiceConfiguration} instance + */ + ServiceConfiguration getServiceConfiguration(); } diff --git a/src/main/java/com/rogiel/httpchannel/service/ServiceException.java b/src/main/java/com/rogiel/httpchannel/service/ServiceException.java new file mode 100644 index 0000000..44f102b --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/ServiceException.java @@ -0,0 +1,41 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +import java.io.IOException; + +/** + * Base exception for any {@link Service}. + * + * @author Rogiel + * @since 1.0 + */ +public class ServiceException extends IOException { + private static final long serialVersionUID = 1L; + + public ServiceException(String message) { + super(message); + } + + public ServiceException(Throwable t) { + super(t); + } + + public ServiceException(String message, Throwable t) { + super(message, t); + } +} diff --git a/src/main/java/com/rogiel/httpchannel/UploadChannel.java b/src/main/java/com/rogiel/httpchannel/service/UploadChannel.java similarity index 88% rename from src/main/java/com/rogiel/httpchannel/UploadChannel.java rename to src/main/java/com/rogiel/httpchannel/service/UploadChannel.java index d36cec9..572c613 100644 --- a/src/main/java/com/rogiel/httpchannel/UploadChannel.java +++ b/src/main/java/com/rogiel/httpchannel/service/UploadChannel.java @@ -14,14 +14,17 @@ * You should have received a copy of the GNU General Public License * along with seedbox. If not, see . */ -package com.rogiel.httpchannel; +package com.rogiel.httpchannel.service; -import java.net.URI; import java.nio.channels.WritableByteChannel; /** * @author Rogiel */ public interface UploadChannel extends WritableByteChannel { - URI getLink(); + long getLength(); + + String getFilename(); + + String getDownloadLink(); } diff --git a/src/main/java/com/rogiel/httpchannel/service/UploadListener.java b/src/main/java/com/rogiel/httpchannel/service/UploadListener.java new file mode 100644 index 0000000..a73abf5 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/UploadListener.java @@ -0,0 +1,29 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +/** + * This listener keeps an track on the progress on an {@link Uploader} service. + * + * @author Rogiel + * @since 1.0 + */ +public interface UploadListener { + long getFilesize(); + + String getFilename(); +} diff --git a/src/main/java/com/rogiel/httpchannel/service/UploadListenerContentBody.java b/src/main/java/com/rogiel/httpchannel/service/UploadListenerContentBody.java new file mode 100644 index 0000000..ec88413 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/UploadListenerContentBody.java @@ -0,0 +1,74 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.channels.Channels; +import java.nio.channels.WritableByteChannel; + +import net.sf.f2s.util.ThreadUtils; + +import org.apache.http.entity.mime.content.AbstractContentBody; +import org.apache.http.entity.mime.content.ContentBody; + +import com.rogiel.httpchannel.service.channel.LinkedUploadChannel; + +/** + * {@link ContentBody} used to upload files in {@link Uploader} implementations. + * + * @author Rogiel + * @since 1.0 + */ +public class UploadListenerContentBody extends AbstractContentBody { + private final LinkedUploadChannel channel; + + public UploadListenerContentBody(LinkedUploadChannel channel) { + super("application/octet-stream"); + this.channel = channel; + } + + @Override + public String getFilename() { + return channel.getFilename(); + } + + @Override + public void writeTo(OutputStream out) throws IOException { + final WritableByteChannel outputChannel = Channels.newChannel(out); + channel.linkChannel(outputChannel); + + while (channel.isOpen() && outputChannel.isOpen()) { + ThreadUtils.sleep(500); + } + } + + @Override + public String getCharset() { + return null; + } + + @Override + public long getContentLength() { + return channel.getLength(); + } + + @Override + public String getTransferEncoding() { + return "binary"; + } +} diff --git a/src/main/java/com/rogiel/httpchannel/service/UploadService.java b/src/main/java/com/rogiel/httpchannel/service/UploadService.java index 9cbfc07..41ac7e0 100644 --- a/src/main/java/com/rogiel/httpchannel/service/UploadService.java +++ b/src/main/java/com/rogiel/httpchannel/service/UploadService.java @@ -16,38 +16,39 @@ */ package com.rogiel.httpchannel.service; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.WritableByteChannel; - -import com.rogiel.httpchannel.UploadChannel; - /** - * @author Rogiel + * Implements an service capable of uploading a file. + * + * @author Rogiel + * @since 1.0 */ -public interface UploadService { - UploadChannel upload(String filename, long filesize); - +public interface UploadService extends Service { /** - * Simple delegating implementation for {@link UploadChannel}. + * Creates a new instance of {@link Uploader}. This instance is attached + * with the parent {@link Service} instance.
+ * Note: not all services might support description * - * @author Rogiel + * @param file + * the file to be uploaded + * @param description + * the description of the upload. If supported. + * @return the new {@link Uploader} instance */ - public abstract class SimpleUploadChannel implements UploadChannel { - protected final WritableByteChannel channel; + Uploader getUploader(String description); - public SimpleUploadChannel(WritableByteChannel channel) { - this.channel = channel; - } + /** + * Get the maximum upload file size supported by this service. + * + * @return the maximum filesize supported + */ + long getMaximumFilesize(); - @Override - public int write(ByteBuffer src) throws IOException { - return channel.write(src); - } - - @Override - public boolean isOpen() { - return channel.isOpen(); - } - } + /** + * Return the matrix of capabilities for this {@link Uploader}. + * + * @return {@link CapabilityMatrix} with all capabilities of this + * {@link Uploader}. + * @see UploaderCapability + */ + CapabilityMatrix getUploadCapabilities(); } diff --git a/src/main/java/com/rogiel/httpchannel/service/Uploader.java b/src/main/java/com/rogiel/httpchannel/service/Uploader.java new file mode 100644 index 0000000..8a6e300 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/Uploader.java @@ -0,0 +1,38 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +import java.io.IOException; + +/** + * This interfaces provides uploading for an service. + * + * @author Rogiel + * @since 1.0 + */ +public interface Uploader { + /** + * Starts the upload process on this service. + * + * @param listener + * the listener do keep an track on the upload process + * @throws UploadServiceException + * thrown if something went wrong + * @throws IOException + */ + UploadChannel upload(UploadListener listener) throws IOException; +} diff --git a/src/main/java/com/rogiel/httpchannel/service/UploaderCapability.java b/src/main/java/com/rogiel/httpchannel/service/UploaderCapability.java new file mode 100644 index 0000000..a96c57b --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/UploaderCapability.java @@ -0,0 +1,38 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service; + +/** + * Capability an certain {@link Uploader} can have. + * + * @author Rogiel + * @since 1.0 + */ +public enum UploaderCapability { + /** + * Can upload while not authenticated into any account + */ + UNAUTHENTICATED_UPLOAD, + /** + * Can upload while authenticated with a non-premium account + */ + NON_PREMIUM_ACCOUNT_UPLOAD, + /** + * Can upload while authenticated with a premium account + */ + PREMIUM_ACCOUNT_UPLOAD; +} diff --git a/src/main/java/com/rogiel/httpchannel/service/captcha/Captcha.java b/src/main/java/com/rogiel/httpchannel/service/captcha/Captcha.java new file mode 100644 index 0000000..9778c67 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/captcha/Captcha.java @@ -0,0 +1,26 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service.captcha; + +/** + * @author Rogiel + * @since 1.0 + */ +public interface Captcha { + String getAnswer(); + void setAnswer(String answer); +} diff --git a/src/main/java/com/rogiel/httpchannel/service/captcha/ImageCaptcha.java b/src/main/java/com/rogiel/httpchannel/service/captcha/ImageCaptcha.java new file mode 100644 index 0000000..832d8ae --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/captcha/ImageCaptcha.java @@ -0,0 +1,47 @@ +/* + * This file is part of 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 . + */ +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; + } +} diff --git a/src/main/java/com/rogiel/httpchannel/service/channel/InputStreamDownloadChannel.java b/src/main/java/com/rogiel/httpchannel/service/channel/InputStreamDownloadChannel.java new file mode 100644 index 0000000..d7f1811 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/channel/InputStreamDownloadChannel.java @@ -0,0 +1,69 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service.channel; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; + +import com.rogiel.httpchannel.service.DownloadChannel; + + +/** + * @author Rogiel + * + */ +public class InputStreamDownloadChannel implements DownloadChannel { + private final ReadableByteChannel channel; + + private final long length; + private final String filename; + + public InputStreamDownloadChannel(InputStream in, final long length, + final String filename) { + this.channel = Channels.newChannel(in); + this.length = length; + this.filename = filename; + } + + @Override + public int read(ByteBuffer dst) throws IOException { + return channel.read(dst); + } + + @Override + public boolean isOpen() { + return channel.isOpen(); + } + + @Override + public void close() throws IOException { + channel.close(); + } + + @Override + public long getLength() { + return length; + } + + @Override + public String getFilename() { + return filename; + } +} diff --git a/src/main/java/com/rogiel/httpchannel/service/channel/LinkedUploadChannel.java b/src/main/java/com/rogiel/httpchannel/service/channel/LinkedUploadChannel.java new file mode 100644 index 0000000..8309855 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/channel/LinkedUploadChannel.java @@ -0,0 +1,93 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service.channel; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.WritableByteChannel; + +import com.rogiel.httpchannel.service.UploadChannel; + + +/** + * @author Rogiel + * + */ +public class LinkedUploadChannel implements UploadChannel { + private WritableByteChannel channel; + private final LinkedUploadChannelCloseCallback closeCallback; + + private final long length; + private final String filename; + private String downloadLink; + + private boolean open = true; + + public LinkedUploadChannel(LinkedUploadChannelCloseCallback closeCallback, + long filesize, String filename) { + this.closeCallback = closeCallback; + this.filename = filename; + this.length = filesize; + } + + @Override + public int write(ByteBuffer src) throws IOException { + if (channel == null) + throw new IOException("Channel is not linked yet"); + return channel.write(src); + } + + @Override + public boolean isOpen() { + return (channel != null ? channel.isOpen() : true) && open; + } + + @Override + public void close() throws IOException { + open = false; + downloadLink = closeCallback.finish(); + } + + public interface LinkedUploadChannelCloseCallback { + String finish() throws IOException; + } + + @Override + public long getLength() { + return length; + } + + @Override + public String getFilename() { + return filename; + } + + @Override + public String getDownloadLink() { + return downloadLink; + } + + public void linkChannel(WritableByteChannel channel) throws IOException { + if(this.channel != null) + throw new IOException("This channel is already linked."); + this.channel = channel; + } + + public boolean isLinked() { + return channel != null; + } +} diff --git a/src/main/java/com/rogiel/httpchannel/service/config/ServiceConfiguration.java b/src/main/java/com/rogiel/httpchannel/service/config/ServiceConfiguration.java new file mode 100644 index 0000000..7c3c3c0 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/config/ServiceConfiguration.java @@ -0,0 +1,40 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service.config; + +import java.lang.reflect.Proxy; + +import net.sf.f2s.util.transformer.Transformer; + +/** + * This is an flag interface to indicate that an certain Interface is the + * configuration for the service.
+ *
+ * Every service must create an interface 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.
+ *
+ * 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 { +} diff --git a/src/main/java/com/rogiel/httpchannel/service/config/ServiceConfigurationHelper.java b/src/main/java/com/rogiel/httpchannel/service/config/ServiceConfigurationHelper.java new file mode 100644 index 0000000..c3b494c --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/config/ServiceConfigurationHelper.java @@ -0,0 +1,112 @@ +/* + * This file is part of 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 . + */ +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 net.sf.f2s.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 + * 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 defaultConfiguration( + Class 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 + * 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 file(Class 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; + } + }); + } +} diff --git a/src/main/java/com/rogiel/httpchannel/service/config/ServiceConfigurationProperty.java b/src/main/java/com/rogiel/httpchannel/service/config/ServiceConfigurationProperty.java new file mode 100644 index 0000000..b5d00f5 --- /dev/null +++ b/src/main/java/com/rogiel/httpchannel/service/config/ServiceConfigurationProperty.java @@ -0,0 +1,51 @@ +/* + * This file is part of 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 . + */ +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.
+ *
+ *

Usage example

+ * + *
+ * public interface DummyServiceConfiguration extends ServiceConfiguration {
+ * 	@ServiceConfigurationProperty(defaultValue = "true")
+ * 	boolean retryAllowed();
+ * }
+ * 
+ * + * The default implementation created by + * {@link ServiceConfigurationHelper#defaultConfiguration()} will always return + * the defaultValue. + * + * @author Rogiel + * @version 1.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface ServiceConfigurationProperty { + String key(); + String defaultValue(); +} diff --git a/src/main/java/com/rogiel/httpchannel/service/impl/MegaUploadService.java b/src/main/java/com/rogiel/httpchannel/service/impl/MegaUploadService.java index 67b807a..26e6222 100644 --- a/src/main/java/com/rogiel/httpchannel/service/impl/MegaUploadService.java +++ b/src/main/java/com/rogiel/httpchannel/service/impl/MegaUploadService.java @@ -17,35 +17,318 @@ package com.rogiel.httpchannel.service.impl; import java.io.IOException; -import java.net.URI; +import java.net.URL; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.regex.Pattern; -import com.rogiel.httpchannel.DownloadChannel; -import com.rogiel.httpchannel.UploadChannel; -import com.rogiel.httpchannel.service.CaptchaResolver; +import net.sf.f2s.util.HttpClientUtils; +import net.sf.f2s.util.PatternUtils; +import net.sf.f2s.util.ThreadUtils; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.mime.MultipartEntity; +import org.apache.http.entity.mime.content.StringBody; + +import com.rogiel.httpchannel.service.AbstractDownloader; +import com.rogiel.httpchannel.service.AbstractHttpService; +import com.rogiel.httpchannel.service.AuthenticationService; +import com.rogiel.httpchannel.service.Authenticator; +import com.rogiel.httpchannel.service.AuthenticatorCapability; +import com.rogiel.httpchannel.service.AuthenticatorListener; +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.UploadChannel; +import com.rogiel.httpchannel.service.UploadListener; +import com.rogiel.httpchannel.service.UploadListenerContentBody; 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.config.ServiceConfiguration; +import com.rogiel.httpchannel.service.config.ServiceConfigurationProperty; +import com.rogiel.httpchannel.service.impl.MegaUploadService.MegaUploadServiceConfiguration; /** - * @author Rogiel + * This service handles login, upload and download to MegaUpload.com. * + * @author Rogiel + * @since 1.0 */ -public class MegaUploadService implements DownloadService, UploadService { - public DownloadChannel download(URI uri, CaptchaResolver captchaResolver) { - return new SimpleDownloadChannel(null) { - }; +public class MegaUploadService extends + AbstractHttpService implements Service, + UploadService, DownloadService, AuthenticationService { + private static final Pattern UPLOAD_URL_PATTERN = Pattern + .compile("http://www([0-9]*)\\.megaupload\\.com/upload_done\\.php\\?UPLOAD_IDENTIFIER=[0-9]*"); + + private static final Pattern DOWNLOAD_DIRECT_LINK_PATTERN = Pattern + .compile("http://www([0-9]*)\\.megaupload\\.com/files/([A-Za-z0-9]*)/([^\"]*)"); + private static final Pattern DOWNLOAD_TIMER = Pattern + .compile("count=([0-9]*);"); + // private static final Pattern DOWNLOAD_FILESIZE = Pattern + // .compile("[0-9]*(\\.[0-9]*)? (K|M|G)B"); + + private static final Pattern DOWNLOAD_URL_PATTERN = Pattern + .compile("http://www\\.megaupload\\.com/\\?d=([A-Za-z0-9]*)"); + + public MegaUploadService(final MegaUploadServiceConfiguration configuration) { + super(configuration); } - public UploadChannel upload(String filename, long filesize) { - return new SimpleUploadChannel(null) { - @Override - public void close() throws IOException { - + @Override + public String getId() { + return "megaupload"; + } + + @Override + public int getMajorVersion() { + return 1; + } + + @Override + public int getMinorVersion() { + return 0; + } + + @Override + public Uploader getUploader(String description) { + return new MegaUploadUploader(description); + } + + @Override + public long getMaximumFilesize() { + return 1 * 1024 * 1024 * 1024; + } + + @Override + public CapabilityMatrix getUploadCapabilities() { + return new CapabilityMatrix( + UploaderCapability.UNAUTHENTICATED_UPLOAD, + UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD, + UploaderCapability.PREMIUM_ACCOUNT_UPLOAD); + } + + @Override + public Downloader getDownloader(URL url) { + return new MegaUploadDownloader(url); + } + + @Override + public boolean matchURL(URL url) { + return false; + } + + @Override + public CapabilityMatrix getDownloadCapabilities() { + return new CapabilityMatrix( + DownloaderCapability.UNAUTHENTICATED_DOWNLOAD, + DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD, + DownloaderCapability.PREMIUM_ACCOUNT_DOWNLOAD); + } + + @Override + public Authenticator getAuthenticator(Credential credential) { + return new MegaUploadAuthenticator(credential); + } + + @Override + public CapabilityMatrix getAuthenticationCapability() { + return new CapabilityMatrix(); + } + + protected class MegaUploadUploader implements Uploader, + LinkedUploadChannelCloseCallback { + private final String description; + + private Future uploadFuture; + + public MegaUploadUploader(String description) { + this.description = (description != null ? description + : configuration.getDefaultUploadDescription()); + } + + @Override + public UploadChannel upload(UploadListener listener) throws IOException { + final String body = HttpClientUtils.get(client, + "http://www.megaupload.com/multiupload/"); + final String url = PatternUtils.find(UPLOAD_URL_PATTERN, body); + + final HttpPost upload = new HttpPost(url); + final MultipartEntity entity = new MultipartEntity(); + upload.setEntity(entity); + + final LinkedUploadChannel channel = new LinkedUploadChannel(this, + listener.getFilesize(), listener.getFilename()); + + entity.addPart("multifile_0", + new UploadListenerContentBody(channel)); + entity.addPart("multimessage_0", new StringBody(description)); + + uploadFuture = HttpClientUtils.executeAsync(client, upload); + while (!channel.isLinked() && !uploadFuture.isDone()) { + ThreadUtils.sleep(100); } - - @Override - public URI getLink() { + return channel; + } + + @Override + public String finish() throws IOException { + try { + return PatternUtils.find(DOWNLOAD_URL_PATTERN, + uploadFuture.get()); + } catch (InterruptedException e) { return null; + } catch (ExecutionException e) { + throw (IOException) e.getCause(); } - }; + } + } + + protected class MegaUploadDownloader extends AbstractDownloader { + private final URL url; + + public MegaUploadDownloader(URL url) { + this.url = url; + } + + @Override + public DownloadChannel download(DownloadListener listener) + throws IOException { + final HttpGet request = new HttpGet(url.toString()); + final HttpResponse response = client.execute(request); + final String content = IOUtils.toString(response.getEntity() + .getContent()); + + // try to find timer + final String stringTimer = PatternUtils.find(DOWNLOAD_TIMER, + content, 1); + int timer = 0; + if (stringTimer != null && stringTimer.length() > 0) { + timer = Integer.parseInt(stringTimer); + } + if (timer > 0 && configuration.respectWaitTime()) { + timer(listener, timer * 1000); + } + + final String downloadUrl = PatternUtils.find( + DOWNLOAD_DIRECT_LINK_PATTERN, content, 0); + if (downloadUrl != null && downloadUrl.length() > 0) { + final HttpGet downloadRequest = new HttpGet(downloadUrl); + final HttpResponse downloadResponse = client + .execute(downloadRequest); + if (downloadResponse.getStatusLine().getStatusCode() == HttpStatus.SC_FORBIDDEN + || downloadResponse.getStatusLine().getStatusCode() == HttpStatus.SC_SERVICE_UNAVAILABLE) { + downloadResponse.getEntity().getContent().close(); + if (cooldown(listener, 60 * 1000)) + return download(listener); // retry download + } else { + final String filename = FilenameUtils.getName(downloadUrl); + // listener.fileName(filename); + + final Header contentLengthHeader = downloadResponse + .getFirstHeader("Content-Length"); + long contentLength = -1; + if (contentLengthHeader != null) { + contentLength = Long.valueOf(contentLengthHeader + .getValue()); + // listener.fileSize(contentLength); + } + + return new InputStreamDownloadChannel(downloadResponse + .getEntity().getContent(), contentLength, filename); + } + } else { + throw new IOException("Download link not found"); + } + throw new IOException("Unknown error"); + } + } + + protected class MegaUploadAuthenticator implements Authenticator { + private final Credential credential; + + public MegaUploadAuthenticator(Credential credential) { + this.credential = credential; + } + + @Override + public void login(AuthenticatorListener listener) { + try { + final HttpPost login = new HttpPost( + "http://www.megaupload.com/?c=login"); + final MultipartEntity entity = new MultipartEntity(); + login.setEntity(entity); + + entity.addPart("login", new StringBody("1")); + entity.addPart("username", + new StringBody(credential.getUsername())); + entity.addPart("password", + new StringBody(credential.getPassword())); + + final String response = HttpClientUtils.execute(client, login); + if (response.contains("Username and password do " + + "not match. Please try again!")) { + listener.invalidCredentials(credential); + return; + } + listener.loginSuccessful(credential); + } catch (IOException e) { + // throw new NestedLoginServiceException(e); + // TODO throw an exception here + } + } + + @Override + public void logout(AuthenticatorListener listener) { + try { + final HttpPost logout = new HttpPost( + "http://www.megaupload.com/?c=account"); + final MultipartEntity entity = new MultipartEntity(); + logout.setEntity(entity); + + entity.addPart("logout", new StringBody("1")); + HttpClientUtils.execute(client, logout); + + // TODO check logout status + + listener.logout(credential); + return; + } catch (IOException e) { + // throw new NestedLoginServiceException(e); + // TODO throw an exception here + } + } + } + + 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() + "." + + getMinorVersion(); } } diff --git a/src/main/java/net/sf/f2s/util/HttpClientUtils.java b/src/main/java/net/sf/f2s/util/HttpClientUtils.java new file mode 100644 index 0000000..244db20 --- /dev/null +++ b/src/main/java/net/sf/f2s/util/HttpClientUtils.java @@ -0,0 +1,63 @@ +/* + * This file is part of 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 . + */ +package net.sf.f2s.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; + +public class HttpClientUtils { + private static final ExecutorService threadPool = Executors + .newCachedThreadPool(); + + public static String get(HttpClient client, String url) throws IOException { + return execute(client, new HttpGet(url)); + } + + public static String execute(HttpClient client, HttpUriRequest request) + throws IOException { + return toString(client.execute(request)); + } + + public static Future executeAsync(final HttpClient client, + final HttpUriRequest request) throws IOException { + return threadPool.submit(new Callable() { + @Override + public String call() throws Exception { + return HttpClientUtils.toString(client.execute(request)); + } + }); + } + + public static String toString(HttpResponse response) throws IOException { + final InputStream in = response.getEntity().getContent(); + try { + return IOUtils.toString(in); + } finally { + in.close(); + } + } +} diff --git a/src/main/java/net/sf/f2s/util/PatternUtils.java b/src/main/java/net/sf/f2s/util/PatternUtils.java new file mode 100644 index 0000000..48d5a18 --- /dev/null +++ b/src/main/java/net/sf/f2s/util/PatternUtils.java @@ -0,0 +1,46 @@ +/* + * This file is part of 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 . + */ +package net.sf.f2s.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PatternUtils { + public static String find(Pattern pattern, String text) { + return find(pattern, text, 0); + } + + public static String find(Pattern pattern, String text, int n) { + final Matcher matcher = pattern.matcher(text); + if (matcher.find()) { + return matcher.group(n); + } + return null; + } + + public static String match(Pattern pattern, String text) { + return match(pattern, text, 0); + } + + public static String match(Pattern pattern, String text, int n) { + final Matcher matcher = pattern.matcher(text); + if (matcher.matches()) { + return matcher.group(n); + } + return null; + } +} diff --git a/src/main/java/net/sf/f2s/util/ThreadUtils.java b/src/main/java/net/sf/f2s/util/ThreadUtils.java new file mode 100644 index 0000000..45b441b --- /dev/null +++ b/src/main/java/net/sf/f2s/util/ThreadUtils.java @@ -0,0 +1,30 @@ +/* + * This file is part of 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 . + */ +package net.sf.f2s.util; + +/** + * @author Rogiel + * @since 1.0 + */ +public class ThreadUtils { + public static void sleep(long time) { + try { + Thread.sleep(time); + } catch (InterruptedException e) { + } + } +} diff --git a/src/main/java/net/sf/f2s/util/transformer/TransformationException.java b/src/main/java/net/sf/f2s/util/transformer/TransformationException.java new file mode 100644 index 0000000..478641a --- /dev/null +++ b/src/main/java/net/sf/f2s/util/transformer/TransformationException.java @@ -0,0 +1,55 @@ +/* + * This file is part of 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 . + */ +package net.sf.f2s.util.transformer; + +/** + * @author Rogiel + * @since 1.0 + */ +public class TransformationException extends Exception { + private static final long serialVersionUID = 1L; + + public TransformationException() { + } + + /** + * @param message + * the message + */ + public TransformationException(String message) { + super(message); + } + + /** + * @param cause + * the cause + */ + public TransformationException(Throwable cause) { + super(cause); + } + + /** + * @param message + * the message + * @param cause + * the cause + */ + public TransformationException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/com/rogiel/httpchannel/service/CaptchaResolver.java b/src/main/java/net/sf/f2s/util/transformer/Transformer.java similarity index 82% rename from src/main/java/com/rogiel/httpchannel/service/CaptchaResolver.java rename to src/main/java/net/sf/f2s/util/transformer/Transformer.java index 3f44684..c78a877 100644 --- a/src/main/java/com/rogiel/httpchannel/service/CaptchaResolver.java +++ b/src/main/java/net/sf/f2s/util/transformer/Transformer.java @@ -14,12 +14,12 @@ * You should have received a copy of the GNU General Public License * along with seedbox. If not, see . */ -package com.rogiel.httpchannel.service; +package net.sf.f2s.util.transformer; /** - * @author Rogiel + * @author rogiel * */ -public interface CaptchaResolver { - +public interface Transformer { + O transform(String data) throws TransformationException; } diff --git a/src/main/java/net/sf/f2s/util/transformer/TransformerFactory.java b/src/main/java/net/sf/f2s/util/transformer/TransformerFactory.java new file mode 100644 index 0000000..43dc12b --- /dev/null +++ b/src/main/java/net/sf/f2s/util/transformer/TransformerFactory.java @@ -0,0 +1,47 @@ +/* + * This file is part of 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 . + */ +package net.sf.f2s.util.transformer; + +import java.net.URL; + +import net.sf.f2s.util.transformer.impl.BooleanTransformer; +import net.sf.f2s.util.transformer.impl.IntegerTransformer; +import net.sf.f2s.util.transformer.impl.LongTransformer; +import net.sf.f2s.util.transformer.impl.StringTransformer; +import net.sf.f2s.util.transformer.impl.URLTransformer; + +/** + * @author Rogiel + * @since 1.0 + */ +public class TransformerFactory { + @SuppressWarnings("unchecked") + public static Transformer getTransformer(Class type) { + if (String.class.isAssignableFrom(type)) { + return (Transformer) new StringTransformer(); + } else if (Boolean.class.isAssignableFrom(type) || type == Boolean.TYPE) { + return (Transformer) new BooleanTransformer(); + } else if (Integer.class.isAssignableFrom(type) || type == Integer.TYPE) { + return (Transformer) new IntegerTransformer(); + } else if (Long.class.isAssignableFrom(type) || type == Long.TYPE) { + return (Transformer) new LongTransformer(); + } else if (URL.class.isAssignableFrom(type)) { + return (Transformer) new URLTransformer(); + } + return null; + } +} diff --git a/src/main/java/net/sf/f2s/util/transformer/impl/BooleanTransformer.java b/src/main/java/net/sf/f2s/util/transformer/impl/BooleanTransformer.java new file mode 100644 index 0000000..f860811 --- /dev/null +++ b/src/main/java/net/sf/f2s/util/transformer/impl/BooleanTransformer.java @@ -0,0 +1,30 @@ +/* + * This file is part of 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 . + */ +package net.sf.f2s.util.transformer.impl; + +import net.sf.f2s.util.transformer.Transformer; + +/** + * @author rogiel + * + */ +public class BooleanTransformer implements Transformer { + @Override + public Boolean transform(String data) { + return Boolean.parseBoolean(data); + } +} diff --git a/src/main/java/net/sf/f2s/util/transformer/impl/IntegerTransformer.java b/src/main/java/net/sf/f2s/util/transformer/impl/IntegerTransformer.java new file mode 100644 index 0000000..6830b0f --- /dev/null +++ b/src/main/java/net/sf/f2s/util/transformer/impl/IntegerTransformer.java @@ -0,0 +1,30 @@ +/* + * This file is part of 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 . + */ +package net.sf.f2s.util.transformer.impl; + +import net.sf.f2s.util.transformer.Transformer; + +/** + * @author rogiel + * + */ +public class IntegerTransformer implements Transformer { + @Override + public Integer transform(String data) { + return Integer.parseInt(data); + } +} diff --git a/src/main/java/net/sf/f2s/util/transformer/impl/LongTransformer.java b/src/main/java/net/sf/f2s/util/transformer/impl/LongTransformer.java new file mode 100644 index 0000000..891e468 --- /dev/null +++ b/src/main/java/net/sf/f2s/util/transformer/impl/LongTransformer.java @@ -0,0 +1,30 @@ +/* + * This file is part of 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 . + */ +package net.sf.f2s.util.transformer.impl; + +import net.sf.f2s.util.transformer.Transformer; + +/** + * @author rogiel + * + */ +public class LongTransformer implements Transformer { + @Override + public Long transform(String data) { + return Long.parseLong(data); + } +} diff --git a/src/main/java/net/sf/f2s/util/transformer/impl/StringTransformer.java b/src/main/java/net/sf/f2s/util/transformer/impl/StringTransformer.java new file mode 100644 index 0000000..3935d01 --- /dev/null +++ b/src/main/java/net/sf/f2s/util/transformer/impl/StringTransformer.java @@ -0,0 +1,30 @@ +/* + * This file is part of 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 . + */ +package net.sf.f2s.util.transformer.impl; + +import net.sf.f2s.util.transformer.Transformer; + +/** + * @author rogiel + * + */ +public class StringTransformer implements Transformer { + @Override + public String transform(String data) { + return data; + } +} diff --git a/src/main/java/net/sf/f2s/util/transformer/impl/URLTransformer.java b/src/main/java/net/sf/f2s/util/transformer/impl/URLTransformer.java new file mode 100644 index 0000000..47824f9 --- /dev/null +++ b/src/main/java/net/sf/f2s/util/transformer/impl/URLTransformer.java @@ -0,0 +1,38 @@ +/* + * This file is part of 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 . + */ +package net.sf.f2s.util.transformer.impl; + +import java.net.MalformedURLException; +import java.net.URL; + +import net.sf.f2s.util.transformer.TransformationException; +import net.sf.f2s.util.transformer.Transformer; + +/** + * @author rogiel + * + */ +public class URLTransformer implements Transformer { + @Override + public URL transform(String data) throws TransformationException { + try { + return new URL(data); + } catch (MalformedURLException e) { + throw new TransformationException(e); + } + } +} diff --git a/src/test/java/com/rogiel/httpchannel/service/impl/MegaUploadServiceTest.java b/src/test/java/com/rogiel/httpchannel/service/impl/MegaUploadServiceTest.java new file mode 100644 index 0000000..2185fb4 --- /dev/null +++ b/src/test/java/com/rogiel/httpchannel/service/impl/MegaUploadServiceTest.java @@ -0,0 +1,289 @@ +/* + * This file is part of 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 . + */ +package com.rogiel.httpchannel.service.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +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.ByteBuffer; +import java.nio.channels.Channels; +import java.util.Properties; + +import junit.framework.Assert; + +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.AuthenticatorListener; +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.UploadChannel; +import com.rogiel.httpchannel.service.UploadListener; +import com.rogiel.httpchannel.service.UploadService; +import com.rogiel.httpchannel.service.UploaderCapability; +import com.rogiel.httpchannel.service.captcha.Captcha; +import com.rogiel.httpchannel.service.config.ServiceConfigurationHelper; +import com.rogiel.httpchannel.service.impl.MegaUploadService.MegaUploadServiceConfiguration; + +public class MegaUploadServiceTest { + private Service service; + + /** + * See src/test/resources/config/megaupload.properties + *

+ * Key: username + */ + private String VALID_USERNAME; + /** + * See src/test/resources/config/megaupload.properties + *

+ * Key: password + */ + private String VALID_PASSWORD; + + private static final String INVALID_USERNAME = "invalid"; + private static final String INVALID_PASSWORD = "abc"; + + @Before + public void setUp() throws Exception { + // MegaUploadServiceConfiguration.class; + service = new MegaUploadService( + ServiceConfigurationHelper + .defaultConfiguration(MegaUploadServiceConfiguration.class)); + + final Properties properties = new Properties(); + properties.load(new FileInputStream( + "src/test/resources/config/megaupload.properties")); + VALID_USERNAME = properties.getProperty("username"); + VALID_PASSWORD = properties.getProperty("password"); + } + + @Test + public void testServiceId() { + System.out.println("Service: "+service.toString()); + assertEquals("megaupload", service.getId()); + } + + @Test + public void testValidAuthenticator() throws IOException { + ((AuthenticationService) service).getAuthenticator( + new Credential(VALID_USERNAME, VALID_PASSWORD)).login( + new AuthenticatorListener() { + @Override + public void invalidCredentials(Credential credential) { + fail("This login attemp should've been successful."); + } + + @Override + public void loginSuccessful(Credential credential) { + } + + @Override + public void logout(Credential credential) { + } + + @Override + public void exception(IOException e) throws IOException { + throw e; + } + }); + } + + @Test + public void testInvalidAuthenticator() throws IOException { + ((AuthenticationService) service).getAuthenticator( + new Credential(INVALID_USERNAME, INVALID_PASSWORD)).login( + new AuthenticatorListener() { + @Override + public void invalidCredentials(Credential credential) { + } + + @Override + public void loginSuccessful(Credential credential) { + fail("This login attemp should't have been successful."); + } + + @Override + public void logout(Credential credential) { + } + + @Override + public void exception(IOException e) throws IOException { + throw e; + } + }); + } + + @Test + public void testNonLoguedInUploader() throws IOException { + assertTrue( + "This service does not have the capability UploadCapability.FREE_UPLOAD", + ((UploadService) service).getUploadCapabilities().has( + UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD)); + final UploadChannel channel = ((UploadService) service).getUploader( + "Upload by httpchannel").upload(new UploadListener() { + @Override + public long getFilesize() { + return 10; + } + + @Override + public String getFilename() { + return "test.bin"; + } + }); + final ByteBuffer buffer = ByteBuffer.allocate(10); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + + buffer.flip(); + + channel.write(buffer); + channel.close(); + Assert.assertNotNull(channel.getDownloadLink()); + } + + @Test + public void testLoguedInUploader() throws IOException { + assertTrue( + "This service does not have the capability UploadCapability.PREMIUM_UPLOAD", + ((UploadService) service).getUploadCapabilities().has( + UploaderCapability.PREMIUM_ACCOUNT_UPLOAD)); + + ((AuthenticationService) service).getAuthenticator( + new Credential(VALID_USERNAME, VALID_PASSWORD)).login( + new AuthenticatorListener() { + @Override + public void invalidCredentials(Credential credential) { + fail("Invalid credentials"); + } + + @Override + public void loginSuccessful(Credential credential) { + } + + @Override + public void logout(Credential credential) { + } + + @Override + public void exception(IOException e) throws IOException { + // TODO Auto-generated method stub + + } + }); + + final UploadChannel channel = ((UploadService) service).getUploader( + "Upload by httpchannel").upload(new UploadListener() { + @Override + public long getFilesize() { + return 10; + } + + @Override + public String getFilename() { + return "test.bin"; + } + }); + final ByteBuffer buffer = ByteBuffer.allocate(10); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + buffer.put((byte) 0x00); + + buffer.flip(); + + channel.write(buffer); + channel.close(); + Assert.assertNotNull(channel.getDownloadLink()); + } + + @Test + public void testDownloader() throws IOException, MalformedURLException { + final DownloadChannel channel = ((DownloadService) service) + .getDownloader(new URL("http://www.megaupload.com/?d=CVQKJ1KM")) + .download(new DownloadListener() { + @Override + public boolean timer(long time, TimerWaitReason reason) { + System.out.println("Waiting " + time + " in " + reason); + // if (reason == TimerWaitReason.DOWNLOAD_TIMER) + // return true; + return true; + } + + @Override + public String captcha(Captcha captcha) { + return null; + } + }); + final ByteArrayOutputStream bout = new ByteArrayOutputStream(); + IOUtils.copy(Channels.newInputStream(channel), bout); + System.out.println(bout.size()); + } + + @Test + public void testNoWaitDownloader() throws IOException, + MalformedURLException { + service = new MegaUploadService(ServiceConfigurationHelper.file( + MegaUploadServiceConfiguration.class, new File( + "src/test/resources/megaupload-nowait.properties"))); + + final DownloadChannel channel = ((DownloadService) service) + .getDownloader(new URL("http://www.megaupload.com/?d=CVQKJ1KM")) + .download(new DownloadListener() { + @Override + public boolean timer(long time, TimerWaitReason reason) { + System.out.println("Waiting " + time + " in " + reason); + if (reason == TimerWaitReason.DOWNLOAD_TIMER) + return true; + return false; + } + + @Override + public String captcha(Captcha captcha) { + // TODO Auto-generated method stub + return null; + } + }); + } +}