Skip to content

Commit 058e25b

Browse files
committed
Upgrade to supporting Cid, and cbor encoding.
Implement dag api. Partially Implement IpldNode, though it's not used yet. Bump version to 1.1.0, and increase minimum IPFS version to 0.4.5
1 parent 659bafe commit 058e25b

File tree

15 files changed

+2098
-18
lines changed

15 files changed

+2098
-18
lines changed

lib/cid.jar

7.87 KB
Binary file not shown.

lib/multibase.jar

8.57 KB
Binary file not shown.

lib/multihash.jar

-1.59 KB
Binary file not shown.

src/main/java/io/ipfs/api/IPFS.java

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
package io.ipfs.api;
22

3+
import io.ipfs.cid.*;
34
import io.ipfs.multihash.Multihash;
45
import io.ipfs.multiaddr.MultiAddress;
56

67
import java.io.*;
78
import java.net.*;
89
import java.util.*;
9-
import java.util.function.*;
1010
import java.util.stream.*;
1111

1212
public class IPFS {
1313

14-
public static final String MIN_VERSION = "0.4.3";
14+
public static final String MIN_VERSION = "0.4.5";
1515
public enum PinType {all, direct, indirect, recursive}
1616
public List<String> ObjectTemplates = Arrays.asList("unixfs-dir");
1717
public List<String> ObjectPatchTypes = Arrays.asList("add-link", "rm-link", "set-data", "append-data");
@@ -25,6 +25,7 @@ public enum PinType {all, direct, indirect, recursive}
2525
public final Swarm swarm = new Swarm();
2626
public final Bootstrap bootstrap = new Bootstrap();
2727
public final Block block = new Block();
28+
public final Dag dag = new Dag();
2829
public final Diag diag = new Diag();
2930
public final Config config = new Config();
3031
public final Refs refs = new Refs();
@@ -138,7 +139,7 @@ public List<Multihash> local() throws IOException {
138139
String jsonStream = new String(retrieve("refs/local"));
139140
return JSONParser.parseStream(jsonStream).stream()
140141
.map(m -> (String) (((Map) m).get("Ref")))
141-
.map(Multihash::fromBase58)
142+
.map(Cid::decode)
142143
.collect(Collectors.toList());
143144
}
144145
}
@@ -149,7 +150,7 @@ public class Pin {
149150
public List<Multihash> add(Multihash hash) throws IOException {
150151
return ((List<Object>)((Map)retrieveAndParse("pin/add?stream-channels=true&arg=" + hash)).get("Pins"))
151152
.stream()
152-
.map(x -> Multihash.fromBase58((String)x))
153+
.map(x -> Cid.decode((String)x))
153154
.collect(Collectors.toList());
154155
}
155156

@@ -160,7 +161,7 @@ public Map<Multihash, Object> ls() throws IOException {
160161
public Map<Multihash, Object> ls(PinType type) throws IOException {
161162
return ((Map<String, Object>)(((Map)retrieveAndParse("pin/ls?stream-channels=true&t="+type.name())).get("Keys"))).entrySet()
162163
.stream()
163-
.collect(Collectors.toMap(x -> Multihash.fromBase58(x.getKey()), x-> x.getValue()));
164+
.collect(Collectors.toMap(x -> Cid.decode(x.getKey()), x-> x.getValue()));
164165
}
165166

166167
public List<Multihash> rm(Multihash hash) throws IOException {
@@ -169,7 +170,7 @@ public List<Multihash> rm(Multihash hash) throws IOException {
169170

170171
public List<Multihash> rm(Multihash hash, boolean recursive) throws IOException {
171172
Map json = retrieveMap("pin/rm?stream-channels=true&r=" + recursive + "&arg=" + hash);
172-
return ((List<Object>) json.get("Pins")).stream().map(x -> Multihash.fromBase58((String) x)).collect(Collectors.toList());
173+
return ((List<Object>) json.get("Pins")).stream().map(x -> Cid.decode((String) x)).collect(Collectors.toList());
173174
}
174175
}
175176

@@ -189,7 +190,12 @@ public byte[] get(Multihash hash) throws IOException {
189190
}
190191

191192
public List<MerkleNode> put(List<byte[]> data) throws IOException {
192-
Multipart m = new Multipart("http://" + host + ":" + port + version+"block/put?stream-channels=true", "UTF-8");
193+
return put(data, Optional.empty());
194+
}
195+
196+
public List<MerkleNode> put(List<byte[]> data, Optional<String> format) throws IOException {
197+
String fmt = format.map(f -> "&format=" + f).orElse("");
198+
Multipart m = new Multipart("http://" + host + ":" + port + version+"block/put?stream-channels=true" + fmt, "UTF-8");
193199
for (byte[] f : data)
194200
m.addFilePart("file", new NamedStreamable.ByteArrayWrapper(f));
195201
String res = m.finish();
@@ -352,9 +358,9 @@ public List<MultiAddress> rm(MultiAddress addr, boolean all) throws IOException
352358
ipfs peers in the internet.
353359
*/
354360
public class Swarm {
355-
public List<MultiAddress> peers() throws IOException {
361+
public List<Peer> peers() throws IOException {
356362
Map m = retrieveMap("swarm/peers?stream-channels=true");
357-
return ((List<Object>)m.get("Strings")).stream().map(x -> new MultiAddress((String)x)).collect(Collectors.toList());
363+
return ((List<Object>)m.get("Peers")).stream().map(Peer::fromJSON).collect(Collectors.toList());
358364
}
359365

360366
public Map addrs() throws IOException {
@@ -373,6 +379,33 @@ public Map disconnect(String multiAddr) throws IOException {
373379
}
374380
}
375381

382+
public class Dag {
383+
public byte[] get(Cid cid) throws IOException {
384+
return retrieve("block/get?stream-channels=true&arg=" + cid);
385+
}
386+
387+
public MerkleNode put(byte[] object) throws IOException {
388+
return put("json", object, "cbor");
389+
}
390+
391+
public MerkleNode put(String inputFormat, byte[] object) throws IOException {
392+
return put(inputFormat, object, "cbor");
393+
}
394+
395+
public MerkleNode put(byte[] object, String outputFormat) throws IOException {
396+
return put("json", object, outputFormat);
397+
}
398+
399+
public MerkleNode put(String inputFormat, byte[] object, String outputFormat) throws IOException {
400+
block.put(Arrays.asList(object));
401+
String prefix = "http://" + host + ":" + port + version;
402+
Multipart m = new Multipart(prefix + "block/put/?stream-channels=true&input-enc=" + inputFormat + "&f=" + outputFormat, "UTF-8");
403+
m.addFilePart("file", new NamedStreamable.ByteArrayWrapper(object));
404+
String res = m.finish();
405+
return MerkleNode.fromJSON(JSONParser.parse(res));
406+
}
407+
}
408+
376409
public class Diag {
377410
public String net() throws IOException {
378411
return new String(retrieve("diag/net?stream-channels=true"));
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
package io.ipfs.api;
2+
3+
import io.ipfs.api.cbor.*;
4+
import io.ipfs.cid.*;
5+
import io.ipfs.multihash.*;
6+
7+
import java.security.*;
8+
import java.util.*;
9+
import java.util.stream.*;
10+
11+
public interface IpldNode extends Cborable {
12+
13+
Pair<IpldNode, List<String>> resolve(List<String> path);
14+
15+
/** Lists all paths within the object under 'path', and up to the given depth.
16+
* To list the entire object (similar to `find .`) pass "" and -1
17+
* @param path
18+
* @param depth
19+
* @return
20+
*/
21+
List<String> tree(String path, int depth);
22+
23+
/**
24+
*
25+
* @return calculate this objects Cid
26+
*/
27+
default Cid cid() {
28+
byte[] raw = rawData();
29+
try {
30+
MessageDigest md = MessageDigest.getInstance("SHA-256");
31+
md.update(raw);
32+
byte[] digest = md.digest();
33+
Multihash h = new Multihash(Multihash.Type.sha2_256, digest);
34+
return new Cid(1, Cid.Codec.DagCbor, h);
35+
} catch (NoSuchAlgorithmException e) {
36+
throw new RuntimeException(e.getMessage(), e);
37+
}
38+
}
39+
40+
/**
41+
*
42+
* @return size of this object when encoded
43+
*/
44+
long size();
45+
46+
/**
47+
*
48+
* @return this object's serialization
49+
*/
50+
byte[] rawData();
51+
52+
/**
53+
*
54+
* @return the merkle links from this object
55+
*/
56+
List<Link> getLinks();
57+
58+
static IpldNode fromCBOR(CborObject cbor) {
59+
return new CborIpldNode(cbor);
60+
}
61+
62+
static IpldNode fromJSON(Object json) {
63+
return new JsonIpldNode(json);
64+
}
65+
66+
class CborIpldNode implements IpldNode {
67+
private final CborObject base;
68+
69+
public CborIpldNode(CborObject base) {
70+
this.base = base;
71+
}
72+
73+
@Override
74+
public CborObject toCbor() {
75+
return base;
76+
}
77+
78+
@Override
79+
public Pair<IpldNode, List<String>> resolve(List<String> path) {
80+
throw new IllegalStateException("Unimplemented!");
81+
}
82+
83+
@Override
84+
public List<String> tree(String path, int depth) {
85+
return tree(base, path, depth);
86+
}
87+
88+
private List<String> tree(CborObject base, String rawPath, int depth) {
89+
String path = rawPath.startsWith("/") ? rawPath.substring(1) : rawPath;
90+
91+
if (depth == 0 || (path.equals("") && depth != -1))
92+
return Collections.singletonList("");
93+
94+
if (base instanceof CborObject.CborMap) {
95+
return ((CborObject.CborMap) base).values.entrySet()
96+
.stream()
97+
.flatMap(e -> {
98+
String name = ((CborObject.CborString) e.getKey()).value;
99+
if (path.startsWith(name) || depth == -1)
100+
return tree(e.getValue(), path.length() > 0 ? path.substring(name.length()) : path,
101+
depth == -1 ? -1 : depth - 1)
102+
.stream()
103+
.map(p -> "/" + name + p);
104+
return Stream.empty();
105+
}).collect(Collectors.toList());
106+
}
107+
if (depth == -1)
108+
return Collections.singletonList("");
109+
return Collections.emptyList();
110+
}
111+
112+
@Override
113+
public long size() {
114+
return rawData().length;
115+
}
116+
117+
@Override
118+
public byte[] rawData() {
119+
return base.toByteArray();
120+
}
121+
122+
@Override
123+
public List<Link> getLinks() {
124+
return getLinks(base);
125+
}
126+
127+
private static List<Link> getLinks(CborObject base) {
128+
if (base instanceof CborObject.CborMerkleLink)
129+
return Collections.singletonList(new Link("", 0, ((CborObject.CborMerkleLink) base).target));
130+
if (base instanceof CborObject.CborMap) {
131+
return ((CborObject.CborMap) base).values.values()
132+
.stream()
133+
.flatMap(cbor -> getLinks(cbor).stream())
134+
.collect(Collectors.toList());
135+
}
136+
if (base instanceof CborObject.CborList) {
137+
return ((CborObject.CborList) base).value
138+
.stream()
139+
.flatMap(cbor -> getLinks(cbor).stream())
140+
.collect(Collectors.toList());
141+
}
142+
return Collections.emptyList();
143+
}
144+
}
145+
146+
class JsonIpldNode implements IpldNode {
147+
private final Object json;
148+
149+
public JsonIpldNode(Object json) {
150+
this.json = json;
151+
}
152+
153+
@Override
154+
public CborObject toCbor() {
155+
throw new IllegalStateException("Unimplemented!");
156+
}
157+
158+
@Override
159+
public Pair<IpldNode, List<String>> resolve(List<String> path) {
160+
throw new IllegalStateException("Unimplemented!");
161+
}
162+
163+
@Override
164+
public List<String> tree(String path, int depth) {
165+
throw new IllegalStateException("Unimplemented!");
166+
}
167+
168+
@Override
169+
public long size() {
170+
return rawData().length;
171+
}
172+
173+
@Override
174+
public byte[] rawData() {
175+
return JSONParser.toString(json).getBytes();
176+
}
177+
178+
@Override
179+
public List<Link> getLinks() {
180+
throw new IllegalStateException("Unimplemented!");
181+
}
182+
}
183+
184+
class Link {
185+
public final String name;
186+
// Cumulative size of target
187+
public final long size;
188+
public final Multihash target;
189+
190+
public Link(String name, long size, Multihash target) {
191+
this.name = name;
192+
this.size = size;
193+
this.target = target;
194+
}
195+
196+
@Override
197+
public boolean equals(Object o) {
198+
if (this == o) return true;
199+
if (o == null || getClass() != o.getClass()) return false;
200+
201+
Link link = (Link) o;
202+
203+
if (size != link.size) return false;
204+
if (name != null ? !name.equals(link.name) : link.name != null) return false;
205+
return target != null ? target.equals(link.target) : link.target == null;
206+
207+
}
208+
209+
@Override
210+
public int hashCode() {
211+
int result = name != null ? name.hashCode() : 0;
212+
result = 31 * result + (int) (size ^ (size >>> 32));
213+
result = 31 * result + (target != null ? target.hashCode() : 0);
214+
return result;
215+
}
216+
}
217+
}

src/main/java/io/ipfs/api/MerkleNode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.ipfs.api;
22

3+
import io.ipfs.cid.*;
34
import io.ipfs.multihash.Multihash;
45

56
import java.util.*;
@@ -23,7 +24,7 @@ public MerkleNode(String hash, Optional<String> name) {
2324

2425
public MerkleNode(String hash, Optional<String> name, Optional<Integer> size, Optional<Integer> type, List<MerkleNode> links, Optional<byte[]> data) {
2526
this.name = name;
26-
this.hash = Multihash.fromBase58(hash);
27+
this.hash = Cid.decode(hash);
2728
this.size = size;
2829
this.type = type;
2930
this.links = links;

0 commit comments

Comments
 (0)