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/icsapp/execsvc.go

653 lines
20 KiB
Go

package icsapp
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
"strings"
"syscall"
"time"
"gitlab.com/cinnamon/voiceagent/icsconf"
"gitlab.com/cinnamon/voiceagent/icserror"
"gitlab.com/cinnamon/voiceagent/icsevent"
"gitlab.com/cinnamon/voiceagent/icshttp"
"gitlab.com/cinnamon/voiceagent/icshttpclient"
"gitlab.com/cinnamon/voiceagent/icslog"
"gitlab.com/cinnamon/voiceagent/icsnet"
"gitlab.com/cinnamon/voiceagent/icssessionmanager"
"gitlab.com/cinnamon/voiceagent/icssvc"
"gitlab.com/cinnamon/voiceagent/icsws"
"gitlab.com/cinnamon/voiceagent/recorddata"
"gitlab.com/cinnamon/voiceagent/recorddata/readcallsignal"
)
const (
LINEEND1 = "\r\n"
LINEEND2 = "EOM"
)
type IcsExec struct {
service *icssvc.IcsService
config *icsconf.IcsConfig
httpsrv *icshttp.Router
hbNet *icsnet.IcsTCPNet
sttNet *icsnet.IcsTCPNet
csNet *icsnet.IcsTCPNet
ttsNet *icsnet.IcsTCPNet
cmdNet *icsnet.IcsTCPNet
}
func Init(conf *icsconf.IcsConfig) (e *IcsExec) {
e = &IcsExec{}
e.service = icssvc.GetServiceStatus()
e.config = conf
e.httpsrv = icshttp.NewRouter()
return e
}
func (exe IcsExec) Execute() *icserror.IcsError {
l := icslog.GetIcsLog()
logFile, _ := os.Create("track" + time.Now().Format("20060102_150405") + ".log")
syscall.Dup2(int(logFile.Fd()), 2)
for !exe.service.GetExit() {
for exe.service.GetStop() {
time.Sleep(time.Millisecond)
}
//init session manager and run
sm := icssessionmanager.NewSessionManager()
sm.Load()
/////////////////////////////////////////////////////////////////////
//make http handler
httpDone := make(chan error)
if exe.config.HTTPConfig.Value {
icshttp.BuildHandler(exe.httpsrv)
l.Print(icslog.LOG_LEVEL_DEBUG2, -1, "Registered http handlers")
//start http server
go func() {
saddr := fmt.Sprintf(":%d", exe.config.HTTPConfig.Port)
httpErr := http.ListenAndServe(saddr, exe.httpsrv)
if httpErr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, -1, "HTTP Listen failed - %v", httpErr)
fmt.Println("HTTP Listen failed -", httpErr)
httpDone <- httpErr
} else {
l.Printf(icslog.LOG_LEVEL_INFO, -1, "HTTP Listen - %s", saddr)
}
//httpDone <- nil
}()
}
select {
// case hbch := <-hbDone:
// if hbch != nil {
// return hbch
// }
// case sttch := <-sttDone:
// if sttch != nil {
// return sttch
// }
// /*
// case csch := <-csDone:
// if csch != nil {
// return csch
// }
// */
// case ttsch := <-ttsDone:
// if ttsch != nil {
// return ttsch
// }
// case cmdch := <-cmdDone:
// if cmdch != nil {
// return cmdch
// }
case httpch := <-httpDone:
if httpch != nil {
icserror.ICSERRAPPHTTP.SetError(httpch)
return icserror.ICSERRAPPHTTP
}
}
}
return nil
}
func TCPConnHandlerHeartBeat(t *icsnet.IcsTCPNet, bufend string) {
l := icslog.GetIcsLog()
l.Printf(icslog.LOG_LEVEL_INFO, -1, "[HeartBeat] Conencted - %s", t.RemoteAddr().String())
fmt.Printf("[HeartBeat] Conencted - %s\n", t.RemoteAddr().String())
defer t.Close()
for {
buf, rlen, rerr := t.ReadS(0, bufend)
if rerr != nil {
fmt.Println("Reads Error!", rerr.GetError())
break
} else {
l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "[%d] %s", rlen, string(buf))
fmt.Printf("[%d] %s\n", rlen, string(buf))
buf = nil
}
}
}
func TCPConnHandlerSTT(t *icsnet.IcsTCPNet, bufend string) {
l := icslog.GetIcsLog()
l.Printf(icslog.LOG_LEVEL_INFO, -1, "[STT] Conencted - %s", t.RemoteAddr().String())
fmt.Printf("[STT] Conencted - %s\n", t.RemoteAddr().String())
defer t.Close()
for {
buf, rlen, rerr := t.ReadS(recorddata.MAX_CALLSIGNAL_PACKET_LEN, bufend)
if rerr != nil {
fmt.Println("Reads Error!", rerr.GetError())
break
} else {
l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "STT - [%d] %s", rlen, string(buf))
fmt.Printf("[%d] %s\n", rlen, string(buf))
cs := readcallsignal.NewCallSignal(buf)
l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "STT - call signal \n%v", cs)
buf = nil
}
}
}
func TCPConnHandlerTTS(t *icsnet.IcsTCPNet, bufend string) {
l := icslog.GetIcsLog()
l.Printf(icslog.LOG_LEVEL_INFO, -1, "[TTS] Conencted - %s", t.RemoteAddr().String())
fmt.Printf("[TTS] Conencted - %s\n", t.RemoteAddr().String())
defer t.Close()
for {
buf, rlen, rerr := t.ReadS(0, bufend)
if rerr != nil {
fmt.Println("Reads Error!", rerr.GetError())
break
} else {
l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "TTS - [%d] %s", rlen, string(buf))
fmt.Printf("[%d] %s\n", rlen, string(buf))
buf = nil
}
}
}
//processing bot command
func TCPConnHandlerCommand(t *icsnet.IcsTCPNet, bufend string) {
l := icslog.GetIcsLog()
//conf := icsconf.GetIcsConfig()
l.Printf(icslog.LOG_LEVEL_INFO, -1, "[Bot Command] Conencted - %s", t.RemoteAddr().String())
defer func() {
l.Printf(icslog.LOG_LEVEL_INFO, -1, "[Bot Command] Closed - %s", t.RemoteAddr().String())
t.Close()
}()
for {
buf, rlen, rerr := t.ReadS(81, bufend)
//buf, rlen, rerr := t.ReadS(0, bufend)
if rerr != nil {
if rerr.GetError() != io.EOF {
//fmt.Println("Reads Error!", rerr.GetError())
l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "[Bot Command] Reads Error! - %s[%s]",
rerr.GetError(), string(buf))
}
/*
aerr := rerr.GetError()
if aerr.Error() == "EOF" {
fmt.Println("Reads Error EOFFF!", rerr.GetError())
}
*/
break
} else {
l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "Recved Command - [%d] %s", rlen, string(buf))
//fmt.Printf("[%d] %s\n", rlen, string(buf))
cs := readcallsignal.NewCallSignal(buf)
if cs == nil {
l.Print(icslog.LOG_LEVEL_DEBUG2, -1, "[Call Signal] CallSignal Parsing Error!")
buf = nil
return
}
n := bytes.Index([]byte(cs.ChannelID), []byte{0})
if n != -1 {
cs.ChannelID = string([]byte(cs.ChannelID)[:n])
}
n = bytes.Index([]byte(cs.Station), []byte{0})
if n != -1 {
cs.Station = string([]byte(cs.Station)[:n])
}
n = bytes.Index([]byte(cs.AgentID), []byte{0})
if n != -1 {
cs.AgentID = string([]byte(cs.AgentID)[:n])
}
l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "Call Signal - [%d] chID: %s, SID: %s, Station: %s, AgentID: %s, EventType: %s, CustTel: %s, %d:%d",
len(buf),
cs.ChannelID,
cs.ServerID,
cs.Station,
cs.AgentID,
cs.EventType,
cs.CustID,
cs.StartTime,
cs.EndTime)
//fmt.Printf("345LINE [%d] %s\n", len(buf), string(buf))
if strings.Compare(cs.EventType, "S") == 0 { //START CALL
l.Print(icslog.LOG_LEVEL_INFO, -1, "Call Started")
//alloc session with station
session, serr := icssessionmanager.AllocSession(cs.ChannelID, cs.ServerID, cs.Station, "", true)
if serr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Session Aloocation Failure. Check Licensed Session Number - %s", serr.GetError())
buf = nil
return
}
//find agent conf
//if session.AgentConfig == nil {
agentConf := session.FindAgentConfig(cs.AgentID)
if agentConf == nil {
l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Could not find Agent Config - %s", cs.AgentID)
buf = nil
return
}
session.SetAgentConfig(agentConf)
l.Printf(icslog.LOG_LEVEL_DEBUG, session.ID, "Set Agent Config - %s", cs.AgentID)
//}
//set tcp connection to session's for response
session.TcpConn = t
//listen voice port
vraddr := icsnet.NewNetAddrWithIPPort("0.0.0.0", session.AgentConfig.Port)
//vraddr := icsnet.NewNetAddrWithIPPort("0.0.0.0", conf.AgentConfig[session.ID].Port)
session.VoiceNeter = icsnet.NewUDP(&vraddr, nil)
lerr := session.VoiceNeter.Listen()
if lerr != nil {
l.Printf(icslog.LOG_LEVEL_FATAL, session.ID, "Port[%s] Listen Failure - %s", vraddr, lerr.GetError())
} else {
l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Voice port listening - %s", vraddr)
}
/*
url := fmt.Sprintf("http://%s:%d%s",
session.AgentConfig.BotConfig.IP,
session.AgentConfig.BotConfig.Port,
session.AgentConfig.BotConfig.URL)
icshttpclient.PostServiceInfo(url, session.AgentConfig.BotConfig.CustTel)
*/
//sesion start
session.Start()
////////////////////////////////////////////////
//post event to the session
h := icsevent.NewEventH()
var evt *icsevent.Event
var evtErr *icserror.IcsError
if evt, evtErr = h.AllocEvent(cs); evtErr != nil {
//evtErr.Print()
return
}
l.Printf(icslog.LOG_LEVEL_INFO, -1, "Post SIP event[%d] to Session[%03d]", evt.ID, session.ID)
h.PostEvent(int(session.GetSessionID()), evt)
} else if strings.Compare(cs.EventType, "D") == 0 { //DTMF
l.Printf(icslog.LOG_LEVEL_INFO, -1, "DTMF Event - %s", cs.InOut)
//find session
session, serr := icssessionmanager.FindSession(cs)
if serr != nil || session == nil {
l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Finding Session Failure - %s", serr.GetError())
buf = nil
return
}
////////////////////////////////////////////////
//post event to the session
h := icsevent.NewEventH()
var evt *icsevent.Event
var evtErr *icserror.IcsError
if evt, evtErr = h.AllocEvent(cs); evtErr != nil {
//evtErr.Print()
return
}
l.Printf(icslog.LOG_LEVEL_INFO, -1, "Post SIP event[%d] to Session[%03d]", evt.ID, session.ID)
h.PostEvent(int(session.GetSessionID()), evt)
} else if strings.Compare(cs.EventType, "E") == 0 { //END CALL
l.Print(icslog.LOG_LEVEL_INFO, -1, "Call Ended")
//find session
session, serr := icssessionmanager.FindSession(cs)
if serr != nil || session == nil {
l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Finding Session Failure - %s", serr.GetError())
buf = nil
return
}
//find agent conf
if session.AgentConfig == nil {
agentConf := session.FindAgentConfig(cs.AgentID)
if agentConf == nil {
l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Could not find Agent Config - %s", cs.AgentID)
buf = nil
return
}
session.SetAgentConfig(agentConf)
}
switch session.AgentConfig.Action {
case "voicegateway":
url := fmt.Sprintf("http://%s:%d%s",
session.AgentConfig.BotConfig.IP,
session.AgentConfig.BotConfig.Port,
session.AgentConfig.BotConfig.URL2)
//remove null terminator
var custid string
n := bytes.Index([]byte(cs.CustID), []byte{0})
if n != -1 {
custid = string([]byte(cs.CustID)[:n])
} else {
custid = cs.CustID
}
var sstation string
n = bytes.Index([]byte(cs.Station), []byte{0})
if n != -1 {
sstation = string([]byte(cs.Station)[:n])
} else {
sstation = cs.Station
}
scallID := session.GetCallID()
botToken := session.GetBotToken()
//send hangup to bot
processResp := icshttpclient.PostProcess(url, "HANGUP", "", custid, "ICS_RCP", scallID, sstation, botToken, "")
l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "CALL HANGUP - %+v", processResp)
}
//close voiceneter
verr := session.VoiceNeter.Close()
if verr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to close Voice port - %s", verr.GetError())
} else {
l.Print(icslog.LOG_LEVEL_INFO, session.ID, "Closed Voice port")
}
//close session
session.Stop()
serr = session.RemoveSession()
if serr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "RemoveSession Error %s", serr.GetMessage())
}
buf = nil
}
buf = nil
}
}
}
//from VoiceCapture
func TCPConnHandlerCS(t *icsnet.IcsTCPNet, bufend string) {
l := icslog.GetIcsLog()
//conf := icsconf.GetIcsConfig()
l.Printf(icslog.LOG_LEVEL_INFO, -1, "[Call Signal] Connected - %s", t.RemoteAddr().String())
defer t.Close()
for {
buf, _, rerr := t.ReadS(recorddata.MAX_CALLSIGNAL_PACKET_LEN, bufend)
//buf, _, rerr := t.ReadS(61, bufend)
//buf, rlen, rerr := t.ReadS(0, bufend)
if rerr != nil {
if aerr := rerr.GetError(); aerr != io.EOF {
l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "[Call Signal] Reads Error! - %s", rerr.GetError())
}
buf = nil
return
} else {
cs := readcallsignal.NewCallSignal(buf)
if cs == nil {
l.Print(icslog.LOG_LEVEL_DEBUG2, -1, "[Call Signal] CallSignal Parsing Error!")
buf = nil
return
}
//var agentid string
n := bytes.Index([]byte(cs.CustID), []byte{0})
if n != -1 {
cs.CustID = string([]byte(cs.CustID)[:n])
}
n = bytes.Index([]byte(cs.AgentID), []byte{0})
if n != -1 {
cs.AgentID = string([]byte(cs.AgentID)[:n])
}
n = bytes.Index([]byte(cs.ChannelID), []byte{0})
if n != -1 {
cs.ChannelID = string([]byte(cs.ChannelID)[:n])
}
l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "Call Signal - [%d] chID: %s, SID: %s, Station: %s, AgentID: %s, EventType: %s, CustTel: %s, %d:%d",
len(buf),
cs.ChannelID,
cs.ServerID,
cs.Station,
cs.AgentID,
cs.EventType,
cs.CustID,
cs.StartTime,
cs.EndTime)
fmt.Printf("345LINE [%d] %s\n", len(buf), string(buf))
if strings.Compare(cs.EventType, "S") == 0 { //START CALL
l.Print(icslog.LOG_LEVEL_INFO, -1, "Call Started")
session, serr := icssessionmanager.AllocSession(cs.ChannelID, cs.ServerID, cs.Station, "", true)
if serr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Session Aloocation Failure. Check Licensed Session Number - %s", serr.GetError())
buf = nil
return
}
//find agent conf
//if session.AgentConfig == nil {
agentConf := session.FindAgentConfig(cs.AgentID)
if agentConf == nil {
l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Could not find Agent Config - %s", cs.AgentID)
buf = nil
return
}
session.SetAgentConfig(agentConf)
l.Printf(icslog.LOG_LEVEL_DEBUG, session.ID, "Set Agent Config - %s", cs.AgentID)
//}
//listen voice port
vraddr := icsnet.NewNetAddrWithIPPort("0.0.0.0", session.AgentConfig.Port)
session.VoiceNeter = icsnet.NewUDP(&vraddr, nil)
lerr := session.VoiceNeter.Listen()
if lerr != nil {
l.Printf(icslog.LOG_LEVEL_FATAL, session.ID, "Port[%s] Listen Failure - %s", vraddr, lerr.GetError())
} else {
l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Voice port open - %s", vraddr)
}
//connect to websocket server
//TODO: error-handling!!
wshost := fmt.Sprintf("%s:%d", session.AgentConfig.WSConfig.IP, session.AgentConfig.WSConfig.Port)
wspath := fmt.Sprintf("/%s/%s/websocket", cs.Station, cs.Station) //cs.AgentID)
path := fmt.Sprintf("%s%s", session.AgentConfig.WSConfig.Path, wspath)
//path := fmt.Sprintf("%s%s", session.AgentConfig.WSConfig.Path, "/123/01234567/websocket")
//path := fmt.Sprintf("%s%s", conf.AgentConfig[session.ID].WSConfig.Path, "/123/01234567/websocket")
session.WSConn = icsws.NewWSClient(wshost, path)
wserr := session.WSConn.Connect()
if wserr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to connect Websocket server[%s/%s] - %s",
wshost, path, wserr.GetError())
} else {
//connect
imsg := icsws.NewIAP()
imsg.Connect()
ierr := session.WSConn.Write(imsg.String())
if ierr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to connect Websocket server[%s/%s] - %s",
wshost, path, ierr.GetError())
} else {
for iter := 0; iter < 3; iter++ {
connected, ierr := session.WSConn.Read()
if ierr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to connect Websocket server[%s/%s] - %s",
wshost, path, ierr.GetError())
} else {
if !strings.Contains(string(connected), "CONNECTED") {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to connect Websocket server[%s/%s]. Retry - %d",
wshost, path, iter)
continue
} else {
l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Connected Websocket server - %s",
string(connected))
break
}
}
}
//subscribe
agentname := session.AgentConfig.Name
imsg.Subscribe(agentname)
ierr = session.WSConn.Write(imsg.String())
if ierr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to Subscribe - %s", ierr.GetError())
} else {
l.Print(icslog.LOG_LEVEL_INFO, session.ID, "Subscribe Websocket")
}
//room in
imsg.RoomIn(agentname, agentname)
ierr = session.WSConn.Write(imsg.String())
if ierr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to sent Room-In - %s", ierr.GetError())
} else {
l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Sent Room-In to Websocket server [%s]", imsg.String())
}
//call start
var custid string
n := bytes.Index([]byte(cs.CustID), []byte{0})
if n != -1 {
custid = string([]byte(cs.CustID)[:n])
} else {
custid = cs.CustID
}
imsg.CallStart(agentname, custid)
ierr = session.WSConn.Write(imsg.String())
if ierr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to sent Call Start - %s", ierr.GetError())
} else {
l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Sent Call start to Websocket server [%s]", imsg.String())
}
}
}
session.Start()
////////////////////////////////////////////////
h := icsevent.NewEventH()
var evt *icsevent.Event
var evtErr *icserror.IcsError
if evt, evtErr = h.AllocEvent(cs); evtErr != nil {
//evtErr.Print()
return
}
l.Printf(icslog.LOG_LEVEL_INFO, -1, "Post SIP event[%d] to Session[%03d]", evt.ID, session.ID)
h.PostEvent(int(session.GetSessionID()), evt)
buf = nil
} else if strings.Compare(cs.EventType, "E") == 0 { //END CALL
l.Print(icslog.LOG_LEVEL_INFO, -1, "Call Ended")
session, serr := icssessionmanager.FindSession(cs)
if serr != nil || session == nil {
l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Finding Session Failure - %s", serr.GetError())
buf = nil
return
}
//find agent conf
if session.AgentConfig == nil {
agentConf := session.FindAgentConfig(cs.AgentID)
if agentConf == nil {
l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Could not find Agent Config - %s", cs.AgentID)
buf = nil
return
}
session.SetAgentConfig(agentConf)
}
//close voiceneter
verr := session.VoiceNeter.Close()
if verr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failted to close Voice port - %s", verr.GetError())
} else {
l.Print(icslog.LOG_LEVEL_INFO, session.ID, "Close Voice port")
}
agentname := session.AgentConfig.Name
//agentname := conf.AgentConfig[session.ID].Name
imsg := icsws.NewIAP()
//call end
var custid string
n := bytes.Index([]byte(cs.CustID), []byte{0})
if n != -1 {
custid = string([]byte(cs.CustID)[:n])
} else {
custid = cs.CustID
}
imsg.CallEnd(agentname, custid)
ierr := session.WSConn.Write(imsg.String())
if ierr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to sent Call End - %s", ierr.GetError())
} else {
l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Sent Call End to Websocket server [%s]", imsg.String())
}
time.Sleep(time.Second)
//room out
imsg.RoomOut(agentname, agentname)
ierr = session.WSConn.Write(imsg.String())
if ierr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to sent Room-Out - %s", ierr.GetError())
} else {
l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Sent Room-Out to Websocket server [%s]", imsg.String())
}
//disconnect stomp
imsg.Disconnect()
ierr = session.WSConn.Write(imsg.String())
if ierr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to sent Disconnect - %s", ierr.GetError())
} else {
l.Print(icslog.LOG_LEVEL_INFO, session.ID, "Sent Disconnect to Websocket server")
}
//close ws connection
verr = session.WSConn.Close()
if verr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "Failed to Close Websocket Connection - %s", verr.GetError())
} else {
l.Print(icslog.LOG_LEVEL_INFO, session.ID, "Close Websocket Connection")
}
session.Stop()
serr = session.RemoveSession()
if serr != nil {
l.Printf(icslog.LOG_LEVEL_ERROR, session.ID, "RemoveSession Error %s", serr.GetMessage())
}
buf = nil
return
}
}
}
}