bobble 0.0.4 → 0.0.5
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.
- data/lib/bobble/checker.rb +112 -0
- data/lib/bobble/notifier/gmail.rb +29 -0
- data/lib/bobble/notifier/google_voice.rb +85 -0
- data/lib/bobble/notifier/twilio.rb +35 -0
- data/lib/bobble/util.rb +10 -8
- data/lib/bobble.rb +7 -46
- metadata +12 -11
- data/lib/bobble/gmail_notifier.rb +0 -25
- data/lib/bobble/google_voice_notifier.rb +0 -81
- data/lib/bobble/twilio_notifier.rb +0 -31
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'bobble/notifier/twilio'
|
2
|
+
require 'bobble/notifier/google_voice'
|
3
|
+
require 'bobble/notifier/gmail'
|
4
|
+
|
5
|
+
module Bobble
|
6
|
+
class Checker
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def check(url, options={})
|
10
|
+
{
|
11
|
+
# The status that is considered a success.
|
12
|
+
# If nil, any status other than 50x is success.
|
13
|
+
:success_status => nil,
|
14
|
+
# Specified headers are required for the response
|
15
|
+
# to be considered a success.
|
16
|
+
# Regex values can be specified.
|
17
|
+
:success_header => nil,
|
18
|
+
# Response body must match the specified body.
|
19
|
+
# Can be a regex.
|
20
|
+
:success_body => nil
|
21
|
+
}.update(options)
|
22
|
+
|
23
|
+
begin
|
24
|
+
response = http_request(url)
|
25
|
+
assert_success(response, options)
|
26
|
+
puts "Successful!: #{url}"
|
27
|
+
rescue Exception => e
|
28
|
+
message = "FAILED: #{url} - #{e.message}"
|
29
|
+
puts message
|
30
|
+
|
31
|
+
self.send_notification(message, url)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def http_request(url)
|
36
|
+
uri = URI.parse(url)
|
37
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
38
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
39
|
+
return http.request(request)
|
40
|
+
end
|
41
|
+
|
42
|
+
# raises an exception if not successful
|
43
|
+
def assert_success(response, options)
|
44
|
+
if response.code.to_i >= 500
|
45
|
+
raise Exception.new("Response status code error: #{response.code}")
|
46
|
+
end
|
47
|
+
|
48
|
+
if options[:success_status]
|
49
|
+
unless response.code.to_i == options[:success_status].to_i
|
50
|
+
raise Exception.new("Response status code error. Is: #{response.code} Expected: #{options[:success_status]}")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if options[:success_header]
|
55
|
+
options[:success_header].each do |k,v|
|
56
|
+
header_value = response.header[k.to_s]
|
57
|
+
if v.is_a?(Regexp)
|
58
|
+
unless header_value =~ v
|
59
|
+
raise Exception.new("Response header '#{k}' should match regexp #{v} ('#{header_value}' does not match)")
|
60
|
+
end
|
61
|
+
else
|
62
|
+
unless header_value == v
|
63
|
+
raise Exception.new("Response header '#{k}' should have value '#{v}' (instead is #{header_value})")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
if options[:success_body]
|
70
|
+
match = options[:success_body]
|
71
|
+
if match.is_a?(Regexp)
|
72
|
+
unless response.body =~ match
|
73
|
+
raise Exception.new("Response body should match regexp #{match}, but does not.")
|
74
|
+
end
|
75
|
+
else
|
76
|
+
unless response.body.strip == match.strip
|
77
|
+
raise Exception.new("Response body should be '#{match}', instead is '#{response.body}'")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
def send_notification(message, url)
|
85
|
+
if Bobble.option(:gmail)
|
86
|
+
begin
|
87
|
+
Notifier::Gmail.send(message, url)
|
88
|
+
rescue Exception => e
|
89
|
+
puts "Gmail Notifier failed: #{e.message}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
if Bobble.option(:twilio)
|
94
|
+
begin
|
95
|
+
Notifier::Twilio.send(message)
|
96
|
+
rescue Exception => e
|
97
|
+
puts "Twilio Notifier failed: #{e.message}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
if Bobble.option(:google_voice)
|
102
|
+
begin
|
103
|
+
Notifier::GoogleVoice.send(message)
|
104
|
+
rescue Exception => e
|
105
|
+
puts "Google Voice Notifier failed: #{e.message}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'pony'
|
2
|
+
|
3
|
+
module Bobble
|
4
|
+
module Notifier
|
5
|
+
class Gmail
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def send(message, url)
|
9
|
+
Pony.mail({
|
10
|
+
:to => ENV["BOBBLE_GMAIL_TO_EMAIL"],
|
11
|
+
:via => :smtp,
|
12
|
+
:via_options => {
|
13
|
+
:address => 'smtp.gmail.com',
|
14
|
+
:port => '587',
|
15
|
+
:enable_starttls_auto => true,
|
16
|
+
:user_name => ENV["BOBBLE_GMAIL_USERNAME"],
|
17
|
+
:password => ENV["BOBBLE_GMAIL_PASSWORD"],
|
18
|
+
:authentication => :plain, # :plain, :login, :cram_md5, no auth by default
|
19
|
+
:domain => "localhost.localdomain" # the HELO domain provided by the client to the server
|
20
|
+
},
|
21
|
+
:body => message,
|
22
|
+
:subject => "Bobble: #{url} is down"
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'bobble/util'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Google Voice Notifier
|
5
|
+
# Adapted from: http://brettterpstra.com/sms-from-the-command-line-with-google-voice/
|
6
|
+
#
|
7
|
+
module Bobble
|
8
|
+
module Notifier
|
9
|
+
class GoogleVoice
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def postit(uri_str, data, header = nil, limit = 3)
|
13
|
+
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
|
14
|
+
url = URI.parse(uri_str)
|
15
|
+
http = Net::HTTP.new(url.host,443)
|
16
|
+
http.use_ssl = true
|
17
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
18
|
+
response,content = http.post(url.path,data,header)
|
19
|
+
case response
|
20
|
+
when Net::HTTPSuccess then content
|
21
|
+
when Net::HTTPRedirection then postit(response['location'],data,header, limit - 1)
|
22
|
+
else
|
23
|
+
puts response.inspect
|
24
|
+
response.error!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def getit(uri_str, header, limit = 3)
|
29
|
+
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
|
30
|
+
url = URI.parse(uri_str)
|
31
|
+
http = Net::HTTP.new(url.host,url.port)
|
32
|
+
http.use_ssl = true
|
33
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
34
|
+
response,content = http.get(url.path,header)
|
35
|
+
case response
|
36
|
+
when Net::HTTPSuccess then content
|
37
|
+
when Net::HTTPRedirection then getit(response['location'],header, limit - 1)
|
38
|
+
else
|
39
|
+
response.error!
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def send(message)
|
44
|
+
message = Bobble::Util.shorten_to_text_message(message)
|
45
|
+
|
46
|
+
username = ENV["BOBBLE_GVOICE_USERNAME"]
|
47
|
+
password = ENV["BOBBLE_GVOICE_PASSWORD"]
|
48
|
+
# TODO: support multiple numbers
|
49
|
+
number = ENV["BOBBLE_GVOICE_TO_PHONENUMBER"]
|
50
|
+
numbers = [number]
|
51
|
+
|
52
|
+
data = "accountType=GOOGLE&Email=#{username}&Passwd=#{password}&service=grandcentral&source=brettterpstra-CLISMS-2.0"
|
53
|
+
res = postit('https://www.google.com/accounts/ClientLogin',data)
|
54
|
+
|
55
|
+
if res
|
56
|
+
authcode = res.match(/Auth=(.+)/)[1]
|
57
|
+
header = {'Authorization' => "GoogleLogin auth=#{authcode.strip}",'Content-Length' => '0'}
|
58
|
+
newres = getit('https://www.google.com/voice',header)
|
59
|
+
|
60
|
+
if newres
|
61
|
+
rnrse = newres.match(/'_rnr_se': '([^']+)'/)[1]
|
62
|
+
numbers.each do |num|
|
63
|
+
data = "_rnr_se=#{rnrse}&phoneNumber=#{num.strip}&text=#{message}&id="
|
64
|
+
finalres = postit('https://www.google.com/voice/sms/send/',data,header)
|
65
|
+
|
66
|
+
if finalres["ok"]
|
67
|
+
puts "Message sent to #{num}"
|
68
|
+
else
|
69
|
+
puts "Error sending to #{num}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
else
|
74
|
+
newres.error!
|
75
|
+
end
|
76
|
+
|
77
|
+
else
|
78
|
+
res.error!
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'twilio-ruby'
|
2
|
+
require 'bobble/util'
|
3
|
+
|
4
|
+
module Bobble
|
5
|
+
module Notifier
|
6
|
+
class Twilio
|
7
|
+
class << self
|
8
|
+
|
9
|
+
@@client = nil
|
10
|
+
|
11
|
+
def create_client
|
12
|
+
return if @@client
|
13
|
+
|
14
|
+
account_sid = ENV['BOBBLE_TWILIO_SID']
|
15
|
+
auth_token = ENV['BOBBLE_TWILIO_TOKEN']
|
16
|
+
|
17
|
+
@@client = Twilio::REST::Client.new account_sid, auth_token
|
18
|
+
end
|
19
|
+
|
20
|
+
def send(message)
|
21
|
+
create_client
|
22
|
+
message = Bobble::Util.shorten_to_text_message(message)
|
23
|
+
|
24
|
+
params = {
|
25
|
+
:from => ENV['BOBBLE_TWILIO_FROM_PHONENUMBER'],
|
26
|
+
:to => ENV['BOBBLE_TWILIO_TO_PHONENUMBER'],
|
27
|
+
:body => message
|
28
|
+
}
|
29
|
+
@@client.account.sms.messages.create(params)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/bobble/util.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
|
2
|
-
class
|
1
|
+
module Bobble
|
2
|
+
class Util
|
3
|
+
class << self
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
def shorten_to_text_message(message)
|
6
|
+
text_message = message
|
7
|
+
if message.length > 140
|
8
|
+
text_message = message[0..136] + "..."
|
9
|
+
end
|
10
|
+
return message
|
8
11
|
end
|
9
|
-
return message
|
10
|
-
end
|
11
12
|
|
13
|
+
end
|
12
14
|
end
|
13
15
|
end
|
data/lib/bobble.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'bobble/checker'
|
2
|
+
|
3
|
+
module Bobble
|
2
4
|
class << self
|
3
5
|
|
4
6
|
# default options are guessed based on what environment variables are present
|
@@ -8,56 +10,15 @@ class Bobble
|
|
8
10
|
:gmail => !!ENV["BOBBLE_GMAIL_USERNAME"]
|
9
11
|
}
|
10
12
|
|
11
|
-
def
|
12
|
-
@@options
|
13
|
+
def option(key)
|
14
|
+
@@options[key]
|
13
15
|
end
|
14
16
|
|
15
|
-
def check(url)
|
16
|
-
|
17
|
-
response = Net::HTTP.get(URI.parse(url))
|
18
|
-
raise Exception.new("empty response") if response == ""
|
19
|
-
puts "Successful!: #{url}"
|
20
|
-
rescue Exception => e
|
21
|
-
message = "FAILED: #{url} - #{e.message}"
|
22
|
-
puts message
|
23
|
-
|
24
|
-
send_notification(message, url)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def send_notification(message, url)
|
29
|
-
|
30
|
-
if @@options[:gmail]
|
31
|
-
begin
|
32
|
-
GmailNotifier.send(message, url)
|
33
|
-
rescue Exception => e
|
34
|
-
puts "Gmail Notifier failed: #{e.message}"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
if @@options[:twilio]
|
39
|
-
begin
|
40
|
-
TwilioNotifier.send(message)
|
41
|
-
rescue Exception => e
|
42
|
-
puts "Twilio Notifier failed: #{e.message}"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
if @@options[:google_voice]
|
47
|
-
begin
|
48
|
-
GoogleVoiceNotifier.send(message)
|
49
|
-
rescue Exception => e
|
50
|
-
puts "Google Voice Notifier failed: #{e.message}"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
17
|
+
def check(url, options={})
|
18
|
+
Bobble::Checker.check(url, options)
|
54
19
|
end
|
55
20
|
|
56
21
|
end
|
57
22
|
end
|
58
23
|
|
59
|
-
require 'bobble/twilio_notifier'
|
60
|
-
require 'bobble/google_voice_notifier'
|
61
|
-
require 'bobble/gmail_notifier'
|
62
|
-
|
63
24
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bobble
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-07-06 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: twilio-ruby
|
16
|
-
requirement: &
|
16
|
+
requirement: &70256347466300 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 3.6.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70256347466300
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: pony
|
27
|
-
requirement: &
|
27
|
+
requirement: &70256347465820 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,19 +32,20 @@ dependencies:
|
|
32
32
|
version: '1.4'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
36
|
-
description: For
|
37
|
-
|
35
|
+
version_requirements: *70256347465820
|
36
|
+
description: For pinging your web services (any URL) & freely or cheaply getting email/SMS
|
37
|
+
notifications when they're down.
|
38
38
|
email: ahfarmer@gmail.com
|
39
39
|
executables: []
|
40
40
|
extensions: []
|
41
41
|
extra_rdoc_files: []
|
42
42
|
files:
|
43
43
|
- lib/bobble.rb
|
44
|
-
- lib/bobble/
|
45
|
-
- lib/bobble/google_voice_notifier.rb
|
46
|
-
- lib/bobble/twilio_notifier.rb
|
44
|
+
- lib/bobble/checker.rb
|
47
45
|
- lib/bobble/util.rb
|
46
|
+
- lib/bobble/notifier/gmail.rb
|
47
|
+
- lib/bobble/notifier/google_voice.rb
|
48
|
+
- lib/bobble/notifier/twilio.rb
|
48
49
|
homepage: https://github.com/ahfarmer/bobble
|
49
50
|
licenses: []
|
50
51
|
post_install_message:
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'pony'
|
2
|
-
|
3
|
-
class Bobble::GmailNotifier
|
4
|
-
class << self
|
5
|
-
|
6
|
-
def send(message, url)
|
7
|
-
Pony.mail({
|
8
|
-
:to => ENV["BOBBLE_GMAIL_TO_EMAIL"],
|
9
|
-
:via => :smtp,
|
10
|
-
:via_options => {
|
11
|
-
:address => 'smtp.gmail.com',
|
12
|
-
:port => '587',
|
13
|
-
:enable_starttls_auto => true,
|
14
|
-
:user_name => ENV["BOBBLE_GMAIL_USERNAME"],
|
15
|
-
:password => ENV["BOBBLE_GMAIL_PASSWORD"],
|
16
|
-
:authentication => :plain, # :plain, :login, :cram_md5, no auth by default
|
17
|
-
:domain => "localhost.localdomain" # the HELO domain provided by the client to the server
|
18
|
-
},
|
19
|
-
:body => message,
|
20
|
-
:subject => "Bobble: #{url} is down"
|
21
|
-
})
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
require 'bobble/util'
|
2
|
-
|
3
|
-
#
|
4
|
-
# Google Voice Notifier
|
5
|
-
# Adapted from: http://brettterpstra.com/sms-from-the-command-line-with-google-voice/
|
6
|
-
#
|
7
|
-
class Bobble::GoogleVoiceNotifier
|
8
|
-
class << self
|
9
|
-
|
10
|
-
def postit(uri_str, data, header = nil, limit = 3)
|
11
|
-
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
|
12
|
-
url = URI.parse(uri_str)
|
13
|
-
http = Net::HTTP.new(url.host,443)
|
14
|
-
http.use_ssl = true
|
15
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
16
|
-
response,content = http.post(url.path,data,header)
|
17
|
-
case response
|
18
|
-
when Net::HTTPSuccess then content
|
19
|
-
when Net::HTTPRedirection then postit(response['location'],data,header, limit - 1)
|
20
|
-
else
|
21
|
-
puts response.inspect
|
22
|
-
response.error!
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def getit(uri_str, header, limit = 3)
|
27
|
-
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
|
28
|
-
url = URI.parse(uri_str)
|
29
|
-
http = Net::HTTP.new(url.host,url.port)
|
30
|
-
http.use_ssl = true
|
31
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
32
|
-
response,content = http.get(url.path,header)
|
33
|
-
case response
|
34
|
-
when Net::HTTPSuccess then content
|
35
|
-
when Net::HTTPRedirection then getit(response['location'],header, limit - 1)
|
36
|
-
else
|
37
|
-
response.error!
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def send(message)
|
42
|
-
message = Bobble::Util.shorten_to_text_message(message)
|
43
|
-
|
44
|
-
username = ENV["BOBBLE_GVOICE_USERNAME"]
|
45
|
-
password = ENV["BOBBLE_GVOICE_PASSWORD"]
|
46
|
-
# TODO: support multiple numbers
|
47
|
-
number = ENV["BOBBLE_GVOICE_TO_PHONENUMBER"]
|
48
|
-
numbers = [number]
|
49
|
-
|
50
|
-
data = "accountType=GOOGLE&Email=#{username}&Passwd=#{password}&service=grandcentral&source=brettterpstra-CLISMS-2.0"
|
51
|
-
res = postit('https://www.google.com/accounts/ClientLogin',data)
|
52
|
-
|
53
|
-
if res
|
54
|
-
authcode = res.match(/Auth=(.+)/)[1]
|
55
|
-
header = {'Authorization' => "GoogleLogin auth=#{authcode.strip}",'Content-Length' => '0'}
|
56
|
-
newres = getit('https://www.google.com/voice',header)
|
57
|
-
|
58
|
-
if newres
|
59
|
-
rnrse = newres.match(/'_rnr_se': '([^']+)'/)[1]
|
60
|
-
numbers.each do |num|
|
61
|
-
data = "_rnr_se=#{rnrse}&phoneNumber=#{num.strip}&text=#{message}&id="
|
62
|
-
finalres = postit('https://www.google.com/voice/sms/send/',data,header)
|
63
|
-
|
64
|
-
if finalres["ok"]
|
65
|
-
puts "Message sent to #{num}"
|
66
|
-
else
|
67
|
-
puts "Error sending to #{num}"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
else
|
72
|
-
newres.error!
|
73
|
-
end
|
74
|
-
|
75
|
-
else
|
76
|
-
res.error!
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'twilio-ruby'
|
2
|
-
require 'bobble/util'
|
3
|
-
|
4
|
-
class Bobble::TwilioNotifier
|
5
|
-
class << self
|
6
|
-
|
7
|
-
@@client = nil
|
8
|
-
|
9
|
-
def create_client
|
10
|
-
return if @@client
|
11
|
-
|
12
|
-
account_sid = ENV['BOBBLE_TWILIO_SID']
|
13
|
-
auth_token = ENV['BOBBLE_TWILIO_TOKEN']
|
14
|
-
|
15
|
-
@@client = Twilio::REST::Client.new account_sid, auth_token
|
16
|
-
end
|
17
|
-
|
18
|
-
def send(message)
|
19
|
-
create_client
|
20
|
-
message = Bobble::Util.shorten_to_text_message(message)
|
21
|
-
|
22
|
-
params = {
|
23
|
-
:from => ENV['BOBBLE_TWILIO_FROM_PHONENUMBER'],
|
24
|
-
:to => ENV['BOBBLE_TWILIO_TO_PHONENUMBER'],
|
25
|
-
:body => message
|
26
|
-
}
|
27
|
-
@@client.account.sms.messages.create(params)
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|