package plugins.CENO.FreenetInterface;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import freenet.client.FetchContext;
import freenet.client.FetchException;
import freenet.client.FetchResult;
import freenet.client.HighLevelSimpleClient;
import freenet.client.InsertBlock;
import freenet.client.InsertContext;
import freenet.client.InsertException;
import freenet.client.async.BaseManifestPutter;
import freenet.client.async.ClientGetCallback;
import freenet.client.async.ClientGetter;
import freenet.client.async.ClientPutCallback;
import freenet.client.async.ClientPutter;
import freenet.client.async.DefaultManifestPutter;
import freenet.client.async.PersistenceDisabledException;
import freenet.client.async.TooManyFilesInsertException;
import freenet.keys.FreenetURI;
import freenet.node.Node;
import freenet.node.RequestClient;
import freenet.node.RequestStarter;
import freenet.support.Logger;
import freenet.support.SimpleReadOnlyArrayBucket;
import freenet.support.api.Bucket;
import freenet.support.api.RandomAccessBucket;
import freenet.support.io.BucketTools;
public class HighLevelSimpleClientInterface {
protected static final boolean realTimeFlag = false;
private static volatile HighLevelSimpleClientInterface HLSCInterface = null;
private HLSCRequestClient requestClient;
private HighLevelSimpleClient client;
private Node node;
public class HLSCRequestClient implements RequestClient {
public boolean persistent() {
return false;
}
public boolean realTimeFlag() {
return realTimeFlag;
}
}
private HighLevelSimpleClientInterface() {
}
public HighLevelSimpleClientInterface(Node node) {
synchronized (HighLevelSimpleClientInterface.class) {
if (HLSCInterface == null) {
HLSCInterface = new HighLevelSimpleClientInterface();
HLSCInterface.node = node;
HLSCInterface.client = node.clientCore.makeClient(RequestStarter.MAXIMUM_PRIORITY_CLASS, false, false);
HLSCInterface.requestClient = new HLSCRequestClient();
}
}
}
public HighLevelSimpleClientInterface(Node node, HighLevelSimpleClient hlSimpleClient) {
synchronized (HighLevelSimpleClientInterface.class) {
if (HLSCInterface == null) {
HLSCInterface = new HighLevelSimpleClientInterface();
HLSCInterface.client = hlSimpleClient;
HLSCInterface.node = node;
HLSCInterface.requestClient = new HLSCRequestClient();
}
}
}
/**
* Generates a new key pair, consisting of the insert URI at index 0 and the
* request URI at index 1.
*
* @param docName
* The document name
* @return An array containing the insert and request URI
*/
public static FreenetURI[] generateKeyPair(String docName) {
FreenetURI[] keyPair = HLSCInterface.client.generateKeyPair(docName);
return keyPair;
}
public static FetchContext getFetchContext() {
return HLSCInterface.client.getFetchContext();
}
public static InsertContext getInsertContext(boolean b) {
return HLSCInterface.client.getInsertContext(b);
}
public static RequestClient getRequestClient() {
return HLSCInterface.requestClient;
}
/**
* Synchronously fetch a file from Freenet, given a FreenetURI
*
* @param uri of the file to be fetched
* @return a FetchResult instance upon successful fetch
* @throws FetchException
*/
public static FetchResult fetchURI(FreenetURI uri) throws FetchException {
FetchResult result = HLSCInterface.client.fetch(uri);
return result;
}
/**
* Asynchronously fetch a file from Freenet, given a FreenetURI
*
* @param uri of the file to be fetched
* @return a FetchResult instance upon successful fetch
* @throws FetchException
*/
public static ClientGetter fetchURI(FreenetURI uri, long maxSize,
ClientGetCallback callback, FetchContext fctx) throws FetchException {
return HLSCInterface.client.fetch(uri, maxSize, callback, fctx);
}
// /**
// * Non-blocking insert.
// * @param isMetadata If true, insert metadata.
// * @param cb Will be called when the insert completes. If the request is persistent
// * this will be called on the database thread with a container parameter.
// * @param ctx Insert context so you can customise the insertion process.
// */
// public static ClientPutter insert(InsertBlock insert, String filenameHint, boolean isMetadata, InsertContext ctx, ClientPutCallback cb) throws InsertException {
// ClientPutter clientPutter = HLSCInterface.client.insert(insert, filenameHint, isMetadata, ctx, cb);
// return clientPutter;
// }
public static FreenetURI insert(InsertBlock insert, boolean getCHKOnly, String filenameHint) throws InsertException {
return HLSCInterface.client.insert(insert, getCHKOnly, filenameHint);
}
/**
* Non-blocking insert.
* @param isMetadata If true, insert metadata.
* @param cb Will be called when the insert completes. If the request is persistent
* this will be called on the database thread with a container parameter.
* @param ctx Insert context so you can customise the insertion process.
*/
public static ClientPutter insert(InsertBlock insert, String filenameHint, boolean isMetadata, InsertContext ctx, ClientPutCallback cb, short priority) throws InsertException {
return HLSCInterface.client.insert(insert, filenameHint, isMetadata, ctx, cb, priority);
}
public static FreenetURI insertManifest(FreenetURI insertURI, HashMap<String, Object> bucketsByName, String defaultName) throws InsertException {
return HLSCInterface.client.insertManifest(insertURI, bucketsByName, defaultName);
}
public static FreenetURI insertManifest(FreenetURI insertURI, HashMap<String, Object> bucketsByName, String defaultName, short priorityClass) throws InsertException {
return HLSCInterface.client.insertManifest(insertURI, bucketsByName, defaultName, priorityClass);
}
public static FreenetURI insertManifestCb(FreenetURI insertURI, HashMap<String, Object> bucketsByName, String defaultName, short priorityClass, byte[] forceCryptoKey, ClientPutCallback insertCb) throws InsertException {
DefaultManifestPutter putter;
try {
putter = new DefaultManifestPutter(insertCb, BaseManifestPutter.bucketsByNameToManifestEntries(bucketsByName), priorityClass, insertURI, defaultName, getInsertContext(true), false, forceCryptoKey, HLSCInterface.node.clientCore.clientContext);
} catch (TooManyFilesInsertException e) {
Logger.warning(HighLevelSimpleClientInterface.class, "TooManyFiles in a single directory to fit in a single Manifest file, will not insert URI: " + insertURI.toString());
return null;
}
try {
HLSCInterface.node.clientCore.clientContext.start(putter);
} catch (PersistenceDisabledException e) {
Logger.warning(HighLevelSimpleClientInterface.class, "Could not start Manifest insertion for URI: " + insertURI.toString() + " Error: " + e.getMessage());
return null;
}
return insertURI;
}
public static FreenetURI insertSingleChunk(FreenetURI uri, String content, ClientPutCallback cb) throws InsertException, PersistenceDisabledException, UnsupportedEncodingException {
RandomAccessBucket b = new SimpleReadOnlyArrayBucket(content.getBytes("UTF-8"));
InsertContext ctx = HLSCInterface.node.clientCore.makeClient((short)0, true, false).getInsertContext(true);
ClientPutter clientPutter = new ClientPutter(cb, b, uri,
null, // Modern ARKs easily fit inside 1KB so should be pure SSKs => no MIME type; this improves fetchability considerably
ctx,
RequestStarter.INTERACTIVE_PRIORITY_CLASS, false, null, false, HLSCInterface.node.clientCore.clientContext, null, -1L);
HLSCInterface.node.clientCore.clientContext.start(clientPutter);
return uri;
}
public static FreenetURI insertSingleChunk(FreenetURI uri, byte[] content, ClientPutCallback cb) throws InsertException, PersistenceDisabledException, UnsupportedEncodingException {
RandomAccessBucket b = new SimpleReadOnlyArrayBucket(content);
InsertContext ctx = HLSCInterface.node.clientCore.makeClient((short)0, true, false).getInsertContext(true);
ClientPutter clientPutter = new ClientPutter(cb, b, uri,
null, // Modern ARKs easily fit inside 1KB so should be pure SSKs => no MIME type; this improves fetchability considerably
ctx,
RequestStarter.INTERACTIVE_PRIORITY_CLASS, false, null, false, HLSCInterface.node.clientCore.clientContext, null, -1L);
HLSCInterface.node.clientCore.clientContext.start(clientPutter);
return uri;
}
static Bucket getBucketFromString(String content) throws IOException {
// If the content is an HTML/XML file and there are hidden characters before the <html> opening tag, remove them
int bucketLength, index = 0;
if (content.indexOf("<") != 0) {
try {
if (content.substring(0, 50).matches("(?ui)[\\s\\S]*\\<(!DOCTYPE)?\\s*(html|\\?xml)[\\s\\S]*")) {
//FIXME: Instead of creating a substring, find the index of the byte corresponding to "<" and assign it
// to the index variable. indexOf("<") won't work because of multi-byte UTF-8 characters
content = content.substring(content.indexOf("<"));
}
} catch (StringIndexOutOfBoundsException e) {
Logger.minor(HighLevelSimpleClientInterface.class, "Content of bundle to insert is less than 50 characters long");
}
}
bucketLength = content.getBytes().length - index;
Bucket bucket = HLSCInterface.node.clientCore.tempBucketFactory.makeBucket(bucketLength);
BucketTools.copyFrom(bucket, new ByteArrayInputStream(content.getBytes(), index, bucketLength), bucketLength);
return bucket;
}
}