jiantaoli 4 年之前
父節點
當前提交
16197f0235

a → .gitignore


+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
1
+# Default ignored files
2
+/shelf/
3
+/workspace.xml
4
+# Datasource local storage ignored files
5
+/dataSources/
6
+/dataSources.local.xml
7
+# Editor-based HTTP Client requests
8
+/httpRequests/

+ 8 - 0
.idea/miads.iml

@@ -0,0 +1,8 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<module type="WEB_MODULE" version="4">
3
+  <component name="NewModuleRootManager">
4
+    <content url="file://$MODULE_DIR$" />
5
+    <orderEntry type="inheritedJdk" />
6
+    <orderEntry type="sourceFolder" forTests="false" />
7
+  </component>
8
+</module>

+ 6 - 0
.idea/misc.xml

@@ -0,0 +1,6 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="JavaScriptSettings">
4
+    <option name="languageLevel" value="ES6" />
5
+  </component>
6
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="ProjectModuleManager">
4
+    <modules>
5
+      <module fileurl="file://$PROJECT_DIR$/.idea/miads.iml" filepath="$PROJECT_DIR$/.idea/miads.iml" />
6
+    </modules>
7
+  </component>
8
+</project>

+ 522 - 0
ads_handler.go

@@ -0,0 +1,522 @@
1
+package main
2
+
3
+import (
4
+	"fmt"
5
+	"github.com/gin-gonic/gin"
6
+	"math/rand"
7
+	"miads/adslib"
8
+	"miads/adslib/addata"
9
+	"miads/adslib/ads_checker"
10
+	"miads/adslib/city"
11
+	"miads/adslib/device"
12
+	"miads/adslib/graylog"
13
+	"miads/adslib/ip2region"
14
+	"miads/adslib/redis_data"
15
+	"miads/adslib/utils"
16
+	"net/url"
17
+	"strconv"
18
+	"strings"
19
+	"time"
20
+)
21
+
22
+var DECRYPT_KEY = "%videoopen%!@#$%"
23
+
24
+func adsHandler(c *gin.Context) {
25
+	c.Header("Content-Type", "application/json")
26
+
27
+	request := Request{}
28
+	request.Parse(c)
29
+	//uaClientOrigin := utils.GetArgument(c, "ua","")
30
+	//originMac := utils.GetArgument(c, "mac","")
31
+	//clientImei := request.Imei
32
+
33
+	fmt.Printf("%+v", request)
34
+	advertiser := "xiaomi"
35
+	uaClient := request.UaClient
36
+	// 获取ua
37
+	if uaClient == "" {
38
+		uaClient = c.GetHeader("User-Agent")
39
+		if uaClient == "" {
40
+			uaClient = "Dalvik/2.1.0 (Linux; U; Android 6.0.1; MI 4LTE MIUI/6.9.1)"
41
+		}
42
+	}
43
+
44
+	// 获取ip
45
+	checkReqSourceFlag, err := ads_checker.CheckReqSource(request.ReqSource)
46
+	if err != nil {
47
+		c.String(404, "check req source failed")
48
+		return
49
+	}
50
+
51
+	ip := ""
52
+	if checkReqSourceFlag {
53
+		ip = request.ReqSourceIp
54
+	}
55
+
56
+	if ip=="" {
57
+		ip = c.GetHeader("X-Forwarded-For")
58
+	}
59
+
60
+	if ip == "" {
61
+		ip = c.GetHeader("X-Real-IP")
62
+	}
63
+	if ip == "" {
64
+		ip = c.Request.RemoteAddr
65
+	}
66
+	if strings.Index(ip, ",") != -1 {
67
+		ip = strings.Split(ip, ",")[0]
68
+	}
69
+
70
+	ipInfo, err := ip2region.Ip2Region(ip)
71
+	if err != nil {
72
+		c.String(404, "ip 2 region failed")
73
+		return
74
+	}
75
+
76
+	// 上報
77
+	if request.NewAdsFlag == 1 {
78
+		grayLogData := struct {
79
+			Ip string
80
+			Imei string
81
+			Model string
82
+			NetworkType string `json:"network_type"`
83
+			Provice string
84
+			City string
85
+			ScreeSize string `json:"screen_size"`
86
+			Ua string
87
+			Brand string
88
+			Androidid string `json:"android_id"`
89
+			ShortMessage string `json:"short_message"`
90
+			ReqSource string `json:"req_source"`
91
+		}{
92
+			Ip:           ip,
93
+			Imei:         request.Imei,
94
+			Model:        request.Model,
95
+			NetworkType:  request.NetworkType,
96
+			Provice:      ipInfo.Province,
97
+			City:         ipInfo.City,
98
+			ScreeSize:    request.ScreenSize,
99
+			Ua:           request.UaClient,
100
+			Brand:        request.Brand,
101
+			Androidid:    request.Androidid,
102
+			ShortMessage: "ads_api_log",
103
+			ReqSource:    "zhiku",
104
+		}
105
+
106
+		graylog.Log(grayLogData)
107
+	}
108
+
109
+	cityCode, err := city.GetCityCode(ipInfo.City)
110
+	if err != nil {
111
+		c.String(404, "get city code failed")
112
+		return
113
+	}
114
+
115
+	// 是否是安卓
116
+	if request.Imei =="" {
117
+		device.SetAdsTagLog(advertiser, request.ReqSource, "DS_IOS", cityCode)
118
+		graylog.LogApi("ios_device", request.Idfa,"", request.ReqSource)
119
+	} else {
120
+		device.SetAdsTagLog(advertiser, request.ReqSource,"DS_ANDRIOID", cityCode)
121
+	}
122
+
123
+	freqControlInterval := 600
124
+	// 深圳,东莞强行用600秒控制, 其他地区从配置读取
125
+	if strings.Index(ipInfo.City, "深圳")== -1 && strings.Index(ipInfo.City, "东莞")==-1 {
126
+		// 频率控制
127
+		freqControlConf, err := redis_data.GetFreqCrontolConf(request.ReqSource)
128
+		if err != nil {
129
+			c.String(404, "get freq control conf failed")
130
+			return
131
+		}
132
+
133
+		hour, _ := strconv.Atoi(time.Now().Format("01"))
134
+		tmpCrontrolInterval, ok := freqControlConf.GetControlTime(hour)
135
+		if ok {
136
+			freqControlInterval = tmpCrontrolInterval
137
+		}
138
+	}
139
+
140
+	lastReqTime, err := device.GetIpReqTime(ip)
141
+	if err != nil {
142
+		c.String(404, "get last req time failed")
143
+		return
144
+	}
145
+
146
+	needControl := false
147
+	if request.ReqSource != "wzb_h5"  && lastReqTime != 0  && time.Now().Unix() - lastReqTime < int64(freqControlInterval) {
148
+		// 需要凭空
149
+		needControl = true
150
+		device.SetAdsTagLog(advertiser, request.ReqSource,"DS_FREQ_0", cityCode)
151
+	} else {
152
+		device.SetIpReqTime(ip, time.Now().Unix())
153
+		device.SetAdsTagLog(advertiser, request.ReqSource,"DS_FREQ_1", cityCode)
154
+	}
155
+
156
+	//### 检查是否是ip黑名单
157
+	isIpBlack, err := ads_checker.CheckBlackIp(ip)
158
+	if err != nil {
159
+		c.String(404, "get city code failed")
160
+		return
161
+	}
162
+	if isIpBlack {
163
+		graylog.LogApi("black_ip_list", ip,"", request.ReqSource)
164
+		device.SetAdsTagLog(advertiser, request.ReqSource,"DS_BLACK_IP", cityCode)
165
+	}
166
+
167
+	// 获取渠道的黑白性
168
+	reqChannelFlag, err := redis_data.GetChannelFlag(request.ReqSource,"ads_req")
169
+	if err != nil {
170
+		c.String(404, "get req channel flag failed")
171
+		return
172
+	}
173
+	flowWeight := reqChannelFlag.Weigth
174
+	flowRandomNum := rand.Intn(100)
175
+
176
+	flowFlag := 0  // 有效的百分比
177
+	if flowRandomNum <= flowWeight{
178
+		flowFlag = 1
179
+	}
180
+	if reqChannelFlag.ChannelFlag == 1 {
181
+		device.SetAdsTagLog(advertiser, request.ReqSource,fmt.Sprintf("DS_REQ_SOURCE_{%d}", reqChannelFlag.ChannelFlag), cityCode)
182
+	}
183
+
184
+	// 替换成小米的设备
185
+	replaceFlag := 0
186
+	imei := request.Imei
187
+	sendPhoneType := 0
188
+	userFlag := 0
189
+	originImei := ""
190
+
191
+	// 检查是否是小米的设备
192
+	specialDeviceNum := 0
193
+	if request.ReqSource == "wzb_h5" {
194
+		specialDeviceNum = 6  // wzb_h5渠道只綁定一个imei, 具体愿意不知道
195
+	}
196
+	if request.ReqSource == "moyuntv" || (!request.IsMiDevice() &&
197
+		(!isIpBlack &&  !needControl && reqChannelFlag.ChannelFlag ==1) && flowFlag == 1) {
198
+		randomNum := 3
199
+		deviceConf, realRedisKey, err := device.GetMiDeviceConf(ip, randomNum, specialDeviceNum)
200
+		if err != nil {
201
+			c.String(404, "get req channel flag failed")
202
+			return
203
+		}
204
+		if deviceConf != nil {
205
+			device.SetAdsTagLog(advertiser, request.ReqSource, "DS_CACHE", cityCode) // 通过缓存请求
206
+			imei = deviceConf.Imei
207
+			uaClient = deviceConf.Ua
208
+			originImei = deviceConf.OriginImei
209
+			if imei != "" {
210
+				replaceFlag = 1
211
+				userFlag = 1
212
+			}
213
+		} else {
214
+			// 先从对应的城市找,找不到在走原来的逻辑
215
+			// 上报事件
216
+			graylog.LogApi("city_search_city_code", strconv.Itoa(cityCode), ipInfo.City, request.ReqSource)
217
+			device.SetAdsTagLog(advertiser, request.ReqSource, "DS_CODE_REQ", cityCode) // 可做城市替换
218
+			if cityCode != 0 {
219
+				device.SetAdsTagLog(advertiser, request.ReqSource, "DS_CODE", cityCode) // 替换成功
220
+
221
+				fakeImei := ""
222
+				fakeDeviceConf, leftCnt, err := device.GetDailyFakeDeviceConfByCityCode(cityCode)
223
+				if err != nil {
224
+					c.String(404, "get device conf failed")
225
+					return
226
+				}
227
+
228
+				// 0 没有获取到, 1 获取到了
229
+				gotCityFakeDeviceConfFlag := 0
230
+				replaceUa := ""
231
+				if fakeDeviceConf != nil {
232
+					device.SetAdsTagLog(advertiser, request.ReqSource, "DS_REPL", cityCode)
233
+					device.SetMiDeviceConf(realRedisKey, *fakeDeviceConf)
234
+					imei = fakeDeviceConf.Imei
235
+					uaClient = fakeDeviceConf.Ua
236
+					originImei = fakeDeviceConf.OriginImei
237
+					fakeImei = fakeDeviceConf.Imei
238
+					if fakeDeviceConf.Imei != "" {
239
+						gotCityFakeDeviceConfFlag = 1
240
+						userFlag = 2
241
+						replaceFlag = 1
242
+					}
243
+				}
244
+
245
+				grayLogData := struct {
246
+					ReqSource    string `json:"req_source"`
247
+					OldImei      string `json:"old_imei"`
248
+					NewImei      string `json:"new_imei"`
249
+					IP           string `json:"ip"`
250
+					City         string `json:"city"`
251
+					CityCode     int `json:"city_code"`
252
+					Province     string
253
+					HitFlag      int    `json:"hit_flag"`
254
+					LeftCnt      int    `json:"left_cnt"`
255
+					ReplaceUa    string `json:"replace_ua"`
256
+					ShortMessage string `json:"short_message"`
257
+				}{
258
+					ReqSource:    request.ReqSource,
259
+					OldImei:      request.Imei,
260
+					NewImei:      fakeImei,
261
+					IP:           ip,
262
+					City:         ipInfo.City,
263
+					CityCode:     cityCode,
264
+					Province:     ipInfo.Province,
265
+					HitFlag:      gotCityFakeDeviceConfFlag,
266
+					LeftCnt:      leftCnt,
267
+					ReplaceUa:    replaceUa,
268
+					ShortMessage: "",
269
+				}
270
+
271
+				// 进行日志的上报
272
+				graylog.Log(grayLogData)
273
+			}
274
+		}
275
+
276
+		// 解码ua_client
277
+		uaClient, _ = url.QueryUnescape(uaClient)
278
+	} else if request.IsMiDevice() {
279
+		device.SetAdsTagLog(advertiser, request.ReqSource,"DS_MI_REAL", cityCode)  // 是小米设备
280
+		userFlag = 3
281
+		sendPhoneType = 1
282
+	}
283
+
284
+	// 检查下,替换后的设备是否是黑名单, 再次检查, 防止放入cache后, 新增了黑名单
285
+	isBlackImei, err := device.CheckIsBlackImei(imei, false)
286
+	if err != nil {
287
+		c.String(404, "get device conf failed")
288
+		return
289
+	}
290
+
291
+	if isBlackImei {
292
+		if replaceFlag == 1 {
293
+			device.SetAdsTagLog(advertiser, request.ReqSource, "DS_BLACK_IMEI_REPLACE", cityCode)
294
+		} else {
295
+			device.SetAdsTagLog(advertiser, request.ReqSource,"DS_BLACK_IMEI", cityCode)
296
+		}
297
+	}
298
+
299
+	// 组装公共的dsp_info
300
+	dspInfo := utils.DspParam{}
301
+	dspInfo.Init()
302
+	dspInfo.DspCityCode = cityCode
303
+	dspInfo.Imei = imei
304
+	dspInfo.OriginImei = request.Imei
305
+	dspInfo.OsVersion = request.OsVersion
306
+	dspInfo.Mac = strings.ToUpper(request.Mac)
307
+	dspInfo.OriginMac = request.Mac
308
+	dspInfo.Idfa = request.Idfa
309
+	dspInfo.Model = request.Model
310
+	dspInfo.Brand = request.Brand
311
+	dspInfo.ScreenSize = request.ScreenSize
312
+	dspInfo.NetworkType = request.NetworkType
313
+	dspInfo.Androidid = request.Androidid
314
+	dspInfo.Platform = request.Platform
315
+	dspInfo.Ip = ip
316
+	dspInfo.Ua = uaClient
317
+	dspInfo.City = ipInfo.City
318
+	dspInfo.Province = ipInfo.Province
319
+	dspInfo.UaOrigin = request.UaClient
320
+	dspInfo.ReqSource = request.ReqSource
321
+	if request.IsMiDevice() {
322
+		dspInfo.RealMiFlag = 1
323
+	}
324
+	dspInfo.ReplaceFlag = replaceFlag
325
+	dspInfo.RealReqSource = request.ReqSource
326
+	dspInfo.SendPhoneType = sendPhoneType
327
+	md5Imei := imei
328
+	if dspInfo.ReplaceFlag == 0 {
329
+		md5Imei = utils.Md5(imei)
330
+	}
331
+
332
+	dspInfo.RealMd5Imei = md5Imei
333
+	//response = {'result': 0, 'msg': 'ok','ads_result':''}
334
+	//ads_item = None
335
+	//xiaomi_response = []
336
+	hour, _ := strconv.Atoi(time.Now().Format("01"))
337
+
338
+	canRequest := true
339
+	if 0 <= hour && hour <=1 {
340
+		randNum := rand.Intn(100)
341
+		if randNum > 5 {
342
+			canRequest = false
343
+		}
344
+	}
345
+
346
+	var adData *addata.AdData
347
+	var xiaomiResponse []addata.XiaomiAdData
348
+	xiaomiRspAction := make(map[string]int, 100)
349
+	var adDataNum int
350
+
351
+	// 非频率控制,设备黑名单,ip黑名单,白名单渠道,并且替换了小米设备的
352
+	if canRequest && !isBlackImei && reqChannelFlag.ChannelFlag == 1 && flowFlag ==1 && !isIpBlack && advertiser == "xiaomi" && request.ReqSource  != "" && !isBlackImei && !needControl && (replaceFlag==1 || request.IsMiDevice()) {
353
+		adData, xiaomiResponse, xiaomiRspAction, adDataNum, err = addata.GetAdsInfos(&dspInfo, advertiser)
354
+	}
355
+
356
+	//can_mix_flag = 1
357
+	//xiaomi_response_flag = 0
358
+	if adData != nil &&  len(adData.TargetAddition) > 1 {
359
+		realTarget := ""
360
+		if adData.Target != ""{
361
+			md5Skip := utils.Md5(addata.Target)
362
+			conf := adslib.GetConf()
363
+			realTarget = conf.Host + fmt.Sprintf("?action=LOADING&req_source=%s&advertiser=video&skip=%s&brand=%s&request_id=%s&skip_other=%s",
364
+				dspInfo.ReqSource, "", dspInfo.Brand, dspInfo.RequestId, md5Skip)
365
+
366
+			// 塞入Redis中
367
+			redis_data.SetSkipInfo(md5Skip, adData.Target)
368
+		}
369
+		adData.Target = realTarget
370
+		adData.JsOrderId, _ = redis_data.GetMinScriptOrderByAdv(advertiser)
371
+		adData.UserAgent = uaClient
372
+
373
+		if dspInfo.ReqSource =="kuxin" && adData.Target != "" {
374
+			adData.DpReport = fmt.Sprintf("%s?action=DP_CLICK&advertiser=video&req_source=%s", common.get_request_host(None), dspInfo.ReqSource)
375
+			adData.Dp = adslib.GetConf().DpTest
376
+		}
377
+		if dspInfo.SendPhoneType == 0 {
378
+			device.SetAdsTagLog(advertiser,dspInfo.ReqSource,"ADS_GET", cityCode)  // 广告获取成功
379
+		} else if dspInfo.SendPhoneType==1 {
380
+			device.SetAdsTagLog(advertiser,dspInfo.ReqSource,"ADS_GET_1", cityCode)  // 广告获取成功
381
+		}
382
+		device.SetAdsTagLog(advertiser, dspInfo.ReqSource, fmt.Sprintf("ADS_USER_%d", userFlag), cityCode)  //  广告类型,缓存,新用户,小米手机
383
+		// 判断这个渠道是否要去融合和融合的流量占比
384
+		mixChannelFlag, err := redis_data.GetChannelFlag(dspInfo.ReqSource, "ads_mix")
385
+		if err != nil {
386
+			c.String(404, "get device conf failed")
387
+			return
388
+		}
389
+		flowRandomNum = rand.Intn(100)
390
+		isOverFlow := false
391
+		//flow_flag = 0
392
+		if flowRandomNum > mixChannelFlag.Weigth {
393
+			isOverFlow = true
394
+		}
395
+		if mixChannelFlag.ChannelFlag !=1 || isOverFlow {
396
+			//extra_infos = []
397
+		}
398
+
399
+		adDataNew, err := xiaomi_mix.combine_mix_infos_v2(ads_item,extra_infos)
400
+
401
+		// 组装返回去的action
402
+		//target_addition_infos = ads_item.get('target_addition')
403
+		//server_action_response = {"server_view":0,"server_click":0,"server_close":0,"server_video_finish":0,"server_video_timer":0}
404
+		//for target_info in target_addition_infos:
405
+		//if target_info['type']=="VIEW":
406
+		//server_action_response['server_view']=1
407
+		//redis_device.set_req_source_view('xiaomi',req_source,'xiafa')
408
+		//if target_info['type']=="CLICK":
409
+		//server_action_response['server_click']=1
410
+		//if target_info['type']=="CLOSE":
411
+		//server_action_response['server_close']=1
412
+		//if target_info['type']=="VIDEO_FINISH":
413
+		//server_action_response['server_video_finish']=1
414
+		//if target_info['type']=="VIDEO_TIMER":
415
+		//server_action_response['server_video_timer']=1
416
+		//response_report_flag = 1
417
+
418
+		//#增加跟随订单
419
+		//if len(target_addition_infos) == 2  and server_action_response['server_video_finish'] == 1 and req_source in ['kuxin','zhiku']:
420
+		//from thirds import tt_thirds
421
+		//ads_item_new =yield tt_thirds.combine_order_by(ads_item_new,dsp_info)
422
+		//# 检查最后是否有click
423
+		//last_target_addition_infos = ads_item_new.get('target_addition',[])
424
+		//for last_target_addition_info in last_target_addition_infos:
425
+		//if last_target_addition_info['type']=="CLICK":
426
+		//can_mix_flag = 0
427
+		//break
428
+		//if last_target_addition_info['type']=="VIDEO_TIMER":
429
+		//can_mix_flag = 0
430
+		//break
431
+		//if new_ads_flag==0:
432
+		//response.update(ads_item_new)
433
+		//else:
434
+		//encrypt_ads_item = self.prpcrypt_tools.to_encrypt_content(json.dumps(ads_item_new))
435
+		//response['ads_result']=encrypt_ads_item
436
+		//hour = int(time.strftime("%H",time.localtime(time.time())))
437
+		//if (hour>=0 and hour<=23) and replace_flag==1:
438
+		//random_num = abs(hash(ads_imei))%(10 ** 4)
439
+		//if random_num<3000:
440
+		//response_report_flag = 1
441
+		//else:
442
+		//response_report_flag = 0
443
+		//if response_report_flag==1:
444
+		//try:
445
+		//add_beanstalk_response.BeanstalkHandle().add_ads_response_info(md5_imei,ads_ip,web.utf8(province),web.utf8(city),ads_item_new,dsp_city_code,req_source,real_imei,xiaomi_response,xiaomi_action,server_action_response,dsp_info.request_id,xiaomi_ads_data_num)
446
+		//except:
447
+		//log.send_try_except()
448
+	}
449
+	//if can_mix_flag==1:
450
+	//response['result'] = 2
451
+	//response['msg'] = 'no ads'
452
+	//if xiaomi_response_flag==1:
453
+	//response['result'] = 0
454
+	//response['msg'] = 'ok'
455
+	//#增加打底广告
456
+	//if req_source in ['kuxin','zhiku'] and freq_contro_flag==1 and device_black_flag==0:
457
+	//short_message = "kong"
458
+	//## 先跑定投
459
+	//from thirds import tt_thirds
460
+	//ads_item,extra_item = yield tt_thirds.get_ads_infos(dsp_info,fix_flag=0,xiaomi_has_flag=xiaomi_response_flag)
461
+	//## 定投没有就跑其他的
462
+	//if not extra_item:
463
+	//from thirds import tt_thirds
464
+	//ads_item,extra_item = yield tt_thirds.get_ads_infos(dsp_info,fix_flag=1,xiaomi_has_flag=xiaomi_response_flag)
465
+	//redis_device.set_ads_tag_log(advertiser,req_source,'ADS_ZIYOU_GET',dsp_city_code)  # 广告获取成功
466
+	//if extra_item:
467
+	//short_message = "ads_tt_thirds"
468
+	//order_name = extra_item['order_name']
469
+	//if extra_item and extra_item['order_name'] == 'mh_dsp' and xiaomi_response_flag==0:
470
+	//redis_device.set_ads_tag_log(advertiser,req_source,'ADS_ZIYOU_MH',dsp_city_code)  # 广告获取成功
471
+	//#如果是外部dsp,走这个逻辑
472
+	//from thirds import xiaomi_extra
473
+	//extra_item,ads_item = yield xiaomi_extra.get_ads_infos(dsp_info)
474
+	//short_message = "ads_vast_response"
475
+	//if extra_item and extra_item['order_name']=="xiaodu_dsp" and xiaomi_response_flag==0:
476
+	//redis_device.set_ads_tag_log(advertiser,req_source,'ADS_ZIYOU_XIAODU',dsp_city_code)  # 广告获取成功
477
+	//from thirds import xiaodu
478
+	//extra_item,_ = yield xiaodu.get_ads_infos(dsp_info)
479
+	//short_message = "ads_xiaodu_response"
480
+	//if extra_item is not None and short_message in ['ads_xiaodu_response','ads_vast_response','ads_tt_thirds']:
481
+	//response_data_report = {}
482
+	//response_data_report['ip'] = ads_ip
483
+	//response_data_report['short_message'] =  short_message
484
+	//response_data_report['req_source'] = req_source
485
+	//response_data_report['response_vast'] = json.dumps(extra_item)
486
+	//response_data_report['order_name']=order_name
487
+	//response_data_report['advertiser']=advertiser
488
+	//log.send_to_graylog_tornado(gelf_data=response_data_report)
489
+	//if short_message=="ads_tt_thirds":
490
+	//from thirds import thirds_mix_xiaomi
491
+	//extra_item = thirds_mix_xiaomi.mix_last_infos(extra_item,response)
492
+	//if (extra_item) != None:
493
+	//redis_device.set_ads_tag_log(advertiser,req_source,'ADS_ZIYOU_HAVE',dsp_city_code)  # 广告获取成功
494
+	//if req_source in ['zhiku']:
495
+	//response['result']=0
496
+	//response['msg']='ok'
497
+	//response['ads_result']= self.prpcrypt_tools.to_encrypt_content(json.dumps(extra_item))
498
+	//self.report_graylog(json.dumps(extra_item))
499
+	//self.write(json.dumps(response))
500
+	//self.finish()
501
+	//return
502
+	//else:
503
+	//extra_item['result']=0
504
+	//extra_item['msg']="ok"
505
+	//json_response = json.dumps(extra_item)
506
+	//self.report_graylog(json_response)
507
+	//self.write(json_response)
508
+	//self.finish()
509
+	//return
510
+	//redis_tools.set_ads_real_request_num(advertiser)
511
+	//json_response = json.dumps(response)
512
+	//try:
513
+	//if new_ads_flag==0:
514
+	//self.report_graylog(json_response)
515
+	//redis_device.set_ads_tag_log(advertiser,req_source,'DS_REQ',dsp_city_code)  # 所有请求
516
+	//except:
517
+	//pass
518
+	//self.write(json_response)
519
+	//self.finish()
520
+
521
+	c.String(200, "hehe")
522
+}

