urbit-api 0.2.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/urbit/graph.rb CHANGED
@@ -4,12 +4,13 @@ require 'urbit/parser'
4
4
 
5
5
  module Urbit
6
6
  class Graph
7
- attr_reader :host_ship_name, :name, :ship
7
+ attr_reader :host_ship_name, :name, :ship
8
8
 
9
9
  def initialize(ship:, graph_name:, host_ship_name:)
10
10
  @ship = ship
11
- @name = graph_name
11
+ @group = nil
12
12
  @host_ship_name = host_ship_name
13
+ @name = graph_name
13
14
  @nodes = SortedSet.new
14
15
  end
15
16
 
@@ -17,6 +18,28 @@ module Urbit
17
18
  @nodes << node unless node.deleted?
18
19
  end
19
20
 
21
+ def creator
22
+ self.fetch_link if @creator.nil?
23
+ @creator
24
+ end
25
+
26
+ def description
27
+ self.fetch_link if @description.nil?
28
+ @description
29
+ end
30
+
31
+ def group
32
+ if @group.nil?
33
+ @link = self.fetch_link
34
+ @group = @link.group unless @link.nil?
35
+ end
36
+ @group
37
+ end
38
+
39
+ def group=(a_group)
40
+ @group = a_group
41
+ end
42
+
20
43
  def host_ship
21
44
  "~#{@host_ship_name}"
22
45
  end
@@ -84,6 +107,16 @@ module Urbit
84
107
  self.fetch_sibling_nodes(node, :older, count)[0..(count - 1)]
85
108
  end
86
109
 
110
+ def title
111
+ self.fetch_link if @title.nil?
112
+ @title
113
+ end
114
+
115
+ def type
116
+ self.fetch_link if @type.nil?
117
+ @type
118
+ end
119
+
87
120
  #
88
121
  # the canonical printed representation of a Graph
89
122
  def to_s
@@ -98,6 +131,15 @@ module Urbit
98
131
  "add-graph")
99
132
  end
100
133
 
134
+ def fetch_link
135
+ @link = self.ship.links.find_graph(resource: self.resource)
136
+ @creator = @link.metadata['creator']
137
+ @description = @link.metadata['description']
138
+ @title = @link.metadata['title']
139
+ @type = @link.metadata['config']['graph']
140
+ @link
141
+ end
142
+
101
143
  def fetch_newest_nodes(count)
