push.go 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. package zoho
  2. import (
  3. "crm-api/pkg/httpclient"
  4. "crm-api/pkg/lfshook"
  5. "encoding/json"
  6. "fmt"
  7. "io/ioutil"
  8. "net/http"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "gopkg.in/ini.v1"
  13. )
  14. var TimestampList = make(map[string]string)
  15. var StartTimeList = make(map[string]time.Time) // 事件中 Timestamp 转 StartTime 有问题,重新记录时间
  16. var LinkedidList = make(map[string]string) // 临时记录 incoming 和 outgoing
  17. var DialStatusList = make(map[string]string) // 临时记录 DialStatus:ANSWER NOANSWER
  18. var CallTypeList = make(map[string]string) //通过Linkedid临时记录拨打类型呼入还是呼出
  19. var TimetimesList = make(map[string]int)
  20. var n int
  21. func CallClicktodialerror(event map[string]string) {
  22. confPath := "/etc/asterisk/crm_api.conf"
  23. cfg, err := ini.Load(confPath)
  24. if err != nil {
  25. lfshook.NewLogger().Error(err)
  26. return
  27. }
  28. ZOHO_URL := cfg.Section("general").Key("zohoUrl").String()
  29. if ZOHO_URL == "" {
  30. lfshook.NewLogger().Error("/etc/asterisk/crm_api.conf not set zohoUrl")
  31. return
  32. }
  33. Channel := strings.Split(event["Channel"], "/")
  34. // fmt.Println("Channel[0] = ", Channel[0])
  35. if Channel[0] == "Local" {
  36. if event["Event"] == "SoftHangupRequest" {
  37. if event["Context"] == "macro-stdexten" || event["Context"] == "macro-stdexten-withoutvm" && len(event["Exten"]) > 3 {
  38. ExtenStatus := strings.Split(event["Exten"], "-")
  39. fmt.Println(len(event["Exten"]))
  40. if ExtenStatus[1] == "NOANSWER" {
  41. getURL := fmt.Sprintf("%s/phonebridge/v3/clicktodialerror?code=noanswer&from=%s&to=%s", ZOHO_URL, event["ConnectedLineNum"], event["CallerIDNum"])
  42. // if zohoUser != "" {
  43. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  44. // }
  45. fmt.Println("getURL = ", getURL)
  46. go httpclient.ZohoGet(getURL)
  47. return
  48. } else if ExtenStatus[1] == "BUSY" {
  49. getURL := fmt.Sprintf("%s/phonebridge/v3/clicktodialerror?code=notavailble&from=%s&to=%s&message=agentunavailable", ZOHO_URL, event["ConnectedLineNum"], event["CallerIDNum"])
  50. // if zohoUser != "" {
  51. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  52. // }
  53. fmt.Println("getURL = ", getURL)
  54. go httpclient.ZohoGet(getURL)
  55. return
  56. } else if ExtenStatus[1] == "CHANUNAVAIL" {
  57. getURL := fmt.Sprintf("%s/phonebridge/v3/clicktodialerror?code=rejected&from=%s&to=%s", ZOHO_URL, event["ConnectedLineNum"], event["CallerIDNum"])
  58. // if zohoUser != "" {
  59. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  60. // }
  61. fmt.Println("getURL = ", getURL)
  62. go httpclient.ZohoGet(getURL)
  63. return
  64. }
  65. }
  66. }
  67. }
  68. CallNotify(event)
  69. }
  70. func CallNotify(event map[string]string) {
  71. confPath := "/etc/asterisk/crm_api.conf"
  72. cfg, err := ini.Load(confPath)
  73. if err != nil {
  74. lfshook.NewLogger().Error(err)
  75. return
  76. }
  77. ZOHO_URL := cfg.Section("general").Key("zohoUrl").String()
  78. if ZOHO_URL == "" {
  79. lfshook.NewLogger().Error("/etc/asterisk/crm_api.conf not set zohoUrl")
  80. return
  81. }
  82. // var getURL string
  83. // fmt.Println("Context = ", event["Context"])
  84. // 呼叫发起事件
  85. // if event["Event"] == "DialBegin" && event["Context"] == "macro-stdexten" {
  86. // if event["Event"] == "DialBegin" && strings.Compare(event["Context"], "macro-stdexten") == 0 {
  87. if event["Event"] == "DialBegin" {
  88. lfshook.NewLogger().Error(event)
  89. if TimetimesList[event["Linkedid"]] != 0 {
  90. TimetimesList[event["Linkedid"]] = TimetimesList[event["Linkedid"]] + 1
  91. } else {
  92. TimetimesList[event["Linkedid"]] = 1
  93. }
  94. Channel := strings.Split(event["Channel"], "/")
  95. fmt.Println("Channel[0] = ", Channel[0])
  96. // Outgoing Call - Ringing
  97. if event["Context"] == "macro-trunkdial-failover" {
  98. lfshook.NewLogger().Info("Outgoing Call - Ringing")
  99. fmt.Println("event[] = ", event)
  100. fmt.Println("event = ", event["Event"])
  101. fmt.Println("Linkedid = ", event["Timestamp"])
  102. StartTimeList[event["Linkedid"]] = time.Now().Add(-8 * time.Hour)
  103. // https://www.zohoapis.com/phonebridge/v3/callnotify?type=dialed&state=ringing&id=10031&from=123456789&to=12300000001
  104. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dialed&state=ringing&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"])
  105. // if zohoUser != "" {
  106. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  107. // }
  108. fmt.Println("getURL = ", getURL)
  109. go httpclient.ZohoGet(getURL)
  110. // Incoming Call - Ringing
  111. // if event["Context"] == "macro-stdexten" {
  112. } else if (event["Context"] == "macro-stdexten" && Channel[0] != "Local") || (event["Context"] == "macro-stdexten-withoutvm" && Channel[0] != "Local") { // 开启语音留言:macro-stdexten 关闭语音留言:macro-stdexten-withoutvm
  113. lfshook.NewLogger().Error("Incoming Call - Ringing")
  114. fmt.Println("event[] = ", event)
  115. fmt.Println("event = ", event["Event"])
  116. StartTimeList[event["Linkedid"]] = time.Now().Add(-8 * time.Hour)
  117. fmt.Println("Linkedid = ", event["Timestamp"])
  118. // if strings.Compare(event["Context"], "macro-stdexten") == 0 { // OK
  119. // https://www.zohoapis.com/phonebridge/v3/callnotify?type=received&state=ringing&id=10033&from=12300000001&to=123456789
  120. // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ringing&id=%s&from=%s&to=%s", ZOHO_URL, callId, event["Exten"], callDest) // 取得from to 可能不准
  121. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ringing&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"])
  122. // if zohoUser != "" {
  123. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  124. // }
  125. fmt.Println("getURL = ", getURL)
  126. go httpclient.ZohoGet(getURL)
  127. } else if strings.HasPrefix(event["Context"], "department") || strings.HasSuffix(event["Context"], "queue") {
  128. StartTimeList[event["Linkedid"]] = time.Now().Add(-8 * time.Hour)
  129. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ringing&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"])
  130. // if zohoUser != "" {
  131. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  132. // }
  133. fmt.Println("getURL = ", getURL)
  134. go httpclient.ZohoGet(getURL)
  135. }
  136. // 呼叫结束事件
  137. } else if event["Event"] == "DialEnd" {
  138. Channel := strings.Split(event["Channel"], "/")
  139. // 记录呼叫状态
  140. DialStatusList[event["Linkedid"]] = event["DialStatus"]
  141. fmt.Println("DialEnd[] = ", event)
  142. fmt.Println("Channel[0] = ", Channel[0])
  143. // Outgoing Call - Unattended
  144. if event["Context"] == "macro-trunkdial-failover" && event["DialStatus"] == "CANCEL" {
  145. lfshook.NewLogger().Info("Outgoing Call - CANCEL")
  146. fmt.Println("event[] = ", event)
  147. fmt.Println("event = ", event["Event"])
  148. fmt.Println("Linkedid = ", event["Timestamp"])
  149. // startTime := StartTimeList[event["Linkedid"]].Format("2006-01-02 15:04:09")
  150. startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time
  151. startTime := startTimeutc.Format(time.RFC3339)
  152. fmt.Println("startTime: ", startTime)
  153. // https://www.zohoapis.com/phonebridge/v3/callnotify?type=dialed&state=busy&id=10025&from=123456789&to=12300000001&start_time=2024-12-04 15:09:10
  154. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dialed&state=busy&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"], startTime)
  155. // if zohoUser != "" {
  156. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  157. // }
  158. fmt.Println("getURL = ", getURL)
  159. go httpclient.ZohoGet(getURL)
  160. delete(StartTimeList, event["Linkedid"])
  161. // Incoming Call - Missed
  162. // if event["Context"] == "macro-stdexten" && event["DialStatus"] != "ANSWER" {
  163. } else if event["Context"] == "macro-trunkdial-failover" && event["DialStatus"] == "NOANSWER" {
  164. lfshook.NewLogger().Info("Outgoing Call - NOANSWER")
  165. fmt.Println("event[] = ", event)
  166. fmt.Println("event = ", event["Event"])
  167. fmt.Println("Linkedid = ", event["Timestamp"])
  168. // startTime := StartTimeList[event["Linkedid"]].Format("2006-01-02 15:04:09")
  169. startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time
  170. startTime := startTimeutc.Format(time.RFC3339)
  171. fmt.Println("startTime: ", startTime)
  172. // https://www.zohoapis.com/phonebridge/v3/callnotify?type=dialed&state=busy&id=10025&from=123456789&to=12300000001&start_time=2024-12-04 15:09:10
  173. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dialed&state=noanswer&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"], startTime)
  174. // if zohoUser != "" {
  175. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  176. // }
  177. fmt.Println("getURL = ", getURL)
  178. go httpclient.ZohoGet(getURL)
  179. delete(StartTimeList, event["Linkedid"])
  180. // Incoming Call - Missed
  181. // if event["Context"] == "macro-stdexten" && event["DialStatus"] != "ANSWER" {
  182. } else if event["Context"] == "macro-trunkdial-failover" && event["DialStatus"] == "BUSY" {
  183. lfshook.NewLogger().Info("Outgoing Call - BUSY")
  184. fmt.Println("event[] = ", event)
  185. fmt.Println("event = ", event["Event"])
  186. fmt.Println("Linkedid = ", event["Timestamp"])
  187. // startTime := StartTimeList[event["Linkedid"]].Format("2006-01-02 15:04:09")
  188. startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time
  189. startTime := startTimeutc.Format(time.RFC3339)
  190. fmt.Println("startTime: ", startTime)
  191. // https://www.zohoapis.com/phonebridge/v3/callnotify?type=dialed&state=busy&id=10025&from=123456789&to=12300000001&start_time=2024-12-04 15:09:10
  192. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dialed&state=rejected&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"], startTime)
  193. // if zohoUser != "" {
  194. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  195. // }
  196. fmt.Println("getURL = ", getURL)
  197. go httpclient.ZohoGet(getURL)
  198. delete(StartTimeList, event["Linkedid"])
  199. // Incoming Call - Missed
  200. // if event["Context"] == "macro-stdexten" && event["DialStatus"] != "ANSWER" {
  201. } else if (event["Context"] == "macro-stdexten" && event["DialStatus"] != "ANSWER" && Channel[0] != "Local") || (event["Context"] == "macro-stdexten-withoutvm" && event["DialStatus"] != "ANSWER" && Channel[0] != "Local") { // 开启语音留言:macro-stdexten 关闭语音留言:macro-stdexten-withoutvm
  202. lfshook.NewLogger().Error("Incoming Call - Missed")
  203. fmt.Println("event[] = ", event)
  204. fmt.Println("event = ", event["Event"])
  205. // startTime := StartTimeList[event["Linkedid"]].Format("2006-01-02 15:04:09")
  206. startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time
  207. startTime := startTimeutc.Format(time.RFC3339)
  208. fmt.Println("startTime: ", startTime)
  209. fmt.Println("Linkedid = ", event["Timestamp"])
  210. // https://www.zohoapis.com/phonebridge/v3/callnotify?type=received&state=missed&id=10005&from=12300000001&to=123456789&start_time=2024-12-04 15:09:10
  211. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=missed&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"], startTime)
  212. // if zohoUser != "" {
  213. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  214. // }
  215. fmt.Println("getURL = ", getURL)
  216. go httpclient.ZohoGet(getURL)
  217. delete(StartTimeList, event["Linkedid"])
  218. } else if (strings.HasPrefix(event["Context"], "department") || strings.HasSuffix(event["Context"], "queue")) && event["DialStatus"] != "ANSWER" && TimetimesList[event["Linkedid"]] < 2 && TimetimesList[event["Linkedid"]] > 0 {
  219. startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time
  220. startTime := startTimeutc.Format(time.RFC3339)
  221. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=missed&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"], startTime)
  222. // if zohoUser != "" {
  223. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  224. // }
  225. fmt.Println("getURL = ", getURL)
  226. go httpclient.ZohoGet(getURL)
  227. delete(TimetimesList, event["Linkedid"])
  228. } else if (strings.HasPrefix(event["Context"], "department") || strings.HasSuffix(event["Context"], "queue")) && event["DialStatus"] != "ANSWER" && TimetimesList[event["Linkedid"]] >= 2 {
  229. n = n + 1
  230. if TimetimesList[event["Linkedid"]] == n {
  231. lfshook.NewLogger().Error("hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")
  232. startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time
  233. startTime := startTimeutc.Format(time.RFC3339)
  234. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=missed&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"], startTime)
  235. // if zohoUser != "" {
  236. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  237. // }
  238. fmt.Println("getURL = ", getURL)
  239. go httpclient.ZohoGet(getURL)
  240. delete(TimetimesList, event["Linkedid"])
  241. n = 0
  242. }
  243. } else if event["DialStatus"] == "ANSWER" {
  244. delete(TimetimesList, event["Linkedid"])
  245. }
  246. // 呼叫已连接事件
  247. } else if event["Event"] == "BridgeEnter" {
  248. Channel := strings.Split(event["Channel"], "/")
  249. fmt.Println("Channel[0] = ", Channel[0])
  250. // Outgoing Call - Answered
  251. if event["Context"] == "macro-trunkdial-failover" && event["Priority"] == "1" { // 注意这里选择 Priority:1 的,便于确认 CallerIDNum,ConnectedLineNum
  252. // 记录开始时间
  253. // TimestampList[event["Uniqueid"]] = event["Timestamp"] // error 需要把 Uniqueid 改为 Linkedid
  254. // StartTimeList[event["Uniqueid"]] = time.Now() // error 需要把 Uniqueid 改为 Linkedid
  255. lfshook.NewLogger().Info("Outgoing Call - Answered")
  256. fmt.Println("event[] = ", event)
  257. fmt.Println("event = ", event["Event"])
  258. fmt.Println("Linkedid = ", event["Timestamp"])
  259. TimestampList[event["Linkedid"]] = event["Timestamp"]
  260. StartTimeList[event["Linkedid"]] = time.Now().Add(-8 * time.Hour)
  261. LinkedidList["Linkedid"] = event["Linkedid"]
  262. CallTypeList[event["Linkedid"]] = "outgoing"
  263. // https: //www.zohoapis.com/phonebridge/v3/callnotify?type=dialed&state=answered&id=10003&from=123456789&to=12300000001
  264. // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dialed&state=answered&id=%s&from=%s&to=%s", ZOHO_URL, callId, event["CallerIDNum"], event["ConnectedLineNum"])
  265. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dialed&state=answered&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["ConnectedLineNum"], event["CallerIDNum"])
  266. // if zohoUser != "" {
  267. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  268. // }
  269. fmt.Println("getURL = ", getURL)
  270. go httpclient.ZohoGet(getURL)
  271. // Incoming Call - Answered
  272. // if event["Context"] == "macro-stdexten" {
  273. } else if (event["Context"] == "macro-stdexten" || event["Context"] == "macro-stdexten-withoutvm") && Channel[0] != "Local" { // 开启语音留言:macro-stdexten 关闭语音留言:macro-stdexten-withoutvm
  274. // 记录开始时间
  275. // TimestampList[event["Uniqueid"]] = event["Timestamp"] // Uniqueid 有时通话也不合适 NG // 都改为 Linkedid
  276. // StartTimeList[event["Uniqueid"]] = time.Now() // Uniqueid 有时通话也不合适 NG // 都改为 Linkedid
  277. lfshook.NewLogger().Error("Incoming Call - Answered")
  278. fmt.Println("event[] = ", event)
  279. fmt.Println("event = ", event["Event"])
  280. fmt.Println("Linkedid = ", event["Timestamp"])
  281. TimestampList[event["Linkedid"]] = event["Timestamp"] // 呼入时设置 Uniqueid 不是 Linkedid
  282. StartTimeList[event["Linkedid"]] = time.Now().Add(-8 * time.Hour) // 呼入时设置 Uniqueid 不是 Linkedid
  283. LinkedidList["Linkedid"] = event["Linkedid"]
  284. CallTypeList[event["Linkedid"]] = "incoming"
  285. // https://www.zohoapis.com/phonebridge/v3/callnotify?type=received&state=answered&id=10023&from=12300000001&to=123456789
  286. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=answered&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["ConnectedLineNum"])
  287. // if zohoUser != "" {
  288. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  289. // }
  290. fmt.Println("getURL = ", getURL)
  291. go httpclient.ZohoGet(getURL)
  292. } else if (strings.HasPrefix(event["Context"], "department") && event["Priority"] == "1") || strings.HasSuffix(event["Context"], "queue") {
  293. TimestampList[event["Linkedid"]] = event["Timestamp"] // 呼入时设置 Uniqueid 不是 Linkedid
  294. StartTimeList[event["Linkedid"]] = time.Now().Add(-8 * time.Hour) // 呼入时设置 Uniqueid 不是 Linkedid
  295. LinkedidList["Linkedid"] = event["Linkedid"]
  296. CallTypeList[event["Linkedid"]] = "incoming"
  297. if event["Priority"] == "1" {
  298. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=answered&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["ConnectedLineNum"], event["CallerIDNum"])
  299. // if zohoUser != "" {
  300. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  301. // }
  302. fmt.Println("getURL = ", getURL)
  303. go httpclient.ZohoGet(getURL)
  304. } else {
  305. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=answered&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["ConnectedLineNum"])
  306. // if zohoUser != "" {
  307. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  308. // }
  309. fmt.Println("getURL = ", getURL)
  310. go httpclient.ZohoGet(getURL)
  311. }
  312. delete(TimetimesList, event["Linkedid"])
  313. n = 0
  314. }
  315. // 呼叫挂断事件
  316. } else if event["Event"] == "HangupRequest" {
  317. // * ===================================================================================== */
  318. // 判断呼叫状态,为 ANSWER 时才推送,否则见以上推送 Outgoing Call - Unattended 或 Incoming Call - Missed
  319. Channel := strings.Split(event["Channel"], "/")
  320. fmt.Println("event[] = ", event)
  321. fmt.Println("Channel[0] = ", Channel[0])
  322. // lfshook.NewLogger().Errorf("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa %+v", event["Context"])
  323. fmt.Println("ChannelHangupRequest1 = ", DialStatusList[event["Linkedid"]])
  324. fmt.Println("ChannelHangupRequest1 = ", event["DialStatus"])
  325. // if DialStatusList[event["Linkedid"]] == "ANSWER" {//暂时不使用dialend的呼叫状态
  326. lfshook.NewLogger().Errorf("ChannelHangupRequest = %+v", event["Uniqueid"])
  327. fmt.Println("event[] = ", event)
  328. fmt.Println("event = ", event["Event"])
  329. startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time
  330. startTime := startTimeutc.Format(time.RFC3339)
  331. fmt.Println("startTime: ", startTime)
  332. // Outgoing Call - Ended
  333. if event["Context"] == "macro-trunkdial-failover" && CallTypeList[event["Linkedid"]] == "outgoing" {
  334. fmt.Println("Linkedid = ", event["Timestamp"])
  335. durationTime := getDuration(event["Linkedid"], event["Timestamp"])
  336. lfshook.NewLogger().Errorf("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaCallTypeList %+v", CallTypeList)
  337. if durationTime != -1 {
  338. if event["Priority"] == "1" {
  339. // https://www.zohoapis.com/phonebridge/v3/callnotify?type=dailed&state=ended&id=10030&from=123456789&to=12300000001&start_time=2024-12-04 11:32:15&duration=325
  340. // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dailed&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["CallerIDNum"], event["ConnectedLineNum"], startTime, durationTime)
  341. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dailed&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, event["Linkedid"], event["ConnectedLineNum"], event["CallerIDNum"], startTime, durationTime)
  342. // if zohoUser != "" {
  343. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  344. // }
  345. fmt.Println("getURL = ", getURL)
  346. go httpclient.ZohoGet(getURL)
  347. } else {
  348. // https://www.zohoapis.com/phonebridge/v3/callnotify?type=dailed&state=ended&id=10030&from=123456789&to=12300000001&start_time=2024-12-04 11:32:15&duration=325
  349. // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dailed&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["CallerIDNum"], event["ConnectedLineNum"], startTime, durationTime)
  350. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dailed&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["ConnectedLineNum"], startTime, durationTime)
  351. // if zohoUser != "" {
  352. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  353. // }
  354. fmt.Println("getURL = ", getURL)
  355. go httpclient.ZohoGet(getURL)
  356. }
  357. }
  358. // 删除记录时间
  359. delete(StartTimeList, event["Linkedid"])
  360. delete(CallTypeList, event["Linkedid"])
  361. // Incoming Call - Ended
  362. // // if event["Context"] == "macro-stdexten" { // Context:DialPlan1
  363. // } else if Channel[0] != "Local" && durationTime != -1 { // 开启语音留言:macro-stdexten 关闭语音留言:macro-stdexten-withoutvm
  364. } else if Channel[0] != "Local" && CallTypeList[event["Linkedid"]] == "incoming" {
  365. // if event["Context"] != "macro-trunkdial-failover" {
  366. fmt.Println("Linkedid = ", event["Timestamp"])
  367. durationTime := getDuration(event["Linkedid"], event["Timestamp"])
  368. if durationTime != -1 {
  369. if event["Priority"] == "1" {
  370. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, event["Linkedid"], event["ConnectedLineNum"], event["CallerIDNum"], startTime, durationTime)
  371. // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["ConnectedLineNum"], event["CallerIDName"], startTime, durationTime)
  372. // if zohoUser != "" {
  373. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  374. // }
  375. fmt.Println("getURL = ", getURL)
  376. go httpclient.ZohoGet(getURL)
  377. } else {
  378. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["ConnectedLineNum"], startTime, durationTime)
  379. // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["ConnectedLineNum"], event["CallerIDName"], startTime, durationTime)
  380. // if zohoUser != "" {
  381. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  382. // }
  383. fmt.Println("getURL = ", getURL)
  384. go httpclient.ZohoGet(getURL)
  385. }
  386. }
  387. delete(StartTimeList, event["Linkedid"])
  388. delete(CallTypeList, event["Linkedid"])
  389. // 还需优化判断,开启语音留言时,主叫挂断才是 macro-stdexten , 被叫挂断是 DialPlan1
  390. // 关闭语音留言时,主叫挂断才是 macro-stdexten-withoutvm , 被叫挂断是 DialPlan1
  391. // 如果 Outgoing Call 只会是 macro-trunkdial-failover 的话,那么和以下判断换一下,else 不判断,都为 Incoming Call 处理
  392. }
  393. // }
  394. } else if event["Event"] == "AttendedTransfer" { //热转接
  395. if event["Result"] == "Success" {
  396. durationTime := getDuration(event["SecondTransfererLinkedid"], event["Timestamp"])
  397. startTimeutc := StartTimeList[event["SecondTransfererLinkedid"]].In(time.UTC) // 存储从string 改为 time.Time
  398. startTime := startTimeutc.Format(time.RFC3339)
  399. fmt.Println("startTime: ", startTime)
  400. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, event["SecondTransfererLinkedid"], event["TransfereeCallerIDNum"], event["TransfereeConnectedLineNum"], startTime, durationTime)
  401. // if zohoUser != "" {
  402. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  403. // }
  404. fmt.Println("getURL = ", getURL)
  405. go httpclient.ZohoGet(getURL)
  406. }
  407. } else if event["Event"] == "SoftHangupRequest" {
  408. Channel := strings.Split(event["Channel"], "/")
  409. if (event["Context"] == "macro-stdexten" || event["Context"] == "macro-stdexten-withoutvm") && Channel[0] != "Local" && len(event["Exten"]) > 3 {
  410. startTimebj := time.Now().Add(-8 * time.Hour)
  411. startTimeutc := startTimebj.In(time.UTC) // 存储从string 改为 time.Time
  412. startTime := startTimeutc.Format(time.RFC3339)
  413. if event["ConnectedLineNum"] == "<unknown>" {
  414. ConnectedLineNum := strings.Split(strings.Split(event["ConnectedLineNum"], "<")[1], ">")[0]
  415. getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=missed&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], ConnectedLineNum, startTime)
  416. // if zohoUser != "" {
  417. // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  418. // }
  419. fmt.Println("getURL = ", getURL)
  420. go httpclient.ZohoGet(getURL)
  421. }
  422. }
  423. }
  424. // else if event["Event"] == "SoftHangupRequest" {
  425. // Channel := strings.Split(event["Channel"], "/")
  426. // if event["Exten"] == "s-CHANUNAVAIL" && Channel[0] != "Local" {
  427. // startTimebj := time.Now().Add(-8 * time.Hour)
  428. // startTimeutc := startTimebj.In(time.UTC) // 存储从string 改为 time.Time
  429. // startTime := startTimeutc.Format(time.RFC3339)
  430. // ConnectedLineNum := strings.Split(strings.Split(event["ConnectedLineNum"], "<")[1], ">")[0]
  431. // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=missed&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], ConnectedLineNum, startTime)
  432. // // if zohoUser != "" {
  433. // // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  434. // // }
  435. // fmt.Println("getURL = ", getURL)
  436. // go httpclient.ZohoGet(getURL)
  437. // }
  438. // }
  439. // else if event["Event"] == "Cdr" {
  440. // if event["Disposition"] == "ANSWERED" && event["CallType"] == "incoming" && strings.HasPrefix(event["DestinationContext"], "department") {
  441. // durationTime := getDuration(LinkedidList["Linkedid"], event["Timestamp"])
  442. // startTimeutc := StartTimeList[LinkedidList["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time
  443. // startTime := startTimeutc.Format(time.RFC3339)
  444. // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, event["Linkedid"], event["Source"], event["Destination"], startTime, durationTime)
  445. // // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["ConnectedLineNum"], event["CallerIDName"], startTime, durationTime)
  446. // // if zohoUser != "" {
  447. // // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  448. // // }
  449. // fmt.Println("getURL = ", getURL)
  450. // go httpclient.ZohoGet(getURL)
  451. // delete(LinkedidList, "Linkedid")
  452. // }
  453. // }
  454. // else if event["Event"] == "Cdr" {
  455. // if event["Disposition"] == "ANSWERED" {
  456. // durationTime := getDuration(LinkedidList["Linkedid"], event["Timestamp"])
  457. // startTimeutc := StartTimeList[LinkedidList["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time
  458. // startTime := startTimeutc.Format(time.RFC3339)
  459. // CallSrcNum := strings.Split(strings.Split(event["CallSrcNum"], "<")[1], ">")[0]
  460. // if event["CallType"] == "outgoing" {
  461. // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dailed&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, LinkedidList["Linkedid"], CallSrcNum, event["CallDestNum"], startTime, durationTime)
  462. // // if zohoUser != "" {
  463. // // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  464. // // }
  465. // fmt.Println("getURL = ", getURL)
  466. // go httpclient.ZohoGet(getURL)
  467. // delete(LinkedidList, "Linkedid")
  468. // } else if event["CallType"] == "incoming" {
  469. // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, LinkedidList["Linkedid"], CallSrcNum, event["CallDestNum"], startTime, durationTime)
  470. // // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["ConnectedLineNum"], event["CallerIDName"], startTime, durationTime)
  471. // // if zohoUser != "" {
  472. // // getURL = fmt.Sprintf("%s&zohouser=%s", getURL, zohoUser)
  473. // // }
  474. // fmt.Println("getURL = ", getURL)
  475. // go httpclient.ZohoGet(getURL)
  476. // delete(LinkedidList, "Linkedid")
  477. // }
  478. // }
  479. // }
  480. // fmt.Println("getURL = ", getURL)
  481. // 测试验证下上面有没有删除,以防TimestampList越来越大
  482. // for k, v := range TimestampList {
  483. // fmt.Printf("===Linkedid:%s Timestamp:%s===\n", k, v)
  484. // }
  485. }
  486. // 使用事件中event["Timestamp"]的值计算时间间隔
  487. // func getDuration(uniqueid string, timeStamp string) int {
  488. func getDuration(linkedid string, timeStamp string) int { // 都改为 Linkedid
  489. fmt.Println("startTimeStamp Str: ", TimestampList[linkedid])
  490. if TimestampList[linkedid] == "" || timeStamp == "" {
  491. fmt.Printf("linkedid 或 timeStamp 为空\n")
  492. return -1
  493. }
  494. startTimeStamp, err := strconv.ParseFloat(TimestampList[linkedid], 64)
  495. if err != nil {
  496. fmt.Printf("startTimeStamp转换出错: %v\n", err)
  497. return -1
  498. }
  499. fmt.Printf("startTimeStamp=%f\n", startTimeStamp)
  500. endTimeStamp, err := strconv.ParseFloat(timeStamp, 64)
  501. if err != nil {
  502. fmt.Printf("endTimeStamp转换出错: %v\n", err)
  503. return -1
  504. }
  505. fmt.Printf("endTimeStamp=%f\n", endTimeStamp)
  506. durationTime := time.Duration(endTimeStamp-startTimeStamp) * time.Second
  507. // fmt.Println("durationTime=", durationTime) // durationTime= 35s
  508. // fmt.Printf("durationTime=%d\n", durationTime) // durationTime=35000000000
  509. // fmt.Printf("durationTime=%d\n", durationTime.Seconds()) // durationTime=%!d(float64=35)
  510. // fmt.Printf("durationTime=%f\n", durationTime.Seconds()) // durationTime=35.000000
  511. fmt.Printf("durationTime=%d\n", int(durationTime.Seconds())) // durationTime=35
  512. // durationTime001 := time.Duration(endTimeStamp - startTimeStamp)
  513. // fmt.Println("durationTime001=", durationTime001) // durationTime001= 35ns
  514. // durationTime003 := time.Duration(endTimeStamp - startTimeStamp).Seconds()
  515. // fmt.Println("durationTime003=", durationTime003) // durationTime003= 3.5e-08
  516. // 删除记录时间
  517. delete(TimestampList, linkedid)
  518. // return durationTime
  519. return int(durationTime.Seconds())
  520. }
  521. // @tags PBX-zoho
  522. // @Summary 刷新token
  523. // @Description 刷新token
  524. // @Security ZohoToken
  525. // @Accept json
  526. // @Produce json
  527. // @Router /api/zoho/refresh-token [post]
  528. func RefreshToken() {
  529. fmt.Printf("RefreshToken ............\n")
  530. // 获取配置文件信息
  531. // confPath := "/etc/asterisk/vtiger_api.conf"
  532. confPath := "/etc/asterisk/crm_api.conf"
  533. cfg, err := ini.Load(confPath)
  534. if err != nil {
  535. lfshook.NewLogger().Error(err)
  536. return
  537. }
  538. ZohoAuthUrl := cfg.Section("general").Key("zohoAuthUrl").String()
  539. ZohoRefreshToken := cfg.Section("general").Key("zohoRefreshToken").String()
  540. ZohoClientId := cfg.Section("general").Key("zohoClientId").String()
  541. ZohoClientSecret := cfg.Section("general").Key("zohoClientSecret").String()
  542. if ZohoAuthUrl == "" || ZohoRefreshToken == "" || ZohoClientId == "" || ZohoClientSecret == "" {
  543. lfshook.NewLogger().Error("/etc/asterisk/crm_api.conf not set zohoAuthUrl or zohoRefreshToken or zohoClientId or zohoClientSecret")
  544. return
  545. }
  546. // 创建请求
  547. // https://accounts.zoho.com/oauth/v2/token?refresh_token=1004.86c8c0e3db7bfe9133598825bef28eb9.17a82a3bf3e675c504f478c1b0b5c456
  548. // &client_id=1004.LWJCJZD5O9DB6SZLL5YJEWHT7LH0BV&client_secret=fc3aef43dc58af8a49d3ed597710924200b03f74d0&grant_type=refresh_token
  549. getURL := fmt.Sprintf("%s/oauth/v2/token?refresh_token=%s&client_id=%s&client_secret=%s&grant_type=refresh_token", ZohoAuthUrl, ZohoRefreshToken, ZohoClientId, ZohoClientSecret)
  550. fmt.Printf("getURL = %s\n", getURL)
  551. // data := httpRequest(ctx, "POST", getURL)
  552. // /* =====================================================================================
  553. req, err := http.NewRequest("POST", getURL, nil)
  554. if err != nil {
  555. fmt.Println("创建请求时发生错误:", err)
  556. return
  557. }
  558. // 创建HTTP客户端
  559. client := &http.Client{}
  560. // req.Header.Set("Authorization", "Bearer "+accessToken) // 刷新token时不需要
  561. // 发送请求
  562. resp, err := client.Do(req)
  563. if err != nil {
  564. fmt.Println("发送请求时发生错误:", err)
  565. return
  566. }
  567. defer resp.Body.Close()
  568. // 读取请求后的响应
  569. data, err := ioutil.ReadAll(resp.Body)
  570. if err != nil {
  571. // 读取数据错误
  572. lfshook.NewLogger().Warn("ioutil ReadAll failed :", err.Error())
  573. // api.Error(ctx, http.StatusInternalServerError, err.Error())
  574. return
  575. }
  576. lfshook.NewLogger().Infof("data %+v", string(data))
  577. // * ===================================================================================== */
  578. refreshTokenData := RefreshTokenResp{}
  579. err = json.Unmarshal([]byte(data), &refreshTokenData)
  580. if err != nil {
  581. // 转换数据错误
  582. lfshook.NewLogger().Warn("json unmarshal failed :", err.Error())
  583. // api.Error(ctx, http.StatusInternalServerError, err.Error())
  584. return
  585. }
  586. // 将获取的 access_token 写入文件 crm_api.conf
  587. cfg.Section("general").Key("zohoAccessToken").SetValue(refreshTokenData.AccessToken)
  588. err = cfg.SaveTo(confPath)
  589. if err != nil {
  590. lfshook.NewLogger().Error(err)
  591. // api.Error(ctx, http.StatusInternalServerError, err.Error())
  592. return
  593. }
  594. // 打印请求后的响应
  595. fmt.Printf("data = %+v\n", string(data))
  596. // api.Success(ctx, string(data))
  597. // api.Success(ctx, refreshTokenData)
  598. // return
  599. }
  600. // 每隔55分钟刷新token
  601. func RefreshTokenTicker() {
  602. fmt.Printf("RefreshTokenTicker ............\n")
  603. ticker := time.NewTicker(55 * time.Minute)
  604. defer ticker.Stop()
  605. done := make(chan bool)
  606. // go func() { // 注释掉OK
  607. for {
  608. select {
  609. case <-done:
  610. return
  611. case t := <-ticker.C:
  612. fmt.Println("Tick at", t)
  613. RefreshToken()
  614. }
  615. }
  616. // }()
  617. }