urbit-api 0.1.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/.ruby-version +2 -1
- data/README.md +191 -32
- data/bin/console +6 -3
- data/lib/urbit/ack_message.rb +14 -9
- data/lib/urbit/api/version.rb +1 -1
- data/lib/urbit/channel.rb +33 -22
- data/lib/urbit/chat_channel.rb +22 -0
- data/lib/urbit/close_message.rb +15 -0
- data/lib/urbit/fact.rb +206 -0
- data/lib/urbit/graph.rb +143 -0
- data/lib/urbit/message.rb +18 -24
- data/lib/urbit/node.rb +152 -0
- data/lib/urbit/parser.rb +62 -0
- data/lib/urbit/poke_message.rb +7 -0
- data/lib/urbit/receiver.rb +30 -10
- data/lib/urbit/setting.rb +30 -0
- data/lib/urbit/ship.rb +170 -15
- data/lib/urbit/subscribe_message.rb +8 -9
- data/misc/graph-store_graph +51 -0
- data/misc/graph-store_keys +15 -0
- data/misc/graph-store_node +34 -0
- data/misc/graph-store_update +76 -0
- data/misc/graph-update_add-graph +20 -0
- data/misc/graph-update_add-nodes +75 -0
- data/misc/post +12 -0
- data/misc/settings-store.json +52 -0
- data/urbit-api.gemspec +1 -3
- metadata +20 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cef1b4e2c8a8a7ef8ba203f66e92e516e563c7b32119e98ee55366983e72dd3
|
4
|
+
data.tar.gz: dc6267d7c21e034c6725309a15678b09b4e0d8713990b5e975c94ef25475caed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b19087253b1b6864e0941b94513f530aee01856357d590468e670273412a273a8ad4e514bc21c21ea86bc24877e4cc72b9ce475cbf218c2f53efafd462e2cb7
|
7
|
+
data.tar.gz: 1443c08a0370fd78bf33dca3c701aba09669421d434b10a475544a0828fe1eaae3ac1a222aa963654e29e800b3f7ab019efd73bbd2d9dbb6b00f4c775f52e63c
|
data/.ruby-version
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
2.7.
|
1
|
+
2.7.4
|
2
|
+
|
data/README.md
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
# Urbit::Api
|
2
|
+
|
2
3
|
## The Ruby interface to the Urbit HTTP API
|
3
4
|
|
4
5
|
This library wraps the Urbit ship http interface exposing it as a Ruby gem.
|
5
6
|
|
7
|
+
[](https://github.com/urbit/awesome-urbit)
|
8
|
+
[](https://badge.fury.io/rb/urbit-api)
|
9
|
+
[](https://github.com/Zaxonomy/urbit-ruby/blob/master/LICENSE.txt)
|
10
|
+
|
6
11
|
## Installation
|
7
12
|
|
8
13
|
Add this line to your application's Gemfile:
|
@@ -21,39 +26,194 @@ Or install it yourself as:
|
|
21
26
|
|
22
27
|
## Usage
|
23
28
|
|
24
|
-
```
|
25
|
-
|
26
|
-
require 'urbit/urbit'
|
29
|
+
```sh
|
30
|
+
> bin/console
|
27
31
|
|
28
32
|
# This will instantiate a ship that connects to the fake `~zod` dev server by default
|
29
33
|
# See Urbit docs for more info: https://urbit.org/using/develop/
|
30
|
-
ship = Urbit.new
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
ship.
|
37
|
-
|
38
|
-
|
39
|
-
ship.
|
40
|
-
|
34
|
+
[1] pry(main)> ship = Urbit.new
|
35
|
+
=> #<Urbit::Ship:0x00007fa74b87f920 ...
|
36
|
+
|
37
|
+
OR... with config file...
|
38
|
+
> ship = Urbit.connect(config_file: '_config-barsyr-latreb.yml')
|
39
|
+
|
40
|
+
> ship.logged_in?
|
41
|
+
=> false
|
42
|
+
|
43
|
+
> ship.login
|
44
|
+
=> #<Urbit::Ship:0x00007fa74b87f920 ...
|
45
|
+
|
46
|
+
> ship.logged_in?
|
47
|
+
=> true
|
48
|
+
|
49
|
+
> ship.to_s
|
50
|
+
=> "a Ship(name: '~barsyr-latreb', host: 'http://localhost', port: '8080')"
|
51
|
+
|
52
|
+
> channel = ship.subscribe(app: 'graph-store', path: '/updates')
|
53
|
+
=> a Channel (Open) on ~barsyr-latreb(name: 'Channel-0', key: '1622836437b540b4')
|
54
|
+
|
55
|
+
# Subscribing works by opening a Channel. Your ships has a collection of all it's open Channels.
|
56
|
+
> channel = ship.open_channels.first
|
57
|
+
=> a Channel (Open) on ~barsyr-latreb(name: 'Channel-0', key: '1622836437b540b4')
|
58
|
+
|
59
|
+
# Notice that it's the same one.
|
60
|
+
|
61
|
+
# Every Channel has a unique key to identify it.
|
62
|
+
> channel.key
|
63
|
+
=> "16142890875c348d"
|
64
|
+
|
65
|
+
# The Channel has a Receiver that 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.
|
66
|
+
> channel.receiver.facts.count
|
67
|
+
=> 12
|
68
|
+
|
69
|
+
# Perform any action through landscape that would initiate an update into %graph-store...
|
70
|
+
# In this case I have added a comment to a local notebook.
|
71
|
+
> channel.receiver.facts.last
|
72
|
+
=> a Fact({:ship=>{:name=>"~barsyr-latreb", :host=>"http://localhost", :port=>"8080"}, :resource=>"~barsyr-latreb/test0-996", :acknowleged=>true, :is_graph_update=>true})
|
73
|
+
|
74
|
+
# Your ship keeps a collection of all the messages sent to urbit:
|
75
|
+
> channel.sent_messages.collect {|m| m.to_s}
|
76
|
+
=> [
|
77
|
+
"a Message({:action=>"poke", :app=>"hood", :id=>1, :json=>"Opening Airlock", :mark=>"helm-hi", :ship=>"barsyr-latreb"})",
|
78
|
+
"a Message({:action=>"subscribe", :app=>"graph-store", :id=>2, :path=>"/updates", :ship=>"barsyr-latreb"})",
|
79
|
+
"a Message({"id"=>3, "action"=>"ack", "event-id"=>"0"})",
|
80
|
+
"a Message({"id"=>4, "action"=>"ack", "event-id"=>"1"})",
|
81
|
+
"a Message({"id"=>5, "action"=>"ack", "event-id"=>"2"})"
|
82
|
+
]
|
83
|
+
|
84
|
+
#
|
85
|
+
# --------------------------------------------------------------------
|
86
|
+
# Poke
|
87
|
+
# --------------------------------------------------------------------
|
88
|
+
#
|
89
|
+
> ship.poke(app: 'hood', mark: 'helm-hi', message: 'Opening Airlock')
|
90
|
+
=> a Channel (Open) on ~barsyr-latreb(name: 'Channel-0', key: '1630355920a717e1')
|
91
|
+
|
92
|
+
#
|
93
|
+
# --------------------------------------------------------------------
|
94
|
+
# Scry
|
95
|
+
# --------------------------------------------------------------------
|
96
|
+
#
|
97
|
+
# Retrieving your ship's base hash using scry....
|
98
|
+
> ship.scry(app: 'file-server', path: '/clay/base/hash')
|
99
|
+
# => {:status=>200, :code=>"ok", :body=>"\"e75k5\""}
|
100
|
+
|
101
|
+
#
|
102
|
+
# --------------------------------------------------------------------
|
103
|
+
# Spider
|
104
|
+
# --------------------------------------------------------------------
|
105
|
+
#
|
106
|
+
# Creating a new Notebook in "My Channels" using %spider....
|
107
|
+
> create_json = %Q(
|
108
|
+
{"create": {"resource": { "ship": "~zod", "name": "random_name"},
|
109
|
+
"title": "Testing",
|
110
|
+
"description": "Testing Un-Managed Graph Creation",
|
111
|
+
"associated" : {"policy": {"invite": {"pending": []}}},
|
112
|
+
"module": "publish", "mark": "graph-validator-publish"}}
|
113
|
+
)
|
114
|
+
> ship.spider(mark_in: 'graph-view-action', mark_out: 'json', thread: 'graph-create', data: create_json)
|
115
|
+
# => {:status=>200, :code=>"ok", :body=>"\"e75k5\""}
|
116
|
+
|
117
|
+
#
|
118
|
+
# --------------------------------------------------------------------
|
119
|
+
# %graph-store
|
120
|
+
# --------------------------------------------------------------------
|
121
|
+
#
|
122
|
+
> puts ship.graph_names
|
123
|
+
~barsyr-latreb/dm-inbox
|
124
|
+
~darlur/announce
|
125
|
+
~bitbet-bolbel/urbit-community-5.963
|
126
|
+
~winter-paches/top-shelf-6391
|
127
|
+
~winter-paches/the-great-north-7.579
|
128
|
+
~barsyr-latreb/test0-996
|
129
|
+
~fabled-faster/test-chat-a-5919
|
130
|
+
~barsyr-latreb/test1-4287
|
131
|
+
~darrux-landes/welcome-to-urbit-community
|
132
|
+
~millyt-dorsen/finance-2.962
|
133
|
+
~fabled-faster/interface-testing-facility-683
|
134
|
+
~darlur/help-desk-4556
|
135
|
+
=>
|
136
|
+
|
137
|
+
# Reference a graph by name and return a single node.
|
138
|
+
> puts ship.graph(resource: '~winter-paches/top-shelf-6391').node(index: "170.141.184.505.207.751.870.046.689.877.378.990.080")
|
139
|
+
a Node({:index=>"170.141.184.505.207.751.870.046.689.877.378.990.080", :author=>"witfyl-ravped", :contents=>[{"text"=>"the patches don't really bother me though tbh"}], :time_sent=>1629316468195, :is_parent=>false, :child_count=>0})
|
140
|
+
=>
|
141
|
+
|
142
|
+
# You can also reference a graph by its index in the graphs collection.
|
143
|
+
> puts ship.graphs[3].node(index: "170.141.184.505.207.751.870.046.689.877.378.990.080")
|
144
|
+
a Node({:index=>"170.141.184.505.207.751.870.046.689.877.378.990.080", :author=>"witfyl-ravped", :contents=>[{"text"=>"the patches don't really bother me though tbh"}], :time_sent=>1629316468195, :is_parent=>false, :child_count=>0})
|
145
|
+
=>
|
146
|
+
|
147
|
+
# Return the contents of the 5 oldest nodes of a graph
|
148
|
+
> graph = ship.graph(resource: '~winter-paches/top-shelf-6391')
|
149
|
+
> graph.oldest_nodes(count: 5).sort.each {|n| p n.contents};nil
|
150
|
+
[{"text"=>"watching the 2020 stanley cup finals (tampa (sigh) just went up 2-0 in game 3) and i thought: \"the great north has to have a hockey chat, eh?\""}]
|
151
|
+
[{"text"=>"we'll see if this has legs. ;)"}]
|
152
|
+
[{"text"=>"shortie! now 2-1 tampa."}]
|
153
|
+
[{"text"=>"looks like tampa's going to go up 2-1. as a canadian this geographically depresses me. :/"}]
|
154
|
+
[{"text"=>"anyone in the stands?"}]
|
155
|
+
=>
|
156
|
+
|
157
|
+
# A single Node. In this case, the 3rd oldest node in the graph.
|
158
|
+
> puts graph.nodes[2].contents
|
159
|
+
{"text"=>"shortie! now 2-1 tampa."}
|
160
|
+
=>
|
161
|
+
|
162
|
+
# Getting the next newer Node. Remember that it always returns an Array, hence the '#first'.
|
163
|
+
> puts graph.nodes[2].next.first.contents
|
164
|
+
{"text"=>"looks like tampa's going to go up 2-1. as a canadian this geographically depresses me. :/"}
|
165
|
+
=>
|
166
|
+
|
167
|
+
# Return the indexes of the newest 5 nodes of a graph
|
168
|
+
> ship.graph(resource: '~winter-paches/top-shelf-6391').newest_nodes(count: 5).sort.each {|n| p n.index};nil
|
169
|
+
"170.141.184.505.209.257.330.601.508.862.548.770.816"
|
170
|
+
"170.141.184.505.209.375.247.350.471.711.992.578.048"
|
171
|
+
"170.141.184.505.209.545.972.004.310.065.795.301.376"
|
172
|
+
"170.141.184.505.209.627.337.970.761.265.544.429.568"
|
173
|
+
"170.141.184.505.209.644.102.846.398.558.514.446.336"
|
174
|
+
=>
|
175
|
+
|
176
|
+
# Fetching nodes older relative to another node. (See indexes above)
|
177
|
+
> puts (node = ship.graph(resource: '~winter-paches/top-shelf-6391').node(index: "170.141.184.505.209.644.102.846.398.558.514.446.336"))
|
178
|
+
a Node({:index=>"170.141.184.505.209.644.102.846.398.558.514.446.336", :author=>"winter-paches", :contents=>[{"text"=>"yep. that's how i did it as a kid. harry caray was the white sox announcer before he turned traitor and went to the cubs."}], :time_sent=>1629419046028, :is_parent=>false, :child_count=>0})
|
179
|
+
=>
|
180
|
+
|
181
|
+
> puts node.previous
|
182
|
+
a Node({:index=>"170.141.184.505.209.627.337.970.761.265.544.429.568", :author=>"pathus-hiddyn", :contents=>[{"text"=>"Lol oh man I haven’t listened to a baseball game on the radio in forever. It is great isn’t it. "}], :time_sent=>1629418137668, :is_parent=>false, :child_count=>0})
|
183
|
+
=>
|
184
|
+
|
185
|
+
> node.previous(count: 4).each {|n| p n.index};nil
|
186
|
+
"170.141.184.505.209.257.330.601.508.862.548.770.816"
|
187
|
+
"170.141.184.505.209.375.247.350.471.711.992.578.048"
|
188
|
+
"170.141.184.505.209.545.972.004.310.065.795.301.376"
|
189
|
+
"170.141.184.505.209.627.337.970.761.265.544.429.568"
|
190
|
+
|
191
|
+
#
|
192
|
+
# --------------------------------------------------------------------
|
193
|
+
# %settings-store
|
194
|
+
# --------------------------------------------------------------------
|
195
|
+
#
|
196
|
+
> ship.setting(desk: 'landscape', bucket: 'calm').each {|e| p e};nil
|
197
|
+
["hideUtilities", false]
|
198
|
+
["hideGroups", false]
|
199
|
+
["hideAvatars", true]
|
200
|
+
["hideUnreads", true]
|
201
|
+
["hideNicknames", true]
|
202
|
+
|
203
|
+
> ship.subscribe(app: 'settings-store', path: '/all')
|
204
|
+
=> a Channel (Open) on ~barsyr-latreb(name: 'Channel-0', key: '164375139513eacb')
|
205
|
+
|
206
|
+
# We are now listening for changes in any settings on the ship. Go to Landscape and toggle the "Hide Groups" button...
|
207
|
+
Received a Fact for [a Channel (Open) on ~barsyr-latreb(name: 'Channel-0', key: '164375139513eacb')] -- [message] -- [{"json":{"settings-event":{"put-entry":{"bucket-key":"calm","desk":"landscape","entry-key":"hideGroups","value":true}}},"id":1,"response":"diff"}]
|
208
|
+
|
209
|
+
> ship.setting(desk: 'landscape', bucket: 'calm').each {|e| p e};nil
|
210
|
+
["hideUtilities", false]
|
211
|
+
**["hideGroups", true]**
|
212
|
+
["hideAvatars", true]
|
213
|
+
["hideUnreads", true]
|
214
|
+
["hideNicknames", true]
|
41
215
|
|
42
|
-
channel = ship.open_channel('my-channel')
|
43
|
-
# => #<Urbit::Channel:0x00007fa74b291e50 ...
|
44
|
-
|
45
|
-
channel.key
|
46
|
-
# => "16142890875c348d"
|
47
|
-
|
48
|
-
ship.channels.first.key
|
49
|
-
# => "16142890875c348d"
|
50
|
-
|
51
|
-
receiver = channel.subscribe(app: 'graph-store', path: '/updates')
|
52
|
-
# => #<Urbit::Receiver:0x00007fd3928eba58
|
53
|
-
|
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
216
|
```
|
56
|
-
|
57
217
|
### Configuration
|
58
218
|
|
59
219
|
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.
|
@@ -83,11 +243,10 @@ ship = Urbit.new(host: '127.0.0.1', port: '8080')
|
|
83
243
|
```sh
|
84
244
|
bin/test
|
85
245
|
```
|
86
|
-
### ~zod
|
87
|
-
|
88
246
|
Tests assume that an instance of a ["fake" development Urbit ship](https://urbit.org/using/develop/) (one not connected to the live network) will be running, available at `http://localhost:8080`.
|
247
|
+
### "fake" ~zod
|
89
248
|
|
90
|
-
To create
|
249
|
+
To create this development ship:
|
91
250
|
```sh
|
92
251
|
./urbit -F zod
|
93
252
|
```
|
@@ -95,7 +254,7 @@ To create a development ship:
|
|
95
254
|
|
96
255
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
97
256
|
|
98
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
257
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
99
258
|
|
100
259
|
## Contributing
|
101
260
|
|
data/bin/console
CHANGED
@@ -4,8 +4,11 @@ require "bundler/setup"
|
|
4
4
|
require "pry"
|
5
5
|
require "urbit/urbit"
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
puts "Welcome! This is an interactive environment to explore your Urbit ship."
|
8
|
+
puts "You create a config file with connection details for your ship and off you go."
|
9
|
+
puts ""
|
10
10
|
puts "e.g., ship = Urbit.new(config_file: 'my_config.yml')"
|
11
|
+
puts "=> a Ship(name: '~barsyr-latreb', host: 'http://localhost', port: '8080')"
|
12
|
+
|
13
|
+
Pry.config.print = proc { |output, value| output.puts "=> #{value}" }
|
11
14
|
Pry.start
|
data/lib/urbit/ack_message.rb
CHANGED
@@ -1,18 +1,23 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
require 'urbit/message'
|
4
|
-
|
5
1
|
module Urbit
|
6
2
|
class AckMessage < Message
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
attr_reader :ack_id
|
4
|
+
|
5
|
+
def initialize(channel:, sse_message_id:)
|
6
|
+
super(channel: channel)
|
11
7
|
@ack_id = sse_message_id
|
12
8
|
end
|
13
9
|
|
10
|
+
def action
|
11
|
+
"ack"
|
12
|
+
end
|
13
|
+
|
14
14
|
def to_h
|
15
|
-
|
15
|
+
# Need to use the older hash style due to the key having a dash.
|
16
|
+
{'id' => self.id, 'action' => self.action, 'event-id' => self.ack_id}
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"an AckMessage(#{self.to_h})"
|
16
21
|
end
|
17
22
|
end
|
18
23
|
end
|
data/lib/urbit/api/version.rb
CHANGED
data/lib/urbit/channel.rb
CHANGED
@@ -1,52 +1,58 @@
|
|
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
|
9
10
|
class Channel
|
10
11
|
attr_accessor :messages
|
11
|
-
attr_reader :key, :name, :ship
|
12
|
+
attr_reader :key, :name, :receiver, :ship
|
12
13
|
|
13
|
-
def initialize(ship
|
14
|
+
def initialize(ship:, name:)
|
14
15
|
@ship = ship
|
15
16
|
@key = "#{Time.now.to_i}#{SecureRandom.hex(3)}"
|
16
17
|
@messages = []
|
17
18
|
@name = name
|
19
|
+
@receiver = nil
|
18
20
|
@is_open = false
|
19
|
-
@is_subscribed = false
|
20
21
|
end
|
21
22
|
|
22
23
|
def close
|
23
24
|
# puts "closing #{name}"
|
24
|
-
m = Urbit::CloseMessage.new(self)
|
25
|
-
@is_open = !self.
|
25
|
+
m = Urbit::CloseMessage.new(channel: self)
|
26
|
+
@is_open = !self.send(message: m)
|
26
27
|
end
|
27
28
|
|
28
29
|
def closed?
|
29
30
|
!@is_open
|
30
31
|
end
|
31
32
|
|
32
|
-
def open(a_message_string)
|
33
|
-
m = Urbit::Message.new(self, "poke", "hood", "helm-hi", a_message_string)
|
34
|
-
@is_open = self.send_message(m)
|
35
|
-
end
|
36
|
-
|
37
33
|
def open?
|
38
34
|
@is_open
|
39
35
|
end
|
40
36
|
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
#
|
38
|
+
# One way to open a channel by "poking" an urbit app with a mark and a (json) message.
|
39
|
+
# A typical example of this is poking the 'hood' app using the mark 'helm-hi' to start a DM chat.
|
40
|
+
#
|
41
|
+
def poke(app:, mark:, message:)
|
42
|
+
@is_open = self.send(message: (Urbit::PokeMessage.new(channel: self, app: app, mark: mark, a_string: message)))
|
43
|
+
@receiver = Urbit::Receiver.new(channel: self)
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def queue(message:)
|
48
|
+
message.id = self.sent_messages.size + 1
|
49
|
+
@messages << message
|
44
50
|
end
|
45
51
|
|
46
52
|
# Answers true if message was successfully sent.
|
47
|
-
def
|
48
|
-
self.
|
49
|
-
resp =
|
53
|
+
def send(message:)
|
54
|
+
self.queue(message: message)
|
55
|
+
resp = message.transmit
|
50
56
|
resp.reason_phrase == "ok"
|
51
57
|
end
|
52
58
|
|
@@ -58,14 +64,19 @@ module Urbit
|
|
58
64
|
self.open? ? "Open" : "Closed"
|
59
65
|
end
|
60
66
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
67
|
+
#
|
68
|
+
# Subscribe to an app at a path.
|
69
|
+
# Returns a Receiver which will begin to get back a stream of facts... which is a... Dictionary? Encyclopedia?
|
70
|
+
#
|
71
|
+
def subscribe(app:, path:)
|
72
|
+
m = Urbit::SubscribeMessage.new(channel: self, app: app, path: path)
|
73
|
+
@is_open = self.send(message: m)
|
74
|
+
@receiver = Urbit::Receiver.new(channel: self)
|
75
|
+
self
|
65
76
|
end
|
66
77
|
|
67
78
|
def subscribed?
|
68
|
-
@
|
79
|
+
@is_open
|
69
80
|
end
|
70
81
|
|
71
82
|
def to_s
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
require 'urbit/message'
|
4
|
+
require 'urbit/receiver'
|
5
|
+
require 'urbit/close_message'
|
6
|
+
require 'urbit/poke_message'
|
7
|
+
require 'urbit/subscribe_message'
|
8
|
+
|
9
|
+
module Urbit
|
10
|
+
class ChatChannel < Channel
|
11
|
+
# def messages
|
12
|
+
# self.fetch_all_nodes if @nodes.empty?
|
13
|
+
# @nodes
|
14
|
+
# end
|
15
|
+
|
16
|
+
# def newest_messages(count = 100)
|
17
|
+
# self.fetch_newest_nodes(count) if @nodes.empty?
|
18
|
+
# self.nodes
|
19
|
+
# end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/lib/urbit/fact.rb
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'urbit/graph'
|
2
|
+
require 'urbit/node'
|
3
|
+
require 'urbit/parser'
|
4
|
+
|
5
|
+
module Urbit
|
6
|
+
class Fact
|
7
|
+
attr_reader :ack
|
8
|
+
|
9
|
+
def initialize(channel:, event:)
|
10
|
+
@channel = channel
|
11
|
+
@data = event.data
|
12
|
+
@type = event.type
|
13
|
+
puts "Received a Fact for [#{channel}] -- [#{@type}] -- [#{@data}]"
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# This is a Facotry method to make the proper Fact subclass from
|
18
|
+
# a Channel Event.
|
19
|
+
#
|
20
|
+
def self.collect(channel:, event:)
|
21
|
+
contents = JSON.parse(event.data)
|
22
|
+
return Fact.new(channel: channel, event: event) if contents["json"].nil?
|
23
|
+
return SettingsEventFact.new(channel: channel, event: event) if contents["json"]["settings-event"]
|
24
|
+
|
25
|
+
return Fact.new(channel: channel, event: event) if contents["json"]["graph-update"].nil?
|
26
|
+
return AddGraphFact.new(channel: channel, event: event) if contents["json"]["graph-update"]["add-graph"]
|
27
|
+
return AddNodesFact.new(channel: channel, event: event) if contents["json"]["graph-update"]["add-nodes"]
|
28
|
+
return RemoveGraphFact.new(channel: channel, event: event) if contents["json"]["graph-update"]["remove-graph"]
|
29
|
+
|
30
|
+
return Fact.new(channel: channel, event: event)
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_ack(ack:)
|
34
|
+
@ack = :ack
|
35
|
+
end
|
36
|
+
|
37
|
+
def contents
|
38
|
+
JSON.parse(@data)
|
39
|
+
end
|
40
|
+
|
41
|
+
def for_this_ship?
|
42
|
+
self.ship == @channel.ship
|
43
|
+
end
|
44
|
+
|
45
|
+
def graph_update?
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
def is_acknowledged?
|
50
|
+
!@ack.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
def raw_json
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def ship
|
58
|
+
@channel.ship
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_h
|
62
|
+
{
|
63
|
+
ship: self.ship.to_h,
|
64
|
+
acknowleged: self.is_acknowledged?,
|
65
|
+
is_graph_update: self.graph_update?
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_s
|
70
|
+
"a #{self.class.name}(#{self.to_h})"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class GraphUpdateFact < Fact
|
75
|
+
def initialize(channel:, event:)
|
76
|
+
super channel: channel, event: event
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Attach this new fact as a node to its Graph.
|
81
|
+
#
|
82
|
+
def attach_parser
|
83
|
+
# puts "Received a graph update for [#{self.ship.graph(resource: self.resource)}]"
|
84
|
+
if self.incoming_graph
|
85
|
+
# puts "Received an add_graph event: #{self.raw_json} on #{self.resource}"
|
86
|
+
self.create_parser
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def create_parser
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def graph_update?
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
def incoming_graph
|
99
|
+
self.ship.graph(resource: self.resource)
|
100
|
+
end
|
101
|
+
|
102
|
+
def resource
|
103
|
+
return "~#{self.resource_h["ship"]}/#{self.resource_h["name"]}" unless self.resource_h.nil?
|
104
|
+
end
|
105
|
+
|
106
|
+
def resource_h
|
107
|
+
self.raw_json["resource"]
|
108
|
+
end
|
109
|
+
|
110
|
+
def root_h
|
111
|
+
self.contents["json"]["graph-update"]
|
112
|
+
end
|
113
|
+
|
114
|
+
def to_h
|
115
|
+
super.merge!(resource: self.resource)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class AddGraphFact < GraphUpdateFact
|
120
|
+
def initialize(channel:, event:)
|
121
|
+
super channel: channel, event: event
|
122
|
+
end
|
123
|
+
|
124
|
+
def create_parser
|
125
|
+
Urbit::AddGraphParser.new(for_graph: incoming_graph, with_json: self.raw_json).add_nodes
|
126
|
+
end
|
127
|
+
|
128
|
+
def raw_json
|
129
|
+
self.root_h["add-graph"]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class AddNodesFact < GraphUpdateFact
|
134
|
+
def initialize(channel:, event:)
|
135
|
+
super channel: channel, event: event
|
136
|
+
end
|
137
|
+
|
138
|
+
def create_parser
|
139
|
+
Urbit::AddNodesParser.new(for_graph: incoming_graph, with_json: self.raw_json).add_nodes
|
140
|
+
end
|
141
|
+
|
142
|
+
def raw_json
|
143
|
+
self.root_h["add-nodes"]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class RemoveGraphFact < GraphUpdateFact
|
148
|
+
def initialize(channel:, event:)
|
149
|
+
super channel: channel, event: event
|
150
|
+
end
|
151
|
+
|
152
|
+
def create_parser
|
153
|
+
Urbit::RemoveGraphParser.new(for_graph: incoming_graph, with_json: self.raw_json)
|
154
|
+
end
|
155
|
+
|
156
|
+
def raw_json
|
157
|
+
self.root_h["remove-graph"]
|
158
|
+
end
|
159
|
+
|
160
|
+
def resource_h
|
161
|
+
self.raw_json
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
class SettingsEventFact < Fact
|
166
|
+
def initialize(channel:, event:)
|
167
|
+
super channel: channel, event: event
|
168
|
+
|
169
|
+
if self.for_this_ship?
|
170
|
+
# See if we already have this setting, if no add it, if yes update it.
|
171
|
+
if (entries = channel.ship.setting(bucket: self.bucket))
|
172
|
+
entries[self.entry] = self.value
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def bucket
|
178
|
+
self.contents["bucket-key"]
|
179
|
+
end
|
180
|
+
|
181
|
+
def contents
|
182
|
+
JSON.parse(@data)["json"]["settings-event"]["put-entry"]
|
183
|
+
end
|
184
|
+
|
185
|
+
def desk
|
186
|
+
self.contents["desk"]
|
187
|
+
end
|
188
|
+
|
189
|
+
def entry
|
190
|
+
self.contents["entry-key"]
|
191
|
+
end
|
192
|
+
|
193
|
+
def to_h
|
194
|
+
super.merge!({
|
195
|
+
bucket: self.bucket,
|
196
|
+
desk: self.desk,
|
197
|
+
entry: self.entry,
|
198
|
+
value: self.value
|
199
|
+
})
|
200
|
+
end
|
201
|
+
|
202
|
+
def value
|
203
|
+
self.contents["value"]
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|