+ 549 - 0
adslib/addata/xiaomi.go

@@ -0,0 +1,549 @@
1
+package addata
2
+
3
+import (
4
+	"encoding/json"
5
+	"fmt"
6
+	"html"
7
+	"io/ioutil"
8
+	"math/rand"
9
+	"miads/adslib"
10
+	"miads/adslib/device"
11
+	"miads/adslib/redis_data"
12
+	"miads/adslib/utils"
13
+	"net/http"
14
+	"net/url"
15
+	"strconv"
16
+	"strings"
17
+)
18
+
19
+type XiaomiAdData struct {
20
+DetailURL   string `json:"detail_url"`
21
+DisplayType struct {
22
+Delay    int64  `json:"delay"`
23
+Name     string `json:"name"`
24
+RowCount int64  `json:"row_count"`
25
+} `json:"display_type"`
26
+Duration   int64  `json:"duration"`
27
+EmcType    string `json:"emc_type"`
28
+ID         string `json:"id"`
29
+ImageURL   string `json:"image_url"`
30
+Proportion string `json:"proportion"`
31
+Settings   struct {
32
+ClickType   string `json:"click_type"`
33
+HideCloseAt int64  `json:"hide_close_at"`
34
+LogTime     string `json:"log_time"`
35
+ShowCloseAt int64  `json:"show_close_at"`
36
+} `json:"settings"`
37
+SkipTime        int64    `json:"skip_time"`
38
+TagID           string   `json:"tag_id"`
39
+Target          string   `json:"target"`
40
+TargetAddition  []string `json:"target_addition"`
41
+TargetAddition1 string   `json:"target_addition1"`
42
+Title           string   `json:"title"`
43
+VideoURL        string   `json:"video_url"`
44
+}
45
+
46
+type XiaoMiAdInfoRsp struct {
47
+	Data []XiaomiAdData  `json:"data"`
48
+	Msg    string `json:"msg"`
49
+	Result int64  `json:"result"`
50
+}
51
+
52
+type AdAction struct {
53
+	Type string `json:"type"`
54
+	Duration int `json:"duration"`
55
+	Urls []string `json:"urls"`
56
+}
57
+
58
+type AdInfo struct {
59
+	AdActions []AdAction `json:"ads_infos"`
60
+	PercentBegin int`json:"percent_begin"`
61
+	PercentEnd int`json:"percent_end"`
62
+}
63
+
64
+type AdData struct {
65
+	TargetAddition []AdAction `json:"target_addition"`
66
+	Target string
67
+	ImageUrl string`json:"image_url"`
68
+	Duration int64
69
+	VideoUrl string`json:"video_url"`
70
+	JsOrderId string `json:"js_order_id"`
71
+	UserAgent string `json:"user_agent"`
72
+	DpReport string `json:"dp_report"`
73
+	Dp string `json:"dp"`
74
+}
75
+
76
+func getAdsReqUrl(dsp *utils.DspParam) string {
77
+	reqUrl := "https://m.video.xiaomi.com/api/a3/otv_emc?"
78
+	ref := "yilin"
79
+	sn := "05817a33d4210ad2c67f4b869b5eedde"
80
+	// 组装 emcp
81
+	reqUrl = reqUrl + "_emcp=pre_play"
82
+	// 组装 devid
83
+	reqUrl = reqUrl + "&_devid="+ dsp.RealMd5Imei
84
+	//  组装 ref
85
+	reqUrl = reqUrl + "&ref=" + ref
86
+	// 组装 sn
87
+	reqUrl = reqUrl + "&_sn=" + sn
88
+	// 组装 ip
89
+	reqUrl = reqUrl + "&__ip__=" + dsp.Ip
90
+	rad := rand.Intn(100)
91
+	if rad < 15 {
92
+		dsp.SendPhoneType = 1
93
+	} else {
94
+		dsp.SendPhoneType = 0
95
+	}
96
+	reqUrl = reqUrl + fmt.Sprintf("&_phonetype=%d", dsp.SendPhoneType)
97
+	return reqUrl
98
+}
99
+// 获取广告信息
100
+func GetAdsInfos(dsp *utils.DspParam, advertiser string) (*AdData, []XiaomiAdData, map[string]int, int, error) {
101
+	reqUrl := getAdsReqUrl(dsp)
102
+
103
+	if dsp.SendPhoneType == 0 {
104
+		device.SetAdsTagLog("xiaomi", dsp.ReqSource, "ADS_XIAOMI", dsp.DspCityCode)
105
+	} else if dsp.SendPhoneType == 1{
106
+		device.SetAdsTagLog("xiaomi", dsp.ReqSource, "ADS_XIAOMI_1", dsp.DspCityCode)
107
+	}
108
+
109
+	client := &http.Client{}
110
+	fmt.Printf("req url: %s\n", reqUrl)
111
+	req, err := http.NewRequest("GET", reqUrl,  nil)
112
+	if err != nil {
113
+		return nil, nil, nil, 0, err
114
+	}
115
+
116
+	req.Header.Set(",authority","m.video.xiaomi.com")
117
+	req.Header.Set(",method","GET")
118
+	req.Header.Set(",path", reqUrl[26:])
119
+	req.Header.Set(",scheme","https")
120
+	req.Header.Set("content-type","application/json")
121
+	req.Header.Set("accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3")
122
+	req.Header.Set("accept-encoding","gzip, deflate, br")
123
+	req.Header.Set("accept-language","zh-CN,zh;q=0.9")
124
+	req.Header.Set("cache-control","max-age=0")
125
+	req.Header.Set("upgrade-insecure-requests","1")
126
+	req.Header.Set("user-agent",dsp.Ua)
127
+
128
+	resp, err := client.Do(req)
129
+	if err != nil {
130
+		return nil, nil, nil, 0, err
131
+	}
132
+	defer resp.Body.Close()
133
+	body, err := ioutil.ReadAll(resp.Body)
134
+	fmt.Printf("rsp body: %s\n", body)
135
+	if err != nil {
136
+		return nil, nil, nil, 0, err
137
+	}
138
+	rsp := XiaoMiAdInfoRsp{}
139
+	err = json.Unmarshal(body, &rsp)
140
+	if err != nil {
141
+		return nil, nil, nil, 0, err
142
+	}
143
+
144
+	adsDataNum := len(rsp.Data)
145
+	xiaomiResponseAction := map[string]int {
146
+		"xiaomi_view":0, "xiaomi_click":0, "xiaomi_close":0, "xiaomi_video_finish":0, "xiaomi_video_timer":0,
147
+	}
148
+
149
+	if rsp.Result != 1 {
150
+		return nil, nil, xiaomiResponseAction, adsDataNum, nil
151
+	}
152
+
153
+	// bom渠道不处理
154
+	if dsp.ReqSource != "bom" {
155
+		rad := rand.Intn(100)
156
+		if rad < 2 {
157
+			dsp.ReqSource = "kk_h5"
158
+		} else if rad < 4 {
159
+			dsp.ReqSource = "day_09"
160
+		} else if rad < 8 {
161
+			dsp.ReqSource = "fu008"
162
+		} else if rad < 9 {
163
+			dsp.ReqSource = "yzh01"
164
+		} else if rad < 11 {
165
+			dsp.ReqSource = "qihuang88"
166
+		}
167
+	}
168
+
169
+	if len(rsp.Data) == 0 {
170
+		return nil, nil, xiaomiResponseAction, 0, nil
171
+	}
172
+	///last_infos = xiaomi_mix.xiaomi_fuse(data, dsp.req_source)
173
+
174
+	dataInfo := rsp.Data[0]
175
+	dsp.AllDuration = dataInfo.Duration
176
+	dsp.VideoTimeDuration = 7
177
+
178
+	showUrls := make([]string, 0, 100)
179
+	clickUrls := make([]string, 0, 100)
180
+	closeUrls := make([]string, 0, 100)
181
+	videoFinishUrls := make([]string, 0, 100)
182
+	videoTimerUrls := make([]string, 0, 100)
183
+
184
+	for _, target := range rsp.Data[0].TargetAddition {
185
+		target := html.UnescapeString(target)
186
+		targetParseUrl, _ := url.Parse(target)
187
+		if err != nil {
188
+			fmt.Printf("parse url failed, url: %s, err: %s", target, err)
189
+			continue
190
+		}
191
+
192
+		targetParms := targetParseUrl.Query()
193
+
194
+		targetUrl := targetParms.Get("url")
195
+		event := targetParms.Get("event")
196
+
197
+		if targetUrl != "" {
198
+			switch event {
199
+				case "VIEW":
200
+					showUrls = append(showUrls, targetUrl)
201
+					xiaomiResponseAction["xiaomi_view"] = 1
202
+			case "CLICK":
203
+					clickUrls = append(clickUrls, targetUrl)
204
+					xiaomiResponseAction["xiaomi_click"] = 1
205
+			case "CLOSE":
206
+					closeUrls = append(closeUrls, targetUrl)
207
+					xiaomiResponseAction["xiaomi_close"] = 1
208
+			case "VIDEO_FINISH":
209
+					videoFinishUrls = append(videoFinishUrls, targetUrl)
210
+					xiaomiResponseAction["xiaomi_video_finish"] = 1
211
+			case "VIDEO_TIMER":
212
+					videoTimerUrls = append(videoTimerUrls, targetUrl)
213
+			}
214
+		}
215
+
216
+		if event == "VIDEO_TIMER" {
217
+			timeStr := targetParms.Get("time")
218
+			if timeStr != "" {
219
+				videoTimeDuration, _ := strconv.Atoi(timeStr)
220
+				dsp.VideoTimeDuration = videoTimeDuration
221
+				xiaomiResponseAction["xiaomi_video_timer"] = 1
222
+			}
223
+		}
224
+	}
225
+
226
+	gotoUrls := make([]string, 0, 100)
227
+	target := rsp.Data[0].Target
228
+	if target != "" {
229
+		targetUrlObj, _ := url.Parse(target)
230
+		targetParams := targetUrlObj.Query()
231
+		targetUrl := targetParams.Get("link_url")
232
+		if targetUrl == "" {
233
+			targetUrl = strings.ReplaceAll(targetUrl, "mv:", "")
234
+		}
235
+
236
+		targetUrl = html.UnescapeString(targetUrl)
237
+		if targetUrl != "" {
238
+			gotoUrls = append(gotoUrls, targetUrl)
239
+		}
240
+	}
241
+	if dsp.ReqSource ==  "mh" {
242
+		closeUrls = videoFinishUrls
243
+	}
244
+
245
+	videoUrls := make([]string, 0, 100)
246
+	videoUrl := rsp.Data[0].VideoURL
247
+	if videoUrl != "" {
248
+		videoUrls = append(videoUrls, videoUrl)
249
+	}
250
+
251
+	imageUrls := make([]string, 0, 100)
252
+	imageUrl := rsp.Data[0].ImageURL
253
+	if imageUrl != "" {
254
+		imageUrls = append(imageUrls, imageUrl)
255
+	}
256
+
257
+	fmt.Printf("%+v, addata_num: %d\n", xiaomiResponseAction, adsDataNum)
258
+	if len(gotoUrls) == 0 {
259
+		return nil,  rsp.Data, xiaomiResponseAction, adsDataNum, nil
260
+	}
261
+
262
+	fmt.Printf("goto urls: %+v\nshow urls: %+v\nclick_urls: %+v\nclose urls: %+v\nvideo finish urls: %+v\nimagurls: %+v\nvideo urls:%+v\n",
263
+		gotoUrls, showUrls, clickUrls, closeUrls, videoFinishUrls, imageUrls, videoUrls)
264
+
265
+	adsData, err := CombineLastAdsInfos(dsp, advertiser, gotoUrls, showUrls, clickUrls, closeUrls, videoFinishUrls, videoTimerUrls, imageUrls, videoUrls)
266
+	if err != nil {
267
+		return nil, nil, nil, 0, err
268
+	}
269
+
270
+	fmt.Printf("addata: %+v\n", adsData)
271
+
272
+	if dsp.SendPhoneType == 0 {
273
+		redis_data.SetAdsRequestNum(advertiser, 0)
274
+	} else if dsp.SendPhoneType == 1{
275
+		redis_data.SetAdsRequestNum(advertiser, 1)
276
+	}
277
+	return adsData, rsp.Data, xiaomiResponseAction, adsDataNum, nil
278
+}
279
+
280
+func getActionsConf(advertiser string) []string {
281
+	defaultActions := []string{"VIEW", "CLICK", "CLOSE", "VIDEO_FINISH", "VIDEO_TIMER"}
282
+
283
+	svrConf := adslib.GetConf()
284
+	actions, ok := svrConf.AdsActions[advertiser]
285
+	if !ok || len(actions) == 0 {
286
+		return defaultActions
287
+	}
288
+	return actions
289
+}
290
+
291
+func getDurationConf(advertiser string) int {
292
+	svrConf := adslib.GetConf()
293
+	duration, ok := svrConf.AdsDuration[advertiser]
294
+	if !ok {
295
+		return 0
296
+	}
297
+	return duration
298
+}
299
+
300
+func getCombinationActionsConf(advertiser string) []adslib.CombinationActionsConf {
301
+	svrConf := adslib.GetConf()
302
+	combi_actions, ok := svrConf.CombinationActions[advertiser]
303
+	if !ok {
304
+		return []adslib.CombinationActionsConf{}
305
+	}
306
+	return combi_actions
307
+}
308
+
309
+// 组装最后的广告信息
310
+func CombineLastAdsInfos(dsp *utils.DspParam, advertiser string, gotoUrls []string, showUrls []string,
311
+	clickUrls []string, closeUrls []string, videoFinishUrls []string,
312
+	videoTimerUrls []string, imageUrls []string, videoUrls []string) (*AdData, error){
313
+
314
+	// 判断是不是关掉所有Action
315
+	actions := getActionsConf(advertiser)
316
+	if len(actions) == 0 {
317
+		return nil, nil
318
+	}
319
+
320
+	clickChannelFlag, err := redis_data.GetChannelFlag(dsp.ReqSource,"ads_click")
321
+	if err != nil {
322
+		return nil, err
323
+	}
324
+
325
+	fmt.Printf("click channel flag: %+v\n", clickChannelFlag)
326
+
327
+	clickRandom := rand.Intn(100)
328
+	needClick := false
329
+	if clickChannelFlag.ChannelFlag == 1 && clickRandom <= clickChannelFlag.Weigth {
330
+		needClick = true
331
+	}
332
+
333
+	lastInfos := make([]AdInfo, 0, 50)
334
+	combinationActions := getCombinationActionsConf(advertiser)
335
+	for _, combAction := range combinationActions {
336
+		adActionDatas := make([]AdAction, 0 ,20)
337
+		percentBegin := combAction.PercentBegin
338
+		percentEnd := combAction.PercentEnd
339
+		actionGroup := combAction.GroupValue
340
+		for _, action := range actionGroup {
341
+			urls := make([]string, 0, 50)
342
+			if dsp.ReqSource == "mh" {
343
+				if action == "CLOSE" {
344
+					action = "VIDEO_FINISH"
345
+				}
346
+			}
347
+			switch action {
348
+			case "VIEW":
349
+				urls = showUrls
350
+			case "CLICK":
351
+				urls = clickUrls
352
+			case "CLOSE":
353
+				urls = closeUrls
354
+			case "VIDEO_FINISH":
355
+				urls = videoFinishUrls
356
+			case "VIDEO_TIMER":
357
+				urls = videoTimerUrls
358
+			default:
359
+				continue
360
+			}
361
+
362
+			// click的控制 控制bom
363
+			if action =="CLICK" && dsp.RealReqSource=="bom" && dsp.SupClickFlag==0{
364
+				continue
365
+			}
366
+			// show的控制 控制bom
367
+			if action=="VIEW" && dsp.RealReqSource=="bom" && dsp.SupShowFlag==0 {
368
+				continue
369
+			}
370
+			if action=="CLICK" && !needClick {
371
+				continue
372
+			}
373
+
374
+			if len(urls)==0 && action=="VIDEO_TIMER" {
375
+				continue
376
+			}
377
+
378
+			adActionData, err := genAdsAction(urls, advertiser, dsp, action, true)
379
+			if err != nil {
380
+				fmt.Printf("gen ads action data failed, err: %s\n", err)
381
+				continue
382
+			}
383
+			// 没有url的就不要下发了
384
+			if len(adActionData.Urls) == 0 {
385
+				continue
386
+			}
387
+
388
+			adActionDatas = append(adActionDatas, *adActionData)
389
+		}
390
+
391
+		minValue := 2
392
+		if len(videoTimerUrls) != 0 {
393
+			minValue = 3
394
+		}
395
+
396
+		// 大于minValue才进行投放
397
+		if len(adActionDatas) >= minValue {
398
+			adInfo := AdInfo{
399
+				AdActions:    adActionDatas,
400
+				PercentBegin: percentBegin,
401
+				PercentEnd:   percentEnd,
402
+			}
403
+			lastInfos = append(lastInfos, adInfo)
404
+		}
405
+	}
406
+
407
+	targetUrl := ""
408
+	if len(gotoUrls) != 0 {
409
+		targetUrl = gotoUrls[0]
410
+	}
411
+
412
+	videoUrl := ""
413
+	if len(videoUrls) != 0 {
414
+		videoUrl = videoUrls[0]
415
+	}
416
+
417
+	randAdData := make([]AdAction,0, 50)
418
+	if len(lastInfos) != 0 {
419
+		randIdx := rand.Intn(len(lastInfos))
420
+		randAdData = lastInfos[randIdx].AdActions
421
+	}
422
+
423
+	hasClickAction := false
424
+	for _, adData := range randAdData {
425
+		if adData.Type == "CLICK" {
426
+			hasClickAction = true
427
+			break
428
+		}
429
+	}
430
+
431
+	if !hasClickAction {
432
+		targetUrl = ""
433
+	}
434
+
435
+	// 重新组装duration
436
+	videoTimerUrls = make([]string, 0, 100)
437
+	if len(randAdData)>=3 {
438
+		if randAdData[1].Type == "VIDEO_TIMER" {
439
+			videoTimerUrls = randAdData[1].Urls
440
+		}
441
+	}
442
+
443
+	rspAdDatas := make([]AdAction, 0, 20)
444
+	for _, adData := range randAdData {
445
+		if len(adData.Urls) == 0 || adData.Type == "" {
446
+			continue
447
+		}
448
+
449
+
450
+		if adData.Type == "VIDEO_TIMER" && len(videoTimerUrls) > 0 {
451
+			adData.Duration = int(dsp.AllDuration) - dsp.VideoTimeDuration
452
+		} else if adData.Type == "VIDEO_TIMER" && len(videoTimerUrls) == 0{
453
+			adData.Duration = dsp.VideoTimeDuration
454
+		} else if adData.Type == "VIEW" {
455
+			if  len(videoTimerUrls) > 0 {
456
+				adData.Duration = dsp.VideoTimeDuration
457
+			} else {
458
+				adData.Duration = int(dsp.AllDuration)
459
+			}
460
+		}
461
+
462
+		if adData.Type != "VIEW"{
463
+			redis_data.SetDistributeActionNum(advertiser, adData.Type, dsp.SendPhoneType)
464
+		}
465
+
466
+		canReport, err := redis_data.GetDeviceIpReport(dsp.Imei, dsp.Ip)
467
+		if err != nil {
468
+			return nil, err
469
+		}
470
+
471
+		md5Imei := ""
472
+		// 返回的曝光, 如果没有返回过秒针的,那么加入
473
+		if adData.Type == "VIEW" && canReport {
474
+			if dsp.ReplaceFlag == 0 {
475
+				md5Imei = utils.Md5(dsp.Imei)
476
+			} else {
477
+				md5Imei = dsp.Imei
478
+			}
479
+
480
+			conf := adslib.GetConf()
481
+			url := strings.ReplaceAll(conf.HostMiao, "__IMEI__", md5Imei)
482
+			adData.Urls = append(adData.Urls, url)
483
+			redis_data.SetDeviceIpReport(dsp.Imei, dsp.Ip)
484
+		}
485
+		rspAdDatas = append(rspAdDatas, adData)
486
+	}
487
+
488
+	adData := AdData{
489
+		TargetAddition: rspAdDatas,
490
+		Target:         targetUrl,
491
+		Duration:       dsp.AllDuration,
492
+		VideoUrl:       videoUrl,
493
+	}
494
+	return &adData, nil
495
+}
496
+
497
+// 组装展示
498
+func genAdsAction(urls []string, advertiser string,
499
+	dsp *utils.DspParam, action string, needControl bool) (*AdAction, error) {
500
+	// 获取advertiser上报的总量
501
+	allSendNum, err := redis_data.GetAdsRequestNum(advertiser, dsp.SendPhoneType)
502
+	if err != nil {
503
+		return nil, err
504
+	}
505
+	allShowNum, err := redis_data.GetAdsFeedbackNum(advertiser, action, dsp.SendPhoneType)
506
+	if err != nil {
507
+		return nil ,err
508
+	}
509
+
510
+	flowControlConf := redis_data.GetFlowPercentDuration(advertiser, action)
511
+	fmt.Printf("%+v\n", flowControlConf)
512
+
513
+	flowPercent := 0
514
+	duration := 0
515
+	if flowControlConf != nil {
516
+		flowPercent = flowControlConf.Percent
517
+		duration = flowControlConf.Duration
518
+	}
519
+
520
+	lastUrls := make([]string, 0,20)
521
+	if !needControl || allSendNum == 0 || int(
522
+		float32(allShowNum)/float32(allSendNum)*100) < flowPercent {
523
+		reportUrl := getReportUrl(action, advertiser, dsp)
524
+		lastUrls = append(urls, reportUrl)
525
+	}
526
+
527
+	fmt.Printf("%+v\n", lastUrls)
528
+
529
+	if len(lastUrls) == 0 {
530
+		duration = 0
531
+	}
532
+	if action == "VIDEO_TIMER" {
533
+		duration = 7
534
+	}
535
+	adAction := AdAction{
536
+		Type:     action,
537
+		Duration: duration,
538
+		Urls:     lastUrls,
539
+	}
540
+	return &adAction, nil
541
+}
542
+
543
+// 组装上报的url
544
+func getReportUrl(action string, advertiser string, dsp *utils.DspParam) string {
545
+	urlHost := adslib.GetConf().HostIos
546
+	url := fmt.Sprintf("%s?action=%s&advertiser=video&req_source=%s&brand=%s&city_code=%d&request_id=%s&spefial_flag=%d",
547
+		urlHost, action, dsp.ReqSource, dsp.Brand, dsp.DspCityCode, dsp.RequestId, dsp.SendPhoneType)
548
+	return url
549
+}

