Skip to content

Commit

Permalink
Add ability to add a dir (only empty works until multiple multipart e…
Browse files Browse the repository at this point in the history
…lements are supported by ipfs.
  • Loading branch information
ianopolous committed Jul 8, 2017
1 parent ceeb061 commit 8e173b7
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 25 deletions.
5 changes: 3 additions & 2 deletions src/main/java/io/ipfs/api/IPFS.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import java.io.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.stream.*;

Expand Down Expand Up @@ -73,10 +74,10 @@ public MerkleNode add(NamedStreamable file) throws IOException {
}

public List<MerkleNode> add(List<NamedStreamable> files) throws IOException {
Multipart m = new Multipart("http://" + host + ":" + port + version+"add?stream-channels=true", "UTF-8");
Multipart m = new Multipart("http://" + host + ":" + port + version + "add", "UTF-8");
for (NamedStreamable file: files) {
if (file.isDirectory()) {
m.addSubtree("", ((NamedStreamable.FileWrapper)file).getFile());
m.addSubtree(Paths.get("/"), file);
} else
m.addFilePart("file", file);
};
Expand Down
31 changes: 18 additions & 13 deletions src/main/java/io/ipfs/api/Multipart.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;

public class Multipart {
Expand Down Expand Up @@ -52,33 +53,37 @@ public void addFormField(String name, String value) {
writer.flush();
}

public void addSubtree(String path, File dir) throws IOException {
String dirPath = path + (path.length() > 0 ? "/" : "") + dir.getName();
public void addSubtree(Path parentPath, NamedStreamable dir) throws IOException {
Path dirPath = parentPath.resolve(dir.getName().get());
addDirectoryPart(dirPath);
for (File f: dir.listFiles()) {
for (NamedStreamable f: dir.getChildren()) {
if (f.isDirectory())
addSubtree(dirPath, f);
else
addFilePart("file", new NamedStreamable.FileWrapper(dirPath + "/", f));
addFilePart("file", f);
}
}

public void addDirectoryPart(String path) {
public void addDirectoryPart(Path path) {
writer.append("--" + boundary).append(LINE_FEED);
writer.append("Content-Disposition: file; filename=\"" + encode(path.toString()) + "\"").append(LINE_FEED);
writer.append("Content-Type: application/x-directory").append(LINE_FEED);
writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
writer.append(LINE_FEED);
writer.append(LINE_FEED);
writer.flush();
}

private static String encode(String in) {
try {
writer.append("--" + boundary).append(LINE_FEED);
writer.append("Content-Disposition: file; filename=\"" + URLEncoder.encode(path, "UTF-8") + "\"").append(LINE_FEED);
writer.append("Content-Type: application/x-directory").append(LINE_FEED);
writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
writer.append(LINE_FEED);
writer.append(LINE_FEED);
writer.flush();
return URLEncoder.encode(in, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}

public void addFilePart(String fieldName, NamedStreamable uploadFile) {
Optional<String> fileName = uploadFile.getName();
Optional<String> fileName = uploadFile.getName().map(n -> encode(n));
writer.append("--" + boundary).append(LINE_FEED);
if (!fileName.isPresent())
writer.append("Content-Disposition: file; name=\"" + fieldName + "\";").append(LINE_FEED);
Expand Down
58 changes: 48 additions & 10 deletions src/main/java/io/ipfs/api/NamedStreamable.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.stream.*;

public interface NamedStreamable
{
InputStream getInputStream() throws IOException;

Optional<String> getName();

List<NamedStreamable> getChildren();

boolean isDirectory();

default byte[] getContents() throws IOException {
Expand All @@ -24,15 +27,9 @@ default byte[] getContents() throws IOException {

class FileWrapper implements NamedStreamable {
private final File source;
private final String pathPrefix;

public FileWrapper(String pathPrefix, File source) {
this.source = source;
this.pathPrefix = pathPrefix;
}

public FileWrapper(File source) {
this("", source);
this.source = source;
}

public InputStream getInputStream() throws IOException {
Expand All @@ -43,13 +40,18 @@ public boolean isDirectory() {
return source.isDirectory();
}

public File getFile() {
return source;
@Override
public List<NamedStreamable> getChildren() {
return isDirectory() ?
Stream.of(source.listFiles())
.map(NamedStreamable.FileWrapper::new)
.collect(Collectors.toList()) :
Collections.emptyList();
}

public Optional<String> getName() {
try {
return Optional.of(URLEncoder.encode(pathPrefix + source.getName(), "UTF-8"));
return Optional.of(URLEncoder.encode(source.getName(), "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
Expand Down Expand Up @@ -81,8 +83,44 @@ public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(data);
}

@Override
public List<NamedStreamable> getChildren() {
return Collections.emptyList();
}

public Optional<String> getName() {
return name;
}
}

class DirWrapper implements NamedStreamable {

private final String name;
private final List<NamedStreamable> children;

public DirWrapper(String name, List<NamedStreamable> children) {
this.name = name;
this.children = children;
}

@Override
public InputStream getInputStream() throws IOException {
throw new IllegalStateException("Cannot get an input stream for a directory!");
}

@Override
public Optional<String> getName() {
return Optional.of(name);
}

@Override
public List<NamedStreamable> getChildren() {
return children;
}

@Override
public boolean isDirectory() {
return true;
}
}
}
8 changes: 8 additions & 0 deletions src/test/java/io/ipfs/api/APITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ public void singleFileTest() {
fileTest(file);
}

@org.junit.Test
public void dirTest() throws IOException {
NamedStreamable.DirWrapper dir = new NamedStreamable.DirWrapper("root", Arrays.asList());
MerkleNode addResult = ipfs.add(dir);
List<MerkleNode> ls = ipfs.ls(addResult.hash);
Assert.assertTrue(ls.size() > 0);
}

@org.junit.Test
public void directoryTest() throws IOException {
Random rnd = new Random();
Expand Down

0 comments on commit 8e173b7

Please sign in to comment.