package action import ( "errors" "fmt" "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/pkg/lfshook" "pbx-api-gin/pkg/utils" "sort" "strings" "time" ) var Pads = []string{"2413", "2414", "2415", "2421", "2422", "2423", "2424", "2425", "2431", "2432", "2433", "2434", "2435", "2441", "2442", "2443", "2444", "2445", "2451", "2452", "2453", "2454", "2455", "2461", "2462", "2463", "2464", "2465", "2471", "2472", "2473", "2474", "2475", "2481", "2482", "2483", "2484", "2485", "2411", "2412"} var Pacus = []string{"2111", "2121", "2131", "2141", "2151", "2161", "2171", "2181"} var Speakers = []string{"2111", "2121", "2131", "2141", "2151", "2161", "2171", "2181", "2311", "2381"} // Function triggered before no cab occupied signal interrupt func InActiveHangup() { if active.ActivedCab == "" { HangupTask("PA") HangupTask("CPA") HangupTask("VOL") HangupTask("PAD-OCC") } } // Hangup 挂断指定分机或通道 func Hangup(channel string) { lfshook.NewLogger().Infof("hangup extensions/channel %s", channel) if !utils.IsChannel(channel) { channel = fmt.Sprintf(`/^(PJ)?SIP\/%s-.*$/`, channel) } action := map[string]string{ "Action": "hangup", "Channel": channel, } lfshook.NewLogger().Infof("hangup action %+v", action) if _, _, err := AminInstance.Send(action); err != nil { lfshook.NewLogger().Errorf("Hangup %+v", err) } } // Hangup 挂断所有分机,除指定分机和PAD func HangupAllExcept(caller string) { //all PACU for _, ret := range Pacus { Hangup(ret) } switch caller { case "2311": Hangup("1411") //IO1 Hangup("1481") //IO8 //Hangup("2311") //ICP1 Hangup("2381") //ICP8 case "2381": Hangup("1411") //IO1 Hangup("1481") //IO8 Hangup("2311") //ICP1 //Hangup("2381") //ICP8 case "1411": //Hangup("1411") //IO1 Hangup("1481") //IO8 Hangup("2311") //ICP1 Hangup("2381") //ICP8 case "1481": Hangup("1411") //IO1 //Hangup("1481") //IO8 Hangup("2311") //ICP1 Hangup("2381") //ICP8 case "": Hangup("1411") //IO1 Hangup("1481") //IO8 Hangup("2311") //ICP1 Hangup("2381") //ICP8 } } // Hangup task func HangupTask(TaskName string) { lfshook.NewLogger().Infof("HangupTask TaskName:%s ", TaskName) taskInfo, ok := priority.RegistryTask.Get(TaskName) if ok { HangupAllLocalChan() ConfbridgeKick(taskInfo.ConfbridgeID, "all") Hangup(taskInfo.RunChannel) } } // interrupt the running task func InterruptRunningTask(toRunTask string) { var task priority.TaskInfo var taskName string var ok bool lfshook.NewLogger().Infof("InterruptRunningTask toRuntask=%s RunningTask:%s ", toRunTask, taskName) if toRunTask != "PA" && toRunTask != "PAD-ICP" && toRunTask != "PAD-TMS" { // ignore C2C taskName, task, ok = priority.RegistryTask.HighestPriorityRunningTask1() if !ok { return } } else { // have to check C2C taskName, task, ok = priority.RegistryTask.HighestPriorityRunningTask() if !ok { return } } //same type return if toRunTask == taskName { if toRunTask == "PAD-ICP" || toRunTask == "PAD-TMS" || toRunTask == "PAD-OCC" { //Auto Answer PAD-OCC one by one, clean the old confbridge and channels before answer a new PAD . if toRunTask == "PAD-OCC" { Hangup(task.RunChannel) //pad ConfbridgeKick(task.ConfbridgeID, "all") HangupIO() //io //lfshook.NewLogger().Infof("===InterruptRunningTask=ret==== ") } return } } //pad all reset if toRunTask == "AlarmHoldResetAll" { HangupAllLocalChan() return } switch task.RunType { case "CPA": //kick CPA members CPAConfbridgeKick(task.ConfbridgeID) case "EMG": //kick EMG members EMGConfbridgeKick(task.ConfbridgeID) case "C2C": // Interrupt C2C task running, if toRunTask == "PA" || toRunTask == "PAD-ICP" || toRunTask == "PAD-TMS" { HangupICP() return } case "PAD-ICP", "PAD-TMS": // Interrupt PAD task running, priority.InterruptedPad = "PAD-ICP" lfshook.NewLogger().Infof("InterruptRunningTask interrupt PAD-ICP/PAD-TMS ,Running type :%s !", task.RunType) chans, err := CoreShowChannels() if err != nil { lfshook.NewLogger().Infof("InterruptRunningTask CoreShowChannels err:%+v", err) return } //1. Redirect the connected PAD to 0300,hangup the other pad channel for _, ret := range chans { // Redirect the connected PAD to 0300 if utils.IsPAIU(ret.CallerIDNum) { if ret.ConnectedLineNum == "" { //redirect pad chanspy channel err := Redirect(ret.Channel, "0300", "queues-icp-redirect", "", "PAD") if err != nil { lfshook.NewLogger().Infof("InterruptRunningTask Redirect err:%+v", err) return } number := strings.Split(strings.Split(ret.Channel, "-")[0], "/")[1] active.NotifyPaiu(number, "hold") //HangupAllLocalChan() } } } for _, ret := range chans { //hangup pad call ICP channel if utils.IsPAIU(ret.CallerIDNum) { if utils.IsPAIU(ret.CallerIDNum) && ret.ChannelStateDesc == "Up" && utils.IsICP(ret.ConnectedLineNum) { lfshook.NewLogger().Infof("Hangup PAD Channel :%+v", ret.Channel) Hangup(ret.Channel) } } } priority.RegistryTask.StopAndUnregister("PAD-ICP") priority.RegistryTask.StopAndUnregister("PAD-TMS") //2. hangup task channel (ICP + PACU) //lfshook.NewLogger().Infof("===InterruptRunningTask=2. hangup task channel === ") HangupAllLocalChan() HangupICP() //pad end if priority.PADStart == 1 { alstatus.PaStatus("", "PAD", "end") priority.PADStart = 0 } case "PAD-OCC": // Interrupt PAD-OCC task running, if toRunTask == "C2C" { HangupICP() break } else { priority.InterruptedPad = "PAD-OCC" priority.OCCAnswer = 0 resCaller, err := QueueStatus("0301", "") // check OCC queue, get entries if err != nil { lfshook.NewLogger().Infof("QueueStatus err:%+v", err) return } for _, caller := range resCaller.Entrys { //lfshook.NewLogger().Infof("===QueueStatus=entry=%+v", caller) time.Sleep(time.Millisecond * 50) RedirectInQueue(caller.CallerIDNum, "0300", "queues-icp-redirect", caller.CallerIDNum) // redirect All PAD redirect to ICP queue } priority.RegistryTask.StopAndUnregister("PAD-OCC") //2. Hangup connected PAD //lfshook.NewLogger().Infof("===InterruptRunningTask=Hangup connected PAD=== ") Hangup(task.RunChannel) //3. Hangup OI & ICP HangupIO() HangupAllLocalChan() ConfbridgeKick(task.ConfbridgeID, "all") //occ pad end if priority.PADOccStart == 1 { alstatus.OccPad("end") priority.PADOccStart = 0 } } default: lfshook.NewLogger().Infof("InterruptRunningTask goto default !") //if !strings.Contains(priority.RunningPATaskChan, "0502@default") { // Hangup(priority.RunningPATaskChan) //} Hangup(task.RunChannel) ConfbridgeKick(task.ConfbridgeID, "all") } } // Hangup all ICP func HangupICP() { Hangup("2311") //ICP1 Hangup("2381") //ICP8 } // Hangup all IO func HangupIO() { Hangup("1411") //IO1 Hangup("1481") //IO8 } // Hangup all PACU func HangupAllPACU() { //all PACU for _, ret := range Pacus { Hangup(ret) } } func HangupAllLocalChan() { chans, err := CoreShowChannels() if err != nil { lfshook.NewLogger().Infof("CoreShowChannels %+v", err) return } for _, ret := range chans { if strings.Contains(ret.Channel, "Local") && !strings.Contains(ret.Channel, "0502@default") { //lfshook.NewLogger().Infof("HangupAllLocalChan=====hangup========= %+v", ret) Hangup(ret.Channel) } } } // Hangup all PACU func HangupAllPAD() { //all PAD for _, ret := range Pads { Hangup(ret) } } // Hangup all calls func HangupAll() { utils.ExecCmdAsync("/usr/sbin/asterisk", "-rx", "hangup request all") } // Dial 拨打号码 func Dial(src, dst, dialrule, callerID, callerName string, callType string) { chanel := fmt.Sprintf("%s/%s@default", "Local", src) action := map[string]string{ "Action": "Originate", "Channel": chanel, "Exten": dst, "Context": dialrule, "CallerID": fmt.Sprintf("%s<%s>", callerName, callerID), "Priority": "1", "Variable": fmt.Sprintf("CAB=%s", callType), "async": "true", } lfshook.NewLogger().Infof("dial action %+v", action) res, _, err := AminInstance.Send(action) if err != nil { lfshook.NewLogger().Errorf("%+v", err) } lfshook.NewLogger().Info(res) } // Dial 拨打号码 func DialICP(src, dst, dialrule, callerID, callerName string) { chanel := fmt.Sprintf("%s/%s@call-icp", "Local", src) action := map[string]string{ "Action": "Originate", "Channel": chanel, "Exten": dst, "Context": dialrule, "CallerID": fmt.Sprintf("%s<%s>", callerName, callerID), "Priority": "1", "Variable": fmt.Sprintf("CBID=%s", callerID), "async": "true", } lfshook.NewLogger().Infof("dial action %+v", action) res, _, err := AminInstance.Send(action) if err != nil { lfshook.NewLogger().Errorf("%+v", err) } lfshook.NewLogger().Info(res) } // 获取分机状态 func ExtenStatus(exten string) (Status string) { action := map[string]string{ "Action": "ExtensionState", "Exten": exten, "Context": "default", } res, _, err := AminInstance.Send(action) if err != nil { lfshook.NewLogger().Errorf("%+v", err) return "" } //lfshook.NewLogger().Infof("================ExtensionState:res %+v", res) return res["StatusText"] } // PACU ChanSpy func ChanSpy(src, dst string, whisper, bargein bool) { lfshook.NewLogger().Infof("chan spy src:%s dst:%s", src, dst) //channel := fmt.Sprintf("%s/%s", utils.DialPrefix, dst) channel := fmt.Sprintf("Local/%s@aio-rule", dst) data := fmt.Sprintf("%s/%s,qBE", utils.DialPrefix, src) /* if whisper { data = fmt.Sprintf("%s,w", data) } if bargein { data = fmt.Sprintf("%s,B", data) } */ action := map[string]string{ "Action": "Originate", "Channel": channel, // 不存在的通话 "Application": "ChanSpy", "Data": data, // 存在的通话 "CallerID": dst, "Async": "true", } lfshook.NewLogger().Infof("PACU ChanSpy action %+v", action) _, _, err := AminInstance.Send(action) if err != nil { lfshook.NewLogger().Errorf("%+v", err) } } // Redirect 转接 func RedirectInQueue(channel, dst, dialrule, callerID string) (err error) { //callerID := "redirect" //lfshook.NewLogger().Infof("redirect src %s to dst %s", channel, dst) if !utils.IsChannel(channel) { //callerID = channel if channel, err = GetChannelByExtenNotBridged(channel); err != nil { return err } } action := map[string]string{ "Action": "Redirect", "Channel": channel, "Exten": dst, "Context": dialrule, "CallerID": callerID, "Priority": "1", "async": "true", } lfshook.NewLogger().Infof("RedirectInQueue: %+v", action) res, _, err := AminInstance.Send(action) if err != nil { lfshook.NewLogger().Error(err) } lfshook.NewLogger().Info(res) return err } // Redirect 转接 func Redirect(channel, dst, dialrule, callerID, callerName string) (err error) { //callerID := "redirect" //lfshook.NewLogger().Infof("redirect src %s to dst %s", channel, dst) if !utils.IsChannel(channel) { callerID = channel if channel, err = GetChannelByExten(channel); err != nil { return err } } action := map[string]string{ "Action": "Redirect", "Channel": channel, "Exten": dst, "Context": dialrule, "CallerID": fmt.Sprintf("%s<%s>", callerName, callerID), "Priority": "1", "async": "true", } lfshook.NewLogger().Infof("Redirect: %+v", action) res, _, err := AminInstance.Send(action) if err != nil { lfshook.NewLogger().Error(err) } lfshook.NewLogger().Info(res) return err } func SetPadTimer() { toRunPadpriority := priority.GetPriorityByKey(priority.InterruptedPad) //Get PAD priori 获取之前打断的报警优先级 //toRunpriority := priority.GetPriorityByKey("PAD-ICP") _, taskTmp, ok := priority.RegistryTask.HighestPriorityRunningTask() if ok { lfshook.NewLogger().Infof("PAD SetPadTimer runing priority:%d toRun priority:%d", taskTmp.Priority, toRunPadpriority) if taskTmp.Priority < toRunPadpriority { //higher priority task running ,do not set timer return } } res, err := QueueStatus("0300", "") // check OCC queue , if empty OCC-PAD start if err != nil { lfshook.NewLogger().Infof("QueueStatus err%+v", err) return } if res.Calls != "0" { lfshook.NewLogger().Infof("PAD SetPadTimer Set QueueTimer timeout 30s !") active.SetTimer = true 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 err:%+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 err:%+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("====SetPadTimer==QueueTimer==2=") //lfshook.NewLogger().Infof("==SetPadTimer==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.Millisecond * 100) //200 ms delay } } }) } } func ConfbridgeKick(confnum, channel string) (res map[string]string, err error) { action := map[string]string{ "Action": "ConfbridgeKick", "Conference": confnum, "Channel": channel, } res, _, err = AminInstance.Send(action) if err != nil { return nil, err } lfshook.NewLogger().Infof("ConfbridgeKick res:%+v", res) if res["Response"] != "Success" { return nil, errors.New(res["Message"]) } return res, nil } func CPAConfbridgeKick(confnum string) (res map[string]string, err error) { chans, err := ConfbridgeList(confnum) if err != nil { return nil, errors.New(res["Message"]) } for _, confChan := range chans { if !strings.Contains(confChan, "PJSIP/1481") { ConfbridgeKick(confnum, confChan) } } return res, nil } func CPAConfbridgeReinvite(confID string) { time.Sleep(time.Millisecond * 500) for _, ext := range Speakers { ConfbridgeReinvite(ext, "call-speakers-cpa", confID) } } func EMGConfbridgeKick(confnum string) (res map[string]string, err error) { chans, err := ConfbridgeList(confnum) if err != nil { return nil, errors.New(res["Message"]) } for _, confChan := range chans { if !strings.Contains(confChan, "0502@default") { ConfbridgeKick(confnum, confChan) } } return res, nil } func EMGConfbridgeReinvite(confID string) { time.Sleep(time.Millisecond * 500) for _, ext := range Speakers { ConfbridgeReinvite(ext, "call-speakers-emg", confID) } } func ConfbridgeList(confnum string) (chans []string, err error) { action := map[string]string{ "Action": "ConfbridgeList", "Conference": confnum, } res, events, err := AminInstance.Send(action) if err != nil { return nil, err } lfshook.NewLogger().Infof("ConfbridgeList res:%+v", res) if res["Response"] == "Success" { for _, event := range events { if event.Data["Event"] == "ConfbridgeList" { chans = append(chans, event.Data["Channel"]) } } return chans, nil } else { return nil, errors.New(res["Message"]) } } func ConfbridgeReinvite(src, context, confID string) { if ExtenStatus(src) != "Idle" { lfshook.NewLogger().Infof(" ConfbridgeReinvite ext:%s Not Idle !", src) return } chanel := fmt.Sprintf("Local/%s@%s", src, context) action := map[string]string{ "Action": "Originate", "Channel": chanel, "Exten": "000", "Context": "confbridge-join", "CallerID": fmt.Sprintf("%s<%s>", "", ""), "Priority": "1", "Variable": fmt.Sprintf("CBID=%s", confID), "async": "true", } lfshook.NewLogger().Infof("dial action %+v", action) res, _, err := AminInstance.Send(action) if err != nil { lfshook.NewLogger().Errorf("%+v", err) } lfshook.NewLogger().Info(res) } func ICPConfbridgeReinvite(confID, paType string) { switch paType { case "PAD-OCC": go DialICP("8", "2311", "confbridge-join", confID, "1") //ICP1---call go DialICP("8", "2381", "confbridge-join", confID, "8") //ICP8---call case "CPA": go DialICP("2", "2311", "confbridge-join", confID, "1") //ICP1---call go DialICP("2", "2381", "confbridge-join", confID, "8") //ICP8---call case "EMG": go DialICP("3", "2311", "confbridge-join", confID, "1") //ICP1---call go DialICP("3", "2381", "confbridge-join", confID, "8") //ICP8---call case "SPC": go DialICP("6", "2311", "confbridge-join", confID, "1") //ICP1---call go DialICP("6", "2381", "confbridge-join", confID, "8") //ICP8---call case "STN": go DialICP("4", "2311", "confbridge-join", confID, "1") //ICP1---call go DialICP("4", "2381", "confbridge-join", confID, "8") //ICP8---call case "DCS": go DialICP("5", "2311", "confbridge-join", confID, "1") //ICP1---call go DialICP("5", "2381", "confbridge-join", confID, "8") //ICP8---call case "CHK": go DialICP("10", "2311", "confbridge-join", confID, "1") //ICP1---call go DialICP("10", "2381", "confbridge-join", confID, "8") //ICP8---call case "VOL": go DialICP("11", "2311", "confbridge-join", confID, "1") //ICP1---call go DialICP("11", "2381", "confbridge-join", confID, "8") //ICP8---call } }