mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-20 22:59:54 +01:00
Remove RemovableDrivePlugin, refactor plugin interface.
This commit is contained in:
@@ -50,7 +50,6 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -334,7 +333,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
return zin;
|
return zin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getConfigInputStream() throws IOException {
|
private InputStream getConfigInputStream() {
|
||||||
int resId = getResourceId("torrc");
|
int resId = getResourceId("torrc");
|
||||||
return appContext.getResources().openRawResource(resId);
|
return appContext.getResources().openRawResource(resId);
|
||||||
}
|
}
|
||||||
@@ -499,7 +498,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() throws PluginException {
|
public void stop() {
|
||||||
running = false;
|
running = false;
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
if (networkStateReceiver != null)
|
if (networkStateReceiver != null)
|
||||||
@@ -533,20 +532,16 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Map<ContactId, TransportProperties> contacts) {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
Map<ContactId, TransportProperties> remote =
|
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
|
||||||
callback.getRemoteProperties();
|
connectAndCallBack(e.getKey(), e.getValue());
|
||||||
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
|
||||||
ContactId c = e.getKey();
|
|
||||||
if (!connected.contains(c)) connectAndCallBack(c, e.getValue());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectAndCallBack(ContactId c, TransportProperties p) {
|
private void connectAndCallBack(ContactId c, TransportProperties p) {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
if (!isRunning()) return;
|
|
||||||
DuplexTransportConnection d = createConnection(p);
|
DuplexTransportConnection d = createConnection(p);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
@@ -556,13 +551,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(TransportProperties p) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
return createConnection(callback.getRemoteProperties(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private DuplexTransportConnection createConnection(TransportProperties p) {
|
|
||||||
String onion = p.get(PROP_ONION);
|
String onion = p.get(PROP_ONION);
|
||||||
if (StringUtils.isNullOrEmpty(onion)) return null;
|
if (StringUtils.isNullOrEmpty(onion)) return null;
|
||||||
if (!ONION.matcher(onion).matches()) {
|
if (!ONION.matcher(onion).matches()) {
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.briarproject.bramble.api.plugin;
|
||||||
|
|
||||||
|
public interface FileConstants {
|
||||||
|
|
||||||
|
String PROP_PATH = "path";
|
||||||
|
}
|
||||||
@@ -2,8 +2,9 @@ package org.briarproject.bramble.api.plugin;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Map;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface Plugin {
|
public interface Plugin {
|
||||||
@@ -39,21 +40,19 @@ public interface Plugin {
|
|||||||
boolean isRunning();
|
boolean isRunning();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the plugin's {@link #poll(Collection)} method should be
|
* Returns true if the plugin should be polled periodically to attempt to
|
||||||
* called periodically to attempt to establish connections.
|
* establish connections.
|
||||||
*/
|
*/
|
||||||
boolean shouldPoll();
|
boolean shouldPoll();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the desired interval in milliseconds between calls to the
|
* Returns the desired interval in milliseconds between polling attempts.
|
||||||
* plugin's {@link #poll(Collection)} method.
|
|
||||||
*/
|
*/
|
||||||
int getPollingInterval();
|
int getPollingInterval();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to establish connections to contacts, passing any created
|
* Attempts to establish connections to the given contacts, passing any
|
||||||
* connections to the callback. To avoid creating redundant connections,
|
* created connections to the callback.
|
||||||
* the plugin may exclude the given contacts from polling.
|
|
||||||
*/
|
*/
|
||||||
void poll(Collection<ContactId> connected);
|
void poll(Map<ContactId, TransportProperties> contacts);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
package org.briarproject.bramble.api.plugin;
|
package org.briarproject.bramble.api.plugin;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface through which a transport plugin interacts with the rest of
|
* An interface through which a transport plugin interacts with the rest of
|
||||||
* the application.
|
* the application.
|
||||||
@@ -25,17 +22,7 @@ public interface PluginCallback {
|
|||||||
TransportProperties getLocalProperties();
|
TransportProperties getLocalProperties();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the plugin's remote transport properties.
|
* Merges the given settings with the plugin's settings
|
||||||
*/
|
|
||||||
Map<ContactId, TransportProperties> getRemoteProperties();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the plugin's remote transport properties for the given contact.
|
|
||||||
*/
|
|
||||||
TransportProperties getRemoteProperties(ContactId c);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merges the given settings with the namespaced settings
|
|
||||||
*/
|
*/
|
||||||
void mergeSettings(Settings s);
|
void mergeSettings(Settings s);
|
||||||
|
|
||||||
@@ -45,34 +32,12 @@ public interface PluginCallback {
|
|||||||
void mergeLocalProperties(TransportProperties p);
|
void mergeLocalProperties(TransportProperties p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Presents the user with a choice among two or more named options and
|
* Signals that the transport is enabled.
|
||||||
* returns the user's response. The message may consist of a translatable
|
|
||||||
* format string and arguments.
|
|
||||||
*
|
|
||||||
* @return an index into the array of options indicating the user's choice,
|
|
||||||
* or -1 if the user cancelled the choice.
|
|
||||||
*/
|
|
||||||
int showChoice(String[] options, String... message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asks the user to confirm an action and returns the user's response. The
|
|
||||||
* message may consist of a translatable format string and arguments.
|
|
||||||
*/
|
|
||||||
boolean showConfirmationMessage(String... message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a message to the user. The message may consist of a translatable
|
|
||||||
* format string and arguments.
|
|
||||||
*/
|
|
||||||
void showMessage(String... message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signal that the transport got enabled.
|
|
||||||
*/
|
*/
|
||||||
void transportEnabled();
|
void transportEnabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal that the transport got disabled.
|
* Signals that the transport is disabled.
|
||||||
*/
|
*/
|
||||||
void transportDisabled();
|
void transportDisabled();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,6 @@ public interface TransportConnectionWriter {
|
|||||||
*/
|
*/
|
||||||
int getMaxIdleTime();
|
int getMaxIdleTime();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the capacity of the transport connection in bytes.
|
|
||||||
*/
|
|
||||||
long getCapacity();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an output stream for writing to the transport connection.
|
* Returns an output stream for writing to the transport connection.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -71,11 +71,6 @@ public abstract class AbstractDuplexTransportConnection
|
|||||||
return plugin.getMaxIdleTime();
|
return plugin.getMaxIdleTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getCapacity() {
|
|
||||||
return Long.MAX_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutputStream getOutputStream() throws IOException {
|
public OutputStream getOutputStream() throws IOException {
|
||||||
return AbstractDuplexTransportConnection.this.getOutputStream();
|
return AbstractDuplexTransportConnection.this.getOutputStream();
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package org.briarproject.bramble.api.plugin.duplex;
|
package org.briarproject.bramble.api.plugin.duplex;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -15,12 +15,11 @@ import javax.annotation.Nullable;
|
|||||||
public interface DuplexPlugin extends Plugin {
|
public interface DuplexPlugin extends Plugin {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to create and return a connection to the given contact using
|
* Attempts to create and return a connection using the given transport
|
||||||
* the current transport and configuration properties. Returns null if a
|
* properties. Returns null if a connection cannot be created.
|
||||||
* connection cannot be created.
|
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
DuplexTransportConnection createConnection(ContactId c);
|
DuplexTransportConnection createConnection(TransportProperties p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the plugin supports short-range key agreement.
|
* Returns true if the plugin supports short-range key agreement.
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.plugin.PluginCallback;
|
import org.briarproject.bramble.api.plugin.PluginCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for handling connections created by a duplex transport plugin.
|
* An interface through which a duplex plugin interacts with the rest of the
|
||||||
|
* application.
|
||||||
*/
|
*/
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface DuplexPluginCallback extends PluginCallback {
|
public interface DuplexPluginCallback extends PluginCallback {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package org.briarproject.bramble.api.plugin.simplex;
|
package org.briarproject.bramble.api.plugin.simplex;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -15,18 +15,16 @@ import javax.annotation.Nullable;
|
|||||||
public interface SimplexPlugin extends Plugin {
|
public interface SimplexPlugin extends Plugin {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to create and return a reader for the given contact using the
|
* Attempts to create and return a reader for the given transport
|
||||||
* current transport and configuration properties. Returns null if a reader
|
* properties. Returns null if a reader cannot be created.
|
||||||
* cannot be created.
|
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
TransportConnectionReader createReader(ContactId c);
|
TransportConnectionReader createReader(TransportProperties p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to create and return a writer for the given contact using the
|
* Attempts to create and return a writer for the given transport
|
||||||
* current transport and configuration properties. Returns null if a writer
|
* properties. Returns null if a writer cannot be created.
|
||||||
* cannot be created.
|
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
TransportConnectionWriter createWriter(ContactId c);
|
TransportConnectionWriter createWriter(TransportProperties p);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
|||||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for handling readers and writers created by a simplex transport
|
* An interface through which a simplex plugin interacts with the rest of the
|
||||||
* plugin.
|
* application.
|
||||||
*/
|
*/
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface SimplexPluginCallback extends PluginCallback {
|
public interface SimplexPluginCallback extends PluginCallback {
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.ui;
|
|
||||||
|
|
||||||
public interface UiCallback {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Presents the user with a choice among two or more named options and
|
|
||||||
* returns the user's response. The message may consist of a translatable
|
|
||||||
* format string and arguments.
|
|
||||||
*
|
|
||||||
* @return an index into the array of options indicating the user's choice,
|
|
||||||
* or -1 if the user cancelled the choice.
|
|
||||||
*/
|
|
||||||
int showChoice(String[] options, String... message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asks the user to confirm an action and returns the user's response. The
|
|
||||||
* message may consist of a translatable format string and arguments.
|
|
||||||
*/
|
|
||||||
boolean showConfirmationMessage(String... message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a message to the user. The message may consist of a translatable
|
|
||||||
* format string and arguments.
|
|
||||||
*/
|
|
||||||
void showMessage(String... message);
|
|
||||||
}
|
|
||||||
@@ -22,19 +22,6 @@ public class OsUtils {
|
|||||||
return os != null && os.contains("Mac OS");
|
return os != null && os.contains("Mac OS");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isMacLeopardOrNewer() {
|
|
||||||
if (!isMac() || version == null) return false;
|
|
||||||
try {
|
|
||||||
String[] v = version.split("\\.");
|
|
||||||
if (v.length != 3) return false;
|
|
||||||
int major = Integer.parseInt(v[0]);
|
|
||||||
int minor = Integer.parseInt(v[1]);
|
|
||||||
return major >= 10 && minor >= 5;
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isLinux() {
|
public static boolean isLinux() {
|
||||||
return os != null && os.contains("Linux") && !isAndroid();
|
return os != null && os.contains("Linux") && !isAndroid();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,12 +32,10 @@ import org.briarproject.bramble.api.settings.Settings;
|
|||||||
import org.briarproject.bramble.api.settings.SettingsManager;
|
import org.briarproject.bramble.api.settings.SettingsManager;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
import org.briarproject.bramble.api.ui.UiCallback;
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@@ -71,7 +69,6 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
private final TransportPropertyManager transportPropertyManager;
|
private final TransportPropertyManager transportPropertyManager;
|
||||||
private final SecureRandom random;
|
private final SecureRandom random;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final UiCallback uiCallback;
|
|
||||||
private final Map<TransportId, Plugin> plugins;
|
private final Map<TransportId, Plugin> plugins;
|
||||||
private final List<SimplexPlugin> simplexPlugins;
|
private final List<SimplexPlugin> simplexPlugins;
|
||||||
private final List<DuplexPlugin> duplexPlugins;
|
private final List<DuplexPlugin> duplexPlugins;
|
||||||
@@ -85,8 +82,7 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
ConnectionRegistry connectionRegistry,
|
ConnectionRegistry connectionRegistry,
|
||||||
SettingsManager settingsManager,
|
SettingsManager settingsManager,
|
||||||
TransportPropertyManager transportPropertyManager,
|
TransportPropertyManager transportPropertyManager,
|
||||||
SecureRandom random, Clock clock,
|
SecureRandom random, Clock clock) {
|
||||||
UiCallback uiCallback) {
|
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
@@ -97,7 +93,6 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
this.transportPropertyManager = transportPropertyManager;
|
this.transportPropertyManager = transportPropertyManager;
|
||||||
this.random = random;
|
this.random = random;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.uiCallback = uiCallback;
|
|
||||||
plugins = new ConcurrentHashMap<>();
|
plugins = new ConcurrentHashMap<>();
|
||||||
simplexPlugins = new CopyOnWriteArrayList<>();
|
simplexPlugins = new CopyOnWriteArrayList<>();
|
||||||
duplexPlugins = new CopyOnWriteArrayList<>();
|
duplexPlugins = new CopyOnWriteArrayList<>();
|
||||||
@@ -106,13 +101,14 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startService() throws ServiceException {
|
public void startService() {
|
||||||
if (used.getAndSet(true)) throw new IllegalStateException();
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
// Instantiate the poller
|
// Instantiate the poller
|
||||||
if (pluginConfig.shouldPoll()) {
|
if (pluginConfig.shouldPoll()) {
|
||||||
LOG.info("Starting poller");
|
LOG.info("Starting poller");
|
||||||
Poller poller = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller poller = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, this, random, clock);
|
connectionRegistry, this, transportPropertyManager, random,
|
||||||
|
clock);
|
||||||
eventBus.addListener(poller);
|
eventBus.addListener(poller);
|
||||||
}
|
}
|
||||||
// Instantiate the simplex plugins and start them asynchronously
|
// Instantiate the simplex plugins and start them asynchronously
|
||||||
@@ -297,26 +293,6 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<ContactId, TransportProperties> getRemoteProperties() {
|
|
||||||
try {
|
|
||||||
return transportPropertyManager.getRemoteProperties(id);
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransportProperties getRemoteProperties(ContactId c) {
|
|
||||||
try {
|
|
||||||
return transportPropertyManager.getRemoteProperties(c, id);
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
return new TransportProperties();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mergeSettings(Settings s) {
|
public void mergeSettings(Settings s) {
|
||||||
try {
|
try {
|
||||||
@@ -335,21 +311,6 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int showChoice(String[] options, String... message) {
|
|
||||||
return uiCallback.showChoice(options, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean showConfirmationMessage(String... message) {
|
|
||||||
return uiCallback.showConfirmationMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showMessage(String... message) {
|
|
||||||
uiCallback.showMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void transportEnabled() {
|
public void transportEnabled() {
|
||||||
eventBus.broadcast(new TransportEnabledEvent(id));
|
eventBus.broadcast(new TransportEnabledEvent(id));
|
||||||
|
|||||||
@@ -1,18 +1,10 @@
|
|||||||
package org.briarproject.bramble.plugin;
|
package org.briarproject.bramble.plugin;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
||||||
import org.briarproject.bramble.api.plugin.PluginManager;
|
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.plugin;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
@@ -19,10 +20,13 @@ import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
|
|||||||
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -33,10 +37,10 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -49,6 +53,7 @@ class Poller implements EventListener {
|
|||||||
private final ConnectionManager connectionManager;
|
private final ConnectionManager connectionManager;
|
||||||
private final ConnectionRegistry connectionRegistry;
|
private final ConnectionRegistry connectionRegistry;
|
||||||
private final PluginManager pluginManager;
|
private final PluginManager pluginManager;
|
||||||
|
private final TransportPropertyManager transportPropertyManager;
|
||||||
private final SecureRandom random;
|
private final SecureRandom random;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final Lock lock;
|
private final Lock lock;
|
||||||
@@ -58,12 +63,14 @@ class Poller implements EventListener {
|
|||||||
@Scheduler ScheduledExecutorService scheduler,
|
@Scheduler ScheduledExecutorService scheduler,
|
||||||
ConnectionManager connectionManager,
|
ConnectionManager connectionManager,
|
||||||
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
|
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
|
||||||
|
TransportPropertyManager transportPropertyManager,
|
||||||
SecureRandom random, Clock clock) {
|
SecureRandom random, Clock clock) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.connectionManager = connectionManager;
|
this.connectionManager = connectionManager;
|
||||||
this.connectionRegistry = connectionRegistry;
|
this.connectionRegistry = connectionRegistry;
|
||||||
this.pluginManager = pluginManager;
|
this.pluginManager = pluginManager;
|
||||||
|
this.transportPropertyManager = transportPropertyManager;
|
||||||
this.random = random;
|
this.random = random;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
lock = new ReentrantLock();
|
lock = new ReentrantLock();
|
||||||
@@ -119,10 +126,15 @@ class Poller implements EventListener {
|
|||||||
private void connectToContact(ContactId c, SimplexPlugin p) {
|
private void connectToContact(ContactId c, SimplexPlugin p) {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
TransportId t = p.getId();
|
TransportId t = p.getId();
|
||||||
if (!connectionRegistry.isConnected(c, t)) {
|
if (connectionRegistry.isConnected(c, t)) return;
|
||||||
TransportConnectionWriter w = p.createWriter(c);
|
try {
|
||||||
|
TransportProperties props =
|
||||||
|
transportPropertyManager.getRemoteProperties(c, t);
|
||||||
|
TransportConnectionWriter w = p.createWriter(props);
|
||||||
if (w != null)
|
if (w != null)
|
||||||
connectionManager.manageOutgoingConnection(c, t, w);
|
connectionManager.manageOutgoingConnection(c, t, w);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -130,10 +142,15 @@ class Poller implements EventListener {
|
|||||||
private void connectToContact(ContactId c, DuplexPlugin p) {
|
private void connectToContact(ContactId c, DuplexPlugin p) {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
TransportId t = p.getId();
|
TransportId t = p.getId();
|
||||||
if (!connectionRegistry.isConnected(c, t)) {
|
if (connectionRegistry.isConnected(c, t)) return;
|
||||||
DuplexTransportConnection d = p.createConnection(c);
|
try {
|
||||||
|
TransportProperties props =
|
||||||
|
transportPropertyManager.getRemoteProperties(c, t);
|
||||||
|
DuplexTransportConnection d = p.createConnection(props);
|
||||||
if (d != null)
|
if (d != null)
|
||||||
connectionManager.manageOutgoingConnection(c, t, d);
|
connectionManager.manageOutgoingConnection(c, t, d);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -185,7 +202,17 @@ class Poller implements EventListener {
|
|||||||
private void poll(Plugin p) {
|
private void poll(Plugin p) {
|
||||||
TransportId t = p.getId();
|
TransportId t = p.getId();
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Polling plugin " + t);
|
if (LOG.isLoggable(INFO)) LOG.info("Polling plugin " + t);
|
||||||
p.poll(connectionRegistry.getConnectedContacts(t));
|
try {
|
||||||
|
Map<ContactId, TransportProperties> remote =
|
||||||
|
transportPropertyManager.getRemoteProperties(t);
|
||||||
|
Collection<ContactId> connected =
|
||||||
|
connectionRegistry.getConnectedContacts(t);
|
||||||
|
remote = new HashMap<>(remote);
|
||||||
|
remote.keySet().removeAll(connected);
|
||||||
|
if (!remote.isEmpty()) p.poll(remote);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ScheduledPollTask {
|
private class ScheduledPollTask {
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import org.briarproject.bramble.util.StringUtils;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -250,19 +249,16 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Map<ContactId, TransportProperties> contacts) {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return;
|
if (!isRunning() || !shouldAllowContactConnections()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
// Try to connect to known devices in parallel
|
// Try to connect to known devices in parallel
|
||||||
Map<ContactId, TransportProperties> remote =
|
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
|
||||||
callback.getRemoteProperties();
|
|
||||||
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
|
||||||
ContactId c = e.getKey();
|
|
||||||
if (connected.contains(c)) continue;
|
|
||||||
String address = e.getValue().get(PROP_ADDRESS);
|
String address = e.getValue().get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) continue;
|
if (StringUtils.isNullOrEmpty(address)) continue;
|
||||||
String uuid = e.getValue().get(PROP_UUID);
|
String uuid = e.getValue().get(PROP_UUID);
|
||||||
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
||||||
|
ContactId c = e.getKey();
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return;
|
if (!isRunning() || !shouldAllowContactConnections()) return;
|
||||||
if (!connectionLimiter.canOpenContactConnection()) return;
|
if (!connectionLimiter.canOpenContactConnection()) return;
|
||||||
@@ -308,10 +304,9 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(TransportProperties p) {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return null;
|
if (!isRunning() || !shouldAllowContactConnections()) return null;
|
||||||
if (!connectionLimiter.canOpenContactConnection()) return null;
|
if (!connectionLimiter.canOpenContactConnection()) return null;
|
||||||
TransportProperties p = callback.getRemoteProperties(c);
|
|
||||||
String address = p.get(PROP_ADDRESS);
|
String address = p.get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||||
String uuid = p.get(PROP_UUID);
|
String uuid = p.get(PROP_UUID);
|
||||||
|
|||||||
@@ -1,27 +1,21 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
package org.briarproject.bramble.plugin.file;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MIN_STREAM_LENGTH;
|
import static org.briarproject.bramble.api.plugin.FileConstants.PROP_PATH;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
abstract class FilePlugin implements SimplexPlugin {
|
abstract class FilePlugin implements SimplexPlugin {
|
||||||
@@ -29,25 +23,15 @@ abstract class FilePlugin implements SimplexPlugin {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(FilePlugin.class.getName());
|
Logger.getLogger(FilePlugin.class.getName());
|
||||||
|
|
||||||
protected final Executor ioExecutor;
|
|
||||||
protected final SimplexPluginCallback callback;
|
protected final SimplexPluginCallback callback;
|
||||||
protected final int maxLatency;
|
protected final int maxLatency;
|
||||||
protected final AtomicBoolean used = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
protected volatile boolean running = false;
|
protected abstract void writerFinished(File f, boolean exception);
|
||||||
|
|
||||||
@Nullable
|
protected abstract void readerFinished(File f, boolean exception,
|
||||||
protected abstract File chooseOutputDirectory();
|
boolean recognised);
|
||||||
|
|
||||||
protected abstract Collection<File> findFilesByName(String filename);
|
FilePlugin(SimplexPluginCallback callback, int maxLatency) {
|
||||||
|
|
||||||
protected abstract void writerFinished(File f);
|
|
||||||
|
|
||||||
protected abstract void readerFinished(File f);
|
|
||||||
|
|
||||||
protected FilePlugin(Executor ioExecutor, SimplexPluginCallback callback,
|
|
||||||
int maxLatency) {
|
|
||||||
this.ioExecutor = ioExecutor;
|
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
}
|
}
|
||||||
@@ -58,81 +42,36 @@ abstract class FilePlugin implements SimplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMaxIdleTime() {
|
public TransportConnectionReader createReader(TransportProperties p) {
|
||||||
return Integer.MAX_VALUE; // We don't need keepalives
|
if (!isRunning()) return null;
|
||||||
}
|
String path = p.get(PROP_PATH);
|
||||||
|
if (isNullOrEmpty(path)) return null;
|
||||||
@Override
|
|
||||||
public boolean isRunning() {
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransportConnectionReader createReader(ContactId c) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransportConnectionWriter createWriter(ContactId c) {
|
|
||||||
if (!running) return null;
|
|
||||||
return createWriter(createConnectionFilename());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String createConnectionFilename() {
|
|
||||||
StringBuilder s = new StringBuilder(12);
|
|
||||||
for (int i = 0; i < 8; i++) s.append((char) ('a' + Math.random() * 26));
|
|
||||||
s.append(".dat");
|
|
||||||
return s.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Package access for testing
|
|
||||||
boolean isPossibleConnectionFilename(String filename) {
|
|
||||||
return filename.toLowerCase(Locale.US).matches("[a-z]{8}\\.dat");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private TransportConnectionWriter createWriter(String filename) {
|
|
||||||
if (!running) return null;
|
|
||||||
File dir = chooseOutputDirectory();
|
|
||||||
if (dir == null || !dir.exists() || !dir.isDirectory()) return null;
|
|
||||||
File f = new File(dir, filename);
|
|
||||||
try {
|
try {
|
||||||
long capacity = dir.getFreeSpace();
|
File file = new File(path);
|
||||||
if (capacity < MIN_STREAM_LENGTH) return null;
|
FileInputStream in = new FileInputStream(file);
|
||||||
OutputStream out = new FileOutputStream(f);
|
return new FileTransportReader(file, in, this);
|
||||||
return new FileTransportWriter(f, out, capacity, this);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
f.delete();
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createReaderFromFile(File f) {
|
@Override
|
||||||
if (!running) return;
|
public TransportConnectionWriter createWriter(TransportProperties p) {
|
||||||
ioExecutor.execute(new ReaderCreator(f));
|
if (!isRunning()) return null;
|
||||||
}
|
String path = p.get(PROP_PATH);
|
||||||
|
if (isNullOrEmpty(path)) return null;
|
||||||
private class ReaderCreator implements Runnable {
|
try {
|
||||||
|
File file = new File(path);
|
||||||
private final File file;
|
if (!file.exists() && !file.createNewFile()) {
|
||||||
|
LOG.info("Failed to create file");
|
||||||
private ReaderCreator(File file) {
|
return null;
|
||||||
this.file = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (isPossibleConnectionFilename(file.getName())) {
|
|
||||||
try {
|
|
||||||
FileInputStream in = new FileInputStream(file);
|
|
||||||
callback.readerCreated(new FileTransportReader(file, in,
|
|
||||||
FilePlugin.this));
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
FileOutputStream out = new FileOutputStream(file);
|
||||||
|
return new FileTransportWriter(file, out, this);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,9 +38,6 @@ class FileTransportReader implements TransportConnectionReader {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
if (recognised) {
|
plugin.readerFinished(file, exception, recognised);
|
||||||
file.delete();
|
|
||||||
plugin.readerFinished(file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,14 +18,11 @@ class FileTransportWriter implements TransportConnectionWriter {
|
|||||||
|
|
||||||
private final File file;
|
private final File file;
|
||||||
private final OutputStream out;
|
private final OutputStream out;
|
||||||
private final long capacity;
|
|
||||||
private final FilePlugin plugin;
|
private final FilePlugin plugin;
|
||||||
|
|
||||||
FileTransportWriter(File file, OutputStream out, long capacity,
|
FileTransportWriter(File file, OutputStream out, FilePlugin plugin) {
|
||||||
FilePlugin plugin) {
|
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.capacity = capacity;
|
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,11 +36,6 @@ class FileTransportWriter implements TransportConnectionWriter {
|
|||||||
return plugin.getMaxIdleTime();
|
return plugin.getMaxIdleTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getCapacity() {
|
|
||||||
return capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutputStream getOutputStream() {
|
public OutputStream getOutputStream() {
|
||||||
return out;
|
return out;
|
||||||
@@ -56,7 +48,6 @@ class FileTransportWriter implements TransportConnectionWriter {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
if (exception) file.delete();
|
plugin.writerFinished(file, exception);
|
||||||
else plugin.writerFinished(file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -207,20 +207,16 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Map<ContactId, TransportProperties> contacts) {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
Map<ContactId, TransportProperties> remote =
|
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
|
||||||
callback.getRemoteProperties();
|
connectAndCallBack(e.getKey(), e.getValue());
|
||||||
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
|
||||||
ContactId c = e.getKey();
|
|
||||||
if (!connected.contains(c)) connectAndCallBack(c, e.getValue());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectAndCallBack(ContactId c, TransportProperties p) {
|
private void connectAndCallBack(ContactId c, TransportProperties p) {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
if (!isRunning()) return;
|
|
||||||
DuplexTransportConnection d = createConnection(p);
|
DuplexTransportConnection d = createConnection(p);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
@@ -230,13 +226,8 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(TransportProperties p) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
return createConnection(callback.getRemoteProperties(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private DuplexTransportConnection createConnection(TransportProperties p) {
|
|
||||||
for (InetSocketAddress remote : getRemoteSocketAddresses(p)) {
|
for (InetSocketAddress remote : getRemoteSocketAddresses(p)) {
|
||||||
if (!isConnectable(remote)) {
|
if (!isConnectable(remote)) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
|||||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||||
import org.briarproject.bramble.api.settings.SettingsManager;
|
import org.briarproject.bramble.api.settings.SettingsManager;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.ui.UiCallback;
|
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.jmock.Mockery;
|
import org.jmock.Mockery;
|
||||||
@@ -26,9 +25,7 @@ import java.security.SecureRandom;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.RejectedExecutionHandler;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|
||||||
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
|
||||||
@@ -40,19 +37,20 @@ public class PluginManagerImplTest extends BrambleTestCase {
|
|||||||
setThreadingPolicy(new Synchroniser());
|
setThreadingPolicy(new Synchroniser());
|
||||||
}};
|
}};
|
||||||
Executor ioExecutor = Executors.newSingleThreadExecutor();
|
Executor ioExecutor = Executors.newSingleThreadExecutor();
|
||||||
ScheduledExecutorService scheduler = context.mock(ScheduledExecutorService.class);
|
ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
SecureRandom random = new SecureRandom();
|
SecureRandom random = new SecureRandom();
|
||||||
Clock clock = context.mock(Clock.class);
|
Clock clock = context.mock(Clock.class);
|
||||||
EventBus eventBus = context.mock(EventBus.class);
|
EventBus eventBus = context.mock(EventBus.class);
|
||||||
PluginConfig pluginConfig = context.mock(PluginConfig.class);
|
PluginConfig pluginConfig = context.mock(PluginConfig.class);
|
||||||
ConnectionManager connectionManager =
|
ConnectionManager connectionManager =
|
||||||
context.mock(ConnectionManager.class);
|
context.mock(ConnectionManager.class);
|
||||||
ConnectionRegistry connectionRegistry = context.mock(ConnectionRegistry.class);
|
ConnectionRegistry connectionRegistry =
|
||||||
|
context.mock(ConnectionRegistry.class);
|
||||||
SettingsManager settingsManager =
|
SettingsManager settingsManager =
|
||||||
context.mock(SettingsManager.class);
|
context.mock(SettingsManager.class);
|
||||||
TransportPropertyManager transportPropertyManager =
|
TransportPropertyManager transportPropertyManager =
|
||||||
context.mock(TransportPropertyManager.class);
|
context.mock(TransportPropertyManager.class);
|
||||||
UiCallback uiCallback = context.mock(UiCallback.class);
|
|
||||||
|
|
||||||
// Two simplex plugin factories: both create plugins, one fails to start
|
// Two simplex plugin factories: both create plugins, one fails to start
|
||||||
SimplexPluginFactory simplexFactory =
|
SimplexPluginFactory simplexFactory =
|
||||||
@@ -124,9 +122,9 @@ public class PluginManagerImplTest extends BrambleTestCase {
|
|||||||
oneOf(duplexPlugin).stop();
|
oneOf(duplexPlugin).stop();
|
||||||
}});
|
}});
|
||||||
|
|
||||||
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, scheduler, eventBus,
|
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, scheduler,
|
||||||
pluginConfig, connectionManager, connectionRegistry, settingsManager,
|
eventBus, pluginConfig, connectionManager, connectionRegistry,
|
||||||
transportPropertyManager, random, clock, uiCallback);
|
settingsManager, transportPropertyManager, random, clock);
|
||||||
|
|
||||||
// Two plugins should be started and stopped
|
// Two plugins should be started and stopped
|
||||||
p.startService();
|
p.startService();
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
|
|||||||
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||||
@@ -24,13 +26,15 @@ import org.jmock.lib.legacy.ClassImposteriser;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
|
||||||
@@ -44,6 +48,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
context.mock(ConnectionRegistry.class);
|
context.mock(ConnectionRegistry.class);
|
||||||
private final PluginManager pluginManager =
|
private final PluginManager pluginManager =
|
||||||
context.mock(PluginManager.class);
|
context.mock(PluginManager.class);
|
||||||
|
private final TransportPropertyManager transportPropertyManager =
|
||||||
|
context.mock(TransportPropertyManager.class);
|
||||||
private final Clock clock = context.mock(Clock.class);
|
private final Clock clock = context.mock(Clock.class);
|
||||||
private final ScheduledFuture future = context.mock(ScheduledFuture.class);
|
private final ScheduledFuture future = context.mock(ScheduledFuture.class);
|
||||||
private final SecureRandom random;
|
private final SecureRandom random;
|
||||||
@@ -51,6 +57,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
private final Executor ioExecutor = new ImmediateExecutor();
|
private final Executor ioExecutor = new ImmediateExecutor();
|
||||||
private final TransportId transportId = getTransportId();
|
private final TransportId transportId = getTransportId();
|
||||||
private final ContactId contactId = new ContactId(234);
|
private final ContactId contactId = new ContactId(234);
|
||||||
|
private final TransportProperties properties = new TransportProperties();
|
||||||
private final int pollingInterval = 60 * 1000;
|
private final int pollingInterval = 60 * 1000;
|
||||||
private final long now = System.currentTimeMillis();
|
private final long now = System.currentTimeMillis();
|
||||||
|
|
||||||
@@ -66,8 +73,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
SimplexPlugin simplexPlugin1 =
|
SimplexPlugin simplexPlugin1 =
|
||||||
context.mock(SimplexPlugin.class, "simplexPlugin1");
|
context.mock(SimplexPlugin.class, "simplexPlugin1");
|
||||||
TransportId simplexId1 = getTransportId();
|
TransportId simplexId1 = getTransportId();
|
||||||
List<SimplexPlugin> simplexPlugins = Arrays.asList(simplexPlugin,
|
List<SimplexPlugin> simplexPlugins =
|
||||||
simplexPlugin1);
|
asList(simplexPlugin, simplexPlugin1);
|
||||||
TransportConnectionWriter simplexWriter =
|
TransportConnectionWriter simplexWriter =
|
||||||
context.mock(TransportConnectionWriter.class);
|
context.mock(TransportConnectionWriter.class);
|
||||||
|
|
||||||
@@ -76,8 +83,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
TransportId duplexId = getTransportId();
|
TransportId duplexId = getTransportId();
|
||||||
DuplexPlugin duplexPlugin1 =
|
DuplexPlugin duplexPlugin1 =
|
||||||
context.mock(DuplexPlugin.class, "duplexPlugin1");
|
context.mock(DuplexPlugin.class, "duplexPlugin1");
|
||||||
List<DuplexPlugin> duplexPlugins = Arrays.asList(duplexPlugin,
|
List<DuplexPlugin> duplexPlugins =
|
||||||
duplexPlugin1);
|
asList(duplexPlugin, duplexPlugin1);
|
||||||
DuplexTransportConnection duplexConnection =
|
DuplexTransportConnection duplexConnection =
|
||||||
context.mock(DuplexTransportConnection.class);
|
context.mock(DuplexTransportConnection.class);
|
||||||
|
|
||||||
@@ -96,8 +103,12 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(simplexId1));
|
will(returnValue(simplexId1));
|
||||||
oneOf(connectionRegistry).isConnected(contactId, simplexId1);
|
oneOf(connectionRegistry).isConnected(contactId, simplexId1);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
|
// Get the transport properties
|
||||||
|
oneOf(transportPropertyManager).getRemoteProperties(contactId,
|
||||||
|
simplexId1);
|
||||||
|
will(returnValue(properties));
|
||||||
// Connect to the contact
|
// Connect to the contact
|
||||||
oneOf(simplexPlugin1).createWriter(contactId);
|
oneOf(simplexPlugin1).createWriter(properties);
|
||||||
will(returnValue(simplexWriter));
|
will(returnValue(simplexWriter));
|
||||||
// Pass the connection to the connection manager
|
// Pass the connection to the connection manager
|
||||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||||
@@ -105,7 +116,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
// Get the duplex plugins
|
// Get the duplex plugins
|
||||||
oneOf(pluginManager).getDuplexPlugins();
|
oneOf(pluginManager).getDuplexPlugins();
|
||||||
will(returnValue(duplexPlugins));
|
will(returnValue(duplexPlugins));
|
||||||
// The first plugin supports polling
|
// The duplex plugin supports polling
|
||||||
oneOf(duplexPlugin).shouldPoll();
|
oneOf(duplexPlugin).shouldPoll();
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
// Check whether the contact is already connected
|
// Check whether the contact is already connected
|
||||||
@@ -113,8 +124,12 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(duplexId));
|
will(returnValue(duplexId));
|
||||||
oneOf(connectionRegistry).isConnected(contactId, duplexId);
|
oneOf(connectionRegistry).isConnected(contactId, duplexId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
|
// Get the transport properties
|
||||||
|
oneOf(transportPropertyManager).getRemoteProperties(contactId,
|
||||||
|
duplexId);
|
||||||
|
will(returnValue(properties));
|
||||||
// Connect to the contact
|
// Connect to the contact
|
||||||
oneOf(duplexPlugin).createConnection(contactId);
|
oneOf(duplexPlugin).createConnection(properties);
|
||||||
will(returnValue(duplexConnection));
|
will(returnValue(duplexConnection));
|
||||||
// Pass the connection to the connection manager
|
// Pass the connection to the connection manager
|
||||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||||
@@ -125,7 +140,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new ContactStatusChangedEvent(contactId, true));
|
p.eventOccurred(new ContactStatusChangedEvent(contactId, true));
|
||||||
}
|
}
|
||||||
@@ -165,8 +181,12 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
// Check whether the contact is already connected
|
// Check whether the contact is already connected
|
||||||
oneOf(connectionRegistry).isConnected(contactId, transportId);
|
oneOf(connectionRegistry).isConnected(contactId, transportId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
|
// Get the transport properties
|
||||||
|
oneOf(transportPropertyManager).getRemoteProperties(contactId,
|
||||||
|
transportId);
|
||||||
|
will(returnValue(properties));
|
||||||
// Connect to the contact
|
// Connect to the contact
|
||||||
oneOf(plugin).createConnection(contactId);
|
oneOf(plugin).createConnection(properties);
|
||||||
will(returnValue(duplexConnection));
|
will(returnValue(duplexConnection));
|
||||||
// Pass the connection to the connection manager
|
// Pass the connection to the connection manager
|
||||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||||
@@ -174,15 +194,15 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new ConnectionClosedEvent(contactId, transportId,
|
p.eventOccurred(new ConnectionClosedEvent(contactId, transportId,
|
||||||
false));
|
false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRescheduleOnConnectionOpened() throws Exception {
|
public void testRescheduleOnConnectionOpened() {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -205,14 +225,15 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
||||||
false));
|
false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRescheduleDoesNotReplaceEarlierTask() throws Exception {
|
public void testRescheduleDoesNotReplaceEarlierTask() {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -248,7 +269,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
||||||
false));
|
false));
|
||||||
@@ -257,7 +279,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRescheduleReplacesLaterTask() throws Exception {
|
public void testRescheduleReplacesLaterTask() {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -296,7 +318,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
||||||
false));
|
false));
|
||||||
@@ -306,8 +329,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPollsOnTransportEnabled() throws Exception {
|
public void testPollsOnTransportEnabled() throws Exception {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
DuplexPlugin plugin = context.mock(DuplexPlugin.class);
|
||||||
List<ContactId> connected = Collections.singletonList(contactId);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
allowing(plugin).getId();
|
allowing(plugin).getId();
|
||||||
@@ -335,20 +357,69 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
|
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
|
||||||
will(returnValue(future));
|
will(returnValue(future));
|
||||||
// Poll the plugin
|
// Get the transport properties and connected contacts
|
||||||
|
oneOf(transportPropertyManager).getRemoteProperties(transportId);
|
||||||
|
will(returnValue(singletonMap(contactId, properties)));
|
||||||
oneOf(connectionRegistry).getConnectedContacts(transportId);
|
oneOf(connectionRegistry).getConnectedContacts(transportId);
|
||||||
will(returnValue(connected));
|
will(returnValue(emptyList()));
|
||||||
oneOf(plugin).poll(connected);
|
// Poll the plugin
|
||||||
|
oneOf(plugin).poll(singletonMap(contactId, properties));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new TransportEnabledEvent(transportId));
|
p.eventOccurred(new TransportEnabledEvent(transportId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCancelsPollingOnTransportDisabled() throws Exception {
|
public void testDoesNotPollIfAllContactsAreConnected() throws Exception {
|
||||||
|
DuplexPlugin plugin = context.mock(DuplexPlugin.class);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
allowing(plugin).getId();
|
||||||
|
will(returnValue(transportId));
|
||||||
|
// Get the plugin
|
||||||
|
oneOf(pluginManager).getPlugin(transportId);
|
||||||
|
will(returnValue(plugin));
|
||||||
|
// The plugin supports polling
|
||||||
|
oneOf(plugin).shouldPoll();
|
||||||
|
will(returnValue(true));
|
||||||
|
// Schedule a polling task immediately
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(now));
|
||||||
|
oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L),
|
||||||
|
with(MILLISECONDS));
|
||||||
|
will(returnValue(future));
|
||||||
|
will(new RunAction());
|
||||||
|
// Running the polling task schedules the next polling task
|
||||||
|
oneOf(plugin).getPollingInterval();
|
||||||
|
will(returnValue(pollingInterval));
|
||||||
|
oneOf(random).nextDouble();
|
||||||
|
will(returnValue(0.5));
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(now));
|
||||||
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
|
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
|
||||||
|
will(returnValue(future));
|
||||||
|
// Get the transport properties and connected contacts
|
||||||
|
oneOf(transportPropertyManager).getRemoteProperties(transportId);
|
||||||
|
will(returnValue(singletonMap(contactId, properties)));
|
||||||
|
oneOf(connectionRegistry).getConnectedContacts(transportId);
|
||||||
|
will(returnValue(singletonList(contactId)));
|
||||||
|
// All contacts are connected, so don't poll the plugin
|
||||||
|
}});
|
||||||
|
|
||||||
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
|
p.eventOccurred(new TransportEnabledEvent(transportId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCancelsPollingOnTransportDisabled() {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -371,7 +442,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new TransportEnabledEvent(transportId));
|
p.eventOccurred(new TransportEnabledEvent(transportId));
|
||||||
p.eventOccurred(new TransportDisabledEvent(transportId));
|
p.eventOccurred(new TransportDisabledEvent(transportId));
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ import java.net.ServerSocket;
|
|||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@@ -40,7 +38,6 @@ import static org.junit.Assert.assertTrue;
|
|||||||
|
|
||||||
public class LanTcpPluginTest extends BrambleTestCase {
|
public class LanTcpPluginTest extends BrambleTestCase {
|
||||||
|
|
||||||
private final ContactId contactId = new ContactId(234);
|
|
||||||
private final Backoff backoff = new TestBackoff();
|
private final Backoff backoff = new TestBackoff();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -160,12 +157,10 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
error.set(true);
|
error.set(true);
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
// Tell the plugin about the port
|
// Connect to the port
|
||||||
TransportProperties p = new TransportProperties();
|
TransportProperties p = new TransportProperties();
|
||||||
p.put("ipPorts", addrString + ":" + port);
|
p.put("ipPorts", addrString + ":" + port);
|
||||||
callback.remote.put(contactId, p);
|
DuplexTransportConnection d = plugin.createConnection(p);
|
||||||
// Connect to the port
|
|
||||||
DuplexTransportConnection d = plugin.createConnection(contactId);
|
|
||||||
assertNotNull(d);
|
assertNotNull(d);
|
||||||
// Check that the connection was accepted
|
// Check that the connection was accepted
|
||||||
assertTrue(latch.await(5, SECONDS));
|
assertTrue(latch.await(5, SECONDS));
|
||||||
@@ -281,7 +276,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComparatorPrefersNonZeroPorts() throws Exception {
|
public void testComparatorPrefersNonZeroPorts() {
|
||||||
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
||||||
InetSocketAddress nonZero = new InetSocketAddress("1.2.3.4", 1234);
|
InetSocketAddress nonZero = new InetSocketAddress("1.2.3.4", 1234);
|
||||||
InetSocketAddress zero = new InetSocketAddress("1.2.3.4", 0);
|
InetSocketAddress zero = new InetSocketAddress("1.2.3.4", 0);
|
||||||
@@ -294,7 +289,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComparatorPrefersLongerPrefixes() throws Exception {
|
public void testComparatorPrefersLongerPrefixes() {
|
||||||
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
||||||
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
|
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
|
||||||
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
|
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
|
||||||
@@ -314,7 +309,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComparatorPrefersSiteLocalToLinkLocal() throws Exception {
|
public void testComparatorPrefersSiteLocalToLinkLocal() {
|
||||||
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
||||||
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
|
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
|
||||||
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
|
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
|
||||||
@@ -345,8 +340,6 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
private static class Callback implements DuplexPluginCallback {
|
private static class Callback implements DuplexPluginCallback {
|
||||||
|
|
||||||
private final Map<ContactId, TransportProperties> remote =
|
|
||||||
new Hashtable<>();
|
|
||||||
private final CountDownLatch propertiesLatch = new CountDownLatch(1);
|
private final CountDownLatch propertiesLatch = new CountDownLatch(1);
|
||||||
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
||||||
private final TransportProperties local = new TransportProperties();
|
private final TransportProperties local = new TransportProperties();
|
||||||
@@ -361,16 +354,6 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<ContactId, TransportProperties> getRemoteProperties() {
|
|
||||||
return remote;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransportProperties getRemoteProperties(ContactId c) {
|
|
||||||
return remote.get(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mergeSettings(Settings s) {
|
public void mergeSettings(Settings s) {
|
||||||
}
|
}
|
||||||
@@ -381,20 +364,6 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
propertiesLatch.countDown();
|
propertiesLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int showChoice(String[] options, String... message) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean showConfirmationMessage(String... message) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showMessage(String... message) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void incomingConnectionCreated(DuplexTransportConnection d) {
|
public void incomingConnectionCreated(DuplexTransportConnection d) {
|
||||||
connectionsLatch.countDown();
|
connectionsLatch.countDown();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class CaptureArgumentAction<T> implements Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object invoke(Invocation invocation) throws Throwable {
|
public Object invoke(Invocation invocation) {
|
||||||
captured.set(capturedClass.cast(invocation.getParameter(index)));
|
captured.set(capturedClass.cast(invocation.getParameter(index)));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,14 @@ import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
|||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@@ -51,12 +52,12 @@ public class TestPluginConfigModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<DuplexPluginFactory> getDuplexFactories() {
|
public Collection<DuplexPluginFactory> getDuplexFactories() {
|
||||||
return Collections.emptyList();
|
return emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
||||||
return Collections.singletonList(simplex);
|
return singletonList(simplex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,20 +10,20 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
|||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.reliability.ReliabilityLayerFactory;
|
import org.briarproject.bramble.api.reliability.ReliabilityLayerFactory;
|
||||||
import org.briarproject.bramble.plugin.bluetooth.JavaBluetoothPluginFactory;
|
import org.briarproject.bramble.plugin.bluetooth.JavaBluetoothPluginFactory;
|
||||||
import org.briarproject.bramble.plugin.file.RemovableDrivePluginFactory;
|
|
||||||
import org.briarproject.bramble.plugin.modem.ModemPluginFactory;
|
import org.briarproject.bramble.plugin.modem.ModemPluginFactory;
|
||||||
import org.briarproject.bramble.plugin.tcp.LanTcpPluginFactory;
|
import org.briarproject.bramble.plugin.tcp.LanTcpPluginFactory;
|
||||||
import org.briarproject.bramble.plugin.tcp.WanTcpPluginFactory;
|
import org.briarproject.bramble.plugin.tcp.WanTcpPluginFactory;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
public class DesktopPluginModule extends PluginModule {
|
public class DesktopPluginModule extends PluginModule {
|
||||||
|
|
||||||
@@ -41,12 +41,8 @@ public class DesktopPluginModule extends PluginModule {
|
|||||||
backoffFactory);
|
backoffFactory);
|
||||||
DuplexPluginFactory wan = new WanTcpPluginFactory(ioExecutor,
|
DuplexPluginFactory wan = new WanTcpPluginFactory(ioExecutor,
|
||||||
backoffFactory, shutdownManager);
|
backoffFactory, shutdownManager);
|
||||||
SimplexPluginFactory removable =
|
|
||||||
new RemovableDrivePluginFactory(ioExecutor);
|
|
||||||
Collection<SimplexPluginFactory> simplex =
|
|
||||||
Collections.singletonList(removable);
|
|
||||||
Collection<DuplexPluginFactory> duplex =
|
Collection<DuplexPluginFactory> duplex =
|
||||||
Arrays.asList(bluetooth, modem, lan, wan);
|
asList(bluetooth, modem, lan, wan);
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
PluginConfig pluginConfig = new PluginConfig() {
|
PluginConfig pluginConfig = new PluginConfig() {
|
||||||
|
|
||||||
@@ -57,7 +53,7 @@ public class DesktopPluginModule extends PluginModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
||||||
return simplex;
|
return emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
class LinuxRemovableDriveFinder extends UnixRemovableDriveFinder {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getMountCommand() {
|
|
||||||
return "/bin/mount";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
protected String parseMountPoint(String line) {
|
|
||||||
// The format is "/dev/foo on /bar/baz type bam (opt1,opt2)"
|
|
||||||
String pattern = "^/dev/[^ ]+ on (.*) type [^ ]+ \\([^)]+\\)$";
|
|
||||||
String path = line.replaceFirst(pattern, "$1");
|
|
||||||
return path.equals(line) ? null : path;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isRemovableDriveMountPoint(String path) {
|
|
||||||
return path.startsWith("/mnt/") || path.startsWith("/media/");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
class LinuxRemovableDriveMonitor extends UnixRemovableDriveMonitor {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String[] getPathsToWatch() {
|
|
||||||
return new String[] {"/mnt", "/media"};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
class MacRemovableDriveFinder extends UnixRemovableDriveFinder {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getMountCommand() {
|
|
||||||
return "/sbin/mount";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
protected String parseMountPoint(String line) {
|
|
||||||
// The format is "/dev/foo on /bar/baz (opt1, opt2)"
|
|
||||||
String pattern = "^/dev/[^ ]+ on (.*) \\([^)]+\\)$";
|
|
||||||
String path = line.replaceFirst(pattern, "$1");
|
|
||||||
return path.equals(line) ? null : path;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isRemovableDriveMountPoint(String path) {
|
|
||||||
return path.startsWith("/Volumes/");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
class MacRemovableDriveMonitor extends UnixRemovableDriveMonitor {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String[] getPathsToWatch() {
|
|
||||||
return new String[] {"/Volumes"};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.locks.Condition;
|
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
|
||||||
@ParametersNotNullByDefault
|
|
||||||
class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(PollingRemovableDriveMonitor.class.getName());
|
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
|
||||||
private final RemovableDriveFinder finder;
|
|
||||||
private final int pollingInterval;
|
|
||||||
|
|
||||||
private final Lock pollingLock = new ReentrantLock();
|
|
||||||
private final Condition stopPolling = pollingLock.newCondition();
|
|
||||||
|
|
||||||
private volatile boolean running = false;
|
|
||||||
private volatile Callback callback = null;
|
|
||||||
|
|
||||||
PollingRemovableDriveMonitor(Executor ioExecutor,
|
|
||||||
RemovableDriveFinder finder, int pollingInterval) {
|
|
||||||
this.ioExecutor = ioExecutor;
|
|
||||||
this.finder = finder;
|
|
||||||
this.pollingInterval = pollingInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start(Callback callback) throws IOException {
|
|
||||||
this.callback = callback;
|
|
||||||
running = true;
|
|
||||||
ioExecutor.execute(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stop() throws IOException {
|
|
||||||
running = false;
|
|
||||||
pollingLock.lock();
|
|
||||||
try {
|
|
||||||
stopPolling.signalAll();
|
|
||||||
} finally {
|
|
||||||
pollingLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
Collection<File> drives = finder.findRemovableDrives();
|
|
||||||
while (running) {
|
|
||||||
pollingLock.lock();
|
|
||||||
try {
|
|
||||||
stopPolling.await(pollingInterval, MILLISECONDS);
|
|
||||||
} finally {
|
|
||||||
pollingLock.unlock();
|
|
||||||
}
|
|
||||||
if (!running) return;
|
|
||||||
Collection<File> newDrives = finder.findRemovableDrives();
|
|
||||||
for (File f : newDrives) {
|
|
||||||
if (!drives.contains(f)) callback.driveInserted(f);
|
|
||||||
}
|
|
||||||
drives = newDrives;
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOG.warning("Interrupted while waiting to poll");
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
} catch (IOException e) {
|
|
||||||
callback.exceptionThrown(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
interface RemovableDriveFinder {
|
|
||||||
|
|
||||||
Collection<File> findRemovableDrives() throws IOException;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
interface RemovableDriveMonitor {
|
|
||||||
|
|
||||||
void start(Callback c) throws IOException;
|
|
||||||
|
|
||||||
void stop() throws IOException;
|
|
||||||
|
|
||||||
interface Callback {
|
|
||||||
|
|
||||||
void driveInserted(File root);
|
|
||||||
|
|
||||||
void exceptionThrown(IOException e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.PluginException;
|
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
class RemovableDrivePlugin extends FilePlugin
|
|
||||||
implements RemovableDriveMonitor.Callback {
|
|
||||||
|
|
||||||
static final TransportId ID =
|
|
||||||
new TransportId("org.briarproject.bramble.file");
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(RemovableDrivePlugin.class.getName());
|
|
||||||
|
|
||||||
private final RemovableDriveFinder finder;
|
|
||||||
private final RemovableDriveMonitor monitor;
|
|
||||||
|
|
||||||
RemovableDrivePlugin(Executor ioExecutor, SimplexPluginCallback callback,
|
|
||||||
RemovableDriveFinder finder, RemovableDriveMonitor monitor,
|
|
||||||
int maxLatency) {
|
|
||||||
super(ioExecutor, callback, maxLatency);
|
|
||||||
this.finder = finder;
|
|
||||||
this.monitor = monitor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransportId getId() {
|
|
||||||
return ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start() throws PluginException {
|
|
||||||
if (used.getAndSet(true)) throw new IllegalStateException();
|
|
||||||
running = true;
|
|
||||||
try {
|
|
||||||
monitor.start(this);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new PluginException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stop() throws PluginException {
|
|
||||||
running = false;
|
|
||||||
try {
|
|
||||||
monitor.stop();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new PluginException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldPoll() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPollingInterval() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void poll(Collection<ContactId> connected) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected File chooseOutputDirectory() {
|
|
||||||
try {
|
|
||||||
List<File> drives = new ArrayList<>(finder.findRemovableDrives());
|
|
||||||
if (drives.isEmpty()) return null;
|
|
||||||
String[] paths = new String[drives.size()];
|
|
||||||
for (int i = 0; i < paths.length; i++) {
|
|
||||||
paths[i] = drives.get(i).getPath();
|
|
||||||
}
|
|
||||||
int i = callback.showChoice(paths, "REMOVABLE_DRIVE_CHOOSE_DRIVE");
|
|
||||||
if (i == -1) return null;
|
|
||||||
return drives.get(i);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void readerFinished(File f) {
|
|
||||||
callback.showMessage("REMOVABLE_DRIVE_READ_FINISHED");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void writerFinished(File f) {
|
|
||||||
callback.showMessage("REMOVABLE_DRIVE_WRITE_FINISHED");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Collection<File> findFilesByName(String filename) {
|
|
||||||
List<File> matches = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
for (File drive : finder.findRemovableDrives()) {
|
|
||||||
File[] files = drive.listFiles();
|
|
||||||
if (files != null) {
|
|
||||||
for (File f : files) {
|
|
||||||
if (f.isFile() && filename.equals(f.getName()))
|
|
||||||
matches.add(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
return matches;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void driveInserted(File root) {
|
|
||||||
File[] files = root.listFiles();
|
|
||||||
if (files != null) {
|
|
||||||
for (File f : files) if (f.isFile()) createReaderFromFile(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exceptionThrown(IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
|
||||||
import org.briarproject.bramble.util.OsUtils;
|
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
@NotNullByDefault
|
|
||||||
public class RemovableDrivePluginFactory implements SimplexPluginFactory {
|
|
||||||
|
|
||||||
// Maximum latency 14 days (Royal Mail or lackadaisical carrier pigeon)
|
|
||||||
private static final int MAX_LATENCY = 14 * 24 * 60 * 60 * 1000;
|
|
||||||
private static final int POLLING_INTERVAL = 10 * 1000; // 10 seconds
|
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
|
||||||
|
|
||||||
public RemovableDrivePluginFactory(Executor ioExecutor) {
|
|
||||||
this.ioExecutor = ioExecutor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransportId getId() {
|
|
||||||
return RemovableDrivePlugin.ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMaxLatency() {
|
|
||||||
return MAX_LATENCY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SimplexPlugin createPlugin(SimplexPluginCallback callback) {
|
|
||||||
RemovableDriveFinder finder;
|
|
||||||
RemovableDriveMonitor monitor;
|
|
||||||
if (OsUtils.isLinux()) {
|
|
||||||
finder = new LinuxRemovableDriveFinder();
|
|
||||||
monitor = new LinuxRemovableDriveMonitor();
|
|
||||||
} else if (OsUtils.isMacLeopardOrNewer()) {
|
|
||||||
finder = new MacRemovableDriveFinder();
|
|
||||||
monitor = new MacRemovableDriveMonitor();
|
|
||||||
} else if (OsUtils.isMac()) {
|
|
||||||
// JNotify requires OS X 10.5 or newer, so we have to poll
|
|
||||||
finder = new MacRemovableDriveFinder();
|
|
||||||
monitor = new PollingRemovableDriveMonitor(ioExecutor, finder,
|
|
||||||
POLLING_INTERVAL);
|
|
||||||
} else if (OsUtils.isWindows()) {
|
|
||||||
finder = new WindowsRemovableDriveFinder();
|
|
||||||
monitor = new PollingRemovableDriveMonitor(ioExecutor, finder,
|
|
||||||
POLLING_INTERVAL);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new RemovableDrivePlugin(ioExecutor, callback, finder, monitor,
|
|
||||||
MAX_LATENCY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
abstract class UnixRemovableDriveFinder implements RemovableDriveFinder {
|
|
||||||
|
|
||||||
protected abstract String getMountCommand();
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
protected abstract String parseMountPoint(String line);
|
|
||||||
|
|
||||||
protected abstract boolean isRemovableDriveMountPoint(String path);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<File> findRemovableDrives() throws IOException {
|
|
||||||
List<File> drives = new ArrayList<>();
|
|
||||||
Process p = new ProcessBuilder(getMountCommand()).start();
|
|
||||||
Scanner s = new Scanner(p.getInputStream(), "UTF-8");
|
|
||||||
try {
|
|
||||||
while (s.hasNextLine()) {
|
|
||||||
String line = s.nextLine();
|
|
||||||
String[] tokens = line.split(" ");
|
|
||||||
if (tokens.length < 3) continue;
|
|
||||||
// The general format is "/dev/foo on /bar/baz ..."
|
|
||||||
if (tokens[0].startsWith("/dev/") && tokens[1].equals("on")) {
|
|
||||||
// The path may contain spaces so we can't use tokens[2]
|
|
||||||
String path = parseMountPoint(line);
|
|
||||||
if (path != null && isRemovableDriveMountPoint(path)) {
|
|
||||||
File f = new File(path);
|
|
||||||
if (f.exists() && f.isDirectory()) drives.add(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
return drives;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import net.contentobjects.jnotify.JNotify;
|
|
||||||
import net.contentobjects.jnotify.JNotifyListener;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
|
||||||
@ParametersNotNullByDefault
|
|
||||||
abstract class UnixRemovableDriveMonitor implements RemovableDriveMonitor,
|
|
||||||
JNotifyListener {
|
|
||||||
|
|
||||||
//TODO: rationalise this in a further refactor
|
|
||||||
private static final Lock staticLock = new ReentrantLock();
|
|
||||||
|
|
||||||
// The following are locking: staticLock
|
|
||||||
private static boolean triedLoad = false;
|
|
||||||
private static Throwable loadError = null;
|
|
||||||
|
|
||||||
private final Lock lock = new ReentrantLock();
|
|
||||||
|
|
||||||
// The following are locking: lock
|
|
||||||
private final List<Integer> watches = new ArrayList<>();
|
|
||||||
private boolean started = false;
|
|
||||||
private Callback callback = null;
|
|
||||||
|
|
||||||
protected abstract String[] getPathsToWatch();
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static Throwable tryLoad() {
|
|
||||||
try {
|
|
||||||
Class.forName("net.contentobjects.jnotify.JNotify");
|
|
||||||
return null;
|
|
||||||
} catch (UnsatisfiedLinkError | ClassNotFoundException e) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void checkEnabled() throws IOException {
|
|
||||||
staticLock.lock();
|
|
||||||
try {
|
|
||||||
if (!triedLoad) {
|
|
||||||
loadError = tryLoad();
|
|
||||||
triedLoad = true;
|
|
||||||
}
|
|
||||||
if (loadError != null) throw new IOException(loadError.toString());
|
|
||||||
} finally {
|
|
||||||
staticLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start(Callback callback) throws IOException {
|
|
||||||
checkEnabled();
|
|
||||||
List<Integer> watches = new ArrayList<>();
|
|
||||||
int mask = JNotify.FILE_CREATED;
|
|
||||||
for (String path : getPathsToWatch()) {
|
|
||||||
if (new File(path).exists())
|
|
||||||
watches.add(JNotify.addWatch(path, mask, false, this));
|
|
||||||
}
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
if (started) throw new AssertionError();
|
|
||||||
if (this.callback != null) throw new AssertionError();
|
|
||||||
started = true;
|
|
||||||
this.callback = callback;
|
|
||||||
this.watches.addAll(watches);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stop() throws IOException {
|
|
||||||
checkEnabled();
|
|
||||||
List<Integer> watches;
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
if (!started) throw new AssertionError();
|
|
||||||
if (callback == null) throw new AssertionError();
|
|
||||||
started = false;
|
|
||||||
callback = null;
|
|
||||||
watches = new ArrayList<>(this.watches);
|
|
||||||
this.watches.clear();
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
for (Integer w : watches) JNotify.removeWatch(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fileCreated(int wd, String rootPath, String name) {
|
|
||||||
Callback callback;
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
callback = this.callback;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
if (callback != null)
|
|
||||||
callback.driveInserted(new File(rootPath + "/" + name));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fileDeleted(int wd, String rootPath, String name) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fileModified(int wd, String rootPath, String name) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fileRenamed(int wd, String rootPath, String oldName,
|
|
||||||
String newName) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import com.sun.jna.platform.win32.Kernel32;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
class WindowsRemovableDriveFinder implements RemovableDriveFinder {
|
|
||||||
|
|
||||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa364939.aspx
|
|
||||||
private static final int DRIVE_REMOVABLE = 2;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<File> findRemovableDrives() throws IOException {
|
|
||||||
File[] roots = File.listRoots();
|
|
||||||
if (roots == null) throw new IOException();
|
|
||||||
List<File> drives = new ArrayList<>();
|
|
||||||
for (File root : roots) {
|
|
||||||
try {
|
|
||||||
int type = Kernel32.INSTANCE.GetDriveType(root.getPath());
|
|
||||||
if (type == DRIVE_REMOVABLE) drives.add(root);
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return drives;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,7 +17,7 @@ import org.briarproject.bramble.util.StringUtils;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Collection;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Map<ContactId, TransportProperties> contacts) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,17 +139,16 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(TransportProperties p) {
|
||||||
if (!running) return null;
|
if (!running) return null;
|
||||||
// Get the ISO 3166 code for the caller's country
|
// Get the ISO 3166 code for the caller's country
|
||||||
String fromIso = callback.getLocalProperties().get("iso3166");
|
String fromIso = callback.getLocalProperties().get("iso3166");
|
||||||
if (StringUtils.isNullOrEmpty(fromIso)) return null;
|
if (StringUtils.isNullOrEmpty(fromIso)) return null;
|
||||||
// Get the ISO 3166 code for the callee's country
|
// Get the ISO 3166 code for the callee's country
|
||||||
TransportProperties properties = callback.getRemoteProperties(c);
|
String toIso = p.get("iso3166");
|
||||||
String toIso = properties.get("iso3166");
|
|
||||||
if (StringUtils.isNullOrEmpty(toIso)) return null;
|
if (StringUtils.isNullOrEmpty(toIso)) return null;
|
||||||
// Get the callee's phone number
|
// Get the callee's phone number
|
||||||
String number = properties.get("number");
|
String number = p.get("number");
|
||||||
if (StringUtils.isNullOrEmpty(number)) return null;
|
if (StringUtils.isNullOrEmpty(number)) return null;
|
||||||
// Convert the number into direct dialling form
|
// Convert the number into direct dialling form
|
||||||
number = CountryCodes.translate(number, fromIso, toIso);
|
number = CountryCodes.translate(number, fromIso, toIso);
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
public class LinuxRemovableDriveFinderTest extends BrambleTestCase {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testParseMountPoint() {
|
|
||||||
LinuxRemovableDriveFinder f = new LinuxRemovableDriveFinder();
|
|
||||||
String line = "/dev/sda3 on / type ext3"
|
|
||||||
+ " (rw,errors=remount-ro,commit=0)";
|
|
||||||
assertEquals("/", f.parseMountPoint(line));
|
|
||||||
line = "gvfs-fuse-daemon on /home/alice/.gvfs"
|
|
||||||
+ " type fuse.gvfs-fuse-daemon (rw,nosuid,nodev,user=alice)";
|
|
||||||
assertEquals(null, f.parseMountPoint(line)); // Can't be parsed
|
|
||||||
line = "fusectl on /sys/fs/fuse/connections type fusectl (rw)";
|
|
||||||
assertEquals(null, f.parseMountPoint(line)); // Can't be parsed
|
|
||||||
line = "/dev/sdd1 on /media/HAZ SPACE(!) type vfat"
|
|
||||||
+ " (rw,nosuid,nodev,uhelper=udisks,uid=1000,gid=1000,"
|
|
||||||
+ "shortname=mixed,dmask=0077,utf8=1,showexec,flush)";
|
|
||||||
assertEquals("/media/HAZ SPACE(!)", f.parseMountPoint(line));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
public class MacRemovableDriveFinderTest extends BrambleTestCase {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testParseMountPoint() {
|
|
||||||
MacRemovableDriveFinder f = new MacRemovableDriveFinder();
|
|
||||||
String line = "/dev/disk0s3 on / (local, journaled)";
|
|
||||||
assertEquals("/", f.parseMountPoint(line));
|
|
||||||
line = "devfs on /dev (local)";
|
|
||||||
assertEquals(null, f.parseMountPoint(line)); // Can't be parsed
|
|
||||||
line = "<volfs> on /.vol";
|
|
||||||
assertEquals(null, f.parseMountPoint(line)); // Can't be parsed
|
|
||||||
line = "automount -nsl [117] on /Network (automounted)";
|
|
||||||
assertEquals(null, f.parseMountPoint(line)); // Can't be parsed
|
|
||||||
line = "/dev/disk1s1 on /Volumes/HAZ SPACE(!) (local, nodev, nosuid)";
|
|
||||||
assertEquals("/Volumes/HAZ SPACE(!)", f.parseMountPoint(line));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.plugin.file.RemovableDriveMonitor.Callback;
|
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
public class PollingRemovableDriveMonitorTest extends BrambleTestCase {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testOneCallbackPerFile() throws Exception {
|
|
||||||
// Create a finder that returns no files the first time, then two files
|
|
||||||
File file1 = new File("foo");
|
|
||||||
File file2 = new File("bar");
|
|
||||||
@NotNullByDefault
|
|
||||||
RemovableDriveFinder finder = new RemovableDriveFinder() {
|
|
||||||
|
|
||||||
private AtomicBoolean firstCall = new AtomicBoolean(true);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<File> findRemovableDrives() throws IOException {
|
|
||||||
if (firstCall.getAndSet(false)) return Collections.emptyList();
|
|
||||||
else return Arrays.asList(file1, file2);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Create a callback that waits for two files
|
|
||||||
CountDownLatch latch = new CountDownLatch(2);
|
|
||||||
List<File> detected = new ArrayList<>();
|
|
||||||
@NotNullByDefault
|
|
||||||
Callback callback = new Callback() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void driveInserted(File f) {
|
|
||||||
detected.add(f);
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exceptionThrown(IOException e) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Create the monitor and start it
|
|
||||||
RemovableDriveMonitor monitor = new PollingRemovableDriveMonitor(
|
|
||||||
Executors.newCachedThreadPool(), finder, 1);
|
|
||||||
monitor.start(callback);
|
|
||||||
// Wait for the monitor to detect the files
|
|
||||||
assertTrue(latch.await(10, SECONDS));
|
|
||||||
monitor.stop();
|
|
||||||
// Check that both files were detected
|
|
||||||
assertEquals(2, detected.size());
|
|
||||||
assertTrue(detected.contains(file1));
|
|
||||||
assertTrue(detected.contains(file2));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExceptionCallback() throws Exception {
|
|
||||||
// Create a finder that throws an exception the second time it's polled
|
|
||||||
RemovableDriveFinder finder = new RemovableDriveFinder() {
|
|
||||||
|
|
||||||
private AtomicBoolean firstCall = new AtomicBoolean(true);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<File> findRemovableDrives() throws IOException {
|
|
||||||
if (firstCall.getAndSet(false)) return Collections.emptyList();
|
|
||||||
else throw new IOException();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Create a callback that waits for an exception
|
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
|
||||||
@NotNullByDefault
|
|
||||||
Callback callback = new Callback() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void driveInserted(File root) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exceptionThrown(IOException e) {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Create the monitor and start it
|
|
||||||
RemovableDriveMonitor monitor = new PollingRemovableDriveMonitor(
|
|
||||||
Executors.newCachedThreadPool(), finder, 1);
|
|
||||||
monitor.start(callback);
|
|
||||||
assertTrue(latch.await(10, SECONDS));
|
|
||||||
monitor.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,378 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
|
||||||
import org.briarproject.bramble.plugin.file.RemovableDriveMonitor.Callback;
|
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
|
||||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
|
||||||
import org.jmock.Expectations;
|
|
||||||
import org.jmock.Mockery;
|
|
||||||
import org.jmock.lib.concurrent.Synchroniser;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MIN_STREAM_LENGTH;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
public class RemovableDrivePluginTest extends BrambleTestCase {
|
|
||||||
|
|
||||||
private final File testDir = TestUtils.getTestDirectory();
|
|
||||||
private final ContactId contactId = new ContactId(234);
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
testDir.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWriterIsNullIfNoDrivesAreFound() throws Exception {
|
|
||||||
List<File> drives = Collections.emptyList();
|
|
||||||
|
|
||||||
Mockery context = new Mockery() {{
|
|
||||||
setThreadingPolicy(new Synchroniser());
|
|
||||||
}};
|
|
||||||
Executor executor = context.mock(Executor.class);
|
|
||||||
SimplexPluginCallback callback =
|
|
||||||
context.mock(SimplexPluginCallback.class);
|
|
||||||
RemovableDriveFinder finder =
|
|
||||||
context.mock(RemovableDriveFinder.class);
|
|
||||||
RemovableDriveMonitor monitor =
|
|
||||||
context.mock(RemovableDriveMonitor.class);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(monitor).start(with(any(Callback.class)));
|
|
||||||
oneOf(finder).findRemovableDrives();
|
|
||||||
will(returnValue(drives));
|
|
||||||
}});
|
|
||||||
|
|
||||||
RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
|
|
||||||
callback, finder, monitor, 0);
|
|
||||||
plugin.start();
|
|
||||||
|
|
||||||
assertNull(plugin.createWriter(contactId));
|
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWriterIsNullIfNoDriveIsChosen() throws Exception {
|
|
||||||
File drive1 = new File(testDir, "1");
|
|
||||||
File drive2 = new File(testDir, "2");
|
|
||||||
List<File> drives = new ArrayList<>();
|
|
||||||
drives.add(drive1);
|
|
||||||
drives.add(drive2);
|
|
||||||
|
|
||||||
Mockery context = new Mockery() {{
|
|
||||||
setThreadingPolicy(new Synchroniser());
|
|
||||||
}};
|
|
||||||
Executor executor = context.mock(Executor.class);
|
|
||||||
SimplexPluginCallback callback =
|
|
||||||
context.mock(SimplexPluginCallback.class);
|
|
||||||
RemovableDriveFinder finder =
|
|
||||||
context.mock(RemovableDriveFinder.class);
|
|
||||||
RemovableDriveMonitor monitor =
|
|
||||||
context.mock(RemovableDriveMonitor.class);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(monitor).start(with(any(Callback.class)));
|
|
||||||
oneOf(finder).findRemovableDrives();
|
|
||||||
will(returnValue(drives));
|
|
||||||
oneOf(callback).showChoice(with(any(String[].class)),
|
|
||||||
with(any(String[].class)));
|
|
||||||
will(returnValue(-1)); // The user cancelled the choice
|
|
||||||
}});
|
|
||||||
|
|
||||||
RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
|
|
||||||
callback, finder, monitor, 0);
|
|
||||||
plugin.start();
|
|
||||||
|
|
||||||
assertNull(plugin.createWriter(contactId));
|
|
||||||
File[] files = drive1.listFiles();
|
|
||||||
assertTrue(files == null || files.length == 0);
|
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWriterIsNullIfOutputDirDoesNotExist() throws Exception {
|
|
||||||
File drive1 = new File(testDir, "1");
|
|
||||||
File drive2 = new File(testDir, "2");
|
|
||||||
List<File> drives = new ArrayList<>();
|
|
||||||
drives.add(drive1);
|
|
||||||
drives.add(drive2);
|
|
||||||
|
|
||||||
Mockery context = new Mockery() {{
|
|
||||||
setThreadingPolicy(new Synchroniser());
|
|
||||||
}};
|
|
||||||
Executor executor = context.mock(Executor.class);
|
|
||||||
SimplexPluginCallback callback =
|
|
||||||
context.mock(SimplexPluginCallback.class);
|
|
||||||
RemovableDriveFinder finder =
|
|
||||||
context.mock(RemovableDriveFinder.class);
|
|
||||||
RemovableDriveMonitor monitor =
|
|
||||||
context.mock(RemovableDriveMonitor.class);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(monitor).start(with(any(Callback.class)));
|
|
||||||
oneOf(finder).findRemovableDrives();
|
|
||||||
will(returnValue(drives));
|
|
||||||
oneOf(callback).showChoice(with(any(String[].class)),
|
|
||||||
with(any(String[].class)));
|
|
||||||
will(returnValue(0)); // The user chose drive1 but it doesn't exist
|
|
||||||
}});
|
|
||||||
|
|
||||||
RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
|
|
||||||
callback, finder, monitor, 0);
|
|
||||||
plugin.start();
|
|
||||||
|
|
||||||
assertNull(plugin.createWriter(contactId));
|
|
||||||
File[] files = drive1.listFiles();
|
|
||||||
assertTrue(files == null || files.length == 0);
|
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWriterIsNullIfOutputDirIsAFile() throws Exception {
|
|
||||||
File drive1 = new File(testDir, "1");
|
|
||||||
File drive2 = new File(testDir, "2");
|
|
||||||
List<File> drives = new ArrayList<>();
|
|
||||||
drives.add(drive1);
|
|
||||||
drives.add(drive2);
|
|
||||||
// Create drive1 as a file rather than a directory
|
|
||||||
assertTrue(drive1.createNewFile());
|
|
||||||
|
|
||||||
Mockery context = new Mockery() {{
|
|
||||||
setThreadingPolicy(new Synchroniser());
|
|
||||||
}};
|
|
||||||
Executor executor = context.mock(Executor.class);
|
|
||||||
SimplexPluginCallback callback =
|
|
||||||
context.mock(SimplexPluginCallback.class);
|
|
||||||
RemovableDriveFinder finder =
|
|
||||||
context.mock(RemovableDriveFinder.class);
|
|
||||||
RemovableDriveMonitor monitor =
|
|
||||||
context.mock(RemovableDriveMonitor.class);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(monitor).start(with(any(Callback.class)));
|
|
||||||
oneOf(finder).findRemovableDrives();
|
|
||||||
will(returnValue(drives));
|
|
||||||
oneOf(callback).showChoice(with(any(String[].class)),
|
|
||||||
with(any(String[].class)));
|
|
||||||
will(returnValue(0)); // The user chose drive1 but it's not a dir
|
|
||||||
}});
|
|
||||||
|
|
||||||
RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
|
|
||||||
callback, finder, monitor, 0);
|
|
||||||
plugin.start();
|
|
||||||
|
|
||||||
assertNull(plugin.createWriter(contactId));
|
|
||||||
File[] files = drive1.listFiles();
|
|
||||||
assertTrue(files == null || files.length == 0);
|
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWriterIsNotNullIfOutputDirIsADir() throws Exception {
|
|
||||||
File drive1 = new File(testDir, "1");
|
|
||||||
File drive2 = new File(testDir, "2");
|
|
||||||
List<File> drives = new ArrayList<>();
|
|
||||||
drives.add(drive1);
|
|
||||||
drives.add(drive2);
|
|
||||||
// Create drive1 as a directory
|
|
||||||
assertTrue(drive1.mkdir());
|
|
||||||
|
|
||||||
Mockery context = new Mockery() {{
|
|
||||||
setThreadingPolicy(new Synchroniser());
|
|
||||||
}};
|
|
||||||
Executor executor = context.mock(Executor.class);
|
|
||||||
SimplexPluginCallback callback =
|
|
||||||
context.mock(SimplexPluginCallback.class);
|
|
||||||
RemovableDriveFinder finder =
|
|
||||||
context.mock(RemovableDriveFinder.class);
|
|
||||||
RemovableDriveMonitor monitor =
|
|
||||||
context.mock(RemovableDriveMonitor.class);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(monitor).start(with(any(Callback.class)));
|
|
||||||
oneOf(finder).findRemovableDrives();
|
|
||||||
will(returnValue(drives));
|
|
||||||
oneOf(callback).showChoice(with(any(String[].class)),
|
|
||||||
with(any(String[].class)));
|
|
||||||
will(returnValue(0)); // The user chose drive1
|
|
||||||
}});
|
|
||||||
|
|
||||||
RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
|
|
||||||
callback, finder, monitor, 0);
|
|
||||||
plugin.start();
|
|
||||||
|
|
||||||
assertNotNull(plugin.createWriter(contactId));
|
|
||||||
// The output file should exist and should be empty
|
|
||||||
File[] files = drive1.listFiles();
|
|
||||||
assertNotNull(files);
|
|
||||||
assertEquals(1, files.length);
|
|
||||||
assertEquals(0, files[0].length());
|
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWritingToWriter() throws Exception {
|
|
||||||
File drive1 = new File(testDir, "1");
|
|
||||||
File drive2 = new File(testDir, "2");
|
|
||||||
List<File> drives = new ArrayList<>();
|
|
||||||
drives.add(drive1);
|
|
||||||
drives.add(drive2);
|
|
||||||
// Create drive1 as a directory
|
|
||||||
assertTrue(drive1.mkdir());
|
|
||||||
|
|
||||||
Mockery context = new Mockery() {{
|
|
||||||
setThreadingPolicy(new Synchroniser());
|
|
||||||
}};
|
|
||||||
Executor executor = context.mock(Executor.class);
|
|
||||||
SimplexPluginCallback callback =
|
|
||||||
context.mock(SimplexPluginCallback.class);
|
|
||||||
RemovableDriveFinder finder =
|
|
||||||
context.mock(RemovableDriveFinder.class);
|
|
||||||
RemovableDriveMonitor monitor =
|
|
||||||
context.mock(RemovableDriveMonitor.class);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(monitor).start(with(any(Callback.class)));
|
|
||||||
oneOf(finder).findRemovableDrives();
|
|
||||||
will(returnValue(drives));
|
|
||||||
oneOf(callback).showChoice(with(any(String[].class)),
|
|
||||||
with(any(String[].class)));
|
|
||||||
will(returnValue(0)); // The user chose drive1
|
|
||||||
oneOf(callback).showMessage(with(any(String[].class)));
|
|
||||||
}});
|
|
||||||
|
|
||||||
RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
|
|
||||||
callback, finder, monitor, 0);
|
|
||||||
plugin.start();
|
|
||||||
|
|
||||||
TransportConnectionWriter writer = plugin.createWriter(contactId);
|
|
||||||
assertNotNull(writer);
|
|
||||||
// The output file should exist and should be empty
|
|
||||||
File[] files = drive1.listFiles();
|
|
||||||
assertNotNull(files);
|
|
||||||
assertEquals(1, files.length);
|
|
||||||
assertEquals(0, files[0].length());
|
|
||||||
// Writing to the output stream should increase the size of the file
|
|
||||||
OutputStream out = writer.getOutputStream();
|
|
||||||
out.write(new byte[1234]);
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
// Disposing of the writer should not delete the file
|
|
||||||
writer.dispose(false);
|
|
||||||
assertTrue(files[0].exists());
|
|
||||||
assertEquals(1234, files[0].length());
|
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEmptyDriveIsIgnored() throws Exception {
|
|
||||||
Mockery context = new Mockery() {{
|
|
||||||
setThreadingPolicy(new Synchroniser());
|
|
||||||
}};
|
|
||||||
Executor executor = context.mock(Executor.class);
|
|
||||||
SimplexPluginCallback callback =
|
|
||||||
context.mock(SimplexPluginCallback.class);
|
|
||||||
RemovableDriveFinder finder =
|
|
||||||
context.mock(RemovableDriveFinder.class);
|
|
||||||
RemovableDriveMonitor monitor =
|
|
||||||
context.mock(RemovableDriveMonitor.class);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(monitor).start(with(any(Callback.class)));
|
|
||||||
}});
|
|
||||||
|
|
||||||
RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
|
|
||||||
callback, finder, monitor, 0);
|
|
||||||
plugin.start();
|
|
||||||
|
|
||||||
plugin.driveInserted(testDir);
|
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFilenames() {
|
|
||||||
Mockery context = new Mockery() {{
|
|
||||||
setThreadingPolicy(new Synchroniser());
|
|
||||||
}};
|
|
||||||
Executor executor = context.mock(Executor.class);
|
|
||||||
SimplexPluginCallback callback =
|
|
||||||
context.mock(SimplexPluginCallback.class);
|
|
||||||
RemovableDriveFinder finder =
|
|
||||||
context.mock(RemovableDriveFinder.class);
|
|
||||||
RemovableDriveMonitor monitor =
|
|
||||||
context.mock(RemovableDriveMonitor.class);
|
|
||||||
|
|
||||||
RemovableDrivePlugin plugin = new RemovableDrivePlugin(executor,
|
|
||||||
callback, finder, monitor, 0);
|
|
||||||
|
|
||||||
assertFalse(plugin.isPossibleConnectionFilename("abcdefg.dat"));
|
|
||||||
assertFalse(plugin.isPossibleConnectionFilename("abcdefghi.dat"));
|
|
||||||
assertFalse(plugin.isPossibleConnectionFilename("abcdefgh_dat"));
|
|
||||||
assertFalse(plugin.isPossibleConnectionFilename("abcdefgh.rat"));
|
|
||||||
assertTrue(plugin.isPossibleConnectionFilename("abcdefgh.dat"));
|
|
||||||
assertTrue(plugin.isPossibleConnectionFilename("ABCDEFGH.DAT"));
|
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReaderIsCreated() throws Exception {
|
|
||||||
Mockery context = new Mockery() {{
|
|
||||||
setThreadingPolicy(new Synchroniser());
|
|
||||||
}};
|
|
||||||
SimplexPluginCallback callback =
|
|
||||||
context.mock(SimplexPluginCallback.class);
|
|
||||||
RemovableDriveFinder finder =
|
|
||||||
context.mock(RemovableDriveFinder.class);
|
|
||||||
RemovableDriveMonitor monitor =
|
|
||||||
context.mock(RemovableDriveMonitor.class);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(monitor).start(with(any(Callback.class)));
|
|
||||||
oneOf(callback).readerCreated(with(any(FileTransportReader.class)));
|
|
||||||
}});
|
|
||||||
|
|
||||||
RemovableDrivePlugin plugin = new RemovableDrivePlugin(
|
|
||||||
new ImmediateExecutor(), callback, finder, monitor, 0);
|
|
||||||
plugin.start();
|
|
||||||
|
|
||||||
File f = new File(testDir, "abcdefgh.dat");
|
|
||||||
OutputStream out = new FileOutputStream(f);
|
|
||||||
out.write(new byte[MIN_STREAM_LENGTH]);
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
assertEquals(MIN_STREAM_LENGTH, f.length());
|
|
||||||
plugin.driveInserted(testDir);
|
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
TestUtils.deleteTestDirectory(testDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.plugin.file.RemovableDriveMonitor.Callback;
|
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
|
||||||
import org.briarproject.bramble.util.OsUtils;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
public class UnixRemovableDriveMonitorTest extends BrambleTestCase {
|
|
||||||
|
|
||||||
private final File testDir = TestUtils.getTestDirectory();
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
testDir.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNonexistentDir() throws Exception {
|
|
||||||
if (!(OsUtils.isLinux() || OsUtils.isMacLeopardOrNewer())) {
|
|
||||||
System.err.println("WARNING: Skipping test, can't run on this OS");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
File doesNotExist = new File(testDir, "doesNotExist");
|
|
||||||
RemovableDriveMonitor monitor = createMonitor(doesNotExist);
|
|
||||||
@NotNullByDefault
|
|
||||||
Callback callback = new Callback() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void driveInserted(File root) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exceptionThrown(IOException e) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
monitor.start(callback);
|
|
||||||
monitor.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testOneCallbackPerFile() throws Exception {
|
|
||||||
if (!(OsUtils.isLinux() || OsUtils.isMacLeopardOrNewer())) {
|
|
||||||
System.err.println("WARNING: Skipping test, can't run on this OS");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Create a callback that will wait for two files before stopping
|
|
||||||
List<File> detected = new ArrayList<>();
|
|
||||||
CountDownLatch latch = new CountDownLatch(2);
|
|
||||||
@NotNullByDefault
|
|
||||||
Callback callback = new Callback() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void driveInserted(File f) {
|
|
||||||
detected.add(f);
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exceptionThrown(IOException e) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Create the monitor and start it
|
|
||||||
RemovableDriveMonitor monitor = createMonitor(testDir);
|
|
||||||
monitor.start(callback);
|
|
||||||
// Create two files in the test directory
|
|
||||||
File file1 = new File(testDir, "1");
|
|
||||||
File file2 = new File(testDir, "2");
|
|
||||||
assertTrue(file1.createNewFile());
|
|
||||||
assertTrue(file2.createNewFile());
|
|
||||||
// Wait for the monitor to detect the files
|
|
||||||
assertTrue(latch.await(5, SECONDS));
|
|
||||||
monitor.stop();
|
|
||||||
// Check that both files were detected
|
|
||||||
assertEquals(2, detected.size());
|
|
||||||
assertTrue(detected.contains(file1));
|
|
||||||
assertTrue(detected.contains(file2));
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
TestUtils.deleteTestDirectory(testDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
private RemovableDriveMonitor createMonitor(File dir) {
|
|
||||||
@NotNullByDefault
|
|
||||||
RemovableDriveMonitor monitor = new UnixRemovableDriveMonitor() {
|
|
||||||
@Override
|
|
||||||
protected String[] getPathsToWatch() {
|
|
||||||
return new String[] {dir.getPath()};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return monitor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.bramble.plugin.modem;
|
package org.briarproject.bramble.plugin.modem;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
@@ -66,7 +65,6 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
TransportProperties remote = new TransportProperties();
|
TransportProperties remote = new TransportProperties();
|
||||||
remote.put("iso3166", ISO_1336);
|
remote.put("iso3166", ISO_1336);
|
||||||
remote.put("number", NUMBER);
|
remote.put("number", NUMBER);
|
||||||
ContactId contactId = new ContactId(234);
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// start()
|
// start()
|
||||||
oneOf(serialPortList).getPortNames();
|
oneOf(serialPortList).getPortNames();
|
||||||
@@ -78,14 +76,12 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
// createConnection()
|
// createConnection()
|
||||||
oneOf(callback).getLocalProperties();
|
oneOf(callback).getLocalProperties();
|
||||||
will(returnValue(local));
|
will(returnValue(local));
|
||||||
oneOf(callback).getRemoteProperties(contactId);
|
|
||||||
will(returnValue(remote));
|
|
||||||
oneOf(modem).dial(NUMBER);
|
oneOf(modem).dial(NUMBER);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
}});
|
}});
|
||||||
plugin.start();
|
plugin.start();
|
||||||
// A connection should be returned
|
// A connection should be returned
|
||||||
assertNotNull(plugin.createConnection(contactId));
|
assertNotNull(plugin.createConnection(remote));
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +101,6 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
TransportProperties remote = new TransportProperties();
|
TransportProperties remote = new TransportProperties();
|
||||||
remote.put("iso3166", ISO_1336);
|
remote.put("iso3166", ISO_1336);
|
||||||
remote.put("number", NUMBER);
|
remote.put("number", NUMBER);
|
||||||
ContactId contactId = new ContactId(234);
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// start()
|
// start()
|
||||||
oneOf(serialPortList).getPortNames();
|
oneOf(serialPortList).getPortNames();
|
||||||
@@ -117,14 +112,12 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
// createConnection()
|
// createConnection()
|
||||||
oneOf(callback).getLocalProperties();
|
oneOf(callback).getLocalProperties();
|
||||||
will(returnValue(local));
|
will(returnValue(local));
|
||||||
oneOf(callback).getRemoteProperties(contactId);
|
|
||||||
will(returnValue(remote));
|
|
||||||
oneOf(modem).dial(NUMBER);
|
oneOf(modem).dial(NUMBER);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
}});
|
}});
|
||||||
plugin.start();
|
plugin.start();
|
||||||
// No connection should be returned
|
// No connection should be returned
|
||||||
assertNull(plugin.createConnection(contactId));
|
assertNull(plugin.createConnection(remote));
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +137,6 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
TransportProperties remote = new TransportProperties();
|
TransportProperties remote = new TransportProperties();
|
||||||
remote.put("iso3166", ISO_1336);
|
remote.put("iso3166", ISO_1336);
|
||||||
remote.put("number", NUMBER);
|
remote.put("number", NUMBER);
|
||||||
ContactId contactId = new ContactId(234);
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// start()
|
// start()
|
||||||
oneOf(serialPortList).getPortNames();
|
oneOf(serialPortList).getPortNames();
|
||||||
@@ -156,8 +148,6 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
// createConnection()
|
// createConnection()
|
||||||
oneOf(callback).getLocalProperties();
|
oneOf(callback).getLocalProperties();
|
||||||
will(returnValue(local));
|
will(returnValue(local));
|
||||||
oneOf(callback).getRemoteProperties(contactId);
|
|
||||||
will(returnValue(remote));
|
|
||||||
oneOf(modem).dial(NUMBER);
|
oneOf(modem).dial(NUMBER);
|
||||||
will(throwException(new IOException()));
|
will(throwException(new IOException()));
|
||||||
// resetModem()
|
// resetModem()
|
||||||
@@ -170,7 +160,7 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
}});
|
}});
|
||||||
plugin.start();
|
plugin.start();
|
||||||
// No connection should be returned
|
// No connection should be returned
|
||||||
assertNull(plugin.createConnection(contactId));
|
assertNull(plugin.createConnection(remote));
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,15 +19,13 @@ import org.briarproject.bramble.api.plugin.PluginConfig;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.reporting.DevConfig;
|
import org.briarproject.bramble.api.reporting.DevConfig;
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
import org.briarproject.bramble.api.ui.UiCallback;
|
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
|
||||||
import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory;
|
import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory;
|
||||||
import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
|
import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
|
||||||
import org.briarproject.bramble.plugin.tor.TorPluginFactory;
|
import org.briarproject.bramble.plugin.tor.TorPluginFactory;
|
||||||
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.android.DozeWatchdog;
|
import org.briarproject.briar.api.android.DozeWatchdog;
|
||||||
@@ -37,9 +35,7 @@ import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
@@ -51,6 +47,8 @@ import dagger.Module;
|
|||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
import static android.content.Context.MODE_PRIVATE;
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS;
|
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS;
|
||||||
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX;
|
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX;
|
||||||
|
|
||||||
@@ -67,27 +65,9 @@ public class AppModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final Application application;
|
private final Application application;
|
||||||
private final UiCallback uiCallback;
|
|
||||||
|
|
||||||
public AppModule(Application application) {
|
public AppModule(Application application) {
|
||||||
this.application = application;
|
this.application = application;
|
||||||
uiCallback = new UiCallback() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int showChoice(String[] options, String... message) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean showConfirmationMessage(String... message) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showMessage(String... message) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -96,11 +76,6 @@ public class AppModule {
|
|||||||
return application;
|
return application;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
UiCallback provideUICallback() {
|
|
||||||
return uiCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
DatabaseConfig provideDatabaseConfig(Application app) {
|
DatabaseConfig provideDatabaseConfig(Application app) {
|
||||||
@@ -122,8 +97,7 @@ public class AppModule {
|
|||||||
@Scheduler ScheduledExecutorService scheduler,
|
@Scheduler ScheduledExecutorService scheduler,
|
||||||
AndroidExecutor androidExecutor, SecureRandom random,
|
AndroidExecutor androidExecutor, SecureRandom random,
|
||||||
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
||||||
Application app, LocationUtils locationUtils, DevReporter reporter,
|
Application app, LocationUtils locationUtils, EventBus eventBus) {
|
||||||
EventBus eventBus) {
|
|
||||||
Context appContext = app.getApplicationContext();
|
Context appContext = app.getApplicationContext();
|
||||||
DuplexPluginFactory bluetooth =
|
DuplexPluginFactory bluetooth =
|
||||||
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
|
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
|
||||||
@@ -133,8 +107,7 @@ public class AppModule {
|
|||||||
torSocketFactory, backoffFactory);
|
torSocketFactory, backoffFactory);
|
||||||
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
||||||
scheduler, backoffFactory, appContext);
|
scheduler, backoffFactory, appContext);
|
||||||
Collection<DuplexPluginFactory> duplex =
|
Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan);
|
||||||
Arrays.asList(bluetooth, tor, lan);
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
PluginConfig pluginConfig = new PluginConfig() {
|
PluginConfig pluginConfig = new PluginConfig() {
|
||||||
|
|
||||||
@@ -145,14 +118,13 @@ public class AppModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
||||||
return Collections.emptyList();
|
return emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldPoll() {
|
public boolean shouldPoll() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
return pluginConfig;
|
return pluginConfig;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user