ms.safi.btsync.BTSyncApp.java Source code

Java tutorial

Introduction

Here is the source code for ms.safi.btsync.BTSyncApp.java

Source

/*
 * Copyright 2014 Omeed Safi
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package ms.safi.btsync;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.SystemUtils;
import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;

/**
 * BTSyncApp is used for starting an instance of BitTorrent Sync. A BitTorrent Sync v1.3.105 
 * executable for linux and windows platforms are bundled with this library.
 * 
 * @author Omeed Safi
 */
public class BTSyncApp implements AutoCloseable {

    private String deviceName;
    private int listeningPort;
    private boolean useUpnp;
    private String storagePath;
    private boolean useGui;
    private String listen;
    private String login;
    private String password;
    private String apiKey;

    private File btSyncTmpFolder = new File(System.getProperty("java.io.tmpdir"), "BTSyncJava");
    private File btSyncExecutable;
    private File btSyncConf = new File(btSyncTmpFolder, "sync.conf");

    private Process runningAppProcess;

    /**
     * Constructs a new BTSyncApp used to start a BitTorrent Sync instance with default
     * settings.
     * 
     * <p>Default Settings:
     * <ul>
     * <li>device_name = "BTSync-Java"
     * <li>listening_port = 0 (Meaning random port assignment)
     * <li>use_upnp = false
     * <li>storage_path = ./
     * <li>use_gui = false
     * <li>listen = 127.0.0.1:18080
     * <li>login = user
     * <li>password = password
     * </ul>
     * 
     * @param apiKey the BitTorrent Sync API Key
     */
    public BTSyncApp(String apiKey) {
        this.deviceName = "BTSyncJava";
        this.listeningPort = 0;
        this.useUpnp = false;
        this.storagePath = "./";
        this.useGui = false;
        this.listen = "127.0.0.1:18080";
        this.login = "user";
        this.password = "password";
        this.apiKey = apiKey;

        try {
            FileUtils.deleteDirectory(btSyncTmpFolder);
            Files.createDirectory(btSyncTmpFolder.toPath());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Sets the device_name for BitTorrent Sync to use. The default is <code>BTSync-Java</code>
     * 
     * @param deviceName the deviceName to set
     * @return the updated BTSyncApp instance
     */
    public BTSyncApp setDeviceName(String deviceName) {
        this.deviceName = deviceName;
        return this;
    }

    /**
     * Sets the listening_port for BitTorrent Sync to use. The default is <code>0</code> which 
     * means a port is randomly assigned
     * 
     * @param listeningPort the listeningPort to set
     * @return the updated BTSyncApp instance
     */
    public BTSyncApp setListeningPort(int listeningPort) {
        this.listeningPort = listeningPort;
        return this;
    }

    /**
     * Sets the use_upnp flag for BitTorrent Sync. The default is <code>false</code>.
     * Need more research to understand what this flag actually is for better description.
     * 
     * @param useUpnp whether BitTorrent Sync will use UPNP or not
     * @return the updated BTSyncApp instance
     */
    public BTSyncApp setUseUpnp(boolean useUpnp) {
        this.useUpnp = useUpnp;
        return this;
    }

    /**
     * Sets the storage_path for BitTorrent Sync to use. The default is <code>./</code>
     * 
     * @param storagePath the storagePath to set
     * @return the updated BTSyncApp instance
     */
    public BTSyncApp setStoragePath(String storagePath) {
        this.storagePath = storagePath;
        return this;
    }

    /**
     * Sets the use_gui for BitTorrent Sync. The default is <code>false</code>. 
     * The use_gui option sets whether or not BitTorrent Sync should be shown when running.
     * Effects of setting the use_gui value to <code>true</code> on linux is unknown as linux only has webui
     * 
     * @param useGui whether the BT Sync GUI is shown or not
     * @return the updated BTSyncApp instance
     */
    public BTSyncApp setUseGui(boolean useGui) {
        this.useGui = useGui;
        return this;
    }

    /**
     * Sets the address:port that BitTorrent Sync will listen on. The default is <code>127.0.0.1:18080</code>.
     * 
     * @param listen the address:port
     * @return the updated BTSyncApp instance
     */
    public BTSyncApp setListen(String listen) {
        this.listen = listen;
        return this;
    }

    /**
     * Sets the username for clients to use to accessing BitTorrent Sync API methods.
     * The default is <code>user</code>.
     * 
     * @param login the username
     * @return the updated BTSyncApp instance
     */
    public BTSyncApp setLogin(String login) {
        this.login = login;
        return this;
    }

    /**
     * Sets the password for clients to use to accessing BitTorrent Sync API methods.
     * The default is <code>password</code>.
     * 
     * @param password the password
     * @return the updated BTSyncApp instance
     */
    public BTSyncApp setPassword(String password) {
        this.password = password;
        return this;
    }

    /**
     * Starts BitTorrent Sync and returns an instance of BTSyncClient for accessing
     * the BitTorrent Sync API.
     * 
     * <p>See the class description for the current limitations of this method. 
     * 
     * @return a BTSyncClient preconfigured for accessing the BitTorrent Sync started
     */
    public BTSyncClient startBtSync() {
        if (SystemUtils.IS_OS_WINDOWS) {
            btSyncExecutable = new File(btSyncTmpFolder, "btsync.exe");
            return this.startBtSyncWindows();
        } else if (SystemUtils.IS_OS_UNIX) {
            btSyncExecutable = new File(btSyncTmpFolder, "btsync");
            return this.startBtSyncLinux();
        } else if (SystemUtils.IS_OS_MAC_OSX) {
            return this.startBtSyncMacOsx();
        } else {
            return null;
        }
    }

    private BTSyncClient startBtSyncWindows() {
        this.extractWinBtSync();
        this.buildConf();

        try {
            //Print this line using logging api
            //System.out.println(btSyncExecutable.getCanonicalPath() + " /config " + btSyncConf.getCanonicalPath());
            runningAppProcess = Runtime.getRuntime()
                    .exec(btSyncExecutable.getCanonicalPath() + " /config " + btSyncConf.getCanonicalPath());
        } catch (IOException e) {
            e.printStackTrace();
        }

        return new BTSyncClient(this.listen, this.login, this.password);
    }

    private BTSyncClient startBtSyncLinux() {
        this.extractLinuxBtSync();
        this.buildConf();

        try {
            //Print this line using logging api
            //System.out.println(btSyncExecutable.getCanonicalPath() + " --config " + btSyncConf.getCanonicalPath());
            runningAppProcess = Runtime.getRuntime()
                    .exec(btSyncExecutable.getCanonicalPath() + " --config " + btSyncConf.getCanonicalPath());
        } catch (IOException e) {
            e.printStackTrace();
        }

        return new BTSyncClient(this.listen, this.login, this.password);
    }

    private BTSyncClient startBtSyncMacOsx() {
        return null;
    }

    private void buildConf() {
        try {
            Files.createFile(btSyncConf.toPath());
            btSyncConf.setReadable(true, false);
            btSyncConf.setWritable(true, false);

            JsonFactory jFactory = new JsonFactory();
            JsonGenerator jGenerator = jFactory.createJsonGenerator(btSyncConf, JsonEncoding.UTF8);
            jGenerator.useDefaultPrettyPrinter();

            jGenerator.writeStartObject(); // {
            jGenerator.writeStringField("device_name", this.deviceName);
            jGenerator.writeNumberField("listening_port", this.listeningPort);
            jGenerator.writeBooleanField("check_for_updates", false); // NEVER CHECK FOR UPDATES
            jGenerator.writeBooleanField("use_upnp", useUpnp);
            jGenerator.writeStringField("storage_path", this.storagePath);
            jGenerator.writeBooleanField("use_gui", this.useGui);
            jGenerator.writeFieldName("webui");
            jGenerator.writeStartObject(); // {
            jGenerator.writeStringField("listen", this.listen);
            jGenerator.writeStringField("login", this.login);
            jGenerator.writeStringField("password", this.password);
            jGenerator.writeStringField("api_key", this.apiKey);
            jGenerator.writeEndObject(); // }
            jGenerator.writeEndObject(); // }

            jGenerator.close();
        } catch (JsonGenerationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void extractWinBtSync() {
        try {
            URL url = getClass().getClassLoader().getResource("btsync-win.exe");
            InputStream in = url.openStream();

            Files.copy(in, btSyncExecutable.toPath());
            btSyncExecutable.setExecutable(true, false);
            btSyncExecutable.setReadable(true, false);
            btSyncExecutable.setWritable(true, false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void extractLinuxBtSync() {
        try {
            URL url = getClass().getClassLoader().getResource("btsync-linux-i386");
            InputStream in = url.openStream();

            Files.copy(in, btSyncExecutable.toPath());
            btSyncExecutable.setExecutable(true, false);
            btSyncExecutable.setReadable(true, false);
            btSyncExecutable.setWritable(true, false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void close() {
        // Close BTSync if running
        if (isAlive(runningAppProcess)) {
            runningAppProcess.destroy();
            try {
                runningAppProcess.waitFor();
            } catch (InterruptedException e) {
                System.out.println("Exception while waiting for the BTSync process to end");
                e.printStackTrace();
            }
        }

        // Cleanup files
        try {
            FileUtils.deleteDirectory(btSyncTmpFolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean isAlive(Process p) {
        try {
            p.exitValue();
            return false;
        } catch (IllegalThreadStateException e) {
            return true;
        }
    }
}