urbit-api 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 626e3718491acdc2cd451fc847e489bac5bb4eb1490797bf6417fb9352c8b17b
4
- data.tar.gz: a744f2e30e52b901d1e681bdb8a2109f48facd9bcdc45cfc9148a11a0f32d059
3
+ metadata.gz: 8ffd645b7c5236244e5c081587835863586b11d035d3197e7e286fa223bc3c0f
4
+ data.tar.gz: 19e8360fbdf96a1149a99dc7218bd835ac3af5338f5ff0b0cfc0c907ea383f27
5
5
  SHA512:
6
- metadata.gz: 31738b651665457fb50113b26e6f3fe319473bc8112c01ba9fedc58f27c474a62a40a1619ee0c1c765dbf70582f61c54885521a3b53c91bcd30b963ff6ca0d5b
7
- data.tar.gz: 36f2bcab1490c8dfe2b83cd875dba0d9571f53f65e7760d0cdfd38ccd8b5eb21753cf039cda46d11cff9f493d9cf4d818397ec36a8b66ea334e79459f8cf3d1c
6
+ metadata.gz: 84a0d8b5144e08a43080f3d4b0caaecba73e9fd5a74f2d5f1c04f66f1577dc64ebdf44e2fb91716c2ce746b4c96062e0615a24c5a54d760fd1a0ae9ec8b9af36
7
+ data.tar.gz: 41e5ffab8a9b67bce7c1373ee932ab17834e5684da3de41bb6bc19fa44b115e0fea4472e78e672b4ddd7c74c4e970ba0a20cf9123f27db1d5b763d67ca1f2185
data/README.md CHANGED
@@ -3,6 +3,8 @@
3
3
 
4
4
  This library wraps the Urbit ship http interface exposing it as a Ruby gem.
5
5
 