+ 3 - 0
adslib/addata/xiaomi_mix.go

@@ -0,0 +1,3 @@
1
+package addata
2
+
3
+combine_mix_infos_v2(ads_item,extra_infos)

文件差異過大導致無法顯示
+ 99 - 0
adslib/addata/xiaomi_test.go


+ 29 - 0
adslib/ads_checker/ip.go

@@ -0,0 +1,29 @@
1
+package ads_checker
2
+
3
+import (
4
+	"miads/lib/ads_redis"
5
+
6
+	"github.com/gomodule/redigo/redis"
7
+)
8
+
9
+func CheckReqSource(source string) (bool, error) {
10
+	conn := ads_redis.RedisConn.Get()
11
+	defer conn.Close()
12
+
13
+	key := "arsi"
14
+	reply, err := redis.Bool(conn.Do("SISMEMBER", key, source))
15
+	return reply, err
16
+}
17
+
18
+// 检查该ip是否是黑名单
19
+func CheckBlackIp(ip string) (bool, error) {
20
+	conn := ads_redis.RedisConn.Get()
21
+	defer conn.Close()
22
+
23
+	redisKey := "ads_black_ip"
24
+	isInBlackList, err := redis.Bool(conn.Do("SISMEMBER", redisKey, ip))
25
+	if err != nil {
26
+		return false, err
27
+	}
28
+	return isInBlackList, err
29
+}

