/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.clients.fcp;
import java.util.HashMap;
import freenet.client.InsertContext;
import freenet.client.async.BaseManifestPutter;
import freenet.clients.fcp.ClientRequest.Persistence;
import freenet.crypt.EncryptedRandomAccessBucket;
import freenet.keys.FreenetURI;
import freenet.node.Node;
import freenet.support.HexUtil;
import freenet.support.Logger;
import freenet.support.SimpleFieldSet;
import freenet.support.api.Bucket;
import freenet.support.api.ManifestElement;
import freenet.support.io.DelayedFreeBucket;
import freenet.support.io.DelayedFreeRandomAccessBucket;
import freenet.support.io.FileBucket;
import freenet.support.io.NullBucket;
import freenet.support.io.PaddedEphemerallyEncryptedBucket;
import freenet.support.io.PersistentTempFileBucket;
import freenet.support.io.TempBucketFactory;
public class PersistentPutDir extends FCPMessage {
static final String name = "PersistentPutDir";
final String identifier;
final FreenetURI uri;
final FreenetURI privateURI;
final int verbosity;
final short priorityClass;
final Persistence persistence;
final boolean global;
private final HashMap<String, Object> manifestElements;
final String defaultName;
final String token;
final boolean started;
final int maxRetries;
final boolean wasDiskPut;
private final SimpleFieldSet cached;
final boolean dontCompress;
final String compressorDescriptor;
final boolean realTime;
final byte[] splitfileCryptoKey;
final InsertContext.CompatibilityMode compatMode;
public PersistentPutDir(String identifier, FreenetURI publicURI, FreenetURI privateURI, int verbosity, short priorityClass,
Persistence persistence, boolean global, String defaultName, HashMap<String, Object> manifestElements,
String token, boolean started, int maxRetries, boolean dontCompress, String compressorDescriptor, boolean wasDiskPut, boolean realTime, byte[] splitfileCryptoKey,
InsertContext.CompatibilityMode cmode) {
this.identifier = identifier;
this.uri = publicURI;
this.privateURI = privateURI;
this.verbosity = verbosity;
this.priorityClass = priorityClass;
this.persistence = persistence;
this.global = global;
this.defaultName = defaultName;
this.manifestElements = manifestElements;
this.token = token;
this.started = started;
this.maxRetries = maxRetries;
this.wasDiskPut = wasDiskPut;
this.dontCompress = dontCompress;
this.compressorDescriptor = compressorDescriptor;
this.realTime = realTime;
this.splitfileCryptoKey = splitfileCryptoKey;
this.compatMode = cmode;
cached = generateFieldSet();
}
private SimpleFieldSet generateFieldSet() {
SimpleFieldSet fs = new SimpleFieldSet(false); // false because this can get HUGE
fs.putSingle("Identifier", identifier);
fs.putSingle("URI", uri.toString(false, false));
if(privateURI != null)
fs.putSingle("PrivateURI", privateURI.toString(false, false));
fs.put("Verbosity", verbosity);
fs.putSingle("Persistence", persistence.toString().toLowerCase());
fs.put("PriorityClass", priorityClass);
fs.put("Global", global);
fs.putSingle("PutDirType", wasDiskPut ? "disk" : "complex");
fs.putOverwrite("CompatibilityMode", compatMode.name());
SimpleFieldSet files = new SimpleFieldSet(false);
// Flatten the hierarchy, it can be reconstructed on restarting.
// Storing it directly would be a PITA.
// FIXME/RESOLVE: The new BaseManifestPutter's container mode does not hold the origin data,
// after composing the PutHandlers (done in BaseManifestPutter), they are 'lost':
// A resumed half done container put can not get the complete file list from BaseManifestPutter.
// Is it really necessary to include the file list here?
ManifestElement[] elements = BaseManifestPutter.flatten(manifestElements);
fs.putSingle("DefaultName", defaultName);
for(int i=0;i<elements.length;i++) {
String num = Integer.toString(i);
ManifestElement e = elements[i];
String mimeOverride = e.getMimeTypeOverride();
SimpleFieldSet subset = new SimpleFieldSet(false);
FreenetURI tempURI = e.getTargetURI();
subset.putSingle("Name", e.getName());
if(tempURI != null) {
subset.putSingle("UploadFrom", "redirect");
subset.putSingle("TargetURI", tempURI.toString());
} else {
Bucket origData = e.getData();
Bucket data = origData;
if(data instanceof DelayedFreeBucket) {
data = ((DelayedFreeBucket)data).getUnderlying();
} else if(data instanceof DelayedFreeRandomAccessBucket) {
data = ((DelayedFreeRandomAccessBucket)data).getUnderlying();
}
subset.put("DataLength", e.getSize());
if(mimeOverride != null)
subset.putSingle("Metadata.ContentType", mimeOverride);
// What to do with the bucket?
// It is either a persistent encrypted bucket or a file bucket ...
if(data == null) {
Logger.error(this, "Bucket already freed: "+e.getData()+" for "+e+" for "+e.getName()+" for "+identifier);
} else if(data instanceof FileBucket) {
subset.putSingle("UploadFrom", "disk");
subset.putSingle("Filename", ((FileBucket)data).getFile().getPath());
} else if (data instanceof PaddedEphemerallyEncryptedBucket || data instanceof NullBucket || data instanceof PersistentTempFileBucket || data instanceof TempBucketFactory.TempBucket || data instanceof EncryptedRandomAccessBucket) {
subset.putSingle("UploadFrom", "direct");
} else {
throw new IllegalStateException("Don't know what to do with bucket: "+data);
}
}
files.put(num, subset);
}
files.put("Count", elements.length);
fs.put("Files", files);
if(token != null)
fs.putSingle("ClientToken", token);
fs.put("Started", started);
fs.put("MaxRetries", maxRetries);
fs.put("DontCompress", dontCompress);
if(compressorDescriptor != null)
fs.putSingle("Codecs", compressorDescriptor);
fs.put("RealTime", realTime);
if(splitfileCryptoKey != null)
fs.putSingle("SplitfileCryptoKey", HexUtil.bytesToHex(splitfileCryptoKey));
return fs;
}
@Override
public SimpleFieldSet getFieldSet() {
return cached;
}
@Override
public String getName() {
return name;
}
@Override
public void run(FCPConnectionHandler handler, Node node)
throws MessageInvalidException {
throw new MessageInvalidException(ProtocolErrorMessage.INVALID_MESSAGE, "PersistentPut goes from server to client not the other way around", identifier, global);
}
}