Class: Urbit::Ship

Inherits:
Object
  • Object
show all
Defined in:
lib/urbit/ship.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config: Config.new) ⇒ Ship

Returns a new instance of Ship.



15
16
17
18
19
20
21
22
23
24
# File 'lib/urbit/ship.rb', line 15

def initialize(config: Config.new)
  @auth_cookie = nil
  @channels    = []
  @config      = config
  @graphs      = []
  @groups      = Groups.new ship: self
  @links       = Links.new
  @settings    = nil                         # Use lazy initialization here
  @logged_in   = false
end

Instance Attribute Details

Returns the value of attribute auth_cookie.



13
14
15
# File 'lib/urbit/ship.rb', line 13

def auth_cookie
  @auth_cookie
end

#channelsObject (readonly)

Returns the value of attribute channels.



13
14
15
# File 'lib/urbit/ship.rb', line 13

def channels
  @channels
end

#configObject (readonly)

Returns the value of attribute config.



13
14
15
# File 'lib/urbit/ship.rb', line 13

def config
  @config
end

#logged_inObject

Returns the value of attribute logged_in.



12
13
14
# File 'lib/urbit/ship.rb', line 12

def logged_in
  @logged_in
end

Class Method Details

.finalize(channels) ⇒ Object



26
27
28
# File 'lib/urbit/ship.rb', line 26

def self.finalize(channels)
  proc { channels.each { |c| c.close } }
end

Instance Method Details



34
35
36
# File 'lib/urbit/ship.rb', line 34

def cookie
  auth_cookie
end

#graph(resource:) ⇒ Object



38
39
40
# File 'lib/urbit/ship.rb', line 38

def graph(resource:)
  self.graphs.find {|g| g.resource == resource}
end

#graph_namesObject

A helper method to just print out the descriptive names of all the ship’s graphs.



65
66
67
# File 'lib/urbit/ship.rb', line 65

def graph_names
  self.graphs.collect {|g| g.resource}
end

#graphs(flush_cache: true) ⇒ Object

Answers a collection of all the top-level graphs on this ship. This collection is cached and will need to be invalidated to discover new graphs.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/urbit/ship.rb', line 46

def graphs(flush_cache: true)
  @graphs = [] if flush_cache
  if @graphs.empty?
    if self.logged_in?
      r = self.scry(app: 'graph-store', path: '/keys')
      if r[:body]
        body = JSON.parse r[:body]
        body["graph-update"]["keys"].each do |k|
          @graphs << Graph.new(ship: self, graph_name: k["name"], host_ship_name: k["ship"])
        end
      end
    end
  end
  @graphs
end

#groupsObject

Answers the object managing the Groups on this ship. This object provides all the helper methods to list, join, leave, &c. a Group



73
74
75
# File 'lib/urbit/ship.rb', line 73

def groups
  @groups
end


77
78
79
# File 'lib/urbit/ship.rb', line 77

def links
  @links
end

#logged_in?Boolean

Returns:

  • (Boolean)


30
31
32
# File 'lib/urbit/ship.rb', line 30

def logged_in?
  logged_in
end

#loginObject



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/urbit/ship.rb', line 81

def 
  return self if logged_in?

  ensure_connections_closed
  response = Faraday.post(, "password=#{config.code}")
  parse_cookie(response)
  @groups.load

  # For now we will require a subscription to all metadata. it's the glue between %graphs and %groups.
  # A key issue that arose is that these are both async %subscribe calls and so there are sync issues
  #   if we try to directly link the groups and the graphs. Instead we need to just store the links
  #   and lazy-instatiate the metadata _if_ we have received it.
  @links.load ship: self

  self
end

#nameObject



98
99
100
# File 'lib/urbit/ship.rb', line 98

def name
  config.name
end

#open_channelsObject



102
103
104
# File 'lib/urbit/ship.rb', line 102

def open_channels
  @channels.select {|c| c.open?}
end

#pat_pObject



106
107
108
# File 'lib/urbit/ship.rb', line 106

def pat_p
  config.name
end

#poke(app:, mark:, message:) ⇒ Object

Poke an app with a message using a mark.

Returns a Channel which has been created and opened and will begin

to get back a stream of facts via its Receiver.


116
117
118
# File 'lib/urbit/ship.rb', line 116

def poke(app:, mark:, message:)
  (self.add_channel).poke(app: app, mark: mark, message: message)
end

#remove_graph(desk: 'landscape', graph:) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/urbit/ship.rb', line 120

def remove_graph(desk: 'landscape', graph:)
  delete_json = %Q({
    "delete": {
      "resource": {
        "ship": "#{self.name}",
        "name": "#{graph.name}"
      }
    }
  })

  spider = self.spider(desk: desk, mark_in: 'graph-view-action', mark_out: 'json', thread: 'graph-delete', data: delete_json, args: ["NO_RESPONSE"])
  if (retcode = (200 == spider[:status]))
    self.graphs.delete graph
  end
  retcode
end

#scry(app:, path:, mark: 'json') ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/urbit/ship.rb', line 137

def scry(app:, path:, mark: 'json')
  self.
  mark = ".#{mark}" unless mark.empty?
  scry_url = "#{self.url}/~/scry/#{app}#{path}#{mark}"

  response = Faraday.get(scry_url) do |req|
    req.headers['Accept'] = 'application/json'
    req.headers['Cookie'] = self.cookie
  end

  {status: response.status, code: response.reason_phrase, body: response.body}
end

#settingsObject

Answers the object managing the Settings on this ship. This object provides all the helper methods to list, update, and remove a Setting



154
155
156
157
158
159
# File 'lib/urbit/ship.rb', line 154

def settings
  if self.logged_in?
    @settings = Settings.load(ship: self) if @settings.nil?
  end
  @settings
end

#spider(desk: 'landscape', mark_in:, mark_out:, thread:, data:, args: []) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/urbit/ship.rb', line 161

def spider(desk: 'landscape', mark_in:, mark_out:, thread:, data:, args: [])
  self.
  url = "#{self.url}/spider/#{desk}/#{mark_in}/#{thread}/#{mark_out}.json"

  # TODO: This is a huge hack due to the fact that certain spider operations are known to
  #       not return when they should. Instead I just set the timeout low and catch the
  #       error and act like everything is ok.
  if args.include?("NO_RESPONSE")
    conn = Faraday::Connection.new()
    conn.options.timeout = 1
    conn.options.open_timeout = 1

    begin
      response = conn.post(url) do |req|
        req.headers['Accept'] = 'application/json'
        req.headers['Cookie'] = self.cookie
        req.body = data
      end
    rescue Faraday::TimeoutError
      return {status: 200, code: "ok", body: "null"}
    end
  end

  response = Faraday.post(url) do |req|
    req.headers['Accept'] = 'application/json'
    req.headers['Cookie'] = self.cookie
    req.body = data
  end

  {status: response.status, code: response.reason_phrase, body: response.body}
end

#subscribe(app:, path:) ⇒ Object

Subscribe to an app at a path.

Returns a Channel which has been created and opened and will begin

to get back a stream of facts via its Receiver.


199
200
201
# File 'lib/urbit/ship.rb', line 199

def subscribe(app:, path:)
  (self.add_channel).subscribe(app: app, path: path)
end

#to_hObject



203
204
205
# File 'lib/urbit/ship.rb', line 203

def to_h
  {name: "#{self.pat_p}", host: "#{self.config.host}", port: "#{self.config.port}"}
end

#to_sObject



207
208
209
# File 'lib/urbit/ship.rb', line 207

def to_s
  "a Ship(#{self.to_h})"
end

#untilded_nameObject



211
212
213
# File 'lib/urbit/ship.rb', line 211

def untilded_name
  name.gsub('~', '')
end

#urlObject



215
216
217
# File 'lib/urbit/ship.rb', line 215

def url
  self.config.api_base_url
end