From a917ab7056dd445810a622894574777035037a53 Mon Sep 17 00:00:00 2001 From: Andrew Padilla Date: Wed, 7 Sep 2022 10:14:35 -0600 Subject: [PATCH 1/3] added Files class to IPFS.java similar to JianYongKang/java-ipfs-http-client repo --- src/main/java/io/ipfs/api/IPFS.java | 206 ++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/src/main/java/io/ipfs/api/IPFS.java b/src/main/java/io/ipfs/api/IPFS.java index a3dc9f2..a47dae9 100755 --- a/src/main/java/io/ipfs/api/IPFS.java +++ b/src/main/java/io/ipfs/api/IPFS.java @@ -44,7 +44,9 @@ public enum PinType {all, direct, indirect, recursive} public final Stats stats = new Stats(); public final Name name = new Name(); public final Pubsub pubsub = new Pubsub(); + public final Files files = new Files(); + public IPFS(String host, int port) { this(host, port, "/api/v0/", false); } @@ -641,6 +643,210 @@ public Object log() throws IOException { } } + // Files commands related classes + public class Files { + + public Map chcid() throws IOException { + return retrieveMap("files/chcid"); + } + + public Map chcid(String path) throws IOException { + return retrieveMap("files/chcid?args=" + path); + } + + public Map cp(String source, String dest) throws IOException { + return retrieveMap("files/cp?arg=" + source + "&arg=" + dest); + } + + public Map cp(String source, String dest, boolean parents) throws IOException { + return retrieveMap("files/cp?arg=" + source + "&arg=" + dest + "&parents=" + parents); + } + + public Map flush() throws IOException { + return retrieveMap("files/flush"); + } + public Map flush(String path) throws IOException { + return retrieveMap("files/flush?arg=" + path); + } + + public Map ls() throws IOException { + return retrieveMap("files/ls"); + } + + public Map ls(String path) throws IOException { + return retrieveMap("files/ls?arg=" + path); + } + + public Map ls(String path, boolean longListing, boolean u) throws IOException { + return retrieveMap("files/ls?arg=" + path + "&long=" + longListing + "&U=" + u); + } + + public Map mkdir(String path) throws IOException { + return retrieveMap("files/mkdir?arg=" + path); + } + + public Map mkdir(String path, boolean parents, int cidVersion, Multihash hash) throws IOException { + return retrieveMap("files/mkdir?arg=" + path + "&parents=" + parents + "&cid-version=" + cidVersion + "&hash=" + hash); + } + + public Map mv(String source, String dest) throws IOException { + return retrieveMap("files/mv?arg=" + source + "&arg=" + dest); + } + + public Map read(String path) throws IOException { + return retrieveMap("files/read?arg=" + path); + } + public Map read(String path, int offset, int count) throws IOException { + return retrieveMap("files/read?arg=" + path + "&offset=" + offset + "&count=" + count); + } + + public Map rm(String path) throws IOException { + return retrieveMap("files/rm?arg=" + path); + } + + public Map rm(String path, boolean recursive, boolean force) throws IOException { + return retrieveMap("files/rm?arg=" + path + "&recursive=" + recursive + "&force=" + force); + } + + public Map stat(String path) throws IOException { + return retrieveMap("files/stat?arg=" + path); + } + + } + + public abstract class FilesArgs { + private Map> args = new LinkedHashMap>(); // store in order added + + public String toString() { + + // create list to store query param name/value pairs + List qParamList = new ArrayList(); + + + for (Map.Entry> e: args.entrySet()) { + final String paramName; + List paramValues; + // encode param name and its value(s) + paramName = URLEncoder.encode(e.getKey()); + paramValues = e.getValue(); + + for (String v: paramValues) { + String paramValue = URLEncoder.encode(v); + qParamList.add( String.format("%s=%s",paramName, paramValue) ); + } + } + + return String.join("&",qParamList); + + + } + + protected void add(String paramName,String paramValue) { + + List values = args.get(paramName); + if (values != null) { + // param name has been assigned at least one value before. + // add another value to existing list + values.add(paramValue); + } else { + // param name not found. make new List + List l = new ArrayList(); + + // add single entry + l.add(paramValue); + // add list as value to param name in map + args.put(paramName,l); + } + + + } + + } + + + + /** + * Defined here: https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-files-chcid + */ + public class FilesChCIDArgs extends FilesArgs { + public FilesChCIDArgs() { + + } + + public FilesChCIDArgs path(String mfsPath) { + add("arg",mfsPath); + + return (this); + } + + public FilesChCIDArgs cidVersion(int cidVersion) { + add("cid-version",Integer.toString(cidVersion)); + + return (this); + } + + public FilesChCIDArgs hash(String hashFunction) { + add("hash",hashFunction); + + return (this); + } + + + } + + /** + * Defined here: https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-files-cp + */ + public class FilesCpArgs extends FilesArgs { + public FilesCpArgs(String srcIPFSOrMFSPath, String dstMFSPath) { + add("arg",srcIPFSOrMFSPath); + add("arg",dstMFSPath); + } + + public FilesCpArgs makeParentDirs(boolean parents) { + add("parents",Boolean.toString(parents)); + + return (this); + } + } + + + + public class FilesFlushArgs extends FilesArgs { + + } + + public class FilesLsArgs extends FilesArgs { + + } + + public class FilesMkdirArgs extends FilesArgs { + + } + + public class FilesMvArgs extends FilesArgs { + + } + + public class FilesReadArgs extends FilesArgs { + + } + + public class FilesRmArgs extends FilesArgs { + + } + + public class FilesStatArgs extends FilesArgs { + + } + + public class FilesWriteArgs extends FilesArgs { + + } + + // End Files Command Classes + + private Map retrieveMap(String path) throws IOException { return (Map)retrieveAndParse(path); } From 2e638c7fc32882c297772ddfff5136341945ba4f Mon Sep 17 00:00:00 2001 From: Andrew Padilla Date: Thu, 8 Sep 2022 17:05:07 -0600 Subject: [PATCH 2/3] Added class based arguments for files subcommand arguments --- src/main/java/io/ipfs/api/IPFS.java | 262 +++++++++++++++++++++++----- 1 file changed, 221 insertions(+), 41 deletions(-) diff --git a/src/main/java/io/ipfs/api/IPFS.java b/src/main/java/io/ipfs/api/IPFS.java index 5b6379d..385498f 100755 --- a/src/main/java/io/ipfs/api/IPFS.java +++ b/src/main/java/io/ipfs/api/IPFS.java @@ -658,67 +658,51 @@ public Map chcid() throws IOException { return retrieveMap("files/chcid"); } - public Map chcid(String path) throws IOException { - return retrieveMap("files/chcid?args=" + path); + public Map chcid(FilesChCIDArgs args) throws IOException { + return retrieveMap("files/chcid?" + args); } - public Map cp(String source, String dest) throws IOException { - return retrieveMap("files/cp?arg=" + source + "&arg=" + dest); - } - - public Map cp(String source, String dest, boolean parents) throws IOException { - return retrieveMap("files/cp?arg=" + source + "&arg=" + dest + "&parents=" + parents); + public Map cp(FilesCpArgs args) throws IOException { + return retrieveMap("files/cp?" + args); } public Map flush() throws IOException { return retrieveMap("files/flush"); } - public Map flush(String path) throws IOException { - return retrieveMap("files/flush?arg=" + path); + + public Map flush(FilesFlushArgs args) throws IOException { + return retrieveMap("files/flush?" + args); } public Map ls() throws IOException { return retrieveMap("files/ls"); } - public Map ls(String path) throws IOException { - return retrieveMap("files/ls?arg=" + path); + public Map ls(FilesLsArgs args) throws IOException { + return retrieveMap("files/ls?" + args); } - public Map ls(String path, boolean longListing, boolean u) throws IOException { - return retrieveMap("files/ls?arg=" + path + "&long=" + longListing + "&U=" + u); + public Map mkdir(FilesMkdirArgs args) throws IOException { + return retrieveMap("files/mkdir?" + args); } - public Map mkdir(String path) throws IOException { - return retrieveMap("files/mkdir?arg=" + path); + public Map mv(FilesMvArgs args) throws IOException { + return retrieveMap("files/mv?" + args); } - public Map mkdir(String path, boolean parents, int cidVersion, Multihash hash) throws IOException { - return retrieveMap("files/mkdir?arg=" + path + "&parents=" + parents + "&cid-version=" + cidVersion + "&hash=" + hash); + public Map read(FilesReadArgs args) throws IOException { + return retrieveMap("files/read?" + args); } - public Map mv(String source, String dest) throws IOException { - return retrieveMap("files/mv?arg=" + source + "&arg=" + dest); + public Map rm(FilesRmArgs args) throws IOException { + return retrieveMap("files/rm?" + args); } - public Map read(String path) throws IOException { - return retrieveMap("files/read?arg=" + path); - } - public Map read(String path, int offset, int count) throws IOException { - return retrieveMap("files/read?arg=" + path + "&offset=" + offset + "&count=" + count); + public Map stat(FilesStatArgs args) throws IOException { + return retrieveMap("files/stat?" + args); } - public Map rm(String path) throws IOException { - return retrieveMap("files/rm?arg=" + path); - } - public Map rm(String path, boolean recursive, boolean force) throws IOException { - return retrieveMap("files/rm?arg=" + path + "&recursive=" + recursive + "&force=" + force); - } - - public Map stat(String path) throws IOException { - return retrieveMap("files/stat?arg=" + path); - } } @@ -777,9 +761,6 @@ protected void add(String paramName,String paramValue) { * Defined here: https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-files-chcid */ public class FilesChCIDArgs extends FilesArgs { - public FilesChCIDArgs() { - - } public FilesChCIDArgs path(String mfsPath) { add("arg",mfsPath); @@ -787,8 +768,8 @@ public FilesChCIDArgs path(String mfsPath) { return (this); } - public FilesChCIDArgs cidVersion(int cidVersion) { - add("cid-version",Integer.toString(cidVersion)); + public FilesChCIDArgs cidVersion(int cidVersionToUse) { + add("cid-version",Integer.toString(cidVersionToUse)); return (this); } @@ -807,11 +788,13 @@ public FilesChCIDArgs hash(String hashFunction) { */ public class FilesCpArgs extends FilesArgs { public FilesCpArgs(String srcIPFSOrMFSPath, String dstMFSPath) { + add("arg",srcIPFSOrMFSPath); add("arg",dstMFSPath); } public FilesCpArgs makeParentDirs(boolean parents) { + add("parents",Boolean.toString(parents)); return (this); @@ -819,37 +802,234 @@ public FilesCpArgs makeParentDirs(boolean parents) { } - + /** + * Defined here: https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-files-flush + * + */ public class FilesFlushArgs extends FilesArgs { + public FilesFlushArgs path(String pathToFlush) { + add("arg",pathToFlush); + + return (this); + } } + /** + * + * + */ public class FilesLsArgs extends FilesArgs { + public FilesLsArgs path(String pathToShowListing) { + add("arg",pathToShowListing); + + return (this); + } + + public FilesLsArgs longListingFormat(boolean useLongListingFormat) { + add("long",Boolean.toString(useLongListingFormat)); + + return (this); + } + + public FilesLsArgs noSort(boolean noSort) { + add("U",Boolean.toString(noSort)); + + return (this); + } } + /** + * + * + */ public class FilesMkdirArgs extends FilesArgs { + public FilesMkdirArgs(String path) { + add("arg",path); + } + + public FilesMkdirArgs parents(boolean makeParentDirsAsNeeded) { + add("parents", Boolean.toString(makeParentDirsAsNeeded)); + + return (this); + } + + public FilesMkdirArgs cidVersion(int cidVersionToUse) { + add("cid-version",Integer.toString(cidVersionToUse)); + + return (this); + } + + public FilesMkdirArgs hash(String hashFunction) { + add("hash",hashFunction); + + return (this); + } } + /** + * + * + */ public class FilesMvArgs extends FilesArgs { + public FilesMvArgs(String srcPath, String dstPath) { + add("arg",srcPath); + add("arg",dstPath); + } + } + /** + * + * + */ public class FilesReadArgs extends FilesArgs { + public FilesReadArgs(String pathToRead) { + add("arg",pathToRead); + } + + public FilesReadArgs offset(int byteOffsetToStartReading) { + add("offset",Integer.toString(byteOffsetToStartReading)); + + return (this); + + } + + public FilesReadArgs count(long maxBytesToRead) { + add("count",Long.toString(maxBytesToRead)); + + return (this); + } + } + /** + * + * + */ public class FilesRmArgs extends FilesArgs { + public FilesRmArgs(String path, String... morePaths) { + + add("arg",path); + + for (String p: morePaths) { + add("arg",p); + } + + } + + public FilesRmArgs recursive(boolean recursivelyRemoveDirs) { + add("recursive",Boolean.toString(recursivelyRemoveDirs)); + + return (this); + + } + + public FilesRmArgs force(boolean forciblyRemoveTargetAtPath) { + add("force",Boolean.toString(forciblyRemoveTargetAtPath)); + + return (this); + + } } + /** + * + * + */ public class FilesStatArgs extends FilesArgs { + public FilesStatArgs(String pathToNodeToStat) { + add("arg",pathToNodeToStat); + } + + public FilesStatArgs format(String formatString) { + add("format",formatString); + + return (this); + } + + public FilesStatArgs hash(boolean printOnlyHash) { + add("hash",Boolean.toString(printOnlyHash)); + + return (this); + } + + public FilesStatArgs size(boolean printOnlySize) { + add("size",Boolean.toString(printOnlySize)); + + return (this); + } + + public FilesStatArgs withLocal(boolean computeAmountOfDagThatIsLocal) { + + add("with-local",Boolean.toString(computeAmountOfDagThatIsLocal)); + + return (this); + } + + } public class FilesWriteArgs extends FilesArgs { + public FilesWriteArgs(String path) { + add("arg",path); + } + + public FilesWriteArgs offset(long offsetToBeginWriting) { + add("offset",Long.toString(offsetToBeginWriting)); + + return (this); + } + + public FilesWriteArgs create(boolean createFileIfNotExists) { + add("create",Boolean.toString(createFileIfNotExists)); + + return (this); + } + + public FilesWriteArgs parents(boolean makeParentDirsAsNeeded) { + add("parents",Boolean.toString(makeParentDirsAsNeeded)); + + return (this); + } + + public FilesWriteArgs truncate(boolean truncateFileSizeToZeroBeforeWrite) { + add("truncate",Boolean.toString(truncateFileSizeToZeroBeforeWrite)); + + return (this); + } + + public FilesWriteArgs count(long maxNumberBytesToRead) { + add("count",Long.toString(maxNumberBytesToRead)); + + return (this); + } + + public FilesWriteArgs rawLeaves(boolean useRawBlocksForNewLeafNodes) { + add("raw-leaves",Boolean.toString(useRawBlocksForNewLeafNodes)); + + return (this); + } + + public FilesWriteArgs cidVersion(int cidVersionToUse) { + add("cid-version",Integer.toString(cidVersionToUse)); + + return (this); + } + + public FilesWriteArgs hash(String hashFunction) { + add("hash", hashFunction); + + return (this); + } + } // End Files Command Classes From f6c5f1efb3592d607ca43e8e26a5233e66e909c7 Mon Sep 17 00:00:00 2001 From: Andrew Padilla Date: Wed, 14 Sep 2022 10:43:59 -0600 Subject: [PATCH 3/3] finished completing 'ipfs files' subcommand API --- src/main/java/io/ipfs/api/IPFS.java | 528 ++++++++++++----------- src/main/java/io/ipfs/api/Multipart.java | 17 + src/test/java/io/ipfs/api/APITest.java | 334 ++++++++++++++ 3 files changed, 638 insertions(+), 241 deletions(-) diff --git a/src/main/java/io/ipfs/api/IPFS.java b/src/main/java/io/ipfs/api/IPFS.java index 385498f..238f243 100755 --- a/src/main/java/io/ipfs/api/IPFS.java +++ b/src/main/java/io/ipfs/api/IPFS.java @@ -47,7 +47,7 @@ public enum PinType {all, direct, indirect, recursive} public final Pubsub pubsub = new Pubsub(); public final Files files = new Files(); - + public IPFS(String host, int port) { this(host, port, "/api/v0/", false); } @@ -88,7 +88,7 @@ public IPFS(String host, int port, String version, int connectTimeoutMillis, int throw new RuntimeException(e); } } - + /** * Configure a HTTP client timeout * @param timeout (default 0: infinite timeout) @@ -658,19 +658,19 @@ public Map chcid() throws IOException { return retrieveMap("files/chcid"); } - public Map chcid(FilesChCIDArgs args) throws IOException { + public Map chcid(ChCIDArgs args) throws IOException { return retrieveMap("files/chcid?" + args); } - public Map cp(FilesCpArgs args) throws IOException { - return retrieveMap("files/cp?" + args); + public byte[] cp(CpArgs args) throws IOException { + return retrieve("files/cp?" + args); } public Map flush() throws IOException { return retrieveMap("files/flush"); } - public Map flush(FilesFlushArgs args) throws IOException { + public Map flush(FlushArgs args) throws IOException { return retrieveMap("files/flush?" + args); } @@ -678,372 +678,395 @@ public Map ls() throws IOException { return retrieveMap("files/ls"); } - public Map ls(FilesLsArgs args) throws IOException { + public Map ls(LsArgs args) throws IOException { return retrieveMap("files/ls?" + args); } - public Map mkdir(FilesMkdirArgs args) throws IOException { + public Map mkdir(MkdirArgs args) throws IOException { return retrieveMap("files/mkdir?" + args); } - public Map mv(FilesMvArgs args) throws IOException { - return retrieveMap("files/mv?" + args); + public byte[] mv(MvArgs args) throws IOException { + return retrieve("files/mv?" + args); } - public Map read(FilesReadArgs args) throws IOException { - return retrieveMap("files/read?" + args); + public byte[] read(ReadArgs args) throws IOException { + return retrieve("files/read?" + args); } - public Map rm(FilesRmArgs args) throws IOException { - return retrieveMap("files/rm?" + args); + public byte[] rm(RmArgs args) throws IOException { + return retrieve("files/rm?" + args); } - public Map stat(FilesStatArgs args) throws IOException { + public Map stat(StatArgs args) throws IOException { return retrieveMap("files/stat?" + args); } + public Map write(WriteArgs args, NamedStreamable uploadFile) throws IOException { + return retrieveMap("files/write?" + args,uploadFile); - } + } - public abstract class FilesArgs { - private Map> args = new LinkedHashMap>(); // store in order added + /** + * files args classes + * + */ + public abstract class Args { + private Map> args = new LinkedHashMap>(); // store in order added - public String toString() { + public String toString() { - // create list to store query param name/value pairs - List qParamList = new ArrayList(); - - - for (Map.Entry> e: args.entrySet()) { - final String paramName; - List paramValues; - // encode param name and its value(s) - paramName = URLEncoder.encode(e.getKey()); - paramValues = e.getValue(); - - for (String v: paramValues) { - String paramValue = URLEncoder.encode(v); - qParamList.add( String.format("%s=%s",paramName, paramValue) ); - } - } + // create list to store query param name/value pairs + List qParamList = new ArrayList(); - return String.join("&",qParamList); - - } + for (Map.Entry> e: args.entrySet()) { + final String paramName; + List paramValues; + // encode param name and its value(s) + paramName = URLEncoder.encode(e.getKey()); + paramValues = e.getValue(); + + for (String v: paramValues) { + String paramValue = URLEncoder.encode(v); + qParamList.add( String.format("%s=%s",paramName, paramValue) ); + } + } - protected void add(String paramName,String paramValue) { + return String.join("&",qParamList); - List values = args.get(paramName); - if (values != null) { - // param name has been assigned at least one value before. - // add another value to existing list - values.add(paramValue); - } else { - // param name not found. make new List - List l = new ArrayList(); - // add single entry - l.add(paramValue); - // add list as value to param name in map - args.put(paramName,l); } - - - } - - } + protected void add(String paramName,String paramValue) { + + List values = args.get(paramName); + if (values != null) { + // param name has been assigned at least one value before. + // add another value to existing list + values.add(paramValue); + } else { + // param name not found. make new List + List l = new ArrayList(); + + // add single entry + l.add(paramValue); + // add list as value to param name in map + args.put(paramName,l); + } - /** - * Defined here: https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-files-chcid - */ - public class FilesChCIDArgs extends FilesArgs { + } - public FilesChCIDArgs path(String mfsPath) { - add("arg",mfsPath); - - return (this); } - public FilesChCIDArgs cidVersion(int cidVersionToUse) { - add("cid-version",Integer.toString(cidVersionToUse)); - - return (this); - } - public FilesChCIDArgs hash(String hashFunction) { - add("hash",hashFunction); - return (this); - } + /** + * Defined here: https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-files-chcid + */ + public class ChCIDArgs extends Args { - - } + public ChCIDArgs path(String mfsPath) { + add("arg",mfsPath); - /** - * Defined here: https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-files-cp - */ - public class FilesCpArgs extends FilesArgs { - public FilesCpArgs(String srcIPFSOrMFSPath, String dstMFSPath) { + return (this); + } - add("arg",srcIPFSOrMFSPath); - add("arg",dstMFSPath); - } + public ChCIDArgs cidVersion(int cidVersionToUse) { + add("cid-version",Integer.toString(cidVersionToUse)); - public FilesCpArgs makeParentDirs(boolean parents) { + return (this); + } - add("parents",Boolean.toString(parents)); + public ChCIDArgs hash(String hashFunction) { + add("hash",hashFunction); - return (this); - } - } + return (this); + } - - /** - * Defined here: https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-files-flush - * - */ - public class FilesFlushArgs extends FilesArgs { - public FilesFlushArgs path(String pathToFlush) { - add("arg",pathToFlush); - - return (this); } - } - /** - * - * - */ - public class FilesLsArgs extends FilesArgs { + /** + * Defined here: https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-files-cp + */ + public class CpArgs extends Args { + public CpArgs(String srcIPFSOrMFSPath, String dstMFSPath) { - public FilesLsArgs path(String pathToShowListing) { - add("arg",pathToShowListing); + add("arg",srcIPFSOrMFSPath); + add("arg",dstMFSPath); + } - return (this); - } + public CpArgs makeParentDirs(boolean parents) { - public FilesLsArgs longListingFormat(boolean useLongListingFormat) { - add("long",Boolean.toString(useLongListingFormat)); + add("parents",Boolean.toString(parents)); - return (this); + return (this); + } } - public FilesLsArgs noSort(boolean noSort) { - add("U",Boolean.toString(noSort)); - return (this); - } - } + /** + * Defined here: https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-files-flush + * + */ + public class FlushArgs extends Args { - /** - * - * - */ - public class FilesMkdirArgs extends FilesArgs { + public FlushArgs path(String pathToFlush) { - public FilesMkdirArgs(String path) { - add("arg",path); + add("arg",pathToFlush); + + return (this); + } } - public FilesMkdirArgs parents(boolean makeParentDirsAsNeeded) { - add("parents", Boolean.toString(makeParentDirsAsNeeded)); + /** + * + * + */ + public class LsArgs extends Args { + + public LsArgs path(String pathToShowListing) { + add("arg",pathToShowListing); - return (this); - } + return (this); + } - public FilesMkdirArgs cidVersion(int cidVersionToUse) { - add("cid-version",Integer.toString(cidVersionToUse)); + public LsArgs longListingFormat(boolean useLongListingFormat) { + add("long",Boolean.toString(useLongListingFormat)); + + return (this); + } - return (this); + public LsArgs noSort(boolean noSort) { + add("U",Boolean.toString(noSort)); + + return (this); + } } - public FilesMkdirArgs hash(String hashFunction) { - add("hash",hashFunction); + /** + * + * + */ + public class MkdirArgs extends Args { + + public MkdirArgs(String path) { + add("arg",path); + } - return (this); - } - } + public MkdirArgs parents(boolean makeParentDirsAsNeeded) { + add("parents", Boolean.toString(makeParentDirsAsNeeded)); - /** - * - * - */ - public class FilesMvArgs extends FilesArgs { + return (this); + } - public FilesMvArgs(String srcPath, String dstPath) { - add("arg",srcPath); - add("arg",dstPath); - } + public MkdirArgs cidVersion(int cidVersionToUse) { + add("cid-version",Integer.toString(cidVersionToUse)); - } + return (this); + } - /** - * - * - */ - public class FilesReadArgs extends FilesArgs { + public MkdirArgs hash(String hashFunction) { + add("hash",hashFunction); - public FilesReadArgs(String pathToRead) { - add("arg",pathToRead); + return (this); + } } - public FilesReadArgs offset(int byteOffsetToStartReading) { - add("offset",Integer.toString(byteOffsetToStartReading)); - - return (this); - - } + /** + * + * + */ + public class MvArgs extends Args { - public FilesReadArgs count(long maxBytesToRead) { - add("count",Long.toString(maxBytesToRead)); + public MvArgs(String srcPath, String dstPath) { + add("arg",srcPath); + add("arg",dstPath); + } - return (this); } - } + /** + * + * + */ + public class ReadArgs extends Args { - /** - * - * - */ - public class FilesRmArgs extends FilesArgs { + public ReadArgs(String pathToRead) { + add("arg",pathToRead); + } - public FilesRmArgs(String path, String... morePaths) { + public ReadArgs offset(int byteOffsetToStartReading) { + add("offset",Integer.toString(byteOffsetToStartReading)); - add("arg",path); + return (this); - for (String p: morePaths) { - add("arg",p); + } + + public ReadArgs count(long maxBytesToRead) { + add("count",Long.toString(maxBytesToRead)); + + return (this); } } - public FilesRmArgs recursive(boolean recursivelyRemoveDirs) { - add("recursive",Boolean.toString(recursivelyRemoveDirs)); + /** + * + * + */ + public class RmArgs extends Args { - return (this); + public RmArgs(String path, String... morePaths) { - } + add("arg",path); + + for (String p: morePaths) { + add("arg",p); + } - public FilesRmArgs force(boolean forciblyRemoveTargetAtPath) { - add("force",Boolean.toString(forciblyRemoveTargetAtPath)); + } - return (this); + public RmArgs recursive(boolean recursivelyRemoveDirs) { + add("recursive",Boolean.toString(recursivelyRemoveDirs)); - } - } + return (this); - /** - * - * - */ - public class FilesStatArgs extends FilesArgs { + } - public FilesStatArgs(String pathToNodeToStat) { - add("arg",pathToNodeToStat); - } + public RmArgs force(boolean forciblyRemoveTargetAtPath) { + add("force",Boolean.toString(forciblyRemoveTargetAtPath)); - public FilesStatArgs format(String formatString) { - add("format",formatString); + return (this); - return (this); + } } - public FilesStatArgs hash(boolean printOnlyHash) { - add("hash",Boolean.toString(printOnlyHash)); + /** + * + * + */ + public class StatArgs extends Args { - return (this); - } + public StatArgs(String pathToNodeToStat) { + add("arg",pathToNodeToStat); + } - public FilesStatArgs size(boolean printOnlySize) { - add("size",Boolean.toString(printOnlySize)); + public StatArgs format(String formatString) { + add("format",formatString); - return (this); - } + return (this); + } - public FilesStatArgs withLocal(boolean computeAmountOfDagThatIsLocal) { + public StatArgs hash(boolean printOnlyHash) { + add("hash",Boolean.toString(printOnlyHash)); - add("with-local",Boolean.toString(computeAmountOfDagThatIsLocal)); + return (this); + } - return (this); - } + public StatArgs size(boolean printOnlySize) { + add("size",Boolean.toString(printOnlySize)); + return (this); + } - } + public StatArgs withLocal(boolean computeAmountOfDagThatIsLocal) { - public class FilesWriteArgs extends FilesArgs { + add("with-local",Boolean.toString(computeAmountOfDagThatIsLocal)); - public FilesWriteArgs(String path) { - add("arg",path); - } + return (this); + } - public FilesWriteArgs offset(long offsetToBeginWriting) { - add("offset",Long.toString(offsetToBeginWriting)); - return (this); } - public FilesWriteArgs create(boolean createFileIfNotExists) { - add("create",Boolean.toString(createFileIfNotExists)); + public class WriteArgs extends Args { - return (this); - } + public WriteArgs(String path) { + add("arg",path); + } - public FilesWriteArgs parents(boolean makeParentDirsAsNeeded) { - add("parents",Boolean.toString(makeParentDirsAsNeeded)); + public WriteArgs offset(long offsetToBeginWriting) { + add("offset",Long.toString(offsetToBeginWriting)); - return (this); - } + return (this); + } - public FilesWriteArgs truncate(boolean truncateFileSizeToZeroBeforeWrite) { - add("truncate",Boolean.toString(truncateFileSizeToZeroBeforeWrite)); + public WriteArgs create(boolean createFileIfNotExists) { + add("create",Boolean.toString(createFileIfNotExists)); - return (this); - } + return (this); + } - public FilesWriteArgs count(long maxNumberBytesToRead) { - add("count",Long.toString(maxNumberBytesToRead)); + public WriteArgs parents(boolean makeParentDirsAsNeeded) { + add("parents",Boolean.toString(makeParentDirsAsNeeded)); - return (this); - } + return (this); + } - public FilesWriteArgs rawLeaves(boolean useRawBlocksForNewLeafNodes) { - add("raw-leaves",Boolean.toString(useRawBlocksForNewLeafNodes)); + public WriteArgs truncate(boolean truncateFileSizeToZeroBeforeWrite) { + add("truncate",Boolean.toString(truncateFileSizeToZeroBeforeWrite)); - return (this); - } + return (this); + } - public FilesWriteArgs cidVersion(int cidVersionToUse) { - add("cid-version",Integer.toString(cidVersionToUse)); + public WriteArgs count(long maxNumberBytesToRead) { + add("count",Long.toString(maxNumberBytesToRead)); - return (this); - } + return (this); + } + + public WriteArgs rawLeaves(boolean useRawBlocksForNewLeafNodes) { + add("raw-leaves",Boolean.toString(useRawBlocksForNewLeafNodes)); + + return (this); + } + + public WriteArgs cidVersion(int cidVersionToUse) { + add("cid-version",Integer.toString(cidVersionToUse)); + + return (this); + } + + public WriteArgs hash(String hashFunction) { + add("hash", hashFunction); - public FilesWriteArgs hash(String hashFunction) { - add("hash", hashFunction); + return (this); + } - return (this); } + } + // End Files Command Classes - + private Map retrieveMap(String path) throws IOException { return (Map)retrieveAndParse(path); } + private Map retrieveMap(String path, NamedStreamable uploadFile) throws IOException { + return (Map)retrieveAndParse(path,uploadFile); + } + private Object retrieveAndParse(String path) throws IOException { byte[] res = retrieve(path); return JSONParser.parse(new String(res)); } + private Object retrieveAndParse(String path, NamedStreamable uploadFile) throws IOException { + + byte[] res = retrieve(path,uploadFile); + + return JSONParser.parse(new String(res)); + + } + private Stream retrieveAndParseStream(String path, ForkJoinPool executor) throws IOException { BlockingQueue> results = new LinkedBlockingQueue<>(); InputStream in = retrieveStream(path); @@ -1081,6 +1104,12 @@ private byte[] retrieve(String path) throws IOException { return IPFS.get(target, connectTimeoutMillis, readTimeoutMillis); } + private byte[] retrieve(String path, NamedStreamable uploadFile) throws IOException { + URL target = new URL(protocol,host,port,version + path); + + return IPFS.get(target, connectTimeoutMillis, readTimeoutMillis, uploadFile); + } + private static byte[] get(URL target, int connectTimeoutMillis, int readTimeoutMillis) throws IOException { HttpURLConnection conn = configureConnection(target, "POST", connectTimeoutMillis, readTimeoutMillis); conn.setDoOutput(true); @@ -1124,6 +1153,23 @@ HTTP endpoint (usually :5001). Applications integrating on top of the } } + private static byte[] get(URL target, int connectTimeoutMillis, int readTimeoutMillis, NamedStreamable uploadFile) throws IOException { + + /* + Posts data stream (i.e. uploadFile) as a multipart/form-data request message body + */ + + Multipart m = new Multipart(target.toString(),"UTF-8",connectTimeoutMillis,readTimeoutMillis); + if (uploadFile.isDirectory()) { + // can't upload directory paths + throw new IllegalArgumentException("'" + uploadFile.getName() + "' is a directory."); + } + m.addFilePart("file",Paths.get(""), uploadFile); + + return m.finish().getBytes(); + + } + public static RuntimeException extractError(IOException e, HttpURLConnection conn) { InputStream errorStream = conn.getErrorStream(); String err = errorStream == null ? e.getMessage() : new String(readFully(errorStream)); @@ -1214,7 +1260,7 @@ private static final byte[] readFully(InputStream in) { while ((r=in.read(buf)) >= 0) resp.write(buf, 0, r); return resp.toByteArray(); - + } catch(IOException ex) { throw new RuntimeException("Error reading InputStrean", ex); } @@ -1223,7 +1269,7 @@ private static final byte[] readFully(InputStream in) { private static boolean detectSSL(MultiAddress multiaddress) { return multiaddress.toString().contains("/https"); } - + private static HttpURLConnection configureConnection(URL target, String method, int connectTimeoutMillis, int readTimeoutMillis) throws IOException { HttpURLConnection conn = (HttpURLConnection) target.openConnection(); conn.setRequestMethod(method); diff --git a/src/main/java/io/ipfs/api/Multipart.java b/src/main/java/io/ipfs/api/Multipart.java index fe72690..a4341e6 100755 --- a/src/main/java/io/ipfs/api/Multipart.java +++ b/src/main/java/io/ipfs/api/Multipart.java @@ -32,6 +32,23 @@ public Multipart(String requestURL, String charset) { } } + public Multipart(String requestURL,String charset,int connectTimeoutMillis, int readTimeoutMillis) { + + this(requestURL,charset); + + // now set request/read timeouts supplied + if (httpConn != null) { + httpConn.setConnectTimeout(connectTimeoutMillis); + httpConn.setReadTimeout(readTimeoutMillis); + return; + } + + // somehow httpConn not initialized! + throw new IllegalStateException("expected httpConn to be initialized, found " + httpConn); + + + } + public static String createBoundary() { Random r = new Random(); String allowed = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; diff --git a/src/test/java/io/ipfs/api/APITest.java b/src/test/java/io/ipfs/api/APITest.java index 0f28b0e..12496fe 100755 --- a/src/test/java/io/ipfs/api/APITest.java +++ b/src/test/java/io/ipfs/api/APITest.java @@ -13,6 +13,7 @@ import java.util.stream.*; import static org.junit.Assert.assertTrue; +import java.net.URLEncoder; public class APITest { @@ -729,6 +730,339 @@ public void updateTest() throws IOException { Object update = ipfs.update(); } + @Test + public void filesTest() throws IOException { + + // Test Files*Args classes + + + // test chcid args + IPFS.Files.ChCIDArgs chCIDArgs = ipfs.files.new ChCIDArgs(); + Assert.assertEquals(chCIDArgs.toString(), ""); + + String expected,actual; + + expected = encodeQueryParam("arg","/mfs/path"); + actual = chCIDArgs.path("/mfs/path").toString(); + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("cid-version","1"); + actual = chCIDArgs.cidVersion(1).toString(); + Assert.assertEquals(expected,actual); + + + expected = expected + '&' + encodeQueryParam("hash","myHashName"); + actual = chCIDArgs.hash("myHashName").toString(); + Assert.assertEquals(expected,actual); + + // test cp args + IPFS.Files.CpArgs cpArgs = ipfs.files.new CpArgs("/my/src","/my/dst"); + + expected = encodeQueryParam("arg","/my/src") + '&' + encodeQueryParam("arg","/my/dst"); + actual = cpArgs.toString(); + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("parents","true"); + actual = cpArgs.makeParentDirs(true).toString(); + Assert.assertEquals(expected,actual); + + // test flush args + IPFS.Files.FlushArgs flushArgs = ipfs.files.new FlushArgs(); + + Assert.assertEquals("",flushArgs.toString()); + + expected = encodeQueryParam("arg", "/my/flush/path"); + actual = flushArgs.path("/my/flush/path").toString(); + + Assert.assertEquals(expected,actual); + + // test ls args + IPFS.Files.LsArgs lsArgs = ipfs.files.new LsArgs(); + + Assert.assertEquals("",lsArgs.toString()); + + expected = encodeQueryParam("arg","/ls/path"); + actual = lsArgs.path("/ls/path").toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("long","true"); + actual = lsArgs.longListingFormat(true).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("U","false"); + actual = lsArgs.noSort(false).toString(); + + Assert.assertEquals(expected,actual); + + // test mkdir Args + IPFS.Files.MkdirArgs mkdirArgs = ipfs.files.new MkdirArgs("/mkdir/path"); + + expected = encodeQueryParam("arg","/mkdir/path"); + actual = mkdirArgs.toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("parents","true"); + actual = mkdirArgs.parents(true).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("cid-version","5"); + actual = mkdirArgs.cidVersion(5).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("hash","myHashName"); + actual = mkdirArgs.hash("myHashName").toString(); + + Assert.assertEquals(expected,actual); + + // test mv args + IPFS.Files.MvArgs mvArgs = ipfs.files.new MvArgs("/path/src","/path/dst"); + + expected = encodeQueryParam("arg","/path/src") + '&' + encodeQueryParam("arg","/path/dst"); + actual = mvArgs.toString(); + + Assert.assertEquals(expected,actual); + + // test read args + IPFS.Files.ReadArgs readArgs = ipfs.files.new ReadArgs("/path/read"); + + expected = encodeQueryParam("arg","/path/read"); + actual = readArgs.toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("offset","55"); + actual = readArgs.offset(55).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("count","9898"); + actual = readArgs.count(9898).toString(); + + Assert.assertEquals(expected,actual); + + // test rm args + IPFS.Files.RmArgs rmArgs = ipfs.files.new RmArgs("/path/rm"); + + expected = encodeQueryParam("arg","/path/rm"); + actual = rmArgs.toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("recursive","false"); + actual = rmArgs.recursive(false).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("force","true"); + actual = rmArgs.force(true).toString(); + + Assert.assertEquals(expected,actual); + + // test stat args + IPFS.Files.StatArgs statArgs = ipfs.files.new StatArgs("/path/stat"); + + expected = encodeQueryParam("arg","/path/stat"); + actual = statArgs.toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("format","test"); + actual = statArgs.format("test").toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("hash","true"); + actual = statArgs.hash(true).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("size","false"); + actual = statArgs.size(false).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("with-local","true"); + actual = statArgs.withLocal(true).toString(); + + Assert.assertEquals(expected,actual); + + // test write args + IPFS.Files.WriteArgs writeArgs = ipfs.files.new WriteArgs("/path/write"); + + expected = encodeQueryParam("arg","/path/write"); + actual = writeArgs.toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("offset","1776"); + actual = writeArgs.offset(1776).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("create","true"); + actual = writeArgs.create(true).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("parents","true"); + actual = writeArgs.parents(true).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("truncate","true"); + actual = writeArgs.truncate(true).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("count","12"); + actual = writeArgs.count(12).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("raw-leaves","true"); + actual = writeArgs.rawLeaves(true).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("cid-version","3"); + actual = writeArgs.cidVersion(3).toString(); + + Assert.assertEquals(expected,actual); + + expected = expected + '&' + encodeQueryParam("hash","myhash1"); + actual = writeArgs.hash("myhash1").toString(); + + Assert.assertEquals(expected,actual); + + + // test files api calls + String []mfsPathElements = {UUID.randomUUID().toString(), + UUID.randomUUID().toString(), + UUID.randomUUID().toString()}; + + String testMfsDir = String.format("/%s", String.join("/",mfsPathElements)); + + + // test making dir with create parents + + Map mapRsp = ipfs.files.mkdir( ipfs.files.new MkdirArgs(testMfsDir).parents(true)); + + + //byte[] largerData = new byte[100*1024*1024]; + //new Random(1).nextBytes(largerData); + //NamedStreamable.ByteArrayWrapper largeFile = new NamedStreamable.ByteArrayWrapper("nontrivial.txt", largerData); + + String smallFilePart1 = "how much wood "; + String smallFilePart2 = "could a woodchuck chuck, "; + String smallFilePart3 = "if a woodchuck could chuck wood?"; + + String fileName = "woodchuck.txt"; + + NamedStreamable ns = new NamedStreamable.ByteArrayWrapper(fileName, smallFilePart1.getBytes()); + + + String fileToWrite = String.format("%s/%s",testMfsDir,fileName); + + // write chunk 1 of 3 + ipfs.files.write( ipfs.files.new WriteArgs(fileToWrite).create(true),ns); + // write chunk 2 of 3 + ns = new NamedStreamable.ByteArrayWrapper(fileName, smallFilePart2.getBytes()); + ipfs.files.write( ipfs.files.new WriteArgs(fileToWrite).offset(smallFilePart1.length()),ns); + // write chunk 3 of 3 + ns = new NamedStreamable.ByteArrayWrapper(fileName, smallFilePart3.getBytes()); + ipfs.files.write( ipfs.files.new WriteArgs(fileToWrite).offset(smallFilePart1.length() + smallFilePart2.length()),ns); + + // read whole file back + byte[] bytesRead = ipfs.files.read(ipfs.files.new ReadArgs(fileToWrite)); + + expected = smallFilePart1+smallFilePart2+smallFilePart3; + actual = new String(bytesRead); + + Assert.assertEquals(expected, actual); + + bytesRead = ipfs.files.read(ipfs.files.new ReadArgs(fileToWrite).offset(smallFilePart1.length() + smallFilePart2.length())); + + expected = smallFilePart3; + actual = new String(bytesRead); + + Assert.assertEquals(expected, actual); + + bytesRead = ipfs.files.read(ipfs.files.new ReadArgs(fileToWrite).offset(smallFilePart1.length()).count(smallFilePart2.length())); + + expected = smallFilePart2; + actual = new String(bytesRead); + + Assert.assertEquals(expected, actual); + + // test cp by copying woodchuck.txt to first dir path element + String src,dst; + + src = fileToWrite; + dst = "/" + mfsPathElements[0] + "/" + fileName; + + ipfs.files.cp(ipfs.files.new CpArgs(src,dst)); + + // test ls by listing woodchuck files + Map lsRsp1 = ipfs.files.ls( ipfs.files.new LsArgs().path(src)); + Map lsRsp2 = ipfs.files.ls( ipfs.files.new LsArgs().path(dst)); + + + Map rsp1LsEntry0 = (Map) ((List)lsRsp1.get("Entries")).get(0); + Map rsp2LsEntry0 = (Map) ((List)lsRsp2.get("Entries")).get(0); + + // are hashes of woodchuck files equal (original and copy) ? + Assert.assertEquals( (String) rsp1LsEntry0.get("Hash"), (String) rsp2LsEntry0.get("Hash")); + Assert.assertEquals( (Integer) rsp1LsEntry0.get("Size"), (Integer) rsp2LsEntry0.get("Size")); + Assert.assertEquals( (Integer) rsp1LsEntry0.get("Type"), (Integer) rsp2LsEntry0.get("Type")); + + // test stat by stat'ing woodchuck files + Map statRsp1 = ipfs.files.stat( ipfs.files.new StatArgs(src)); + Map statRsp2 = ipfs.files.stat( ipfs.files.new StatArgs(dst)); + + Assert.assertEquals( (Integer) statRsp1.get("Blocks"), (Integer) statRsp2.get("Blocks") ); + Assert.assertEquals( (Integer) statRsp1.get("CumulativeSize"), (Integer) statRsp2.get("CumulativeSize") ); + Assert.assertEquals( (String) statRsp1.get("Hash"), (String) statRsp2.get("Hash") ); + Assert.assertEquals( (Boolean) statRsp1.get("Local"), (Boolean) statRsp2.get("Local") ); + Assert.assertEquals( (Integer) statRsp1.get("Size"), (Integer) statRsp2.get("Size") ); + Assert.assertEquals( (Integer) statRsp1.get("SizeLocal"), (Integer) statRsp2.get("SizeLocal") ); + Assert.assertEquals( (String) statRsp1.get("Type"), (String) statRsp2.get("Type") ); + Assert.assertEquals( (Integer) statRsp1.get("WithLocality"), (Integer) statRsp2.get("WithLocality") ); + + + + // test mv by moving testMfsDir as child of first path element + src = testMfsDir; + dst = String.format("/%s",mfsPathElements[0]); + + byte[] rspMv = ipfs.files.mv ( ipfs.files.new MvArgs(src,dst)); + + + // now mv dir by renaming it + src = dst + "/" + mfsPathElements[2] ; + dst = "/" + mfsPathElements[0] + "/" + "newDir"; + + rspMv = ipfs.files.mv ( ipfs.files.new MvArgs(src,dst)); + + // rm whole root dir created in this test recursively removing its contents as well + src = "/" + mfsPathElements[0]; + + byte[] rspRm = ipfs.files.rm ( ipfs.files.new RmArgs(src).recursive(true)); + + + + } + + + + private String encodeQueryParam(String name, String value) { + return URLEncoder.encode(name) + "=" + URLEncoder.encode(value); + + } private byte[] randomBytes(int len) { byte[] res = new byte[len]; r.nextBytes(res);