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 } } } }