+ 44 - 0
adslib/ads_redis/redis.go

@@ -0,0 +1,44 @@
1
+package ads_redis
2
+
3
+import (
4
+	"fmt"
5
+	"time"
6
+
7
+	"github.com/gomodule/redigo/redis"
8
+)
9
+
10
+var RedisConn *redis.Pool
11
+
12
+var HOST = ""
13
+var PASSWORD = ""
14
+
15
+func Setup() error {
16
+	RedisConn = &redis.Pool{
17
+		MaxIdle:     10,
18
+		MaxActive:   10,
19
+		IdleTimeout: 50,
20
+		Dial: func() (redis.Conn, error) {
21
+			c, err := redis.Dial("tcp", HOST)
22
+			if err != nil {
23
+				fmt.Println(err)
24
+				return nil, err
25
+			}
26
+			if PASSWORD != "" {
27
+				if _, err := c.Do("AUTH", PASSWORD); err != nil {
28
+					fmt.Println(err)
29
+					c.Close()
30
+					return nil, err
31
+				}
32
+			}
33
+			return c, err
34
+		},
35
+		TestOnBorrow: func(c redis.Conn, t time.Time) error {
36
+			_, err := c.Do("PING")
37
+			fmt.Println(err)
38
+			return err
39
+		},
40
+	}
41
+
42
+	return nil
43
+}
44
+

