adammck-rubysms 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,168 +1,43 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "libglade2.rb"
4
3
  require "drb.rb"
5
4
 
6
- SERVER_PORT = "1370"
7
-
8
- class SmsGui
9
- include GetText
10
- attr :glade
5
+ class Client
6
+ SERVER_PORT = "1370"
11
7
 
12
8
  def initialize
13
-
14
- # if this file is a symlink (which is probably is, since rubygems
15
- # automatically symlinks bin files into /usr/bin), find the original
16
- # source file, so we can find the glade src relatively
17
- this_file = File.symlink?(__FILE__) ? \
18
- File.readlink(__FILE__) : __FILE__
19
-
20
- # find and load up the glade src for the gui
21
- glade_src = File.expand_path(File.dirname(this_file) + "/../lib/drb-client.glade")
22
- @glade = GladeXML.new(glade_src) do |handler|
23
- method(handler)
24
- end
25
-
26
- # for storing outgoing
27
- # messages for recall
28
- @history = []
29
- @hist_pos = 0
30
-
31
- # fetch references to the gtk widgets
32
- @source = @glade.get_widget("entry_source")
33
- @entry = @glade.get_widget("entry_message")
34
- @log = @glade.get_widget("textview_log")
35
- @lb = @log.buffer
36
-
37
- # create a text mark to keep at the end of
38
- # the log, so we can keep scrolling to it
39
- @lb.create_mark("end", @lb.end_iter, true)
40
-
41
- # create colors for incoming and outgoing messages
42
- @lb.create_tag("incoming", "family"=>"monospace", "foreground"=>"#AA0000")
43
- @lb.create_tag("outgoing", "family"=>"monospace", "foreground"=>"#0000AA")
44
- @lb.create_tag("error", "family"=>"monospace", "foreground"=>"#FFFFFF", "background"=>"#FF0000")
45
-
46
- # prepopulate the source phone number with six digits
47
9
  @src = (1111 + rand(8888)).to_s
48
- @source.text = @src
49
-
50
- # fire up drb, to send outgoing messages to rubysms
51
- @injector = DRbObject.new_with_uri("druby://localhost:#{SERVER_PORT}")
52
- puts "Connected to RubySMS at: #{@injector.__drburi}"
53
-
54
- # start listening for incoming messages from rubysms
55
- @drb = DRb.start_service("druby://localhost:#{SERVER_PORT}#{@src}", self)
56
- puts "Started DRb client at: #{@drb.uri}"
57
-
58
- # display the GUI
59
- @glade.get_widget("window").show
60
- @entry.grab_focus
61
- end
62
-
63
-
64
- # user closed the window,
65
- # so terminate the program
66
- def on_quit
67
- Gtk.main_quit
10
+ @outgoing = DRbObject.new_with_uri("druby://localhost:#{SERVER_PORT}")
11
+ @incoming = DRb.start_service("druby://localhost:#{SERVER_PORT}#{@src}", self)
68
12
  end
69
-
70
-
71
- # user clicked "send", or pressed
72
- # enter while in the entry field
73
- def on_button_send_clicked
74
- msg = @entry.text
75
-
76
- # do nothing if the message is blank
77
- return nil if msg.empty?
78
- log ">> #{msg}", "incoming"
79
13
 
80
- begin
81
- # attempt to send the message
82
- # to rubysms via drb, as if it
83
- # were a real incoming sms
84
- @injector.incoming(@src, msg)
85
-
86
- @hist_pos = 0
87
- @history.push(msg)
88
- @entry.text = ""
89
-
90
- # couldn't connect!
91
- rescue DRb::DRbConnError
92
- log("Connection to RubySMS failed!", "error")
93
- #log("Tried URI: #{@injector.__drburi}", "error")
94
- rescue => err
95
- log(err.message, "error")
96
- log(" " + err.backtrace.join("\n "), "error")
97
- end
14
+ def print(str)
15
+ $stdout.print(str)
16
+ $stdout.flush
98
17
  end
