ruby-ipfs-api 0.5.0 → 0.5.1

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: 6ed5bd942765642e4bd3c2d5288cabc376fc63fd
4
- data.tar.gz: a4b6662afce323e336b7b5e89837e13a148c3d76
3
+ metadata.gz: b88f45e74fc2a1d52cbb1ddb1475d99a8d90c958
4
+ data.tar.gz: a437843901b0627e9df05bf2eddd39829bcc025c
5
5
  SHA512:
6
- metadata.gz: 911bf26795481cac044b2d68f572f197a6b96deffd9ac35862d3ee8897424f4cb67bce6800b69b6b32b90d69c0c10b945629f66d11334688791839c59ab2ade1
7
- data.tar.gz: 6912913ce0388053688d9308748023bacb37b1e0ca42c18d110852ef6b7561a02bb4923de45613c070e11bd0d2afc2abcfd725cd73f8ec6d832d7f01e5702b69
6
+ metadata.gz: '0584b5117850f444ad8c496ebba5045692ba7d0c9885d448f2d3e714d84e1481462abbe8031721fe981a0a5a5f6d4bf87539f1ca911cc05d56cd89e73ebb4e67'
7
+ data.tar.gz: 7526273d89114e60ecc224e4484abc641c033b54ae52fce7d9075c836275a9e5682cbee49a04835f53caff2c051c391684cf9af282fcea834d94f4526d7e2874
data/lib/api/files/cat.rb CHANGED
@@ -6,7 +6,7 @@ module Ipfs
6
6
  PATH = '/cat'
7
7
 
8
8
  def self.build_request(multihash)
9
- Command.build_request(PATH, multihash: Ipfs::Multihash.new(multihash))
9
+ Command.build_request(PATH, multihash: multihash)
10
10
  end
11
11
 
12
12
  def self.parse_response(response)
data/lib/client.rb CHANGED
@@ -1,37 +1,141 @@
1
- require_relative './http_api'
1
+ require 'http'
2
+ require 'uri'
3
+
4
+ require_relative './errors'
2
5
  require_relative './api/command'
3
- require_relative './multihash'
6
+ require_relative './api/generic/id'
7
+
8
+ require_relative './connection/default'
9
+ require_relative './connection/ipfs_config'
10
+ require_relative './connection/unreachable'
4
11
 
5
12
  module Ipfs
13
+ # The client is not intended to be manipulated. It is a singleton class used
14
+ # to route commands and their corresponding requests.
15
+ #
16
+ # However, it contains certain, read-only, information that can be useful for
17
+ # debugging purposes.
6
18
  class Client
7
- def initialize(server = {})
8
- @http_api = HttpApi.new server
9
- end
19
+ # @api private
20
+ DEFAULT_BASE_PATH = '/api/v0'
21
+ # @api private
22
+ CONNECTION_METHODS = [
23
+ Connection::Default,
24
+ Connection::IpfsConfig,
25
+ Connection::Unreachable
26
+ ]
10
27
 
11
- def id
12
- execute Command::Id
13
- end
28
+ # @api private
29
+ class << self
30
+ def initialize
31
+ attempt_connection
14
32
 
15
- def version
16
- execute Command::Version
17
- end
33
+ retrieve_ids
34
+ retrieve_daemon_version
18
35
 
19
- def cat(multihash)
20
- execute Command::Cat, multihash
21
- end
36
+ ObjectSpace.define_finalizer(self, proc { @@connection.close })
37
+ end
22
38
 
23
- def ls(multihash)
24
- execute Command::Ls, multihash
25
- end
26
39
 
27
- def add(filepath)
28
- execute Command::Add, filepath
29
- end
40
+ # @api private
41
+ def execute(command, *args)
42
+ command.parse_response call command.build_request *args
43
+ end
44
+
45
+ # Various debugging information concerning the Ipfs node itself
46
+ #
47
+ # @example
48
+ # Ipfs::Client.id
49
+ # #=> {
50
+ # peer_id: 'QmVnLbr9Jktjwx...',
51
+ # addresses: [
52
+ # "/ip4/127.0.0.1/tcp/4001/ipfs/QmVwxnW4Z8JVMDfo1jeFMNqQor5naiStUPooCdf2Yu23Gi",
53
+ # "/ip4/192.168.1.16/tcp/4001/ipfs/QmVwxnW4Z8JVMDfo1jeFMNqQor5naiStUPooCdf2Yu23Gi",
54
+ # "/ip6/::1/tcp/4001/ipfs/QmVwxnW4Z8JVMDfo1jeFMNqQor5naiStUPooCdf2Yu23Gi",
55
+ # "/ip6/2a01:e34:ef8d:2940:8f7:c616:...5naiStUPooCdf2Yu23Gi",
56
+ # "/ip6/2a01:e34:ef8d:2940:...5naiStUPooCdf2Yu23Gi",
57
+ # "/ip4/78.248.210.148/tcp/13684/ipfs/Qm...o1jeFMNqQor5naiStUPooCdf2Yu23Gi"
58
+ # ],
59
+ # public_key: "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwgg...AgMBAAE=",
60
+ # agent_version: "go-ipfs/0.4.13/3b16b74"
61
+ # }
62
+ #
63
+ # @return [Hash{Symbol => String, Array<String>}]
64
+ def id
65
+ @@id
66
+ end
30
67
 
