1. 基于RestClient的OpenSIPS呼叫处理方法:
  2. 宁卫通信
  3. 新闻动态
  4. 宁卫新闻
  5. 基于RestClient的OpenSIPS呼叫处理方法

基于RestClient的OpenSIPS呼叫处理方法

一、前言

      OpenSIPS是一个开源的SIP(会话初始协议)服务器,用于构建通信系统,在大并发、WebRTC、信令处理、高可靠性、媒体代理等方方面面有非常强的支撑能力。在OpenSIPS的丰富模块集合中,rest_client模块为OpenSIPS提供了向RESTful Web服务发起HTTP请求的能力。

以下是有关rest_client模块的详细描述:

二、概述

      rest_client模块允许你从OpenSIPS脚本中发起HTTP/HTTPS请求,与外部系统(如数据库、其他服务等)交互。使用这个模块,你可以将OpenSIPS集成到更广泛的生态系统中,从而实现更复杂的用例。

  当我们提到OpenSIPS与外部系统的集成,实际上我们是指OpenSIPS有能力与其他非SIP系统交互。rest_client模块提供了一个方便的桥梁,让OpenSIPS可以通过RESTful API与各种外部服务进行交互。

1.  集成与外部数据库

  尽管OpenSIPS本身支持多种数据库连接(如MySQLPostgreSQLNoSQL数据库等),但有时你可能需要与支持RESTful API的数据库进行交互。例如,你可能想从一个NoSQL数据库中获取数据,该数据库提供了HTTP API而不是传统的SQL接口。

2.  动态路由

  你可以使用rest_client从外部服务获取路由决策,从而在OpenSIPS中动态决定呼叫的目标或下一跳。但不建议这么用,尽量预加载模式,而不是次次向外部发请求,才是我们使用OpenSIPS的意义。

3.   认证与授权

  对于一些高级的认证方案(例如OAuth),你可能需要与一个认证服务器交互。rest_client可以帮助你完成这个过程。

4.   与其他微服务的交互

  现代的应用架构经常采用微服务的模式。rest_client模块可以使OpenSIPS轻松地与这些微服务进行交互,从而增强其功能。

5.   异步操作

  为了不阻塞OpenSIPS的主流程,你可以使用OpenSIPS的异步能力与rest_client结合,这样即使HTTP请求有延迟或需要较长时间来获得响应,也不会影响OpenSIPS的主要操作

三、具体操作

OpenSIPS的配置:

route{  if (is_method("INVITE")) { route(call_control); }}route[call_control] { $var(call-id)=$ci;  $var(from-uri)=$fu;  $var(from-user-id)=$fU; $avp(from-display-name)=$fn; $var(to-uri)=$tu; $var(to-user-id)=$rU; $avp(to-display-name)=$tn; $var(from-domain)=$fd; $var(to-domain)=$rd; $avp(agent)=$ua; $var(webserver)="http://127.0.0.1:8082";$var(request_body)='{"call-id":"'+$var(call-id)+'",'+ '"from-uri":"'+$var(from-uri)+'",'+ '"from-user-id":"'+$var(from-user-id)+'",'+ '"from-display-name":'+$avp(from-display-name)+','+ '"to-uri":"'+$var(to-uri)+'",'+ '"to-user-id":"'+$var(to-user-id)+'",'+ '"to-display-name":'+$avp(to-display-name)+','+ '"from-domain":"'+$var(from-domain)+'",'+ '"agent":"'+$avp(agent)+'",'+ '"source-ip":"'+$si+'",'+ '"method":"'+$rm+'",'+ '"to-domain":"'+$var(to-domain)+ '"}'; if (is_method("INVITE")) { xlog("L_INFO","在$cfg_line行处理,往$var(webserver)发送-->$var(request_body)"); async(rest_post("$var(webserver)/api/callcontrol",$var(request_body),"application/json", $var(response), $var(rtype),$var(rcode)), load_balance); } if (is_method("REGISTER")) { xlog("L_INFO","在$cfg_line行处理,往$var(webserver)发送-->$var(request_body)"); async(rest_post("$var(webserver)/api/callcontrol",$var(request_body),"application/json", $var(response), $var(rtype),$var(rcode)), load_balance); }} 


RestfulApi实现:

Rest API接口服务器,这次我们选择的是基于Golang开发GIN WEB服务框架

Gin是一个用Go(或称Golang)编写的HTTP web框架。由于其简洁的API、高性能和与Go语言的天然兼容性,它已经成为Go社区中最受欢迎的web框架之一。以下是基于GolangGin服务器的主要优势:

1. 性能

速度:Gin是一个非常快速的框架。它的路由器基于httprouter,被认为是Go中最快的HTTP路由器之一。

低内存占用:Go语言本身就为并发和高性能设计,与CJava相比,它通常使用更少的内存和CPU

2. 简洁性

简单的APIGin提供了一个直观而简洁的API,使开发人员能够迅速上手并构建强大的web应用程序。

