github.com/minio/simdjson-go@v0.4.6-0.20231116094823-04d21cddf993/examples/openrtb/openrtb_request.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "github.com/minio/simdjson-go" 6 "os" 7 "sync" 8 ) 9 10 var tagParamsPool sync.Pool 11 12 // TagParams Extract only basic needed fields from the OpenRTB request 13 type TagParams struct { 14 ReqId string 15 ImpressionId string 16 SiteUrl string 17 PublisherId string 18 Referrer string 19 UserId string 20 AppId string 21 AppName string 22 AppStoreUrl string 23 SiteDomain string 24 SiteId string 25 Height string 26 Width string 27 Ip string 28 DeviceType uint8 29 Carrier string 30 DeviceUa string 31 DeviceMake string 32 DeviceId string 33 OS string 34 Longitude string 35 Latitude string 36 Country string 37 City string 38 State string 39 Metro string 40 Postal string 41 Bcat []string 42 TimeMax int16 43 BidFloor float32 44 ParsedBid *simdjson.ParsedJson 45 } 46 47 func (tp *TagParams) Reset() { 48 parsedBid := tp.ParsedBid 49 // re-init tp. Go compiler optimizes it. Note that it will all inner structs will be cleared too 50 *tp = TagParams{} 51 // The ParsedBid was a pointer but it was set to nil after the reset, so we must restore it 52 tp.ParsedBid = parsedBid 53 } 54 55 func populateTagParams(bidReqBody []byte) (*TagParams, error) { 56 tagParams := AcquireTagParams() 57 // Reuse previously used ParsedBid and don't copy field 58 bidReq, err := simdjson.Parse(bidReqBody, tagParams.ParsedBid, simdjson.WithCopyStrings(false)) 59 if err != nil { 60 ReleaseTagParams(tagParams) 61 return nil, err 62 } 63 // store the ParsedJson for reuse next time 64 tagParams.ParsedBid = bidReq 65 66 bidReqId := "" 67 tmax := int64(0) 68 bcat := []string(nil) 69 userId := "" 70 siteId := "" 71 siteDomain := "" 72 sitePage := "" 73 siteReferrer := "" 74 publisherId := "" 75 appBundle := "" 76 appId := "" 77 appName := "" 78 appStoreUrl := "" 79 ipV4 := "" 80 ipV6 := "" 81 deviceType := int64(0) 82 deviceOs := "" 83 deviceMake := "" 84 deviceIfa := "" 85 deviceCarrier := "" 86 deviceUa := "" 87 country := "" 88 longitude := "" 89 latitude := "" 90 city := "" 91 state := "" 92 metro := "" 93 postal := "" 94 impId := "" 95 bidFloor := float64(0) 96 width := "" 97 height := "" 98 99 bidReqIter := bidReq.Iter() 100 typ := bidReqIter.Advance() 101 if typ != simdjson.TypeRoot { 102 return nil, err 103 } 104 rootIter := &simdjson.Iter{} 105 typ, _, err = bidReqIter.Root(rootIter) 106 if err != nil || typ != simdjson.TypeObject { 107 return nil, err 108 } 109 rootObj := &simdjson.Object{} 110 _, err = rootIter.Object(rootObj) 111 if err != nil { 112 return nil, err 113 } 114 l1PropsIter := &simdjson.Iter{} 115 for { 116 l1PropName, l1PropType, l1PropErr := rootObj.NextElementBytes(l1PropsIter) 117 if l1PropType == simdjson.TypeNone || l1PropErr != nil { 118 break 119 } 120 switch string(l1PropName) { 121 case "id": 122 bidReqId, _ = l1PropsIter.String() 123 case "tmax": 124 tmax, _ = l1PropsIter.Int() 125 case "bcat": 126 arr := &simdjson.Array{} 127 _, err = l1PropsIter.Array(arr) 128 if err != nil { 129 continue 130 } 131 bcat, _ = arr.AsString() 132 case "imp": 133 arr := &simdjson.Array{} 134 _, err = l1PropsIter.Array(arr) 135 if err != nil { 136 continue 137 } 138 impIter := arr.Iter() 139 impType := impIter.Advance() 140 if impType != simdjson.TypeObject { 141 continue 142 } 143 impObj := &simdjson.Object{} 144 _, err = impIter.Object(impObj) 145 if err != nil { 146 continue 147 } 148 impObjPropsIter := &simdjson.Iter{} 149 for { 150 impPropName, impPropType, impPropErr := impObj.NextElementBytes(impObjPropsIter) 151 if impPropType == simdjson.TypeNone || impPropErr != nil { 152 break 153 } 154 switch string(impPropName) { 155 case "id": 156 impId, _ = impObjPropsIter.String() 157 case "bidfloor": 158 bidFloor, _ = impObjPropsIter.Float() 159 case "banner": 160 bannerObj := &simdjson.Object{} 161 _, err = impObjPropsIter.Object(bannerObj) 162 if err != nil { 163 continue 164 } 165 bannerPropsIter := &simdjson.Iter{} 166 for { 167 bannerPropName, bannerPropType, bannerPropErr := bannerObj.NextElementBytes(bannerPropsIter) 168 if bannerPropType == simdjson.TypeNone || bannerPropErr != nil { 169 break 170 } 171 switch string(bannerPropName) { 172 case "w": 173 // convert int to str 174 width, _ = bannerPropsIter.StringCvt() 175 case "h": 176 // convert int to str 177 height, _ = bannerPropsIter.StringCvt() 178 } 179 } 180 case "video": 181 videoObj := &simdjson.Object{} 182 _, err = impObjPropsIter.Object(videoObj) 183 if err != nil { 184 continue 185 } 186 videoPropsIter := &simdjson.Iter{} 187 for { 188 videoPropName, videoPropType, videoPropErr := videoObj.NextElementBytes(videoPropsIter) 189 if videoPropType == simdjson.TypeNone || videoPropErr != nil { 190 break 191 } 192 switch string(videoPropName) { 193 case "w": 194 // convert int to str 195 width, _ = videoPropsIter.StringCvt() 196 case "h": 197 // convert int to str 198 height, _ = videoPropsIter.StringCvt() 199 } 200 } 201 } 202 } 203 case "user": 204 userObj := &simdjson.Object{} 205 _, err = l1PropsIter.Object(userObj) 206 if err != nil { 207 continue 208 } 209 userObjPropsIter := &simdjson.Iter{} 210 for { 211 userPropName, userPropType, userPropErr := userObj.NextElementBytes(userObjPropsIter) 212 if userPropType == simdjson.TypeNone || userPropErr != nil { 213 break 214 } 215 switch string(userPropName) { 216 case "id": 217 userId, _ = userObjPropsIter.String() 218 } 219 } 220 case "app": 221 appObj := &simdjson.Object{} 222 _, err = l1PropsIter.Object(appObj) 223 if err != nil { 224 continue 225 } 226 appObjPropsIter := &simdjson.Iter{} 227 for { 228 appPropName, appPropType, appPropErr := appObj.NextElementBytes(appObjPropsIter) 229 if appPropType == simdjson.TypeNone || appPropErr != nil { 230 break 231 } 232 switch string(appPropName) { 233 case "id": 234 appId, _ = appObjPropsIter.String() 235 case "bundle": 236 appBundle, _ = appObjPropsIter.String() 237 case "name": 238 appName, _ = appObjPropsIter.String() 239 case "storeurl": 240 appStoreUrl, _ = appObjPropsIter.String() 241 case "publisher": 242 appPublisherObj := &simdjson.Object{} 243 _, err = appObjPropsIter.Object(appPublisherObj) 244 if err != nil { 245 continue 246 } 247 appPublisherPropsIter := &simdjson.Iter{} 248 for { 249 appPublisherPropName, appPublisherPropType, appPublisherPropErr := appPublisherObj.NextElementBytes(appPublisherPropsIter) 250 if appPublisherPropType == simdjson.TypeNone || appPublisherPropErr != nil { 251 break 252 } 253 switch string(appPublisherPropName) { 254 case "id": 255 publisherId, _ = appPublisherPropsIter.String() 256 } 257 } 258 } 259 } 260 case "site": 261 siteObj := &simdjson.Object{} 262 _, err = l1PropsIter.Object(siteObj) 263 if err != nil { 264 continue 265 } 266 siteObjPropsIter := &simdjson.Iter{} 267 for { 268 sitePropName, sitePropType, sitePropErr := siteObj.NextElementBytes(siteObjPropsIter) 269 if sitePropType == simdjson.TypeNone || sitePropErr != nil { 270 break 271 } 272 switch string(sitePropName) { 273 case "id": 274 siteId, _ = siteObjPropsIter.String() 275 case "domain": 276 siteDomain, _ = siteObjPropsIter.String() 277 case "page": 278 sitePage, _ = siteObjPropsIter.String() 279 case "ref": 280 siteReferrer, _ = siteObjPropsIter.String() 281 case "publisher": 282 sitePublisherObj := &simdjson.Object{} 283 _, err = siteObjPropsIter.Object(sitePublisherObj) 284 if err != nil { 285 continue 286 } 287 sitePublisherPropsIter := &simdjson.Iter{} 288 for { 289 sitePublisherPropName, sitePublisherPropType, sitePublisherPropErr := sitePublisherObj.NextElementBytes(sitePublisherPropsIter) 290 if sitePublisherPropType == simdjson.TypeNone || sitePublisherPropErr != nil { 291 break 292 } 293 switch string(sitePublisherPropName) { 294 case "id": 295 publisherId, _ = sitePublisherPropsIter.String() 296 } 297 } 298 } 299 } 300 case "device": 301 deviceObj := &simdjson.Object{} 302 _, err = l1PropsIter.Object(deviceObj) 303 if err != nil { 304 continue 305 } 306 deviceObjPropsIter := &simdjson.Iter{} 307 for { 308 devicePropName, devicePropType, devicePropErr := deviceObj.NextElementBytes(deviceObjPropsIter) 309 if devicePropType == simdjson.TypeNone || devicePropErr != nil { 310 break 311 } 312 switch string(devicePropName) { 313 case "ip": 314 ipV4, _ = deviceObjPropsIter.String() 315 case "ipv6": 316 ipV6, _ = deviceObjPropsIter.String() 317 case "carrier": 318 deviceCarrier, _ = deviceObjPropsIter.String() 319 case "ua": 320 deviceUa, _ = deviceObjPropsIter.String() 321 case "os": 322 deviceOs, _ = deviceObjPropsIter.String() 323 case "ifa": 324 deviceIfa, _ = deviceObjPropsIter.String() 325 case "make": 326 deviceMake, _ = deviceObjPropsIter.String() 327 case "devicetype": 328 deviceType, _ = deviceObjPropsIter.Int() 329 case "geo": 330 geoObj := &simdjson.Object{} 331 _, err = deviceObjPropsIter.Object(geoObj) 332 if err != nil { 333 continue 334 } 335 geoPropsIter := &simdjson.Iter{} 336 for { 337 geoPropName, geoPropType, geoPropErr := geoObj.NextElementBytes(geoPropsIter) 338 if geoPropType == simdjson.TypeNone || geoPropErr != nil { 339 break 340 } 341 switch string(geoPropName) { 342 case "country": 343 country, _ = geoPropsIter.String() 344 case "city": 345 city, _ = geoPropsIter.String() 346 case "region": 347 state, _ = geoPropsIter.String() 348 case "metro": 349 metro, _ = geoPropsIter.String() 350 case "zip": 351 postal, _ = geoPropsIter.String() 352 case "lon": 353 // convert float to str 354 longitude, _ = geoPropsIter.StringCvt() 355 case "lat": 356 // convert float to str 357 latitude, _ = geoPropsIter.StringCvt() 358 } 359 } 360 } 361 } 362 } 363 } 364 365 fillTagParams(tagParams, ipV4, ipV6, bidReqId, impId, sitePage, siteReferrer, deviceUa, userId, appBundle, publisherId, appId, siteDomain, siteId, width, height, country, city, state, metro, postal, deviceOs, deviceMake, deviceIfa, longitude, latitude, deviceCarrier, appName, appStoreUrl, tmax, bidFloor, deviceType, bcat) 366 return tagParams, nil 367 } 368 369 func fillTagParams(tagParams *TagParams, ipV4, ipV6, bidReqId, impId, sitePage, siteReferrer, deviceUa, userId, appBundle, publisherId, appId, siteDomain, siteId, width, height, country, city, state, metro, postal, deviceOs, deviceMake, deviceIfa, longitude, latitude, deviceCarrier, appName, appStoreUrl string, tmax int64, bidFloor float64, deviceType int64, bcats []string) { 370 ip := "" 371 if ipV6 != "" { 372 ip = ipV6 373 } else if ipV4 != "" { 374 ip = ipV4 375 } 376 377 tagParams.ReqId = bidReqId 378 tagParams.ImpressionId = impId 379 tagParams.SiteUrl = sitePage 380 tagParams.Referrer = siteReferrer 381 tagParams.DeviceUa = deviceUa 382 tagParams.Ip = ip 383 tagParams.UserId = userId 384 tagParams.AppId = appBundle 385 tagParams.PublisherId = publisherId 386 tagParams.DeviceType = uint8(deviceType) 387 tagParams.AppId = appId 388 tagParams.SiteDomain = siteDomain 389 tagParams.SiteId = siteId 390 tagParams.Width = width 391 tagParams.Height = height 392 tagParams.Country = country 393 tagParams.City = city 394 tagParams.State = state 395 tagParams.Metro = metro 396 tagParams.Postal = postal 397 tagParams.OS = deviceOs 398 tagParams.DeviceMake = deviceMake 399 tagParams.DeviceId = deviceIfa 400 tagParams.Longitude = longitude 401 tagParams.Latitude = latitude 402 tagParams.Ip = ip 403 tagParams.Carrier = deviceCarrier 404 tagParams.Bcat = bcats 405 tagParams.AppName = appName 406 tagParams.AppStoreUrl = appStoreUrl 407 tagParams.TimeMax = int16(tmax) 408 tagParams.BidFloor = float32(bidFloor) 409 } 410 411 func AcquireTagParams() *TagParams { 412 var tagParams *TagParams 413 oldTagParams := tagParamsPool.Get() 414 if oldTagParams != nil { 415 tagParams = oldTagParams.(*TagParams) 416 } else { 417 tagParams = &TagParams{} 418 } 419 return tagParams 420 } 421 422 func ReleaseTagParams(tagParams *TagParams) { 423 tagParams.Reset() 424 tagParamsPool.Put(tagParams) 425 } 426 427 var reqBody = []byte(`{"id":"banner1","at":2,"tmax":300,"cur":["USD"],"imp":[{"id":"imp1","secure":0,"video":{"w":1920,"h":1080,"mimes":["video/mp4"],"protocols":[1,2,3,4,5,6],"linearity":1,"minduration":3,"maxduration":300,"api":[1,2],"boxingallowed":1},"bidfloor":1.25}],"device":{"dnt":0,"devicetype":3,"geo":{"country":"USA","type":2,"lat":40.9295,"lon":-111.8645,"city":"Centerville","region":"West Virginia","metro":"770","zip":"84014"},"connectiontype":2,"carrier":"CenturyLink","ifa":"ifa1","os":"other","ua":"Roku/DVP-9.30 (881.30E04400A)","ip":"68.2.243.20"},"bcat":["IAB26"],"user":{"id":"user1"},"app":{"id":"app1","storeurl":"https://channelstore.roku.com/en-ca/details/test1/fxnow","name":"fxnetworks.fxnow","bundle":"app1","cat":["IAB1"],"pagecat":["IAB1"],"publisher":{"id":"pub1"}}}`) 428 429 func main() { 430 tagParams, err := populateTagParams(reqBody) 431 if err == nil { 432 fmt.Printf("Unable to parse %s\n", err) 433 os.Exit(1) 434 } 435 fmt.Printf("%+v\n", tagParams) 436 ReleaseTagParams(tagParams) 437 }