More FreeSWITCH ruby love - FXC on the way
With FSR well under way and being used both internally and in the wild for FreeSWITCH application development, the next logical step will be a Configurator for FreeSWITCH itself.
FreeSWITCH has long lacked the standard Administrator/User configuration available via web or GUI, FXC is intended to allow web interfaces for configuration to be built easily with any Rack application utilizing the FreeSWITCH xml_curl
interface.
The first pass of FXC will include some Rack middleware which turns FreeSWITCH requests (to /
) into easy to organize routes such as /directory/register/internal/1000
, /dialplan/public/8885551212
, /configuration/acl.conf
.
The goal is to eliminate the gruntwork of routing by POST variables, exposing clean Rack-app routes up the stack (for ramaze, sinatra, etc).
The following is an example with Ramaze.
middleware.rb
module FXC
module Rack
class Middleware
def initialize(app)
@app = app
end
def call(env)
r = ::Rack::Request.new(env)
return @app.call(env) unless r.params["section"]
path = r.params["section"] + "/"
path << case path
when "dialplan/"
dp_req(env, r)
when "directory/"
dir_req(env, r)
when "configuration/"
conf_req(env, r)
end
env["PATH_INFO"] << (env["PATH_INFO"].match(%r{/$}) ? path : "/#{path}")
@app.call(env)
end
private
def dp_req(env, r)
s = [r.params["Caller-Context"]]
s << r.params["Caller-Destination-Number"]
s.join("/")
end
def dir_req(env, r)
s = []
if r.params["purpose"]
s << r.params["purpose"].gsub("-","_")
s << r.params["sip_profile"]
elsif r.params["action"] and r.params["action"] == "sip_auth"
s << "register"
s << r.params["sip_profile"]
s << r.params["sip_auth_username"]
elsif r.params["user"]
s << "voicemail"
s << r.params["sip_profile"]
s << r.params["user"]
end
s.join("/")
end
def conf_req(env, r)
s = []
if r.params["key_name"] == "name"
s << r.params["key_value"]
end
s.join("/")
end
end
end
end
controller/dialplan.rb
module FXC
class Dialplan < Controller
map '/dialplan'
layout :dialplan
def index(*args)
Ramaze::Log.info("Got unhandled dialplan request: #{request.inspect}")
not_found
end
def default(number)
Ramaze::Log.info("got default dialplan request for #{number}")
not_found
end
def public(number)
@did = FXC::Did.first(:number.like /#{number.sub(/^1/,'1?')}/)
if @did
@user = @did.user
@targets = @did.targets
Ramaze::Log.info("Routing #{@did.number} to #{@user.dialstring}")
render_view(:index)
else
Ramaze::Log.info("Got public dialplan request for #{number}, but no DID matches: ")
not_found
end
end
end
end
In the FXC::Dialplan controller, each method represents a FreeSWICH dialplan context. Undefined contexts (in this ramaze controller) will fallthrough to the index method and be logged.
Finally, the FreeSWITCH configuration to send requests to above app becomes a single line / single url.
conf/autoload_configs/xml_curl.conf.xml
<configuration name="xml_curl.conf" description="cURL XML Gateway">
<bindings>
<binding name="fxc">
<param name="gateway-url" value="http://127.0.0.1:9292/" bindings="configuration|directory|dialplan"/>
</binding>
</bindings>
</configuration>
Next step is completing all the methods available for each binding type (configuration, dialplan, directory). Once complete FreeSWITCH web config on Rack should follow rapidly. That will be the “Look Ma, No XML” FXC release (TBA).