99
-
100
- def on_entry_message_key_press(widget, event)
101
- if event.keyval == 65362 # up arrow
102
- if @hist_pos > -@history.length
103
- @hist_pos -= 1
104
- @entry.text = @history[@hist_pos]
105
- @entry.grab_focus
106
- end
107
-
108
- # prevent default event,
109
- # which bumps the focus
110
- # upwards to the log
111
- return true
112
- end
113
-
114
- if event.keyval == 65364 # down arrow
115
- if @hist_pos < -1
116
- @hist_pos += 1
117
- @entry.text = @history[@hist_pos]
118
- @entry.grab_focus
119
- end
120
-
121
- # prevent default
122
- return true
18
+
19
+ def start
20
+ while(true)
21
+ print "< "
22
+ str = $stdin.gets.strip
23
+ @outgoing.incoming(@src, str)
24
+
25
+ # to allow time for a message to
26
+ # come back; yes, this is horrible
27
+ sleep 0.5
123
28
  end
124
-
125
- # any other key resets
126
- # the position in history
127
- @hist_pos = 0
128
- return false
129
- end
130
-
131
-
132
- def log(msg, tag)
133
- # prepend a newline, unless this
134
- # is the first entry (to avoid a
135
- # one-line gap at the top)
136
- msg = "\n" + msg\
137
- if @lb.char_count > 0
138
-
139
- # add a single entry to the message log
140
- # (using the colors defined in #initialize)
141
- @lb.insert(@lb.end_iter, msg, tag)
142
-
143
- # scroll to the end of the *previous*
144
- # message, to bring the top of this
145
- # message into view, in case it is long
146
- @log.scroll_to_mark(@lb.get_mark("end"), 0, true, 1, 0)
147
-
148
- # update the position of the end marker,
149
- # which we will scroll to (above), when
150
- # the next message is logged
151
- @lb.move_mark(@lb.get_mark("end"), @lb.end_iter)
152
- @lb.end_iter.line_offset = 0
153
29
  end
154
-
155
-
30
+
156
31
  def incoming(msg)
157
- # we received a message! do nothing
158
- # except add it to the message log
159
- msg.gsub!(/\n/, "\n ")
160
- log "<< #{msg}", "outgoing"
32
+ print "> #{msg}\n"
161
33
  end
162
34
  end
163
35
 
36
+ # exit gracefully if
37
+ # ctrl+c is received
38
+ trap("INT") do
39
+ puts
40
+ exit
41
+ end
164
42
 
