ragi 1.0.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.
Files changed (42) hide show
  1. data/CHANGELOG +12 -0
  2. data/RAGI Overview_files/filelist.xml +5 -0
  3. data/RAGI Overview_files/image001.gif +0 -0
  4. data/README +114 -0
  5. data/call_connection.rb +515 -0
  6. data/call_handler.rb +362 -0
  7. data/call_initiate.rb +188 -0
  8. data/call_server.rb +147 -0
  9. data/config.rb +68 -0
  10. data/example-call-audio.mp3 +0 -0
  11. data/ragi.gempsec +23 -0
  12. data/sample-apps/simon/simon_handler.rb +94 -0
  13. data/sample-apps/simon/sounds/README +9 -0
  14. data/sample-apps/simon/sounds/simon-1.gsm +0 -0
  15. data/sample-apps/simon/sounds/simon-2.gsm +0 -0
  16. data/sample-apps/simon/sounds/simon-3.gsm +0 -0
  17. data/sample-apps/simon/sounds/simon-4.gsm +0 -0
  18. data/sample-apps/simon/sounds/simon-5.gsm +0 -0
  19. data/sample-apps/simon/sounds/simon-6.gsm +0 -0
  20. data/sample-apps/simon/sounds/simon-7.gsm +0 -0
  21. data/sample-apps/simon/sounds/simon-8.gsm +0 -0
  22. data/sample-apps/simon/sounds/simon-9.gsm +0 -0
  23. data/sample-apps/simon/sounds/simon-again.gsm +0 -0
  24. data/sample-apps/simon/sounds/simon-beep-again.gsm +0 -0
  25. data/sample-apps/simon/sounds/simon-beep-beep.gsm +0 -0
  26. data/sample-apps/simon/sounds/simon-beep-gameover.gsm +0 -0
  27. data/sample-apps/simon/sounds/simon-beep-high.gsm +0 -0
  28. data/sample-apps/simon/sounds/simon-beep-low.gsm +0 -0
  29. data/sample-apps/simon/sounds/simon-beep-medium.gsm +0 -0
  30. data/sample-apps/simon/sounds/simon-beep-score.gsm +0 -0
  31. data/sample-apps/simon/sounds/simon-beep-welcome.gsm +0 -0
  32. data/sample-apps/simon/sounds/simon-beep.gsm +0 -0
  33. data/sample-apps/simon/sounds/simon-gameover.gsm +0 -0
  34. data/sample-apps/simon/sounds/simon-goodbye.gsm +0 -0
  35. data/sample-apps/simon/sounds/simon-high.gsm +0 -0
  36. data/sample-apps/simon/sounds/simon-low.gsm +0 -0
  37. data/sample-apps/simon/sounds/simon-medium.gsm +0 -0
  38. data/sample-apps/simon/sounds/simon-score.gsm +0 -0
  39. data/sample-apps/simon/sounds/simon-welcome.gsm +0 -0
  40. data/start_ragi.rb +41 -0
  41. data/test.rb +109 -0
  42. metadata +77 -0
@@ -0,0 +1,147 @@
1
+ #
2
+ # RAGI - Ruby classes for implementing an AGI server for Asterisk
3
+ # The BSD License for RAGI follows.
4
+ #
5
+ # Copyright (c) 2005, SNAPVINE LLC (www.snapvine.com)
6
+ # All rights reserved.
7
+
8
+ # Redistribution and use in source and binary forms, with or without
9
+ # modification, are permitted provided that the following conditions are met:
10
+ #
11
+ # * Redistributions of source code must retain the above copyright notice,
12
+ # this list of conditions and the following disclaimer.
13
+ # * Redistributions in binary form must reproduce the above copyright notice,
14
+ # this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ # * Neither the name of SNAPVINE nor the names of its contributors
17
+ # may be used to endorse or promote products derived from this software
18
+ # without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ require 'webrick/config'
32
+ require 'webrick/log'
33
+ require 'webrick/server'
34
+ require 'ragi/call_handler'
35
+ require 'ragi/call_connection'
36
+ require 'ragi/config'
37
+ require 'thread'
38
+
39
+ module RAGI
40
+ VERSION = "0.0.1"
41
+
42
+ @globalConfig = nil
43
+
44
+ def self.LOGGER
45
+ @logger ||= WEBrick::Log::new
46
+ @logger
47
+ end
48
+
49
+ def self.LOGGER=(logger)
50
+ @logger = logger
51
+ end
52
+
53
+ def self.globalConfig
54
+ # This assignment will make a dup
55
+ @globalConfig ||= RAGI::Config::Globals
56
+ @globalConfig
57
+ end
58
+
59
+ def self.globalConfig=(newConfig)
60
+ @globalConfig = newConfig.dup()
61
+ end
62
+
63
+ class CallServer
64
+ @incomingcallsocket = nil
65
+
66
+ # 4573 = asterisk AGI
67
+ # RAGI::CallHandler - default handler
68
+
69
+ def initialize(config = {}, default = RAGI::Config::Standard)
70
+ @config = default.dup.update(config)
71
+ @config[:Logger] ||= WEBrick::Log::new
72
+ @config[:ParentStopCallback] = @config[:StopCallback] if @config[:StopCallback]
73
+ @config[:StopCallback] = method('shutdown_done')
74
+
75
+ RAGI.LOGGER = @config[:Logger]
76
+
77
+ @mutex = Mutex.new
78
+ @signal = ConditionVariable.new
79
+ @running = true
80
+
81
+ if (@incomingcallsocket == nil)
82
+ begin
83
+ # code to executed in a thread
84
+ RAGI.LOGGER.info("#{self.class.name}: default-handler=#{@config[:DefaultHandler].to_s} port=#{@config[:Port]}")
85
+ @incomingcallsocket = WEBrick::GenericServer.new( @config )
86
+
87
+ @incomingcallsocket.start{ |sock|
88
+ cc = CallConnection.new(sock)
89
+
90
+ route = {
91
+ :handler => @config[:DefaultHandler],
92
+ :action => :dialup
93
+ }
94
+
95
+ # the default call handler comes from config environment.rb
96
+
97
+ if (cc.agi_url != nil && cc.agi_url != '/')
98
+ route = CallHandler.route(cc.agi_url)
99
+ end
100
+ RAGI.LOGGER.info("#{self.class.name}: processing call with #{route[:handler].to_s}")
101
+
102
+ CallHandler.process(route, cc)
103
+
104
+ # todo: Catch exceptions and say something to the user
105
+ # before we disconnect them. Something like this maybe:
106
+ #
107
+ # rescue StandardError => err
108
+ # if (cc) then
109
+ # cc.play_sound('tc/std/sorry-error')
110
+ # cc.hang_up()
111
+ # end
112
+ # raise
113
+ # end
114
+ }
115
+ RAGI.LOGGER.info("#{self.class.name}: server shutdown port=#{@config[:Port]}")
116
+
117
+ rescue StandardError => err
118
+ RAGI.LOGGER.error("#{err.message}")
119
+ RAGI.LOGGER.error(err.backtrace.join("\n"))
120
+ end
121
+
122
+ end
123
+ end
124
+
125
+ def shutdown
126
+ @incomingcallsocket.shutdown
127
+ end
128
+
129
+ def shutdown_done
130
+ RAGI.LOGGER.debug("#{self.class.name}: Shutdown complete")
131
+
132
+ @config[:ParentStopCallback].call if @config[:ParentStopCallback]
133
+ @mutex.synchronize do
134
+ @running = false
135
+ @signal.signal
136
+ end
137
+ end
138
+
139
+ def join
140
+ @mutex.synchronize do
141
+ if @running
142
+ @signal.wait(@mutex)
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,68 @@
1
+ #
2
+ # RAGI - Ruby classes for implementing an AGI server for Asterisk
3
+ # The BSD License for RAGI follows.
4
+ #
5
+ # Copyright (c) 2005, SNAPVINE LLC (www.snapvine.com)
6
+ # All rights reserved.
7
+
8
+ # Redistribution and use in source and binary forms, with or without
9
+ # modification, are permitted provided that the following conditions are met:
10
+ #
11
+ # * Redistributions of source code must retain the above copyright notice,
12
+ # this list of conditions and the following disclaimer.
13
+ # * Redistributions in binary form must reproduce the above copyright notice,
14
+ # this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ # * Neither the name of SNAPVINE nor the names of its contributors
17
+ # may be used to endorse or promote products derived from this software
18
+ # without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # config.rb -- Default configurations.
32
+ #
33
+
34
+ require 'webrick/config'
35
+ require 'ragi/call_handler'
36
+
37
+ module RAGI
38
+
39
+ DEFAULT_PORT = 4573
40
+
41
+ module Config
42
+
43
+ # for HTTPServer, HTTPRequest, HTTPResponse ...
44
+ Standard = WEBrick::Config::General.dup.update(
45
+ :Port => RAGI::DEFAULT_PORT,
46
+ :HandlerMap => {}
47
+ )
48
+
49
+ Globals = {
50
+ # Name of the box running the agi server, so that asterisk can find it
51
+ # by default this will use your Ruby server's name
52
+ "agiServer" => `hostname`.strip(),
53
+
54
+ # Path to use for saving outgoing call files
55
+ "outgoingCallPath" =>
56
+ ENV['RAGI_OUT_CALL_PATH'] ? ENV['RAGI_OUT_CALL_PATH'] : "var/spool/asterisk/outgoing",
57
+
58
+ # Path to use for saving wakeup call files
59
+ "wakeupCallPath" =>
60
+ ENV['RAGI_WAKEUP_CALL_PATH'] ? ENV['RAGI_WAKEUP_CALL_PATH'] : "var/spool/asterisk/wakeups",
61
+
62
+ # Path to the built-in sound files relative to the SIP server.
63
+ "sipSoundPath" =>
64
+ ENV['RAGI_SIP_SOUND_PATH'] ? ENV['RAGI_SIP_SOUND_PATH'] : "var/lib/asterisk/sounds"
65
+ }
66
+
67
+ end
68
+ end
Binary file
@@ -0,0 +1,23 @@
1
+ require "rubygems"
2
+ require "rake"
3
+
4
+ spec = Gem::Specification.new do |gem|
5
+ gem.name = "ragi"
6
+ gem.version = "1.0.0"
7
+ gem.author = "Joe Heitzeberg"
8
+ gem.email = "joe_AT_snapvine.com"
9
+ gem.homepage = "http://rubyforge.org/projects/ragi"
10
+ gem.platform = Gem::Platform::RUBY
11
+ gem.summary = "RAGI allows you to create useful telephony applications using Asterisk and Ruby [on Rails]."
12
+ gem.description = "RAGI allows you to create useful telephony applications using Asterisk and Ruby [on Rails]. Please see the included README file for more information"
13
+ gem.has_rdoc = false
14
+
15
+ gem.files = FileList['example-call-audio.mp3', 'ragi.gempsec', 'CHANGELOG', 'README', '*.rb', 'RAGI Overview_files/*', 'sample-apps/simon/*.rb', 'sample-apps/simon/sounds/README', 'sample-apps/simon/sounds/*.gsm'].to_a
16
+ gem.files.reject! { |fn| fn.include? "SVN" }
17
+ end
18
+
19
+ if $0 == __FILE__
20
+ Gem.manage_gems
21
+ Gem::Builder.new(spec).build
22
+ end
23
+
@@ -0,0 +1,94 @@
1
+ # RAGI -- Ruby Asterisk Gateway Interface
2
+ # See ragi.sourceforge.net for more information.
3
+ # Sponsored by SnapVine, Inc (www.snapvine.com)
4
+ #
5
+ # Class: SimonHandler
6
+ # Description: this call handler implements a simple memory game over the phone.
7
+ #
8
+
9
+ require 'ragi/call_handler'
10
+
11
+ class SimonHandler < RAGI::CallHandler
12
+ APP_NAME = 'simon'
13
+
14
+ # When the RAGI server connects from Asterisk over AGI to our app, it calls this method.
15
+ def dialup
16
+ answer # answer the call
17
+ wait(1) # give it 1 seconds to make sure the connection is established
18
+
19
+
20
+ playAgain = true
21
+ while (playAgain)
22
+ instructions # tell the caller how to play the game
23
+ score = play_game # start the game and play it, returning the score when done
24
+ announce_score(score) # tell them how they did
25
+ playAgain = ask_play_again # ask if they want to play again
26
+ end
27
+ say_goodbye
28
+ hang_up #end the call
29
+ end
30
+
31
+ def instructions
32
+ play_sound("simon-welcome")
33
+ end
34
+
35
+ def play_game
36
+
37
+ intArray = [rand(10)]
38
+ score = 0
39
+
40
+ # test the user's memory on the current int array
41
+ while memory_test(intArray)
42
+ score += 1
43
+
44
+ # grow the array by one digit
45
+ intArray << rand(10) # choose a number between 0 and 9 inclusive
46
+
47
+ wait(1)
48
+ end
49
+
50
+ score
51
+ end
52
+
53
+ def memory_test(intArray)
54
+ # say each number in the array
55
+ intArray.each do |number|
56
+ play_sound("simon-#{number}") # there are sounds like simon-6.gsm
57
+ end
58
+
59
+ # listen for user key presses (number of presses should be == intArray.length)
60
+ # Note: give about 1 second per key press (intArray.length * 1500)
61
+ resultStr = get_data("simon-beep", (intArray.length * 1500), intArray.length)
62
+
63
+ # Check if what they entered matches the int array
64
+ if (resultStr == intArray.join("")) # note: join converts from array to string
65
+ return true
66
+ else
67
+ play_sound("simon-gameover")
68
+ return false
69
+ end
70
+ end
71
+
72
+ def announce_score(score)
73
+ if (score <= 9)
74
+ play_sound("simon-score")
75
+ play_sound("simon-#{score.to_s}")
76
+ end
77
+ if (score < 5)
78
+ play_sound("simon-low")
79
+ elsif (score < 10)
80
+ play_sound("simon-medium")
81
+ else
82
+ play_sound("simon-high")
83
+ end
84
+ end
85
+
86
+ def ask_play_again
87
+ # Give the user three seconds to press a digit
88
+ return (get_data("simon-again", 3000, 1).length > 0)
89
+ end
90
+
91
+ def say_goodbye
92
+ play_sound("simon-goodbye")
93
+ end
94
+ end
@@ -0,0 +1,9 @@
1
+ These are the sounds needed for the simon sample app.
2
+
3
+ You'll need to copy these sounds directly to the default sounds directory on your Asterisk server (e.g. var/lib/asterisk/sounds/) in order to use the simon game app.
4
+
5
+ In the simon call handler, it plays these sounds using the playSound command, e.g.:
6
+ play_sound("simon-welcome")
7
+
8
+ This command tells the asterisk server to play the sound "simon-welcome.gsm" from the asterisk server's default sound location (e.g. var/lib/asterisk/sounds/simon-welcome.gsm)
9
+
@@ -0,0 +1,41 @@
1
+ #
2
+ # RAGI - Ruby classes for implementing an AGI server for Asterisk
3
+ # The BSD License for RAGI follows.
4
+ #
5
+ # Copyright (c) 2005, SNAPVINE LLC (www.snapvine.com)
6
+ # All rights reserved.
7
+
8
+ # Redistribution and use in source and binary forms, with or without
9
+ # modification, are permitted provided that the following conditions are met:
10
+ #
11
+ # * Redistributions of source code must retain the above copyright notice,
12
+ # this list of conditions and the following disclaimer.
13
+ # * Redistributions in binary form must reproduce the above copyright notice,
14
+ # this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ # * Neither the name of SNAPVINE nor the names of its contributors
17
+ # may be used to endorse or promote products derived from this software
18
+ # without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Class: start_ragi.rb
32
+ # This class provides a server to answer incoming AGI requests from Asterisk.
33
+ # It is configured to run the sample app, Simon.
34
+ #
35
+
36
+
37
+ require 'ragi/call_server'
38
+ require 'ragi/sample-apps/simon/simon_handler'
39
+
40
+ RAGI::CallServer.new( :DefaultHandler => SimonHandler )
41
+
data/test.rb ADDED
@@ -0,0 +1,109 @@
1
+ #
2
+ # RAGI - Ruby classes for implementing an AGI server for Asterisk
3
+ # The BSD License for RAGI follows.
4
+ #
5
+ # Copyright (c) 2005, SNAPVINE LLC (www.snapvine.com)
6
+ # All rights reserved.
7
+
8
+ # Redistribution and use in source and binary forms, with or without
9
+ # modification, are permitted provided that the following conditions are met:
10
+ #
11
+ # * Redistributions of source code must retain the above copyright notice,
12
+ # this list of conditions and the following disclaimer.
13
+ # * Redistributions in binary form must reproduce the above copyright notice,
14
+ # this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ # * Neither the name of SNAPVINE nor the names of its contributors
17
+ # may be used to endorse or promote products derived from this software
18
+ # without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ module RAGI
32
+ # This class is useful for writing unit tests
33
+ class TestSocket
34
+
35
+ def initialize(params, messages)
36
+ @params = params
37
+ @messages = messages
38
+ @inParams = true
39
+ @currentIndex = 0
40
+ end
41
+
42
+ def self.Exec(cmd, params)
43
+ [ "EXEC #{cmd} #{params}", "200 result=0"]
44
+ end
45
+
46
+ def self.GetData(soundfile, result)
47
+ ["GET DATA #{soundfile} 2000", "200 result=#{result} (timeout)"]
48
+ end
49
+
50
+ def self.StreamFile(soundfile, escapeDigits, initialOffset, result, endpos)
51
+ ["STREAM FILE #{soundfile} \"#{escapeDigits}\" #{initialOffset}",
52
+ "200 result=#{result} endpos=#{endpos}"]
53
+ end
54
+
55
+ def self.PlaySound(soundfile)
56
+ [ "EXEC playback #{soundfile}", "200 result=0"]
57
+ end
58
+
59
+ def self.SayNumber(number)
60
+ SayNumberFull(number, " \"*#\"")
61
+ end
62
+
63
+ def self.SayNumberFull(number, escapeDigits)
64
+ [ "SAY NUMBER #{number} \"#{escapeDigits}\"", "200 result=0"]
65
+ end
66
+
67
+ def self.HangUp()
68
+ [ "HANGUP", "200 result=0"]
69
+ end
70
+
71
+ def print(msg)
72
+ if @inParams
73
+ raise StandardError, "Should not receive commands until parameters are parse"
74
+ end
75
+
76
+ if (!@messages[@currentIndex])
77
+ raise StandardError, "Too many messages received\nMessage =#{msg}= received"
78
+ end
79
+
80
+ if (msg != @messages[@currentIndex][0])
81
+ raise StandardError, "Unexpected message received\nMessage =#{msg}= received\nExpected =#{@messages[@currentIndex][0]}"
82
+ end
83
+ end
84
+
85
+ def gets
86
+ if (@inParams) then
87
+ if (@currentIndex < @params.length) then
88
+ key = @params.keys[@currentIndex]
89
+ val = "#{key}: #{@params[@params.keys[@currentIndex]]}"
90
+ @currentIndex += 1
91
+ else
92
+ @currentIndex = 0
93
+ @inParams = false
94
+ val = ''
95
+ end
96
+ else
97
+ if (@currentIndex < @messages.length) then
98
+ val = @messages[@currentIndex][1]
99
+ @currentIndex += 1
100
+ else
101
+ raise StandardError, "Unexpected messages past end of test case"
102
+ @currentIndex = 0
103
+ val = '\n'
104
+ end
105
+ end
106
+ val
107
+ end
108
+ end
109
+ end