mirror of
https://github.com/moparisthebest/mailiverse
synced 2024-11-28 11:22:14 -05:00
add files
This commit is contained in:
parent
10028cd6e8
commit
e822c224af
19
java/core/src/core/connector/ConnectorException.java
Normal file
19
java/core/src/core/connector/ConnectorException.java
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector;
|
||||
|
||||
public class ConnectorException extends Exception
|
||||
{
|
||||
public ConnectorException (Exception e)
|
||||
{
|
||||
super(e);
|
||||
}
|
||||
|
||||
public ConnectorException (String message)
|
||||
{
|
||||
super (message);
|
||||
}
|
||||
}
|
53
java/core/src/core/connector/FileInfo.java
Normal file
53
java/core/src/core/connector/FileInfo.java
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
|
||||
public class FileInfo
|
||||
{
|
||||
static public class SortByDateAscending implements Comparator<FileInfo>
|
||||
{
|
||||
@Override
|
||||
public int compare(FileInfo o1, FileInfo o2)
|
||||
{
|
||||
long time = o1.date.getTime() - o2.date.getTime();
|
||||
return time == 0 ? 0 : (time > 0 ? 1 : -1);
|
||||
}
|
||||
};
|
||||
|
||||
enum Type
|
||||
{
|
||||
Directory
|
||||
}
|
||||
|
||||
public String path;
|
||||
public String relativePath;
|
||||
public long size;
|
||||
public Type type;
|
||||
public Date date;
|
||||
public String version;
|
||||
public Object user;
|
||||
|
||||
public FileInfo(String path, String relativePath, long size, Date date, String version)
|
||||
{
|
||||
this.path = path;
|
||||
this.relativePath = relativePath;
|
||||
this.size = size;
|
||||
this.date = date;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getFileName()
|
||||
{
|
||||
int lastSlash = path.lastIndexOf('/');
|
||||
if (lastSlash == -1)
|
||||
return path;
|
||||
|
||||
return path.substring(lastSlash+1);
|
||||
}
|
||||
}
|
26
java/core/src/core/connector/async/AsyncStoreConnector.java
Normal file
26
java/core/src/core/connector/async/AsyncStoreConnector.java
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.async;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import core.callback.Callback;
|
||||
|
||||
public interface AsyncStoreConnector
|
||||
{
|
||||
Callback list_ (String path);
|
||||
Callback createDirectory_ (String path);
|
||||
Callback ensureDirectories_ (String[] directories);
|
||||
|
||||
Callback put_ (String path, byte[] bytes);
|
||||
Callback get_ (String path);
|
||||
|
||||
Callback put_ (String path);
|
||||
Callback get_ ();
|
||||
|
||||
Callback move_ (String from, String to);
|
||||
Callback delete_ (String path);
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.async;
|
||||
|
||||
import core.callback.Callback;
|
||||
import core.callback.CallbackDefault;
|
||||
import core.util.Base64;
|
||||
import core.util.Zip;
|
||||
|
||||
public abstract class AsyncStoreConnectorAdapter implements AsyncStoreConnector
|
||||
{
|
||||
AsyncStoreConnector connector;
|
||||
|
||||
AsyncStoreConnectorAdapter (AsyncStoreConnector connector)
|
||||
{
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback list_(String path)
|
||||
{
|
||||
return connector.list_(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback createDirectory_(String path)
|
||||
{
|
||||
return connector.createDirectory_(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback ensureDirectories_(String[] directories)
|
||||
{
|
||||
return connector.ensureDirectories_(directories);
|
||||
}
|
||||
|
||||
public Callback get_(String path)
|
||||
{
|
||||
return
|
||||
new CallbackDefault(path) {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
String path = V(0);
|
||||
get_().setReturn(callback).invoke((String)path);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
public Callback get_()
|
||||
{
|
||||
return connector.get_();
|
||||
}
|
||||
|
||||
public Callback put_(String path, byte[] bytes)
|
||||
{
|
||||
return
|
||||
new CallbackDefault(path, bytes) {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
String path = V(0);
|
||||
byte[] bytes = V(1);
|
||||
put_(path).setReturn(callback).invoke(bytes);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Callback put_(String path)
|
||||
{
|
||||
return connector.put_(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback move_(String from, String to)
|
||||
{
|
||||
return connector.move_(from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback delete_(String path)
|
||||
{
|
||||
return connector.delete_(path);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.async;
|
||||
|
||||
import core.callback.Callback;
|
||||
import core.callback.CallbackDefault;
|
||||
import core.callback.CallbackWithVariables;
|
||||
import core.callbacks.SaveArguments;
|
||||
import core.util.Base64;
|
||||
|
||||
|
||||
public class AsyncStoreConnectorBase64 extends AsyncStoreConnectorAdapter
|
||||
{
|
||||
public AsyncStoreConnectorBase64(AsyncStoreConnector connector)
|
||||
{
|
||||
super(connector);
|
||||
}
|
||||
|
||||
public Callback get_()
|
||||
{
|
||||
SaveArguments save = new SaveArguments();
|
||||
|
||||
return super.get_()
|
||||
.addCallback(save)
|
||||
.addCallback(Base64.decodeBytes_())
|
||||
.addCallback(save.restore_(0,101));
|
||||
}
|
||||
|
||||
public Callback put_(String path)
|
||||
{
|
||||
return Base64.encodeBytes_().addCallback(super.put_(path));
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.async;
|
||||
|
||||
import core.callback.Callback;
|
||||
import core.callback.CallbackDefault;
|
||||
import core.callbacks.SaveArguments;
|
||||
import core.crypt.Cryptor;
|
||||
import core.util.Base64;
|
||||
import core.util.Zip;
|
||||
|
||||
public class AsyncStoreConnectorEncrypted extends AsyncStoreConnectorAdapter
|
||||
{
|
||||
Cryptor cryptor;
|
||||
|
||||
public AsyncStoreConnectorEncrypted(Cryptor cryptor, AsyncStoreConnector connector)
|
||||
{
|
||||
super(connector);
|
||||
this.cryptor = cryptor;
|
||||
}
|
||||
|
||||
public Callback get_()
|
||||
{
|
||||
SaveArguments save = new SaveArguments();
|
||||
|
||||
return super.get_()
|
||||
.addCallback(save)
|
||||
.addCallback(cryptor.decrypt_())
|
||||
.addCallback(Zip.inflate_())
|
||||
.addCallback(save.restore_(0,101));
|
||||
|
||||
}
|
||||
|
||||
public Callback put_(String path)
|
||||
{
|
||||
return Zip.deflate_().addCallback(cryptor.encrypt_()).addCallback(super.put_(path));
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.async;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import core.callback.Callback;
|
||||
import core.callback.CallbackChain;
|
||||
import core.callback.CallbackDefault;
|
||||
import core.callback.CallbackEmpty;
|
||||
import core.callback.CallbackWithVariables;
|
||||
import core.connector.FileInfo;
|
||||
|
||||
public abstract class AsyncStoreConnectorHelper implements AsyncStoreConnector
|
||||
{
|
||||
abstract public void list(String path, Callback callback);
|
||||
abstract public void createDirectory(String path, Callback callback);
|
||||
abstract public void get(String path, Callback callback);
|
||||
abstract public void put(String path, byte[] bytes, Callback callback);
|
||||
abstract public void delete(String path, Callback callback);
|
||||
// abstract public void move(String from, String to, Callback callback);
|
||||
|
||||
public void ensureDirectories(String[] folders, Callback callback)
|
||||
{
|
||||
CallbackChain chain = new CallbackChain();
|
||||
|
||||
for (String path : folders)
|
||||
{
|
||||
chain.addCallback(new CallbackWithVariables(path) {
|
||||
|
||||
@Override
|
||||
public void invoke(Object... arguments)
|
||||
{
|
||||
String path = V(0);
|
||||
createDirectory(path, callback);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
chain.setReturn(callback);
|
||||
|
||||
chain.invoke();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback createDirectory_(String path)
|
||||
{
|
||||
return new CallbackDefault(path) {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
createDirectory((String)V(0), callback);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback list_(String path)
|
||||
{
|
||||
return new CallbackDefault(path) {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
list((String)V(0), callback);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback get_()
|
||||
{
|
||||
return new CallbackDefault() {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
get((String)arguments[0], callback);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Callback get_(String path)
|
||||
{
|
||||
return
|
||||
new CallbackDefault(path) {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
get((String)V(0), callback);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback put_(String path)
|
||||
{
|
||||
return new CallbackDefault(path) {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
put((String)V(0), (byte[])arguments[0], callback);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Callback put_(String path, byte[] bytes)
|
||||
{
|
||||
return
|
||||
new CallbackDefault(path, bytes) {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
put((String)V(0), (byte[])V(1), callback);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback move_(String from, String to)
|
||||
{
|
||||
return new CallbackEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback delete_(String path) {
|
||||
return
|
||||
new CallbackDefault(path) {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
delete((String)V(0), callback);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback ensureDirectories_(String[] folders)
|
||||
{
|
||||
return new CallbackDefault(new Object[] { folders }) {
|
||||
|
||||
@Override
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
ensureDirectories((String[])V(0), callback);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
244
java/core/src/core/connector/async/Lock.java
Normal file
244
java/core/src/core/connector/async/Lock.java
Normal file
@ -0,0 +1,244 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.async;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import core.util.SecureRandom;
|
||||
|
||||
import core.callback.Callback;
|
||||
import core.callback.CallbackDefault;
|
||||
import core.connector.FileInfo;
|
||||
import core.util.LogNull;
|
||||
import core.util.LogOut;
|
||||
|
||||
public class Lock
|
||||
{
|
||||
static LogNull log = new LogNull(Lock.class);
|
||||
static SecureRandom random = new SecureRandom();
|
||||
|
||||
public AsyncStoreConnector connector;
|
||||
String path;
|
||||
int intervalSeconds;
|
||||
int remainingBeforeRelockSecond;
|
||||
Date expiration;
|
||||
String version;
|
||||
|
||||
public Lock(AsyncStoreConnector connector, String path, int intervalSeconds, int remainingBeforeRelockSecond)
|
||||
{
|
||||
this.connector = connector;
|
||||
this.path = path;
|
||||
this.intervalSeconds = intervalSeconds;
|
||||
this.remainingBeforeRelockSecond = remainingBeforeRelockSecond;
|
||||
}
|
||||
|
||||
protected void reset ()
|
||||
{
|
||||
version = null;
|
||||
expiration = null;
|
||||
}
|
||||
|
||||
protected Date getExpirationFor (Date timeLocked)
|
||||
{
|
||||
return new Date(timeLocked.getTime() + intervalSeconds * 1000);
|
||||
}
|
||||
|
||||
protected boolean hasExpired (Date expiration)
|
||||
{
|
||||
Date now = new Date();
|
||||
return now.after(expiration);
|
||||
}
|
||||
|
||||
protected boolean closeToExpiration (Date expiration)
|
||||
{
|
||||
return getRemainingTimeInSeconds(expiration) < 1;
|
||||
}
|
||||
|
||||
protected long getRemainingTimeInSeconds (Date expiration)
|
||||
{
|
||||
Date now = new Date();
|
||||
return (expiration.getTime() - now.getTime())/1000;
|
||||
}
|
||||
|
||||
public Callback lock_()
|
||||
{
|
||||
return
|
||||
connector.list_(path)
|
||||
.addCallback(lockOnInfo_())
|
||||
.addCallback(possiblyLockIfNecessary_());
|
||||
}
|
||||
|
||||
public Callback relock_()
|
||||
{
|
||||
return new CallbackDefault()
|
||||
{
|
||||
public void onSuccess(Object... arguments) throws Exception
|
||||
{
|
||||
if (expiration == null || closeToExpiration(expiration))
|
||||
{
|
||||
log.debug(this, "lock close to expired or expired, going to fully lock");
|
||||
call(lock_());
|
||||
}
|
||||
else
|
||||
{
|
||||
log.debug(this, "lock still active, relock only if necesary.");
|
||||
call(possiblyLockIfNecessary_());
|
||||
}
|
||||
}
|
||||
} ;
|
||||
}
|
||||
|
||||
protected Callback possiblyLockIfNecessary_ ()
|
||||
{
|
||||
return new CallbackDefault() {
|
||||
public void onSuccess(Object... arguments) throws Exception
|
||||
{
|
||||
long remainingTime = 0;
|
||||
|
||||
if (expiration != null)
|
||||
{
|
||||
remainingTime = getRemainingTimeInSeconds(expiration);
|
||||
}
|
||||
|
||||
if (remainingTime < remainingBeforeRelockSecond)
|
||||
{
|
||||
log.debug(this, "remainingTime",remainingTime,"<", remainingBeforeRelockSecond, "LOCKING!");
|
||||
|
||||
byte[] bytes = new byte[8];
|
||||
random.nextBytes(bytes);
|
||||
|
||||
call(
|
||||
connector.put_(path, bytes)
|
||||
.addCallback(storeLock_())
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.debug(this, "remainingTime",remainingTime,">=", remainingBeforeRelockSecond);
|
||||
next(arguments);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Callback lockOnInfo_ ()
|
||||
{
|
||||
return new CallbackDefault () {
|
||||
@Override
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
List<FileInfo> fileInfo = (List<FileInfo>) arguments[0];
|
||||
|
||||
boolean locked = false;
|
||||
if (!fileInfo.isEmpty())
|
||||
{
|
||||
FileInfo info = fileInfo.get(0);
|
||||
Date lockExpiration = getExpirationFor(info.date);
|
||||
|
||||
// it's not our lock
|
||||
if (!info.version.equals(version))
|
||||
{
|
||||
locked = !hasExpired(lockExpiration);
|
||||
reset();
|
||||
|
||||
log.debug(this, "file.date", info.date,"lockExpiration",lockExpiration,"locked",locked);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.debug(this, "we have the lock!! setting expiration..", lockExpiration);
|
||||
expiration = lockExpiration;
|
||||
}
|
||||
}
|
||||
|
||||
if (locked)
|
||||
throw new Exception("Someone else has the lock");
|
||||
|
||||
next(arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Callback storeLock_ ()
|
||||
{
|
||||
return new CallbackDefault() {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
expiration = getExpirationFor(new Date());
|
||||
version = (String) arguments[0];
|
||||
|
||||
next(arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void testLock (List<FileInfo> fileInfo) throws Exception
|
||||
{
|
||||
boolean lockFound = false;
|
||||
|
||||
for (FileInfo i : fileInfo)
|
||||
{
|
||||
log.trace("testLock", i.path, path);
|
||||
if (i.path.equals(path))
|
||||
{
|
||||
lockFound = true;
|
||||
|
||||
if (i.version != version)
|
||||
{
|
||||
throw new Exception("Lock was not obtained");
|
||||
}
|
||||
else
|
||||
{
|
||||
log.debug(this, "test lock found the lock, setting the expiration time to the file system.", i.date);
|
||||
expiration = getExpirationFor(i.date);
|
||||
}
|
||||
|
||||
if (hasExpired(expiration))
|
||||
throw new Exception("Lock has already expired");
|
||||
}
|
||||
}
|
||||
|
||||
if (!lockFound)
|
||||
throw new Exception("Lock not found.");
|
||||
}
|
||||
|
||||
public Callback testLock_ ()
|
||||
{
|
||||
return new CallbackDefault () {
|
||||
@Override
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
List<FileInfo> fileInfo = (List<FileInfo>) arguments[0];
|
||||
testLock(fileInfo);
|
||||
next(arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Callback unlock_()
|
||||
{
|
||||
return new CallbackDefault ()
|
||||
{
|
||||
public void onSuccess(Object... arguments) throws Exception
|
||||
{
|
||||
// never unlock, just let them expire
|
||||
|
||||
/*
|
||||
if (hasExpired(expiration))
|
||||
{
|
||||
next(new Exception("Lock has already expired"));
|
||||
}
|
||||
else
|
||||
{
|
||||
connector.delete_(path).setReturn(callback).invoke();
|
||||
reset();
|
||||
}
|
||||
*/
|
||||
|
||||
next(arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
};
|
53
java/core/src/core/connector/dropbox/ClientInfoDropbox.java
Normal file
53
java/core/src/core/connector/dropbox/ClientInfoDropbox.java
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.dropbox;
|
||||
|
||||
import core.constants.ConstantsDropbox;
|
||||
import core.util.Environment;
|
||||
|
||||
|
||||
public class ClientInfoDropbox
|
||||
{
|
||||
private String userPrefix;
|
||||
private String appKey;
|
||||
private String appSecret;
|
||||
private String tokenKey;
|
||||
private String tokenSecret;
|
||||
|
||||
public ClientInfoDropbox (Environment e)
|
||||
{
|
||||
userPrefix = e.get(ConstantsDropbox.DropboxUserPrefix);
|
||||
appKey = e.checkGet(ConstantsDropbox.DropboxAppKey);
|
||||
appSecret = e.checkGet(ConstantsDropbox.DropboxAppSecret);
|
||||
tokenKey = e.checkGet(ConstantsDropbox.DropboxTokenKey);
|
||||
tokenSecret = e.checkGet(ConstantsDropbox.DropboxTokenSecret);
|
||||
}
|
||||
|
||||
public String getUserPrefix ()
|
||||
{
|
||||
return userPrefix;
|
||||
}
|
||||
|
||||
public String getAppKey ()
|
||||
{
|
||||
return appKey;
|
||||
}
|
||||
|
||||
public String getAppSecret ()
|
||||
{
|
||||
return appSecret;
|
||||
}
|
||||
|
||||
public String getTokenKey ()
|
||||
{
|
||||
return tokenKey;
|
||||
}
|
||||
|
||||
public String getTokenSecret ()
|
||||
{
|
||||
return tokenSecret;
|
||||
}
|
||||
}
|
375
java/core/src/core/connector/dropbox/async/ConnectorDropbox.java
Normal file
375
java/core/src/core/connector/dropbox/async/ConnectorDropbox.java
Normal file
@ -0,0 +1,375 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.dropbox.async;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import core.callback.Callback;
|
||||
import core.callback.CallbackDefault;
|
||||
import core.callback.CallbackWithVariables;
|
||||
import core.connector.FileInfo;
|
||||
import core.connector.async.AsyncStoreConnectorHelper;
|
||||
import core.connector.dropbox.ClientInfoDropbox;
|
||||
import core.util.DateFormat;
|
||||
import core.util.FastRandom;
|
||||
import core.util.HttpDelegate;
|
||||
import core.util.LogNull;
|
||||
|
||||
public class ConnectorDropbox extends AsyncStoreConnectorHelper
|
||||
{
|
||||
static LogNull log = new LogNull(ConnectorDropbox.class);
|
||||
|
||||
ClientInfoDropbox info;
|
||||
HttpDelegate httpDelegate;
|
||||
FastRandom fastRandom;
|
||||
|
||||
public ConnectorDropbox(ClientInfoDropbox clientInfo, HttpDelegate httpDelegate)
|
||||
{
|
||||
this.info = clientInfo;
|
||||
this.httpDelegate = httpDelegate;
|
||||
fastRandom = new FastRandom();
|
||||
}
|
||||
|
||||
protected String getGlobalPath (String path)
|
||||
{
|
||||
if (info.getUserPrefix() != null)
|
||||
return info.getUserPrefix() + "/" + path;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public void listDirectoryFinished (String containingPath, Callback callback, Object... arguments)
|
||||
{
|
||||
log.debug("listDirectoryFinished");
|
||||
try
|
||||
{
|
||||
if (arguments[0] instanceof Exception)
|
||||
throw (Exception)arguments[0];
|
||||
|
||||
String result = (String)arguments[0];
|
||||
List<FileInfo> fileInfos = new ArrayList<FileInfo>();
|
||||
|
||||
JSONObject o = new JSONObject(result);
|
||||
JSONArray contents = (JSONArray) o.get("contents");
|
||||
|
||||
DateFormat dateTimeFormat = new DateFormat("EEE, d MMM yyyy HH:mm:ss Z");
|
||||
|
||||
for (int i=0; i<contents.length(); ++i)
|
||||
{
|
||||
JSONObject f = (JSONObject) contents.get(i);
|
||||
String dropboxPath = (String) f.get("path");
|
||||
|
||||
int realPath = dropboxPath.indexOf(containingPath);
|
||||
if (realPath == -1)
|
||||
continue;
|
||||
|
||||
String path = dropboxPath.substring(realPath);
|
||||
String relativePath = path.substring(containingPath.length());
|
||||
|
||||
long size = ((Integer)f.get("bytes")).longValue();
|
||||
String time = (String) f.get("modified");
|
||||
String revision = (String) f.getString("rev");
|
||||
|
||||
Date date = dateTimeFormat.parse(time);
|
||||
FileInfo fi = new FileInfo(path, relativePath, size, date, revision);
|
||||
|
||||
fileInfos.add(fi);
|
||||
}
|
||||
|
||||
Collections.sort(fileInfos, new FileInfo.SortByDateAscending());
|
||||
for (FileInfo i : fileInfos)
|
||||
log.debug ("path: ", i.path, " date:", i.date);
|
||||
|
||||
callback.invoke(fileInfos);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
|
||||
callback.invoke(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void searchDirectoryFinished (String containingPath, Callback callback, Object... arguments)
|
||||
{
|
||||
log.debug("listDirectoryFinished");
|
||||
try
|
||||
{
|
||||
if (arguments[0] instanceof Exception)
|
||||
throw (Exception)arguments[0];
|
||||
|
||||
String result = (String)arguments[0];
|
||||
List<FileInfo> fileInfos = new ArrayList<FileInfo>();
|
||||
|
||||
JSONArray contents = new JSONArray(result);
|
||||
DateFormat dateTimeFormat = new DateFormat("EEE, d MMM yyyy HH:mm:ss Z");
|
||||
|
||||
for (int i=0; i<contents.length(); ++i)
|
||||
{
|
||||
JSONObject f = (JSONObject) contents.get(i);
|
||||
String dropboxPath = (String) f.get("path");
|
||||
|
||||
int realPath = dropboxPath.indexOf(containingPath);
|
||||
if (realPath == -1)
|
||||
continue;
|
||||
|
||||
String path = dropboxPath.substring(realPath);
|
||||
String relativePath = path.substring(containingPath.length());
|
||||
|
||||
long size = ((Integer)f.get("bytes")).longValue();
|
||||
String time = (String) f.get("modified");
|
||||
String revision = (String) f.getString("rev");
|
||||
|
||||
Date date = dateTimeFormat.parse(time);
|
||||
FileInfo fi = new FileInfo(path, relativePath, size, date, revision);
|
||||
|
||||
fileInfos.add(fi);
|
||||
}
|
||||
|
||||
Collections.sort(fileInfos, new FileInfo.SortByDateAscending());
|
||||
for (FileInfo i : fileInfos)
|
||||
log.debug ("path: ", i.path, " date:", i.date);
|
||||
|
||||
callback.invoke(fileInfos);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
|
||||
callback.invoke(e);
|
||||
}
|
||||
}
|
||||
public void list (String path, Callback callback)
|
||||
{
|
||||
if (path.endsWith("/"))
|
||||
doList(path, callback);
|
||||
else
|
||||
doSearch(path, callback);
|
||||
}
|
||||
|
||||
public void doSearch(String path, Callback callback)
|
||||
{
|
||||
log.debug("searchDirectory",path);
|
||||
try
|
||||
{
|
||||
String API_METADATA_URL="https://api.dropbox.com/1/search/sandbox";
|
||||
|
||||
String globalPath = getGlobalPath(path);
|
||||
String directory = globalPath.substring(0, globalPath.lastIndexOf('/'));
|
||||
String file = globalPath.substring(globalPath.lastIndexOf('/')+1);
|
||||
|
||||
String url =
|
||||
API_METADATA_URL +
|
||||
"/" + directory +
|
||||
"?query=" + file +
|
||||
"&oauth_consumer_key=" + info.getAppKey() +
|
||||
"&oauth_token=" + info.getTokenKey() +
|
||||
"&oauth_signature_method=PLAINTEXT" +
|
||||
"&oauth_signature=" + info.getAppSecret() + "%26" + info.getTokenSecret() +
|
||||
"&oauth_timestamp=" + new Date().getTime() +
|
||||
"&oauth_nonce=" + fastRandom.nextInt();
|
||||
|
||||
httpDelegate.execute (HttpDelegate.GET, url, null, false, false, null,
|
||||
new CallbackWithVariables(callback, path) {
|
||||
@Override
|
||||
public void invoke(Object... arguments)
|
||||
{
|
||||
Callback callback = V(0);
|
||||
String path = V(1);
|
||||
searchDirectoryFinished(path, callback, arguments);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
callback.invoke(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void doList(String path, Callback callback)
|
||||
{
|
||||
log.debug("listDirectory",path);
|
||||
try
|
||||
{
|
||||
String API_METADATA_URL="https://api.dropbox.com/1/metadata/sandbox";
|
||||
|
||||
String url =
|
||||
API_METADATA_URL +
|
||||
"/" + getGlobalPath(path) + "?" +
|
||||
"oauth_consumer_key=" + info.getAppKey() + "&" +
|
||||
"oauth_token=" + info.getTokenKey() + "&" +
|
||||
"oauth_signature_method=PLAINTEXT" + "&" +
|
||||
"oauth_signature=" + info.getAppSecret() + "%26" + info.getTokenSecret() + "&" +
|
||||
"oauth_timestamp=" + new Date().getTime() + "&" +
|
||||
"oauth_nonce=" + fastRandom.nextInt();
|
||||
|
||||
httpDelegate.execute (HttpDelegate.GET, url, null, false, false, null,
|
||||
new CallbackWithVariables(callback, path) {
|
||||
@Override
|
||||
public void invoke(Object... arguments)
|
||||
{
|
||||
Callback callback = V(0);
|
||||
String path = V(1);
|
||||
listDirectoryFinished(path, callback, arguments);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
callback.invoke(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void createDirectory(String path, Callback callback)
|
||||
{
|
||||
log.debug("createDirectory",path);
|
||||
try
|
||||
{
|
||||
String API_METADATA_URL="https://api.dropbox.com/1/fileops/create_folder";
|
||||
|
||||
String url =
|
||||
API_METADATA_URL +
|
||||
"?root=sandbox" +
|
||||
"&path="+ getGlobalPath(path) +
|
||||
"&locale=en" +
|
||||
"&oauth_consumer_key=" + info.getAppKey() +
|
||||
"&oauth_token=" + info.getTokenKey() +
|
||||
"&oauth_signature_method=PLAINTEXT" +
|
||||
"&oauth_signature=" + info.getAppSecret() + "%26" + info.getTokenSecret() +
|
||||
"&oauth_timestamp=" + new Date().getTime() +
|
||||
"&oauth_nonce=" + fastRandom.nextInt();
|
||||
|
||||
httpDelegate.execute(HttpDelegate.GET, url, null, false, false, null, callback);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
callback.invoke(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void get(String path, Callback callback)
|
||||
{
|
||||
log.debug("get",path);
|
||||
try
|
||||
{
|
||||
String API_METADATA_URL="https://api-content.dropbox.com/1/files/sandbox";
|
||||
|
||||
String url =
|
||||
API_METADATA_URL +
|
||||
"/" + getGlobalPath(path) + "?" +
|
||||
"oauth_consumer_key=" + info.getAppKey() + "&" +
|
||||
"oauth_token=" + info.getTokenKey() + "&" +
|
||||
"oauth_signature_method=PLAINTEXT" + "&" +
|
||||
"oauth_signature=" + info.getAppSecret() + "%26" + info.getTokenSecret() + "&" +
|
||||
"oauth_timestamp=" + new Date().getTime() + "&" +
|
||||
"oauth_nonce=" + fastRandom.nextInt();
|
||||
|
||||
log.debug(url);
|
||||
|
||||
httpDelegate.execute(HttpDelegate.GET, url, null, false, true, null, grabVersionGet_().setReturn(callback));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
callback.invoke(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void put(String path, byte[] contents, Callback callback)
|
||||
{
|
||||
log.debug("put",path);
|
||||
try
|
||||
{
|
||||
String API_METADATA_URL="https://api-content.dropbox.com/1/files_put/sandbox";
|
||||
|
||||
String url =
|
||||
API_METADATA_URL +
|
||||
"/" + getGlobalPath(path) + "?" +
|
||||
"oauth_consumer_key=" + info.getAppKey() + "&" +
|
||||
"oauth_token=" + info.getTokenKey() + "&" +
|
||||
"oauth_signature_method=PLAINTEXT" + "&" +
|
||||
"oauth_signature=" + info.getAppSecret() + "%26" + info.getTokenSecret() + "&" +
|
||||
"oauth_timestamp=" + new Date().getTime() + "&" +
|
||||
"oauth_nonce=" + fastRandom.nextInt();
|
||||
|
||||
log.debug(url);
|
||||
|
||||
httpDelegate.execute(HttpDelegate.PUT, url, null, true, false, contents, grabVersionPut_().setReturn(callback));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
callback.invoke(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(String path, Callback callback)
|
||||
{
|
||||
log.debug("delete",path);
|
||||
try
|
||||
{
|
||||
String API_METADATA_URL="https://api.dropbox.com/1/fileops/delete";
|
||||
|
||||
String url =
|
||||
API_METADATA_URL +
|
||||
"?root=sandbox" +
|
||||
"&path=" + getGlobalPath(path) +
|
||||
"&oauth_consumer_key=" + info.getAppKey() +
|
||||
"&oauth_token=" + info.getTokenKey() +
|
||||
"&oauth_signature_method=PLAINTEXT" +
|
||||
"&oauth_signature=" + info.getAppSecret() + "%26" + info.getTokenSecret() +
|
||||
"&oauth_timestamp=" + new Date().getTime() +
|
||||
"&oauth_nonce=" + fastRandom.nextInt();
|
||||
|
||||
log.debug(url);
|
||||
|
||||
httpDelegate.execute(HttpDelegate.POST, url, null, false, false, null, callback);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
callback.invoke(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Callback grabVersionPut_()
|
||||
{
|
||||
return new CallbackDefault() {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
String response = (String) arguments[0];
|
||||
JSONObject json = new JSONObject(response);
|
||||
next(json.getString("rev"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Callback grabVersionGet_()
|
||||
{
|
||||
return new CallbackDefault() {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
String[][] headers = (String[][])arguments[1];
|
||||
for (String[] pair : headers)
|
||||
{
|
||||
if (pair[0].equals("x-dropbox-metadata"))
|
||||
{
|
||||
JSONObject json = new JSONObject(pair[1]);
|
||||
next(arguments[0], json.getString("rev"));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("No x-dropbox-metadata response header");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
229
java/core/src/core/connector/dropbox/sync/DropboxConnector.java
Normal file
229
java/core/src/core/connector/dropbox/sync/DropboxConnector.java
Normal file
@ -0,0 +1,229 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.dropbox.sync;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import core.connector.dropbox.ClientInfoDropbox;
|
||||
|
||||
import com.dropbox.client2.DropboxAPI;
|
||||
import com.dropbox.client2.DropboxAPI.Entry;
|
||||
import com.dropbox.client2.session.AccessTokenPair;
|
||||
import com.dropbox.client2.session.AppKeyPair;
|
||||
import com.dropbox.client2.session.Session;
|
||||
import com.dropbox.client2.session.WebAuthSession;
|
||||
|
||||
import core.connector.ConnectorException;
|
||||
import core.connector.FileInfo;
|
||||
import core.connector.sync.StoreConnector;
|
||||
import core.util.Streams;
|
||||
|
||||
|
||||
public class DropboxConnector implements StoreConnector
|
||||
{
|
||||
ClientInfoDropbox clientInfo;
|
||||
DropboxAPI<?> db;
|
||||
|
||||
public DropboxConnector (ClientInfoDropbox clientInfo)
|
||||
{
|
||||
this.clientInfo = clientInfo;
|
||||
}
|
||||
|
||||
public DropboxAPI<?> createConnection (ClientInfoDropbox info)
|
||||
{
|
||||
AppKeyPair appKeyPair = new AppKeyPair(info.getAppKey(),info.getAppSecret());
|
||||
AccessTokenPair userTokenKeyPair = new AccessTokenPair(info.getTokenKey(), info.getTokenSecret());
|
||||
|
||||
WebAuthSession sourceSession =
|
||||
new WebAuthSession(appKeyPair, Session.AccessType.APP_FOLDER, userTokenKeyPair);
|
||||
|
||||
DropboxAPI<?> sourceClient = new DropboxAPI<WebAuthSession>(sourceSession);
|
||||
|
||||
return sourceClient;
|
||||
}
|
||||
|
||||
|
||||
public void open () throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
db = createConnection(clientInfo);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void close ()
|
||||
{
|
||||
db = null;
|
||||
}
|
||||
|
||||
protected String getGlobalPath (String path)
|
||||
{
|
||||
if (clientInfo.getUserPrefix() != null)
|
||||
return "/" + clientInfo.getUserPrefix() + "/" + path;
|
||||
|
||||
return "/" + path;
|
||||
}
|
||||
|
||||
protected String getUserPath (String path)
|
||||
{
|
||||
if (clientInfo.getUserPrefix() != null)
|
||||
return path.substring(2 + clientInfo.getUserPrefix().length());
|
||||
|
||||
return path.substring(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfo> listDirectory(String path) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!path.endsWith("/"))
|
||||
path = path + "/";
|
||||
|
||||
Entry directory = db.metadata(getGlobalPath(path), 10000, null, true, null);
|
||||
List<FileInfo> listing = new ArrayList<FileInfo>(directory.contents.size());
|
||||
|
||||
SimpleDateFormat dateTimeFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
|
||||
for (Entry file : directory.contents)
|
||||
{
|
||||
if (file.isDeleted)
|
||||
continue;
|
||||
|
||||
String fullPath = getUserPath(file.path);
|
||||
String relativePath = fullPath.substring(path.length());
|
||||
|
||||
listing.add(
|
||||
new FileInfo(
|
||||
fullPath,
|
||||
relativePath,
|
||||
file.bytes, dateTimeFormat.parse(file.modified),
|
||||
file.rev
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Collections.sort(listing, new FileInfo.SortByDateAscending());
|
||||
|
||||
return listing;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectory(String path) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
db.createFolder(getGlobalPath(path));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] get(String path) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
Entry meta = db.metadata(getGlobalPath(path), 1, null, true, null);
|
||||
if (meta.isDeleted)
|
||||
throw new ConnectorException("File deleted");
|
||||
|
||||
return Streams.readFullyBytes(db.getFileStream(getGlobalPath(path), null));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] get(String path, long size) throws ConnectorException
|
||||
{
|
||||
return get(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String path, byte[] contents) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
db.putFileOverwrite(getGlobalPath(path), new ByteArrayInputStream(contents), contents.length, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(String from, String to) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
db.move(getGlobalPath(from), getGlobalPath(to));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String path) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
db.delete(getGlobalPath(path));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean ensureDirectories (String ... folders)
|
||||
{
|
||||
for (String folder : folders)
|
||||
{
|
||||
String[] parts = folder.split("/");
|
||||
|
||||
String path = "";
|
||||
for (String part : parts)
|
||||
{
|
||||
if (!path.isEmpty())
|
||||
path += "/";
|
||||
|
||||
path += part;
|
||||
String fullPath = getGlobalPath(path);
|
||||
try
|
||||
{
|
||||
db.createFolder(fullPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.out.format("Folder[%s] already exists.\n", fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
82
java/core/src/core/connector/dropbox/sync/DropboxSignup.java
Normal file
82
java/core/src/core/connector/dropbox/sync/DropboxSignup.java
Normal file
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.dropbox.sync;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Date;
|
||||
|
||||
import com.dropbox.client2.session.AccessTokenPair;
|
||||
import com.dropbox.client2.session.AppKeyPair;
|
||||
|
||||
import core.util.HttpDelegate;
|
||||
import core.util.LogNull;
|
||||
import core.util.LogOut;
|
||||
import core.util.Pair;
|
||||
import core.util.Streams;
|
||||
|
||||
public class DropboxSignup
|
||||
{
|
||||
static LogNull log = new LogNull (DropboxSignup.class);
|
||||
|
||||
static public AccessTokenPair getDropboxRequestToken (AppKeyPair appKeyPair) throws Exception
|
||||
{
|
||||
log.debug("getDropboxUserToken");
|
||||
URL url = new URL(
|
||||
"https://api.dropbox.com/1/oauth/request_token" +
|
||||
"?oauth_consumer_key=" + appKeyPair.key +
|
||||
"&oauth_signature_method=PLAINTEXT" +
|
||||
"&oauth_signature=" + appKeyPair.secret + "%26" +
|
||||
"&oauth_nonce=\"" + (new Date()).getTime() + "\""
|
||||
);
|
||||
URLConnection c = url.openConnection();
|
||||
String response = Streams.readFullyString(c.getInputStream(), "UTF-8");
|
||||
|
||||
Pair<String,String> token = parseAuthToken(response);
|
||||
return new AccessTokenPair(token.first, token.second);
|
||||
}
|
||||
|
||||
static public AccessTokenPair getDropboxAccessToken (AppKeyPair appKeyPair, AccessTokenPair accessToken) throws Exception
|
||||
{
|
||||
URL url = new URL(
|
||||
"https://api.dropbox.com/1/oauth/access_token" +
|
||||
"?oauth_consumer_key=" + appKeyPair.key +
|
||||
"&oauth_token=" + accessToken.key + "&" +
|
||||
"&oauth_signature_method=PLAINTEXT" +
|
||||
"&oauth_signature=" + appKeyPair.secret + "%26" + accessToken.secret +
|
||||
"&oauth_nonce=\"" + (new Date()).getTime() + "\""
|
||||
);
|
||||
URLConnection c = url.openConnection();
|
||||
String response = Streams.readFullyString(c.getInputStream(), "UTF-8");
|
||||
|
||||
Pair<String,String> token = parseAuthToken(response);
|
||||
return new AccessTokenPair(token.first, token.second);
|
||||
}
|
||||
|
||||
static Pair<String,String> parseAuthToken (String response) throws Exception
|
||||
{
|
||||
String userKey=null, userSecret=null;
|
||||
String[] parts = response.split("&");
|
||||
for (String part : parts)
|
||||
{
|
||||
String[] keyValue = part.split("=");
|
||||
String key = keyValue[0];
|
||||
String value = keyValue[1];
|
||||
|
||||
if (key.equalsIgnoreCase("oauth_token_secret"))
|
||||
userSecret = value;
|
||||
else
|
||||
if (key.equalsIgnoreCase("oauth_token"))
|
||||
userKey = value;
|
||||
}
|
||||
|
||||
if (userSecret == null || userKey == null)
|
||||
throw new Exception ("Could parse authToken");
|
||||
|
||||
return new Pair<String,String>(userKey, userSecret);
|
||||
}
|
||||
}
|
124
java/core/src/core/connector/misc/sync/FileSystemConnector.java
Normal file
124
java/core/src/core/connector/misc/sync/FileSystemConnector.java
Normal file
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.misc.sync;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import core.connector.ConnectorException;
|
||||
import core.connector.FileInfo;
|
||||
import core.connector.sync.StoreConnector;
|
||||
import core.util.FileSystem;
|
||||
import core.util.Streams;
|
||||
|
||||
|
||||
public class FileSystemConnector implements StoreConnector
|
||||
{
|
||||
String prefix;
|
||||
|
||||
public FileSystemConnector (String root)
|
||||
{
|
||||
this.prefix = root + "/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws ConnectorException
|
||||
{
|
||||
File directory = new File(prefix);
|
||||
if (!directory.exists())
|
||||
throw new ConnectorException("Store directory does not exist");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfo> listDirectory(String path) throws ConnectorException
|
||||
{
|
||||
return FileSystem.allFilesFor(new File(prefix + path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectory(String path) throws ConnectorException
|
||||
{
|
||||
File dir = new File (prefix + path);
|
||||
if (!dir.mkdir())
|
||||
{
|
||||
throw new ConnectorException("Unable to create directory");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] get(String path) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
return Streams.readFullyBytes(new FileInputStream(prefix + path));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] get(String path, long size) throws ConnectorException
|
||||
{
|
||||
return get(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String path, byte[] contents) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (path.contains("/"))
|
||||
ensureDirectories(path.substring(0, path.lastIndexOf("/")));
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(prefix + path);
|
||||
fos.write(contents);
|
||||
fos.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(String from, String to) throws ConnectorException
|
||||
{
|
||||
File fromFile = new File(prefix + from);
|
||||
File toFile = new File (prefix, to);
|
||||
|
||||
if (!fromFile.renameTo(toFile))
|
||||
throw new ConnectorException("move file failed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String path) throws ConnectorException
|
||||
{
|
||||
File file = new File(prefix + path);
|
||||
if (!file.delete())
|
||||
throw new ConnectorException("delete file failed");
|
||||
}
|
||||
|
||||
public boolean ensureDirectories (String ... folders)
|
||||
{
|
||||
for (String folder : folders)
|
||||
{
|
||||
File path = new File (prefix + folder);
|
||||
path.mkdirs();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
58
java/core/src/core/connector/s3/ClientInfoS3.java
Normal file
58
java/core/src/core/connector/s3/ClientInfoS3.java
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.s3;
|
||||
|
||||
import core.constants.ConstantsS3;
|
||||
import core.util.Environment;
|
||||
|
||||
|
||||
public class ClientInfoS3
|
||||
{
|
||||
private String bucketName;
|
||||
private String bucketRegion;
|
||||
private String accessId;
|
||||
private String secretKey;
|
||||
|
||||
public ClientInfoS3 (Environment e)
|
||||
{
|
||||
bucketName = e.get(ConstantsS3.AWSBucketName);
|
||||
bucketRegion = e.get(ConstantsS3.AWSBucketRegion);
|
||||
accessId = e.checkGet(ConstantsS3.AWSAccessKeyId);
|
||||
secretKey = e.checkGet(ConstantsS3.AWSSecretKey);
|
||||
}
|
||||
|
||||
public String getBucketEndpoint ()
|
||||
{
|
||||
String bucketEndPoint = null;
|
||||
|
||||
if (bucketRegion == null || bucketRegion.equals(""))
|
||||
bucketEndPoint = "s3.amazonaws.com";
|
||||
else
|
||||
bucketEndPoint = "s3-" + bucketRegion + ".amazonaws.com";
|
||||
|
||||
return bucketEndPoint;
|
||||
}
|
||||
|
||||
public String getBucketName()
|
||||
{
|
||||
return bucketName;
|
||||
}
|
||||
|
||||
public String getBucketRegion ()
|
||||
{
|
||||
return bucketRegion;
|
||||
}
|
||||
|
||||
public String getAccessId()
|
||||
{
|
||||
return accessId;
|
||||
}
|
||||
|
||||
public String getSecretKey()
|
||||
{
|
||||
return secretKey;
|
||||
}
|
||||
}
|
351
java/core/src/core/connector/s3/async/S3Connector.java
Normal file
351
java/core/src/core/connector/s3/async/S3Connector.java
Normal file
@ -0,0 +1,351 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.s3.async;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import core.util.Base64;
|
||||
import core.callback.Callback;
|
||||
import core.callback.CallbackDefault;
|
||||
import core.callback.CallbackWithVariables;
|
||||
import core.connector.FileInfo;
|
||||
import core.connector.async.AsyncStoreConnectorHelper;
|
||||
import core.connector.s3.ClientInfoS3;
|
||||
import core.crypt.HashSha256;
|
||||
import core.crypt.HmacSha1;
|
||||
import core.util.DateFormat;
|
||||
import core.util.FastRandom;
|
||||
import core.util.HttpDelegate;
|
||||
import core.util.LogNull;
|
||||
import core.util.Strings;
|
||||
import core.util.XML;
|
||||
|
||||
public class S3Connector extends AsyncStoreConnectorHelper
|
||||
{
|
||||
static LogNull log = new LogNull(S3Connector.class);
|
||||
final int LOCK_INTERVAL = 10 * 1000;
|
||||
|
||||
ClientInfoS3 info;
|
||||
HttpDelegate httpDelegate;
|
||||
|
||||
HmacSha1 mac;
|
||||
static FastRandom fastRandom = new FastRandom();
|
||||
|
||||
|
||||
protected String createUrlPrefix ()
|
||||
{
|
||||
return "https://" + info.getBucketEndpoint() + "/" + info.getBucketName() + "/";
|
||||
}
|
||||
|
||||
protected String createRandomPostfix ()
|
||||
{
|
||||
return "random=" + fastRandom.nextLong();
|
||||
}
|
||||
|
||||
// This method converts AWSSecretKey into crypto instance.
|
||||
protected void setKey(String AWSSecretKey) throws Exception
|
||||
{
|
||||
mac = new HmacSha1(Strings.toBytes(AWSSecretKey));
|
||||
}
|
||||
|
||||
// This method creates S3 signature for a given String.
|
||||
protected String sign(String data) throws Exception
|
||||
{
|
||||
// Signed String must be BASE64 encoded.
|
||||
byte[] signBytes = mac.mac(Strings.toBytes(data));
|
||||
String signature = Base64.encode(signBytes);
|
||||
return signature;
|
||||
}
|
||||
|
||||
protected String format(String format, Date date)
|
||||
{
|
||||
DateFormat df = new DateFormat(format);
|
||||
String dateString = df.format(date, 0) + " GMT";
|
||||
return dateString;
|
||||
}
|
||||
|
||||
protected String[][] makeHeaders (String keyId, String method, String contentMD5, String contentType, int contentLength, Date date, String resource) throws Exception
|
||||
{
|
||||
String fmt = "EEE, dd MMM yyyy HH:mm:ss";
|
||||
String dateString = format(fmt, date);
|
||||
|
||||
// Generate signature
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append(method).append("\n");
|
||||
buf.append(contentMD5).append("\n");
|
||||
buf.append(contentType).append("\n");
|
||||
buf.append("\n"); // empty real date header
|
||||
buf.append("x-amz-date:");
|
||||
buf.append(dateString).append("\n");
|
||||
buf.append(resource);
|
||||
|
||||
log.debug("Signing:{" + buf.toString() + "}");
|
||||
String signature = sign(buf.toString());
|
||||
|
||||
String[][] headers;
|
||||
if (method.equals("PUT"))
|
||||
{
|
||||
headers = new String[][] {
|
||||
{"X-Amz-Date" , dateString },
|
||||
{"Content-Type", contentType },
|
||||
{"Content-Length", ""+contentLength },
|
||||
{"Authorization", "AWS " + keyId + ":" + signature }
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
headers = new String[][] {
|
||||
{"X-Amz-Date" , dateString },
|
||||
{"Authorization", "AWS " + keyId + ":" + signature }
|
||||
};
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
public S3Connector(ClientInfoS3 clientInfo, HttpDelegate httpDelegate) throws Exception
|
||||
{
|
||||
this.info = clientInfo;
|
||||
this.httpDelegate = httpDelegate;
|
||||
|
||||
setKey (info.getSecretKey());
|
||||
}
|
||||
|
||||
long toVersionFromString (String s) throws Exception
|
||||
{
|
||||
HashSha256 hash = new HashSha256();
|
||||
byte[] result = hash.hash(Strings.toBytes(s));
|
||||
|
||||
long l =
|
||||
((long)result[0]) |
|
||||
((long)result[1] << 8) |
|
||||
((long)result[2] << 16) |
|
||||
((long)result[3] << 24);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
public void listDirectoryFinished (List<FileInfo> files, Callback callback, String path, Object... arguments)
|
||||
{
|
||||
log.debug("listDirectoryFinished");
|
||||
try
|
||||
{
|
||||
if (arguments[0] instanceof Exception)
|
||||
throw (Exception)arguments[0];
|
||||
|
||||
String result = (String)arguments[0];
|
||||
log.trace(result);
|
||||
|
||||
DateFormat dateTimeFormat = new DateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z' Z");
|
||||
|
||||
Object doc = XML.parse(result);
|
||||
Object[] nodes = XML.getElementsByTagName(doc, "Contents");
|
||||
for (Object currentNode : nodes)
|
||||
{
|
||||
if ( XML.getNodeType(currentNode) == XML.ELEMENT_NODE )
|
||||
{
|
||||
Object keyNode = XML.getElementsByTagName(currentNode, "Key")[0];
|
||||
Object etagNode = XML.getElementsByTagName(currentNode, "ETag")[0];
|
||||
Object sizeNode = XML.getElementsByTagName(currentNode, "Size")[0];
|
||||
Object lastModifiedNode = XML.getElementsByTagName(currentNode, "LastModified")[0];
|
||||
|
||||
log.trace(XML.textOf(keyNode), XML.textOf(sizeNode), XML.textOf(etagNode), XML.textOf(lastModifiedNode));
|
||||
|
||||
String fullPath = XML.textOf(keyNode);
|
||||
String relativePath = fullPath.substring(path.length());
|
||||
|
||||
FileInfo fi = new FileInfo(
|
||||
fullPath,
|
||||
relativePath,
|
||||
Long.parseLong(XML.textOf(sizeNode)),
|
||||
dateTimeFormat.parse(XML.textOf(lastModifiedNode) + " GMT"),
|
||||
XML.textOf(etagNode)
|
||||
);
|
||||
|
||||
files.add(fi);
|
||||
}
|
||||
}
|
||||
|
||||
if (XML.textOf(XML.getElementsByTagName(doc, "IsTruncated")[0]).equals("true"))
|
||||
{
|
||||
log.debug("results were truncated, requesting more...");
|
||||
listIterative(files, path, callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.debug("results were complete, invoking callback");
|
||||
|
||||
Collections.sort(files, new FileInfo.SortByDateAscending());
|
||||
for (FileInfo i : files)
|
||||
log.trace ("path: ", i.path, " date:", i.date);
|
||||
|
||||
callback.invoke(files);
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
|
||||
callback.invoke(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void list(String path, Callback callback)
|
||||
{
|
||||
listIterative(new ArrayList<FileInfo>(), path, callback);
|
||||
}
|
||||
|
||||
public void listIterative(List<FileInfo> files, String path, Callback callback)
|
||||
{
|
||||
log.debug("listDirectory",path);
|
||||
try
|
||||
{
|
||||
String url =
|
||||
createUrlPrefix() +
|
||||
"?prefix=" + path + "&max-keys=1000" +
|
||||
(!files.isEmpty() ? ("&marker=" + files.get(files.size()-1).path) : "") +
|
||||
"&" + createRandomPostfix();
|
||||
|
||||
log.debug(url);
|
||||
|
||||
String[][] headers = makeHeaders (
|
||||
info.getAccessId(), "GET", "", "", 0, new Date(), "/" + info.getBucketName() + "/"
|
||||
);
|
||||
|
||||
httpDelegate.execute (HttpDelegate.GET, url, headers, false, false, null,
|
||||
new CallbackWithVariables(files, callback, path) {
|
||||
@Override
|
||||
public void invoke(Object... arguments)
|
||||
{
|
||||
List<FileInfo> files = V(0);
|
||||
Callback callback = V(1);
|
||||
String path = V(2);
|
||||
listDirectoryFinished(files, callback, path, arguments);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
|
||||
callback.invoke(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectory(String path, Callback callback)
|
||||
{
|
||||
log.debug("createDirectory",path);
|
||||
callback.invoke(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void get(String path, Callback callback)
|
||||
{
|
||||
log.debug("get",path);
|
||||
try
|
||||
{
|
||||
String url =
|
||||
createUrlPrefix() +
|
||||
path +
|
||||
"?" + createRandomPostfix();
|
||||
|
||||
log.debug(url);
|
||||
|
||||
String[][] headers = makeHeaders (
|
||||
info.getAccessId(), "GET", "", "", 0, new Date(), "/" + info.getBucketName() + "/" + path
|
||||
);
|
||||
|
||||
httpDelegate.execute(HttpDelegate.GET, url, headers, false, true, null, grabVersion_(true).setReturn(callback));
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
callback.invoke(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Callback grabVersion_(boolean includeResponseData)
|
||||
{
|
||||
return new CallbackDefault(includeResponseData) {
|
||||
public void onSuccess(Object... arguments) throws Exception {
|
||||
|
||||
boolean includeResponseData = V(0);
|
||||
String[][] headers = (String[][])arguments[1];
|
||||
|
||||
for (String[] pair : headers)
|
||||
{
|
||||
if (pair[0].equals("ETag"))
|
||||
{
|
||||
if (includeResponseData)
|
||||
next(arguments[0], pair[1]);
|
||||
else
|
||||
next(pair[1]);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("No ETag Response header");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String path, byte[] contents, Callback callback)
|
||||
{
|
||||
log.debug("put",path);
|
||||
try
|
||||
{
|
||||
String url =
|
||||
createUrlPrefix() +
|
||||
path +
|
||||
"?" + createRandomPostfix();
|
||||
|
||||
log.debug(url);
|
||||
|
||||
String[][] headers = makeHeaders (
|
||||
info.getAccessId(), "PUT", "", "application/octet-stream", contents.length, new Date(), "/" + info.getBucketName() + "/" + path
|
||||
);
|
||||
|
||||
httpDelegate.execute(HttpDelegate.PUT, url, headers, true, false, contents, grabVersion_(false).setReturn(callback));
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
callback.invoke(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String path, Callback callback)
|
||||
{
|
||||
log.debug("delete",path);
|
||||
|
||||
try
|
||||
{
|
||||
String url =
|
||||
createUrlPrefix() +
|
||||
path +
|
||||
"?" + createRandomPostfix();
|
||||
|
||||
log.debug(url);
|
||||
|
||||
String[][] headers = makeHeaders (
|
||||
info.getAccessId(), "DELETE", "", "", 0, new Date(), "/" + info.getBucketName() + "/" + path
|
||||
);
|
||||
|
||||
httpDelegate.execute(HttpDelegate.DELETE, url, headers, true, false, null, callback);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
callback.invoke(e);
|
||||
}
|
||||
}
|
||||
}
|
179
java/core/src/core/connector/s3/sync/S3Connector.java
Normal file
179
java/core/src/core/connector/s3/sync/S3Connector.java
Normal file
@ -0,0 +1,179 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.s3.sync;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.amazonaws.services.s3.AmazonS3;
|
||||
import com.amazonaws.services.s3.AmazonS3Client;
|
||||
import com.amazonaws.services.s3.model.GetObjectRequest;
|
||||
import com.amazonaws.services.s3.model.ListObjectsRequest;
|
||||
import com.amazonaws.services.s3.model.ObjectListing;
|
||||
import com.amazonaws.services.s3.model.S3ObjectSummary;
|
||||
|
||||
import core.connector.ConnectorException;
|
||||
import core.connector.FileInfo;
|
||||
import core.connector.s3.ClientInfoS3;
|
||||
import core.connector.sync.StoreConnector;
|
||||
import core.util.Streams;
|
||||
|
||||
|
||||
public class S3Connector implements StoreConnector
|
||||
{
|
||||
AmazonS3 s3;
|
||||
ClientInfoS3 info;
|
||||
|
||||
public S3Connector (ClientInfoS3 info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public void open () throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
s3 = new AmazonS3Client(new SimpleAWSCredentials(info.getAccessId(), info.getSecretKey()));
|
||||
s3.setEndpoint(info.getBucketEndpoint());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void close ()
|
||||
{
|
||||
s3 = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfo> listDirectory(String path) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
ObjectListing bucketListing =
|
||||
s3.listObjects(
|
||||
new ListObjectsRequest()
|
||||
.withBucketName(info.getBucketName())
|
||||
.withPrefix(path)
|
||||
);
|
||||
|
||||
List<FileInfo> listing = new ArrayList<FileInfo>(bucketListing.getObjectSummaries().size());
|
||||
|
||||
boolean finished = false;
|
||||
while (!finished)
|
||||
{
|
||||
for (S3ObjectSummary s3s : bucketListing.getObjectSummaries())
|
||||
{
|
||||
String key = s3s.getKey();
|
||||
long size = s3s.getSize();
|
||||
Date date = s3s.getLastModified();
|
||||
|
||||
listing.add(new FileInfo(key, key.substring(path.length()+1), size, date, s3s.getETag()));
|
||||
}
|
||||
if (bucketListing.isTruncated())
|
||||
bucketListing = s3.listNextBatchOfObjects(bucketListing);
|
||||
else
|
||||
finished = true;
|
||||
}
|
||||
|
||||
return listing;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectory(String path) throws ConnectorException
|
||||
{
|
||||
// no need in s3
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] get(String path, long size) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
GetObjectRequest request = new GetObjectRequest(info.getBucketName(), path);
|
||||
if (size >= 0)
|
||||
request.withRange(0, size);
|
||||
|
||||
return Streams.readFullyBytes(s3.getObject(request).getObjectContent());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] get(String path) throws ConnectorException
|
||||
{
|
||||
return get(path, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String path, byte[] contents) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
s3.putObject(info.getBucketName(), path, new ByteArrayInputStream(contents), null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(String from, String to) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
s3.copyObject(info.getBucketName(), from, info.getBucketName(), to);
|
||||
s3.deleteObject(info.getBucketName(), from);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String path) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
s3.deleteObject(info.getBucketName(), path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean ensureDirectories (String ... folders)
|
||||
{
|
||||
for (String folder : folders)
|
||||
{
|
||||
try
|
||||
{
|
||||
createDirectory(folder);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.out.format("Folder[%s] already exists.\n", folder);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.s3.sync;
|
||||
|
||||
|
||||
import com.amazonaws.auth.AWSCredentials;
|
||||
|
||||
import core.constants.ConstantsS3;
|
||||
import core.util.Environment;
|
||||
|
||||
public class SimpleAWSCredentials implements AWSCredentials
|
||||
{
|
||||
private String a, s;
|
||||
|
||||
public SimpleAWSCredentials(String a, String s)
|
||||
{
|
||||
this.a = a;
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
public SimpleAWSCredentials(Environment e)
|
||||
{
|
||||
this(e.checkGet(ConstantsS3.AWSAccessKeyId), e.checkGet(ConstantsS3.AWSSecretKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAWSAccessKeyId()
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAWSSecretKey()
|
||||
{
|
||||
return s;
|
||||
}
|
||||
}
|
102
java/core/src/core/connector/sync/EncryptedStoreConnector.java
Normal file
102
java/core/src/core/connector/sync/EncryptedStoreConnector.java
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.sync;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import core.connector.ConnectorException;
|
||||
import core.connector.FileInfo;
|
||||
import core.crypt.Cryptor;
|
||||
import core.util.Streams;
|
||||
import core.util.Zip;
|
||||
|
||||
|
||||
public class EncryptedStoreConnector implements StoreConnector
|
||||
{
|
||||
StoreConnector store;
|
||||
Cryptor cryptor;
|
||||
|
||||
public EncryptedStoreConnector (Cryptor cryptor, StoreConnector store)
|
||||
{
|
||||
this.store = store;
|
||||
this.cryptor = cryptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws ConnectorException
|
||||
{
|
||||
store.open();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws ConnectorException
|
||||
{
|
||||
store.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfo> listDirectory(String path) throws ConnectorException
|
||||
{
|
||||
return store.listDirectory(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectory(String path) throws ConnectorException
|
||||
{
|
||||
store.createDirectory(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] get(String path) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
return Zip.inflate(cryptor.decrypt(store.get(path)));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] get(String path, long size) throws ConnectorException
|
||||
{
|
||||
return get(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String path, byte[] contents) throws ConnectorException
|
||||
{
|
||||
try
|
||||
{
|
||||
store.put(path, cryptor.encrypt(Zip.deflate(contents)));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConnectorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(String from, String to) throws ConnectorException
|
||||
{
|
||||
store.move(from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String path) throws ConnectorException
|
||||
{
|
||||
store.delete(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ensureDirectories(String... folders)
|
||||
{
|
||||
return store.ensureDirectories(folders);
|
||||
}
|
||||
|
||||
}
|
29
java/core/src/core/connector/sync/StoreConnector.java
Normal file
29
java/core/src/core/connector/sync/StoreConnector.java
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Author: Timothy Prepscius
|
||||
* License: GPLv3 Affero + keep my name in the code!
|
||||
*/
|
||||
|
||||
package core.connector.sync;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import core.connector.ConnectorException;
|
||||
import core.connector.FileInfo;
|
||||
|
||||
public interface StoreConnector
|
||||
{
|
||||
public void open () throws ConnectorException;
|
||||
public void close () throws ConnectorException;
|
||||
|
||||
List<FileInfo> listDirectory (String path) throws ConnectorException;
|
||||
void createDirectory (String path) throws ConnectorException;
|
||||
|
||||
byte[] get (String path) throws ConnectorException;
|
||||
byte[] get (String path, long size) throws ConnectorException;
|
||||
|
||||
void put (String path, byte[] contents) throws ConnectorException;
|
||||
void move (String from, String to) throws ConnectorException;
|
||||
void delete (String path) throws ConnectorException;
|
||||
|
||||
public boolean ensureDirectories (String ... folders);
|
||||
}
|
Loading…
Reference in New Issue
Block a user