Created
August 31, 2011 16:27
-
-
Save libryder/1183954 to your computer and use it in GitHub Desktop.
Web component of restful_clicktocall
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
begin | |
require 'rack' | |
require 'json' | |
rescue LoadError | |
abort "ERROR: restful_rpc requires the 'rack' and 'json' gems" | |
end | |
# Don't you love regular expressions? Matches only 0-255 octets. Recognizes "*" as an octet wildcard. | |
VALID_IP_ADDRESS = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|\*)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|\*)$/ | |
def ip_allowed?(ip) | |
raise ArgumentError, "#{ip.inspect} is not a valid IP address!" unless ip.kind_of?(String) && ip =~ VALID_IP_ADDRESS | |
octets = ip.split "." | |
case COMPONENTS.restful_rpc["access"] | |
when "everyone" | |
true | |
when "whitelist" | |
whitelist = COMPONENTS.restful_rpc["whitelist"] | |
!! whitelist.find do |pattern| | |
pattern_octets = pattern.split "." | |
# Traverse both arrays in parallel | |
octets.zip(pattern_octets).map do |octet, octet_pattern| | |
octet_pattern == "*" ? true : (octet == octet_pattern) | |
end == [true, true, true, true] | |
end | |
when "blacklist" | |
blacklist = COMPONENTS.restful_rpc["blacklist"] | |
! blacklist.find do |pattern| | |
pattern_octets = pattern.split "." | |
# Traverse both arrays in parallel | |
octets.zip(pattern_octets).map do |octet, octet_pattern| | |
octet_pattern == "*" ? true : (octet == octet_pattern) | |
end == [true, true, true, true] | |
end | |
else | |
raise Adhearsion::Components::ConfigurationError, 'Unrecognized "access" configuration value!' | |
end | |
end | |
RESTFUL_API_HANDLER = lambda do |env| | |
json = env["rack.input"].read | |
# Return "Bad Request" HTTP error if the client forgot | |
return [400, {}, "You must POST a valid JSON object!"] if json.blank? | |
json = JSON.parse(json) | |
nesting = COMPONENTS.restful_rpc["path_nesting"] | |
path = env["PATH_INFO"] | |
return [404, {}, "This resource does not respond to #{path.inspect}"] unless path[0...nesting.size] == nesting | |
path = path[nesting.size..-1] | |
return [404, {"Content-Type" => "application/json"}, "You cannot nest method names!"] if path.include?("/") | |
rpc_object = Adhearsion::Components.component_manager.extend_object_with(Object.new, :rpc) | |
# TODO: set the content-type and other HTTP headers | |
response_object = rpc_object.send(path, *json) | |
if response_object.kind_of? String | |
return [200, {"Content-Type" => "application/json"}, response_object.to_a.to_json] | |
elsif response_object.kind_of? Hash | |
return [200, {"Content-Type" => "application/json"}, response_object.to_json] | |
else | |
return [200, {"Content-Type" => "application/json"}, response_object.headers.to_json] | |
end | |
end | |
initialization do | |
config = COMPONENTS.restful_rpc | |
api = RESTFUL_API_HANDLER | |
port = config["port"] || 5000 | |
authentication = config["authentication"] | |
show_exceptions = config["show_exceptions"] | |
handler = Rack::Handler.const_get(config["handler"] || "Mongrel") | |
if authentication | |
api = Rack::Auth::Basic.new(api) do |username, password| | |
authentication[username] == password | |
end | |
api.realm = "Adhearsion API" | |
end | |
if show_exceptions | |
api = Rack::ShowStatus.new(Rack::ShowExceptions.new(api)) | |
end | |
Thread.new do | |
handler.run api, :Port => port | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rubygems' | |
require 'sinatra' # Get with "gem install sinatra" | |
require 'restful_adhearsion' | |
require 'pp' | |
#Create our Adhearsion object connected to the RESTful API of Adhearsion | |
Adhearsion = RESTfulAdhearsion.new(:host => "localhost", | |
:port => 5000, | |
:user => "jicksta", | |
:password => "roflcopterz") | |
# You'll need to change this for your own format. | |
# Note: this will soon be handled by the Call Routing DSL in Adhearsion. | |
def format_number(number) | |
if number.length == 10 | |
return "SIP/tsgglobal/1#{number}" | |
elsif number.length == 11 | |
return "SIP/tsgglobal/#{number}" | |
else | |
return "SIP/elastix-trunk/#{number}" | |
end | |
end | |
def call_with_source(source) | |
#ahn_log.click_to_call "Finding call with source #{source.inspect} in #{Adhearsion.active_calls.size} active calls" | |
retVal = Hash.new | |
Adhearsion.active_calls.to_a.find do |call| | |
if call.variables[:sourcedid].include? source | |
if (defined? call.variables[:msg_filename] && call.variables[:msg_filename] != nil) | |
retVal[:msg_filename] = call.variables[:msg_filename] | |
retVal[:result] = "alive" | |
end | |
else | |
retVal[:msg_filename] = nil | |
retVal[:result] = "dead" | |
end | |
return retVal | |
end | |
end | |
post "/call" do | |
options = { :channel => format_number(params[:source]), | |
:context => "adhearsion", | |
:priority => "1", | |
:callerid => "8664680900", | |
:exten => "1000", | |
:async => 'true', | |
:variable => "destination=#{format_number(params[:destination])},sourcedid=#{params[:source]}", | |
} | |
#Originates a call over the AMI interface | |
Adhearsion.originate(options) | |
#puts options.to_json | |
"ok".to_json | |
end | |
post "/hangup" do | |
#Get the channel of the active call, then hang it up | |
channel_of_active_call = Adhearsion.hangup_channel_with_destination params[:call_to_hangup] | |
"ok".to_json | |
end | |
get '/status' do | |
# The line below will return either {result:"alive"} or {result:"dead"} to the browser | |
Adhearsion.call_with_source(params[:source]).to_json | |
#{:result => Adhearsion.call_with_source(params[:source])}.to_json | |
end | |
get '/' do | |
#Build our web form that has the JQuery sprinkled in | |
<<-HTML | |
<html><head> | |
<title>Record a greeting</title> | |
<script src="jquery.js" type="text/javascript"></script> | |
<script src="call.js" type="text/javascript"></script> | |
<link href="style.css" media="screen" rel="stylesheet" type="text/css" /> | |
</head><body> | |
<div id="content"> | |
<h1>Record a greeting</h1> | |
<div id="call-form"> | |
<p><label for="source">Your number: </label><input type="text" id="source" name="source"/></p> | |
<p><button onclick="new AhnCall($('#call'), $('#source').val(), $('#destination').val())">Start call</button></p> | |
<input type="hidden" name="destination" value="1" /> | |
</div> | |
</div> | |
<div id="call" class="hidden"> | |
<p>Starting...</p> | |
</div> | |
</body></html> | |
HTML | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment