push.go 30 KB

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