ipfs-api 0.2.0 → 0.3.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 +33 -38
- data/Rakefile +1 -1
- data/ipfs-api.gemspec +4 -6
- data/lib/ipfs-api.rb +2 -2
- data/lib/ipfs-api/connection.rb +43 -39
- data/lib/ipfs-api/io.rb +10 -41
- data/lib/ipfs-api/upload.rb +2 -2
- data/lib/ipfs-api/version.rb +1 -1
- data/test/samples.rb +15 -1
- data/test/test_cmd_add.rb +2 -2
- data/test/test_cmd_cat.rb +2 -2
- data/test/test_cmd_get.rb +2 -2
- data/test/test_cmd_id.rb +2 -2
- data/test/test_cmd_ls.rb +2 -2
- data/test/test_io.rb +7 -9
- data/test/test_upload.rb +2 -2
- metadata +4 -6
- data/test/common.rb +0 -9
- data/test/test_cmd_name.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b33b926a8240b157a5cfa1e14d35093d0f9a4ed
|
4
|
+
data.tar.gz: '0596fee2ce4d0a8a20226a1dbacb8bd47bdaf348'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2723b6ec115c399d23c4fb0cc3fd4af506fcc83a3d2675a58f42139b755ef012563cb4bd4f81e34c6f2693016334548fa94bf819816f4ca5576a8314f329c074
|
7
|
+
data.tar.gz: 2849a2ef6807c906c622cd869b16a527b18965d433c9e0e9d5515e2c054d7aa8e653fcc0ac65b1d73e3e40bc96723bbbca8dfbd2df29c9df6841be18333ed28a
|
data/README.md
CHANGED
@@ -1,71 +1,66 @@
|
|
1
1
|
# Overview
|
2
2
|
|
3
|
-
|
3
|
+
IPFS-API for Ruby is a client library to access the [Interplanetary Filesystem (IPFS)](https://ipfs.io) from Ruby.
|
4
4
|
|
5
5
|
You can find more examples in the
|
6
6
|
[examples directory](https://github.com/hjoest/ruby-ipfs-api/tree/master/examples).
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
10
|
-
|
10
|
+
You need an [IPFS daemon](https://ipfs.io/docs/install/) running
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
ipfs daemon
|
13
|
+
|
14
|
+
To install this gem, run
|
15
|
+
|
16
|
+
gem install ipfs-api
|
15
17
|
|
16
18
|
or simply add this line to your ``Gemfile``
|
17
19
|
|
18
|
-
|
19
|
-
gem 'ipfs-api', '~> 0.1.0'
|
20
|
-
```
|
20
|
+
gem 'ipfs-api', '~> 0.3.0'
|
21
21
|
|
22
22
|
## Basic examples
|
23
23
|
|
24
24
|
This example will add a directory to *IPFS*. The directory ``data``
|
25
25
|
must exist or otherwise an ``Errno::ENOENT`` error will be raised.
|
26
26
|
|
27
|
-
|
28
|
-
require 'ipfs-api'
|
27
|
+
require 'ipfs-api'
|
29
28
|
|
30
|
-
ipfs = IPFS::Connection.new
|
31
|
-
ipfs.add Dir.new('data')
|
32
|
-
```
|
29
|
+
ipfs = IPFS::Connection.new
|
30
|
+
ipfs.add Dir.new('data')
|
33
31
|
|
34
32
|
Afterwards, we can retrieve what we put in.
|
35
|
-
```ruby
|
36
|
-
require 'ipfs-api'
|
37
33
|
|
38
|
-
ipfs
|
34
|
+
require 'ipfs-api'
|
35
|
+
|
36
|
+
ipfs = IPFS::Connection.new
|
39
37
|
|
40
|
-
# retrieve contents of a file
|
41
|
-
print ipfs.cat('QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG')
|
38
|
+
# retrieve contents of a file
|
39
|
+
print ipfs.cat('QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG')
|
42
40
|
|
43
|
-
# retrieve the whole directory
|
44
|
-
ipfs.get('QmSh4Xjoy16v6XmnREE1yCrPM1dnizZc2h6LfrqXsnbBV7', 'copy-of-data')
|
45
|
-
```
|
41
|
+
# retrieve the whole directory and make a copy of it in ``copy-of-data``
|
42
|
+
ipfs.get('QmSh4Xjoy16v6XmnREE1yCrPM1dnizZc2h6LfrqXsnbBV7', 'copy-of-data')
|
46
43
|
|
47
44
|
## Advanced
|
48
45
|
|
49
46
|
Dynamically add folders and files to *IPFS*, without creating them
|
50
47
|
on the local file system:
|
51
48
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
68
|
-
```
|
49
|
+
require 'ipfs-api'
|
50
|
+
|
51
|
+
ipfs = IPFS::Connection.new
|
52
|
+
folder = IPFS::Upload.folder('test') do |test|
|
53
|
+
test.add_file('hello.txt') do |fd|
|
54
|
+
fd.write 'Hello'
|
55
|
+
end
|
56
|
+
test.add_file('world.txt') do |fd|
|
57
|
+
fd.write 'World'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
ipfs.add folder do |node|
|
61
|
+
# display each uploaded node:
|
62
|
+
print "#{node.name}: #{node.hash}\n" if node.finished?
|
63
|
+
end
|
69
64
|
|
70
65
|
## License
|
71
66
|
|
data/Rakefile
CHANGED
@@ -52,7 +52,7 @@ spec = Gem::Specification.new do |s|
|
|
52
52
|
s.has_rdoc = true
|
53
53
|
s.extra_rdoc_files = RDOC_FILES
|
54
54
|
s.rdoc_options = RDOC_OPTIONS
|
55
|
-
s.required_ruby_version = ">=
|
55
|
+
s.required_ruby_version = ">= 2.0.0"
|
56
56
|
end
|
57
57
|
|
58
58
|
# also keep the gemspec up to date each time we package a tarball or gem
|
data/ipfs-api.gemspec
CHANGED
@@ -20,17 +20,15 @@ Gem::Specification.new do |s|
|
|
20
20
|
"lib/ipfs-api/io.rb",
|
21
21
|
"lib/ipfs-api/upload.rb",
|
22
22
|
"lib/ipfs-api/version.rb",
|
23
|
-
"test/common.rb",
|
24
23
|
"test/samples.rb",
|
25
24
|
"test/test_cmd_add.rb",
|
26
25
|
"test/test_cmd_cat.rb",
|
27
26
|
"test/test_cmd_get.rb",
|
28
27
|
"test/test_cmd_id.rb",
|
29
28
|
"test/test_cmd_ls.rb",
|
30
|
-
"test/test_cmd_name.rb",
|
31
29
|
"test/test_io.rb",
|
32
30
|
"test/test_upload.rb"]
|
33
|
-
s.full_name = "ipfs-api-0.
|
31
|
+
s.full_name = "ipfs-api-0.3.0"
|
34
32
|
s.has_rdoc = true
|
35
33
|
s.homepage = "http://hjoest.github.io/ruby-ipfs-api"
|
36
34
|
s.licenses = ["MIT"]
|
@@ -38,11 +36,11 @@ Gem::Specification.new do |s|
|
|
38
36
|
s.platform = "ruby"
|
39
37
|
s.rdoc_options = ["--title", "Interplanetary File System for Ruby", "--quiet", "--main", "lib/ipfs-api.rb"]
|
40
38
|
s.require_paths = ["lib"]
|
41
|
-
s.required_ruby_version = ">=
|
39
|
+
s.required_ruby_version = ">= 2.0.0"
|
42
40
|
s.required_rubygems_version = ">= 0"
|
43
41
|
s.rubyforge_project = "ipfs-api"
|
44
|
-
s.rubygems_version = "2.
|
42
|
+
s.rubygems_version = "2.6.10"
|
45
43
|
s.specification_version = 4
|
46
44
|
s.summary = "Interplanetary File System for Ruby"
|
47
|
-
s.version = "0.
|
45
|
+
s.version = "0.3.0"
|
48
46
|
end
|
data/lib/ipfs-api.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
# =
|
1
|
+
# =IPFS API for Ruby
|
2
2
|
# License:: MIT (see the LICENSE file)
|
3
3
|
# Website:: https://hjoest.github.io/ruby-ipfs-api
|
4
4
|
#
|
5
5
|
# ==Introduction
|
6
6
|
#
|
7
|
-
#
|
7
|
+
# IPFS API for Ruby is an IPFS[https://ipfs.io] library for Ruby.
|
8
8
|
#
|
9
9
|
require 'ipfs-api/version'
|
10
10
|
require 'ipfs-api/io'
|
data/lib/ipfs-api/connection.rb
CHANGED
@@ -11,66 +11,70 @@ module IPFS
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def add nodes, &block
|
14
|
-
|
15
|
-
|
16
|
-
'Content-Disposition' => 'form-data: name="files"',
|
17
|
-
'Content-Type' => "multipart/form-data; boundary=#{boundaries[0]}"
|
18
|
-
}
|
19
|
-
walker = Upload::TreeWalker.depth_first(nodes)
|
14
|
+
boundary = generate_boundary
|
15
|
+
tree_walker = Upload::TreeWalker.depth_first(nodes)
|
20
16
|
node_map = {}
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
rescue StopIteration
|
27
|
-
depth = -1
|
28
|
-
walker = nil
|
29
|
-
end
|
30
|
-
while boundaries.size > depth+1 && boundary = boundaries.shift
|
31
|
-
buf << %Q{\
|
32
|
-
--#{boundary}--\r\n\
|
17
|
+
producer = IO::StreamProducer.new do |buf|
|
18
|
+
buf << %Q{\
|
19
|
+
--#{boundary}\r\n\
|
20
|
+
Content-Disposition: file; filename="root"\r\n\
|
21
|
+
Content-Type: application/x-directory\r\n\
|
33
22
|
\r\n\
|
34
23
|
\r\n\
|
35
24
|
}
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
Content-
|
43
|
-
Content-Type: multipart/mixed; boundary=#{boundaries[0]}\r\n\
|
25
|
+
tree_walker.each do |node, depth|
|
26
|
+
node_map[node.path] = node
|
27
|
+
if node.folder?
|
28
|
+
buf << %Q{\
|
29
|
+
--#{boundary}\r\n\
|
30
|
+
Content-Disposition: file; filename="root#{node.path.gsub('/', '%2F')}"\r\n\
|
31
|
+
Content-Type: application/x-directory\r\n\
|
44
32
|
\r\n\
|
45
33
|
\r\n\
|
46
34
|
}
|
47
|
-
|
48
|
-
|
49
|
-
--#{
|
50
|
-
Content-Disposition: file; filename="#{node.path}"\r\n\
|
35
|
+
elsif node.file?
|
36
|
+
buf << %Q{\
|
37
|
+
--#{boundary}\r\n\
|
38
|
+
Content-Disposition: file; filename="root#{node.path.gsub('/', '%2F')}"\r\n\
|
51
39
|
Content-Type: application/octet-stream\r\n\
|
52
40
|
\r\n\
|
53
41
|
#{node.content}\r\n\
|
54
42
|
}
|
55
|
-
|
56
|
-
|
43
|
+
else
|
44
|
+
raise "Unknown node type: #{node}"
|
45
|
+
end
|
57
46
|
end
|
47
|
+
buf << %Q{\
|
48
|
+
--#{boundary}\r\n\
|
49
|
+
}
|
58
50
|
end
|
59
|
-
|
51
|
+
headers = {
|
52
|
+
'Content-Type' => "multipart/form-data; boundary=#{boundary}"
|
53
|
+
}
|
54
|
+
stream = producer.stream
|
55
|
+
uploaded_nodes = []
|
60
56
|
post("add?encoding=json&r=true&progress=true", stream, headers) do |chunk|
|
61
57
|
next if chunk.empty?
|
62
|
-
upload =
|
58
|
+
upload = nil
|
59
|
+
begin
|
60
|
+
upload = JSON.parse(chunk)
|
61
|
+
rescue JSON::ParserError
|
62
|
+
end
|
63
|
+
next if upload.nil?
|
63
64
|
path, bytes, hash = ['Name', 'Bytes', 'Hash'].map { |p| upload[p] }
|
65
|
+
next if not path.start_with?('root/')
|
66
|
+
path = path[4..-1]
|
64
67
|
node = node_map[path]
|
68
|
+
next if not node
|
65
69
|
node.bytes = bytes if bytes
|
66
70
|
node.hash = hash if hash
|
67
71
|
if block_given?
|
68
72
|
block.call(node)
|
69
73
|
elsif hash
|
70
|
-
|
74
|
+
uploaded_nodes << node
|
71
75
|
end
|
72
76
|
end
|
73
|
-
block_given? ? nil :
|
77
|
+
block_given? ? nil : uploaded_nodes
|
74
78
|
end
|
75
79
|
|
76
80
|
def cat path
|
@@ -82,16 +86,16 @@ Content-Type: application/octet-stream\r\n\
|
|
82
86
|
end
|
83
87
|
|
84
88
|
def get path, destination = nil
|
85
|
-
|
89
|
+
producer = IO::StreamProducer.new do |buf|
|
86
90
|
post("get?arg=#{CGI.escape(path)}") do |chunk|
|
87
91
|
buf << chunk
|
88
92
|
end
|
89
93
|
buf.close
|
90
94
|
end
|
91
95
|
if destination.nil?
|
92
|
-
return stream
|
96
|
+
return producer.stream
|
93
97
|
else
|
94
|
-
return IO::Tar.extract(stream, destination)
|
98
|
+
return IO::Tar.extract(producer.stream, destination)
|
95
99
|
end
|
96
100
|
end
|
97
101
|
|
data/lib/ipfs-api/io.rb
CHANGED
@@ -1,59 +1,28 @@
|
|
1
|
-
require '
|
1
|
+
require 'tempfile'
|
2
2
|
require 'rubygems/package'
|
3
3
|
|
4
4
|
module IPFS; end
|
5
5
|
module IPFS::IO # :nodoc:
|
6
6
|
|
7
|
-
class
|
7
|
+
class StreamProducer # :nodoc:
|
8
8
|
|
9
9
|
def initialize &block
|
10
10
|
@block = block
|
11
|
-
@stream = StringIO.new
|
12
|
-
@d = @p = 0
|
13
|
-
@eof = false
|
14
|
-
fetch_data
|
15
11
|
end
|
16
12
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
s = [length - q, s].min if !length.nil?
|
24
|
-
outbuf[q, s] = @stream.string[@p, s]
|
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
|
28
|
-
fetch_data if @stream.size == @p
|
13
|
+
def stream
|
14
|
+
io = Tempfile.new('ruby-ipfs')
|
15
|
+
begin
|
16
|
+
@block.call io
|
17
|
+
ensure
|
18
|
+
io.close
|
29
19
|
end
|
30
|
-
|
31
|
-
@eof = true
|
32
|
-
end
|
33
|
-
if q == 0 and not length.nil?
|
34
|
-
outbuf = nil
|
35
|
-
end
|
36
|
-
outbuf
|
37
|
-
end
|
38
|
-
|
39
|
-
def pos
|
40
|
-
@d + @p
|
41
|
-
end
|
42
|
-
|
43
|
-
def eof?
|
44
|
-
@eof
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
def fetch_data
|
49
|
-
@p, @d = 0, @d + @p
|
50
|
-
@stream.string = ''
|
51
|
-
@block.call @stream if not @stream.closed?
|
20
|
+
File.open(io.path, 'r')
|
52
21
|
end
|
53
22
|
|
54
23
|
end
|
55
24
|
|
56
|
-
module Tar
|
25
|
+
module Tar # :nodoc:
|
57
26
|
|
58
27
|
def extract stream, destination
|
59
28
|
Gem::Package::TarReader.new(stream) do |tar|
|
data/lib/ipfs-api/upload.rb
CHANGED
data/lib/ipfs-api/version.rb
CHANGED
data/test/samples.rb
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
require 'tmpdir'
|
2
|
-
require '
|
2
|
+
require 'minitest/autorun'
|
3
|
+
begin
|
4
|
+
Minitest.const_get('Test')
|
5
|
+
rescue
|
6
|
+
module Minitest
|
7
|
+
Test = Unit::TestCase
|
8
|
+
end
|
9
|
+
end
|
10
|
+
if ENV['DEBUG']
|
11
|
+
require 'byebug'
|
12
|
+
else
|
13
|
+
def byebug; end
|
14
|
+
end
|
15
|
+
|
16
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
3
17
|
require 'ipfs-api/upload'
|
4
18
|
|
5
19
|
module Samples
|
data/test/test_cmd_add.rb
CHANGED
data/test/test_cmd_cat.rb
CHANGED
data/test/test_cmd_get.rb
CHANGED
data/test/test_cmd_id.rb
CHANGED
data/test/test_cmd_ls.rb
CHANGED
data/test/test_io.rb
CHANGED
@@ -1,22 +1,21 @@
|
|
1
|
-
$:.unshift File.expand_path('
|
1
|
+
$:.unshift File.expand_path('..', __FILE__)
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'samples'
|
4
4
|
require 'ipfs-api/io'
|
5
5
|
|
6
6
|
include IPFS::IO
|
7
7
|
|
8
|
-
class
|
8
|
+
class StreamProducerTest < Minitest::Test
|
9
9
|
|
10
10
|
def setup
|
11
11
|
@parts = Samples.some_byte_sequences
|
12
12
|
enum = @parts.each
|
13
|
-
|
14
|
-
|
15
|
-
writer <<
|
16
|
-
rescue StopIteration
|
17
|
-
writer.close
|
13
|
+
producer = StreamProducer.new do |writer|
|
14
|
+
enum.each do |part|
|
15
|
+
writer << part
|
18
16
|
end
|
19
17
|
end
|
18
|
+
@reader = producer.stream
|
20
19
|
end
|
21
20
|
|
22
21
|
def test_read_byte_wise
|
@@ -24,7 +23,6 @@ class ReadFromWriterIOTest < Minitest::Test
|
|
24
23
|
while (byte = @reader.read(1))
|
25
24
|
result << byte
|
26
25
|
assert_equal result.size, @reader.pos
|
27
|
-
assert_not_eof @reader
|
28
26
|
end
|
29
27
|
assert_eof @reader
|
30
28
|
assert_equal @parts.join, result
|
data/test/test_upload.rb
CHANGED
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.3.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: 2017-02-05 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
|
@@ -30,14 +30,12 @@ files:
|
|
30
30
|
- lib/ipfs-api/io.rb
|
31
31
|
- lib/ipfs-api/upload.rb
|
32
32
|
- lib/ipfs-api/version.rb
|
33
|
-
- test/common.rb
|
34
33
|
- test/samples.rb
|
35
34
|
- test/test_cmd_add.rb
|
36
35
|
- test/test_cmd_cat.rb
|
37
36
|
- test/test_cmd_get.rb
|
38
37
|
- test/test_cmd_id.rb
|
39
38
|
- test/test_cmd_ls.rb
|
40
|
-
- test/test_cmd_name.rb
|
41
39
|
- test/test_io.rb
|
42
40
|
- test/test_upload.rb
|
43
41
|
homepage: http://hjoest.github.io/ruby-ipfs-api
|
@@ -57,7 +55,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
55
|
requirements:
|
58
56
|
- - ">="
|
59
57
|
- !ruby/object:Gem::Version
|
60
|
-
version:
|
58
|
+
version: 2.0.0
|
61
59
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
60
|
requirements:
|
63
61
|
- - ">="
|
@@ -65,7 +63,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
63
|
version: '0'
|
66
64
|
requirements: []
|
67
65
|
rubyforge_project: ipfs-api
|
68
|
-
rubygems_version: 2.
|
66
|
+
rubygems_version: 2.6.10
|
69
67
|
signing_key:
|
70
68
|
specification_version: 4
|
71
69
|
summary: Interplanetary File System for Ruby
|
data/test/common.rb
DELETED
data/test/test_cmd_name.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
$:.unshift File.expand_path('../..', __FILE__)
|
2
|
-
|
3
|
-
require 'test/common'
|
4
|
-
require 'ipfs-api'
|
5
|
-
|
6
|
-
include IPFS
|
7
|
-
|
8
|
-
class CommandNameTest < Minitest::Test
|
9
|
-
|
10
|
-
def test_name_resolve
|
11
|
-
ipfs = Connection.new
|
12
|
-
resolved = ipfs.name.resolve
|
13
|
-
assert resolved.start_with?('/ipfs/Qm')
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_name_resolve_with_id
|
17
|
-
ipfs = Connection.new
|
18
|
-
resolved = ipfs.name.resolve('ipfs.io')
|
19
|
-
assert resolved.start_with?('/ipfs/Qm')
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|