FreeSWITCH 简单图形化界面40 - 使用mod_curl模块进行http请求

FreeSWITCH 简单图形化界面40 - 使用mod_curl模块进行http请求

  • 0、界面预览
  • 00、简介
  • 1、编译安装
    • [1.1 编辑模块配置文件](#1.1 编辑模块配置文件)
  • 2、使用
    • [2.1 拨号规则](#2.1 拨号规则)
      • [GET 请求](#GET 请求)
      • [POST 请求](#POST 请求)
      • [JSON 数据](#JSON 数据)
    • [2.2 Lua 脚本](#2.2 Lua 脚本)
      • [GET 请求](#GET 请求)
      • [POST 请求](#POST 请求)
      • [JSON 数据](#JSON 数据)
  • [3 、示例](#3 、示例)
    • [3.1 示例 1:提交 CDR 到第三方接口](#3.1 示例 1:提交 CDR 到第三方接口)
    • [3.2 示例 2:提交外呼状态到第三方接口](#3.2 示例 2:提交外呼状态到第三方接口)

0、界面预览

http://myfs.f3322.net:8020/

用户名:admin,密码:admin

FreeSWITCH界面安装参考:https://blog.csdn.net/jia198810/article/details/137820796

00、简介

mod_curl是 FreeSWITCH 的一个强大模块,它允许用户通过 HTTP 请求与外部服务进行交互,从而实现数据的获取和提交。无论是简单的 GET 请求,还是复杂的 POST 请求和文件传输,mod_curl都能轻松应对。

1、编译安装

在使用mod_curl之前,需要确保该模块已正确编译并加载到 FreeSWITCH 中。以下是详细的编译和安装步骤:

1.1 编辑模块配置文件

  1. 打开 FreeSWITCH 源代码目录下的modules.conf文件,找到以下行并取消注释:
bash 复制代码
   #applications/mod_curl

保存文件并退出。

  1. 重新编译 FreeSWITCH

在终端中执行以下命令,重新编译 FreeSWITCH:

bash 复制代码
   make
   make install
  1. 加载模块

编辑 FreeSWITCH 的模块加载配置文件modules.conf.xml(路劲为/usr/local/freeswitch/conf/autoload_configs),添加以下内容:

xml 复制代码
   <load module="mod_curl"/>

保存文件后,重新加载 FreeSWITCH 以使模块生效。

  1. 验证模块加载

启动 FreeSWITCH 并进入 CLI,执行以下命令以验证mod_curl是否已正确加载:

bash 复制代码
   module_exists mod_curl

如果返回true,则表示模块加载成功。

2、使用

2.1 拨号规则

mod_curl提供了两种主要的应用方式:curlcurl_sendfile(不常用)。

在拨号规则中,可以通过以下方式调用curl应用:

xml 复制代码
<action application="curl" data="http://example.com/api?param=value"/>

curl应用的请求,会生成两个通道变量 curl_response_data 和curl_response_code,可以使用${}获取。

GET 请求

通过 URL 参数发送 GET 请求:

xml 复制代码
  <action application="curl" data="http://example.com/api?param=value"/>

POST 请求

发送 POST 请求并携带数据:

xml 复制代码
  <action application="curl" data="http://example.com/api post param=value"/>

JSON 数据

发送 JSON 格式的数据:

xml 复制代码
  <action application="curl" data="http://example.com/api content-type application/json post {\"key\":\"value\"}"/>

2.2 Lua 脚本

mod_curl也可以在 Lua 脚本中使用,通过 FreeSWITCH 的 API 接口调用 HTTP 请求。

GET 请求

在 Lua 脚本中发起 GET 请求的示例如下:

lua 复制代码
local api = freeswitch.API()

local url = "http://example.com/api?param=value"
local response = api:execute("curl", url)

freeswitch.consoleLog("INFO", "Response: " .. response .. "\n")

POST 请求

发送 POST 请求的示例如下:

lua 复制代码
local api = freeswitch.API()

local url = "http://example.com/api"
local data = "param=value"
local response = api:execute("curl", url .. " post " .. data)

freeswitch.consoleLog("INFO", "Response: " .. response .. "\n")

JSON 数据

发送 JSON 格式数据的示例如下:

lua 复制代码
local api = freeswitch.API()

local url = "http://example.com/api"
local json_data = "{ \"key\": \"value\" }"
local response = api:execute("curl", url .. " content-type application/json post " .. json_data)

freeswitch.consoleLog("INFO", "Response: " .. response .. "\n")

3 、示例

3.1 示例 1:提交 CDR 到第三方接口

在呼叫结束后,将通话详情记录(CDR)提交到第三方接口。以下是 Lua 脚本的实现示例:

lua 复制代码
#!/usr/bin/env lua
-- upload_cdr.lua
-- 2024年6月29日
-- 提交话单信息到第三方接口
-- 拨号规则,提前设置挂机回调
-- session:execute("set", string.format("api_hangup_hook=lua upload_cdr.lua")

-- 序列化并打印env对象的所有通话信息,调试专用
-- local call_info = env:serialize()
-- freeswitch.consoleLog("INFO", "所有通话信息:\n" .. call_info)
local mobile = env:getHeader("destination_number") or ""
local caller_ani = env:getHeader("Caller-ANI") or ""
local sip_account = env:getHeader("sip_from_user") or ""
local start_time = env:getHeader("start_stamp") or ""
-- local start_time = env:getHeader("answer_stamp") or ""
local end_time = env:getHeader("end_stamp") or ""
local use_time_length = env:getHeader("billsec") or "0"
local order_no = string.format("freeSWITCH%s%s", sip_account, mobile)
local mobile_hangup_api = env:getHeader("mobile_hangup_api") or ""
local api_timeout = env:getHeader("api_timeout") or "3"

-- 打印详细信息,确保变量不为空
if sip_account == mobile then
    freeswitch.consoleLog("INFO", "异常呼叫主叫=被叫,再次获取SIP账号为 : " .. caller_ani .. "\n")
    sip_account = caller_ani
end
freeswitch.consoleLog("INFO", "CallerANI    : " .. caller_ani .. "\n")
freeswitch.consoleLog("INFO", "SIP账号      : " .. sip_account .. "\n")
freeswitch.consoleLog("INFO", "被叫号码     : " .. mobile .. "\n")
freeswitch.consoleLog("INFO", "开始时间     : " .. start_time .. "\n")
freeswitch.consoleLog("INFO", "结束时间     : " .. end_time .. "\n")
freeswitch.consoleLog("INFO", "通话时长     : " .. use_time_length .. "\n")
freeswitch.consoleLog("INFO", "订单号       : " .. order_no .. "\n")
freeswitch.consoleLog("INFO", "CDR推送接口  : " .. mobile_hangup_api .. "\n")
freeswitch.consoleLog("INFO", "接口超时时间  : " .. api_timeout .. "\n")

-- 准备执行命令
local api = freeswitch.API();

--[[
-- 使用python提交
local cmd = string.format(
    "/usr/local/python310/bin/python /usr/local/freeswitch/scripts/upload_cdr.py '%s' '%s' '%s' '%s' '%s' '%s' '%s'",
    mobile, sip_account, start_time, end_time, use_time_length, order_no, mobile_hangup_api)
local response = api:execute("bg_system", cmd)
]]

-- 使用curl提交
local cmd = string.format(
    "%s connect-timeout %s timeout %s post mobile=%s&sip_account=%s&start_time='%s'&end_time='%s'&use_time_length=%s&order_no=%s",
    mobile_hangup_api, api_timeout, api_timeout, mobile, sip_account, start_time, end_time, use_time_length, order_no)
freeswitch.consoleLog("INFO", "推送命令: " .. cmd .. "\n")
local response = api:execute("curl", cmd)
if (response == "") then
    freeswitch.consoleLog("INFO", "推送结果: 无响应,可能连接接口失败!")
else
    freeswitch.consoleLog("INFO", "推送结果: " .. response .. "\n")
end

3.2 示例 2:提交外呼状态到第三方接口

在外呼结束后,将外呼状态提交到第三方接口。以下是 Lua 脚本的实现示例:

lua 复制代码
#!/usr/bin/env lua
-- handle-callout-result.lua
-- 2025年2月26日
-- 处理外呼结果 
-- 外呼api设置挂机回调。originate {origination_caller_id_number=300,orgination_caller_id_name=outcall,api_hangup_hook='lua handle-callout-result.lua'}sofia/gateway/gw01/172xxxx2122 401 xml Local-Extensions 

-- local env
-- local freeswitch

local call_info = env:serialize()
-- -- 序列化并打印env对象的所有通话信息,调试专用
-- freeswitch.consoleLog("INFO", "所有通话信息:\n" .. call_info)

-- 开始时间
local start_time = env:getHeader("start_stamp") or ""

-- 结束时间
local end_time = env:getHeader("end_stamp") or ""

-- 通话时间
local duration = env:getHeader("billsec") or "0"

-- SIP中继名称
local trunk_name = env:getHeader("trunk_name") or ""

-- 被叫号码
local destination_number = env:getHeader("destination_number") or ""

-- 本地号码
local local_number = env:getHeader("rdnis") or ""

-- 备用被叫号码
local sip_to_user = env:getHeader("sip_to_user") or ""

-- 呼出主叫号码
local outgoing_caller_id_number = env:getHeader("origination_caller_id_number") or ""

-- answer api
local answer_api = env:getHeader("answer_api") or ""

-- no_answer api
local no_answer_api = env:getHeader("no_answer_api") or ""

-- api 超时时间
local api_timeout = 3

-- 通话结果
local hangup_cause = env:getHeader("hangup_cause") or ""

-- 是否检查主叫号码被占用
local check_number_in_use = env:getHeader("check_number_in_use") or "false"

local response
local result
local temp_string

-- 打印详细信息,确保变量不为空
if destination_number == "" then
    freeswitch.consoleLog("INFO", string.format("# destination_number未空,使用sip_to_user的值%s\n",sip_to_user))
    destination_number = sip_to_user
end
freeswitch.consoleLog("INFO", "# ==============API接口外呼挂机处理============= \n")

freeswitch.consoleLog("INFO", "# ------------------外呼呼叫信息---------------- \n")
freeswitch.consoleLog("INFO", "# 开始时间  : " .. start_time .. "\n")
freeswitch.consoleLog("INFO", "# 结束时间  : " .. end_time .. "\n")
freeswitch.consoleLog("INFO", "# 通话时长  : " .. duration .. "\n")
freeswitch.consoleLog("INFO", "# 外呼号码  : " .. destination_number .. "\n")
freeswitch.consoleLog("INFO", "# 本地号码  : " .. local_number .. "\n")
freeswitch.consoleLog("INFO", "# 呼出主叫  : " .. outgoing_caller_id_number .. "\n")
freeswitch.consoleLog("INFO", "# 挂机接口  : " .. no_answer_api .. "\n")
freeswitch.consoleLog("INFO", "# ---------------------------------------------\n\n")

-- 执行fs api命令
local api = freeswitch.API();

-- 应答提交api,在401 xml Local-Extensions中。
-- if (hangup_cause == "ANSWER" or hangup_cause == "NORMAL_CLEARING") then
--     -- 呼叫应答提交
--     freeswitch.consoleLog("INFO", "# 呼叫结果  : 呼叫已经应答,推送应答接口\n")
--     if (answer_api == "") then
--         freeswitch.consoleLog("INFO", "# 推送结果  : 应答接口为空,不提交!\n")
--         return
--     else
--         -- 提交无应答结果
--         temp_string = string.format(
--             "%s connect-timeout %s timeout %s post destination_number=%s",
--             no_answer_api, api_timeout, api_timeout, destination_number)
--         freeswitch.consoleLog("INFO", string.format("# 推送结果  : 请求地址:%s\n",temp_string))

--         -- 执行推送
--         response = api:execute("curl",temp_string)
--         if (response == "") then
--             freeswitch.consoleLog("INFO", "# 推送结果  : 接口无响应,可能连接接口失败!\n")
--         else
--             freeswitch.consoleLog("INFO", "# 推送结果  : " .. response .. "\n")
--         end
--     end

freeswitch.consoleLog("INFO", "# ----------------外呼挂机处理-----------------\n")

if (hangup_cause  == "BUSY" or hangup_cause == "USER_BUSY" or hangup_cause == "NO_USER_RESPONSE" or hangup_cause == "NO_ROUTE_DESTINATION" or  hangup_cause == "CALL_REJECTED" or hangup_cause == "NO_ANSWER") then
    freeswitch.consoleLog("INFO", "# 挂机结果  : " .. hangup_cause .. "\n")
    -- 呼叫未应答提交
    freeswitch.consoleLog("INFO", "# 呼叫结果  : 呼叫未应答,推送未应答接口\n")
    if (no_answer_api == "") then
        freeswitch.consoleLog("INFO", "# 推送结果  : 未应答接口为空,不提交!\n")
        return
    else
        -- 提交无应答结果
        temp_string = string.format(
            "%s content-type application/json connect-timeout %s timeout %s post {\"destination_number\":\"%s\"}",
            no_answer_api, api_timeout, api_timeout, destination_number)
        freeswitch.consoleLog("INFO", string.format("# 推送结果  : 请求地址:%s\n",temp_string))
        -- 执行推送
        response = api:execute("curl", temp_string)
        if (response == "") then
            freeswitch.consoleLog("INFO", "# 推送结果  : 接口无响应,可能连接接口失败!\n")
        else
            freeswitch.consoleLog("INFO", "# 推送结果  : ".. response.. "\n")
        end
    end
elseif (hangup_cause  == "NORMAL_CLEARING") then
    freeswitch.consoleLog("INFO", "# 挂机结果   : " .. hangup_cause .. "\n")
    freeswitch.consoleLog("INFO", "# 挂机结果   : 通话正常挂断\n")
else
    freeswitch.consoleLog("INFO", "# 挂机结果   : " .. hangup_cause .. "\n")
end
freeswitch.consoleLog("INFO", "# ----------------------------------------------\n")

-- 如果要检查主叫号码是否被占用,则呼叫结束后,删除正在使用的主叫号码
if (check_number_in_use == "true") then
    freeswitch.consoleLog("INFO", string.format("# 通话已结束 : 开启了检查主叫号码占用,将释放主叫%s\n",outgoing_caller_id_number))
    -- 检查号码是否被占用
    temp_string = string.format(
        "delete/%s/number_in_use_%s",
        trunk_name, outgoing_caller_id_number)
    freeswitch.consoleLog("INFO", string.format("# 通话已结束 : 释放正在使用的主叫号码:%s\n",temp_string))
    result = api:execute("hash",temp_string)
    freeswitch.consoleLog("INFO", string.format("# 通话已结束 : 释放正在使用的主叫号码:%s\n",result))
end
freeswitch.consoleLog("INFO", "# ===============================================\n\n")
return

祝君好运

相关推荐
上官-王野15 分钟前
大模型day01自然语言+大模型+环境
python·ai·conda
dowhileprogramming1 小时前
Flask 框架简介
python·flask
凡人的AI工具箱1 小时前
PyTorch深度学习框架60天进阶学习计划第14天:循环神经网络进阶
人工智能·pytorch·python·深度学习·学习·ai编程
开开心心就好2 小时前
电脑睡眠智能管控:定时、依状态灵活调整,多模式随心选
javascript·windows·python·安全·django·pdf·电脑
q567315233 小时前
使用Lua和lua-resty-http-simple库的爬虫程序爬取图片
爬虫·http·lua
游王子3 小时前
springboot3 RestClient、HTTP 客户端区别
网络·网络协议·http
阿_旭3 小时前
基于YOLO11深度学习的电瓶车进电梯检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】
人工智能·python·深度学习·毕业设计·电瓶车检测