中间件支持:像其他的web框架一样,Gin也支持中间件,使开发者可以轻松地插入功能,如日志、身份验证和跨站请求伪造(CSRF)防护。

3. 并发

GoroutinesGo语言的并发模型基于Goroutines,这些轻量级的线程使得Gin可以轻松处理数千甚至数百万的并发请求。

4. 模块化设计

可扩展:Gin允许你使用插件和中间件扩展其功能,这使得你可以为特定的应用程序或服务创建一个定制的Gin实例。

5. JSON验证

Gin内置支持JSON请求体的绑定和验证,这大大简化了API开发的过程。

6. 错误处理

Gin提供了一个方便的方法来捕获和处理错误,这有助于保持代码的整洁和可读性。

7. 社区与生态系统

Gin拥有一个活跃的社区,这意味着你可以容易地找到插件、中间件和解决常见问题的资源。

与其他Go库的兼容性:由于Gin是用Go编写的,它可以与Go生态系统中的其他库和工具轻松集成。

8. 跨平台

Go语言的其他产品一样,用Gin编写的应用程序也可以轻松地跨多个平台和操作系统进行部署。

结论

Gin是一个功能丰富、高性能的web框架,非常适合那些寻求速度和效率,并希望利用Go强大并发功能的开发者。无论是构建微服务、API还是完整的web应用程序,Gin都是一个出色的选择。

话不多说,基于Gin的代码片段呈现

main.go

func main() { //开启个协程进行监听是否ctrl+C关闭服务 sigs := make(chan os.Signal, 1) done := make(chan bool, 1) log.Printf("启动Gin服务") go func() { initdb.PostgresSQL() }() go func() { initdb.Redis() }() //启动GIN监听服务器端口 r := router.SetupRouter() r.Run(config.Gin_listen()) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) <-done log.Printf("接收到ctrl+C信号,程序开始关闭中...\n")} 


router.go

func SetupRouter() *gin.Engine { r := gin.Default() r.Use(gin.Recovery()) log.Println("启动Gin服务成功") r.POST("/api/callcontrol", control.Callcontrol) //呼叫逻辑控制 return r} 


model.go

type InviteBody struct { Source_ip       string `json:"source-ip"` Call_id         string `json:"call-id"` From_uri        string `json:"from-uri"` From_user_id    string `json:"from-user-id"` Display_name    string `json:"from-display-name"` To_uri          string `json:"to-uri"` To_user_id      string `json:"to-user-id"` To_display_name string `json:"to-display-name"` From_domain     string `json:"from-domain"` To_domain       string `json:"to-domain"` Agent           string `json:"agent"` Method          string `json:"method"`} 


control.go

func Callcontrol(c *gin.Context) { var inviteBody model.InviteBody if err := c.ShouldBindJSON(&inviteBody); err != nil { c.JSON(400, gin.H{"error": err.Error()}) return } jsonData, err := json.MarshalIndent(inviteBody, "", "  ") if err != nil { c.JSON(500, gin.H{"error": "Failed to marshal data"}) return }log.Printf("Invite消息请求内容:%s", string(jsonData))............(更多的逻辑代码自己编写)} 


然后我们就可以看到了两方协作,OpenSIPS向Restful发起请求后的输出:

[opsCall]2023/09/01 11:19:11 callcontrol.go:22: Invite消息请求内容:{ "source-ip": "72.167.53.131", "call-id": "1021992399-1605103198-803483289", "from-uri": "sip:5556@1.2.3.4", "from-user-id": "5556", "from-display-name": "", "to-uri": "sip:0046812111496@1.2.3.4", "to-user-id": "0046812111496", "to-display-name": "", "from-domain": "1.2.3.4", "to-domain": "1.2.3.4", "agent": "Linksys-SPA942", "method": "INVITE"} 


接下来,我们就可以根据获得的JSON结果,通过代码逻辑分析这一通的呼叫是呼入还是呼出,该如何进行变化号码,然后是转发给哪个SIP中继,还是拒绝呼叫,还是送到数据库去验证,还是.....(各种玩法都会产生出来)

总之,通过这种模式可以极大的扩展后续的各种业务。有时候在OpenSIPS上进行数据库方面的操作不是很方便,有时候需要进行各种逻辑判断,如果通过这种rest client方式进行接口对接方式来处理整个呼叫流程,那么将是一种非常方便快捷的来处理呼叫流程的实现方法。

譬如如果是这个IP过来的不允许呼叫,那么返回

{"code":403,"reason":"IP Auth Failed"}

Opensipsjson模块进行解析后,将返回的json结果进行解码后,根据403就可以直接返回一个结果:

send_reply("403", "Forbidden");

总之:

      OpensipsGin的强强联合可以将系统整体的呼叫并发发挥到极致。并且可以通过nginx代理转发模式分别转到多个Gin接口服务器上。性能不再是约束了。

  其实像Gin(Golang)一样强悍的API接口服务器还有很多种,譬如OpenResty(Lua),SpringBoot(Java)等等都可以实现这类的接口服务,如果你擅长PHP也是可以实现的。