165
- # initialize, and block
166
- # until GTK terminates
167
- gui = SmsGui.new
168
- Gtk.main
43
+ Client.new.start
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "libglade2.rb"
4
+ require "drb.rb"
5
+
6
+ SERVER_PORT = "1370"
7
+
8
+ class SmsGui
9
+ include GetText
10
+ attr :glade
11
+
12
+ def initialize
13
+
14
+ # if this file is a symlink (which is probably is, since rubygems
15
+ # automatically symlinks bin files into /usr/bin), find the original
16
+ # source file, so we can find the glade src relatively
17
+ this_file = File.symlink?(__FILE__) ? \
18
+ File.readlink(__FILE__) : __FILE__
19
+
20
+ # find and load up the glade src for the gui
21
+ glade_src = File.expand_path(File.dirname(this_file) + "/../lib/drb-client.glade")
22
+ @glade = GladeXML.new(glade_src) do |handler|
23
+ method(handler)
24
+ end
25
+
26
+ # for storing outgoing
27
+ # messages for recall
28
+ @history = []
29
+ @hist_pos = 0
30
+
31
+ # fetch references to the gtk widgets
32
+ @source = @glade.get_widget("entry_source")
33
+ @entry = @glade.get_widget("entry_message")
34
+ @log = @glade.get_widget("textview_log")
35
+ @lb = @log.buffer
36
+
37
+ # create a text mark to keep at the end of
38
+ # the log, so we can keep scrolling to it
39
+ @lb.create_mark("end", @lb.end_iter, true)
40
+
41
+ # create colors for incoming and outgoing messages
42
+ @lb.create_tag("incoming", "family"=>"monospace", "foreground"=>"#AA0000")
43
+ @lb.create_tag("outgoing", "family"=>"monospace", "foreground"=>"#0000AA")
44
+ @lb.create_tag("error", "family"=>"monospace", "foreground"=>"#FFFFFF", "background"=>"#FF0000")
45
+
46
+ # prepopulate the source phone number with six digits
47
+ @src = (1111 + rand(8888)).to_s
48
+ @source.text = @src
49
+
50
+ # fire up drb, to send outgoing messages to rubysms
51
+ @injector = DRbObject.new_with_uri("druby://localhost:#{SERVER_PORT}")
52
+ puts "Connected to RubySMS at: #{@injector.__drburi}"
53
+
54
+ # start listening for incoming messages from rubysms
55
+ @drb = DRb.start_service("druby://localhost:#{SERVER_PORT}#{@src}", self)
56
+ puts "Started DRb client at: #{@drb.uri}"
57
+
58
+ # display the GUI
59
+ @glade.get_widget("window").show
60
+ @entry.grab_focus
61
+ end
62
+
63
+
64
+ # user closed the window,
65
+ # so terminate the program
66
+ def on_quit
67
+ Gtk.main_quit
68
+ end
69
+
70
+
71
+ # user clicked "send", or pressed
72
+ # enter while in the entry field
73
+ def on_button_send_clicked
74
+ msg = @entry.text
75
+
76
+ # do nothing if the message is blank
77
+ return nil if msg.empty?
78
+ log ">> #{msg}", "incoming"
79
+
80
+ begin
81
+ # attempt to send the message
82
+ # to rubysms via drb, as if it
83
+ # were a real incoming sms
84
+ @injector.incoming(@src, msg)
85
+
86
+ @hist_pos = 0
87
+ @history.push(msg)
88
+ @entry.text = ""
89
+
90
+ # couldn't connect!
91
+ rescue DRb::DRbConnError
92
+ log("Connection to RubySMS failed!", "error")
93
+ #log("Tried URI: #{@injector.__drburi}", "error")
94
+ rescue => err
95
+ log(err.message, "error")
96
+ log(" " + err.backtrace.join("\n "), "error")
97
+ end
98
+ end
99
+
100
+ def on_entry_message_key_press(widget, event)
101
+ if event.keyval == 65362 # up arrow
102
+ if @hist_pos > -@history.length
103
+ @hist_pos -= 1
104
+ @entry.text = @history[@hist_pos]
105
+ @entry.grab_focus
106
+ end
107
+
108
+ # prevent default event,
109
+ # which bumps the focus
110
+ # upwards to the log
111
+ return true
112
+ end
113
+
114
+ if event.keyval == 65364 # down arrow
115
+ if @hist_pos < -1
116
+ @hist_pos += 1
117
+ @entry.text = @history[@hist_pos]
118
+ @entry.grab_focus
119
+ end
120
+
121
+ # prevent default
122
+ return true
123
+ end
124
+
125
+ # any other key resets
126
+ # the position in history
127
+ @hist_pos = 0
128
+ return false
129
+ end
130
+
131
+
132
+ def log(msg, tag)
133
+ # prepend a newline, unless this
134
+ # is the first entry (to avoid a
135
+ # one-line gap at the top)
136
+ msg = "\n" + msg\
137
+ if @lb.char_count > 0
138
+
139
+ # add a single entry to the message log
140
+ # (using the colors defined in #initialize)
141
+ @lb.insert(@lb.end_iter, msg, tag)
142
+
143
+ # scroll to the end of the *previous*
144
+ # message, to bring the top of this
145
+ # message into view, in case it is long
146
+ @log.scroll_to_mark(@lb.get_mark("end"), 0, true, 1, 0)
147
+
148
+ # update the position of the end marker,
149
+ # which we will scroll to (above), when
150
+ # the next message is logged
151
+ @lb.move_mark(@lb.get_mark("end"), @lb.end_iter)
152
+ @lb.end_iter.line_offset = 0
153
+ end
154
+
155
+
156
+ def incoming(msg)
157
+ # we received a message! do nothing
158
+ # except add it to the message log
159
+ msg.gsub!(/\n/, "\n ")
160
+ log "<< #{msg}", "outgoing"
161
+ end
162
+ end
163
+
164
+
165
+ # initialize, and block
166
+ # until GTK terminates
167
+ gui = SmsGui.new
168
+ Gtk.main
@@ -4,6 +4,14 @@
4
4
  module SMS