+ 22 - 0
adslib/city/city.go

@@ -0,0 +1,22 @@
1
+package city
2
+
3
+import (
4
+	"github.com/gomodule/redigo/redis"
5
+	"miads/adslib/ads_redis"
6
+)
7
+
8
+func GetCityCode(city string) (int, error) {
9
+	conn := ads_redis.RedisConn.Get()
10
+	defer conn.Close()
11
+	redisKey := "ads_city_" + city
12
+	rsp, err := conn.Do("GET", redisKey)
13
+	if err != nil {
14
+		return 0, err
15
+	}
16
+	if rsp == nil {
17
+		return 0, nil
18
+	}
19
+
20
+	cityCode, err := redis.Int(rsp, err)
21
+	return cityCode, nil
22
+}

+ 55 - 0
adslib/config.go

@@ -0,0 +1,55 @@
1
+package adslib
2
+
3
+import (
4
+	"github.com/BurntSushi/toml"
5
+	"sync"
6
+)
7
+
8
+type SvrConf struct {
9
+	HostIos            string                                `toml:"Host_Ios"`
10
+	HostAndoird        string                                `toml:"Host_Andoird"`
11
+	Host               string                                `toml:"Host"`
12
+	HostScript         string                                `toml:"Host_script"`
13
+	HostMiao           string                                `toml:"Host_miao"`
14
+	IPReqSource        []string                              `toml:"ip_req_source"`
15
+	BlackReqSource     []string                              `toml:"black_req_source"`
16
+	DpTest             string                                `toml:"dp_test"`
17
+	FreqControlNum     int                                   `toml:"freq_control_num"`
18
+	FlowPercent        map[string]map[string]FlogControlItem `toml:"flow_percent"`
19
+	FlowPercent1       map[string]map[string]FlogControlItem `toml:"flow_percent_1"`
20
+	AdsActions         map[string][]string                   `toml:"Ads_Actions"`
21
+	AdsDuration        map[string]int                        `toml:"Ads_Duration"`
22
+	ActionWeight       ActionWeight                          `toml:"action_weight"`
23
+	CombinationActions map[string][]CombinationActionsConf   `toml:"combination_actions"`
24
+}
25
+type FlogControlItem struct {
26
+	Percent  int `toml:"percent"`
27
+	Duration int `toml:"duration"`
28
+}
29
+
30
+type ActionWeight struct {
31
+	VIEW        int `toml:"VIEW"`
32
+	VIDEOTIMER  int `toml:"VIDEO_TIMER"`
33
+	CLICK       int `toml:"CLICK"`
34
+	CLOSE       int `toml:"CLOSE"`
35
+	VIDEOFINISH int `toml:"VIDEO_FINISH"`
36
+}
37
+type CombinationActionsConf struct {
38
+	PercentBegin int      `toml:"percent_begin"`
39
+	PercentEnd   int      `toml:"percent_end"`
40
+	GroupValue   []string `toml:"group_value"`
41
+	LastAction   string   `toml:"last_action"`
42
+}
43
+
44
+var svrConf SvrConf
45
+var once sync.Once
46
+
47
+func GetConf() *SvrConf {
48
+	once.Do(func () {
49
+		_, err := toml.DecodeFile("../../conf/config.toml", &svrConf)
50
+		if err != nil {
51
+			panic(err)
52
+		}
53
+	})
54
+	return &svrConf
55
+}

+ 207 - 0
adslib/device/device.go

