Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package main
- import (
- "bytes"
- "database/sql"
- "encoding/json"
- "fmt"
- _ "github.com/go-sql-driver/mysql"
- "github.com/ivahaev/amigo"
- "net/http"
- "os"
- "path/filepath"
- "strconv"
- "strings"
- "time"
- )
- type AccountCode struct {
- o string
- e int
- t string
- }
- type Config struct {
- Manager struct {
- User string `json:"user"`
- Pass string `json:"pass"`
- Host string `json:"host"`
- } `json:"manager"`
- Database struct {
- User string `json:"user"`
- Pass string `json:"pass"`
- Host string `json:"host"`
- Name string `json:"name"`
- } `json:"database"`
- API struct {
- URLCrm string `json:"url_crm"`
- URLPeerUse string `json:"url_peer_use"`
- Key string `json:"key"`
- } `json:"api"`
- }
- var db *sql.DB
- var a *amigo.Amigo
- var config Config
- func JSON(operator, type_call, status, num, uniqueid string) {
- vid := map[string]string{
- "operator": operator,
- "type_call": type_call,
- "status": status,
- "num": num,
- "uniqueid": uniqueid}
- vid1, _ := json.Marshal(vid)
- vidEvent := string(vid1)
- fmt.Println(vidEvent, "\n")
- eventsBusVid(vidEvent)
- }
- func httpPOST(urlSet, data string) error {
- //fmt.Println("URL:>", urlSet, "\n")
- //fmt.Println("DATA:>", data, "\n")
- var jsonStr = []byte(data)
- req, err := http.NewRequest("POST", urlSet, bytes.NewBuffer(jsonStr))
- req.Header.Set("Content-Type", "application/json")
- if err != nil {
- return err
- }
- client := &http.Client{
- //Timeout: 150 * time.Millisecond,
- }
- _, err = client.Do(req)
- if err != nil {
- return err
- }
- return nil
- }
- func httpPOSTkey(urlSet, data string) error {
- //fmt.Println("URL:> \n", urlSet)
- //fmt.Println("DATA:> \n", data)
- var jsonStr = []byte(data)
- req, err := http.NewRequest("POST", urlSet, bytes.NewBuffer(jsonStr))
- req.Header.Set("Content-Type", "application/json")
- req.Header.Set("keyaccess", config.API.Key)
- if err != nil {
- return err
- }
- client := &http.Client{
- //Timeout: 150 * time.Millisecond,
- }
- _, err = client.Do(req)
- if err != nil {
- return err
- }
- return nil
- }
- func delDB(exten, callerid, extenOR, calleridOR string) {
- sqlInsert := "delete from calls where `exten`='" + exten + "' OR `callerid`='" + callerid + "' OR `exten`='" + extenOR + "' OR `callerid`='" + calleridOR + "'"
- _, err := db.Exec(sqlInsert)
- if err != nil {
- fmt.Println("Error delete DB:( --> %s", err)
- }
- }
- func eventsBusVid(event string) {
- if event == "" {
- fmt.Println("Event_bus: Ошибка - нет данных \n")
- } else {
- err := httpPOST(config.API.URLCrm, event)
- if err != nil {
- fmt.Printf("Ошибка EventBus: %v\n", err)
- }
- }
- }
- //функция изменения состояния пира, разговаривает или нет
- func peerUse(peer_use string, use_status string) {
- if config.API.URLPeerUse == "" {
- return
- }
- mapS := map[string]string{"operator": peer_use, "queue": "", "status": use_status}
- event, _ := json.Marshal(mapS)
- eventUse := string(event)
- err := httpPOSTkey(config.API.URLPeerUse, eventUse)
- if err != nil {
- fmt.Printf("Ошибка PEERUSE: %v\n", err)
- }
- }
- func dialBeginHandler(data map[string]string) {
- fmt.Println("Событие DialBEGIN \n", data, "\n")
- var chann, type_call, log_EXTEN_db, log_CAllerID_db, log_Uniqueid_caller_db, log_Uniqueid_answer_db string
- var autocall int
- var err error
- db, err = sql.Open("mysql", config.Database.User+":"+config.Database.Pass+"@tcp("+config.Database.Host+")/"+config.Database.Name)
- if err != nil {
- fmt.Println("Нет подключение к базе \n")
- }
- defer db.Close()
- if len(data["Context"]) == 0 {
- return
- }
- if data["Context"] == "autocall-normal" {
- return
- }
- //срез
- arr := (data["DialString"])
- fmc_dialstring := arr[0:3]
- //срез
- if (data["Context"] == "macro-dialout-trunk") || (data["Context"] == "fenix-local") || (data["Context"] == "fenix") || len(data["AccountCode"]) != 0 { //костыль
- if fmc_dialstring == "fmc" && len(data["AccountCode"]) == 0 {
- type_call = "in"
- } else {
- type_call = "out"
- }
- //костыли для FMC!!!!!!!!!!!!!!!
- //$type_call = "out";
- } else {
- type_call = "in"
- }
- if data["Context"] == "ext-queues" {
- fmt.Println("ЭТО Звонок в очереди, не конечный звонок - ВЫХОД")
- fmt.Println(data)
- return
- }
- if (data["Context"] == "macro-dial-one") && (data["CallerIDNum"] == "<unknown>") {
- out_channel := data["Channel"] //запрашиваем название канала
- find_str_1 := "/"
- find_str_2 := "@"
- pos1 := strings.Index(out_channel, find_str_1) //возращение вхождения strbos
- cid := out_channel[pos1+1:] // срез substr
- pos2 := strings.Index(cid, find_str_2) //возращение вхождения
- out_cid := cid[:pos2] //узнаем логин пира который совершает звонок
- fmt.Println("OUT CID ==>> ", out_cid, "\n")
- //$setcid = $manager->SetVar($data['Channel'], 'CALLERID(ALL)', "{$out_cid} <{$out_cid}>");
- log_CAllerID_db = out_cid
- } else {
- if (data["Context"] == "macro-dialout-trunk") && (data["CallerIDNum"] == "<unknown>") { //нужно при звонке через FMC
- out_channel := data["Channel"] //запраиваем название канала
- find_str_1 := "/"
- find_str_2 := "@"
- pos1 := strings.Index(out_channel, find_str_1)
- cid := out_channel[pos1+1:]
- pos2 := strings.Index(cid, find_str_2)
- out_cid := cid[:pos2] //узнаем номер абонента
- fmt.Println("OUT CID ==>> ", out_cid, "\n")
- log_CAllerID_db = out_cid
- } else {
- log_CAllerID_db = data["CallerIDNum"]
- }
- }
- if _, err := strconv.ParseInt(data["DialString"], 0, 64); err == nil { //определяем число или нет
- log_EXTEN_db = data["DialString"]
- } else {
- log_EXTEN_db = data["DestCallerIDNum"]
- //$log_EXTEN_db = $data['DestExten']; Проверяем ощибку S для FMC
- }
- chan_caller := data["Channel"]
- chan_answer := data["DestChannel"]
- log_Uniqueid_caller_db = data["Uniqueid"]
- log_Uniqueid_answer_db = data["DestUniqueid"]
- //делаем правильный callerid для предиктивных звонков
- //Проверяем вспомогательный канал
- find_str_1 := ";2"
- pos1Des := strings.Index(log_Uniqueid_caller_db, find_str_1)
- fmt.Println(log_Uniqueid_caller_db)
- if pos1Des != -1 {
- chann = "2"
- log_Uniqueid_caller_db = log_Uniqueid_caller_db[:pos1Des]
- } else {
- chann = ""
- }
- //Забираем все данные из accountcode
- fmt.Println(data)
- var vidArr map[string]string
- json.Unmarshal([]byte(data["AccountCode"]), &vidArr)
- fmt.Println(vidArr)
- //Забираем все данные из accountcode
- if (len(vidArr["o"]) != 0) && (chann == "2") {
- log_CAllerID_db = vidArr["o"]
- }
- //делаем правильный callerid для предиктивных звонков
- //узнаем этот звонок с автообзвона или нет
- if vidArr["o"] == "autocall" {
- autocall = 1
- } else {
- autocall = 0
- }
- //время
- t := time.Now()
- times := t.Format("2006-01-02 15:04:05")
- //узнаем этот звонок с автообзвона или нет
- //запись в базу
- var sqlInsert = "INSERT INTO calls (type_call,exten,callerid,unigueid_caller,status_call,chan_caller,chan_answer,unigueid_answer,date_start,autocall) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
- _, err = db.Exec(sqlInsert, type_call, log_EXTEN_db, log_CAllerID_db, log_Uniqueid_caller_db, "1", chan_caller, chan_answer, log_Uniqueid_answer_db, times, autocall)
- if err != nil {
- fmt.Println("Ошибка записи в базу :( --> %s", err)
- }
- //событие по виджету (event_bus)
- //fmt.Println("AccountCode ================>>>>>>>", data["AccountCode"], type_call, chann)
- //
- if len(data["AccountCode"]) != 0 {
- if (chann == "2") && (vidArr["t"] != "pred") {
- return
- }
- if (chann != "2") && (vidArr["t"] == "pred") {
- return
- }
- if (chann == "2") && (vidArr["t"] == "norm") {
- return
- }
- if (vidArr["o"] != data["CallerIDNum"]) && (vidArr["t"] == "norm") {
- return
- }
- JSON(vidArr["o"], type_call, "ring", vidArr["e"], log_Uniqueid_caller_db)
- } else {
- //если это звонок не из АПИ то параметры подставляем в зависимости от типа звонка
- if type_call == "in" {
- JSON(log_EXTEN_db, type_call, "ring", log_CAllerID_db, log_Uniqueid_caller_db)
- } else {
- JSON(log_CAllerID_db, type_call, "ring", log_EXTEN_db, log_Uniqueid_caller_db)
- }
- }
- //событие по виджету (event_bus)
- //обновляем статус пира
- peerUse(log_EXTEN_db, "IN_USE")
- peerUse(log_CAllerID_db, "IN_USE")
- }
- func dialEndHandler(data map[string]string) {
- var chann, type_call, cid, log_EXTEN_db, log_CAllerID_db, date_start, date_answer, ringing, callerid, log_Uniqueid_caller_db string
- var autocall int
- var err error
- //Uniqueid = data["Uniqueid"]
- fmt.Println("Событие DialEND \n", data, "\n")
- db, err = sql.Open("mysql", config.Database.User+":"+config.Database.Pass+"@tcp("+config.Database.Host+")/"+config.Database.Name)
- if err != nil {
- fmt.Println("Нет подключение к базе \n")
- }
- defer db.Close()
- if len(data["Context"]) == 0 {
- return
- }
- if data["Context"] == "autocall-normal" {
- return
- }
- if data["Context"] == "ext-queues" {
- fmt.Println("ЭТО Звонок в очереди, не конечный звонок - ВЫХОД")
- return
- }
- if data["DialStatus"] == "ANSWER" {
- log_CAllerID_db = data["CallerIDNum"]
- log_EXTEN_db = data["DestCallerIDNum"]
- log_Uniqueid_caller_db = data["Uniqueid"]
- //
- //Проверяем вспомогательный канал
- find_str_1 := ";2"
- pos1Des := strings.Index(log_Uniqueid_caller_db, find_str_1)
- if pos1Des != -1 {
- chann = "2"
- log_Uniqueid_caller_db = log_Uniqueid_caller_db[:pos1Des]
- } else {
- chann = ""
- }
- //Проверяем вспомогательный канал
- //Забираем все данные из AccountCode
- var vidArr map[string]string
- json.Unmarshal([]byte(data["AccountCode"]), &vidArr)
- fmt.Println(vidArr)
- //
- if (len(vidArr["o"]) != 0) && (chann == "2") {
- log_CAllerID_db = vidArr["o"]
- } else {
- if (data["Context"] == "macro-dialout-trunk") && (data["CallerIDNum"] == "<unknown>") {
- out_channel := data["Channel"]
- findStr1 := "/"
- findStr2 := "@"
- pos1 := strings.Index(out_channel, findStr1)
- cid = out_channel[pos1+1:]
- pos2 := strings.Index(cid, findStr2)
- out_cid := cid[:pos2] //узнаем номер абонента
- log_CAllerID_db = out_cid
- } else {
- fmt.Println("Проверить на рабочем событии \n\n")
- cid = ""
- }
- }
- //узнаем этот звонок с автообзвона или нет
- if vidArr["o"] == "autocall" {
- autocall = 1
- } else {
- autocall = 0
- }
- //узнаем этот звонок с автообзвона или нет
- //время
- t := time.Now()
- times := t.Format("2006-01-02 15:04:05")
- //узнаем этот звонок с автообзвона или нет
- //запись в базу
- sqlInsert := "Update calls set status_call=2, shower=0, date_answer='" + times + "' where `chan_caller`='" + data["Channel"] + "' OR `chan_answer`='" + data["Channel"] + "';"
- _, err := db.Exec(sqlInsert)
- if err != nil {
- fmt.Println("Error insert :( --> %s", err)
- }
- rows, err:= db.Query("select date_start, date_answer, (UNIX_TIMESTAMP(date_answer) - UNIX_TIMESTAMP(date_start)) AS ringing, autocall, callerid,type_call from calls where chan_caller=?", data["Channel"])
- if err != nil {
- fmt.Println("Ошибка в запросе BD: %v\n", err)
- }
- for rows.Next() {
- rows.Scan(&date_start, &date_answer, &ringing, &autocall, &callerid, &type_call)
- //fmt.Println("date_start", date_start)
- //fmt.Println("date_answer", date_answer)
- //fmt.Println("ringing", ringing)
- //fmt.Println("autocall", autocall)
- //fmt.Println("callerid", callerid)
- //fmt.Println("type_call", type_call, "\n")
- }
- if (cid == "") || (log_CAllerID_db == log_EXTEN_db) {
- log_CAllerID_db = callerid
- }
- //событие по виджету (event_bus)
- if len(data["AccountCode"]) != 0 {
- fmt.Println("chan ===>>> ", chann)
- fmt.Println("type_call ===>>> ", vidArr["t"])
- fmt.Println("Operator ===>>> ", vidArr["o"])
- fmt.Println("CallerIDNum ===>>> ", data["CallerIDNum"], "\n")
- if (chann == "2") && (vidArr["t"] == "pred") {
- return
- }
- //if (log_Uniqueid_caller_db != data["Uniqueid"]) && (vidArr["t"] == "norm") {
- // return
- //}
- if (chann == "2") && (vidArr["t"] == "norm") {
- return
- }
- if vidArr["o"] != data["CallerIDNum"] && vidArr["t"] == "norm" {
- return
- }
- JSON(vidArr["o"], type_call, "answer", vidArr["e"], log_Uniqueid_caller_db)
- if vidArr["t"] == "pred" {
- //запись в канал
- setcid, _ := a.Action(map[string]string{"Action": "Setvar", "Channel": data["Channel"], "Variable": "CALLERID(ALL)", "Value": vidArr["e"] + ` <` + vidArr["e"] + `>`})
- fmt.Println("SETVAR ===>>> ", setcid, "\n")
- }
- //eventsBusVid(vidEvent)
- } else {
- //если это звонок не из АПИ то параметры подставляем в зависимости от типа звонка
- if type_call == "in" {
- JSON(log_EXTEN_db, type_call, "answer", log_CAllerID_db, log_Uniqueid_caller_db)
- } else {
- JSON(log_CAllerID_db, type_call, "answer", log_EXTEN_db, log_Uniqueid_caller_db)
- }
- }
- //запись в канал
- _, err = a.Action(map[string]string{"Action": "Setvar", "Channel": data["Channel"], "Variable": "CDR(ringing)", "Value": ringing})
- if err != nil {
- fmt.Println("Ошибка отправки данных в канала: %v\n", err)
- }
- //fmt.Println("!!!!!!!!!!!!!!!!!!SETVAR!!!!!!!!!!!!!!!!!!!", setvar, "!!!!!!!!!!!!!!!!!!!!!!!SETVAR!!!!!!")
- } else {
- return
- }
- }
- func hangupHandler(data map[string]string) {
- var log_CAllerID_db, chann, chan_caller, log_EXTEN_db, autocall, type_call, log_Uniqueid_caller_db string
- var err error
- fmt.Println("Хенгап!!!!! \n", data, "\n")
- db, err = sql.Open("mysql", config.Database.User+":"+config.Database.Pass+"@tcp("+config.Database.Host+")/"+config.Database.Name)
- if err != nil {
- fmt.Println("Нет подключение к базе \n")
- }
- defer db.Close()
- if data["Cause-txt"] == "Unknown" {
- return
- }
- var vidArr map[string]string
- json.Unmarshal([]byte(data["AccountCode"]), &vidArr)
- fmt.Println(vidArr)
- if data["Context"] == "autocall-normal" {
- return
- }
- //запрашиваем CID и Exten
- rows, err := db.Query("select `exten`, `callerid`, `unigueid_caller`, `chan_caller`, `autocall`, `type_call` from calls where (`chan_caller`='" + data["Channel"] + "' OR `chan_answer`='" + data["Channel"] + "') AND `chan_caller`!=''")
- if err != nil {
- fmt.Println("Ошибка запроса CID и Exten \n")
- }
- for rows.Next() {
- rows.Scan(&log_EXTEN_db, &log_CAllerID_db, &log_Uniqueid_caller_db, &chan_caller, &autocall, &type_call)
- fmt.Println("exten", log_EXTEN_db)
- fmt.Println("calleridr", log_CAllerID_db)
- fmt.Println("unigueid_caller", log_Uniqueid_caller_db)
- fmt.Println("chan_caller", chan_caller)
- fmt.Println("autocall", autocall)
- fmt.Println("type_call", type_call, "\n")
- }
- //Проверяем вспомогательный канал
- findStr1 := ";2"
- pos1Des := strings.Index(data["Uniqueid"], findStr1)
- if pos1Des != -1 {
- chann = "2"
- log_Uniqueid_caller_db = data["Uniqueid"][:pos1Des]
- } else {
- chann = ""
- }
- //Проверяем вспомогательный канал
- if type_call != "" {
- if len(data["AccountCode"]) != 0 {
- fmt.Println("chan ===>>> ", chann, "\n")
- fmt.Println("type_call ===>>> ", vidArr["t"], "\n")
- fmt.Println("Operator ===>>> ", vidArr["o"], "\n")
- fmt.Println("CallerIDNum ===>>> ", data["CallerIDNum"], "\n\n")
- if (chann == "2") && (vidArr["t"] == "norm") {
- return
- }
- if (log_Uniqueid_caller_db != data["Uniqueid"]) && (vidArr["t"] == "norm") {
- return
- }
- if (vidArr["o"] != data["CallerIDNum"]) && (vidArr["t"] == "norm") {
- return
- }
- if (vidArr["o"] == data["CallerIDNum"]) && (vidArr["t"] == "pred") {
- return
- }
- if (chann != "2") && (vidArr["t"] == "pred") {
- return
- }
- JSON(vidArr["o"], type_call, "hangup", vidArr["e"], log_Uniqueid_caller_db)
- delDB(vidArr["o"], vidArr["o"], vidArr["e"], vidArr["e"])
- //sqlInsert = "delete from calls where `exten`='" + vidArr["o"] + "' OR `callerid`='" + vidArr["o"] + "' OR `exten`='" + vidArr["e"] + "' OR `callerid`='" + vidArr["e"] + "'"
- //_, err := db.Exec(sqlInsert)
- //if err != nil {
- // fmt.Println("Error insert :( --> %s", err)
- //}
- } else {
- if type_call == "in" {
- JSON(log_EXTEN_db, type_call, "hangup", log_CAllerID_db, log_Uniqueid_caller_db)
- delDB(log_EXTEN_db, log_EXTEN_db, log_CAllerID_db, log_CAllerID_db)
- //sqlInsert = "delete from calls where `exten`='" + log_EXTEN_db + "' OR `callerid`='" + log_EXTEN_db + "' OR `exten`='" + log_CAllerID_db + "' OR `callerid`='" + log_CAllerID_db + "'"
- //_, err := db.Exec(sqlInsert)
- //if err != nil {
- // fmt.Println("Error insert :( --> %s", err)
- // }
- } else {
- JSON(log_CAllerID_db, type_call, "hangup", log_EXTEN_db, log_Uniqueid_caller_db)
- delDB(log_EXTEN_db, log_EXTEN_db, log_CAllerID_db, log_CAllerID_db)
- //sqlInsert = "delete from calls where `exten`='" + log_EXTEN_db + "' OR `callerid`='" + log_EXTEN_db + "' OR `exten`='" + log_CAllerID_db + "' OR `callerid`='" + log_CAllerID_db + "'"
- //_, err := db.Exec(sqlInsert)
- //if err != nil {
- // fmt.Println("Error insert :( --> %s", err)
- //}
- }
- }
- } else {
- fmt.Println("Пусто")
- return
- }
- peerUse(log_CAllerID_db, "NOT_IN_USE")
- peerUse(log_EXTEN_db, "NOT_IN_USE")
- }
- func eventsProcessor(ch <-chan map[string]string) {
- for data := range ch {
- switch data["Event"] {
- case "Dial":
- switch data["SubEvent"] { //for asterisrk 11
- case "Begin": //for asterisrk 11
- dialBeginHandler(data)
- case "End": //for asterisrk 11
- dialEndHandler(data)
- default: //for asterisrk 11
- fmt.Printf("Unknown Dial SubEvent: %s\n", data["SubEvent"])
- }
- case "DialBegin":
- dialBeginHandler(data)
- case "DialEnd":
- dialEndHandler(data)
- case "Hangup":
- hangupHandler(data)
- }
- }
- }
- func main() {
- //Загрузка конфиг файла
- dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
- if err != nil {
- fmt.Println("Ошибка", err)
- }
- fmt.Println(dir)
- configFile, err := os.Open(dir + "/config.json")
- if err != nil {
- fmt.Println("Конфиг не найден")
- return
- }
- jsonParser := json.NewDecoder(configFile)
- err = jsonParser.Decode(&config)
- defer configFile.Close()
- //Подключаемя к AMI
- settings := &amigo.Settings{Username: config.Manager.User, Password: config.Manager.Pass, Host: config.Manager.Host}
- a = amigo.New(settings)
- // Listen for connection events
- a.On("connect", func(message string) {
- fmt.Println("Connected", message)
- })
- a.On("error", func(message string) {
- fmt.Println("Connection error:", message)
- })
- a.Connect()
- chans := map[string]chan map[string]string{}
- c := make(chan map[string]string, 100)
- a.SetEventChannel(c)
- for data := range c {
- uniqueID := data["UniqueID"]
- if len(uniqueID) == 0 {
- uniqueID = data["Uniqueid"]
- }
- switch data["Event"] {
- case "Dial":
- {
- if ch, ok := chans[uniqueID]; ok {
- ch <- data
- continue
- }
- ch := make(chan map[string]string, 3) // capacity is 3 because only 3 events will handled
- ch <- data
- chans[uniqueID] = ch
- go eventsProcessor(ch)
- }
- case "DialBegin": // asterisk 13
- {
- ch := make(chan map[string]string, 3)
- ch <- data
- chans[uniqueID] = ch
- go eventsProcessor(ch)
- }
- case "DialEnd": // asterisk 13
- if ch, ok := chans[uniqueID]; ok {
- ch <- data
- continue
- }
- case "Hangup":
- if ch, ok := chans[uniqueID]; ok {
- ch <- data
- close(ch)
- delete(chans, uniqueID)
- continue
- }
- fmt.Printf("Unknown UniqueID on Hangup event: %s\n", uniqueID)
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement