ipfs-api 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +13 -0
- data/Rakefile +2 -2
- data/examples/basic.rb +8 -0
- data/ipfs-api.gemspec +3 -3
- data/lib/ipfs-api.rb +1 -1
- data/lib/ipfs-api/connection.rb +17 -8
- data/lib/ipfs-api/io.rb +62 -8
- data/lib/ipfs-api/version.rb +1 -1
- data/test/common.rb +6 -1
- data/test/samples.rb +9 -1
- data/test/test_cmd_get.rb +25 -3
- data/test/test_cmd_name.rb +6 -0
- data/test/test_io.rb +59 -7
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32a495dceb347f115f780d7356734ebe1fc5b55b
|
4
|
+
data.tar.gz: 2343699171c0f73806649cfbf4b7e23e25255164
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71434462b2967da13a0c311bdfc3344e60460aebf60b1e690291789bad53fe73b20bf699fa8bba816b225cd95632746b65081699d11bd4c9d8b6858133909627
|
7
|
+
data.tar.gz: d5d72049af5af1d706eba6bfee86d53f3e1950a7016531bc7ee793ff478a6d9dde28ab672eb6588e3a13fe23822885ab0a66568ee17d6ba2e22aa24daf0e3b2a
|
data/README.md
CHANGED
@@ -31,6 +31,19 @@ ipfs = IPFS::Connection.new
|
|
31
31
|
ipfs.add Dir.new('data')
|
32
32
|
```
|
33
33
|
|
34
|
+
Afterwards, we can retrieve what we put in.
|
35
|
+
```ruby
|
36
|
+
require 'ipfs-api'
|
37
|
+
|
38
|
+
ipfs = IPFS::Connection.new
|
39
|
+
|
40
|
+
# retrieve contents of a file
|
41
|
+
print ipfs.cat('QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG')
|
42
|
+
|
43
|
+
# retrieve the whole directory
|
44
|
+
ipfs.get('QmSh4Xjoy16v6XmnREE1yCrPM1dnizZc2h6LfrqXsnbBV7', 'copy-of-data')
|
45
|
+
```
|
46
|
+
|
34
47
|
## Advanced
|
35
48
|
|
36
49
|
Dynamically add folders and files to *IPFS*, without creating them
|
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ PKG_NAME = 'ipfs-api'
|
|
11
11
|
PKG_VERSION = IPFS::VERSION
|
12
12
|
AUTHORS = ['Holger Joest']
|
13
13
|
EMAIL = 'holger@joest.org'
|
14
|
-
HOMEPAGE = 'http://ruby-ipfs-api
|
14
|
+
HOMEPAGE = 'http://hjoest.github.io/ruby-ipfs-api'
|
15
15
|
SUMMARY = 'Interplanetary File System for Ruby'
|
16
16
|
DESCRIPTION = 'This is a client library to access the IPFS from Ruby'
|
17
17
|
RDOC_OPTIONS = [ '--title', SUMMARY, '--quiet', '--main', 'lib/ipfs-api.rb' ]
|
@@ -32,7 +32,7 @@ RDoc::Task.new do |rd|
|
|
32
32
|
rd.options = RDOC_OPTIONS
|
33
33
|
end
|
34
34
|
|
35
|
-
CLEAN.include [ "*.gem*", "pkg", "rdoc" ]
|
35
|
+
CLEAN.include [ "*.gem*", "pkg", "rdoc", "test/tmp" ]
|
36
36
|
|
37
37
|
spec = Gem::Specification.new do |s|
|
38
38
|
s.name = PKG_NAME
|
data/examples/basic.rb
CHANGED
@@ -1,4 +1,12 @@
|
|
1
1
|
require 'ipfs-api'
|
2
2
|
|
3
3
|
ipfs = IPFS::Connection.new
|
4
|
+
|
5
|
+
# add a directory
|
4
6
|
ipfs.add Dir.new('data')
|
7
|
+
|
8
|
+
# retrieve contents of a file
|
9
|
+
print ipfs.cat('QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG')
|
10
|
+
|
11
|
+
# retrieve the whole directory
|
12
|
+
ipfs.get('QmSh4Xjoy16v6XmnREE1yCrPM1dnizZc2h6LfrqXsnbBV7', 'copy-of-data')
|
data/ipfs-api.gemspec
CHANGED
@@ -30,9 +30,9 @@ Gem::Specification.new do |s|
|
|
30
30
|
"test/test_cmd_name.rb",
|
31
31
|
"test/test_io.rb",
|
32
32
|
"test/test_upload.rb"]
|
33
|
-
s.full_name = "ipfs-api-0.
|
33
|
+
s.full_name = "ipfs-api-0.2.0"
|
34
34
|
s.has_rdoc = true
|
35
|
-
s.homepage = "http://ruby-ipfs-api
|
35
|
+
s.homepage = "http://hjoest.github.io/ruby-ipfs-api"
|
36
36
|
s.licenses = ["MIT"]
|
37
37
|
s.name = "ipfs-api"
|
38
38
|
s.platform = "ruby"
|
@@ -44,5 +44,5 @@ Gem::Specification.new do |s|
|
|
44
44
|
s.rubygems_version = "2.4.8"
|
45
45
|
s.specification_version = 4
|
46
46
|
s.summary = "Interplanetary File System for Ruby"
|
47
|
-
s.version = "0.
|
47
|
+
s.version = "0.2.0"
|
48
48
|
end
|
data/lib/ipfs-api.rb
CHANGED
data/lib/ipfs-api/connection.rb
CHANGED
@@ -81,13 +81,18 @@ Content-Type: application/octet-stream\r\n\
|
|
81
81
|
result
|
82
82
|
end
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
84
|
+
def get path, destination = nil
|
85
|
+
stream = IO::ReadFromWriterIO.new do |buf|
|
86
|
+
post("get?arg=#{CGI.escape(path)}") do |chunk|
|
87
|
+
buf << chunk
|
88
|
+
end
|
89
|
+
buf.close
|
90
|
+
end
|
91
|
+
if destination.nil?
|
92
|
+
return stream
|
93
|
+
else
|
94
|
+
return IO::Tar.extract(stream, destination)
|
89
95
|
end
|
90
|
-
result
|
91
96
|
end
|
92
97
|
|
93
98
|
def id
|
@@ -137,9 +142,13 @@ Content-Type: application/octet-stream\r\n\
|
|
137
142
|
@connection = connection
|
138
143
|
end
|
139
144
|
|
140
|
-
def resolve
|
145
|
+
def resolve id = nil
|
141
146
|
@connection.instance_exec(self) do
|
142
|
-
|
147
|
+
if id
|
148
|
+
JSON.parse(post("name/resolve?arg=#{CGI.escape(id)}").body)['Path']
|
149
|
+
else
|
150
|
+
JSON.parse(post('name/resolve').body)['Path']
|
151
|
+
end
|
143
152
|
end
|
144
153
|
end
|
145
154
|
|
data/lib/ipfs-api/io.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'stringio'
|
2
|
+
require 'rubygems/package'
|
2
3
|
|
3
4
|
module IPFS; end
|
4
5
|
module IPFS::IO # :nodoc:
|
@@ -8,31 +9,84 @@ module IPFS::IO # :nodoc:
|
|
8
9
|
def initialize &block
|
9
10
|
@block = block
|
10
11
|
@stream = StringIO.new
|
12
|
+
@d = @p = 0
|
13
|
+
@eof = false
|
11
14
|
fetch_data
|
12
15
|
end
|
13
16
|
|
14
17
|
def read length = nil, outbuf = ''
|
15
|
-
return
|
18
|
+
return '' if length == 0
|
16
19
|
outbuf.slice!(length..-1) if !length.nil?
|
17
20
|
q = 0
|
18
21
|
while @stream.size > 0
|
19
22
|
s = @stream.size - @p
|
20
23
|
s = [length - q, s].min if !length.nil?
|
21
24
|
outbuf[q, s] = @stream.string[@p, s]
|
22
|
-
@p
|
23
|
-
|
24
|
-
break if q == length
|
25
|
+
@p, q = @p + s, q + s
|
26
|
+
@eof = true if length.nil? and @p > 0 and @p == q
|
27
|
+
break if q == length or @eof
|
25
28
|
fetch_data if @stream.size == @p
|
26
29
|
end
|
30
|
+
if length.nil? || outbuf.size < length
|
31
|
+
@eof = true
|
32
|
+
end
|
33
|
+
if q == 0 and not length.nil?
|
34
|
+
outbuf = nil
|
35
|
+
end
|
27
36
|
outbuf
|
28
37
|
end
|
29
38
|
|
39
|
+
def pos
|
40
|
+
@d + @p
|
41
|
+
end
|
42
|
+
|
43
|
+
def eof?
|
44
|
+
@eof
|
45
|
+
end
|
46
|
+
|
30
47
|
private
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
48
|
+
def fetch_data
|
49
|
+
@p, @d = 0, @d + @p
|
50
|
+
@stream.string = ''
|
51
|
+
@block.call @stream if not @stream.closed?
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
module Tar
|
57
|
+
|
58
|
+
def extract stream, destination
|
59
|
+
Gem::Package::TarReader.new(stream) do |tar|
|
60
|
+
path = nil
|
61
|
+
tar.each do |entry|
|
62
|
+
if entry.full_name == '././@LongLink'
|
63
|
+
path = File.join(destination, entry.read.strip)
|
64
|
+
next
|
65
|
+
end
|
66
|
+
path ||= File.join(destination, entry.full_name)
|
67
|
+
if entry.directory?
|
68
|
+
if File.exist?(path) and not File.directory?(path)
|
69
|
+
raise IOError.new("Not a directory: #{path}")
|
70
|
+
end
|
71
|
+
FileUtils.mkdir_p path, :mode => entry.header.mode, :verbose => false
|
72
|
+
elsif entry.file?
|
73
|
+
if File.exist?(path) and not File.file?(path)
|
74
|
+
raise IOError.new("Not a file: #{path}")
|
75
|
+
end
|
76
|
+
File.open path, "wb" do |fd|
|
77
|
+
while (chunk = entry.read(1024))
|
78
|
+
fd.write chunk
|
79
|
+
end
|
80
|
+
end
|
81
|
+
FileUtils.chmod entry.header.mode, path, :verbose => false
|
82
|
+
end
|
83
|
+
path = nil
|
84
|
+
end
|
35
85
|
end
|
86
|
+
true
|
87
|
+
end
|
88
|
+
|
89
|
+
module_function :extract
|
36
90
|
|
37
91
|
end
|
38
92
|
|
data/lib/ipfs-api/version.rb
CHANGED
data/test/common.rb
CHANGED
data/test/samples.rb
CHANGED
@@ -4,6 +4,8 @@ require 'ipfs-api/upload'
|
|
4
4
|
|
5
5
|
module Samples
|
6
6
|
|
7
|
+
TEMP_DIR_PREFIX = 'ruby-ipfs-api-unit-test-'
|
8
|
+
|
7
9
|
include IPFS
|
8
10
|
|
9
11
|
def some_virtual_folders
|
@@ -61,7 +63,7 @@ module Samples
|
|
61
63
|
module_function :some_virtual_folders
|
62
64
|
|
63
65
|
def some_filesystem_folders
|
64
|
-
Dir.mktmpdir(
|
66
|
+
Dir.mktmpdir(TEMP_DIR_PREFIX) do |root|
|
65
67
|
a1 = File.join(root, 'a1')
|
66
68
|
Dir.mkdir(a1, 0755)
|
67
69
|
b1 = File.join(a1, 'b1')
|
@@ -81,4 +83,10 @@ module Samples
|
|
81
83
|
end
|
82
84
|
module_function :some_filesystem_folders
|
83
85
|
|
86
|
+
def some_byte_sequences
|
87
|
+
s = ('a'..'z').to_a.join
|
88
|
+
[ s ] * 17
|
89
|
+
end
|
90
|
+
module_function :some_byte_sequences
|
91
|
+
|
84
92
|
end
|
data/test/test_cmd_get.rb
CHANGED
@@ -7,12 +7,34 @@ include IPFS
|
|
7
7
|
|
8
8
|
class CommandGetTest < Minitest::Test
|
9
9
|
|
10
|
-
def
|
10
|
+
def test_get_as_tar_stream
|
11
11
|
ipfs = Connection.new
|
12
12
|
Samples.some_virtual_folders do |fixture, expectation|
|
13
13
|
ipfs.add fixture
|
14
|
-
|
15
|
-
|
14
|
+
hash = 'QmedYJNEKn656faSHaMv5UFVkgfSzwYf9u4zsYoXqgvnch'
|
15
|
+
stream = ipfs.get(hash)
|
16
|
+
tar = stream.read
|
17
|
+
# take some samples of the TAR archive
|
18
|
+
assert_equal 3072, tar.length
|
19
|
+
[ 0x101, 0x301, 0x501 ].each do |seek|
|
20
|
+
assert_equal 'ustar', tar[seek..seek+4]
|
21
|
+
end
|
22
|
+
[ 0x0, 0x200, 0x400 ].each do |seek|
|
23
|
+
assert_equal hash, tar[seek..seek+45]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_get_and_extract
|
29
|
+
ipfs = Connection.new
|
30
|
+
Samples.some_virtual_folders do |fixture, expectation|
|
31
|
+
ipfs.add fixture
|
32
|
+
hash = 'QmedYJNEKn656faSHaMv5UFVkgfSzwYf9u4zsYoXqgvnch'
|
33
|
+
Dir.mktmpdir(Samples::TEMP_DIR_PREFIX) do |target|
|
34
|
+
ipfs.get hash, target
|
35
|
+
actual = File.read(File.join(target, hash, 'b1/hello.txt'))
|
36
|
+
assert_equal "Hello World!\n", actual
|
37
|
+
end
|
16
38
|
end
|
17
39
|
end
|
18
40
|
|
data/test/test_cmd_name.rb
CHANGED
data/test/test_io.rb
CHANGED
@@ -7,14 +7,66 @@ include IPFS::IO
|
|
7
7
|
|
8
8
|
class ReadFromWriterIOTest < Minitest::Test
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
def setup
|
11
|
+
@parts = Samples.some_byte_sequences
|
12
|
+
enum = @parts.each
|
13
|
+
@reader = ReadFromWriterIO.new do |writer|
|
14
|
+
begin
|
15
|
+
writer << enum.next
|
16
|
+
rescue StopIteration
|
17
|
+
writer.close
|
18
|
+
end
|
15
19
|
end
|
16
|
-
|
17
|
-
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_read_byte_wise
|
23
|
+
result = ''
|
24
|
+
while (byte = @reader.read(1))
|
25
|
+
result << byte
|
26
|
+
assert_equal result.size, @reader.pos
|
27
|
+
assert_not_eof @reader
|
28
|
+
end
|
29
|
+
assert_eof @reader
|
30
|
+
assert_equal @parts.join, result
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_read_larger_chunks
|
34
|
+
result = ''
|
35
|
+
while (chunk = @reader.read(199))
|
36
|
+
result << chunk
|
37
|
+
assert_equal result.size, @reader.pos
|
38
|
+
if chunk.size < 199
|
39
|
+
assert_eof @reader
|
40
|
+
else
|
41
|
+
assert_not_eof @reader
|
42
|
+
end
|
43
|
+
end
|
44
|
+
assert_eof @reader
|
45
|
+
assert_equal @parts.join, result
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_different_variants_of_read
|
49
|
+
chunk = @reader.read(199)
|
50
|
+
assert_equal 199, chunk.size
|
51
|
+
assert_not_eof @reader
|
52
|
+
chunk = @reader.read(0)
|
53
|
+
assert_equal 0, chunk.size
|
54
|
+
assert_not_eof @reader
|
55
|
+
chunk = @reader.read
|
56
|
+
assert_equal 243, chunk.size
|
57
|
+
assert_eof @reader
|
58
|
+
chunk = @reader.read
|
59
|
+
assert_equal 0, chunk.size
|
60
|
+
assert_eof @reader
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def assert_eof stream
|
65
|
+
assert stream.eof?, "Stream should have reached end-of-file"
|
66
|
+
end
|
67
|
+
|
68
|
+
def assert_not_eof stream
|
69
|
+
assert !stream.eof?, "Stream should not yet have reached end-of-file"
|
18
70
|
end
|
19
71
|
|
20
72
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ipfs-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Holger Joest
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-03 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: This is a client library to access the IPFS from Ruby
|
14
14
|
email: holger@joest.org
|
@@ -40,7 +40,7 @@ files:
|
|
40
40
|
- test/test_cmd_name.rb
|
41
41
|
- test/test_io.rb
|
42
42
|
- test/test_upload.rb
|
43
|
-
homepage: http://ruby-ipfs-api
|
43
|
+
homepage: http://hjoest.github.io/ruby-ipfs-api
|
44
44
|
licenses:
|
45
45
|
- MIT
|
46
46
|
metadata: {}
|