Ajax Demo Notes

You can send call info to a webpage in real-time with a little AJAX magic. There are a couple of ways to do this, but the simplest is to use two Javascript functions- setInterval() and XMLHttpRequest()– to constantly read the contents of a text file.

  • setInterval()takes 2 arguments. The first is the code to run, and the second is the amount of time in milliseconds bewteen running the code.
    • For example, setInterval(“loadCallData()”, 1000); will run the Javascript function “loadCallData()” every 1000 milliseconds, or 1 second.

More info on setInterval()

  • XMLHttpRequest()will load the contents of a URL into an object.
    • The contents don’t have to be strict XML or HTML. It will treat the returned contents as straight text.
    • For example, xmlhttp.open(“GET”,’callerid_info.txt’,false); will return the contents of a file called “callerid_info.txt”.

More info on XMLHttpRequest()

Here’s a very simple example of what the code may look like in Sinatra’s app.rb file:

require 'sinatra'
require 'data_mapper'

#------- set up database
DataMapper.setup(:default, {
  :adapter => 'yaml',
  :path => '/home/ck987/sinatra/digit-reader/db'})

#keypress model for database interaction
class Keypress
  include DataMapper::Resource
  property :id, Serial
  property :last_digit, String, :required => true
  property :last_callerid, String
end

# Main route - this is the form where we take the input
get '/' do
  erb :index
end

get '/digitinfo' do
  keypress = Keypress.get(1)
  "#{keypress.last_callerid},#{keypress.last_digit}"
end
#html template
__END__

@@index
<html>
  <head>
  <title>AGI to Ajax Demo</title>
  <script type="text/javascript">

function startLoop(){
  //check every 1 second
  setInterval("loadCallData()", 1000);
}

function loadCallData() {
  if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
     xmlhttp=new XMLHttpRequest();
  } else {// code for IE6, IE5
     xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
  //get caller ID
  xmlhttp.open("GET",'digit-reader/digitinfo',false);
  xmlhttp.send(null);
  var call_dig = xmlhttp.responseText.split(",");
  document.getElementById('callerID').innerHTML=call_dig[0];
  document.getElementById('button').innerHTML=call_dig[1];
}

</script>
</head>

<body onload="startLoop();">
<h3>Call x10:</h3>

Caller:
<div id="callerID">
none.
</div>
<br>
Button:
<div id="button">
none.
</div>
</body>
</html>

This web page will load the contents of “digit-reader/digitinfo” once a second and display it in the Divs “callerID” and “button”.

On the other side of the setup is a Ruby AGI acript that will write to a single row in a YAML file when the call begins, and will update the last_digit column of that row when ever the caller hits a button.

#!/usr/bin/ruby

require 'ruby-agi'
require 'data_mapper'   #for database integration

agi = AGI.new #new agi object

#set up database
DataMapper.setup(:default, {
 :adapter  => 'yaml',
 :path     => '/home/ck987/sinatra/digit-reader/db'})

 #keypress model for database interaction
 class Keypress
  include DataMapper::Resource
  property :id, 		Serial
  property :last_digit, 	String, :required => true
  property :last_callerid,	String
end

# Automatically create the tables if they don't exist
DataMapper.auto_upgrade!
# Finish setup
DataMapper.finalize
keypress = Keypress.first_or_create({:id => 1} , { :last_digit => '-' })
keypress.update(:last_callerid => agi.callerid)
# start agi scripting
agi.stream_file("vm-extension")
while true
	result = agi.wait_for_digit(-1) # wait forever
	if result.digit
	   keypress.update(:last_digit => result.digit)
	end
end

When the caller hangs up, Asterisk runs a small Ruby script that clears out the caller’s info from the files:

#!/usr/bin/ruby
require 'data_mapper'   #for database integration

#set up database
DataMapper.setup(:default, {
 :adapter  => 'yaml',
 :path     => '/home/ck987/sinatra/digit-reader/db'})

 #keypress model for database interaction
 class Keypress
  include DataMapper::Resource
  property :id, 			Serial
  property :last_digit, 	String, :required => true
  property :last_callerid,	String
end

# Automatically create the tables if they don't exist
DataMapper.auto_upgrade!
# Finish setup
DataMapper.finalize
keypress = Keypress.first_or_create({:id => 1} , { :last_digit => '-' })
keypress.update(:last_callerid => ' - ', :last_digit => ' - ')

Here’s what my dialplan looks like:

;----- AGI To WEB -----
[ck987_ajax]
exten => s,1,AGI(/home/ck987/asterisk_agi/digit_writer.rb)
;run a script to reset the database on hangup (This isn't agi, just a script)
exten => h,1,System(/home/ck987/asterisk_agi/digit_reset.rb)

The ‘h’ extension is run when a caller hangs up. It’s useful for doing clean-up operations like logging call times, or in this case, resetting our database.

Redial AJAX Demo