Class: Presbeus

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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client = true) ⇒ Presbeus

Returns a new instance of Presbeus.



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

def initialize client = true
  @client = client
  initialize_arguments
  configuration_path = "#{ENV['HOME']}/.config/presbeus.yml"
  configuration = YAML.load_file configuration_path
  api_server = 'https://api.pushbullet.com'
  api_server = configuration["api_server"] if configuration.include? "api_server"
  @default_device = configuration["default_device"] if configuration.include? "default_device"
  @token = `#{configuration['password_command']}`.chomp
  @notify_command = configuration['notify_command']
  @headers = {"Access-Token" => @token, "Content-Type" => "json"}
  @api_prefix = api_server + '/v2/'
end

Instance Attribute Details

#default_deviceObject

Returns the value of attribute default_device.



21
22
23
# File 'lib/presbeus.rb', line 21

def default_device
  @default_device
end

Class Method Details

.parse_thread(thread) ⇒ Object



126
127
128
# File 'lib/presbeus.rb', line 126

def self.parse_thread thread
  [thread["id"]] + thread["recipients"].map { |r| [r["address"], r["name"]] }.flatten
end

Instance Method Details

#argument(name, args, description) ⇒ Object



230
231
232
233
# File 'lib/presbeus.rb', line 230

def argument name, args, description
  @arguments ||= {}
  @arguments[name] = {args: args, description: description, block: Proc.new { |c| yield c } }
end

#devicesObject



120
121
122
123
124
# File 'lib/presbeus.rb', line 120

def devices
  get_v2("devices")["devices"].map do |device|
    [device["iden"], device["model"]]
  end
end

#get_v2(what) ⇒ Object



110
111
112
113
114
115
116
117
118
# File 'lib/presbeus.rb', line 110

def get_v2 what
  args = {url: @api_prefix + what, headers: @headers}
  if @client
    response = RestClient.get(args[:url], args[:headers])
    JSON.parse response.body
  else
    args
  end
end

#good_syntax?(name, command) ⇒ Boolean

Returns:

  • (Boolean)


248
249
250
251
252
# File 'lib/presbeus.rb', line 248

def good_syntax? name, command
  args = @arguments[name][:args]
  count = args.size + 1
  args.include?(:all) ? command.size >= count : command.size == count
end

#half_widthObject



193
194
195
# File 'lib/presbeus.rb', line 193

def half_width
  width / 2 - 4
end

#helpObject



235
236
237
238
239
240
# File 'lib/presbeus.rb', line 235

def help
  a = @arguments.to_a.map do |_|
     [_[0].to_s, _[1][:args].map { |x| x.to_s }.join(" "), _[1][:description]]
  end
  puts table a
end

#initialize_argumentsObject



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/presbeus.rb', line 23

def initialize_arguments
  argument(:help, [], "show this help")  { help }
  argument(:realtime, [], "handle realtime event stream")  { realtime }
  argument(:realtime_raw, [], "handle realtime event stream")  { @client = false; realtime }
  argument(:shell, [], "run in an interactive shell") { shell }
  argument(:devices, [], "list devices") { puts table devices }
  argument(:pushes, [], "list pushes") { puts table pushes_with_color }
  argument(:threads, [:device_id], "show threads for device") do
    |c| puts table threads c[0]
  end
  argument(:last, [:device_id], "show last thread for device") do |c|
    puts table last_thread c[0]
  end
  argument(:push, [:all], "push note to all devices") do |c|
    push c.join(" ")
  end
  argument(:thread, [:device_id, :thead_id], "show SMS thread") do |c|
    puts table thread_with_two_columns_wrap c[0], c[1]
  end
  argument(:sms, [:device_id, :phone_number, :all], "send SMS") do |c|
    send_sms c[0], c[1], c[2..-1].join(" ")
  end
end

#last_thread(device) ⇒ Object



226
227
228
# File 'lib/presbeus.rb', line 226

def last_thread device
   thread_with_two_columns_wrap device, threads(device).last[0]
end

#post_v2(what, payload) ⇒ Object



101
102
103
104
105
106
107
108
# File 'lib/presbeus.rb', line 101

def post_v2 what, payload
  args = {url: @api_prefix + what, payload: payload.to_json, headers: @headers}
  if @client
    RestClient.post(args[:url], args[:payload], args[:headers])
  else
    args
  end
end

#push(message) ⇒ Object



152
153
154
155
156
157
158
# File 'lib/presbeus.rb', line 152

def push message
  post_v2 "pushes", {
    title: "push from presbeus",
    type: "note",
    body: message.force_encoding("UTF-8"),
  }
end

#pushes(modified_after = nil) ⇒ Object



140
141
142
143
144
145
146
# File 'lib/presbeus.rb', line 140

