mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 11:19:04 +01:00
Changed drive monitors to use callbacks rather than blocking.
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
package net.sf.briar.plugins.file;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.transport.ConnectionRecogniser;
|
||||
import net.sf.briar.api.transport.InvalidConfigException;
|
||||
import net.sf.briar.api.transport.InvalidTransportException;
|
||||
import net.sf.briar.api.transport.TransportConstants;
|
||||
@@ -19,6 +22,8 @@ import org.apache.commons.io.FileSystemUtils;
|
||||
|
||||
abstract class FilePlugin implements BatchTransportPlugin {
|
||||
|
||||
private final ConnectionRecogniser recogniser;
|
||||
|
||||
protected Map<String, String> localProperties = null;
|
||||
protected Map<ContactId, Map<String, String>> remoteProperties = null;
|
||||
protected Map<String, String> config = null;
|
||||
@@ -28,10 +33,14 @@ abstract class FilePlugin implements BatchTransportPlugin {
|
||||
protected abstract File chooseOutputDirectory();
|
||||
protected abstract void writerFinished(File f);
|
||||
|
||||
FilePlugin(ConnectionRecogniser recogniser) {
|
||||
this.recogniser = recogniser;
|
||||
}
|
||||
|
||||
public synchronized void start(Map<String, String> localProperties,
|
||||
Map<ContactId, Map<String, String>> remoteProperties,
|
||||
Map<String, String> config, BatchTransportCallback callback)
|
||||
throws InvalidTransportException, InvalidConfigException {
|
||||
throws InvalidTransportException, InvalidConfigException, IOException {
|
||||
if(started) throw new IllegalStateException();
|
||||
started = true;
|
||||
this.localProperties = localProperties;
|
||||
@@ -40,7 +49,7 @@ abstract class FilePlugin implements BatchTransportPlugin {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
public synchronized void stop() throws IOException {
|
||||
if(!started) throw new IllegalStateException();
|
||||
started = false;
|
||||
}
|
||||
@@ -106,4 +115,37 @@ abstract class FilePlugin implements BatchTransportPlugin {
|
||||
protected long getCapacity(String path) throws IOException {
|
||||
return FileSystemUtils.freeSpaceKb(path) * 1024L;
|
||||
}
|
||||
|
||||
protected void createReaderFromFile(File f) {
|
||||
if(!isPossibleConnectionFilename(f.getName())) return;
|
||||
if(f.length() < TransportConstants.MIN_CONNECTION_LENGTH) return;
|
||||
try {
|
||||
FileInputStream in = new FileInputStream(f);
|
||||
byte[] iv = new byte[TransportConstants.IV_LENGTH];
|
||||
int offset = 0;
|
||||
while(offset < iv.length) {
|
||||
int read = in.read(iv, offset, iv.length - offset);
|
||||
if(read == -1) break;
|
||||
offset += read;
|
||||
}
|
||||
ContactId c = recogniser.acceptConnection(iv);
|
||||
if(c == null) {
|
||||
// Nobody there
|
||||
in.close();
|
||||
return;
|
||||
}
|
||||
FileTransportReader reader = new FileTransportReader(f, in);
|
||||
callback.readerCreated(c, iv, reader);
|
||||
} catch(DbException e) {
|
||||
// FIXME: At least log it
|
||||
return;
|
||||
} catch(IOException e) {
|
||||
// FIXME: At least log it
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isPossibleConnectionFilename(String filename) {
|
||||
return filename.toLowerCase().matches("[a-z]{8}\\.dat");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.sf.briar.plugins.file;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.sf.briar.api.transport.batch.BatchTransportReader;
|
||||
|
||||
class FileTransportReader implements BatchTransportReader {
|
||||
|
||||
private final File file;
|
||||
private final InputStream in;
|
||||
|
||||
private boolean streamInUse = false;
|
||||
|
||||
FileTransportReader(File file, InputStream in) {
|
||||
this.file = file;
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
streamInUse = true;
|
||||
return in;
|
||||
}
|
||||
|
||||
public void dispose() throws IOException {
|
||||
if(streamInUse) in.close();
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
@@ -2,52 +2,39 @@ package net.sf.briar.plugins.file;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
|
||||
|
||||
private final RemovableDriveFinder finder;
|
||||
private final long pollingInterval;
|
||||
private final LinkedList<File> inserted;
|
||||
private final LinkedList<IOException> exceptions;
|
||||
private final Object pollingLock;
|
||||
private final Object pollingLock = new Object();
|
||||
|
||||
private boolean started = false, stopped = false;
|
||||
private Thread pollingThread = null;
|
||||
private volatile boolean running = false;
|
||||
private volatile Callback callback = null;
|
||||
private volatile IOException exception = null;
|
||||
|
||||
public PollingRemovableDriveMonitor(RemovableDriveFinder finder,
|
||||
long pollingInterval) {
|
||||
this.finder = finder;
|
||||
this.pollingInterval = pollingInterval;
|
||||
inserted = new LinkedList<File>();
|
||||
exceptions = new LinkedList<IOException>();
|
||||
pollingLock = new Object();
|
||||
}
|
||||
|
||||
public synchronized void start() throws IOException {
|
||||
if(started || stopped) throw new IllegalStateException();
|
||||
started = true;
|
||||
pollingThread = new Thread(this);
|
||||
pollingThread.start();
|
||||
}
|
||||
|
||||
public synchronized File waitForInsertion() throws IOException {
|
||||
if(!started || stopped) throw new IllegalStateException();
|
||||
if(!exceptions.isEmpty()) throw exceptions.poll();
|
||||
while(inserted.isEmpty()) {
|
||||
try {
|
||||
wait();
|
||||
} catch(InterruptedException ignored) {}
|
||||
if(!exceptions.isEmpty()) throw exceptions.poll();
|
||||
}
|
||||
return inserted.poll();
|
||||
public synchronized void start(Callback callback) throws IOException {
|
||||
if(running) throw new IllegalStateException();
|
||||
running = true;
|
||||
this.callback = callback;
|
||||
new Thread(this).start();
|
||||
}
|
||||
|
||||
public synchronized void stop() throws IOException {
|
||||
if(!started || stopped) throw new IllegalStateException();
|
||||
if(!exceptions.isEmpty()) throw exceptions.poll();
|
||||
stopped = true;
|
||||
if(!running) throw new IllegalStateException();
|
||||
running = false;
|
||||
if(exception != null) {
|
||||
IOException e = exception;
|
||||
exception = null;
|
||||
throw e;
|
||||
}
|
||||
synchronized(pollingLock) {
|
||||
pollingLock.notifyAll();
|
||||
}
|
||||
@@ -56,34 +43,21 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
|
||||
public void run() {
|
||||
try {
|
||||
List<File> drives = finder.findRemovableDrives();
|
||||
while(true) {
|
||||
synchronized(this) {
|
||||
if(stopped) return;
|
||||
}
|
||||
while(running) {
|
||||
synchronized(pollingLock) {
|
||||
try {
|
||||
pollingLock.wait(pollingInterval);
|
||||
} catch(InterruptedException ignored) {}
|
||||
}
|
||||
synchronized(this) {
|
||||
if(stopped) return;
|
||||
}
|
||||
if(!running) return;
|
||||
List<File> newDrives = finder.findRemovableDrives();
|
||||
for(File f : newDrives) {
|
||||
if(!drives.contains(f)) {
|
||||
synchronized(this) {
|
||||
inserted.add(f);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
if(!drives.contains(f)) callback.driveInserted(f);
|
||||
}
|
||||
drives = newDrives;
|
||||
}
|
||||
} catch(IOException e) {
|
||||
synchronized(this) {
|
||||
exceptions.add(e);
|
||||
notifyAll();
|
||||
}
|
||||
exception = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,12 @@ import java.io.IOException;
|
||||
|
||||
interface RemovableDriveMonitor {
|
||||
|
||||
void start() throws IOException;
|
||||
|
||||
File waitForInsertion() throws IOException;
|
||||
void start(Callback c) throws IOException;
|
||||
|
||||
void stop() throws IOException;
|
||||
|
||||
interface Callback {
|
||||
|
||||
void driveInserted(File f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,25 +3,51 @@ package net.sf.briar.plugins.file;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.transport.ConnectionRecogniser;
|
||||
import net.sf.briar.api.transport.InvalidConfigException;
|
||||
import net.sf.briar.api.transport.InvalidTransportException;
|
||||
import net.sf.briar.api.transport.batch.BatchTransportCallback;
|
||||
|
||||
class RemovableDrivePlugin extends FilePlugin {
|
||||
class RemovableDrivePlugin extends FilePlugin
|
||||
implements RemovableDriveMonitor.Callback {
|
||||
|
||||
public static final int TRANSPORT_ID = 0;
|
||||
|
||||
private static final TransportId id = new TransportId(TRANSPORT_ID);
|
||||
|
||||
private final RemovableDriveFinder finder;
|
||||
private final RemovableDriveMonitor monitor;
|
||||
|
||||
RemovableDrivePlugin(RemovableDriveFinder finder) {
|
||||
RemovableDrivePlugin(ConnectionRecogniser recogniser,
|
||||
RemovableDriveFinder finder, RemovableDriveMonitor monitor) {
|
||||
super(recogniser);
|
||||
this.finder = finder;
|
||||
this.monitor = monitor;
|
||||
}
|
||||
|
||||
public TransportId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Map<String, String> localProperties,
|
||||
Map<ContactId, Map<String, String>> remoteProperties,
|
||||
Map<String, String> config, BatchTransportCallback callback)
|
||||
throws InvalidTransportException, InvalidConfigException, IOException {
|
||||
super.start(localProperties, remoteProperties, config, callback);
|
||||
monitor.start(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws IOException {
|
||||
super.stop();
|
||||
monitor.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File chooseOutputDirectory() {
|
||||
try {
|
||||
@@ -43,4 +69,9 @@ class RemovableDrivePlugin extends FilePlugin {
|
||||
protected void writerFinished(File f) {
|
||||
callback.showMessage("REMOVABLE_DRIVE_WRITE_FINISHED");
|
||||
}
|
||||
|
||||
public void driveInserted(File root) {
|
||||
File[] files = root.listFiles();
|
||||
if(files != null) for(File f : files) createReaderFromFile(f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package net.sf.briar.plugins.file;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.contentobjects.jnotify.JNotify;
|
||||
@@ -13,15 +12,16 @@ abstract class UnixRemovableDriveMonitor implements RemovableDriveMonitor,
|
||||
JNotifyListener {
|
||||
|
||||
private final List<Integer> watches = new ArrayList<Integer>();
|
||||
private final LinkedList<File> inserted = new LinkedList<File>();
|
||||
|
||||
private boolean started = false, stopped = false;
|
||||
private boolean started = false;
|
||||
private Callback callback = null;
|
||||
|
||||
protected abstract String[] getPathsToWatch();
|
||||
|
||||
public synchronized void start() throws IOException {
|
||||
if(started || stopped) throw new IllegalStateException();
|
||||
public synchronized void start(Callback callback) throws IOException {
|
||||
if(started) throw new IllegalStateException();
|
||||
started = true;
|
||||
this.callback = callback;
|
||||
int mask = JNotify.FILE_CREATED;
|
||||
for(String path : getPathsToWatch()) {
|
||||
if(new File(path).exists())
|
||||
@@ -29,26 +29,18 @@ JNotifyListener {
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized File waitForInsertion() throws IOException {
|
||||
if(!started || stopped) throw new IllegalStateException();
|
||||
while(inserted.isEmpty()) {
|
||||
try {
|
||||
wait();
|
||||
} catch(InterruptedException ignored) {}
|
||||
}
|
||||
return inserted.poll();
|
||||
}
|
||||
|
||||
public synchronized void stop() throws IOException {
|
||||
if(!started || stopped) throw new IllegalStateException();
|
||||
stopped = true;
|
||||
if(!started) throw new IllegalStateException();
|
||||
started = false;
|
||||
callback = null;
|
||||
for(Integer w : watches) JNotify.removeWatch(w);
|
||||
watches.clear();
|
||||
}
|
||||
|
||||
public void fileCreated(int wd, String rootPath, String name) {
|
||||
synchronized(this) {
|
||||
inserted.add(new File(rootPath + "/" + name));
|
||||
notifyAll();
|
||||
if(!started) throw new IllegalStateException();
|
||||
callback.driveInserted(new File(rootPath + "/" + name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user