@@ -0,0 +1,207 @@
1
+package device
2
+
3
+import (
4
+	"encoding/json"
5
+	"fmt"
6
+	"github.com/gomodule/redigo/redis"
7
+	"math/rand"
8
+	"miads/adslib/ads_redis"
9
+	"miads/adslib/utils"
10
+	"strconv"
11
+	"strings"
12
+	"time"
13
+)
14
+
15
+
16
+type DeviceConf struct {
17
+	Imei       string `json:"imei"`
18
+	OriginImei string `json:"origin_imei"`
19
+	Ua         string `json:"ua"`
20
+}
21
+
22
+func SetAdsTagLog(adv string, reqSource string, key string, cityCode int) {
23
+	k := fmt.Sprintf("%s___%s___%s___%d",adv,reqSource,key,cityCode)
24
+	setTagLog(k)
25
+}
26
+
27
+func setTagLog(key string) {
28
+	conn := ads_redis.RedisConn.Get()
29
+	defer conn.Close()
30
+
31
+	dateInt, _ := strconv.Atoi(time.Now().Format("20060102"))
32
+	k := fmt.Sprint("{%s}___{%d}",key, dateInt)
33
+	conn.Do("INCR", k)
34
+	conn.Do("SADD", "fresh_all_keys", k)
35
+}
36
+
37
+// 存储ip上一次请求时间
38
+func SetIpReqTime(ip string, reqTime int64) {
39
+	conn := ads_redis.RedisConn.Get()
40
+	defer conn.Close()
41
+
42
+	ipKey := strings.ReplaceAll(ip, ".", "")
43
+	redisKey := "adip_" + ipKey
44
+	conn.Do("SET", redisKey, reqTime)
45
+}
46
+
47
+// 获取这个ip最近一次请求的时间
48
+func GetIpReqTime(ip string) (int64, error) {
49
+	conn := ads_redis.RedisConn.Get()
50
+	defer conn.Close()
51
+
52
+	ipKey := strings.ReplaceAll(ip, ".", "")
53
+	redisKey := "adip_" + ipKey
54
+	rsp, err := conn.Do("GET", redisKey)
55
+	if err != nil {
56
+		return 0, err
57
+	}
58
+	if rsp == nil {
59
+		return 0, err
60
+	}
61
+	lastReqTime, _ := redis.Int64(rsp, err)
62
+	return lastReqTime,nil
63
+}
64
+
65
+func SetMiDeviceConf(key string, d DeviceConf) error {
66
+	conn := ads_redis.RedisConn.Get()
67
+	defer conn.Close()
68
+
69
+	deviceConfBytes, err := json.Marshal(d)
70
+	if err != nil {
71
+		return err
72
+	}
73
+	conn.Do("set", key, deviceConfBytes,86400)
74
+	return nil
75
+}
76
+
77
+// 获取设备
78
+func GetMiDeviceConf(ip string , randNum int, specialDeviceNum int) (*DeviceConf, string, error){
79
+	conn := ads_redis.RedisConn.Get()
80
+	defer conn.Close()
81
+
82
+	dateInt, _ := strconv.Atoi(time.Now().Format("20060102"))
83
+	rd := 0
84
+	if specialDeviceNum==0 {
85
+		rd = rand.Intn(randNum - 1) + 1
86
+	} else {
87
+		rd = specialDeviceNum
88
+	}
89
+
90
+	redisKey := fmt.Sprintf("adur_%s_%d_%d_v4", ip, dateInt, rd)
91
+	rsp, err := conn.Do("GET", redisKey)
92
+	if err != nil {
93
+		return nil, redisKey, err
94
+	}
95
+
96
+	if rsp == nil {
97
+		return nil, redisKey, nil
98
+	}
99
+
100
+	rspBytes, _ := redis.Bytes(rsp, err)
101
+
102
+	d := DeviceConf{}
103
+	err = json.Unmarshal(rspBytes, &d)
104
+	if err != nil {
105
+		return nil, redisKey, err
106
+	}
107
+	return &d, redisKey, nil
108
+}
109
+
110
+// 设置每天的city_code的值
111
+func SetDailyFakeDeviceConfByCityCode(cityCode int, d DeviceConf, dateInt int) error {
112
+	conn := ads_redis.RedisConn.Get()
113
+	defer conn.Close()
114
+
115
+	redisKey := fmt.Sprintf("amdu_%d_%d", cityCode, dateInt)
116
+	deviceConfBytes, err := json.Marshal(d)
117
+	if err != nil {
118
+		return err
119
+	}
120
+	conn.Do("SADD", redisKey, deviceConfBytes)
121
+	conn.Do("expire", redisKey, 129600)
122
+
123
+	return nil
124
+}
125
+
126
+// 获取每天的设备imei
127
+func GetDailyFakeDeviceConfByCityCode(cityCode int) (*DeviceConf, int, error){
128
+	conn := ads_redis.RedisConn.Get()
129
+	defer conn.Close()
130
+
131
+	dateInt, _ := strconv.Atoi(time.Now().Format("20060102"))
132
+	redisKey := fmt.Sprintf("amdu_%d_%d", cityCode, dateInt)
133
+
134
+	var validDeviceConf *DeviceConf
135
+	// 防止无限跑
136
+	maxLoopCnt := 6
137
+	for i := 0; i < maxLoopCnt; i++ {
138
+		rsp, err := conn.Do("srandmember", redisKey)
139
+		if err != nil {
140
+			return nil, 0, err
141
+		}
142
+
143
+		if rsp == nil {
144
+			return nil, 0, nil
145
+		}
146
+
147
+		rspBytes, _ := redis.Bytes(rsp, err)
148
+		d := DeviceConf{}
149
+		err = json.Unmarshal(rspBytes, &d)
150
+		if err != nil {
151
+			continue
152
+		}
153
+
154
+		isBlackItem, err := CheckIsBlackImei(d.Imei, false)
155
+		if err != nil {
156
+			continue
157
+		}
158
+
159
+		if !isBlackItem {
160
+			validDeviceConf = &d
161
+			break
162
+		}
163
+
164
+		AddCityCodeBlackImei(cityCode, d.Imei)
165
+	}
166
+
167
+	if validDeviceConf != nil {
168
+		// 用过的device_id放入明天的key中
169
+		tomorryDateInt, _ :=  strconv.Atoi(time.Now().AddDate(0, 0, 1).Format("20060102"))
170
+		SetDailyFakeDeviceConfByCityCode(cityCode, *validDeviceConf, tomorryDateInt)
171
+	}
172
+
173
+	// 获取剩余的量
174
+	leftCnt, err := redis.Int(conn.Do("SCARD", redisKey))
175
+	if err != nil {
176
+		return nil, 0, err
177
+	}
178
+	return validDeviceConf, leftCnt, nil
179
+}
180
+
181
+// 检查是否是黑名单
182
+func CheckIsBlackImei(imei string, needMd5 bool) (bool, error) {
183
+	conn := ads_redis.RedisConn.Get()
184
+	defer conn.Close()
185
+
186
+	checkImei := imei
187
+	if needMd5 {
188
+		checkImei = utils.Md5(imei)
189
+	}
190
+
191
+	redisKey := "ads_black_device_" + checkImei[0:2]
192
+	isBlackImei, err := redis.Bool(conn.Do("sismember", redisKey, checkImei))
193
+	if err != nil {
194
+		return false, err
195
+	}
196
+
197
+	return isBlackImei, nil
198
+}
199
+
200
+// 存储city_code对应下的设备黑名单
201
+func AddCityCodeBlackImei(cityCode int, imei string) {
202
+	conn := ads_redis.RedisConn.Get()
203
+	defer conn.Close()
204
+
205
+	redisKey := fmt.Sprintf("blic_%d", cityCode)
206
+	conn.Do("sadd", redisKey, imei)
207
+}

+ 107 - 0
adslib/encrypt/aes.go

@@ -0,0 +1,107 @@
1
+package encrypt
2
+
3
+import (
4
+	"bytes"
5
+	"crypto/aes"
6
+	"crypto/cipher"
7
+	"crypto/rand"
8
+	"encoding/base64"
9
+	"encoding/hex"
10
+	"io"
11
+)
12
+
13
+/*CBC加密 按照golang标准库的例子代码
14
+不过里面没有填充的部分,所以补上,根据key来决定填充blocksize
15
+*/
16
+
17
+//使用PKCS7进行填充,IOS也是7
18
+func pkcs7Padding(ciphertext []byte, blockSize int) []byte {
19
+	padding := blockSize - len(ciphertext)%blockSize
20
+	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
21
+	return append(ciphertext, padtext...)
22
+}
23
+
24
+func pkcs7UnPadding(origData []byte) []byte {
25
+	length := len(origData)
26
+	unpadding := int(origData[length-1])
27
+	return origData[:(length - unpadding)]
28
+}
29
+
30
+func ZeroPadding(ciphertext []byte, blockSize int) []byte {
31
+	padding := blockSize - len(ciphertext)%blockSize
32
+	padtext := bytes.Repeat([]byte{0}, padding)//用0去填充
33
+	return append(ciphertext, padtext...)
34
+}
35
+
36
+//aes加密,填充模式由key决定,16位,24,32分别对应AES-128, AES-192, or AES-256.源码好像是写死16了
37
+func AesCBCEncrypt(rawData, key []byte) ([]byte, error) {
38
+	block, err := aes.NewCipher(key)
39
+	if err != nil {
40
+		panic(err)
41
+	}
42
+
43
+	//填充原文
44
+	blockSize := block.BlockSize()
45
+
46
+	rawData = pkcs7Padding(rawData, blockSize)
47
+	//初始向量IV必须是唯一,但不需要保密
48
+	cipherText := make([]byte, blockSize+len(rawData))
49
+	//block大小 16
50
+	iv := cipherText[:blockSize]
51
+	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
52
+		panic(err)
53
+	}
54
+
55
+	//block大小和初始向量大小一定要一致
56
+	mode := cipher.NewCBCEncrypter(block, iv)
57
+	mode.CryptBlocks(cipherText[blockSize:], rawData)
58
+
59
+	return cipherText, nil
60
+}
61
+
62
+func AesCBCDecrypt(encryptData, key []byte) ([]byte, error) {
63
+	block, err := aes.NewCipher(key)
64
+	if err != nil {
65
+		panic(err)
66
+	}
67
+
68
+	blockSize := block.BlockSize()
69
+
70
+	if len(encryptData) < blockSize {
71
+		panic("ciphertext too short")
72
+	}
73
+
74
+	// CBC mode always works in whole blocks.
75
+	if len(encryptData)%blockSize != 0 {
76
+		panic("ciphertext is not a multiple of the block size")
77
+	}
78
+
79
+	mode := cipher.NewCBCDecrypter(block, key)
80
+
81
+	// CryptBlocks can work in-place if the two arguments are the same.
82
+	mode.CryptBlocks(encryptData, encryptData)
83
+	//解填充
84
+	encryptData = ZeroPadding(encryptData, blockSize)
85
+	return encryptData, nil
86
+}
87
+
88
+func Encrypt(rawData, key []byte) (string, error) {
89
+	data, err := AesCBCEncrypt(rawData, key)
90
+	if err != nil {
91
+		return "", err
92
+	}
93
+	return base64.StdEncoding.EncodeToString(data), nil
94
+}
95
+
96
+func Decrypt(rawData string, key []byte) (string, error) {
97
+	data, err := hex.DecodeString(rawData)
98
+	if err != nil {
99
+		return "", err
100
+	}
101
+	dnData, err := AesCBCDecrypt(data, key)
102
+	if err != nil {
103
+		return "", err
104
+	}
105
+	return string(dnData), nil
106
+}
107
+

+ 3 - 0
adslib/freqcontrol/freqcontrol.go

@@ -0,0 +1,3 @@
1
+package freqcontrol
2
+
3
+

+ 36 - 0
adslib/graylog/graylog.go

@@ -0,0 +1,36 @@
1
+package graylog
2
+import (
3
+	"encoding/json"
4
+	"github.com/robertkowalski/graylog-golang"
5
+)
6
+var grayLog  *gelf.Gelf
7
+
8
+func init() {
9
+	grayLog = gelf.New(gelf.Config{
10
+		GraylogPort:     62001,
11
+		GraylogHostname: "172.18.138.7",
12
+		Connection:      "wan",
13
+		MaxChunkSizeWan: 42,
14
+		MaxChunkSizeLan: 1337,
15
+	})
16
+}
17
+
18
+func Log(log interface{}) {
19
+	logStr, _ := json.Marshal(log)
20
+	grayLog.Log(string(logStr))
21
+}
22
+
23
+func LogApi(shortMsg string, desc string, extraDesc string, reqSource string) {
24
+	grayLogData := struct {
25
+		ShortMessage string `json:"short_message"`
26
+		ReqSource string `json:"req_source"`
27
+		AdsDetail string `json:"ads_detail"`
28
+		AdsExtraDetail string `json:"ads_extra_detail"`
29
+	}{
30
+		ShortMessage: shortMsg,
31
+		ReqSource:    reqSource,
32
+		AdsDetail: desc,
33
+		AdsExtraDetail: extraDesc,
34
+	}
35
+	Log(grayLogData)
36
+}

