Liverpie is truly language independent on the application end, but since Telegraph is a Rails thing, and Liverpie is also a Ruby thing, here's an example in Ruby on Rails.
Writing state machines is trivial. If you write a web-based state machine in any language, that works with Liverpie, and you want to see your code in the demo lists, please send it to me.
The more languages to demo, the better!
So this is the example in Ruby. The IVR thread is as follows: first it says welcome, then it asks for an extension number, and it'll ask 3 times if you don't give it within 10 seconds. Then it logs the number and hangs up the line. Simple!
Oh, if you're running Rails > 2, remember to disable the authentication in application.rb or explicitely for this controller.
class IvrController < ApplicationController # We use just a little Ruby magic to generate get_ and set_ methods so we # can easier access the session object, where our state machine keeps its # state. This is optional, but it'll let you say set_something(7) instead of # session['something'] = 7, and get_something instead of # session['something']. def self.session_variables(*vars) vars.each do |var| define_method('get_'+var.to_s) { session[var] } define_method('set_'+var.to_s) { |value| session[var] = value } end end session_variables :tries, :extno, :next_step # The main method of the state machine def state_machine if get_next_step.nil? render :text => '' else eval(get_next_step.split(' ').first) end end # Reset the state machine to its initial state def reset set_next_step 'say_welcome' render :text => 'state machine reset' # ignored by Liverpie anyway end private # # IVR / State Machine steps below # def say_welcome set_tries 1 set_extno nil msg = send_msg 'playback', 'ivr/8000/ivr-welcome_to_freeswitch.wav', true fs_render msg, 'event_name', 'CHANNEL_EXECUTE_COMPLETE' set_next_step 'askfor_extno' end def askfor_extno if get_tries > 3 hangup else msg = send_msg "read", "0 10 ivr/8000/ivr-enter_ext.wav extno 10000 #,*" fs_render msg, 'event_name', 'CHANNEL_EXECUTE_COMPLETE' set_next_step 'read_extno' end end def read_extno session[:tries] += 1 set_extno params['variable_extno'] logger.info "EXTENSION NUMBER: #{get_extno}" fs_render 'api sleep 1', 'content_type', 'api/response' # sorta noop if get_extno.to_s.empty? set_next_step 'askfor_extno' else set_next_step 'hangup' end end def hangup uuid = params['unique_id'].to_s msg = "SendMsg #{uuid}\ncall-command: hangup\n" msg << "hangup-cause: SERVICE_NOT_IMPLEMENTED" fs_render msg, 'event_name', 'CHANNEL_EXECUTE_COMPLETE' set_next_step nil end # # Methods specific to FreeSWITCH below # def send_msg(app, pars, blocking=true) uuid = params['unique_id'].to_s msg = "SendMsg #{uuid}\ncall-command: execute\nexecute-app-name: #{app}" msg << "\nexecute-app-arg: #{pars}" msg << "\nevent-lock:true" if blocking end def fs_render(msg, expected_key, expected_value) hash = { 'msg' => msg.to_s, 'expected_key' => expected_key, 'expected_value' => expected_value } render :text => hash.to_yaml end end
Put this controller into your Rails application. The URIs are obviously the ones I included in the example liverpie.yml. Try it from your browser, then by calling the configured extension in FreeSWITCH. The extension number you key in should appear in the Rails application log. (As you can see in the code, that number can have up to 10 digits, or end by * or #.)
This has been contributed by Adeel Ansari and it worked with Tomcat. It needs Liverpie >= 0.2
public class IVRServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().write("reset"); // not needed though } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String uuid = StringUtils.trimToEmpty(request.getParameter("unique_id")); String extNo = StringUtils.trimToEmpty(request.getParameter("variable_extno")); HttpSession session = request.getSession(); String responseStr = null; if (session.getAttribute("next-step") == null) { responseStr = sayWelcome(uuid, session); } else if (((String) session.getAttribute("next-step")).equals("askForExt")) { responseStr = askForExt(uuid, session); } else if (((String) session.getAttribute("next-step")).equals("readExt")) { responseStr = readExt(extNo, session); } else if (((String) session.getAttribute("next-step")).equals("hangup")) { responseStr = hangup(uuid, session); } System.out.println(responseStr); // to print the yaml to console response.getWriter().print(responseStr); response.getWriter().flush(); } String sayWelcome(String uuid, HttpSession session) { session.setAttribute("tries", 1); session.setAttribute("extNo", null); session.setAttribute("next-step", "askForExt"); String msg = createMessage(uuid, "playback", "ivr/8000/ivr-welcome_to_freeswitch.wav"); return formatMessageToYaml(msg, "event_name", "CHANNEL_EXECUTE_COMPLETE"); } String askForExt(String uuid, HttpSession session) { Integer tries = (Integer) session.getAttribute("tries"); if (tries > 3) { return hangup(uuid, session); } else { session.setAttribute("next-step", "readExt"); String msg = createMessage(uuid, "read", "0 10 ivr/8000/ivr-enter_ext.wav extno 10000 #,*"); return formatMessageToYaml(msg, "event_name", "CHANNEL_EXECUTE_COMPLETE"); } } String readExt(String extNo, HttpSession session) { Integer tries = (Integer) session.getAttribute("tries") + 1; session.setAttribute("tries", tries); session.setAttribute("extNo", extNo); if (StringUtils.isBlank(extNo)) { session.setAttribute("next-step", "askForExt"); } else { session.setAttribute("next-step", "hangup"); } return formatMessageToYaml("api sleep 1", "content_type", "api/response"); } String hangup(String uuid, HttpSession session) { session.setAttribute("next-step", null); String msg = "SendMsg " + uuid + "\n call-command: hangup\n hangup-cause: SERVICE_NOT_IMPLEMENTED"; return formatMessageToYaml(msg, "event_name", "CHANNEL_EXECUTE_COMPLETE"); } private String createMessage(String uuid, String app, String args) { return "SendMsg " + StringUtils.trimToEmpty(uuid) + "\n call-command: execute \n " + "execute-app-name: " + app + "\n execute-app-arg: " + args + "\n event-lock: true"; } private String formatMessageToYaml(String msg, String expectKey, String expectValue) { return "---\nmsg: |- \n " + msg + "\nexpected_key: " + expectKey + "\nexpected_value: " + expectValue; } }
© 2008, 2009 Alex Deva, Jonathan Palley. Web design by Loreley Petroiu.
