org.transdroid.daemon.BuffaloNas.BuffaloNasAdapter.java Source code

Java tutorial

Introduction

Here is the source code for org.transdroid.daemon.BuffaloNas.BuffaloNasAdapter.java

Source

/*
 *   This file is part of Transdroid <http://www.transdroid.org>
 *   
 *   Transdroid is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *   
 *   Transdroid is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *   
 *   You should have received a copy of the GNU General Public License
 *   along with Transdroid.  If not, see <http://www.gnu.org/licenses/>.
 *   
 */
package org.transdroid.daemon.BuffaloNas;

import com.android.internalcopy.http.multipart.FilePart;
import com.android.internalcopy.http.multipart.MultipartEntity;
import com.android.internalcopy.http.multipart.Part;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.transdroid.core.gui.log.Log;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.DaemonException;
import org.transdroid.daemon.DaemonException.ExceptionType;
import org.transdroid.daemon.DaemonSettings;
import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.Priority;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentFile;
import org.transdroid.daemon.TorrentStatus;
import org.transdroid.daemon.task.AddByFileTask;
import org.transdroid.daemon.task.AddByUrlTask;
import org.transdroid.daemon.task.DaemonTask;
import org.transdroid.daemon.task.DaemonTaskFailureResult;
import org.transdroid.daemon.task.DaemonTaskResult;
import org.transdroid.daemon.task.DaemonTaskSuccessResult;
import org.transdroid.daemon.task.GetFileListTask;
import org.transdroid.daemon.task.GetFileListTaskSuccessResult;
import org.transdroid.daemon.task.RemoveTask;
import org.transdroid.daemon.task.RetrieveTask;
import org.transdroid.daemon.task.RetrieveTaskSuccessResult;
import org.transdroid.daemon.task.SetTransferRatesTask;
import org.transdroid.daemon.util.HttpHelper;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.ArrayList;

/**
 * The daemon adapter for the Buffalo NAS' integrated torrent client.
 * @author erickok
 */
public class BuffaloNasAdapter implements IDaemonAdapter {

    private static final String LOG_NAME = "qBittorrent daemon";

    private DaemonSettings settings;
    private DefaultHttpClient httpclient;

    public BuffaloNasAdapter(DaemonSettings settings) {
        this.settings = settings;
    }

    @Override
    public DaemonTaskResult executeTask(Log log, DaemonTask task) {

        try {
            switch (task.getMethod()) {
            case Retrieve:

                // Request all torrents from server
                JSONObject result = new JSONObject(makeRequest(log, "/api/torrents-get"));
                return new RetrieveTaskSuccessResult((RetrieveTask) task, parseJsonTorrents(result), null);

            case GetFileList:

                // Request files listing for a specific torrent
                String fhash = task.getTargetTorrent().getUniqueID();
                JSONObject files = new JSONObject(
                        makeRequest(log, "/api/torrent-get-files", new BasicNameValuePair("hash", fhash)));
                return new GetFileListTaskSuccessResult((GetFileListTask) task, parseJsonFiles(files, fhash));

            case AddByFile:

                // Upload a local .torrent file
                String ufile = ((AddByFileTask) task).getFile();
                makeUploadRequest(log, "/api/torrent-add?start=yes", ufile);
                return new DaemonTaskSuccessResult(task);

            case AddByUrl:

                // Request to add a torrent by URL
                String url = ((AddByUrlTask) task).getUrl();
                // @formatter:off
                makeRequest(log, "/api/torrent-add", new BasicNameValuePair("url", url),
                        new BasicNameValuePair("start", "yes"));
                // @formatter:on
                return new DaemonTaskSuccessResult(task);

            case Remove:

                // Remove a torrent
                RemoveTask removeTask = (RemoveTask) task;
                // @formatter:off
                makeRequest(log, "/api/torrent-remove",
                        new BasicNameValuePair("hash", removeTask.getTargetTorrent().getUniqueID()),
                        new BasicNameValuePair("delete-torrent", "yes"),
                        new BasicNameValuePair("delete-data", (removeTask.includingData() ? "yes" : "no")));
                // @formatter:on
                return new DaemonTaskSuccessResult(task);

            case Pause:

                // Pause a torrent
                makeRequest(log, "/api/torrent-stop",
                        new BasicNameValuePair("hash", task.getTargetTorrent().getUniqueID()));
                return new DaemonTaskSuccessResult(task);

            case Resume:

                // Resume a torrent
                makeRequest(log, "/api/torrent-start",
                        new BasicNameValuePair("hash", task.getTargetTorrent().getUniqueID()));
                return new DaemonTaskSuccessResult(task);

            case SetTransferRates:

                // Request to set the maximum transfer rates
                SetTransferRatesTask ratesTask = (SetTransferRatesTask) task;
                String dl = Integer
                        .toString((ratesTask.getDownloadRate() == null ? -1 : ratesTask.getDownloadRate() * 1024));
                String ul = Integer
                        .toString((ratesTask.getUploadRate() == null ? -1 : ratesTask.getUploadRate() * 1024));
                // @formatter:off
                makeRequest(log, "/api/app-settings-set", new BasicNameValuePair("auto_bandwidth_management", "0"),
                        new BasicNameValuePair("max_dl_rate", dl), new BasicNameValuePair("max_ul_rate", ul),
                        new BasicNameValuePair("max_ul_rate_seed", ul));
                // @formatter:on
                return new DaemonTaskSuccessResult(task);

            default:
                return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported,
                        task.getMethod() + " is not supported by " + getType()));
            }
        } catch (JSONException e) {
            return new DaemonTaskFailureResult(task,
                    new DaemonException(ExceptionType.ParsingFailed, e.toString()));
        } catch (DaemonException e) {
            return new DaemonTaskFailureResult(task, e);
        }
    }

    private String makeRequest(Log log, String url, NameValuePair... params) throws DaemonException {

        try {

            // Initialise the HTTP client
            if (httpclient == null) {
                initialise();
            }

            // Add the parameters to the query string
            boolean first = true;
            for (NameValuePair param : params) {
                if (first) {
                    url += "?";
                    first = false;
                } else {
                    url += "&";
                }
                url += param.getName() + "=" + param.getValue();
            }

            // Make the request
            HttpResponse response = httpclient.execute(new HttpGet(buildWebUIUrl(url)));
            HttpEntity entity = response.getEntity();
            if (entity != null) {

                // Read JSON response
                java.io.InputStream instream = entity.getContent();
                String result = HttpHelper.convertStreamToString(instream);
                instream.close();

                // Return raw result
                return result;
            }

            log.d(LOG_NAME, "Error: No entity in HTTP response");
            throw new DaemonException(ExceptionType.UnexpectedResponse, "No HTTP entity object in response.");

        } catch (UnsupportedEncodingException e) {
            throw new DaemonException(ExceptionType.ConnectionError, e.toString());
        } catch (Exception e) {
            log.d(LOG_NAME, "Error: " + e.toString());
            throw new DaemonException(ExceptionType.ConnectionError, e.toString());
        }

    }

    private boolean makeUploadRequest(Log log, String path, String file) throws DaemonException {

        try {

            // Initialise the HTTP client
            if (httpclient == null) {
                initialise();
            }

            // Setup request using POST
            HttpPost httppost = new HttpPost(buildWebUIUrl(path));
            File upload = new File(URI.create(file));
            Part[] parts = { new FilePart("fileEl", upload) };
            httppost.setEntity(new MultipartEntity(parts, httppost.getParams()));

            // Make the request
            HttpResponse response = httpclient.execute(httppost);
            return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK;

        } catch (FileNotFoundException e) {
            throw new DaemonException(ExceptionType.FileAccessError, e.toString());
        } catch (Exception e) {
            log.d(LOG_NAME, "Error: " + e.toString());
            throw new DaemonException(ExceptionType.ConnectionError, e.toString());
        }

    }

    /**
     * Instantiates an HTTP client with proper credentials that can be used for all Buffalo NAS requests.
     * @throws DaemonException On conflicting or missing settings
     */
    private void initialise() throws DaemonException {

        httpclient = HttpHelper.createStandardHttpClient(settings, true);

    }

    /**
     * Build the URL of the http request from the user settings
     * @return The URL to request
     */
    private String buildWebUIUrl(String path) {
        return (settings.getSsl() ? "https://" : "http://") + settings.getAddress() + ":" + settings.getPort()
                + path;
    }

    private ArrayList<Torrent> parseJsonTorrents(JSONObject response) throws JSONException {

        // Parse response
        ArrayList<Torrent> torrents = new ArrayList<Torrent>();
        JSONArray all = response.getJSONArray("torrents");
        for (int i = 0; i < all.length(); i++) {
            JSONObject tor = all.getJSONObject(i);
            int peersConnected = tor.getInt("peers_connected");
            int seedsConnected = tor.getInt("seeds_connected");
            int peersTotal = tor.getInt("peers_total");
            int seedsTotal = tor.getInt("seeds_total");
            long size = tor.getLong("size");
            long sizeDone = tor.getLong("done");
            long sizeUp = tor.getLong("payload_upload");
            int rateUp = tor.getInt("dl_rate");
            int rateDown = tor.getInt("ul_rate");
            // Add the parsed torrent to the list
            // @formatter:off
            torrents.add(new Torrent((long) i, tor.getString("hash"), tor.getString("caption"),
                    parseStatus(tor.getString("state"), tor.getInt("stopped")), null, rateDown, rateUp,
                    seedsConnected, seedsTotal, peersConnected, peersTotal,
                    (rateDown == 0 ? -1 : (int) ((size - sizeDone) / rateDown)), sizeDone, sizeUp, size,
                    (float) sizeDone / size, (float) tor.getDouble("distributed_copies") / 10, null, null, null,
                    null, settings.getType()));
            // @formatter:on
        }

        // Return the list
        return torrents;

    }

    private TorrentStatus parseStatus(String state, int stopped) {
        // Status is given as a descriptive string and an indication if the torrent was stopped/paused
        if (state.equals("downloading")) {
            if (stopped == 1) {
                return TorrentStatus.Paused;
            } else {
                return TorrentStatus.Downloading;
            }
        } else if (state.equals("seeding")) {
            if (stopped == 1) {
                return TorrentStatus.Paused;
            } else {
                return TorrentStatus.Seeding;
            }
        }
        return TorrentStatus.Unknown;
    }

    private ArrayList<TorrentFile> parseJsonFiles(JSONObject response, String hash) throws JSONException {

        // Parse response
        ArrayList<TorrentFile> torrentfiles = new ArrayList<TorrentFile>();
        JSONArray all = response.getJSONObject("torrents").getJSONArray(hash);
        for (int i = 0; i < all.length(); i++) {
            JSONObject file = all.getJSONObject(i);
            long size = file.getLong("size");
            long sizeDone = file.getLong("done");
            // @formatter:off
            torrentfiles.add(new TorrentFile("" + file.getInt("id"), file.getString("name"), file.getString("name"),
                    settings.getDownloadDir() + file.getString("name"), size, sizeDone, Priority.Normal));
            // @formatter:on
        }

        // Return the list
        return torrentfiles;

    }

    @Override
    public Daemon getType() {
        return settings.getType();
    }

    @Override
    public DaemonSettings getSettings() {
        return this.settings;
    }

}