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  }