5
5
  class App < Thing
6
6
 
7
+ NAMED_PRIORITY = {
8
+ :highest => 100,
9
+ :high => 90,
10
+ :normal => 50,
11
+ :low => 10,
12
+ :lowest => 0
13
+ }
14
+
7
15
  # Creates and starts a router to serve only
8
16
  # this application. Handy during development.
9
17
  #
@@ -54,6 +62,83 @@ module SMS
54
62
  router.serve_forever
55
63
  end
56
64
 
65
+ # Sets or returns the priority of this application **class**. Returning
66
+ # this value isn't tremendously useful by itself, and mostly exists for
67
+ # the sake of completeness, and to be called by Application#priority.
68
+ # The value returned is obtained by finding the first ancestor of this
69
+ # class which has a @priority (yes, it looks inside other classes
70
+ # instance variables. I'm sorry.), and converts it to a number via
71
+ # the SMS::App::NAMED_PRIORITY constant.
72
+ #
73
+ # class One < SMS::App
74
+ # priority :high
75
+ # end
76
+ #
77
+ # class Two < One
78
+ # end
79
+ #
80
+ # class Three < Two
81
+ # priority 36
82
+ # end
83
+ #
84
+ # One.priority => 90 # set via NAMED_PRIORITY
85
+ # Two.priority => 90 # inherited from One
86
+ # Three.priority => 36 # set literally
87
+ #
88
+ def self.priority(priority=nil)
89
+
90
+ # set the priority of this class if an argument
91
+ # were provided, and allow execution to continue
92
+ # to check it's validity
93
+ unless priority.nil?
94
+ @priority = priority
95
+ end
96
+
97
+ # find the first ancestor with a priority
98
+ # (Class.ancestors *includes* self)
99
+ self.ancestors.each do |klass|
100
+ if klass.instance_variable_defined?(:@priority)
101
+ prio = klass.instance_variable_get(:@priority)
102
+
103
+ # literal numbers are okay, although
104
+ # that probably isn't such a good idea
105
+ if prio.is_a?(Numeric)
106
+ return prio
107
+
108
+ # if this class has a named priority,
109
+ # resolve and return it's value
110
+ elsif prio.is_a?(Symbol)
111
+ if NAMED_PRIORITY.has_key?(prio)
112
+ return NAMED_PRIORITY[prio]
113
+
114
+ # don't allow invalid named priorites.
115
+ # i can't think of a use case, especially
116
+ # since the constant can be monkey-patched
117
+ # if it's really necessary
118
+ else
119
+ raise(
120
+ NameError,
121
+ "Invalid named priority #{prio.inspect} " +\
122
+ "of {klass}. Valid named priorties are: " +\
123
+ NAMED_PRIORITY.keys.join(", "))
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ # no ancestor has a priority, so assume
130
+ # that this app is of "normal" priority
131
+ return NAMED_PRIORITY[:normal]
132
+ end
133
+
134
+ def priority=(level)
135
+ @priority = level
136
+ end
137
+
138
+ def priority
139
+ @priority or self.class.priority
140
+ end
141
+
57
142
  def incoming(msg)
