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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f5f308798c9180262f9aa758b6010b910142a0d9
4
- data.tar.gz: 13fde3fde504683f14df8e5d891d5291ac3624ba
3
+ metadata.gz: 32a495dceb347f115f780d7356734ebe1fc5b55b
4
+ data.tar.gz: 2343699171c0f73806649cfbf4b7e23e25255164
5
5
  SHA512:
6
- metadata.gz: 9932b1d74862af972ded69d873a42b719b3be8dbbd8cc2977106e746b87282d0eb84efa97f9e288b60e13ef04290b1d42eead4cdaf4f88b072b88420e7a264c6
7
- data.tar.gz: e0ddc8dd3188cdce71cb4f64f738f71fc33f78d92521b03c154d6b861d427bffc77230cfa77f42111bf5154d21a803635321e496a0dbaad12b66f186851bedc9
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.github.io'
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
@@ -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')
@@ -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.1.0"
33
+ s.full_name = "ipfs-api-0.2.0"
34
34
  s.has_rdoc = true
35
- s.homepage = "http://ruby-ipfs-api.github.io"
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.1.0"
47
+ s.version = "0.2.0"
48
48
  end
@@ -1,6 +1,6 @@
1
1
  # =IPFS4R - Interplanetary Filesystem Library for Ruby
2
2
  # License:: MIT (see the LICENSE file)
3
- # Website:: https://ruby-ipfs-api.github.io
3
+ # Website:: https://hjoest.github.io/ruby-ipfs-api
4
4
  #
5
5
  # ==Introduction
6
6
  #
@@ -81,13 +81,18 @@ Content-Type: application/octet-stream\r\n\
81
81
  result
82
82
  end
83
83
 
84
- # FIXME: provides only raw response yet
85
- def get path
86
- result = ''
87
- post("get?arg=#{CGI.escape(path)}") do |chunk|
88
- result << chunk
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
- JSON.parse(post('name/resolve').body)['Path']
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
 
@@ -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 nil if @stream.size == 0
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 += s
23
- q += s
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
- def fetch_data
32
- @p = 0
33
- @stream.string = ""
34
- @block.call @stream if not @stream.closed?
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
 
@@ -1,4 +1,4 @@
1
1
  module IPFS
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
4
4
 
@@ -1,4 +1,9 @@
1
+ gem 'minitest' if RUBY_VERSION =~ /^1\.9/
1
2
  require 'minitest/autorun'
2
- require 'byebug'
3
+ if ENV['DEBUG']
4
+ require 'byebug'
5
+ else
6
+ def byebug; end
7
+ end
3
8
 
4
9
  $:.unshift File.expand_path('../../lib', __FILE__)
@@ -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('ruby-ipfs-api-unit-test-') do |root|
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
@@ -7,12 +7,34 @@ include IPFS
7
7
 
8
8
  class CommandGetTest < Minitest::Test
9
9
 
10
- def test_get
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
- # FIXME: provides only raw response yet
15
- actual = ipfs.get('QmedYJNEKn656faSHaMv5UFVkgfSzwYf9u4zsYoXqgvnch')
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
 
@@ -13,4 +13,10 @@ class CommandNameTest < Minitest::Test
13
13
  assert resolved.start_with?('/ipfs/Qm')
14
14
  end
15
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
+
16
22
  end
@@ -7,14 +7,66 @@ include IPFS::IO
7
7
 
8
8
  class ReadFromWriterIOTest < Minitest::Test
9
9
 
10
- def test_read_write_io
11
- msg = ('a'..'z').to_a.join
12
- reader = ReadFromWriterIO.new do |writer|
13
- writer << msg
14
- writer.close
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
- result = reader.read
17
- assert_equal msg, result
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.1.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: 2015-10-10 00:00:00.000000000 Z
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.github.io
43
+ homepage: http://hjoest.github.io/ruby-ipfs-api
44
44
  licenses:
45
45
  - MIT
46
46
  metadata: {}