resourceChannel.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. package resourceChannel
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "github.com/aliyun/aliyun-oss-go-sdk/oss"
  7. "github.com/go-redis/redis"
  8. "golang.org/x/net/context"
  9. "io/ioutil"
  10. "log"
  11. "net/http"
  12. "net/url"
  13. "os"
  14. "path"
  15. "runtime"
  16. "strconv"
  17. "strings"
  18. "time"
  19. )
  20. func redisCli() *redis.Client {
  21. client := redis.NewClient(&redis.Options{
  22. //Addr: coo.RedisHost, // Redis地址
  23. Addr: "192.168.204.193:6379", // Redis地址
  24. Password: "", // Redis密码,默认为空
  25. DB: 1, // 使用哪个数据库,默认为0
  26. })
  27. _, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
  28. defer cancel()
  29. return client
  30. }
  31. type ResourceAssessment struct {
  32. ID uint `gorm:"primaryKey" json:"id"` // 留学评估表
  33. DataType uint8 `json:"data_type"` // 1.网课 2.api资源 3.专题页 4.工作台录入 5.后台录入 6 小程序
  34. ChatID string `json:"chat_id"` // 会话id
  35. Channel int `json:"channel"` // 渠道id
  36. Category int `json:"category"` // 分类id
  37. CreatedAt time.Time `json:"created_at"` // 数据创建时间
  38. ReferPageURL string `json:"refer_page_url"` // 来源网址
  39. URL string `json:"url"` // 落地页地址
  40. ChatURL string `json:"chat_url"` // 对话发起页
  41. GrUserId string `json:"gr_user_id"` // 神策distinct_id
  42. }
  43. type SemJsChatRecord struct {
  44. ChatID int64 `gorm:"column:CHAT_ID"`
  45. CreateTime time.Time `gorm:"column:CREATE_TIME"`
  46. ReferPage string `gorm:"type:text;column:REFER_PAGE"`
  47. ChatURL string `gorm:"type:text;column:CHAT_URL"`
  48. ChannleID int `gorm:"column:CHANNLE_ID"`
  49. CategoryID int `gorm:"column:CATEGORY_ID"`
  50. GrUserID string `gorm:"column:gr_user_id"`
  51. SourceUrl string `gorm:"column:source_url"`
  52. }
  53. type ChannelCategory struct {
  54. Channel int
  55. Category int
  56. }
  57. // GetChannel 表单渠道归因处理
  58. func GetChannel(assessment ResourceAssessment) ChannelCategory {
  59. log.Printf("%v", assessment)
  60. // 获取神策URL(不包含utm)
  61. cc, _ := redisCli().Get("website:" + assessment.GrUserId).Result()
  62. var websiteUrl SensorsData
  63. json.Unmarshal([]byte(cc), &websiteUrl)
  64. // 到梦解析
  65. if !strings.Contains(assessment.URL, "utm") && !strings.Contains(assessment.ChatURL, "utm") && !strings.Contains(assessment.ReferPageURL, "utm") && (strings.Contains(assessment.ReferPageURL, "daomeng") || strings.Contains(assessment.ChatURL, "daomeng")) {
  66. log.Printf("解析到梦")
  67. assessment.Channel = 38
  68. assessment.Category = getCategory(201)
  69. return ChannelCategory{assessment.Channel, assessment.Category}
  70. }
  71. // 网课解析
  72. if assessment.DataType == 1 {
  73. log.Printf("解析网课")
  74. assessment.Channel = 26
  75. assessment.Category = getCategory(121)
  76. return ChannelCategory{assessment.Channel, assessment.Category}
  77. }
  78. // 小程序解析
  79. if strings.Contains(assessment.ChatURL, "pages") && strings.Split(strings.Split(assessment.ChatURL, "?")[1], "=")[0] == "miniapp" && (strings.Contains(assessment.ChatURL, "baidu") || strings.Contains(assessment.ChatURL, "wechat")) {
  80. log.Printf("解析小程序")
  81. appType := strings.Split(strings.Split(strings.Split(assessment.ChatURL, "?")[1], "=")[1], "_")[1]
  82. if appType == "baidu" {
  83. assessment.Channel = 1
  84. assessment.Category = getCategory(30)
  85. } else if appType == "wechat" {
  86. assessment.Channel = 8
  87. assessment.Category = getCategory(32)
  88. }
  89. return ChannelCategory{assessment.Channel, assessment.Category}
  90. }
  91. // URL解析
  92. if strings.Contains(assessment.URL, "link=") || strings.Contains(assessment.ReferPageURL, "link=") || strings.Contains(assessment.ChatURL, "link=") {
  93. log.Printf("解析URL")
  94. if len(strings.Split(assessment.URL, "_")) == 3 {
  95. var category, _ = strconv.Atoi(strings.Split(assessment.URL, "_")[1])
  96. if category > 10000 {
  97. assessment.Channel = category
  98. assessment.Category = category
  99. }
  100. }
  101. if strings.Contains(assessment.URL, "link=") {
  102. split := strings.Split(assessment.URL, "link")
  103. if strings.Contains(split[1], "form") || strings.Contains(split[1], "from") {
  104. assessment.Channel, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.URL, "link")[1], "form")[0], "_")[1])
  105. var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.URL, "link")[1], "form")[0], "_")[2])
  106. assessment.Category = getCategory(category)
  107. } else {
  108. assessment.Channel = 5
  109. assessment.Category = getCategory(11)
  110. }
  111. } else if strings.Contains(assessment.ReferPageURL, "link=") {
  112. split := strings.Split(assessment.ReferPageURL, "link")
  113. if strings.Contains(split[1], "form") || strings.Contains(split[1], "from") {
  114. assessment.Channel, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.ReferPageURL, "link")[1], "form")[0], "_")[1])
  115. var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.ReferPageURL, "link")[1], "form")[0], "_")[2])
  116. assessment.Category = getCategory(category)
  117. } else {
  118. assessment.Channel = 5
  119. assessment.Category = getCategory(11)
  120. }
  121. } else {
  122. split := strings.Split(assessment.ChatURL, "link")
  123. if strings.Contains(split[1], "form") || strings.Contains(split[1], "from") {
  124. assessment.Channel, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.ChatURL, "link")[1], "form")[0], "_")[1])
  125. var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.ChatURL, "link")[1], "form")[0], "_")[2])
  126. assessment.Category = getCategory(category)
  127. } else {
  128. assessment.Channel = 5
  129. assessment.Category = getCategory(11)
  130. }
  131. }
  132. // 百度惠生活渠道合并
  133. if assessment.Category == 239 {
  134. assessment.Category = getCategory(292)
  135. }
  136. return ChannelCategory{assessment.Channel, assessment.Category}
  137. }
  138. // 获取神策url(包含utm)
  139. cc1, _ := redisCli().Get("sensors:" + assessment.GrUserId).Result()
  140. var utmUrl SensorsData
  141. json.Unmarshal([]byte(cc1), &utmUrl)
  142. // 神策解析
  143. if utmUrl.Url != "" && !strings.Contains(assessment.URL, "link=") && !strings.Contains(assessment.ReferPageURL, "link=") && !strings.Contains(assessment.ChatURL, "link=") {
  144. log.Printf("解析神策")
  145. assessment.Channel = utmUrl.Channel
  146. assessment.Category = utmUrl.Category
  147. // 百度惠生活渠道合并
  148. if assessment.Category == 239 {
  149. assessment.Category = getCategory(292)
  150. }
  151. return ChannelCategory{assessment.Channel, assessment.Category}
  152. }
  153. // 搜索引擎SEO,外链解析
  154. if assessment.ReferPageURL != "" && !strings.Contains(assessment.ReferPageURL, "https://www.jjl.cn/") && !strings.Contains(assessment.ReferPageURL, "https://m.jjl.cn/") {
  155. log.Printf("解析SEO")
  156. assessment.Channel = 5
  157. assessment.Category = getCategory(11)
  158. return ChannelCategory{assessment.Channel, assessment.Category}
  159. }
  160. // 官网自然访问解析
  161. if strings.Contains(assessment.URL, "https://www.jjl.cn/") || strings.Contains(assessment.URL, "https://m.jjl.cn/") ||
  162. strings.Contains(assessment.ReferPageURL, "https://www.jjl.cn/") || strings.Contains(assessment.ReferPageURL, "https://m.jjl.cn/") ||
  163. strings.Contains(assessment.ChatURL, "https://www.jjl.cn/") || strings.Contains(assessment.ChatURL, "https://m.jjl.cn/") ||
  164. strings.Contains(utmUrl.Url, "https://www.jjl.cn/") || strings.Contains(utmUrl.Url, "https://m.jjl.cn/") {
  165. log.Printf("解析官网")
  166. assessment.Channel = 7
  167. assessment.Category = getCategory(126)
  168. return ChannelCategory{assessment.Channel, assessment.Category}
  169. }
  170. log.Printf("默认解析为SEO")
  171. assessment.Channel = 5
  172. assessment.Category = getCategory(11)
  173. return ChannelCategory{assessment.Channel, assessment.Category}
  174. }
  175. // GetChatChannel 会话渠道归因处理
  176. func GetChatChannel(chat SemJsChatRecord) ChannelCategory {
  177. log.Printf("%v", chat)
  178. // 获取神策URL(不包含utm)
  179. cc, _ := redisCli().Get("website:" + chat.GrUserID).Result()
  180. var websiteUrl SensorsData
  181. json.Unmarshal([]byte(cc), &websiteUrl)
  182. // 小程序解析
  183. if strings.Contains(chat.ChatURL, "pages") && strings.Split(strings.Split(chat.ChatURL, "?")[1], "=")[0] == "miniapp" && (strings.Contains(chat.ChatURL, "baidu") || strings.Contains(chat.ChatURL, "wechat")) {
  184. log.Printf("小程序解析")
  185. log.Printf(chat.ChatURL)
  186. appType := strings.Split(strings.Split(strings.Split(chat.ChatURL, "?")[1], "=")[1], "_")[1]
  187. if appType == "baidu" {
  188. chat.ChannleID = 1
  189. chat.CategoryID = getCategory(30)
  190. } else if appType == "wechat" {
  191. chat.ChannleID = 8
  192. chat.CategoryID = getCategory(32)
  193. }
  194. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  195. }
  196. // 到梦解析
  197. if !strings.Contains(chat.ReferPage, "utm") && !strings.Contains(chat.ChatURL, "utm") && (strings.Contains(chat.ReferPage, "daomeng") || strings.Contains(chat.ChatURL, "daomeng")) {
  198. log.Printf("到梦解析")
  199. chat.ChannleID = 38
  200. chat.CategoryID = getCategory(201)
  201. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  202. }
  203. // URL解析
  204. if strings.Contains(chat.ChatURL, "link=") || strings.Contains(chat.ReferPage, "link=") {
  205. log.Printf("解析CHATURL")
  206. if strings.Contains(chat.ChatURL, "link=") {
  207. split := strings.Split(chat.ChatURL, "link=")
  208. if strings.Contains(split[1], "form") || strings.Contains(split[1], "from") {
  209. chat.ChannleID, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(chat.ChatURL, "link")[1], "form")[0], "_")[1])
  210. var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(chat.ChatURL, "link")[1], "form")[0], "_")[2])
  211. chat.CategoryID = getCategory(category)
  212. } else {
  213. chat.ChannleID = 5
  214. chat.CategoryID = getCategory(11)
  215. }
  216. } else {
  217. split := strings.Split(chat.ReferPage, "link=")
  218. if strings.Contains(split[01], "form") || strings.Contains(split[1], "from") {
  219. chat.ChannleID, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(chat.ReferPage, "link")[1], "form")[0], "_")[1])
  220. var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(chat.ReferPage, "link")[1], "form")[0], "_")[2])
  221. chat.CategoryID = getCategory(category)
  222. } else {
  223. chat.ChannleID = 5
  224. chat.CategoryID = getCategory(11)
  225. }
  226. }
  227. // 百度惠生活渠道合并
  228. if chat.CategoryID == 239 {
  229. chat.CategoryID = getCategory(292)
  230. }
  231. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  232. }
  233. // 获取神策url(包含utm)
  234. cc1, _ := redisCli().Get("sensors:" + chat.GrUserID).Result()
  235. var utmUrl SensorsData
  236. json.Unmarshal([]byte(cc1), &utmUrl)
  237. // 神策解析
  238. if utmUrl.Url != "" && utmUrl.Channel > 0 && !strings.Contains(chat.ReferPage, "link=") && !strings.Contains(chat.ChatURL, "link=") {
  239. log.Printf("解析神策")
  240. chat.ChannleID = utmUrl.Channel
  241. chat.CategoryID = utmUrl.Category
  242. // 百度惠生活渠道合并
  243. if chat.CategoryID == 239 {
  244. chat.CategoryID = getCategory(292)
  245. }
  246. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  247. }
  248. // 搜索引擎SEO,外链解析
  249. if chat.ReferPage != "" && !strings.Contains(chat.ReferPage, "https://www.jjl.cn/") && !strings.Contains(chat.ReferPage, "https://m.jjl.cn/") {
  250. log.Printf("解析SEO")
  251. chat.ChannleID = 5
  252. chat.CategoryID = getCategory(11)
  253. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  254. }
  255. // 官网自然访问解析
  256. if strings.Contains(chat.ReferPage, "https://www.jjl.cn/") || strings.Contains(chat.ReferPage, "https://m.jjl.cn/") ||
  257. strings.Contains(chat.ChatURL, "https://www.jjl.cn/") || strings.Contains(chat.ChatURL, "https://m.jjl.cn/") ||
  258. strings.Contains(utmUrl.Url, "https://www.jjl.cn/") || strings.Contains(utmUrl.Url, "https://m.jjl.cn/") {
  259. log.Printf("解析官网")
  260. chat.ChannleID = 7
  261. chat.CategoryID = getCategory(126)
  262. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  263. }
  264. log.Printf("默认解析为SEO")
  265. chat.ChannleID = 5
  266. chat.CategoryID = getCategory(11)
  267. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  268. }
  269. type SensorsData struct {
  270. DistinctId string `json:"distinctID"`
  271. Channel int `json:"channel"`
  272. Category int `json:"category"`
  273. Url string `json:"url"`
  274. }
  275. // 访问神策API
  276. func getSensorsData(sql string) string {
  277. sensorsUrl := "http://10.0.6.35:8107/api/sql/query?token=128d837f466684101710cfb308e7556de975b717c6c2465ba5fc2836d57a64c8&project=production&type=impala&q=" + url.QueryEscape(sql) + "&format=json"
  278. data := []byte("")
  279. log.Printf("REQ_URL:%s", sensorsUrl)
  280. req, err := http.NewRequest("POST", sensorsUrl, bytes.NewBuffer(data))
  281. if err != nil {
  282. log.Printf("ERROR:%s", err.Error())
  283. return err.Error()
  284. }
  285. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  286. client := &http.Client{}
  287. resp, err := client.Do(req)
  288. if err != nil {
  289. return err.Error()
  290. }
  291. defer resp.Body.Close()
  292. respBody, err := ioutil.ReadAll(resp.Body)
  293. if err != nil {
  294. return err.Error()
  295. }
  296. var sensors Sensors
  297. json.Unmarshal([]byte(string(respBody)), &sensors)
  298. return sensors.LatestReferrer
  299. }
  300. // Sensors 神策数据结构体
  301. type Sensors struct {
  302. Url string `json:"$url"`
  303. LatestReferrer string `json:"$latest_referrer"`
  304. }
  305. type SysChannel struct {
  306. OriginalCategory string `json:"original_category"` // 主键ID
  307. CategoryId string `json:"category_id"` // 备注
  308. }
  309. func getCurrentPath() string {
  310. _, filename, _, _ := runtime.Caller(1)
  311. return path.Dir(filename)
  312. }
  313. func getCategory(OriginalCategory int) int {
  314. endpoint := "oss-cn-beijing.aliyuncs.com" // 例如 "oss-cn-hangzhou.aliyuncs.com"
  315. accessKeyID := "LTAI5t7iAtrYaUgGgK8ws54e"
  316. accessKeySecret := "j4A6llCRqZBMzXLQ7ms84LdKl9l0IS"
  317. bucketName := "jjl-prod-bucket"
  318. objectName := "channel/category_mapper.json"
  319. client, err := oss.New(endpoint, accessKeyID, accessKeySecret)
  320. if err != nil {
  321. log.Fatalf("创建OSS客户端失败: %v", err)
  322. }
  323. // 获取存储空间
  324. bucket, err := client.Bucket(bucketName)
  325. if err != nil {
  326. log.Fatalf("获取Bucket失败: %v", err)
  327. }
  328. // 获取对象
  329. body, err := bucket.GetObject(objectName)
  330. if err != nil {
  331. log.Fatalf("获取对象失败: %v", err)
  332. }
  333. defer body.Close()
  334. // 读取对象内容
  335. var channel []SysChannel
  336. decoder := json.NewDecoder(body)
  337. if err := decoder.Decode(&channel); err != nil {
  338. log.Fatalf("解析JSON失败: %v", err)
  339. }
  340. for i := range channel {
  341. ori, _ := strconv.Atoi(channel[i].OriginalCategory)
  342. if ori == OriginalCategory {
  343. category, _ := strconv.Atoi(channel[i].CategoryId)
  344. return category
  345. }
  346. }
  347. return -1
  348. }