You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
voicebot/icssessionmanager/sessionoperator.go

448 lines
12 KiB
Go

package icssessionmanager
import (
"runtime"
"runtime/debug"
"strconv"
"strings"
"time"
"gitlab.com/cinnamon/voiceagent/icsconf"
"gitlab.com/cinnamon/voiceagent/icserror"
"gitlab.com/cinnamon/voiceagent/icshttpclient"
"gitlab.com/cinnamon/voiceagent/icslog"
"gitlab.com/cinnamon/voiceagent/icsnet"
"gitlab.com/cinnamon/voiceagent/icspacketparser"
"gitlab.com/cinnamon/voiceagent/recorddata/readcallsignal"
"gitlab.com/cinnamon/voiceagent/recorddata/responsecs"
)
//////////////////////////////////////////////////////////////////
//session operator
func findSessionWithCallID(callId string) *IcsSession {
sessions := getSessionInstance()
for _, session := range sessions {
session.m.Lock()
if strings.Compare(session.callId, callId) == 0 {
session.m.Unlock()
return session
}
session.m.Unlock()
}
return nil
}
func findSessionWithStation(station string) *IcsSession {
sessions := getSessionInstance()
for _, session := range sessions {
session.m.Lock()
//fmt.Printf("findsessionWithStation: %s, %s\n", session.Station, station)
if strings.Compare(session.Station, station) == 0 {
session.m.Unlock()
return session
}
session.m.Unlock()
}
return nil
}
func findSessionWithBotToken(token string) *IcsSession {
sessions := getSessionInstance()
for _, session := range sessions {
session.m.Lock()
//fmt.Printf("findsessionWithStation: %s, %s\n", session.Station, station)
if strings.Compare(session.botToken, token) == 0 {
session.m.Unlock()
return session
}
session.m.Unlock()
}
return nil
}
func findSessionWithRTPPort(srcPort int, dstPort int) *IcsSession {
sessions := getSessionInstance()
for _, session := range sessions {
session.m.Lock()
if (session.srcPort == srcPort && session.dstPort == dstPort) || (session.srcPort == dstPort && session.dstPort == srcPort) {
session.m.Unlock()
return session
}
session.m.Unlock()
}
return nil
}
/* 미사용 코드로 임시 주석 처리 ( csma 210512 )
func FindSessionID(sip icspacketparser.SIP) (IcsSessionID, *icserror.IcsError) {
callID := sip.GetCallID()
if len(callID) > 0 {
session := findSessionWithCallID(callID)
if session != nil {
return IcsSessionID(session.ID), nil
}
}
return IcsSessionID(-1), icserror.ICSERRSESSNotFoundSession
}
*/
func FindSession(data interface{}) (*IcsSession, *icserror.IcsError) {
//func FindSession(sip icspacketparser.SIP) (*IcsSession, *icserror.IcsError) {
switch v := data.(type) {
case icspacketparser.SIP:
sip := v
callID := sip.GetCallID()
/*
if sip.Method == icspacketparser.ICS_SIP_METHOD_BYE || sip.Method == icspacketparser.ICS_SIP_METHOD_CANCEL {
//fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>", callID)
}
*/
if len(callID) > 0 {
session := findSessionWithCallID(callID)
if session != nil {
return session, nil
}
}
case icspacketparser.RTP:
rtp := v
srcPort := rtp.SrcAddr.Port
dstPort := rtp.DstAddr.Port
session := findSessionWithRTPPort(srcPort, dstPort)
if session != nil {
return session, nil
}
case *readcallsignal.CallSignal:
//case icspacketparser.CallSignal:
cs := v
session := findSessionWithStation(cs.Station)
//fmt.Println("FindSession cs!", cs.Station, cs, session)
if session != nil {
return session, nil
}
//default:
//fmt.Printf(">>>>>>>>>>>>>>>>>>%v-----%T\n", v, v)
}
return nil, icserror.ICSERRSESSNotFoundSession
}
/* 미사용 코드로 임시 주석 처리 ( csma 200512 )
func AllocSessionID(callId string, direction bool) (IcsSessionID, *icserror.IcsError) {
if len(callId) == 0 {
return IcsSessionID(-1), icserror.ICSERRInvalidParam
}
sessions := getSessionInstance()
var id int
for _, session := range sessions {
id++
if len(session.callId) == 0 {
session.callId = callId
session.direction = direction
return IcsSessionID(session.ID), nil
}
}
if id >= channelNum {
return IcsSessionID(-1), icserror.ICSERRSESSMaxSessionNumber
}
return IcsSessionID(-1), icserror.ICSERRSESSNotFoundSession
}
*/
func goid() int {
var buf [64]byte
n := runtime.Stack(buf[:], false)
idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
id, err := strconv.Atoi(idField)
if err != nil {
return -1
}
return id
}
func AllocSession(channelID string, serverID string, station string, callId string, direction bool) (*IcsSession, *icserror.IcsError) {
/*
if len(callId) == 0 {
return nil, icserror.ICSERRInvalidParam
}
*/
l := icslog.GetIcsLog()
sessions := getSessionInstance()
var id int = 0
for _, session := range sessions {
id++
session.m.Lock()
if len(session.Station) == 0 {
//if len(session.callId) == 0 || len(session.Station) == 0 {
session.ChannelID = channelID
session.ServerID = serverID
session.Station = station
session.callId = callId
session.direction = direction
session.txSeq = -1
session.rxSeq = -1
session.isSTTStart = false
/*/////////////////
fname := fmt.Sprintf("./rx_%03d.voice.g729", id)
session.rxFile, _ = os.OpenFile(fname, os.O_CREATE|os.O_WRONLY, 0644)
fname = fmt.Sprintf("./tx_%03d.voice.g729", id)
session.txFile, _ = os.OpenFile(fname, os.O_CREATE|os.O_WRONLY, 0644)
*/ /////////////////
session.m.Unlock()
l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Session[%d] Allocated(%d). Station: %s ==========================",
session.ID, session.goroutineID, session.Station)
return session, nil
}
session.m.Unlock()
}
if id >= channelNum {
return nil, icserror.ICSERRSESSMaxSessionNumber
}
return nil, icserror.ICSERRSESSNotFoundSession
}
func (s *IcsSession) RemoveSession() *icserror.IcsError {
l := icslog.GetIcsLog()
defer func() {
if err := recover(); err != nil {
switch v := err.(type) {
case error:
icserror.ICSERRNETNotConnectError.SetError(v)
l.Printf(icslog.LOG_LEVEL_WARN, s.ID, "PANIC! %s\n%s", icserror.ICSERRNETNotConnectError.GetError().Error(), string(debug.Stack()))
default:
l.Print(icslog.LOG_LEVEL_WARN, s.ID, icserror.ICSERRNETNotConnectError.GetMessage())
}
}
}()
//s.VoiceNeter.Close()
//s.CallSignalNeter.Close()
//id := s.ID
//s = &IcsSession{ID: id}
//s.rxFile.Close()
//s.txFile.Close()
e := &IcsSession{}
s.m.Lock()
s.eventSystem.ClearJob()
s.callId = e.callId
s.Station = e.Station
s.srcPort = e.srcPort
s.dstPort = e.dstPort
s.direction = e.direction
s.isStart = 0
s.dtmf = ""
//bot
s.url = e.url
s.custid = e.custid
s.sstation = e.sstation
s.isFoundPayload = false
if s.RxConverter != nil {
s.RxConverter.Close()
s.RxConverter = nil
}
if s.TxConverter != nil {
s.TxConverter.Close()
s.TxConverter = nil
}
s.botStatus = nil
s.botToken = ""
s.isSTTStart = false
s.txSeq = -1
s.rxSeq = -1
s.MethodAutomata = 0
s.m.Unlock()
l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Removed Session[%d] ==========================", s.goroutineID)
return nil
}
func GetSession(sessionID IcsSessionID) (*IcsSession, *icserror.IcsError) {
if sessionID < IcsSessionID(0) {
return nil, icserror.ICSERRInvalidParam
}
sessions := getSessionInstance()
return sessions[int(sessionID)], nil
}
func (s IcsSession) GetSessionID() IcsSessionID {
return IcsSessionID(s.ID)
}
func (s *IcsSession) CheckSignalMethod(sip icspacketparser.SIP) *icserror.IcsError {
if s.CheckAutomata(&sip) {
if s.MethodAutomata != ICS_SIP_AUTOMATA_CANCEL {
s.SetSessionMethod(sip)
}
} else {
//fmt.Println("^^^^^", "unMatched Automata", s.MethodAutomata, sip.Method)
}
if sip.Method == icspacketparser.ICS_SIP_METHOD_SIP20 && strings.Contains(sip.Cseq, " BYE") || s.MethodAutomata == ICS_SIP_AUTOMATA_CANCEL && sip.Method == icspacketparser.ICS_SIP_METHOD_ACK {
//fmt.Println("^^^^^", "call s.RemoveSession() sip.Method, s.MethodAutomata ", sip.Method, s.MethodAutomata)
serr := s.RemoveSession()
if serr != nil {
//serr.Print()
return serr
}
}
return nil
}
//////////////////////////////////////////////////////////////////
//
func (s *IcsSession) SetTimestamp(now time.Time) {
s.lastTimestamp = now
}
func (s IcsSession) GetPayloadType() icspacketparser.PayloadType {
return s.payloadType
}
func (s *IcsSession) GetDirection() bool {
return s.direction
}
func (s IcsSession) GetCallID() string {
return s.callId
}
func (s IcsSession) GetBotToken() string {
return s.botToken
}
func (s *IcsSession) SetAgentConfig(agentconf *icsconf.AgentConfig) {
s.AgentConfig = agentconf
}
func (s *IcsSession) FindAgentConfig(agentID string) *icsconf.AgentConfig {
conf := icsconf.GetIcsConfig()
//a := strings.SplitN(agentID, string(0), 2)
for _, agentconf := range conf.AgentConfig {
//fmt.Printf("308LINE iter: %d, [%v] [%v] [%v]\n", iter, []byte(agentconf.Name), []byte(agentID), []byte(a[0]))
if strings.Contains(agentID, agentconf.Name) {
//fmt.Println(">>>>", iter, agentconf.Name)
return &agentconf
}
}
return nil
}
func (s *IcsSession) SendVoiceGatewayByeSignal() {
l := icslog.GetIcsLog()
conf := icsconf.GetIcsConfig()
agentname := s.AgentConfig.Name
telno := s.botStatus.Data.TelNo
l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "###### Start BYE Message!!!!!!!!!")
r := responsecs.NewResponse(agentname, telno, responsecs.BYE_COMMAND, responsecs.RC_SUCCESS, 0)
addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port)
wlen, werr := icsnet.SendByeSignal(&addr, nil, r.GetData())
if werr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send BYE to Voice Gateway - %s [%+v]",
werr.GetError(), s.TcpConn)
}
l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent BYE message to VoiceGateway: %d", wlen)
// 윗쪽에서 코드를 봐야함!!
s.Stop()
serr := s.RemoveSession() // 세션을 날려야 바로 전화를 걸었을때 새로 받아짐
if serr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "RemoveSession Error %s", serr.GetMessage())
}
}
func (s *IcsSession) SendVoiceGatewayBotByeSignal(url string, custid string, sstation string) { // Send Bot HANGUP Message
l := icslog.GetIcsLog()
conf := icsconf.GetIcsConfig()
agentname := s.AgentConfig.Name
telno := s.botStatus.Data.TelNo
l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "###### Start BYE Message!!!!!!!!!")
r := responsecs.NewResponse(agentname, telno, responsecs.BYE_COMMAND, responsecs.RC_SUCCESS, 0)
addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port)
wlen, werr := icsnet.SendByeSignal(&addr, nil, r.GetData())
if werr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send BYE to Voice Gateway - %s [%+v]",
werr.GetError(), s.TcpConn)
}
l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent BYE message to VoiceGateway and Bot: %d", wlen)
processResp := icshttpclient.PostProcess(url, "HANGUP", "", custid, "ICS_RCP", s.callId, sstation, s.botToken, "")
if processResp == nil {
l.Print(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error")
}
//close voiceneter
verr := s.VoiceNeter.Close()
if verr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to close Voice port - %s", verr.GetError())
} else {
l.Print(icslog.LOG_LEVEL_INFO, s.ID, "Closed Voice port")
}
//close session
s.Stop()
serr := s.RemoveSession()
if serr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "RemoveSession Error %s", serr.GetMessage())
}
}
//////////////////////////////////////////
//DTMF
// add DTMF
func (s *IcsSession) AddDtmf() {
inputDtmf := s.cs.InOut
if inputDtmf == "10" {
inputDtmf = "#"
} else if inputDtmf == "11" {
inputDtmf = "*"
}
s.m.Lock()
s.dtmf += inputDtmf
s.m.Unlock()
}
// reset DTMF
func (s *IcsSession) ResetDtmf() {
s.m.Lock()
s.dtmf = ""
s.m.Unlock()
}
// get DTMF
func (s *IcsSession) GetDtmf(dtmfEnd string) string {
result := ""
if s.botStatus.Data.MaxDigit == len(s.dtmf) || strings.Contains(s.dtmf, dtmfEnd) { // len check
result = s.dtmf
} else if strings.Contains(s.dtmf, "*") {
result = s.custid
}
return result
}