31
- private
68
+ # Various debugging information concerning the running Ipfs daemon
69
+ # and this library
70
+ #
71
+ # @example
72
+ # Ipfs::Client.daemon
73
+ # #=> {
74
+ # :version: "0.4.13",
75
+ # commit: "cc01b7f",
76
+ # repo: "6",
77
+ # system: "amd64/darwin",
78
+ # golang: "go1.9.2"
79
+ # }
80
+ #
81
+ # @return [Hash{Symbol => String}]
82
+ def daemon
83
+ @@daemon
84
+ end
32
85
 
33
- def execute(command, *args)
34
- command.parse_response @http_api.call command.build_request *args
86
+ private
87
+
88
+ def call(command)
89
+ begin
90
+ @@connection.request(
91
+ command.verb,
92
+ "#{DEFAULT_BASE_PATH}#{command.path}",
93
+ command.options
94
+ )
95
+ rescue HTTP::ConnectionError
96
+ raise Ipfs::Error::UnreachableDaemon, "IPFS is not reachable."
97
+ end
98
+ end
99
+
100
+ def attempt_connection
101
+ find_up = ->(connections) {
102
+ connections.each { |connection|
103
+ co = connection.new
104
+
105
+ return co if co.up?
106
+ }
107
+ }
108
+
109
+ @@connection = find_up.call(CONNECTION_METHODS).make_persistent
110
+ end
111
+
112
+ def retrieve_ids
113
+ (execute Command::Id).tap do |ids|
114
+ @@id = {
115
+ peer_id: ids['ID'],
116
+ addresses: ids['Addresses'],
117
+ public_key: ids['PublicKey'],
118
+ agent_version: ids['AgentVersion'],
119
+ }
120
+ end
121
+ end
122
+
123
+ def retrieve_daemon_version
124
+ (execute Command::Version).tap do |version|
125
+ @@daemon = {
126
+ version: version['Version'],
127
+ commit: version['Commit'],
128
+ repo: version['Repo'],
129
+ system: version['System'],
130
+ golang: version['Golang'],
131
+ api: DEFAULT_BASE_PATH.split('/')[-1]
132
+ }
133
+ end
134
+ end
35
135
  end
136
+
137
+ initialize
138
+
139
+ private_class_method :new
36
140
  end
37
- end
141
+ end
@@ -0,0 +1,28 @@
1
+ require 'http'
2
+ require 'uri'
3
+
4
+ module Ipfs
5
+ module Connection
6
+ class Base
7
+ DEFAULT_BASE_PATH = '/api/v0'
8
+ attr_reader :host, :port
9
+
10
+ def build_uri
11
+ URI::HTTP.build(host: @host, port: @port)
12
+ end
13
+
14
+ def up?
15
+ begin
16
+ HTTP.get("http://#{@host}:#{@port}#{DEFAULT_BASE_PATH}/id")
17
+ true
18
+ rescue HTTP::ConnectionError
19
+ false
20
+ end
21
+ end
22
+
23
+ def make_persistent
24
+ HTTP.persistent build_uri
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,12 @@
1
+ require_relative './base'
2
+
3
+ module Ipfs
4
+ module Connection
5
+ class Default < Base
6
+ def initialize
7
+ @host = 'localhost'
8
+ @port = 5001
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,27 @@
1
+ require_relative './base'
2
+
3
+ module Ipfs
4
+ module Connection
5
+ class IpfsConfig < Base
6
+ CONFIG_FILEPATH = "#{ENV['HOME']}/.ipfs/config"
7
+
8
+ def initialize
9
+ parse_config.tap { |location|
10
+ @host = location[:host]
11
+ @port = location[:port]
12
+ }
13
+ end
14
+
15
+ private
16
+
17
+ def parse_config
18
+ %r{.*API.*/ip4/(.*)/tcp/(\d+)}.match(::File.read CONFIG_FILEPATH) do |matched_data|
19
+ {
20
+ host: matched_data[1],
21
+ port: matched_data[2].to_i
22
+ }
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,12 @@
1
+ require_relative './base'
2
+ require_relative '../errors'
3
+
4
+ module Ipfs
5
+ module Connection
6
+ class Unreachable < Base
7
+ def up?
8
+ raise Ipfs::Error::UnreachableDaemon, "IPFS is not reachable."
9
+ end
10
+ end
11
+ end
12
+ end
data/lib/dagstream.rb CHANGED
@@ -6,14 +6,14 @@ module Ipfs
6
6
 
