diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..5ace4600
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,6 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/ant.yml b/.github/workflows/ant.yml
index 41f59c9d..6abe970e 100644
--- a/.github/workflows/ant.yml
+++ b/.github/workflows/ant.yml
@@ -1,6 +1,10 @@
name: Java CI
-on: [push]
+on:
+ schedule:
+ - cron: '42 0 * * 4'
+ push:
+ pull_request:
jobs:
build:
@@ -8,10 +12,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@v5
- name: Set up JDK 11
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v5
with:
+ distribution: temurin
java-version: 11
- name: Install and run ipfs
run: ./install-run-ipfs.sh
@@ -19,4 +24,4 @@ jobs:
run: ant -noinput -buildfile build.xml dist
- name: Run tests
timeout-minutes: 10
- run: ant -noinput -buildfile build.xml test
\ No newline at end of file
+ run: ant -noinput -buildfile build.xml test
diff --git a/.github/workflows/generated-pr.yml b/.github/workflows/generated-pr.yml
new file mode 100644
index 00000000..b8c5cc63
--- /dev/null
+++ b/.github/workflows/generated-pr.yml
@@ -0,0 +1,14 @@
+name: Close Generated PRs
+
+on:
+ schedule:
+ - cron: '0 0 * * *'
+ workflow_dispatch:
+
+permissions:
+ issues: write
+ pull-requests: write
+
+jobs:
+ stale:
+ uses: ipdxco/unified-github-workflows/.github/workflows/reusable-generated-pr.yml@v1
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 00000000..7c955c41
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -0,0 +1,14 @@
+name: Close Stale Issues
+
+on:
+ schedule:
+ - cron: '0 0 * * *'
+ workflow_dispatch:
+
+permissions:
+ issues: write
+ pull-requests: write
+
+jobs:
+ stale:
+ uses: ipdxco/unified-github-workflows/.github/workflows/reusable-stale-issue.yml@v1
diff --git a/README.md b/README.md
index 0d15acc0..9ffbe11f 100644
--- a/README.md
+++ b/README.md
@@ -96,6 +96,8 @@ Multihash filePointer = Multihash.fromBase58("QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ew
byte[] fileContents = ipfs.cat(filePointer);
```
+More example usage found [here](./src/main/java/io/ipfs/api/demo)
+
## Dependencies
Current versions of dependencies are included in the `./lib` directory.
@@ -105,13 +107,16 @@ Current versions of dependencies are included in the `./lib` directory.
* [multihash](https://github.com/multiformats/java-multihash)
* [cid](https://github.com/ipld/java-cid)
+## Releasing
+The version number is specified in `build.xml` and `pom.xml` and must be changed in both places in order to be accurately reflected in the JAR file manifest. A git tag must be added in the format `vx.x.x` for [JitPack](https://jitpack.io/#ipfs/java-ipfs-http-client/) to work.
+
## Contribute
Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/java-ipfs-api/issues)!
This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
-[](https://github.com/ipfs/community/blob/master/contributing.md)
+[](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md)
## License
diff --git a/build.xml b/build.xml
index 457962cc..5a58aacd 100644
--- a/build.xml
+++ b/build.xml
@@ -40,7 +40,7 @@
-
+
@@ -49,8 +49,8 @@
-
-
+
+
diff --git a/docker-compose.yml b/docker-compose.yml
index 55e521e1..4086f437 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,7 +1,7 @@
version: '2'
services:
ipfs-daemon:
- image: 'ipfs/go-ipfs:v0.6.0'
+ image: 'ipfs/kubo:v0.18.1'
ports:
- "4001:4001"
- "5001:5001"
diff --git a/install-run-ipfs.sh b/install-run-ipfs.sh
index 0a17de7a..a4bf3c85 100755
--- a/install-run-ipfs.sh
+++ b/install-run-ipfs.sh
@@ -1,6 +1,6 @@
#! /bin/sh
-wget https://dist.ipfs.io/go-ipfs/v0.6.0/go-ipfs_v0.6.0_linux-amd64.tar.gz -O /tmp/go-ipfs_linux-amd64.tar.gz
-tar -xvf /tmp/go-ipfs_linux-amd64.tar.gz
-export PATH=$PATH:$PWD/go-ipfs/
+wget https://dist.ipfs.io/kubo/v0.18.1/kubo_v0.18.1_linux-amd64.tar.gz -O /tmp/kubo_linux-amd64.tar.gz
+tar -xvf /tmp/kubo_linux-amd64.tar.gz
+export PATH=$PATH:$PWD/kubo/
ipfs init
ipfs daemon --enable-pubsub-experiment --routing=dhtclient &
diff --git a/lib/cid.jar b/lib/cid.jar
index 71caf698..87ace8bf 100644
Binary files a/lib/cid.jar and b/lib/cid.jar differ
diff --git a/lib/hamcrest-2.2.jar b/lib/hamcrest-2.2.jar
new file mode 100644
index 00000000..71065788
Binary files /dev/null and b/lib/hamcrest-2.2.jar differ
diff --git a/lib/hamcrest-core-1.3.jar b/lib/hamcrest-core-1.3.jar
deleted file mode 100644
index 9d5fe16e..00000000
Binary files a/lib/hamcrest-core-1.3.jar and /dev/null differ
diff --git a/lib/junit-4.12.jar b/lib/junit-4.12.jar
deleted file mode 100644
index 3a7fc266..00000000
Binary files a/lib/junit-4.12.jar and /dev/null differ
diff --git a/lib/junit-4.13.2.jar b/lib/junit-4.13.2.jar
new file mode 100644
index 00000000..6da55d8b
Binary files /dev/null and b/lib/junit-4.13.2.jar differ
diff --git a/lib/multiaddr.jar b/lib/multiaddr.jar
index c8ff06eb..f22b1e47 100644
Binary files a/lib/multiaddr.jar and b/lib/multiaddr.jar differ
diff --git a/lib/multibase.jar b/lib/multibase.jar
index 234da675..1916839f 100644
Binary files a/lib/multibase.jar and b/lib/multibase.jar differ
diff --git a/lib/multihash.jar b/lib/multihash.jar
index bb0cf54f..c70ba2d6 100644
Binary files a/lib/multihash.jar and b/lib/multihash.jar differ
diff --git a/mac-install-run-ipfs.sh b/mac-install-run-ipfs.sh
new file mode 100755
index 00000000..dd46049f
--- /dev/null
+++ b/mac-install-run-ipfs.sh
@@ -0,0 +1,6 @@
+#! /bin/sh
+wget https://dist.ipfs.io/kubo/v0.18.1/kubo_v0.18.1_darwin-arm64.tar.gz -O /tmp/kubo_darwin-arm64.tar.gz
+tar -xvf /tmp/kubo_darwin-arm64.tar.gz
+export PATH=$PATH:$PWD/kubo/
+ipfs init
+ipfs daemon --enable-pubsub-experiment --routing=dhtclient &
diff --git a/pom.xml b/pom.xml
index 55396cb1..405daa71 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.github.ipfs
java-ipfs-http-client
- v1.3.0
+ v1.4.1
jar
java-ipfs-http-client
@@ -32,9 +32,9 @@
UTF-8
UTF-8
- 4.12
- 1.3
- v1.4.1
+ 4.13.2
+ 2.2
+ v1.4.12
@@ -58,7 +58,7 @@
org.hamcrest
- hamcrest-core
+ hamcrest
${version.hamcrest}
test
@@ -69,10 +69,10 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.1
+ 3.8.0
- 1.8
- 1.8
+ 11
+ 11
diff --git a/src/main/java/io/ipfs/api/AddArgs.java b/src/main/java/io/ipfs/api/AddArgs.java
new file mode 100644
index 00000000..747eb57e
--- /dev/null
+++ b/src/main/java/io/ipfs/api/AddArgs.java
@@ -0,0 +1,118 @@
+package io.ipfs.api;
+
+import java.net.URLEncoder;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/*
+Example usage:
+ AddArgs args = AddArgs.Builder.newInstance()
+ .setInline()
+ .setCidVersion(1)
+ .build();
+ */
+public final class AddArgs {
+
+ private final Map args = new HashMap<>();
+
+ public AddArgs(Builder builder)
+ {
+ args.putAll(builder.args);
+ }
+ @Override
+ public String toString()
+ {
+ List asList = args.entrySet()
+ .stream()
+ .sorted(Comparator.comparing(Map.Entry::getKey))
+ .map(e -> e.getKey() + " = " + e.getValue()).collect(Collectors.toList());
+ return Arrays.toString(asList.toArray());
+ }
+ public String toQueryString()
+ {
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry entry: args.entrySet()) {
+ sb.append("&").append(entry.getKey())
+ .append("=")
+ .append(URLEncoder.encode(entry.getValue()));
+ }
+ return sb.length() > 0 ? sb.toString().substring(1) : sb.toString();
+ }
+ public static class Builder {
+ private static final String TRUE = "true";
+ private final Map args = new HashMap<>();
+ private Builder() {}
+ public static Builder newInstance()
+ {
+ return new Builder();
+ }
+ public Builder setQuiet() {
+ args.put("quiet", TRUE);
+ return this;
+ }
+ public Builder setQuieter() {
+ args.put("quieter", TRUE);
+ return this;
+ }
+ public Builder setSilent() {
+ args.put("silent", TRUE);
+ return this;
+ }
+ public Builder setTrickle() {
+ args.put("trickle", TRUE);
+ return this;
+ }
+ public Builder setOnlyHash() {
+ args.put("only-hash", TRUE);
+ return this;
+ }
+ public Builder setWrapWithDirectory() {
+ args.put("wrap-with-directory", TRUE);
+ return this;
+ }
+ public Builder setChunker(String chunker) {
+ args.put("chunker", chunker);
+ return this;
+ }
+ public Builder setRawLeaves() {
+ args.put("raw-leaves", TRUE);
+ return this;
+ }
+ public Builder setNocopy() {
+ args.put("nocopy", TRUE);
+ return this;
+ }
+ public Builder setFscache() {
+ args.put("fscache", TRUE);
+ return this;
+ }
+ public Builder setCidVersion(int version) {
+ args.put("cid-version", String.valueOf(version));
+ return this;
+ }
+ public Builder setHash(String hashFunction) {
+ args.put("hash", hashFunction);
+ return this;
+ }
+ public Builder setInline() {
+ args.put("inline", TRUE);
+ return this;
+ }
+ public Builder setInlineLimit(int maxBlockSize) {
+ args.put("inline-limit", String.valueOf(maxBlockSize));
+ return this;
+ }
+ public Builder setPin() {
+ args.put("pin", TRUE);
+ return this;
+ }
+ public Builder setToFiles(String path) {
+ args.put("to-files", path);
+ return this;
+ }
+ public AddArgs build()
+ {
+ return new AddArgs(this);
+ }
+ }
+}
diff --git a/src/main/java/io/ipfs/api/IPFS.java b/src/main/java/io/ipfs/api/IPFS.java
old mode 100755
new mode 100644
index dbe46dc4..9f93d5c3
--- a/src/main/java/io/ipfs/api/IPFS.java
+++ b/src/main/java/io/ipfs/api/IPFS.java
@@ -1,6 +1,7 @@
package io.ipfs.api;
import io.ipfs.cid.*;
+import io.ipfs.multibase.*;
import io.ipfs.multihash.Multihash;
import io.ipfs.multiaddr.MultiAddress;
@@ -16,6 +17,7 @@ public class IPFS {
public static final Version MIN_VERSION = Version.parse("0.4.11");
public enum PinType {all, direct, indirect, recursive}
+ public enum PinStatus {queued, pinning, pinned, failed}
public List ObjectTemplates = Arrays.asList("unixfs-dir");
public List ObjectPatchTypes = Arrays.asList("add-link", "rm-link", "set-data", "append-data");
private static final int DEFAULT_CONNECT_TIMEOUT_MILLIS = 10_000;
@@ -24,16 +26,20 @@ public enum PinType {all, direct, indirect, recursive}
public final String host;
public final int port;
public final String protocol;
- private final String version;
+ private final String apiVersion;
private final int connectTimeoutMillis;
private final int readTimeoutMillis;
public final Key key = new Key();
+ public final Log log = new Log();
+ public final MultibaseAPI multibase = new MultibaseAPI();
public final Pin pin = new Pin();
public final Repo repo = new Repo();
public final IPFSObject object = new IPFSObject();
public final Swarm swarm = new Swarm();
public final Bootstrap bootstrap = new Bootstrap();
+ public final Bitswap bitswap = new Bitswap();
public final Block block = new Block();
+ public final CidAPI cid = new CidAPI();
public final Dag dag = new Dag();
public final Diag diag = new Diag();
public final Config config = new Config();
@@ -41,9 +47,12 @@ public enum PinType {all, direct, indirect, recursive}
public final Update update = new Update();
public final DHT dht = new DHT();
public final File file = new File();
+ public final Files files = new Files();
+ public final FileStore fileStore = new FileStore();
public final Stats stats = new Stats();
public final Name name = new Name();
public final Pubsub pubsub = new Pubsub();
+ public final VersionAPI version = new VersionAPI();
public IPFS(String host, int port) {
this(host, port, "/api/v0/", false);
@@ -54,14 +63,22 @@ public IPFS(String multiaddr) {
}
public IPFS(MultiAddress addr) {
- this(addr.getHost(), addr.getTCPPort(), "/api/v0/", detectSSL(addr));
+ this(addr.getHost(), addr.getPort(), "/api/v0/", detectSSL(addr));
}
public IPFS(String host, int port, String version, boolean ssl) {
- this(host, port, version, DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, ssl);
+ this(host, port, version, true, DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, ssl);
+ }
+
+ public IPFS(String host, int port, String version, boolean enforceMinVersion, boolean ssl) {
+ this(host, port, version, enforceMinVersion, DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, ssl);
}
public IPFS(String host, int port, String version, int connectTimeoutMillis, int readTimeoutMillis, boolean ssl) {
+ this(host, port, version, true, connectTimeoutMillis, readTimeoutMillis, ssl);
+ }
+
+ public IPFS(String host, int port, String version, boolean enforceMinVersion, int connectTimeoutMillis, int readTimeoutMillis, boolean ssl) {
if (connectTimeoutMillis < 0) throw new IllegalArgumentException("connect timeout must be zero or positive");
if (readTimeoutMillis < 0) throw new IllegalArgumentException("read timeout must be zero or positive");
this.host = host;
@@ -75,24 +92,30 @@ public IPFS(String host, int port, String version, int connectTimeoutMillis, int
this.protocol = "http";
}
- this.version = version;
+ this.apiVersion = version;
// Check IPFS is sufficiently recent
- try {
- Version detected = Version.parse(version());
- if (detected.isBefore(MIN_VERSION))
- throw new IllegalStateException("You need to use a more recent version of IPFS! >= " + MIN_VERSION);
- } catch (IOException e) {
- throw new RuntimeException(e);
+ if (enforceMinVersion) {
+ try {
+ Version detected = Version.parse(version());
+ if (detected.isBefore(MIN_VERSION))
+ throw new IllegalStateException("You need to use a more recent version of IPFS! >= " + MIN_VERSION);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
}
-
+
/**
* Configure a HTTP client timeout
* @param timeout (default 0: infinite timeout)
* @return current IPFS object with configured timeout
*/
public IPFS timeout(int timeout) {
- return new IPFS(host, port, version, connectTimeoutMillis, readTimeoutMillis, protocol.equals("https"));
+ return new IPFS(host, port, apiVersion, timeout, timeout, protocol.equals("https"));
+ }
+
+ public String shutdown() throws IOException {
+ return retrieveString("shutdown");
}
public List add(NamedStreamable file) throws IOException {
@@ -108,13 +131,31 @@ public List add(NamedStreamable file, boolean wrap, boolean hashOnly
}
public List add(List files, boolean wrap, boolean hashOnly) throws IOException {
- Multipart m = new Multipart(protocol + "://" + host + ":" + port + version + "add?stream-channels=true&w="+wrap + "&n="+hashOnly, "UTF-8");
+ Multipart m = new Multipart(protocol + "://" + host + ":" + port + apiVersion + "add?stream-channels=true&w="+wrap + "&n="+hashOnly, "UTF-8");
+ for (NamedStreamable file: files) {
+ if (file.isDirectory()) {
+ m.addSubtree(Paths.get(""), file);
+ } else
+ m.addFilePart("file", Paths.get(""), file);
+ }
+ String res = m.finish();
+ return JSONParser.parseStream(res).stream()
+ .map(x -> MerkleNode.fromJSON((Map) x))
+ .collect(Collectors.toList());
+ }
+
+ public List add(NamedStreamable file, AddArgs args) throws IOException {
+ return add(Collections.singletonList(file), args);
+ }
+
+ public List add(List files, AddArgs args) throws IOException {
+ Multipart m = new Multipart(protocol + "://" + host + ":" + port + apiVersion + "add?stream-channels=true&"+ args.toQueryString(), "UTF-8");
for (NamedStreamable file: files) {
if (file.isDirectory()) {
m.addSubtree(Paths.get(""), file);
} else
m.addFilePart("file", Paths.get(""), file);
- };
+ }
String res = m.finish();
return JSONParser.parseStream(res).stream()
.map(x -> MerkleNode.fromJSON((Map) x))
@@ -159,7 +200,7 @@ public Map resolve(String scheme, Multihash hash, boolean recursive) throws IOEx
return retrieveMap("resolve?arg=/" + scheme+"/"+hash +"&r="+recursive);
}
-
+ @Deprecated
public String dns(String domain, boolean recursive) throws IOException {
Map res = retrieveMap("dns?arg=" + domain + "&r=" + recursive);
return (String)res.get("Path");
@@ -188,6 +229,39 @@ public List local() throws IOException {
/* Pinning an object ensures a local copy of it is kept.
*/
public class Pin {
+ public final Remote remote = new Remote();
+
+ public class Remote {
+ public Map add(String service, Multihash hash, Optional name, boolean background) throws IOException {
+ String nameArg = name.isPresent() ? "&name=" + name.get() : "";
+ return retrieveMap("pin/remote/add?arg=" + hash + "&service=" + service + nameArg + "&background=" + background);
+ }
+ public Map ls(String service, Optional name, Optional> statusList) throws IOException {
+ String nameArg = name.isPresent() ? "&name=" + name.get() : "";
+ String statusArg = statusList.isPresent() ? statusList.get().stream().
+ map(p -> "&status=" + p).collect(Collectors.joining()) : "";
+ return retrieveMap("pin/remote/ls?service=" + service + nameArg + statusArg);
+ }
+ public String rm(String service, Optional name, Optional> statusList, Optional> cidList) throws IOException {
+ String nameArg = name.isPresent() ? "&name=" + name.get() : "";
+ String statusArg = statusList.isPresent() ? statusList.get().stream().
+ map(p -> "&status=" + p).collect(Collectors.joining()) : "";
+ String cidArg = cidList.isPresent() ? cidList.get().stream().
+ map(p -> "&cid=" + p.toBase58()).collect(Collectors.joining()) : "";
+ return retrieveString("pin/remote/rm?service=" + service + nameArg + statusArg + cidArg);
+ }
+ public String addService(String service, String endPoint, String key) throws IOException {
+ return retrieveString("pin/remote/service/add?arg=" + service + "&arg=" + endPoint + "&arg=" + key);
+ }
+
+ public List