presbeus 0.0.9 → 0.0.10
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 +5 -5
- data/bin/presbeus +1 -242
- data/lib/presbeus.rb +243 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9468b0f4ea59ae7a4423a30a1cb56063d1187de95afcf44b25e1c2e9516e9963
|
4
|
+
data.tar.gz: b4a99e169929a912e22be83894126ae468def9483c18becc3e5500b0ab34cbf8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40644f67bda26926f83ebfbc4d539b31dcdd9693d3cfc74b9848f91dd32167720f8a3aec82660e0a5dfc1bf9aaa69903d83e818cfed87f3649abb189b41cb713
|
7
|
+
data.tar.gz: ad07729edaf99ed476c2aea87c0e6942cb2411a60fdeef6e69b72714a8759bf264331aa9cb1ddd8eb0d9df44f7f97b6238f601d44a6ea699a862445a588f3e60
|
data/bin/presbeus
CHANGED
@@ -1,244 +1,3 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require '
|
3
|
-
require 'json'
|
4
|
-
require 'yaml'
|
5
|
-
require 'time_ago_in_words'
|
6
|
-
require 'terminal-table'
|
7
|
-
require 'highline'
|
8
|
-
require 'colorize'
|
9
|
-
require 'readline'
|
10
|
-
#require 'websocket-eventmachine-client'
|
11
|
-
require 'kontena-websocket-client'
|
12
|
-
require 'open-uri'
|
13
|
-
|
14
|
-
class Time
|
15
|
-
|
16
|
-
alias_method :ago_in_words_no_timezone, :ago_in_words
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
class Presbeus
|
21
|
-
|
22
|
-
def initialize_arguments
|
23
|
-
argument(:help, [], "show this help") { help }
|
24
|
-
argument(:realtime, [], "handle realtime event stream") { realtime }
|
25
|
-
argument(:shell, [], "run in an interactive shell") { shell }
|
26
|
-
argument(:devices, [], "list devices") { puts table devices }
|
27
|
-
argument(:pushes, [], "list pushes") { puts table pushes_with_color }
|
28
|
-
argument(:threads, [:device_id], "show threads for device") do
|
29
|
-
|c| puts table threads c[0]
|
30
|
-
end
|
31
|
-
argument(:last, [:device_id], "show last thread for device") do |c|
|
32
|
-
puts table last_thread c[0]
|
33
|
-
end
|
34
|
-
argument(:push, [:all], "push note to all devices") do |c|
|
35
|
-
push c.join(" ")
|
36
|
-
end
|
37
|
-
argument(:thread, [:device_id, :thead_id], "show SMS thread") do |c|
|
38
|
-
puts table thread_with_two_columns_wrap c[0], c[1]
|
39
|
-
end
|
40
|
-
argument(:sms, [:device_id, :phone_number, :all], "send SMS") do |c|
|
41
|
-
send_sms c[0], c[1], c[2..-1].join(" ")
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def initialize
|
46
|
-
initialize_arguments
|
47
|
-
configuration_path = "#{ENV['HOME']}/.config/presbeus.yml"
|
48
|
-
configuration = YAML.load_file configuration_path
|
49
|
-
api_server = 'https://api.pushbullet.com'
|
50
|
-
api_server = configuration["api_server"] if configuration.include? "api_server"
|
51
|
-
@token = `#{configuration['password_command']}`.chomp
|
52
|
-
@notify_command = configuration['notify_command']
|
53
|
-
@headers = {"Access-Token" => @token, "Content-Type" => "json"}
|
54
|
-
@api_prefix = api_server + '/v2/'
|
55
|
-
end
|
56
|
-
|
57
|
-
def realtime_no_reconnect
|
58
|
-
uri = "wss://stream.pushbullet.com/websocket/#{@token}"
|
59
|
-
Kontena::Websocket::Client.connect(uri, ping_timeout: 60) do |client|
|
60
|
-
client.on_pong do |time, delay|
|
61
|
-
p time, delay
|
62
|
-
end
|
63
|
-
client.read do |message|
|
64
|
-
json = JSON.parse(message)
|
65
|
-
type = json["type"]
|
66
|
-
if type != "nop"
|
67
|
-
if type == "tickle"
|
68
|
-
puts(table(pushes_with_color(Time.now.to_i) do |push|
|
69
|
-
`#{@notify_command} "#{push[1]}"` if @notify_command
|
70
|
-
end))
|
71
|
-
end
|
72
|
-
else
|
73
|
-
client.send message # pong
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def realtime
|
80
|
-
while true
|
81
|
-
begin
|
82
|
-
realtime_no_reconnect
|
83
|
-
rescue Kontena::Websocket::TimeoutError => e
|
84
|
-
puts "timeout #{e}"
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def post_v2 what, payload
|
90
|
-
RestClient.post(
|
91
|
-
@api_prefix + what, payload.to_json, @headers)
|
92
|
-
end
|
93
|
-
|
94
|
-
def get_v2 what
|
95
|
-
response = RestClient.get(
|
96
|
-
@api_prefix + what, @headers)
|
97
|
-
JSON.parse response.body
|
98
|
-
end
|
99
|
-
|
100
|
-
def devices
|
101
|
-
get_v2("devices")["devices"].map do |device|
|
102
|
-
[device["iden"], device["model"]]
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def threads iden
|
107
|
-
get_v2("permanents/#{iden}_threads")["threads"].reverse.map do |thread|
|
108
|
-
require 'awesome_print'
|
109
|
-
[thread["id"]] + thread["recipients"].map { |r| [r["address"], r["name"]] }.flatten
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def thread device, id
|
114
|
-
get_v2("permanents/#{device}_thread_#{id}")["thread"]
|
115
|
-
end
|
116
|
-
|
117
|
-
def pushes modified_after = nil
|
118
|
-
path = "pushes"
|
119
|
-
path += "?modified_after=#{modified_after}" if modified_after
|
120
|
-
get_v2(path)["pushes"].map do |push|
|
121
|
-
[Time.at(push["created"].to_i).ago_in_words, push["body"]]
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def user_iden
|
126
|
-
get_v2("users/me")["iden"]
|
127
|
-
end
|
128
|
-
|
129
|
-
def push message
|
130
|
-
post_v2 "pushes", {
|
131
|
-
title: "push from presbeus",
|
132
|
-
type: "note",
|
133
|
-
body: message,
|
134
|
-
}
|
135
|
-
end
|
136
|
-
|
137
|
-
def send_sms device, conversation_iden, message
|
138
|
-
post_v2 "ephemerals", {
|
139
|
-
push: {
|
140
|
-
conversation_iden: conversation_iden,
|
141
|
-
message: message,
|
142
|
-
package_name: "com.pushbullet.android",
|
143
|
-
source_user_iden: user_iden,
|
144
|
-
target_device_iden: device,
|
145
|
-
type: "messaging_extension_reply"
|
146
|
-
},
|
147
|
-
type: "push"
|
148
|
-
}
|
149
|
-
end
|
150
|
-
|
151
|
-
def table rows, config = {}
|
152
|
-
t = Terminal::Table.new config.merge({:rows => rows})
|
153
|
-
t.style = { border_top: false, border_bottom: false, border_y: '' }
|
154
|
-
t
|
155
|
-
end
|
156
|
-
|
157
|
-
def wrap s, width
|
158
|
-
s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n")
|
159
|
-
end
|
160
|
-
|
161
|
-
def with_color string, width, background
|
162
|
-
lines = string.split("\n")
|
163
|
-
lines.map { |line| line.ljust(width).colorize(color: :black, background: background)}.join "\n"
|
164
|
-
end
|
165
|
-
|
166
|
-
def width
|
167
|
-
HighLine::SystemExtensions.terminal_size[0]
|
168
|
-
end
|
169
|
-
|
170
|
-
def half_width
|
171
|
-
width / 2 - 4
|
172
|
-
end
|
173
|
-
|
174
|
-
def width_2
|
175
|
-
width - 4
|
176
|
-
end
|
177
|
-
|
178
|
-
def thread_with_two_columns_wrap device, id
|
179
|
-
res = []
|
180
|
-
thread(device, id).reverse.each do |message|
|
181
|
-
text = [wrap(message["body"], half_width), ""]
|
182
|
-
date = ["\n#{Time.at(message["timestamp"]).ago_in_words}", ""]
|
183
|
-
if message["direction"] != "incoming"
|
184
|
-
text[0] = with_color text[0], half_width, :white
|
185
|
-
text.reverse!
|
186
|
-
date.reverse!
|
187
|
-
else
|
188
|
-
text[0] = with_color text[0], half_width, :green
|
189
|
-
end
|
190
|
-
res << date
|
191
|
-
res << text
|
192
|
-
end
|
193
|
-
res
|
194
|
-
end
|
195
|
-
|
196
|
-
def pushes_with_color modified_after = nil
|
197
|
-
pushes(modified_after).reverse.map do |push|
|
198
|
-
yield(push) if block_given?
|
199
|
-
["\n" + push[0] + "\n" + with_color(wrap(push[1], width_2), width_2, :green)]
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
def last_thread device
|
204
|
-
thread_with_two_columns_wrap device, threads(device).last[0]
|
205
|
-
end
|
206
|
-
|
207
|
-
def argument name, args, description
|
208
|
-
@arguments ||= {}
|
209
|
-
@arguments[name] = {args: args, description: description, block: Proc.new { |c| yield c } }
|
210
|
-
end
|
211
|
-
|
212
|
-
def help
|
213
|
-
a = @arguments.to_a.map do |_|
|
214
|
-
[_[0].to_s, _[1][:args].map { |x| x.to_s }.join(" "), _[1][:description]]
|
215
|
-
end
|
216
|
-
puts table a
|
217
|
-
end
|
218
|
-
|
219
|
-
def shell
|
220
|
-
while buf = Readline.readline("> ", true)
|
221
|
-
run buf.split
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
def good_syntax? name, command
|
226
|
-
args = @arguments[name][:args]
|
227
|
-
count = args.size + 1
|
228
|
-
args.include?(:all) ? command.size >= count : command.size == count
|
229
|
-
end
|
230
|
-
|
231
|
-
def run command
|
232
|
-
if command.size > 0
|
233
|
-
name = command[0].to_sym
|
234
|
-
if @arguments.keys.include?(name) and good_syntax?(name, command)
|
235
|
-
@arguments[name][:block].call command[1..-1]
|
236
|
-
return
|
237
|
-
end
|
238
|
-
end
|
239
|
-
help
|
240
|
-
end
|
241
|
-
|
242
|
-
end
|
243
|
-
|
2
|
+
require 'presbeus'
|
244
3
|
Presbeus.new.run ARGV
|
data/lib/presbeus.rb
ADDED
@@ -0,0 +1,243 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'json'
|
3
|
+
require 'yaml'
|
4
|
+
require 'time_ago_in_words'
|
5
|
+
require 'terminal-table'
|
6
|
+
require 'highline'
|
7
|
+
require 'colorize'
|
8
|
+
require 'readline'
|
9
|
+
#require 'websocket-eventmachine-client'
|
10
|
+
require 'kontena-websocket-client'
|
11
|
+
require 'open-uri'
|
12
|
+
|
13
|
+
class Time
|
14
|
+
|
15
|
+
alias_method :ago_in_words_no_timezone, :ago_in_words
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
class Presbeus
|
20
|
+
|
21
|
+
def initialize_arguments
|
22
|
+
argument(:help, [], "show this help") { help }
|
23
|
+
argument(:realtime, [], "handle realtime event stream") { realtime }
|
24
|
+
argument(:shell, [], "run in an interactive shell") { shell }
|
25
|
+
argument(:devices, [], "list devices") { puts table devices }
|
26
|
+
argument(:pushes, [], "list pushes") { puts table pushes_with_color }
|
27
|
+
argument(:threads, [:device_id], "show threads for device") do
|
28
|
+
|c| puts table threads c[0]
|
29
|
+
end
|
30
|
+
argument(:last, [:device_id], "show last thread for device") do |c|
|
31
|
+
puts table last_thread c[0]
|
32
|
+
end
|
33
|
+
argument(:push, [:all], "push note to all devices") do |c|
|
34
|
+
push c.join(" ")
|
35
|
+
end
|
36
|
+
argument(:thread, [:device_id, :thead_id], "show SMS thread") do |c|
|
37
|
+
puts table thread_with_two_columns_wrap c[0], c[1]
|
38
|
+
end
|
39
|
+
argument(:sms, [:device_id, :phone_number, :all], "send SMS") do |c|
|
40
|
+
send_sms c[0], c[1], c[2..-1].join(" ")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize
|
45
|
+
initialize_arguments
|
46
|
+
configuration_path = "#{ENV['HOME']}/.config/presbeus.yml"
|
47
|
+
configuration = YAML.load_file configuration_path
|
48
|
+
api_server = 'https://api.pushbullet.com'
|
49
|
+
api_server = configuration["api_server"] if configuration.include? "api_server"
|
50
|
+
@token = `#{configuration['password_command']}`.chomp
|
51
|
+
@notify_command = configuration['notify_command']
|
52
|
+
@headers = {"Access-Token" => @token, "Content-Type" => "json"}
|
53
|
+
@api_prefix = api_server + '/v2/'
|
54
|
+
end
|
55
|
+
|
56
|
+
def realtime_no_reconnect
|
57
|
+
uri = "wss://stream.pushbullet.com/websocket/#{@token}"
|
58
|
+
Kontena::Websocket::Client.connect(uri, ping_timeout: 60) do |client|
|
59
|
+
client.on_pong do |time, delay|
|
60
|
+
p time, delay
|
61
|
+
end
|
62
|
+
client.read do |message|
|
63
|
+
json = JSON.parse(message)
|
64
|
+
type = json["type"]
|
65
|
+
if type != "nop"
|
66
|
+
if type == "tickle"
|
67
|
+
puts(table(pushes_with_color(Time.now.to_i) do |push|
|
68
|
+
`#{@notify_command} "#{push[1]}"` if @notify_command
|
69
|
+
end))
|
70
|
+
end
|
71
|
+
else
|
72
|
+
client.send message # pong
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def realtime
|
79
|
+
while true
|
80
|
+
begin
|
81
|
+
realtime_no_reconnect
|
82
|
+
rescue Kontena::Websocket::TimeoutError => e
|
83
|
+
puts "timeout #{e}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def post_v2 what, payload
|
89
|
+
RestClient.post(
|
90
|
+
@api_prefix + what, payload.to_json, @headers)
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_v2 what
|
94
|
+
response = RestClient.get(
|
95
|
+
@api_prefix + what, @headers)
|
96
|
+
JSON.parse response.body
|
97
|
+
end
|
98
|
+
|
99
|
+
def devices
|
100
|
+
get_v2("devices")["devices"].map do |device|
|
101
|
+
[device["iden"], device["model"]]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def threads iden
|
106
|
+
get_v2("permanents/#{iden}_threads")["threads"].reverse.map do |thread|
|
107
|
+
require 'awesome_print'
|
108
|
+
[thread["id"]] + thread["recipients"].map { |r| [r["address"], r["name"]] }.flatten
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def thread device, id
|
113
|
+
get_v2("permanents/#{device}_thread_#{id}")["thread"]
|
114
|
+
end
|
115
|
+
|
116
|
+
def pushes modified_after = nil
|
117
|
+
path = "pushes"
|
118
|
+
path += "?modified_after=#{modified_after}" if modified_after
|
119
|
+
get_v2(path)["pushes"].map do |push|
|
120
|
+
[Time.at(push["created"].to_i).ago_in_words, push["body"]]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def user_iden
|
125
|
+
get_v2("users/me")["iden"]
|
126
|
+
end
|
127
|
+
|
128
|
+
def push message
|
129
|
+
post_v2 "pushes", {
|
130
|
+
title: "push from presbeus",
|
131
|
+
type: "note",
|
132
|
+
body: message,
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
def send_sms device, conversation_iden, message
|
137
|
+
post_v2 "ephemerals", {
|
138
|
+
push: {
|
139
|
+
conversation_iden: conversation_iden,
|
140
|
+
message: message,
|
141
|
+
package_name: "com.pushbullet.android",
|
142
|
+
source_user_iden: user_iden,
|
143
|
+
target_device_iden: device,
|
144
|
+
type: "messaging_extension_reply"
|
145
|
+
},
|
146
|
+
type: "push"
|
147
|
+
}
|
148
|
+
end
|
149
|
+
|
150
|
+
def table rows, config = {}
|
151
|
+
t = Terminal::Table.new config.merge({:rows => rows})
|
152
|
+
t.style = { border_top: false, border_bottom: false, border_y: '' }
|
153
|
+
t
|
154
|
+
end
|
155
|
+
|
156
|
+
def wrap s, width
|
157
|
+
s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n")
|
158
|
+
end
|
159
|
+
|
160
|
+
def with_color string, width, background
|
161
|
+
lines = string.split("\n")
|
162
|
+
lines.map { |line| line.ljust(width).colorize(color: :black, background: background)}.join "\n"
|
163
|
+
end
|
164
|
+
|
165
|
+
def width
|
166
|
+
HighLine::SystemExtensions.terminal_size[0]
|
167
|
+
end
|
168
|
+
|
169
|
+
def half_width
|
170
|
+
width / 2 - 4
|
171
|
+
end
|
172
|
+
|
173
|
+
def width_2
|
174
|
+
width - 4
|
175
|
+
end
|
176
|
+
|
177
|
+
def thread_with_two_columns_wrap device, id
|
178
|
+
res = []
|
179
|
+
thread(device, id).reverse.each do |message|
|
180
|
+
text = [wrap(message["body"], half_width), ""]
|
181
|
+
date = ["\n#{Time.at(message["timestamp"]).ago_in_words}", ""]
|
182
|
+
if message["direction"] != "incoming"
|
183
|
+
text[0] = with_color text[0], half_width, :white
|
184
|
+
text.reverse!
|
185
|
+
date.reverse!
|
186
|
+
else
|
187
|
+
text[0] = with_color text[0], half_width, :green
|
188
|
+
end
|
189
|
+
res << date
|
190
|
+
res << text
|
191
|
+
end
|
192
|
+
res
|
193
|
+
end
|
194
|
+
|
195
|
+
def pushes_with_color modified_after = nil
|
196
|
+
pushes(modified_after).reverse.map do |push|
|
197
|
+
yield(push) if block_given?
|
198
|
+
["\n" + push[0] + "\n" + with_color(wrap(push[1], width_2), width_2, :green)]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def last_thread device
|
203
|
+
thread_with_two_columns_wrap device, threads(device).last[0]
|
204
|
+
end
|
205
|
+
|
206
|
+
def argument name, args, description
|
207
|
+
@arguments ||= {}
|
208
|
+
@arguments[name] = {args: args, description: description, block: Proc.new { |c| yield c } }
|
209
|
+
end
|
210
|
+
|
211
|
+
def help
|
212
|
+
a = @arguments.to_a.map do |_|
|
213
|
+
[_[0].to_s, _[1][:args].map { |x| x.to_s }.join(" "), _[1][:description]]
|
214
|
+
end
|
215
|
+
puts table a
|
216
|
+
end
|
217
|
+
|
218
|
+
def shell
|
219
|
+
while buf = Readline.readline("> ", true)
|
220
|
+
run buf.split
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def good_syntax? name, command
|
225
|
+
args = @arguments[name][:args]
|
226
|
+
count = args.size + 1
|
227
|
+
args.include?(:all) ? command.size >= count : command.size == count
|
228
|
+
end
|
229
|
+
|
230
|
+
def run command
|
231
|
+
if command.size > 0
|
232
|
+
name = command[0].to_sym
|
233
|
+
if @arguments.keys.include?(name) and good_syntax?(name, command)
|
234
|
+
@arguments[name][:block].call command[1..-1]
|
235
|
+
return
|
236
|
+
end
|
237
|
+
end
|
238
|
+
help
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: presbeus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Olivier Abdesselam
|
@@ -102,6 +102,7 @@ extensions: []
|
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
104
|
- bin/presbeus
|
105
|
+
- lib/presbeus.rb
|
105
106
|
homepage: http://github.com/yazgoo/presbeus
|
106
107
|
licenses:
|
107
108
|
- MIT
|
@@ -122,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
123
|
version: '0'
|
123
124
|
requirements: []
|
124
125
|
rubyforge_project:
|
125
|
-
rubygems_version: 2.
|
126
|
+
rubygems_version: 2.7.7
|
126
127
|
signing_key:
|
127
128
|
specification_version: 4
|
128
129
|
summary: command line SMS client for pushbullet
|