fugalh-batphone 0.2.0
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/ChangeLog +2 -0
- data/README +71 -0
- data/lib/agi.rb +121 -0
- metadata +55 -0
data/ChangeLog
ADDED
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
|
+
|