7
7
  def initialize(response)
8
8
  if response.status.code == 200
9
- @content = response
9
+ @content = response.body.to_s
10
10
  else
11
11
  raise Error::InvalidDagStream, JSON.parse(response.body)['Message']
12
12
  end
13
13
  end
14
14
 
15
15
  def to_s
16
- @content.body.to_s
16
+ @content
17
17
  end
18
18
 
19
19
  alias to_str to_s
data/lib/errors.rb CHANGED
@@ -5,5 +5,8 @@ module Ipfs
5
5
 
6
6
  class InvalidMultihash < StandardError
7
7
  end
8
+
9
+ class UnreachableDaemon < StandardError
10
+ end
8
11
  end
9
12
  end
data/lib/file.rb ADDED
@@ -0,0 +1,112 @@
1
+ require_relative './multihash'
2
+ require_relative './api/files/add'
3
+ require_relative './api/files/cat'
4
+
5
+ module Ipfs
6
+ # @attr_reader [String] path The file's path.
7
+ # @attr_reader [Ipfs::Multihash] multihash The file's multihash as returned by Ipfs.
8
+ # @attr_reader [Integer] size The file's size in bytes as returned by Ipfs.
9
+ # @attr_reader [String] name The file's name as returned by Ipfs.
10
+ class File
11
+ attr_reader :path, :multihash, :size, :name
12
+
13
+ # Create an Ipfs file object, either from a Multihash or from a filepath
14
+ # allowing a file to be added to and be retrieved from Ipfs.
15
+ #
16
+ # @example given a filepath
17
+ # Ipfs::File.new(path: 'path/to/file')
18
+ # #=> #<Ipfs::File @path="path/to/file", @added=false>
19
+ # @example given a multihash
20
+ # Ipfs::File.new(multihash: 'QmVfpW2rKzzahcxt5LfYyNnnKvo1L7XyRF8Ykmhttcyztv')
21
+ # #=> #<Ipfs::File @added=false, @multihash=#<Ipfs::Multihash ....>>
22
+ #
23
+ # @param attributes [Hash{Symbol => String}]
24
+ #
25
+ # @return [Ipfs::File]
26
+ #
27
+ # @raise [Error::InvalidMultihash, Errno::ENOENT] Whether the path leads to
28
+ # a non-file entity or the multihash may be invalid,
29
+ # an error is thrown.
30
+ def initialize(**attributes)
31
+ attributes.each { |name, value|
32
+ instance_variable_set("@#{name}".to_sym, send("init_#{name}", value))
33
+ }
34
+
35
+ @added = false
36
+ end
37
+
38
+ # Add a file to the Ipfs' node.
39
+ #
40
+ # @note the call to Ipfs completes data about the added file.
41
+ # See {#multihash}, {#size} and {#name}.
42
+ #
43
+ # An {#Ipfs::File} instantiated from a multihash will not be added to Ipfs
44
+ # (as the presence of the multihash already suppose its addition to a node).
45
+ # In such case, the object is still returned but no call to Ipfs occurs.
46
+ #
47
+ # @example file not being added to Ipfs
48
+ # file = Ipfs::File.new(path: 'path/to/file')
49
+ # file.cat
50
+ # #=> ''
51
+ # file.multihash
52
+ # #=> nil
53
+ # file.name
54
+ # #=> nil
55
+ # file.size
56
+ # #=> nil
57
+ # @example file being added
58
+ # file = Ipfs::File.new(path: 'path/to/file').add
59
+ # file.cat
60
+ # #=> 'file content'
61
+ # file.multihash
62
+ # #=> #<Ipfs::Multihash ...>
63
+ # file.name
64
+ # #=> 'file'
65
+ # file.size
66
+ # #=> 20
67
+ #
68
+ # @return [Ipfs::File] Returns the object on which the method was call.
69
+ def add
70
+ tap {
71
+ Ipfs::Client.execute(Command::Add, @path).tap { |response|
72
+ @added = true
73
+
74
+ @multihash = init_multihash(response['Hash'])
75
+ @size = response['Size'].to_i
76
+ @name = response['Name']
77
+ } if !@added
78
+ }
79
+ end
80
+
81
+ # Use the {#multihash} to get the content of a file from Ipfs and returns it.
82
+ #
83
+ # @note the file must be added first or have a multihash. See {#add} and {#multihash}.
84
+ #
85
+ # @example
86
+ # Ipfs::File.new(path: 'path/to/file').add.cat
87
+ # #=> 'file content'
88
+ #
89
+ # @return [String] The content is returned.
90
+ def cat
91
+ begin
92
+ Ipfs::Client.execute(Command::Cat, @multihash).to_s if @multihash
93
+ rescue Ipfs::Error::InvalidDagStream
94
+ ''
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ def init_multihash(multihash)
101
+ multihash.is_a?(Multihash) ? multihash : Multihash.new(multihash)
102
+ end
103
+
104
+ def init_path(path)
105
+ if ::File.file? path
106
+ path
107
+ else
108
+ raise Errno::ENOENT, 'no such file or directory'
109
+ end
110
+ end
111
+ end
112
+ end
data/lib/ipfs_api.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require_relative './client'
2
+ require_relative './file'
2
3
 