58
143
  if services = self.class.instance_variable_get(:@services)
59
144
 
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env ruby
2
+ # vim: noet
3
+
4
+
5
+ require "rubygems"
6
+ require "clickatell"
7
+ require "mongrel"
8
+ require "rack"
9
+
10
+
11
+ module SMS::Backend
12
+ class Clickatell < Base
13
+ PORT = 1280
14
+
15
+ # just store the arguments until the
16
+ # backend is ready to be started
17
+ def initialize(key, username, password)
18
+ @username = username
19
+ @password = password
20
+ @key = key
21
+ end
22
+
23
+ def start
24
+ @api = ::Clickatell::API.authenticate(@key, @username, @password)
25
+ balance = @api.account_balance
26
+
27
+ # start a separate thread to receive
28
+ # the incoming messages from clickatell
29
+ @rack_thread = Thread.new do
30
+ Rack::Handler::Mongrel.run(
31
+ method(:rack_app), :Port=>PORT)
32
+ end
33
+
34
+ # nothing went wrong this time
35
+ # so dump some useful info
36
+ log [
37
+ "Started #{label} Backend",
38
+ " Account balance: #{balance}"
39
+ ], :init
40
+ end
41
+
42
+ def send_sms(msg)
43
+ begin
44
+ @api.send_message(msg.phone_number, msg.text)
45
+ super
46
+
47
+ # sending failed, for some reason. i've
48
+ # never seen this happen, so just log it
49
+ rescue Clickatell::API::Error => err
50
+ log_exception err, "Message sending FAILED"
51
+ end
52
+ end
53
+
54
+ def rack_app(env)
55
+ req = Rack::Request.new(env)
56
+ post = req.GET
57
+
58
+ # only a single (obscure) url is valid, which
59
+ # must be entered into the clickatell admin
60
+ return resp(404, "Not Found") unless\
61
+ req.path_info == "/sms/receive"
62
+
63
+ # check that the required parameters were
64
+ # provided, and abort if any are missing
65
+ return resp(500, "Missing Parameters") unless\
66
+ post["from"] && post["timestamp"] && post["text"]
67
+
68
+ begin
69
+ # attempt to parse the timestamp
70
+ # (it's a mySQL timestamp... ?!)
71
+ time = Date.strptime(
72
+ post["timestamp"],
73
+ "%Y-%m-%d%H:%M:%S")
74
+
75
+ # timestamp parsing fail
76
+ rescue Exception => err
77
+ log_exception err, "Invalid timestamp: #{post["timestamp"]}"
78
+ return resp(500, "Invalid timestamp")
79
+ end
80
+
81
+ # everything looks fine, so notify rubysms of
82
+ # the incoming message, and acknowledge clickatell
83
+ router.incoming(
84
+ SMS::Incoming.new(
85
+ self, post["from"], time, post["text"]))
86
+ resp(200, "Message Accepted")
87
+ end
88
+
89
+ private
90
+
91
+ def resp(code, text)
92
+ [code, {"content-type" => "text/plain"}, text]
93
+ end
94
+ end
95
+ end
@@ -10,7 +10,8 @@
10
10
  # - rubygsms
11
11
  # - rubygsm
12
12
  begin
13
- dev_dir = "#{dir}/../../../rubygsm"
13
+ dir = File.dirname(__FILE__)
14
+ dev_dir = "#{dir}/../../../../rubygsm"
14
15
  dev_path = "#{dev_dir}/lib/rubygsm.rb"
15
16
  require File.expand_path(dev_path)
16
17
 
@@ -52,40 +53,37 @@ module SMS::Backend
52
53
  end
53
54
 
54
55
  def start