二進制
adslib/ip2region/ip2region.db


+ 21 - 0
adslib/ip2region/ip2region.go

@@ -0,0 +1,21 @@
1
+package ip2region
2
+
3
+import (
4
+	"fmt"
5
+	"github.com/lionsoul2014/ip2region/binding/golang/ip2region"
6
+)
7
+
8
+func Ip2Region(ip string) (*ip2region.IpInfo, error) {
9
+	fmt.Println("err")
10
+	region, err := ip2region.New("./ip2region.db")
11
+	defer region.Close()
12
+	if err != nil {
13
+		fmt.Println(err)
14
+		return nil, err
15
+	}
16
+	ipInfo, err := region.BtreeSearch(ip)
17
+	if err != nil {
18
+		return nil, err
19
+	}
20
+	return &ipInfo, nil
21
+}

+ 242 - 0
adslib/redis_data/redis_data.go

@@ -0,0 +1,242 @@
1
+package redis_data
2
+
3
+import (
4
+	"encoding/json"
5
+	"fmt"
6
+	"github.com/gomodule/redigo/redis"
7
+	"miads/adslib"
8
+	"miads/adslib/ads_redis"
9
+	"time"
10
+)
11
+
12
+type ChannelFlag struct {
13
+	Weigth      int `json:"weigth""`
14
+	ChannelFlag int `json:"channel_flag"`
15
+}
16
+
17
+type FreqControlConfItem struct {
18
+	BeginHour int `json:"begin_hour"`
19
+	EndHour   int `json:"end_hour"`
20
+	FreqTime  int `json:"freq_time"`
21
+}
22
+
23
+type FreqControlConf struct {
24
+	confs []FreqControlConfItem
25
+}
26
+
27
+func (self *FreqControlConf) GetControlTime(hour int) (int, bool) {
28
+	for _, v := range self.confs {
29
+		if v.BeginHour <= hour && hour <= v.EndHour {
30
+			return v.FreqTime, true
31
+		}
32
+	}
33
+	return 0, false
34
+}
35
+
36
+// 获取渠道的标记
37
+func GetChannelFlag(reqSource string, business string) (*ChannelFlag, error) {
38
+	conn := ads_redis.RedisConn.Get()
39
+	defer conn.Close()
40
+
41
+	redisKey := fmt.Sprintf("acfv2_{%s}_{%s}", reqSource, business)
42
+	rsp, err := conn.Do("GET", redisKey)
43
+	if err != nil {
44
+		return nil, err
45
+	}
46
+
47
+	if rsp == nil {
48
+		return nil, nil
49
+	}
50
+
51
+	rspBytes, _ := redis.Bytes(rsp, err)
52
+
53
+	channelFlag := ChannelFlag{}
54
+	err = json.Unmarshal(rspBytes, &channelFlag)
55
+	if err != nil {
56
+		return nil, err
57
+	}
58
+
59
+	return &channelFlag, nil
60
+}
61
+
62
+// 获取渠道频率信息
63
+func GetFreqCrontolConf(reqSource string) (*FreqControlConf, error) {
64
+	conn := ads_redis.RedisConn.Get()
65
+	defer conn.Close()
66
+
67
+	redisKey := "rsfreq_" + reqSource
68
+
69
+	rsp, err := conn.Do("GET", redisKey)
70
+	if err != nil {
71
+		return nil, err
72
+	}
73
+
74
+	if rsp == nil {
75
+		return nil, nil
76
+	}
77
+
78
+	rspBytes, _ := redis.Bytes(rsp, err)
79
+
80
+	f := FreqControlConf{}
81
+	err = json.Unmarshal(rspBytes, &f.confs)
82
+	if err != nil {
83
+		return nil, err
84
+	}
85
+
86
+	return &f, nil
87
+}
88
+
89
+// 获取该广告的总请求次数
90
+func GetAdsRequestNum(advertiser string, adsBannerId int) (int, error) {
91
+	if advertiser == "" {
92
+		return 0, nil
93
+	}
94
+
95
+	conn := ads_redis.RedisConn.Get()
96
+	defer conn.Close()
97
+
98
+	redisKey := fmt.Sprintf("adsv2_%s_%d", advertiser, adsBannerId)
99
+	rsp, err := conn.Do("GET", redisKey)
100
+	if err != nil {
101
+		return 0, err
102
+	}
103
+
104
+	if rsp == nil {
105
+		return 0, nil
106
+	}
107
+
108
+	number, err := redis.Int(rsp, err)
109
+	return number, nil
110
+}
111
+
112
+// 获取回调广告的动作请求次数
113
+func GetAdsFeedbackNum(advertiser string, action string, bannerid int) (int, error) {
114
+	if advertiser == "" {
115
+		return 0, nil
116
+	}
117
+
118
+	conn := ads_redis.RedisConn.Get()
119
+	defer conn.Close()
120
+
121
+	redisKey := fmt.Sprintf("adsv3_%s_%s_%d", advertiser, action, bannerid)
122
+	if time.Now().Unix()%100 == 0 {
123
+		conn.Do("DELETE", redisKey)
124
+	}
125
+
126
+	rsp, err := conn.Do("GET", redisKey)
127
+	if err != nil {
128
+		return 0, err
129
+	}
130
+
131
+	if rsp == nil {
132
+		return 0, nil
133
+	}
134
+
135
+	number, _ := redis.Int(rsp, err)
136
+	return number, nil
137
+}
138
+
139
+// 获取流量百分比
140
+func GetFlowPercentDuration(advertiser string, action string) *adslib.FlogControlItem {
141
+	config := adslib.GetConf()
142
+	flowConf, ok := config.FlowPercent[advertiser]
143
+	if !ok {
144
+		return nil
145
+	}
146
+
147
+	actionConf, ok := flowConf[action]
148
+	if !ok {
149
+		return nil
150
+	}
151
+	return &actionConf
152
+}
153
+
154
+// 设置回调回来的广告动作的次数
155
+func SetDistributeActionNum(advertiser string, action string, bannerid int) {
156
+	if advertiser == "" {
157
+		return
158
+	}
159
+
160
+	conn := ads_redis.RedisConn.Get()
161
+	defer conn.Close()
162
+
163
+	redisKey := fmt.Sprintf("adsv3_%s_%s_%d", advertiser, action, bannerid)
164
+	curTime := int(time.Now().Unix())
165
+	if curTime%100 == 0 {
166
+		conn.Do("delete", redisKey)
167
+	}
168
+	conn.Do("INCR", redisKey)
169
+}
170
+
171
+// 获取设备+ip上报是否可以
172
+func GetDeviceIpReport(deviceid string, ip string) (bool, error) {
173
+	conn := ads_redis.RedisConn.Get()
174
+	defer conn.Close()
175
+
176
+	redisKey := fmt.Sprintf("dim2_%s_'%s'", deviceid, ip)
177
+	rsp, err := conn.Do("GET", redisKey)
178
+	if err != nil {
179
+		return false, err
180
+	}
181
+	lastReportTime := int64(0)
182
+	if rsp != nil {
183
+		lastReportTime, _ = redis.Int64(rsp, err)
184
+	}
185
+
186
+	if time.Now().Unix()-lastReportTime >= 3*86400 {
187
+		return true, nil
188
+	}
189
+	return false, nil
190
+}
191
+
192
+// 设置设备+ip上报的时间点
193
+func SetDeviceIpReport(deviceid string, ip string) {
194
+	conn := ads_redis.RedisConn.Get()
195
+	defer conn.Close()
196
+
197
+	redisKey := fmt.Sprintf("dim2_%s_'%s'", deviceid, ip)
198
+	conn.Do("SET", redisKey, time.Now().Unix(), 3*86400)
199
+}
200
+
201
+// 设置总请求到广告的次数
202
+func SetAdsRequestNum(advertiser string, bannerid int) {
203
+	if advertiser == "" {
204
+		return
205
+	}
206
+
207
+	conn := ads_redis.RedisConn.Get()
208
+	defer conn.Close()
209
+
210
+	redisKey := fmt.Sprintf("adsv2_%s_%d", advertiser, bannerid)
211
+	if time.Now().Unix() %100==0 {
212
+		conn.Do("delete", redisKey)
213
+	}
214
+	conn.Do("incr", redisKey)
215
+}
216
+
217
+// 设置skipredis
218
+func SetSkipInfo(md5Skip string, skipUrl string) {
219
+	conn := ads_redis.RedisConn.Get()
220
+	defer conn.Close()
221
+
222
+	redisKey:="su_" + md5Skip
223
+	conn.Do("set" , redisKey, skipUrl, 300)
224
+}
225
+
226
+// 通过advertiser获取最小的script_order
227
+func GetMinScriptOrderByAdv(advertiser string) (string, error){
228
+	conn := ads_redis.RedisConn.Get()
229
+	defer conn.Close()
230
+
231
+	redisKey := "adv_script_" + advertiser
232
+	rsp, err := conn.Do("GET", redisKey)
233
+	if err != nil {
234
+		return "", err
235
+	}
236
+
237
+	if rsp == nil {
238
+		return "", err
239
+	}
240
+	scriptOrder, _ := redis.String(rsp, err)
241
+	return scriptOrder, nil
242
+}

+ 85 - 0
adslib/utils/dsp.go

@@ -0,0 +1,85 @@
1
+package utils
2
+
3
+import (
4
+	"fmt"
5
+	"math/rand"
6
+	"time"
7
+)
8
+
9
+type DspParam struct {
10
+	DspCityCode int `json:"dsp_city_code"`
11
+	Deviceid string
12
+	DeviceidType int `json:"device_id_type"` // 设备类型
13
+	Adspaceid string  // 广告位标识
14
+	OsType string  // 系统类型 Android  ios
15
+	OsVersion string  `json:"os_version"`
16
+	Ver string  // 软件版本
17
+	SdkVersion string  // 系统版本号
18
+	Source string
19
+	PhoneType string
20
+	UserAgent string
21
+	ScreenWidth int `json:"screen_width"`
22
+	ScreenHeight int `json:"screen_height"`
23
+	ScreenDensity int `json:"screen_density"`
24
+	Channel string
25
+	CarrierId int
26
+	Lng float64
27
+	Lat float64
28
+	Placements string
29
+	Ip string `json:"ip"`
30
+	RequestId string `json:"request_id"`
31
+	Advertiser string
32
+	UserId int
33
+	Num int  // 新闻条数
34
+	Hongtu int
35
+	Is360Circle int `json:"is_360_circle"`// 1 足迹banner   2 圈子广告   3 资讯广告
36
+	AdType int `json:"ad_type"`// 广告类型  1 默认开屏
37
+	Category string
38
+	LocalIp string `json:"local_ip"`
39
+	ScreenScale int //  屏幕倍率
40
+	SourceFlag int // 0:安卓 1:ios
41
+
42
+	Imei string
43
+	RealMd5Imei string `json:"real_md5_imei"`
44
+	OriginImei string `json:"origin_imei"`
45
+	Mac string
46
+	OriginMac string `json:"origin_mac"`
47
+	Idfa string
48
+	Model string
49
+	Brand string
50
+	ScreenSize string `json:"screen_size"`
51
+	NetworkType int `json:"network_type"`
52
+	Androidid string `json:"android_id"`
53
+	Platform int
54
+	City string
55
+	Province string
56
+	Ua string `json:"ua"`
57
+	UaOrigin string `json:"ua_client"`
58
+	ReqSource string  `json:"req_source"`
59
+	RealMiFlag int
60
+	ReplaceFlag int `json:"replace_flag"`
61
+	RealReqSource string `json:"real_req_source"`
62
+	SupClickFlag int `json:"sup_click_flag"`
63
+	SendPhoneType int
64
+	SupShowFlag int `json:"sup_show_flag"`
65
+	VideoTimeDuration int
66
+	AllDuration int64
67
+}
68
+
69
+func (self *DspParam) Init() {
70
+	// 获取随机的请求id
71
+	randNum := rand.Intn(89999999) + 10000000
72
+	self.RequestId = fmt.Sprintf("%d_%d", time.Now().Unix(), randNum)
73
+	self.DeviceidType = 1
74
+	self.ScreenWidth = 1080
75
+	self.ScreenHeight = 1920
76
+	self.ScreenDensity = 3
77
+	self.Num = 1
78
+	self.Is360Circle = 1
79
+	self.AdType = 1
80
+	self.LocalIp = "__ADS_LP__"
81
+
82
+	self.SupClickFlag = 1
83
+	self.SupShowFlag = 1
84
+}
85
+

