Browse Source

Include "mimeType" in metadata for single file resources (but only when a metadata file would have otherwise been created).

qdn-on-chain-data
CalDescent 2 years ago
parent
commit
ea6225ab9a
  1. 46
      src/main/java/org/qortal/arbitrary/ArbitraryDataWriter.java
  2. 17
      src/main/java/org/qortal/arbitrary/metadata/ArbitraryDataTransactionMetadata.java
  3. 9
      src/main/java/org/qortal/data/arbitrary/ArbitraryResourceMetadata.java
  4. 12
      src/test/java/org/qortal/test/arbitrary/ArbitraryTransactionMetadataTests.java

46
src/main/java/org/qortal/arbitrary/ArbitraryDataWriter.java

@ -1,5 +1,7 @@
package org.qortal.arbitrary;
import com.j256.simplemagic.ContentInfo;
import com.j256.simplemagic.ContentInfoUtil;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -23,6 +25,8 @@ import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import java.io.File;
import java.io.IOException;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.nio.file.*;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
@ -48,6 +52,7 @@ public class ArbitraryDataWriter {
private final List<String> tags;
private final Category category;
private List<String> files;
private String mimeType;
private int chunkSize = ArbitraryDataFile.CHUNK_SIZE;
@ -79,6 +84,7 @@ public class ArbitraryDataWriter {
this.tags = ArbitraryDataTransactionMetadata.limitTags(tags);
this.category = category;
this.files = new ArrayList<>(); // Populated in buildFileList()
this.mimeType = null; // Populated in buildFileList()
}
public void save() throws IOException, DataException, InterruptedException, MissingDataException {
@ -144,20 +150,41 @@ public class ArbitraryDataWriter {
}
private void buildFileList() throws IOException {
// Single file resources consist of a single element in the file list
// Check if the path already points to a single file
boolean isSingleFile = this.filePath.toFile().isFile();
Path singleFilePath = null;
if (isSingleFile) {
this.files.add(this.filePath.getFileName().toString());
return;
singleFilePath = this.filePath;
}
else {
// Multi file resources (or a single file in a directory) require a walk through the directory tree
try (Stream<Path> stream = Files.walk(this.filePath)) {
this.files = stream
.filter(Files::isRegularFile)
.map(p -> this.filePath.relativize(p).toString())
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
if (this.files.size() == 1) {
singleFilePath = Paths.get(this.filePath.toString(), this.files.get(0));
}
}
}
// Multi file resources require a walk through the directory tree
try (Stream<Path> stream = Files.walk(this.filePath)) {
this.files = stream
.filter(Files::isRegularFile)
.map(p -> this.filePath.relativize(p).toString())
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
if (singleFilePath != null) {
// Single file resource, so try and determine the MIME type
ContentInfoUtil util = new ContentInfoUtil();
ContentInfo info = util.findMatch(singleFilePath.toFile());
if (info != null) {
// Attempt to extract MIME type from file contents
this.mimeType = info.getMimeType();
}
else {
// Fall back to using the filename
FileNameMap fileNameMap = URLConnection.getFileNameMap();
this.mimeType = fileNameMap.getContentTypeFor(singleFilePath.toFile().getName());
}
}
}
@ -304,6 +331,7 @@ public class ArbitraryDataWriter {
metadata.setCategory(this.category);
metadata.setChunks(this.arbitraryDataFile.chunkHashList());
metadata.setFiles(this.files);
metadata.setMimeType(this.mimeType);
metadata.write();
// Create an ArbitraryDataFile from the JSON file (we don't have a signature yet)

17
src/main/java/org/qortal/arbitrary/metadata/ArbitraryDataTransactionMetadata.java

@ -20,6 +20,7 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
private List<String> tags;
private Category category;
private List<String> files;
private String mimeType;
private static int MAX_TITLE_LENGTH = 80;
private static int MAX_DESCRIPTION_LENGTH = 500;
@ -92,6 +93,10 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
}
this.files = filesList;
}
if (metadata.has("mimeType")) {
this.mimeType = metadata.getString("mimeType");
}
}
@Override
@ -134,6 +139,10 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
}
outer.put("files", files);
if (this.mimeType != null && !this.mimeType.isEmpty()) {
outer.put("mimeType", this.mimeType);
}
this.jsonString = outer.toString(2);
LOGGER.trace("Transaction metadata: {}", this.jsonString);
}
@ -187,6 +196,14 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
return this.files;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public String getMimeType() {
return this.mimeType;
}
public boolean containsChunk(byte[] chunk) {
for (byte[] c : this.chunks) {
if (Arrays.equals(c, chunk)) {

9
src/main/java/org/qortal/data/arbitrary/ArbitraryResourceMetadata.java

@ -16,16 +16,18 @@ public class ArbitraryResourceMetadata {
private Category category;
private String categoryName;
private List<String> files;
private String mimeType;
public ArbitraryResourceMetadata() {
}
public ArbitraryResourceMetadata(String title, String description, List<String> tags, Category category, List<String> files) {
public ArbitraryResourceMetadata(String title, String description, List<String> tags, Category category, List<String> files, String mimeType) {
this.title = title;
this.description = description;
this.tags = tags;
this.category = category;
this.files = files;
this.mimeType = mimeType;
if (category != null) {
this.categoryName = category.getName();
@ -40,6 +42,7 @@ public class ArbitraryResourceMetadata {
String description = transactionMetadata.getDescription();
List<String> tags = transactionMetadata.getTags();
Category category = transactionMetadata.getCategory();
String mimeType = transactionMetadata.getMimeType();
// We don't always want to include the file list as it can be too verbose
List<String> files = null;
@ -47,11 +50,11 @@ public class ArbitraryResourceMetadata {
files = transactionMetadata.getFiles();
}
if (title == null && description == null && tags == null && category == null && files == null) {
if (title == null && description == null && tags == null && category == null && files == null && mimeType == null) {
return null;
}
return new ArbitraryResourceMetadata(title, description, tags, category, files);
return new ArbitraryResourceMetadata(title, description, tags, category, files, mimeType);
}
public List<String> getFiles() {

12
src/test/java/org/qortal/test/arbitrary/ArbitraryTransactionMetadataTests.java

@ -118,6 +118,7 @@ public class ArbitraryTransactionMetadataTests extends Common {
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
assertEquals(category, arbitraryDataFile.getMetadata().getCategory());
assertEquals("text/plain", arbitraryDataFile.getMetadata().getMimeType());
// Now build the latest data state for this name
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ResourceIdType.NAME, service, identifier);
@ -168,6 +169,7 @@ public class ArbitraryTransactionMetadataTests extends Common {
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
assertEquals(category, arbitraryDataFile.getMetadata().getCategory());
assertEquals("text/plain", arbitraryDataFile.getMetadata().getMimeType());
// Delete the file, to simulate that it hasn't been fetched from the network yet
arbitraryDataFile.delete();
@ -230,6 +232,7 @@ public class ArbitraryTransactionMetadataTests extends Common {
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
assertEquals(category, arbitraryDataFile.getMetadata().getCategory());
assertEquals("text/plain", arbitraryDataFile.getMetadata().getMimeType());
// Now build the latest data state for this name
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ResourceIdType.NAME, service, identifier);
@ -318,9 +321,11 @@ public class ArbitraryTransactionMetadataTests extends Common {
assertTrue(resourceMetadata.getFiles().contains("file.txt"));
// Ensure it's not returned when specified to be excluded
// The entire object will be null because there is no metadata
ArbitraryResourceMetadata resourceMetadataSimple = ArbitraryResourceMetadata.fromTransactionMetadata(arbitraryDataFile.getMetadata(), false);
assertNull(resourceMetadataSimple);
assertNull(resourceMetadataSimple.getFiles());
// Single-file resources should have a MIME type
assertEquals("text/plain", arbitraryDataFile.getMetadata().getMimeType());
}
}
@ -369,6 +374,9 @@ public class ArbitraryTransactionMetadataTests extends Common {
// The entire object will be null because there is no metadata
ArbitraryResourceMetadata resourceMetadataSimple = ArbitraryResourceMetadata.fromTransactionMetadata(arbitraryDataFile.getMetadata(), false);
assertNull(resourceMetadataSimple);
// Multi-file resources won't have a MIME type
assertEquals(null, arbitraryDataFile.getMetadata().getMimeType());
}
}

Loading…
Cancel
Save