fugalh-batphone 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/ChangeLog +2 -0
  2. data/README +71 -0
  3. data/lib/agi.rb +121 -0
  4. metadata +55 -0
data/ChangeLog ADDED
@@ -0,0 +1,2 @@
1
+ Thu Jan 17 21:20:59 MST 2008
2
+ - added AGI#args
data/README ADDED
@@ -0,0 +1,71 @@
1
+ = Batphone
2
+
3
+ link:../theme/batphone.png
4
+
5
+ Batphone is an Asterisk Gateway Interface (AGI) library for Ruby. It is
6
+ well-suited to simple bat-tasks, with a small learning curve. (I promise you'll
7
+ spend more time figuring out AGI than batphone). It is also perfectly capable
8
+ of making all your wildest AGI dreams come true. It won't get in your way.
9
+
10
+ 1. http://www.voip-info.org/wiki-Asterisk+AGI
11
+
12
+ == Synopsis
13
+
14
+ In extensions.conf:
15
+
16
+ exten => batphone,1,AGI(batphone.agi)
17
+
18
+ batphone.agi:
19
+
20
+ #!/usr/bin/ruby
21
+ require 'agi'
22
+
23
+ agi = AGI.new
24
+ agi.answer
25
+ agi.stream_file('batman_help_the_monkeys_are_everywhere', nil)
26
+ begin
27
+ # press pound to make them stop!
28
+ r = agi.stream_file('tt-monkeys', '#')
29
+ end while r.result != ?#
30
+ agi.stream_file('POW', nil)
31
+ agi.hangup
32
+
33
+ == Requirements
34
+ Gee, Batman, all you need is Ruby. You might want Asterisk[http://asterisk.org]
35
+ too.
36
+
37
+ == Installation
38
+ Get it from GitHub[http://github.com/fugalh/batphone] and put it somewhere
39
+ batty.
40
+
41
+ sudo rake install
42
+ or
43
+ sudo ruby setup.rb
44
+
45
+ == Details
46
+ An AGI object serves as your proxy to Asterisk. Each time you send a command to
47
+ Asterisk using AGI#send or using the metaprogrammed interface, you get an
48
+ AGI::Response back.
49
+
50
+ == TODO
51
+ - 5xx errors span multiple lines and should be handled by the lib (probably an
52
+ exception raised too)
53
+ - It might be nice to have convenience methods that match up with regular
54
+ Asterisk Applications (commands), e.g. Playback, Background, etc.
55
+ - I'm inclined to make an OpenStruct-like interface to the Asterisk
56
+ environment, but I need to make sure there won't be any metaprogramming
57
+ conflitcs
58
+
59
+ == License
60
+ Copyright:: Copyright (C) 2007 Hans Fugal <mailto:hans@fugal.net>.
61
+ License:: Distributed under the same terms as Ruby.
62
+
63
+ == Colophon
64
+ Holy red phones, Batman! Asterisk is about phones. Rubies are red. Batphones
65
+ are really swell red phones.
66
+
67
+ No relation to batsman[http://eigenclass.org/], though I think he's swell too.
68
+
69
+ The image is from an
70
+ article[http://www.millionaireplayboy.com/toys/batphone.php] on building your
71
+ own physical batphone at Millionaire Playboy.
data/lib/agi.rb ADDED
@@ -0,0 +1,121 @@
1
+ require 'logger'
2
+ require 'ostruct'
3
+
4
+ class AGI
5
+ # Create a new AGI object and parse the Asterisk environment. Usually you
6
+ # will call this without arguments, but you might have your bat-reasons to
7
+ # provide +io_in+ and +io_out+.
8
+ #
9
+ # Also sets up a default SIGHUP trap, logging the event and calling exit. If
10
+ # you want to do some cleanup on SIGHUP instead, override it, e.g.:
11
+ # trap('SIGHUP') { cleanup }
12
+ def initialize(io_in=STDIN, io_out=STDOUT)
13
+ @io_in = io_in
14
+ @io_out = io_out
15
+
16
+ # read vars
17
+ @env = {}
18
+ while (line = @io_in.readline.strip) != ''
19
+ k,v = line.split(':')
20
+ k.strip! if k
21
+ v.strip! if v
22
+ k = $1 if k =~ /^agi_(.*)$/
23
+ @env[k] = v
24
+ end
25
+
26
+ @log = Logger.new(STDERR)
27
+
28
+ @args = ARGV
29
+
30
+ # default trap for SIGHUP, which is what Asterisk sends us when the other
31
+ # end hangs up. An uncaught SIGHUP exception pollutes STDERR needlessly.
32
+ trap('SIGHUP') { @log.debug('Holy SIGHUP, Batman!'); exit }
33
+ end
34
+
35
+ # Logger object, defaults to <tt>Logger.new(STDERR)</tt>. By default nothing
36
+ # is logged, but if you turn up the log level to +DEBUG+ you'll see the
37
+ # behind-the-scenes communication.
38
+ attr_accessor :log
39
+
40
+ # A Hash with the initial environment. Leave off the +agi_+ prefix
41
+ attr_accessor :env
42
+ alias :environment :env
43
+
44
+ # The arguments passed in the Asterisk AGI application, so
45
+ # _X,1,AGI(foo.agi|one|two|three)
46
+ # will give agi.args as ["one","two","three"].
47
+ attr_reader :args
48
+ alias :argv :args
49
+
50
+ # Environment access shortcut. Use strings or symbols as keys.
51
+ def [](key)
52
+ @env[key.to_s]
53
+ end
54
+
55
+ # Send the given command and arguments. Converts +nil+ and "" in
56
+ # +args+ to literal empty quotes
57
+ def send(cmd, *args)
58
+ args.map! {|a| (a.nil? or a == '') ? '""' : a}
59
+ msg = [cmd, *args].join(' ')
60
+ @log.debug ">> "+msg
61
+ @io_out.puts msg
62
+ @io_out.flush # I'm not sure if this is necessary, but just in case
63
+ resp = @io_in.readline
64
+ @log.debug "<< "+resp
65
+ Response.new(resp)
66
+ end
67
+
68
+ # Shortcut for send. e.g.
69
+ # a.say_time(Time.now.to_i, nil)
70
+ # is the same as
71
+ # a.send("SAY TIME",Time.now.to_i,'""')
72
+ def method_missing(symbol, *args)
73
+ cmd = symbol.to_s.upcase.tr('_',' ')
74
+ send(cmd, *args)
75
+ end
76
+
77
+ # Repeat this menu followed by the timeout, with the given digits expected.
78
+ # Use break to exit this menu.
79
+ def menu(audio,digits,timeout=3000, &block)
80
+ while true # (until the block breaks)
81
+ r = self.stream_file(audio,digits)
82
+
83
+ if r.result == 0
84
+ # nothing was dialed yet, let's wait timeout milliseconds longer
85
+ r = self.wait_for_digit(timeout)
86
+ end
87
+ yield(r) # if the block breaks, we go on with life
88
+ end
89
+ end
90
+
91
+ # The answer to every AGI#send is one of these.
92
+ class Response
93
+ # Raw response string
94
+ attr_accessor :raw
95
+ # The return code, usually (almost always) 200
96
+ attr_accessor :code
97
+ # The result value (a string)
98
+ attr_accessor :result
99
+ # The note in parentheses (if any), stripped of parentheses
100
+ attr_accessor :parenthetical
101
+ alias :note :parenthetical
102
+ # The endpos value (if any)
103
+ attr_accessor :endpos
104
+
105
+ # raw:: A string of the form "200 result=0 [(foo)] [endpos=1234]"
106
+ #
107
+ # The variables are populated as you would think. The parenthetical note is
108
+ # stripped of its parentheses.
109
+ #
110
+ # Don't forget that result is often an ASCII value rather than an integer
111
+ # value. In that case you should test against ?d where d is a digit.
112
+ def initialize(raw)
113
+ @raw = raw
114
+ @raw =~ /^(\d+)\s+result=(-?[^\s]*)(?:\s+\((.*)\))?(?:\s+endpos=(-?\d+))?/
115
+ @code = ($1 and $1.to_i)
116
+ @result = $2
117
+ @parenthetical = $3
118
+ @endpos = ($4 and $4.to_i)
119
+ end
120
+ end
121
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fugalh-batphone
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Hans Fugal
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-07-14 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Very simple and easy to learn bridge to AGI (Asterisk Gateway Interface)
17
+ email: hans@fugal.net
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - README
26
+ - ChangeLog
27
+ - lib/agi.rb
28
+ has_rdoc: true
29
+ homepage: http://hans.fugal.net/src/batphone/doc/files/README.html
30
+ post_install_message:
31
+ rdoc_options: []
32
+
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: "0"
40
+ version:
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ requirements: []
48
+
49
+ rubyforge_project:
50
+ rubygems_version: 1.2.0
51
+ signing_key:
52
+ specification_version: 2
53
+ summary: Very simple and easy to learn bridge to AGI (Asterisk Gateway Interface)
54
+ test_files: []
55
+