package action import ( "pbx-api-gin/internal/app/stc/active" "pbx-api-gin/internal/app/stc/priority" alstatus "pbx-api-gin/internal/app/stc/sendstatus" "pbx-api-gin/internal/pkg/configs" "pbx-api-gin/pkg/lfshook" "pbx-api-gin/pkg/utils" "sort" "strconv" "strings" "time" "github.com/sirupsen/logrus" "github.com/tqcenglish/amigo-go" "github.com/tqcenglish/amigo-go/pkg" ) var AminInstance *amigo.Amigo func HandleAMI(event map[string]string) { //lfshook.NewLogger().Infof("===start======%s", event["Event"] switch event["Event"] { case "DTMFBegin": //ICP interrupt PAD if utils.IsICP(event["CallerIDNum"]) { exten := strings.Split(strings.Split(event["Channel"], "/")[1], "-")[0] //get ICP exten number if utils.IsICP(exten) { chans, err := CoreShowChannels() if err != nil { lfshook.NewLogger().Errorf("CoreShowChannels %+v", err) } //1. Redirect the connected PAD to 0300 for _, ret := range chans { //lfshook.NewLogger().Infof("===HangupRunningTask=PAD1====Chans-ret===%+v==== ", ret) if utils.IsPAIU(ret.CallerIDNum) && ret.ChannelStateDesc == "Up" && utils.IsICP(ret.ConnectedLineNum) { //hangup pad call ICP channel //lfshook.NewLogger().Infof("===Hangup=Chan===%+v==== ", ret.Channel) Hangup(ret.Channel) } else if ret.ConnectedLineNum == "" { //redirect pad chanspy channel //lfshook.NewLogger().Infof("===Redirect=Chan===%+v==== ", ret.Channel) err := Redirect(ret.Channel, "0300", "default", exten, "PAD") if err != nil { lfshook.NewLogger().Errorf("Redirect %+v", err) } } } } } case "UserEvent": // RCD filename; PA;CPA; CabCab lfshook.NewLogger().Infof("========event:%s File:%s", event["Event"], event["FILENAME"]) if event["UserEvent"] == "SetRecordFile" { //get record file name alstatus.SendRecordFile(event["FILENAME"], event["RecordType"]) } else if event["UserEvent"] == "CallType" && (event["Type"] == "PA" || event["Type"] == "CPA") { //PA start; check manual PA priority //PA & CPA interrupt others if utils.IsICP(event["CallerIDNum"]) { if active.ActivedCab == "" { //No active Signal on both side,Hangup caller Hangup(event["CallerIDNum"]) } if priority.CheckPriority("ManuPa") { //hangup others if priority is higher HangupRunningTask("PA") //PA interrupt other } else { Hangup(event["CallerIDNum"]) //lowwer priority ,hangup caller } } else if utils.IsIO(event["CallerIDNum"]) { // CPA if priority.CheckPriority("CPA") { if active.ActivedCab == "" { //No active Signal on both side,Hangup caller Hangup(event["CallerIDNum"]) } //hangup others if priority is higher if priority.RunningType != "C2C" { HangupRunningTask("CPA") //CPA interrupt other } else { //call to ICP ; can not stop calling ICP lfshook.NewLogger().Info("==Running CabCab , CPA start call ICP(ICP is on the phone)=====") } } else { Hangup(event["CallerIDNum"]) //lowwer priority ,hangup caller } } } else if event["UserEvent"] == "CallType" && event["Type"] == "C2C" { //CabCab start; check cab cab priority if priority.CheckPriority("CabCab") { if priority.RunningType == "PA" || priority.RunningType == "PAD-ICP" || priority.RunningType == "PAD-TMS" { HangupRunningTask("C2C") //C2C interrupt other } else { //Hangup the other ICP if event["CallerIDNum"] == "2311" { Hangup("2381") } else { Hangup("2311") } } } else { // hangup caller; C2C start failed Hangup(event["CallerIDNum"]) } } case "Hangup": lfshook.NewLogger().Infof("=========%s", event["Event"]) //OCC answer PAD, hangup, redirect the next PAD to OCC if utils.IsIO(event["CallerIDNum"]) && (event["ConnectedLineNum"] == "ano1" || event["ConnectedLineNum"] == "ano8") && event["Context"] == "default" { lfshook.NewLogger().Infof("====Hangup OCC-PAD=====%+v", event) // OCC hangup detected, hangup other running channels HangupAllLocalChan() Hangup(priority.RunningPATaskChan) res, _ := QueueStatus("0301", "") // check OCC queue ,if empty PAD end if res.Calls == "0" { //OCC queue is empty priority.CleanPriorityTag() alstatus.OccPad("end") priority.OCCAnswer = 0 priority.PADOccStart = 0 if priority.ResumeEmgPara.FileName != "" { time.Sleep(time.Second) CheckEmgResume() } break } else { //OCC queue is not empty // HangupAllLocalChan() lfshook.NewLogger().Infof("====Start OCC-PAD===next==%+v", res) if active.ActivedCab == "1" && ExtenStatus("1411") == "Idle" { //check active and OCC status time.Sleep(time.Second) PADChan := "" for _, chanEntry := range res.Entrys { lfshook.NewLogger().Infof("====PAD answered by OCC1 pos:%s===chan:%s=", chanEntry.Position, chanEntry.Channel) if chanEntry.Position == "1" { PADChan = chanEntry.Channel break } } if PADChan != "" { Ext := strings.Split(strings.Split(res.Entrys[0].Channel, "/")[1], "-")[0] alstatus.AlarmStatus(Ext, "connect") go RedirectInQueue(PADChan, "1411", "pad-page-occ-icp", Ext) //PAD Page(OCC+ICPs) go Dial("0401", "0512", "pad-rule-pacus-occ", "ano1", "ano1", "1") // PACUs dial OCC1 } else { lfshook.NewLogger().Infof("===OCC-QueueStatus==PADCchan NULL") } break } else if active.ActivedCab == "8" && ExtenStatus("1481") == "Idle" { time.Sleep(time.Second) PADChan := "" for _, chanEntry := range res.Entrys { lfshook.NewLogger().Infof("====PAD answered by OCC1 pos:%s===chan:%s=", chanEntry.Position, chanEntry.Channel) if chanEntry.Position == "1" { PADChan = chanEntry.Channel break } } if PADChan != "" { Ext := strings.Split(strings.Split(res.Entrys[0].Channel, "/")[1], "-")[0] alstatus.AlarmStatus(Ext, "connect") go RedirectInQueue(PADChan, "1481", "pad-page-occ-icp", Ext) //PAD Page(OCC+ICPs) go Dial("0401", "0512", "pad-rule-pacus-occ", "ano8", "ano8", "8") // PACUs dial OCC1 } else { lfshook.NewLogger().Infof("===OCC-QueueStatus==PADCchan NULL") } break } } } if utils.IsPAIU(event["CallerIDNum"]) { // PAD hangup, check if PAD all end, send PAD end status res, _ := QueueStatus("0300", "") // check ICP queue ,if empty PAD end res1, _ := QueueStatus("0301", "") // check OCC queue ,if empty PAD end lfshook.NewLogger().Infof("==calls:%s===calls1:%s====", res.Calls, res1.Calls) if res.Calls == "0" && res1.Calls == "0" { //priority.CleanPriorityTag() //HangupAllLocalChan() if priority.PADStart == 1 { alstatus.PaStatus(event["CallerIDNum"], "PAD", "end") priority.PADStart = 0 } /*if priority.ResumeEmgPara.FileName != "" { CheckEmgResume() }*/ priority.ICPAnswer = 0 priority.OCCAnswer = 0 break } } case "QueueCallerJoin": lfshook.NewLogger().Infof("=========%s", event["Event"]) if priority.OCCAnswer == 1 && event["Queue"] == "0300" { //New PAD Goto the OCC queue in the first time, if OCC answered alstatus.AlarmStatus(event["CallerIDNum"], "queue") //send status to STC go RedirectInQueue(event["CallerIDNum"], "0301", "queues-occ", event["CallerIDNum"]) break } if utils.IsPAIU(event["CallerIDNum"]) && utils.IsPAIU(event["CallerIDName"]) && event["Queue"] == "0300" { // Alarm join the queue, PAD in the queue alstatus.AlarmStatus(event["CallerIDNum"], "queue") //send status to STC ICPQueue, err := QueueStatus("0300", "") // check ICP queue, get entries if err != nil { lfshook.NewLogger().Infof("==ICP=QueueStatus==%+v", err) return } if priority.ICPAnswer == 0 && ICPQueue.Calls == "1" { //ICP did not answer any first call to the ICP queue ; Ready to Set Occ Queue Timer active.QueueTimer = time.AfterFunc(30*time.Second, func() { // check the PAD 30s timeout res, err := QueueStatus("0301", "") // check OCC queue , if empty OCC-PAD start if err != nil { lfshook.NewLogger().Infof("===OCC-QueueStatus==%+v", err) return } if res.Calls == "0" { // OCC queue empty resCaller, err := QueueStatus("0300", "") // check ICP queue, get entries if err != nil { lfshook.NewLogger().Infof("==ICP=QueueStatus==%+v", err) return } sort.Slice(resCaller.Entrys, func(i, j int) bool { return resCaller.Entrys[i].Position < resCaller.Entrys[j].Position }) for _, caller := range resCaller.Entrys { priority.ICPAnswer = 0 lfshook.NewLogger().Infof("====Redirect to 0301 entry:%s=Pos:%s==", caller.CallerIDNum, caller.Position) //order by pos RedirectInQueue(caller.CallerIDNum, "0301", "queues-occ", caller.CallerIDNum) // redirect All ICP-PAD redirect to OCC queue time.Sleep(time.Microsecond * 500) //200 ms delay } } }) } break } //first PAD caller goto OCC //OCC dial PACUs; //PAD Page OCC+ICPs; if utils.IsPAIU(event["CallerIDNum"]) && event["Queue"] == "0301" && priority.OCCAnswer == 0 { // The first PAD to OCC ,caller is PAD if priority.CheckPriority("PAD-OCC") { HangupRunningTask("PAD-OCC") //PAD-OCC interrupt other priority.OCCAnswer = 1 if active.ActivedCab == "1" /* && ExtenStatus("1411") == "Idle" */ { //check active and OCC status /*if priority.PADOccStart == 0 { alstatus.OccPad("start") priority.PADOccStart = 1 if priority.PADStart == 0 { alstatus.PaStatus(event["CallerIDNum"], "PAD", "start") priority.PADStart = 1 } }*/ alstatus.AlarmStatus(event["CallerIDNum"], "connect") go RedirectInQueue(event["Channel"], "1411", "pad-page-occ-icp", event["CallerIDNum"]) //PAD Page(OCC+ICPs) go Dial("0401", "0512", "pad-rule-pacus-occ", "ano1", "ano1", "1") // PACUs dial OCC1 } else if active.ActivedCab == "8" /*&& ExtenStatus("1481") == "Idle" */ { /*if priority.PADOccStart == 0 { alstatus.OccPad("start") priority.PADOccStart = 1 if priority.PADStart == 0 { alstatus.PaStatus(event["CallerIDNum"], "PAD", "start") priority.PADStart = 1 } }*/ alstatus.AlarmStatus(event["CallerIDNum"], "connect") go RedirectInQueue(event["Channel"], "1481", "pad-page-occ-icp", event["CallerIDNum"]) //PAD Page(OCC+ICPs) go Dial("0401", "0512", "pad-rule-pacus-occ", "ano8", "ano8", "8") // PACUs dial OCC8 } } else { lfshook.NewLogger().Infof("====PAD-OCC Priority false===") } } case "ConfbridgeJoin": lfshook.NewLogger().Infof("=========%+v", event["Event"]) //set priority and send PA status msg switch event["CallerIDName"] { case "EMG": if event["Exten"] == "0502" { priority.RunningPATaskChan = event["Channel"] priority.RunningType = "EMG" //Pa status report priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.EMG) alstatus.PaStatus("", "EMG", "start") return } case "SPC": if event["Exten"] == "0505" { priority.RunningPATaskChan = event["Channel"] priority.RunningType = "SPC" //Pa status report priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.SPC) alstatus.PaStatus("", "SPC", "start") return } case "DCS": if event["Exten"] == "0504" { priority.RunningPATaskChan = event["Channel"] priority.RunningType = "DCS" //Pa status report priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.DCS) alstatus.PaStatus("", "DCS", "start") return } case "STN": if event["Exten"] == "0503" { priority.RunningPATaskChan = event["Channel"] priority.RunningType = "STN" //Pa status report priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.STN) alstatus.PaStatus("", "STN", "start") return } case "CHK": if event["Exten"] == "0510" { priority.RunningPATaskChan = event["Channel"] priority.RunningType = "CHK" //Pa status report priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.CHK) alstatus.PaStatus("", "CHK", "start") return } case "VOL": // tone-test if event["Exten"] == "0513" { priority.RunningPATaskChan = event["Channel"] priority.RunningType = "VOL" //Pa status report priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.VOL) alstatus.PaStatus("", "VOL", "start") return } } //Send PA start msg to STC if utils.IsICP(event["CallerIDNum"]) && event["Exten"] == "0500" { // PA start lfshook.NewLogger().Infof("====PA status:%s=====", "start") priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.ManuPa) alstatus.PaStatus(event["CallerIDNum"], "PA", "start") priority.RunningPATaskChan = event["Channel"] priority.RunningType = "PA" break } else if utils.IsIO(event["CallerIDNum"]) && event["Exten"] == "0501" { //CPA start lfshook.NewLogger().Infof("====CPA status:%s=====", "start") priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.CPA) alstatus.PaStatus(event["CallerIDNum"], "CPA", "start") priority.RunningPATaskChan = event["Channel"] priority.RunningType = "CPA" return } //ICP answer PAD;PACUs connected ICP //PAD chanspy ICP1 //ICP8 call PAD if event["ConnectedLineNum"] == "ani1" && event["Exten"] == "0511" { //PAD answered by ICP; PACUs connected ICP1 lfshook.NewLogger().Infof("====PAD answered by ICP1:%s=====", event["ConnectedLineName"]) alstatus.AlarmStatus(event["ConnectedLineName"], "connect") priority.RunningPATaskChan = event["Channel"] priority.RunningType = "PAD-ICP" priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.PADICP) go RedirectInQueue(event["ConnectedLineName"], "2311", "chanspy-rule-whisper", event["ConnectedLineName"]) //PAD chanspy(EqW) ICP1 if ExtenStatus("2381") == "Idle" { go Dial("0402", event["ConnectedLineName"], "call-pad-rule", event["ConnectedLineName"], event["ConnectedLineName"], "8") // PAD call ICP8 } } if event["ConnectedLineNum"] == "ani8" && event["Exten"] == "0511" { //PAD ansered by ICP8; PACUs connected ICP8 lfshook.NewLogger().Infof("====PAD answered by ICP8:%s=====", event["ConnectedLineName"]) alstatus.AlarmStatus(event["ConnectedLineName"], "connect") priority.RunningPATaskChan = event["Channel"] priority.RunningType = "PAD-ICP" priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.PADICP) go RedirectInQueue(event["ConnectedLineName"], "2381", "chanspy-rule-whisper", event["ConnectedLineName"]) //PAD chanspy(EqW) ICP8 if ExtenStatus("2311") == "Idle" { go Dial("0402", event["ConnectedLineName"], "call-pad-rule", event["ConnectedLineName"], event["ConnectedLineName"], "1") // PAD call ICP1 } break } //OCC answer PAD;Set the task channel if utils.IsPAIU(event["CallerIDNum"]) && utils.IsIO(event["Exten"]) && event["Context"] == "pad-page-occ-icp" { //PAD Page OCC1+ICPs connected lfshook.NewLogger().Infof("====PAD answered by OCC:====") priority.RunningPATaskChan = event["Channel"] priority.RunningType = "PAD-OCC" priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.PADOCC) break } case "ConfbridgeLeave": lfshook.NewLogger().Infof("=========%s", event["Event"]) if utils.IsICP(event["CallerIDNum"]) && event["Exten"] == "0500" { // PA end lfshook.NewLogger().Infof("====PA status =====%s", "end") priority.CleanPriorityTag() alstatus.PaStatus(event["CallerIDNum"], "PA", "end") if priority.ResumeEmgPara.FileName != "" { CheckEmgResume() } } else if utils.IsIO(event["CallerIDNum"]) && event["Exten"] == "0501" { //CPA end lfshook.NewLogger().Infof("====CPA status =====%s", "end") priority.CleanPriorityTag() alstatus.PaStatus(event["CallerIDNum"], "CPA", "end") if priority.ResumeEmgPara.FileName != "" { CheckEmgResume() } //lfshook.NewLogger().Infof("=========%s", event["Event"]) } else if event["CallerIDName"] == "EMG" && event["Exten"] == "0502" { // EMG broadcast hangup priority.CleanPriorityTag() alstatus.PaStatus(event["CallerIDName"], "EMG", "end") priority.ResumeEmgPara = priority.BroadcastResumeParas{} } else if event["CallerIDName"] == "STN" && event["Exten"] == "0503" { priority.CleanPriorityTag() alstatus.PaStatus(event["CallerIDName"], "STN", "end") if priority.ResumeEmgPara.FileName != "" { CheckEmgResume() } } else if event["CallerIDName"] == "DCS" && event["Exten"] == "0504" { priority.CleanPriorityTag() alstatus.PaStatus(event["CallerIDName"], "DCS", "end") if priority.ResumeEmgPara.FileName != "" { CheckEmgResume() } } else if event["CallerIDName"] == "SPC" && event["Exten"] == "0505" { priority.CleanPriorityTag() alstatus.PaStatus(event["CallerIDName"], "SPC", "end") if priority.ResumeEmgPara.FileName != "" { CheckEmgResume() } } else if event["CallerIDName"] == "CHK" && event["Exten"] == "0510" { priority.CleanPriorityTag() alstatus.PaStatus(event["CallerIDName"], "CHK", "end") if priority.ResumeEmgPara.FileName != "" { CheckEmgResume() } } else if event["CallerIDName"] == "VOL" && event["Exten"] == "0513" { priority.CleanPriorityTag() alstatus.PaStatus(event["CallerIDName"], "VOL", "end") if priority.ResumeEmgPara.FileName != "" { CheckEmgResume() } } case "DialEnd": //lfshook.NewLogger().Infof("=========%s", event["Event"]) //Cab Cab start if utils.IsICP(event["CallerIDNum"]) && utils.IsICP(event["ConnectedLineNum"]) && event["DialStatus"] == "ANSWER" { priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.CabCab) priority.RunningType = "C2C" alstatus.PaStatus(event["CallerIDNum"], "C2C", "start") } case "BridgeLeave": //lfshook.NewLogger().Infof("=========%s", event["Event"]) //Cab Cab end if utils.IsICP(event["CallerIDNum"]) && utils.IsICP(event["ConnectedLineNum"]) && event["Exten"] == "0400" { priority.RunningTypePriority = 0 priority.RunningType = "" alstatus.PaStatus(event["CallerIDNum"], "C2C", "end") } case "ExtensionStatus": //lfshook.NewLogger().Infof("=========event:%s Ext:%s status:%s ", event["Event"], event["Exten"], event["StatusText"]) //update extension status if event["StatusText"] == "Idle" || event["StatusText"] == "Unavailable" { if len(event["Exten"]) > 3 && utils.IsPAIU(event["Exten"]) { alstatus.AlarmStatus(event["Exten"], event["StatusText"]) // PAD idle + unavailable } } case "BridgeEnter": // TMS-ICP answer PAD; PACU connect ICP lfshook.NewLogger().Infof("=========event:%s callerid:%s", event["Event"], event["CallerIDNum"]) if utils.IsIO(event["CallerIDNum"]) && utils.IsPAIU(event["ConnectedLineNum"]) { if priority.PADOccStart == 0 { alstatus.OccPad("start") priority.PADOccStart = 1 if priority.PADStart == 0 { alstatus.PaStatus(event["CallerIDNum"], "PAD", "start") priority.PADStart = 1 } } } if utils.IsPACU(event["CallerIDNum"]) && utils.IsPAIU(event["CallerIDName"]) { //ICP and PACU connected lfshook.NewLogger().Infof("====BridgeEnter==IN action===%s===ID:%s Name:%s", event["Event"], event["CallerIDNum"], event["CallerIDName"]) alstatus.AlarmStatus(event["CallerIDName"], "connect") // Alarm connected priority.RunningPATaskChan = event["Channel"] priority.RunningType = "PAD-TMS" priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.PADTMS) if active.ActivedCab == "1" { go RedirectInQueue(event["CallerIDName"], "2311", "chanspy-rule-whisper", "") //PAD chanspy(EqW) ICP1 go Dial("0403", event["CallerIDName"], "call-pad-rule", "2381", "2381", "8") //ICP8---call----PAD } else if active.ActivedCab == "8" { go RedirectInQueue(event["CallerIDName"], "2381", "chanspy-rule-whisper", "") //PAD chanspy(EqW) ICP8 go Dial("0403", event["CallerIDName"], "call-pad-rule", "2311", "2311", "1") //ICP1---call----PAD } } else if utils.IsPAIU(event["CallerIDNum"]) && event["Exten"] == "0405" { // PAD connect ICP-TMS;PACU not available priority.RunningPATaskChan = event["Channel"] priority.RunningType = "PAD-TMS" priority.RunningTypePriority, _ = strconv.Atoi(priority.Priority.PADTMS) lfshook.NewLogger().Infof("====send pad status=====") alstatus.AlarmStatus(event["CallerIDNum"], "connect") // PAD connect ICP-TMS } } } func StartAMI(connectOKCallBack func(), handleEvents []func(event map[string]string)) { lfshook.NewLogger().Info("Start AMI") settings := &amigo.Settings{ Host: configs.ConfigGlobal.AsteriskAMIHost, Port: configs.ConfigGlobal.AsteriskAMIPort, Username: configs.ConfigGlobal.AsteriskAMIUser, Password: configs.ConfigGlobal.AsteriskAMISecret, LogLevel: logrus.ErrorLevel} lfshook.NewLogger().Infof("ami setting: %+v", settings) AminInstance = amigo.New(settings, lfshook.NewLogger()) AminInstance.EventOn(func(payload ...interface{}) { // lfshook.NewLogger().Infof("ami event on %+v", payload[0]) event := payload[0].(map[string]string) go HandleAMI(event) for _, handle := range handleEvents { go handle(event) } }) AminInstance.ConnectOn(func(payload ...interface{}) { lfshook.NewLogger().Infof("ami connect on %+v", payload[0]) if payload[0] == pkg.Connect_OK { connectOKCallBack() } else { lfshook.NewLogger().Errorf("ami connect failure %+v", payload) } }) AminInstance.Connect() } func Connected() bool { if AminInstance != nil { return AminInstance.Connected() } return false }