def pushes modified_after = nil
  path = "pushes"
  path += "?modified_after=#{modified_after}" if modified_after
  get_v2(path)["pushes"].map do |push|
    [Time.at(push["created"].to_i).ago_in_words, push["body"]]
  end
end

#pushes_with_color(modified_after = nil) ⇒ Object



219
220
221
222
223
224
# File 'lib/presbeus.rb', line 219

def pushes_with_color modified_after = nil
  pushes(modified_after).reverse.map do |push|
    yield(push) if block_given?
    ["\n" + push[0] + "\n" + with_color(wrap(push[1], width_2), width_2, :green)]
  end
end

#realtimeObject



87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/presbeus.rb', line 87

def realtime
  $stdout.sync = true if !@cient
  while true
    begin
      realtime_no_reconnect
    rescue Kontena::Websocket::TimeoutError => e
      puts "timeout #{e}" if @client
    rescue Kontena::Websocket::ConnectError => e
      puts "connect error #{e}" if @client
      sleep 60
    end
  end
end

#realtime_no_reconnectObject



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/presbeus.rb', line 61

def realtime_no_reconnect
  uri = "wss://stream.pushbullet.com/websocket/#{@token}"
  Kontena::Websocket::Client.connect(uri, ping_timeout: 60) do |client|
    client.on_pong do |time, delay|
      p time, delay
    end
    client.read do |message|
      json = JSON.parse(message)
      type = json["type"]
      if type != "nop"
        if @client
          if type == "tickle"
            puts(table(pushes_with_color(Time.now.to_i) do |push|
              `#{@notify_command} "#{push[1]}"` if @notify_command
            end))
          end
        else
          puts message
        end
      else
        client.send message # pong
      end
    end
  end
end

#run(command) ⇒ Object



254
255
256
257
258
259
260
261
262
263
# File 'lib/presbeus.rb', line 254

def run command
  if command.size > 0
    name = command[0].to_sym
    if @arguments.keys.include?(name) and good_syntax?(name, command)
      @arguments[name][:block].call command[1..-1]
      return
    end
  end
  help
end

#send_sms(device, conversation_iden, message) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/presbeus.rb', line 160

def send_sms device, conversation_iden, message
  post_v2 "ephemerals", {
    push: {
      conversation_iden: conversation_iden,
      message: message,
      package_name: "com.pushbullet.android",
      source_user_iden: user_iden,
      target_device_iden: device,
      type: "messaging_extension_reply"
    },
    type: "push"
  }
end

#shellObject



242
243
244
245
246
# File 'lib/presbeus.rb', line 242

def shell
  while buf = Readline.readline("> ", true)
    run buf.split
  end
end

#table(rows, config = {}) ⇒ Object



174
175
176
177
178
# File 'lib/presbeus.rb', line 174

def table rows, config = {}
  t = Terminal::Table.new config.merge({:rows => rows})
  t.style = { border_top: false, border_bottom: false, border_y: '' }
  t
end

#thread(device, id) ⇒ Object



136
137
138
# File 'lib/presbeus.rb', line 136

def thread device, id
  get_v2("permanents/#{device}_thread_#{id}")["thread"]
end

#thread_with_two_columns_wrap(device, id) ⇒ Object



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/presbeus.rb', line 201

def thread_with_two_columns_wrap device, id
  res = []
  thread(device, id).reverse.each do |message|
      text = [wrap(message["body"], half_width), ""]
      date = ["\n#{Time.at(message["timestamp"]).ago_in_words}", ""]
      if message["direction"] != "incoming"
        text[0] = with_color text[0], half_width, :white
        text.reverse!
        date.reverse!
      else
        text[0] = with_color text[0], half_width, :green
      end
      res << date
      res << text
  end
  res
end

#threads(iden) ⇒ Object



130
131
132
133
134
# File 'lib/presbeus.rb', line 130

def threads iden
  get_v2("permanents/#{iden}_threads")["threads"].reverse.map do |thread|
    Presbeus.parse_thread thread
  end
end

#user_idenObject



148
149
150
# File 'lib/presbeus.rb', line 148

def user_iden
  get_v2("users/me")["iden"]
end

#widthObject



189
190
191
# File 'lib/presbeus.rb', line 189

def width
  HighLine::SystemExtensions.terminal_size[0]
end

#width_2Object



197
198
199
# File 'lib/presbeus.rb', line 197

def width_2
  width - 4
end

#with_color(string, width, background) ⇒ Object



184
185
186
187
# File 'lib/presbeus.rb', line 184

def with_color string, width, background
  lines = string.split("\n")
  lines.map { |line| line.ljust(width).colorize(color: :black, background: background)}.join "\n"
end

#wrap(s, width) ⇒ Object



180
181
182
# File 'lib/presbeus.rb', line 180

def wrap s, width
  s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n")
end