6
+ [![awesome urbit badge](https://img.shields.io/badge/~-awesome%20urbit-lightgrey)](https://github.com/urbit/awesome-urbit)
7
+
6
8
  ## Installation
7
9
 
8
10
  Add this line to your application's Gemfile:
@@ -21,39 +23,107 @@ Or install it yourself as:
21
23
 
22
24
  ## Usage
23
25
 
24
- ```rb
25
- # TODO: fix namespacing :)
26
- require 'urbit/urbit'
26
+ ```sh
27
+ > bin/console
27
28
 
28
29
  # This will instantiate a ship that connects to the fake `~zod` dev server by default
29
30
  # See Urbit docs for more info: https://urbit.org/using/develop/
30
- ship = Urbit.new
31
+ [1] pry(main)> ship = Urbit.new
31
32
  # => #<Urbit::Ship:0x00007fa74b87f920 ...
32
33
 
33
- ship.logged_in?
34
+ OR... with config file...
35
+ > ship = Urbit.connect(config_file: '_config-barsyr-latreb.yml')
36
+
37
+ > ship.logged_in?
34
38
  # => false
35
39
 
36
- ship.login
40
+ > ship.login
37
41
  # => #<Urbit::Ship:0x00007fa74b87f920 ...
38
42
 
39
- ship.logged_in?
43
+ > ship.logged_in?
40
44
  # => true
41
45
 
42
- channel = ship.open_channel('my-channel')
43
- # => #<Urbit::Channel:0x00007fa74b291e50 ...
46
+ > ship.to_s
47
+ # => "a Ship(name: '~barsyr-latreb', host: 'http://localhost', port: '8080')"
44
48
 
45
- channel.key
46
- # => "16142890875c348d"
49
+ > receiver = ship.subscribe('graph-store', '/updates')
50
+ # => #<Urbit::Receiver:0x00007fd3928eba58
51
+
52
+ # Subscribing works by opening a Channel. Your ships has a collection of all it's open Channels.
53
+ > channel = ship.open_channels.first
54
+ # => #<Urbit::Channel:0x00007fa74b291e50 ...
47
55
 
48
- ship.channels.first.key
56
+ # Every Channel has a unique key to identify it.
57
+ > channel.key
49
58
  # => "16142890875c348d"
50
59
 
51
- receiver = channel.subscribe(app: 'graph-store', path: '/updates')
52
- # => #<Urbit::Receiver:0x00007fd3928eba58
60
+ # The receiver will now be listening on the app and path you specified. Each time an event is sent in it will be stored in the receiver's facts collection.
61
+ > receiver.facts.count
62
+ => 12
63
+
64
+ > receiver.facts.last
65
+ => {:message=>
66
+ {"json"=>
67
+ {"graph-update"=>
68
+ {"add-nodes"=>
69
+ {"resource"=>{"name"=>"test0-996", "ship"=>"barsyr-latreb"},
70
+ "nodes"=>
71
+ {"/170141184504954066298369929365830487769"=>
72
+ {"post"=>
73
+ {"index"=>"/170141184504954066298369929365830487769",
74
+ "author"=>"barsyr-latreb",
75
+ "time-sent"=>1615564146267,
76
+ "signatures"=>[],
77
+ "contents"=>[],
78
+ "hash"=>"0x92b0.c976.58f0.3035.c126.64a0.3043.b962"},
79
+ "children"=>
80
+ {"2"=>
81
+ {"post"=>
82
+ {"index"=>"/170141184504954066298369929365830487769/2",
83
+ "author"=>"barsyr-latreb",
84
+ "time-sent"=>1615564146267,
85
+ "signatures"=>[],
86
+ "contents"=>[],
87
+ "hash"=>"0x2ffe.3ca7.20eb.11af.51f8.fbab.2b88.9f48"},
88
+ "children"=>nil},
89
+ "1"=>
90
+ {"post"=>
91
+ {"index"=>"/170141184504954066298369929365830487769/1",
92
+ "author"=>"barsyr-latreb",
93
+ "time-sent"=>1615564146267,
94
+ "signatures"=>[],
95
+ "contents"=>[],
96
+ "hash"=>"0x2ffe.3ca7.20eb.11af.51f8.fbab.2b88.9f48"},
97
+ "children"=>
98
+ {"1"=>
99
+ {"post"=>
100
+ {"index"=>"/170141184504954066298369929365830487769/1/1",
101
+ "author"=>"barsyr-latreb",
102
+ "time-sent"=>1615564146267,
103
+ "signatures"=>[],
104
+ "contents"=>[{"text"=>"Test 0.8"}, {"text"=>"Test 0.8"}],
105
+ "hash"=>"0x9516.25fc.ca7a.5bb9.356b.2fce.b29a.f372"},
106
+ "children"=>nil}}}}}}}}},
107
+ "id"=>2,
108
+ "response"=>"diff"
109
+ }
110
+ }
111
+
112
+ # Your ship keeps a collection of all the messages sent to urbit:
113
+ > channel.sent_messages.collect {|m| m.to_s}
114
+ => [
115
+ "a Message({:action=>"poke", :app=>"hood", :id=>1, :json=>"Opening Airlock", :mark=>"helm-hi", :ship=>"barsyr-latreb"})",
116
+ "a Message({:action=>"subscribe", :app=>"graph-store", :id=>2, :path=>"/updates", :ship=>"barsyr-latreb"})",
117
+ "a Message({"id"=>3, "action"=>"ack", "event-id"=>"0"})",
118
+ "a Message({"id"=>4, "action"=>"ack", "event-id"=>"1"})",
119
+ "a Message({"id"=>5, "action"=>"ack", "event-id"=>"2"})"
120
+ ]
121
+
122
+ # Retrieving your ship's base hash using scry....
123
+ > ship.scry('file-server', '/clay/base/hash', 'json')
124
+ # => {:status=>200, :code=>"ok", :body=>"\"e75k5\""}
53
125
 
54
- # This receiver will now be listening on the app and path you specified. Each time an event is sent in it will be stored in the receiver's events collection.
55
126
  ```
56
-
57
127
  ### Configuration
58
128
 
59
129
  Configure your ship using a config file or constructor keyword arguments. Either or both can be used; the keyword args will override any values set via config file.
@@ -1,18 +1,15 @@
1
- require 'json'
2
-
3
- require 'urbit/message'
4
-
5
1
  module Urbit
6
2
  class AckMessage < Message
3
+ attr_reader :ack_id
4
+
7
5
  def initialize(channel, sse_message_id)
8
- @action = 'ack'
9
- @channel = channel
10
- @id = 0
6
+ super(channel, 'ack')
11
7
  @ack_id = sse_message_id
12
8
  end
13
9
 
14
10
  def to_h
15
- {'id' => id, 'action' => action, 'event-id' => @ack_id}
11
+ # Need to use the older hash style due to the key having a dash.
12
+ {'id' => self.id, 'action' => self.action, 'event-id' => self.ack_id}
16
13
  end
17
14
  end
18
15
  end
@@ -1,5 +1,5 @@
1
1
  module Urbit
2
2
  module Api
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.2"
4
4
  end
5
5
  end
data/lib/urbit/channel.rb CHANGED
@@ -1,8 +1,9 @@
1
- require 'faraday'
2
1
  require 'securerandom'
3
2
 
4
3
  require 'urbit/message'
5
4
  require 'urbit/receiver'
5
+ require 'urbit/close_message'
6
+ require 'urbit/poke_message'
6
7
  require 'urbit/subscribe_message'
7
8
 
8
9
  module Urbit
@@ -29,8 +30,11 @@ module Urbit
29
30
  !@is_open
30
31
  end
31
32
 
33
+ #
34
+ # We open a channel by "poking" the urbit app 'hood' using the mark 'helm-hi'
35
+ #
32
36
  def open(a_message_string)
33
- m = Urbit::Message.new(self, "poke", "hood", "helm-hi", a_message_string)
37
+ m = Urbit::PokeMessage.new(self, "hood", "helm-hi", a_message_string)
34
38
  @is_open = self.send_message(m)
35
39
  end
36
40
 
@@ -58,6 +62,10 @@ module Urbit
58
62
  self.open? ? "Open" : "Closed"
59
63
  end
60
64
 
65
+ #
66
+ # Subscribe to an app at a path.
67
+ # Returns a Receiver which will begin to get back a stream of facts... which is a... Dictionary? Encyclopedia?
68
+ #
61
69
  def subscribe(app, path)
62
70
  m = Urbit::SubscribeMessage.new(self, app, path)
63
71
  @is_subscribed = self.send_message(m)
@@ -0,0 +1,11 @@
1
+ module Urbit
2
+ class CloseMessage < Message
3
+ def initialize(channel)
4
+ super(channel, 'delete')
5
+ end
6
+
7
+ def to_h
8
+ {id: self.id, action: self.action}
9
+ end
10
+ end
11
+ end
data/lib/urbit/message.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'faraday'
1
2
  require 'json'
2
3
 
3
4
  module Urbit
@@ -5,7 +6,7 @@ module Urbit
5
6
  attr_accessor :id
6
7
  attr_reader :action, :app, :channel, :json, :mark
7
8
 
8
- def initialize(channel, action, app, mark, json)
9
+ def initialize(channel, action, app = nil, mark = nil, json = nil)
9
10
  @action = action
10
11
  @app = app
11
12
  @channel = channel
@@ -57,16 +58,4 @@ module Urbit
57
58
  response
58
59
  end
59
60
  end
60
-
61
- class CloseMessage < Message
62
- def initialize(channel)
63
- @action = 'delete'
64
- @channel = channel
65
- @id = 0
66
- end
67
-
68
- def to_h
69
- {id: id, action: action}
70
- end
71
- end
72
61
  end
@@ -0,0 +1,7 @@
1
+ module Urbit
2
+ class PokeMessage < Message
3
+ def initialize(channel, app, mark, a_string)
4
+ super(channel, 'poke', app, mark, a_string)
5
+ end
6
+ end
7
+ end
@@ -4,21 +4,21 @@ require 'urbit/ack_message'
4
4
 
5
5
  module Urbit
6
6
  class Receiver < SSE::Client
7
- attr_accessor :events
7
+ attr_accessor :facts
8
8
 
9
9
  def initialize(channel)
10
- @events = []
10
+ @facts = []
11
11
  @headers = {'cookie' => channel.ship.cookie}
12
12
  super(channel.url, {headers: @headers}) do |rec|
13
13
  rec.on_event do |event|
14
14
  typ = event.type
15
15
  dat = JSON.parse(event.data)
16
- self.events << {typ => dat}
16
+ self.facts << {typ => dat}
17
17
  channel.send_message(AckMessage.new(channel, event.id))
18
18
  end
19
19
 
20
20
  rec.on_error do |error|
21
- self.events += ["I received an error: #{error.class}"]
21
+ self.facts += ["I received an error fact: #{error.class}"]
22
22
  end
23
23
  end
24
24
  end
data/lib/urbit/ship.rb CHANGED
@@ -48,31 +48,65 @@ module Urbit
48
48
  config.name
49
49
  end
50
50
 
51
- # Opening a channel always creates a new channel which will
52
- # remain open until this ship is disconnected at which point it
53
- # will be closed.
54
- def open_channel(a_name)
55
- login
56
- (c = Channel.new self, a_name).open("Opening Airlock")
57
- self.channels << c
58
- c
59
- end
60
-
61
51
  def open_channels
62
52
  @channels.select {|c| c.open?}
63
53
  end
64
54
 
55
+ def scry(app, path, mark)
56
+ self.login
57
+ scry_url = "#{self.config.api_base_url}/~/scry/#{app}#{path}.#{mark}"
58
+
59
+ response = Faraday.get(scry_url) do |req|
60
+ req.headers['Accept'] = 'application/json'
61
+ req.headers['Cookie'] = self.cookie
62
+ end
63
+
64
+ {status: response.status, code: response.reason_phrase, body: response.body}
65
+ end
66
+
67
+ def spider(mark_in, mark_out, thread, data)
68
+ self.login
69
+ url = "#{self.config.api_base_url}/spider/#{mark_in}/#{thread}/#{mark_out}.json"
70
+
71
+ response = Faraday.post(url) do |req|
72
+ req.headers['Accept'] = 'application/json'
73
+ req.headers['Cookie'] = self.cookie
74
+ req.body = data
75
+ end
76
+
77
+ {status: response.status, code: response.reason_phrase, body: response.body}
78
+ end
79
+
80
+ #
81
+ # Subscribe to an app at a path.
82
+ # Returns a Receiver which will begin to get back a stream of facts... which is a... Dictionary? Encyclopedia?
83
+ #
84
+ def subscribe(app, path)
85
+ self.login
86
+ (c = Channel.new self, self.make_channel_name).open("Creating a Subscription Channel.")
87
+ self.channels << c
88
+ c.subscribe(app, path)
89
+ end
90
+
65
91
  def to_s
66
92
  "a Ship(name: '#{self.pat_p}', host: '#{self.config.host}', port: '#{self.config.port}')"
67
93
  end
68
94
 
69
95
  private
70
96
 
97
+ def make_channel_name
98
+ "Channel-#{self.open_channels.count}"
99
+ end
100
+
71
101
  def ensure_connections_closed
72
102
  # Make sure all our created channels are closed by the GC
73
103
  ObjectSpace.define_finalizer( self, self.class.finalize(channels) )
74
104
  end
75
105
 
106
+ def login_url
107
+ "#{config.api_base_url}/~/login"
108
+ end
109
+
76
110
  def parse_cookie(resp)
77
111
  cookie = resp.headers['set-cookie']
78
112
  return unless cookie
@@ -80,9 +114,5 @@ module Urbit
80
114
  @auth_cookie, @path, @max_age = cookie.split(';')
81
115
  self.logged_in = true if @auth_cookie
82
116
  end
83
-
84
- def login_url
85
- "#{config.api_base_url}/~/login"
86
- end
87
117
  end
88
118
  end
@@ -1,19 +1,14 @@
1
- require 'json'
2
-
3
1
  module Urbit
4
2
  class SubscribeMessage < Message
5
3
  attr_reader :path
6
4
 
7
5
  def initialize(channel, app, path)
8
- @action = 'subscribe'
9
- @app = app
10
- @channel = channel
11
- @id = 0
12
- @path = path
6
+ super(channel, 'subscribe', app)
7
+ @path = path
13
8
  end
14
9
 
15
10
  def to_h
16
- {action: action, app: app, id: id, path: path, ship: ship.untilded_name}
11
+ {action: self.action, app: self.app, id: self.id, path: self.path, ship: self.ship.untilded_name}
17
12
  end
18
13
  end
19
14
  end
data/urbit-api.gemspec CHANGED
@@ -13,8 +13,6 @@ Gem::Specification.new do |spec|
13
13
 
14
14
  spec.required_ruby_version = Gem::Requirement.new(">= 2.7.2")
15
15
 
16
- # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
17
-
18
16
  spec.metadata["homepage_uri"] = spec.homepage
19
17
  spec.metadata["source_code_uri"] = "https://github.com/Zaxonomy/urbit-ruby"
20
18
  spec.metadata["changelog_uri"] = "https://github.com/Zaxonomy/urbit-ruby/CHANGELOG.md"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: urbit-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daryl Richter
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-26 00:00:00.000000000 Z
11
+ date: 2021-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -90,8 +90,10 @@ files:
90
90
  - lib/urbit/api.rb
91
91
  - lib/urbit/api/version.rb
92
92
  - lib/urbit/channel.rb
93
+ - lib/urbit/close_message.rb
93
94
  - lib/urbit/config.rb
94
95
  - lib/urbit/message.rb
96
+ - lib/urbit/poke_message.rb
95
97
  - lib/urbit/receiver.rb
96
98
  - lib/urbit/ship.rb
97
99
  - lib/urbit/subscribe_message.rb