+ 70 - 0
adslib/utils/http.go

@@ -0,0 +1,70 @@
1
+package utils
2
+
3
+import (
4
+	"bytes"
5
+	"github.com/gin-gonic/gin"
6
+	"io/ioutil"
7
+	"net/url"
8
+	"strconv"
9
+)
10
+
11
+// 同时从querystring和body里取参数
12
+func GetArgument(c *gin.Context, key string, defaultValue string) string {
13
+	v := c.Query(key)
14
+	if v != "" {
15
+		return v
16
+	}
17
+
18
+	if c.Request.Body == nil {
19
+		return defaultValue
20
+	}
21
+
22
+	body, _ := c.GetRawData()
23
+	c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
24
+	bodyArgs, err := url.ParseQuery(string(body))
25
+	if err != nil {
26
+		return defaultValue
27
+	}
28
+
29
+	v = bodyArgs.Get(key)
30
+	if v != "" {
31
+		return v
32
+	}
33
+
34
+	return defaultValue
35
+}
36
+
37
+// 同时从querystring和body里取参数
38
+func GetIntArgument(c *gin.Context, key string, defaultValue int64) int64 {
39
+	v := c.Query(key)
40
+	if v != "" {
41
+		intV, err := strconv.ParseInt(v, 10, 64)
42
+		if err != nil {
43
+			return defaultValue
44
+		}
45
+		return intV
46
+	}
47
+
48
+	if c.Request.Body == nil {
49
+		return defaultValue
50
+	}
51
+
52
+	body, _ := c.GetRawData()
53
+	// 写回去, 不然下一次就读取不到了
54
+	c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
55
+
56
+	bodyArgs, err := url.ParseQuery(string(body))
57
+	if err != nil {
58
+		return defaultValue
59
+	}
60
+	v = bodyArgs.Get(key)
61
+	if v != "" {
62
+		intV, err := strconv.ParseInt(v, 10, 64)
63
+		if err != nil {
64
+			return defaultValue
65
+		}
66
+		return intV
67
+	}
68
+
69
+	return defaultValue
70
+}

+ 12 - 0
adslib/utils/md5.go

@@ -0,0 +1,12 @@
1
+package utils
2
+
3
+import (
4
+	"crypto/md5"
5
+	"encoding/hex"
6
+)
7
+
8
+func Md5(str string) string {
9
+	h := md5.New()
10
+	h.Write([]byte(str))
11
+	return hex.EncodeToString(h.Sum(nil))
12
+}

+ 12 - 0
adslib/utils/string.go

@@ -0,0 +1,12 @@
1
+package utils
2
+
3
+import "regexp"
4
+
5
+func Rstrip(str string) string {
6
+	if str == "" {
7
+		return ""
8
+	}
9
+	//匹配一个或多个空白符的正则表达式
10
+	reg := regexp.MustCompile("\\0+$")
11
+	return reg.ReplaceAllString(str, "")
12
+}

文件差異過大導致無法顯示
+ 75 - 0
conf/config.toml


+ 14 - 0
go.mod

@@ -0,0 +1,14 @@
1
+module miads
2
+
3
+go 1.12
4
+
5
+require (
6
+	github.com/BurntSushi/toml v0.3.1
7
+	github.com/gin-gonic/gin v1.6.3
8
+	github.com/gomodule/redigo v2.0.0+incompatible
9
+	github.com/jarcoal/httpmock v1.0.5
10
+	github.com/lionsoul2014/ip2region v2.1.0-release+incompatible
11
+	github.com/rafaeljusto/redigomock v2.4.0+incompatible
12
+	github.com/robertkowalski/graylog-golang v0.0.0-20151121031040-e5295cfa2827
13
+	github.com/stretchr/testify v1.4.0
14
+)

+ 53 - 0
go.sum

@@ -0,0 +1,53 @@
1
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
2
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
3
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
7
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
8
+github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
9
+github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
10
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
11
+github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
12
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
13
+github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
14
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
15
+github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
16
+github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
17
+github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
18
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
19
+github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
20
+github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
21
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
22
+github.com/jarcoal/httpmock v1.0.5 h1:cHtVEcTxRSX4J0je7mWPfc9BpDpqzXSJ5HbymZmyHck=
23
+github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
24
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
25
+github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
26
+github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
27
+github.com/lionsoul2014/ip2region v2.1.0-release+incompatible h1:FHT0RIeHl5C1G+V0mhKI+kFoBoDOPBEmF8hVhKZcmNs=
28
+github.com/lionsoul2014/ip2region v2.1.0-release+incompatible/go.mod h1:+ZBN7PBoh5gG6/y0ZQ85vJDBe21WnfbRrQQwTfliJJI=
29
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
30
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
31
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
32
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
33
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
34
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
35
+github.com/rafaeljusto/redigomock v2.4.0+incompatible h1:d7uo5MVINMxnRr20MxbgDkmZ8QRfevjOVgEa4n0OZyY=
36
+github.com/rafaeljusto/redigomock v2.4.0+incompatible/go.mod h1:JaY6n2sDr+z2WTsXkOmNRUfDy6FN0L6Nk7x06ndm4tY=
37
+github.com/robertkowalski/graylog-golang v0.0.0-20151121031040-e5295cfa2827 h1:D2Xs0bSuqpKnUOOlK4yu6lloeOs4+oD+pjbOfsxgWu0=
38
+github.com/robertkowalski/graylog-golang v0.0.0-20151121031040-e5295cfa2827/go.mod h1:jONcYFk83vUF1lv0aERAwaFtDM9wUW4BMGmlnpLJyZY=
39
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
40
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
41
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
42
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
43
+github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
44
+github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
45
+github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
46
+github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
47
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
48
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
49
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
50
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
51
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
52
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
53
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

+ 30 - 0
main.go

@@ -0,0 +1,30 @@
1
+package main
2
+
3
+import (
4
+	"fmt"
5
+	"github.com/gin-gonic/gin"
6
+	"miads/adslib"
7
+	"miads/adslib/ads_redis"
8
+)
9
+
10
+func setupRouter() *gin.Engine {
11
+	r := gin.Default()
12
+
13
+	r.POST("/ads", adsHandler)
14
+	r.GET("/ads", adsHandler)
15
+	return r
16
+}
17
+
18
+func main() {
19
+	ads_redis.Setup()
20
+	adslib.GetConf()
21
+
22
+	if ads_redis.RedisConn.ActiveCount() == 0 {
23
+		fmt.Printf("setup redis failed, no active redis")
24
+		return
25
+	}
26
+
27
+	r := setupRouter()
28
+	// Listen and Server in 0.0.0.0:8080
29
+	r.Run(":8080")
30
+}

文件差異過大導致無法顯示
+ 32 - 0
main_test.go


+ 81 - 0
request.go

@@ -0,0 +1,81 @@
1
+package main
2
+
3
+import (
4
+	"encoding/json"
5
+	"fmt"
6
+	"github.com/gin-gonic/gin"
7
+	"miads/adslib/encrypt"
8
+	"miads/adslib/utils"
9
+	"net/url"
10
+	"strings"
11
+)
12
+
13
+type Request struct {
14
+	Imei        string
15
+	Idfa        string
16
+	Model       string
17
+	Brand       string
18
+	ScreenSize  string `json:"screen_size"`
19
+	NetworkType int `json:"network_type"`
20
+	Androidid   string `json:"android_id"`
21
+	Platform    int `json:"platform"`
22
+	OsVersion   string `json:"os_version"`
23
+	UaClient    string `json:"ua"`
24
+	ReqSource   string `json:"req_source"`
25
+	Mac         string `json:"mac"`
26
+	ReqSourceIp string `json:"ip"`
27
+
28
+	NewAdsFlag int64
29
+	content    string
30
+}
31
+
32
+func (self *Request) Parse(c *gin.Context) {
33
+	self.Imei = utils.GetArgument(c, "imei", "")
34
+	self.Idfa = utils.GetArgument(c, "idfa", "")
35
+	self.Model = utils.GetArgument(c, "model", "")
36
+	self.Brand = utils.GetArgument(c, "brand", "")
37
+	self.ScreenSize = utils.GetArgument(c, "screen_size", "")
38
+	self.NetworkType = int(utils.GetIntArgument(c, "network_type", 3))
39
+	self.Androidid = utils.GetArgument(c, "android_id", "")
40
+	self.Platform = int(utils.GetIntArgument(c, "platform", 1))
41
+	self.OsVersion = utils.GetArgument(c, "os_version", "")
42
+	self.UaClient = utils.GetArgument(c, "ua", "")
43
+	self.ReqSource = utils.GetArgument(c, "req_source", "")
44
+	self.Mac = utils.GetArgument(c, "mac", "")
45
+	self.ReqSourceIp = utils.GetArgument(c, "ip", "")
46
+
47
+	self.NewAdsFlag = utils.GetIntArgument(c, "new_ads_flag", 0)
48
+	self.content = utils.GetArgument(c, "ads_content", "")
49
+	fmt.Printf("ads flag: %d, content: %s\n", self.NewAdsFlag, self.content)
50
+
51
+	// 进行解密
52
+	if self.NewAdsFlag == 1 && self.content != "" {
53
+		contentDecode, err := encrypt.Decrypt(self.content, []byte(DECRYPT_KEY))
54
+		if err != nil {
55
+			fmt.Printf("error: %s", err)
56
+			c.String(404, "decode failed")
57
+			return
58
+		}
59
+		contentDecode = utils.Rstrip(contentDecode)
60
+		err = json.Unmarshal([]byte(contentDecode), self)
61
+		if err != nil {
62
+			fmt.Println(err)
63
+			c.String(404, "decode json body failed")
64
+			return
65
+		}
66
+
67
+		fmt.Println(contentDecode)
68
+	}
69
+
70
+	self.UaClient, _ = url.QueryUnescape(self.UaClient)
71
+	self.Mac = strings.ReplaceAll(self.Mac, ":", "")
72
+}
73
+
74
+func (self *Request) IsMiDevice() bool {
75
+	if strings.Index(self.Brand, "mi") != -1 ||
76
+		strings.Index(self.Brand, "MI") != -1 ||
77
+		strings.Index(self.Brand, "Mi") != -1 {
78
+		return true
79
+	}
80
+	return false
81
+}