forked from Qortal/qortal
Include "mimeType" in metadata for single file resources (but only when a metadata file would have otherwise been created).
This commit is contained in:
parent
055b66e835
commit
ea6225ab9a
@ -1,5 +1,7 @@
|
|||||||
package org.qortal.arbitrary;
|
package org.qortal.arbitrary;
|
||||||
|
|
||||||
|
import com.j256.simplemagic.ContentInfo;
|
||||||
|
import com.j256.simplemagic.ContentInfoUtil;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@ -23,6 +25,8 @@ import javax.crypto.NoSuchPaddingException;
|
|||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.FileNameMap;
|
||||||
|
import java.net.URLConnection;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
@ -48,6 +52,7 @@ public class ArbitraryDataWriter {
|
|||||||
private final List<String> tags;
|
private final List<String> tags;
|
||||||
private final Category category;
|
private final Category category;
|
||||||
private List<String> files;
|
private List<String> files;
|
||||||
|
private String mimeType;
|
||||||
|
|
||||||
private int chunkSize = ArbitraryDataFile.CHUNK_SIZE;
|
private int chunkSize = ArbitraryDataFile.CHUNK_SIZE;
|
||||||
|
|
||||||
@ -79,6 +84,7 @@ public class ArbitraryDataWriter {
|
|||||||
this.tags = ArbitraryDataTransactionMetadata.limitTags(tags);
|
this.tags = ArbitraryDataTransactionMetadata.limitTags(tags);
|
||||||
this.category = category;
|
this.category = category;
|
||||||
this.files = new ArrayList<>(); // Populated in buildFileList()
|
this.files = new ArrayList<>(); // Populated in buildFileList()
|
||||||
|
this.mimeType = null; // Populated in buildFileList()
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() throws IOException, DataException, InterruptedException, MissingDataException {
|
public void save() throws IOException, DataException, InterruptedException, MissingDataException {
|
||||||
@ -144,20 +150,41 @@ public class ArbitraryDataWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void buildFileList() throws IOException {
|
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();
|
boolean isSingleFile = this.filePath.toFile().isFile();
|
||||||
|
Path singleFilePath = null;
|
||||||
if (isSingleFile) {
|
if (isSingleFile) {
|
||||||
this.files.add(this.filePath.getFileName().toString());
|
this.files.add(this.filePath.getFileName().toString());
|
||||||
return;
|
singleFilePath = this.filePath;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
// Multi file resources require a walk through the directory tree
|
// 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)) {
|
try (Stream<Path> stream = Files.walk(this.filePath)) {
|
||||||
this.files = stream
|
this.files = stream
|
||||||
.filter(Files::isRegularFile)
|
.filter(Files::isRegularFile)
|
||||||
.map(p -> this.filePath.relativize(p).toString())
|
.map(p -> this.filePath.relativize(p).toString())
|
||||||
.filter(s -> !s.isEmpty())
|
.filter(s -> !s.isEmpty())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (this.files.size() == 1) {
|
||||||
|
singleFilePath = Paths.get(this.filePath.toString(), this.files.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.setCategory(this.category);
|
||||||
metadata.setChunks(this.arbitraryDataFile.chunkHashList());
|
metadata.setChunks(this.arbitraryDataFile.chunkHashList());
|
||||||
metadata.setFiles(this.files);
|
metadata.setFiles(this.files);
|
||||||
|
metadata.setMimeType(this.mimeType);
|
||||||
metadata.write();
|
metadata.write();
|
||||||
|
|
||||||
// Create an ArbitraryDataFile from the JSON file (we don't have a signature yet)
|
// Create an ArbitraryDataFile from the JSON file (we don't have a signature yet)
|
||||||
|
@ -20,6 +20,7 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
|
|||||||
private List<String> tags;
|
private List<String> tags;
|
||||||
private Category category;
|
private Category category;
|
||||||
private List<String> files;
|
private List<String> files;
|
||||||
|
private String mimeType;
|
||||||
|
|
||||||
private static int MAX_TITLE_LENGTH = 80;
|
private static int MAX_TITLE_LENGTH = 80;
|
||||||
private static int MAX_DESCRIPTION_LENGTH = 500;
|
private static int MAX_DESCRIPTION_LENGTH = 500;
|
||||||
@ -92,6 +93,10 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
|
|||||||
}
|
}
|
||||||
this.files = filesList;
|
this.files = filesList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (metadata.has("mimeType")) {
|
||||||
|
this.mimeType = metadata.getString("mimeType");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -134,6 +139,10 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
|
|||||||
}
|
}
|
||||||
outer.put("files", files);
|
outer.put("files", files);
|
||||||
|
|
||||||
|
if (this.mimeType != null && !this.mimeType.isEmpty()) {
|
||||||
|
outer.put("mimeType", this.mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
this.jsonString = outer.toString(2);
|
this.jsonString = outer.toString(2);
|
||||||
LOGGER.trace("Transaction metadata: {}", this.jsonString);
|
LOGGER.trace("Transaction metadata: {}", this.jsonString);
|
||||||
}
|
}
|
||||||
@ -187,6 +196,14 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
|
|||||||
return this.files;
|
return this.files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMimeType(String mimeType) {
|
||||||
|
this.mimeType = mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMimeType() {
|
||||||
|
return this.mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean containsChunk(byte[] chunk) {
|
public boolean containsChunk(byte[] chunk) {
|
||||||
for (byte[] c : this.chunks) {
|
for (byte[] c : this.chunks) {
|
||||||
if (Arrays.equals(c, chunk)) {
|
if (Arrays.equals(c, chunk)) {
|
||||||
|
@ -16,16 +16,18 @@ public class ArbitraryResourceMetadata {
|
|||||||
private Category category;
|
private Category category;
|
||||||
private String categoryName;
|
private String categoryName;
|
||||||
private List<String> files;
|
private List<String> files;
|
||||||
|
private String mimeType;
|
||||||
|
|
||||||
public ArbitraryResourceMetadata() {
|
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.title = title;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.tags = tags;
|
this.tags = tags;
|
||||||
this.category = category;
|
this.category = category;
|
||||||
this.files = files;
|
this.files = files;
|
||||||
|
this.mimeType = mimeType;
|
||||||
|
|
||||||
if (category != null) {
|
if (category != null) {
|
||||||
this.categoryName = category.getName();
|
this.categoryName = category.getName();
|
||||||
@ -40,6 +42,7 @@ public class ArbitraryResourceMetadata {
|
|||||||
String description = transactionMetadata.getDescription();
|
String description = transactionMetadata.getDescription();
|
||||||
List<String> tags = transactionMetadata.getTags();
|
List<String> tags = transactionMetadata.getTags();
|
||||||
Category category = transactionMetadata.getCategory();
|
Category category = transactionMetadata.getCategory();
|
||||||
|
String mimeType = transactionMetadata.getMimeType();
|
||||||
|
|
||||||
// We don't always want to include the file list as it can be too verbose
|
// We don't always want to include the file list as it can be too verbose
|
||||||
List<String> files = null;
|
List<String> files = null;
|
||||||
@ -47,11 +50,11 @@ public class ArbitraryResourceMetadata {
|
|||||||
files = transactionMetadata.getFiles();
|
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 null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ArbitraryResourceMetadata(title, description, tags, category, files);
|
return new ArbitraryResourceMetadata(title, description, tags, category, files, mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getFiles() {
|
public List<String> getFiles() {
|
||||||
|
@ -118,6 +118,7 @@ public class ArbitraryTransactionMetadataTests extends Common {
|
|||||||
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
|
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
|
||||||
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
|
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
|
||||||
assertEquals(category, arbitraryDataFile.getMetadata().getCategory());
|
assertEquals(category, arbitraryDataFile.getMetadata().getCategory());
|
||||||
|
assertEquals("text/plain", arbitraryDataFile.getMetadata().getMimeType());
|
||||||
|
|
||||||
// Now build the latest data state for this name
|
// Now build the latest data state for this name
|
||||||
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ResourceIdType.NAME, service, identifier);
|
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ResourceIdType.NAME, service, identifier);
|
||||||
@ -168,6 +169,7 @@ public class ArbitraryTransactionMetadataTests extends Common {
|
|||||||
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
|
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
|
||||||
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
|
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
|
||||||
assertEquals(category, arbitraryDataFile.getMetadata().getCategory());
|
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
|
// Delete the file, to simulate that it hasn't been fetched from the network yet
|
||||||
arbitraryDataFile.delete();
|
arbitraryDataFile.delete();
|
||||||
@ -230,6 +232,7 @@ public class ArbitraryTransactionMetadataTests extends Common {
|
|||||||
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
|
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
|
||||||
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
|
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
|
||||||
assertEquals(category, arbitraryDataFile.getMetadata().getCategory());
|
assertEquals(category, arbitraryDataFile.getMetadata().getCategory());
|
||||||
|
assertEquals("text/plain", arbitraryDataFile.getMetadata().getMimeType());
|
||||||
|
|
||||||
// Now build the latest data state for this name
|
// Now build the latest data state for this name
|
||||||
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ResourceIdType.NAME, service, identifier);
|
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ResourceIdType.NAME, service, identifier);
|
||||||
@ -318,9 +321,11 @@ public class ArbitraryTransactionMetadataTests extends Common {
|
|||||||
assertTrue(resourceMetadata.getFiles().contains("file.txt"));
|
assertTrue(resourceMetadata.getFiles().contains("file.txt"));
|
||||||
|
|
||||||
// Ensure it's not returned when specified to be excluded
|
// 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);
|
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
|
// The entire object will be null because there is no metadata
|
||||||
ArbitraryResourceMetadata resourceMetadataSimple = ArbitraryResourceMetadata.fromTransactionMetadata(arbitraryDataFile.getMetadata(), false);
|
ArbitraryResourceMetadata resourceMetadataSimple = ArbitraryResourceMetadata.fromTransactionMetadata(arbitraryDataFile.getMetadata(), false);
|
||||||
assertNull(resourceMetadataSimple);
|
assertNull(resourceMetadataSimple);
|
||||||
|
|
||||||
|
// Multi-file resources won't have a MIME type
|
||||||
|
assertEquals(null, arbitraryDataFile.getMetadata().getMimeType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user