55
-
56
- # lock the threads during modem initialization,
57
- # simply to avoid the screen log being mixed up
58
- Thread.exclusive do
59
- begin
60
- @gsm = ::Gsm::Modem.new(@port)
61
- @gsm.use_pin(@pin) unless @pin.nil?
62
- @gsm.receive method(:incoming)
63
-
64
- #bands = @gsm.bands_available.join(", ")
65
- #log "Using GSM Band: #{@gsm.band}MHz"
66
- #log "Modem supports: #{bands}"
67
-
68
- log "Waiting for GSM network..."
69
- str = @gsm.wait_for_network
70
- log "Signal strength is: #{str}"
71
-
72
- # couldn't open the port. this usually means
73
- # that the modem isn't plugged in to it...
74
- rescue Errno::ENOENT, ArgumentError
75
- log "Couldn't open #{@port}", :err
76
- raise IOError
77
-
78
- # something else went wrong
79
- # while initializing the modem
80
- rescue ::Gsm::Modem::Error => err
81
- log ["Couldn't initialize the modem",
82
- "RubyGSM Says: #{err.desc}"], :err
83
- raise RuntimeError
84
- end
56
+ begin
57
+ @gsm = ::Gsm::Modem.new(@port)
58
+ @gsm.use_pin(@pin) unless @pin.nil?
59
+ @gsm.receive method(:incoming)
60
+ str = @gsm.wait_for_network
61
+
62
+ #bands = @gsm.bands_available.join(", ")
63
+ #log "Modem supports: #{bands}"
64
+
65
+ # couldn't open the port. this usually means
66
+ # that the modem isn't plugged in to it...
67
+ rescue Errno::ENOENT, ArgumentError => err
68
+ log_exception err,\
69
+ "Couldn't connect to " +\
70
+ "modem on port: #{@port}"
85
71
 
86
- # rubygsm didn't blow up?!
87
- log "Started GSM Backend", :init
72
+ # something else went wrong
73
+ # while initializing the modem
74
+ rescue ::Gsm::Modem::Error => err
75
+ log_exception err,\
76
+ "Couldn't initialize the " +\
77
+ "modem on port: #{@port}"
88
78
  end
79
+
80
+ # nothing went wrong this time
81
+ # so dump some useful info
82
+ log [
83
+ "Started #{label} Backend",
84
+ " Signal strength: #{str}",
85
+ " Port: #{@gsm.port}"
86
+ ], :init
89
87
  end
90
88
 
91
89
  def send_sms(msg)
@@ -94,8 +92,11 @@ module SMS::Backend
94
92
  # send the message to the modem via rubygsm, and log
95
93
  # if it failed. TODO: needs moar info from rubygsm
96
94
  # on *why* sending failed
97
- unless @gsm.send_sms(msg.recipient.phone_number, msg.text)
98
- log "Message sending FAILED", :warn
95
+ begin
96
+ @gsm.send_sms!(msg.recipient.phone_number, msg.text)
97
+
98
+ rescue => err
99
+ log_exception err, "Message sending FAILED"
99
100
  end
100
101
  end
101
102
 
@@ -41,7 +41,7 @@ module SMS::Backend
41
41
 
42
42
  # add a screen log message, which is kind of
43
43
  # a lie, because we haven't started anything yet
44
- uri = "http://localhost:#{@port}"
44
+ uri = "http://localhost:#{@port}/"
45
45
  log ["Started HTTP Offline Backend", "URI: #{uri}"], :init
46
46
 
47
47
  # this is goodbye
@@ -390,7 +390,8 @@ SMS::Backend::HTTP::HTML = <<EOF
390
390
  * reload the load to include it */
391
391
  $("send").set("send", {
392
392
  "url": "/" + session_id + "/send",
393
- "onComplete": update
393
+ "onComplete": function() {
394
+ update.delay(100); }
394
395
 
395
396
  /* submit the form via ajax,
396
397
  * and cancel the full-page */
@@ -54,6 +54,7 @@ module SMS
54
54
 
55
55
  LogColors = {
56
56
  :init => 46,
57
+ :stop => 44,
57
58
  :info => 40,
58
59
  :warn => 41,
59
60
  :err => 41,
@@ -27,13 +27,6 @@ module SMS
27
27
  def log_exception(error, prefix_message=nil)
28
28
  msgs = [error.class, error.message]
29
29
 
30
- # if a prefix was provided (to give a litle
31
- # more info on what went wrong), prepend it
32
- # to the output with a blank line
33
- unless prefix_message.nil?
34
- msg.shift prefix_message, ""
35
- end
36
-
37
30
  # add each line until the current frame is within
38
31
  # rubysms (the remainder will just be from gems)
39
32
  catch(:done) do
@@ -48,6 +41,15 @@ module SMS
48
41
  end
49
42
  end
50
43
 
44
+ # if a prefix was provided (to give a litle
45
+ # more info on what went wrong), prepend it
46
+ # to the output and indent the rest
47
+ unless prefix_message.nil?
48
+ msgs = [prefix_message] + msgs.collect do |msg|
49
+ " " + msg.to_s
50
+ end
51
+ end
52
+
51
53
  @log.event msgs, :warn
52
54
  end
53
55
 
@@ -74,7 +76,7 @@ module SMS
74
76
  # the output, disable the "echoctl" option in your terminal
75
77
  # (i added "stty -echoctl" to my .bashrc)
76
78
  trap("INT") do
77
- log "Shutting down", :init
79
+ log "Shutting down", :stop
78
80
 
79
81
  # fire the "stop" method of
80
82
  # each application and backend
@@ -142,8 +144,9 @@ module SMS
142
144
  # router.add_backend(:GSM, "/dev/ttyS0", 1234)
143
145
  # router.add_backend(:GSM, "/dev/ttyS1", 5678)
144
146
  # router.serve_forever
147
+ #
145
148
  def add_backend(backend, *args)
146
-
149
+
147
150
  # if a backend object was given, add it to this router
148
151
  # TODO: this modifies the argument just slightly. would
149
152
  # it be better to duplicate the object first?
@@ -153,8 +156,15 @@ module SMS
153
156
 
154
157
  # if it's a named backend, spawn it (along
155
158
  # with the optional arguments) and recurse
156
- elsif backend.is_a?(Symbol)
157
- add_backend SMS::Backend.create(backend, *args)
159
+ elsif backend.is_a?(Symbol) or backend.is_a?(String)
160
+ add_backend SMS::Backend.create(backend.to_sym, nil, *args)
161
+
162
+ # no idea what this
163
+ # backend is = boom
164
+ else
165
+ raise RuntimeError,
166
+ "Router#add_backend doesn't know what " +\
167
+ "to do with #{backend} (#{backend.klass})"
158
168
  end
159
169
  end
160
170
 
@@ -163,20 +173,38 @@ module SMS
163
173
  def incoming(msg)
164
174
  log_with_time "[#{msg.backend.label}] #{msg.sender.key}: #{msg.text} (#{msg.text.length})", :in
165
175
 
176
+ # iterate apps starting with
177
+ # the highest numeric priority
178
+ sorted = @apps.sort_by { |a| a.priority }.reverse
179
+
166
180
  # notify each application of the message.
167
- # they may or may not respond to it
168
- @apps.each do |app|
169
- begin
170
- app.incoming msg
171
-
172
- # something went boom in the app
173
- # log it, and continue with the next
174
- rescue StandardError => err
175
- log_exception(err)
181
+ # they may or may not respond to it, and
182
+ # may throw the :halt symbol to stop the
183
+ # notifying further apps. this is useful
184
+ # in conjunction with App.priority
185
+ catch(:halt) do
186
+ sorted.each do |app|
187
+ begin
188
+ catch(:continue) do
189
+ app.incoming msg
190
+
191
+ # if the app responded to the message, cancel
192
+ # further processing - unless :continue was
193
+ # thrown, which jumps over this check
194
+ unless msg.responses.empty?
195
+ throw :halt
196
+ end
197
+ end
176
198
 
177
- # if msg.responses.empty?
178
- # msg.respond("Sorry, there was an error while processing your message.")
179
- # end
199
+ # something went boom in the app
200
+ # log it, and continue with the next
201
+ rescue StandardError => err
202
+ log_exception(err)
203
+
204
+ # if msg.responses.empty?
205
+ # msg.respond("Sorry, there was an error while processing your message.")
206
+ # end
207
+ end
180
208
  end
181
209
  end
182
210
  end
@@ -186,11 +214,15 @@ module SMS
186
214
  def outgoing(msg)
187
215
  log_with_time "[#{msg.backend.label}] #{msg.recipient.key}: #{msg.text} (#{msg.text.length})", :out
188
216
  log("Outgoing message exceeds 140 characters", :warn) if msg.text.length > 140
189
- cancelled = false
217
+
218
+ # iterate apps starting with the loest numeric priority (the
219
+ # opposite to #incoming,so a :highest priority app gets the
220
+ # first look at incoming, and the last word on what goes out)
221
+ sorted = @apps.sort_by { |a| a.priority }
190
222
 
191
223
  # notify each app of the outgoing sms
192
224
  # note that the sending can still fail
193
- @apps.each do |app|
225
+ sorted.each do |app|
194
226
  app.outgoing msg
195
227
  end
196
228
  end
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "rubysms"
3
- s.version = "0.8.1"
4
- s.date = "2009-03-16"
3
+ s.version = "0.8.2"
4
+ s.date = "2009-04-10"
5
5
  s.summary = "Develop and deploy SMS applications with Ruby"
6
6
  s.email = "amckaig@unicef.org"
7
7
  s.homepage = "http://github.com/adammck/rubysms"
@@ -13,7 +13,8 @@ Gem::Specification.new do |s|
13
13
  "README.rdoc",
14
14
  "lib/rubysms.rb",
15
15
 
16
- # gtk gui
16
+ # drb clients
17
+ "bin/rubysms-gtk-drb-client",
17
18
  "bin/rubysms-drb-client",
18
19
  "lib/drb-client.glade",
19
20
 
@@ -28,6 +29,7 @@ Gem::Specification.new do |s|
28
29
 
29
30
  # backends
30
31
  "lib/rubysms/backend/cellphone.ico",
32
+ "lib/rubysms/backend/clickatell.rb",
31
33
  "lib/rubysms/backend/drb.rb",
32
34
  "lib/rubysms/backend/gsm.rb",
33
35
  "lib/rubysms/backend/http.rb",
@@ -38,6 +40,7 @@ Gem::Specification.new do |s|
38
40
  ]
39
41
 
40
42
  s.executables = [
43
+ "rubysms-gtk-drb-client",
41
44
  "rubysms-drb-client"
42
45
  ]
43
46
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adammck-rubysms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Mckaig
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-16 00:00:00 -07:00
12
+ date: 2009-04-10 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -45,6 +45,7 @@ dependencies:
45
45
  description:
46
46
  email: amckaig@unicef.org
47
47
  executables:
48
+ - rubysms-gtk-drb-client
48
49
  - rubysms-drb-client
49
50
  extensions: []
50
51
 
@@ -54,6 +55,7 @@ files:
54
55
  - rubysms.gemspec
55
56
  - README.rdoc
56
57
  - lib/rubysms.rb
58
+ - bin/rubysms-gtk-drb-client
57
59
  - bin/rubysms-drb-client
58
60
  - lib/drb-client.glade
59
61
  - lib/rubysms/application.rb
@@ -64,6 +66,7 @@ files:
64
66
  - lib/rubysms/person.rb
65
67
  - lib/rubysms/thing.rb
66
68
  - lib/rubysms/backend/cellphone.ico
69
+ - lib/rubysms/backend/clickatell.rb
67
70
  - lib/rubysms/backend/drb.rb
68
71
  - lib/rubysms/backend/gsm.rb
69
72
  - lib/rubysms/backend/http.rb