3
4
  module Ipfs
4
- class Client
5
- VERSION = '0.5.0'
6
- end
7
- end
5
+ VERSION = '0.5.1'
6
+ end
data/lib/multihash.rb CHANGED
@@ -11,6 +11,10 @@ module Ipfs
11
11
 
12
12
  def initialize(multihash)
13
13
  @base58_encoded = multihash
14
+
15
+ raise Error::InvalidMultihash,
16
+ "The hash '#{@base58_encoded}' is invalid." unless @base58_encoded.is_a?(String)
17
+
14
18
  @bytes_encoded = to_bytes
15
19
 
16
20
  @function = find_hash_function(@bytes_encoded[0])
@@ -10,7 +10,7 @@ module Ipfs
10
10
 
11
11
  def options
12
12
  @multihash \
13
- ? { params: { arg: @multihash.raw } }
13
+ ? { params: { arg: @multihash.raw } } \
14
14
  : {}
15
15
  end
16
16
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-ipfs-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Benett
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-12-01 00:00:00.000000000 Z
12
+ date: 2019-02-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: http
@@ -39,15 +39,19 @@ files:
39
39
  - lib/api/generic/version.rb
40
40
  - lib/base.rb
41
41
  - lib/client.rb
42
+ - lib/connection/base.rb
43
+ - lib/connection/default.rb
44
+ - lib/connection/ipfs_config.rb
45
+ - lib/connection/unreachable.rb
42
46
  - lib/dagstream.rb
43
47
  - lib/errors.rb
44
- - lib/http_api.rb
48
+ - lib/file.rb
45
49
  - lib/ipfs_api.rb
46
50
  - lib/multihash.rb
47
51
  - lib/request/basic_request.rb
48
52
  - lib/request/file_upload_request.rb
49
53
  - lib/request/request.rb
50
- homepage: https://github.com/mahloun/ruby-ipfs-api
54
+ homepage: https://github.com/tbenett/ruby-ipfs-api
51
55
  licenses:
52
56
  - MIT
53
57
  metadata: {}
data/lib/http_api.rb DELETED
@@ -1,36 +0,0 @@
1
- require 'http'
2
- require 'uri'
3
-
4
- module Ipfs
5
- class HttpApi
6
- attr_reader :host, :port, :base_path
7
-
8
- DEFAULT_HOST = 'localhost'
9
- DEFAULT_PORT = 5001
10
- DEFAULT_BASE_PATH = '/api/v0'
11
-
12
- def initialize(**api_server)
13
- @host = api_server[:host] || DEFAULT_HOST
14
- @port = api_server[:port] || DEFAULT_PORT
15
- @base_path = api_server[:base_path] || DEFAULT_BASE_PATH
16
- end
17
-
18
- def call(command)
19
- HTTP.request(
20
- command.verb,
21
- url(command.path),
22
- command.options
23
- )
24
- end
25
-
26
- private
27
-
28
- def url(command_path)
29
- URI::HTTP.build(
30
- host: @host,
31
- port: @port,
32
- path: @base_path + command_path
33
- )
34
- end
35
- end
36
- end