102
144
  self.fetch_nodes("#{self.graph_resource}/node/siblings/newest/kith/#{count}/",
103
145
  AddNodesParser,
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Urbit
4
+ class Group
5
+ attr_accessor :graphs, :manager, :members, :tags, :title
6
+ attr_reader :hidden, :path, :policy
7
+
8
+ def initialize(path:, members:, policy:, tags:, hidden:)
9
+ @graphs = Set.new
10
+ @hidden = hidden
11
+ @manager = nil
12
+ @members = Set.new(members)
13
+ @path = path
14
+ @policy = policy
15
+ @tags = self.parse_tags(tags)
16
+ end
17
+
18
+ def ==(another_group)
19
+ another_group.path == self.path
20
+ end
21
+
22
+ def <=>(another_group)
23
+ self.path <=> another_group.path
24
+ end
25
+
26
+ def creator
27
+ self.fetch_link if @creator.nil?
28
+ @creator
29
+ end
30
+
31
+ def description
32
+ self.fetch_link if @description.nil?
33
+ @description
34
+ end
35
+
36
+ #
37
+ # This is the action labeled as "Archive" in the Landscape UI.
38
+ # As of now, you can only do this to groups on your own ship.
39
+ #
40
+ def delete
41
+ if (self.host == self.manager.ship.name)
42
+ spdr = self.manager.spider('group-delete', %Q({"remove": {"ship": "#{self.host}", "name": "#{self.key}"}}))
43
+ self.manager.remove(self) if 200 == spdr[:status]
44
+ return spdr
45
+ end
46
+ {status: 400, code: 'bad_request', body: 'Can only delete Groups on your own ship.'}
47
+ end
48
+
49
+ def eql?(another_group)
50
+ another_group.path == self.path
51
+ end
52
+
53
+ def graphs
54
+ if @graphs.empty?
55
+ self.graph_links.each {|gl| @graphs << gl.graph}
56
+ end
57
+ @graphs
58
+ end
59
+
60
+ def host
61
+ self.path_tokens[0]
62
+ end
63
+
64
+ def invite(ship_names:, message:)
65
+ data = %Q({
66
+ "invite": {
67
+ "resource": {
68
+ "ship": "#{self.host}",
69
+ "name": "#{self.key}"
70
+ },
71
+ "ships": [
72
+ "#{ship_names.join(',')}"
73
+ ],
74
+ "description": "#{message}"
75
+ }
76
+ })
77
+ self.manager.spider('group-invite', data)
78
+ end
79
+
80
+ def key
81
+ self.path_tokens[1]
82
+ end
83
+
84
+ def leave
85
+ spdr = self.manager.spider('group-leave', %Q({"leave": {"ship": "#{self.host}", "name": "#{self.key}"}}))
86
+ self.manager.remove(self) if 200 == spdr[:status]
87
+ spdr
88
+ end
89
+
90
+ def path_tokens
91
+ self.path.split('/')
92
+ end
93
+
94
+ def pending_invites
95
+ if (i = @policy["invite"])
96
+ if (p = i["pending"])
97
+ return p.count
98
+ end
99
+ end
100
+ '?'
101
+ end
102
+
103
+ def picture
104
+ self.fetch_link if @picture.nil?
105
+ @picture
106
+ end
107
+
108
+ def title
109
+ self.fetch_link if @title.nil?
110
+ @title
111
+ end
112
+
113
+ def to_h
114
+ {
115
+ title: self.title,
116
+ description: self.description,
117
+ host: self.host,
118
+ key: self.key,
119
+ member_count: self.members.count,
120
+ pending_invites: self.pending_invites,
121
+ hidden: self.hidden
122
+ }
123
+ end
124
+
125
+ def to_list
126
+ self.title || "Untitled - #{self.path}"
127
+ end
128
+
129
+ def to_s
130
+ "a Group(#{self.to_h})"
131
+ end
132
+
133
+ private
134
+
135
+ def fetch_link
136
+ @group_link = self.manager.ship.links.find_group(path: self.path)
137
+ unless @group_link.nil?
138
+ @creator = @group_link.metadata['creator']
139
+ @description = @group_link.metadata['description']
140
+ @picture = @group_link.metadata['picture']
141
+ @title = @group_link.metadata['title']
142
+ end
143
+ end
144
+
145
+ def graph_links
146
+ self.group_link.graph_links
147
+ end
148
+
149
+ def group_link
150
+ if @group_link.nil?
151
+ self.fetch_link
152
+ end
153
+ @group_link
154
+ end
155
+
156
+ def parse_tags(tags)
157
+ h = {}
158
+ return h if tags.empty?
159
+ tags.each {|k, v| h[k] = Set.new(v)}
160
+ tags.replace(h)
161
+ end
162
+
163
+ end
164
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'urbit/parser'
4
+
5
+ module Urbit
6
+
7
+ class GroupParser < Parser
8
+ def resource
9
+ "~#{self.resource_hash["ship"]}/#{self.resource_hash["name"]}"
10
+ end
11
+
12
+ def resource_hash
13
+ @j["resource"]
14
+ end
15
+ end
16
+
17
+ class AddGroupParser < GroupParser
18
+ def group
19
+ Urbit::Group.new(path: self.resource,
20
+ members: [],
21
+ policy: @j["policy"],
22
+ tags: [],
23
+ hidden: @j["hidden"])
24
+ end
25
+ end
26
+
27
+ class ChangeTagParser < GroupParser
28
+ def ships
29
+ @j["ships"]
30
+ end
31
+
32
+ def tag
33
+ @j["tag"]["tag"]
34
+ end
35
+ end
36
+
37
+ class ChangeMemberParser < GroupParser
38
+ def ships
39
+ @j["ships"]
40
+ end
41
+ end
42
+
43
+ class InitialGroupParser < Parser
44
+ def groups
45
+ self.group_hashes.collect {|k, v| Group.new(path: k.sub('/ship/', ''),
46
+ members: v["members"],
47
+ policy: v["policy"],
48
+ tags: v["tags"],
49
+ hidden: v["hidden"])}
50
+ end
51
+
52
+ def group_hashes
53
+ @j
54
+ end
55
+ end
56
+
57
+ class InitialGroupGroupParser < GroupParser
58
+ def group
59
+ Urbit::Group.new(path: self.resource,
60
+ members: self.group_hash["members"],
61
+ policy: self.group_hash["policy"],
62
+ tags: self.group_hash["tags"],
63
+ hidden: self.group_hash["hidden"])
64
+ end
65
+
66
+ def group_hash
67
+ @j["group"]
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Urbit
4
+ class Groups < Set
5
+ attr_accessor :ship
6
+
7
+ def initialize(ship:)
8
+ @ship = ship
9
+ @hash = {}
10
+ end
11
+
12
+ def [](path: nil, title: nil)
13
+ if title.nil?
14
+ if (g = self.select {|g| g.path == path}.first)
15
+ g.manager = self
16
+ return g
17
+ end
18
+ else
19
+ if (g = self.select {|g| g.title == title}.first)
20
+ g.manager = self
21
+ return g
22
+ end
23
+ end
24
+ nil
25
+ end
26
+
27
+ #
28
+ # Adds a Group to this Manager's groups collection
29
+ #
30
+ def add(a_group)
31
+ a_group.manager = self
32
+ self << a_group
33
+ end
34
+
35
+ def add_members(group_path:, ships:)
36
+ if (group = self[path: group_path])
37
+ group.members += ships
38
+ end
39
+ end
40
+
41
+ def add_tag(group_path:, ships:, tag:)
42
+ if (group = self[path: group_path])
43
+ if (group.tags.include? tag)
44
+ group.tags[tag] += ships
45
+ end
46
+ end
47
+ end
48
+
49
+ def create(name:, title:, description:)
50
+ self.spider('group-create', %Q({"create": {"name": "#{name}", "title": "#{title}", "description": "#{description}", "policy": {"open": {"banRanks": [], "banned": []}}}}))
51
+ end
52
+
53
+ def empty?
54
+ self.empty?
55
+ end
56
+
57
+ def join(host:, name:, share_contact: false, auto_join: false)
58
+ data = {join: {resource: {ship: "#{host}", name: "#{name}"}, ship: "#{host}", shareContact: share_contact, app: "groups", autojoin: auto_join}}
59
+ self.ship.poke(app: 'group-view', mark: 'group-view-action', message: data)
60
+ nil
61
+ end
62
+
63
+ def list
64
+ self.map {|g| g.to_list}.join("\n")
65
+ end
66
+
67
+ def remove(group)
68
+ self.delete(group)
69
+ end
70
+
71
+ def remove_members(group_path:, ships:)
72
+ if (group = self[path: group_path])
73
+ group.members -= ships
74
+ end
75
+ end
76
+
77
+ def remove_tag(group_path:, ships:, tag:)
78
+ if (group = self[path: group_path])
79
+ if (group.tags.include? tag)
80
+ group.tags[tag] -= ships
81
+ end
82
+ end
83
+ end
84
+
85
+ def load
86
+ if self.ship.logged_in?
87
+ self.ship.subscribe(app: 'group-store', path: '/groups')
88
+ end
89
+ nil
90
+ end
91
+
92
+ def spider(thread, data)
93
+ self.ship.spider(mark_in: 'group-view-action', mark_out: 'json', thread: thread, data: data)
94
+ end
95
+
96
+ def to_s
97
+ self.sort.each {|g| puts g}
98
+ end
99
+ end
100
+ end
data/lib/urbit/link.rb ADDED
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Urbit
4
+ class Link
5
+ attr_reader :path, :data
6
+
7
+ def initialize(chain:, path:, data:)
8
+ @chain = chain
9
+ @graph = nil
10
+ @group = nil
11
+ @path = path
12
+ @data = data
13
+ end
14
+
15
+ def ==(another)
16
+ another.path == self.path
17
+ end
18
+
19
+ def <=>(another)
20
+ self.path <=> another.path
21
+ end
22
+
23
+ def eql?(another)
24
+ another.path == self.path
25
+ end
26
+
27
+ def graph
28
+ if @graph.nil?
29
+ @graph = self.ship.graph(resource: self.graph_resource)
30
+ end
31
+ @graph
32
+ end
33
+
34
+ def graph_links
35
+ @chain.find_graph_links_for_group(path: self.group_path)
36
+ end
37
+
38
+ def graph_resource
39
+ @data['resource'].sub('/ship/', '')
40
+ end
41
+
42
+ def group
43
+ if @group.nil?
44
+ @group = self.ship.groups[path: self.group_path]
45
+ end
46
+ @group
47
+ end
48
+
49
+ def group_path
50
+ @data['group'].sub('/ship/', '')
51
+ end
52
+
53
+ def metadata
54
+ @data['metadata']
55
+ end
56
+
57
+ def ship
58
+ @chain.ship
59
+ end
60
+
61
+ def to_list
62
+ @path
63
+ end
64
+
65
+ def type
66
+ @data['app-name']
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Urbit
4
+ class Links < Set
5
+ attr_reader :ship
6
+
7
+ def initialize
8
+ @hash = {}
9
+ @ship = nil
10
+ end
11
+
12
+ def [](path:)
13
+ self.select {|l| path == l.path}.first
14
+ end
15
+
16
+ def find_graph(resource:)
17
+ self.select{|l| l.type == 'graph' && resource == l.graph_resource}.first
18
+ end
19
+
20
+ def find_graph_links_for_group(path:)
21
+ self.select{|l| l.type == 'graph' && path == l.group_path}
22
+ end
23
+
24
+ def find_group(path:)
25
+ self.select{|l| l.type == 'groups' && path == l.group_path}.first
26
+ end
27
+
28
+ def list
29
+ self.sort.each {|l| puts l.to_list}
30
+ nil
31
+ end
32
+
33
+ def load(ship:)
34
+ ship.subscribe(app: 'metadata-store', path: '/all')
35
+ @ship = ship
36
+ nil
37
+ end
38
+ end
39
+ end
data/lib/urbit/message.rb CHANGED
@@ -22,11 +22,11 @@ module Urbit
22
22
  end
23
23
 
24
24
  def channel_url
25
- "#{self.ship.config.api_base_url}/~/channel/#{self.channel.key}"
25
+ "#{self.ship.url}/~/channel/#{self.channel.key}"
26
26
  end
27
27
 
28
28
  def request_body
29
- self.to_a.to_json
29
+ JSON.generate(self.to_a)
30
30
  end
31
31
 
32
32
  def ship
data/lib/urbit/parser.rb CHANGED
@@ -3,9 +3,15 @@ require 'urbit/node'
3
3
 
4
4
  module Urbit
5
5
  class Parser
6
+ def initialize(with_json:)
7
+ @j = with_json
8
+ end
9
+ end
10
+
11
+ class GraphParser < Parser
6
12
  def initialize(for_graph:, with_json:)
13
+ super(with_json: with_json)
7
14
  @g = for_graph
8
- @j = with_json
9
15
  end
10
16
 
11
17
  #
@@ -33,16 +39,30 @@ module Urbit
33
39
  end
34
40
  end
35
41
 
36
- class AddGraphParser < Parser
42
+ class AddGraphParser < GraphParser
37
43
  def nodes_hash
38
44
  @j["graph"]
39
45
  end
40
46
 
47
+ def resource_hash
48
+ @j["resource"]
49
+ end
41
50
  end
42
51
 
43
- class AddNodesParser < Parser
52
+ class AddNodesParser < GraphParser
44
53
  def nodes_hash
45
54
  @j["nodes"]
46
55
  end
47
56
  end
57
+
58
+ class RemoveGraphParser < GraphParser
59
+ def nodes_hash
60
+ nil
61
+ end
62
+
63
+ def resource_hash
64
+ @j["resource"]
65
+ end
66
+ end
67
+
48
68
  end
@@ -1,7 +1,7 @@
1
1
  module Urbit
2
2
  class PokeMessage < Message
3
- def initialize(channel:, app:, mark:, a_string:)
4
- super(channel: channel, app: app, mark: mark, contents: a_string)
3
+ def initialize(channel:, app:, mark:, a_message_hash:)
4
+ super(channel: channel, app: app, mark: mark, contents: a_message_hash)
5
5
  end
6
6
  end
7
7
  end
@@ -1,19 +1,19 @@
1
1
  require 'ld-eventsource'
2
+ require "logger"
2
3
 
3
4
  require 'urbit/ack_message'
4
5
  require 'urbit/fact'
5
6
 
6
7
  module Urbit
7
8
  class Receiver < SSE::Client
8
- attr_accessor :facts
9
+ attr_accessor :errors, :facts
9
10
 
10
11
  def initialize(channel:)
11
- @facts = []
12
- super(channel.url, {headers: self.headers(channel)}) do |rec|
12
+ super(channel.url, headers: self.headers(channel), logger: self.default_logger) do |rec|
13
13
  # We are now listening on a socket for SSE::Events. This block will be called for each one.
14
14
  rec.on_event do |event|
15
15
  # Wrap the returned event in a Fact.
16
- @facts << (f = Fact.new(channel: channel, event: event))
16
+ @facts << (f = Fact.collect(channel: channel, event: event))
17
17
 
18
18
  # We need to acknowlege each message or urbit will eventually disconnect us.
19
19
  # We record the ack with the Fact itself.
@@ -22,12 +22,22 @@ module Urbit
22
22
  end
23
23
 
24
24
  rec.on_error do |error|
25
- self.facts += ["I received an error fact: #{error.class}"]
25
+ self.errors << ["I received an error fact: #{error.class}"]
26
26
  end
27
27
  end
28
+
29
+ @errors = []
30
+ @facts = []
28
31
  @is_open = true
29
32
  end
30
33
 
34
+ def default_logger
35
+ log = ::Logger.new($stdout)
36
+ log.level = ::Logger::WARN
37
+ log.progname = 'ld-eventsource'
38
+ log
39
+ end
40
+
31
41
  def open?
32
42
  @is_open
33
43
  end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'urbit/bucket'
4
+
5
+ module Urbit
6
+ class Setting
7
+ attr_accessor :buckets
8
+ attr_reader :desk, :ship
9
+
10
+ def initialize(ship:, desk:, buckets:)
11
+ @ship = ship
12
+ @desk = desk
13
+ @buckets = Set.new
14
+ buckets.each {|k, v| @buckets << Bucket.new(setting: self, name: k, entries: v)}
15
+ end
16
+
17
+ def ==(another_group)
18
+ another_setting.desk == self.desk
19
+ end
20
+
21
+ def <=>(another_group)
22
+ self.desk <=> another_group.desk
23
+ end
24
+
25
+ def [](bucket:)
26
+ self.buckets.select {|b| bucket == b.name}.first
27
+ end
28
+
29
+ def add_bucket(name:, entries:)
30
+ msg = {
31
+ "put-bucket": {
32
+ "bucket-key": "#{name}",
33
+ "desk": "#{self.desk}",
34
+ "bucket": entries
35
+ }
36
+ }
37
+ self.ship.poke(app: 'settings-store', mark: 'settings-event', message: msg)
38
+ nil
39
+ end
40
+
41
+ def entries(bucket:)
42
+ self[bucket: bucket].entries
43
+ end
44
+
45
+ def remove_bucket(name:)
46
+ msg = {
47
+ "del-bucket": {
48
+ "bucket-key": "#{name}",
49
+ "desk": "#{self.desk}"
50
+ }
51
+ }
52
+ self.ship.poke(app: 'settings-store', mark: 'settings-event', message: msg)
53
+ nil
54
+ end
55
+
56
+ def to_h
57
+ {
58
+ desk: @desk,
59
+ buckets: self.buckets,
60
+ }
61
+ end
62
+
63
+ def to_s
64
+ "a Setting(#{self.to_h})"
65
+ end
66
+
67
+ def to_string
68
+ "desk: #{self.desk}\n buckets: #{self.buckets.collect {|b| b.to_string}}"
69
+ end
70
+ end
71
+ end