Added support for single file uploads.

This process could potentially be simplified if we were to modify the structure of the actual zipped data (on the writer side), but this approach is more of a "catch-all" (on the reader side) to support multiple different zip structures, giving us more flexibility. We can still choose to modify the written zip structure if we choose to, which would then cause most of this new code to be skipped.

Note: the filename of a single file is not currently retained; it is renamed to "data" as part of the packaging process. Need to decide if this is okay before we go live.
This commit is contained in:
CalDescent 2021-11-12 13:35:50 +00:00
parent 7bc745fa8e
commit 236a456cae
2 changed files with 56 additions and 2 deletions

View File

@ -167,7 +167,7 @@ public class ArbitraryDataReader {
private void createUncompressedDirectory() {
try {
Files.createDirectories(this.uncompressedPath);
Files.createDirectories(this.uncompressedPath.getParent());
} catch (IOException e) {
throw new IllegalStateException("Unable to create temp directory");
}
@ -366,9 +366,24 @@ public class ArbitraryDataReader {
throw new IllegalStateException(String.format("Unable to unzip file: %s", e.getMessage()));
}
// If unzipped data was a file not a directory, move it into a data/ directory so that the .qortal
// metadata folder is able to be created there too
if (this.uncompressedPath.toFile().isFile()) {
// Rename to temporary filename
Path tempDest = Paths.get(this.uncompressedPath.getParent().toString(), "data2");
this.uncompressedPath.toFile().renameTo(tempDest.toFile());
// Create a "data" directory
Files.createDirectories(this.uncompressedPath);
// Move the original file into the newly created directory
Path finalPath = Paths.get(this.uncompressedPath.toString(), "data");
tempDest.toFile().renameTo(finalPath.toFile());
}
// Replace filePath pointer with the uncompressed file path
if (FilesystemUtils.pathInsideDataOrTempPath(this.filePath)) {
Files.delete(this.filePath);
if (Files.exists(this.filePath)) {
Files.delete(this.filePath);
}
}
this.filePath = this.uncompressedPath;
}

View File

@ -9,6 +9,7 @@ import org.qortal.arbitrary.ArbitraryDataReader;
import org.qortal.arbitrary.ArbitraryDataTransactionBuilder;
import org.qortal.arbitrary.exception.MissingDataException;
import org.qortal.arbitrary.metadata.ArbitraryDataMetadataPatch;
import org.qortal.crypto.Crypto;
import org.qortal.data.transaction.ArbitraryTransactionData;
import org.qortal.data.transaction.ArbitraryTransactionData.*;
import org.qortal.data.transaction.RegisterNameTransactionData;
@ -27,6 +28,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Objects;
import static org.junit.Assert.*;
@ -325,6 +327,43 @@ public class ArbitraryDataTests extends Common {
}
}
@Test
public void testSingleFile() throws DataException, IOException, MissingDataException {
try (final Repository repository = RepositoryManager.getRepository()) {
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
String publicKey58 = Base58.encode(alice.getPublicKey());
String name = "TEST"; // Can be anything for this test
String identifier = "test1"; // Blank, not null
Service service = Service.DOCUMENT; // Can be anything for this test
// Register the name to Alice
RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, "");
TransactionUtils.signAndMint(repository, transactionData, alice);
// Create PUT transaction
Path path1 = Paths.get("src/test/resources/arbitrary/demo1/lorem1.txt");
byte[] path1FileDigest = Crypto.digest(path1.toFile());
ArbitraryDataDigest path1DirectoryDigest = new ArbitraryDataDigest(path1.getParent());
path1DirectoryDigest.compute();
this.createAndMintTxn(repository, publicKey58, path1, name, identifier, Method.PUT, service, alice);
// Now build the latest data state for this name
ArbitraryDataReader arbitraryDataReader1 = new ArbitraryDataReader(name, ResourceIdType.NAME, service, identifier);
arbitraryDataReader1.loadSynchronously(true);
Path builtFilePath = Paths.get(arbitraryDataReader1.getFilePath().toString(), "data");
byte[] builtFileDigest = Crypto.digest(builtFilePath.toFile());
// Compare it against the hash of the original file
assertArrayEquals(builtFileDigest, path1FileDigest);
// The directory digest won't match because the file is renamed to "data"
// We may need to find a way to retain the filename
ArbitraryDataDigest builtDirectoryDigest = new ArbitraryDataDigest(arbitraryDataReader1.getFilePath());
builtDirectoryDigest.compute();
assertFalse(Objects.equals(path1DirectoryDigest.getHash58(), builtDirectoryDigest.getHash58()));
}
}
private void createAndMintTxn(Repository repository, String publicKey58, Path path, String name, String identifier,
Method method, Service service, PrivateKeyAccount account) throws DataException {