github.com/prebid/prebid-server@v0.275.0/adapters/beachfront/beachfront.go (about) 1 package beachfront 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net/http" 8 "strconv" 9 "strings" 10 11 "github.com/prebid/openrtb/v19/adcom1" 12 "github.com/prebid/openrtb/v19/openrtb2" 13 "github.com/prebid/prebid-server/adapters" 14 "github.com/prebid/prebid-server/config" 15 "github.com/prebid/prebid-server/errortypes" 16 "github.com/prebid/prebid-server/openrtb_ext" 17 ) 18 19 const Seat = "beachfront" 20 const BidCapacity = 5 21 22 const defaultVideoEndpoint = "https://reachms.bfmio.com/bid.json?exchange_id" 23 24 const nurlVideoEndpointSuffix = "&prebidserver" 25 26 const beachfrontAdapterName = "BF_PREBID_S2S" 27 const beachfrontAdapterVersion = "1.0.0" 28 29 const minBidFloor = 0.01 30 31 const defaultVideoWidth = 300 32 const defaultVideoHeight = 250 33 const fakeIP = "255.255.255.255" 34 35 type BeachfrontAdapter struct { 36 bannerEndpoint string 37 extraInfo ExtraInfo 38 } 39 40 type ExtraInfo struct { 41 VideoEndpoint string `json:"video_endpoint,omitempty"` 42 } 43 44 type beachfrontRequests struct { 45 Banner beachfrontBannerRequest 46 NurlVideo []beachfrontVideoRequest 47 ADMVideo []beachfrontVideoRequest 48 } 49 50 // --------------------------------------------------- 51 // Video 52 // --------------------------------------------------- 53 54 type beachfrontVideoRequest struct { 55 AppId string `json:"appId"` 56 VideoResponseType string `json:"videoResponseType"` 57 Request openrtb2.BidRequest `json:"request"` 58 } 59 60 // --------------------------------------------------- 61 // 62 // Banner 63 // 64 // --------------------------------------------------- 65 type beachfrontBannerRequest struct { 66 Slots []beachfrontSlot `json:"slots"` 67 Domain string `json:"domain"` 68 Page string `json:"page"` 69 Referrer string `json:"referrer"` 70 Search string `json:"search"` 71 Secure int8 `json:"secure"` 72 DeviceOs string `json:"deviceOs"` 73 DeviceModel string `json:"deviceModel"` 74 IsMobile int8 `json:"isMobile"` 75 UA string `json:"ua"` 76 Dnt int8 `json:"dnt"` 77 User openrtb2.User `json:"user"` 78 AdapterName string `json:"adapterName"` 79 AdapterVersion string `json:"adapterVersion"` 80 IP string `json:"ip"` 81 RequestID string `json:"requestId"` 82 Real204 bool `json:"real204"` 83 SChain openrtb2.SupplyChain `json:"schain,omitempty"` 84 } 85 86 type beachfrontSlot struct { 87 Slot string `json:"slot"` 88 Id string `json:"id"` 89 Bidfloor float64 `json:"bidfloor"` 90 Sizes []beachfrontSize `json:"sizes"` 91 } 92 93 type beachfrontSize struct { 94 W uint64 `json:"w"` 95 H uint64 `json:"h"` 96 } 97 98 // --------------------------------------------------- 99 // Banner response 100 // --------------------------------------------------- 101 102 type beachfrontResponseSlot struct { 103 CrID string `json:"crid"` 104 Price float64 `json:"price"` 105 W uint64 `json:"w"` 106 H uint64 `json:"h"` 107 Slot string `json:"slot"` 108 Adm string `json:"adm"` 109 } 110 111 type beachfrontVideoBidExtension struct { 112 Duration int `json:"duration"` 113 } 114 115 func (a *BeachfrontAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 116 beachfrontRequests, errs := preprocess(request, reqInfo) 117 118 headers := http.Header{} 119 headers.Add("Content-Type", "application/json;charset=utf-8") 120 headers.Add("Accept", "application/json") 121 122 if request.Device != nil { 123 if request.Device.UA != "" { 124 headers.Add("User-Agent", request.Device.UA) 125 } 126 127 if request.Device.Language != "" { 128 headers.Add("Accept-Language", request.Device.Language) 129 } 130 131 if request.Device.DNT != nil { 132 headers.Add("DNT", strconv.Itoa(int(*request.Device.DNT))) 133 } 134 } 135 136 var reqCount = len(beachfrontRequests.ADMVideo) + len(beachfrontRequests.NurlVideo) 137 if len(beachfrontRequests.Banner.Slots) > 0 { 138 reqCount++ 139 } 140 141 var reqs = make([]*adapters.RequestData, reqCount) 142 143 var nurlBump = 0 144 var admBump = 0 145 146 if len(beachfrontRequests.Banner.Slots) > 0 { 147 bytes, err := json.Marshal(beachfrontRequests.Banner) 148 149 if err == nil { 150 reqs[0] = &adapters.RequestData{ 151 Method: "POST", 152 Uri: a.bannerEndpoint, 153 Body: bytes, 154 Headers: headers, 155 } 156 157 nurlBump++ 158 admBump++ 159 } else { 160 errs = append(errs, err) 161 } 162 } 163 164 if request.User != nil && request.User.BuyerUID != "" && reqCount > 0 { 165 headers.Add("Cookie", "__io_cid="+request.User.BuyerUID) 166 } 167 168 for j := 0; j < len(beachfrontRequests.ADMVideo); j++ { 169 bytes, err := json.Marshal(beachfrontRequests.ADMVideo[j].Request) 170 if err == nil { 171 reqs[j+nurlBump] = &adapters.RequestData{ 172 Method: "POST", 173 Uri: a.extraInfo.VideoEndpoint + "=" + beachfrontRequests.ADMVideo[j].AppId, 174 Body: bytes, 175 Headers: headers, 176 } 177 178 admBump++ 179 180 } else { 181 errs = append(errs, err) 182 } 183 } 184 185 for j := 0; j < len(beachfrontRequests.NurlVideo); j++ { 186 bytes, err := json.Marshal(beachfrontRequests.NurlVideo[j].Request) 187 188 if err == nil { 189 bytes = append([]byte(`{"isPrebid":true,`), bytes[1:]...) 190 reqs[j+admBump] = &adapters.RequestData{ 191 Method: "POST", 192 Uri: a.extraInfo.VideoEndpoint + "=" + beachfrontRequests.NurlVideo[j].AppId + nurlVideoEndpointSuffix, 193 Body: bytes, 194 Headers: headers, 195 } 196 } else { 197 errs = append(errs, err) 198 } 199 } 200 201 return reqs, errs 202 } 203 204 func preprocess(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) (beachfrontReqs beachfrontRequests, errs []error) { 205 var videoImps = make([]openrtb2.Imp, 0) 206 var bannerImps = make([]openrtb2.Imp, 0) 207 208 for i := 0; i < len(request.Imp); i++ { 209 if request.Imp[i].Banner != nil && request.Imp[i].Banner.Format != nil && 210 request.Imp[i].Banner.Format[0].H != 0 && request.Imp[i].Banner.Format[0].W != 0 { 211 bannerImps = append(bannerImps, request.Imp[i]) 212 } 213 214 if request.Imp[i].Video != nil { 215 videoImps = append(videoImps, request.Imp[i]) 216 } 217 } 218 219 if len(bannerImps)+len(videoImps) == 0 { 220 errs = append(errs, errors.New("no valid impressions were found in the request")) 221 return 222 } 223 224 if len(bannerImps) > 0 { 225 request.Imp = bannerImps 226 beachfrontReqs.Banner, errs = getBannerRequest(request, reqInfo) 227 } 228 229 if len(videoImps) > 0 { 230 var videoErrs []error 231 var videoList []beachfrontVideoRequest 232 233 request.Imp = videoImps 234 request.Ext = nil 235 236 videoList, videoErrs = getVideoRequests(request, reqInfo) 237 errs = append(errs, videoErrs...) 238 239 for i := 0; i < len(videoList); i++ { 240 if videoList[i].VideoResponseType == "nurl" { 241 beachfrontReqs.NurlVideo = append(beachfrontReqs.NurlVideo, videoList[i]) 242 } 243 244 if videoList[i].VideoResponseType == "adm" { 245 beachfrontReqs.ADMVideo = append(beachfrontReqs.ADMVideo, videoList[i]) 246 } 247 } 248 } 249 250 return 251 } 252 253 func getAppId(ext openrtb_ext.ExtImpBeachfront, media openrtb_ext.BidType) (string, error) { 254 var appid string 255 var error error 256 257 if ext.AppId != "" { 258 appid = ext.AppId 259 } else if media == openrtb_ext.BidTypeVideo && ext.AppIds.Video != "" { 260 appid = ext.AppIds.Video 261 } else if media == openrtb_ext.BidTypeBanner && ext.AppIds.Banner != "" { 262 appid = ext.AppIds.Banner 263 } else { 264 error = errors.New("unable to determine the appId(s) from the supplied extension") 265 } 266 267 return appid, error 268 } 269 270 func getSchain(request *openrtb2.BidRequest) (openrtb_ext.ExtRequestPrebidSChain, error) { 271 var schain openrtb_ext.ExtRequestPrebidSChain 272 return schain, json.Unmarshal(request.Source.Ext, &schain) 273 } 274 275 func getBannerRequest(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) (beachfrontBannerRequest, []error) { 276 var bfr beachfrontBannerRequest 277 var errs = make([]error, 0, len(request.Imp)) 278 279 for i := 0; i < len(request.Imp); i++ { 280 281 beachfrontExt, err := getBeachfrontExtension(request.Imp[i]) 282 283 if err != nil { 284 errs = append(errs, err) 285 continue 286 } 287 288 appid, err := getAppId(beachfrontExt, openrtb_ext.BidTypeBanner) 289 290 if err != nil { 291 errs = append(errs, err) 292 continue 293 } 294 295 if fatal, err := setBidFloor(&beachfrontExt, &request.Imp[i], reqInfo); err != nil { 296 errs = append(errs, err) 297 if fatal { 298 continue 299 } 300 } 301 302 slot := beachfrontSlot{ 303 Id: appid, 304 Slot: request.Imp[i].ID, 305 Bidfloor: request.Imp[i].BidFloor, 306 } 307 308 for j := 0; j < len(request.Imp[i].Banner.Format); j++ { 309 310 slot.Sizes = append(slot.Sizes, beachfrontSize{ 311 H: uint64(request.Imp[i].Banner.Format[j].H), 312 W: uint64(request.Imp[i].Banner.Format[j].W), 313 }) 314 } 315 316 bfr.Slots = append(bfr.Slots, slot) 317 } 318 319 if len(bfr.Slots) == 0 { 320 return bfr, errs 321 } 322 323 if request.Device != nil { 324 bfr.IP = request.Device.IP 325 bfr.DeviceModel = request.Device.Model 326 bfr.DeviceOs = request.Device.OS 327 if request.Device.DNT != nil { 328 bfr.Dnt = *request.Device.DNT 329 } 330 if request.Device.UA != "" { 331 bfr.UA = request.Device.UA 332 } 333 } 334 335 var t = fallBackDeviceType(request) 336 337 if t == adcom1.DeviceMobile { 338 bfr.Page = request.App.Bundle 339 if request.App.Domain == "" { 340 bfr.Domain = getDomain(request.App.Domain) 341 } else { 342 bfr.Domain = request.App.Domain 343 } 344 345 bfr.IsMobile = 1 346 } else if t == adcom1.DevicePC { 347 bfr.Page = request.Site.Page 348 if request.Site.Domain == "" { 349 bfr.Domain = getDomain(request.Site.Page) 350 } else { 351 bfr.Domain = request.Site.Domain 352 } 353 354 bfr.IsMobile = 0 355 } 356 357 bfr.Secure = isSecure(bfr.Page) 358 359 if request.User != nil && request.User.ID != "" { 360 if bfr.User.ID == "" { 361 bfr.User.ID = request.User.ID 362 } 363 } 364 365 if request.User != nil && request.User.BuyerUID != "" { 366 if bfr.User.BuyerUID == "" { 367 bfr.User.BuyerUID = request.User.BuyerUID 368 } 369 } 370 371 bfr.RequestID = request.ID 372 bfr.AdapterName = beachfrontAdapterName 373 bfr.AdapterVersion = beachfrontAdapterVersion 374 375 if request.Imp[0].Secure != nil { 376 bfr.Secure = *request.Imp[0].Secure 377 } 378 bfr.Real204 = true 379 380 if request.Source != nil && request.Source.Ext != nil { 381 schain, err := getSchain(request) 382 if err == nil { 383 bfr.SChain = schain.SChain 384 } 385 } 386 387 return bfr, errs 388 } 389 390 func fallBackDeviceType(request *openrtb2.BidRequest) adcom1.DeviceType { 391 if request.Site != nil { 392 return adcom1.DevicePC 393 } 394 395 return adcom1.DeviceMobile 396 } 397 398 func getVideoRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]beachfrontVideoRequest, []error) { 399 var bfReqs = make([]beachfrontVideoRequest, len(request.Imp)) 400 var errs = make([]error, 0, len(request.Imp)) 401 var failedRequestIndicies = make([]int, 0) 402 403 for i := 0; i < len(request.Imp); i++ { 404 beachfrontExt, err := getBeachfrontExtension(request.Imp[i]) 405 406 if err != nil { 407 failedRequestIndicies = append(failedRequestIndicies, i) 408 errs = append(errs, err) 409 continue 410 } 411 412 appid, err := getAppId(beachfrontExt, openrtb_ext.BidTypeVideo) 413 bfReqs[i].AppId = appid 414 415 if err != nil { 416 failedRequestIndicies = append(failedRequestIndicies, i) 417 errs = append(errs, err) 418 continue 419 } 420 421 bfReqs[i].Request = *request 422 var secure int8 423 424 var deviceCopy openrtb2.Device 425 if bfReqs[i].Request.Device == nil { 426 deviceCopy = openrtb2.Device{} 427 } else { 428 deviceCopy = *bfReqs[i].Request.Device 429 } 430 431 if beachfrontExt.VideoResponseType == "nurl" { 432 bfReqs[i].VideoResponseType = "nurl" 433 } else { 434 bfReqs[i].VideoResponseType = "adm" 435 436 if deviceCopy.IP == "" { 437 deviceCopy.IP = fakeIP 438 } 439 } 440 441 if bfReqs[i].Request.Site != nil && bfReqs[i].Request.Site.Domain == "" && bfReqs[i].Request.Site.Page != "" { 442 siteCopy := *bfReqs[i].Request.Site 443 siteCopy.Domain = getDomain(bfReqs[i].Request.Site.Page) 444 bfReqs[i].Request.Site = &siteCopy 445 secure = isSecure(bfReqs[i].Request.Site.Page) 446 } 447 448 if bfReqs[i].Request.App != nil && bfReqs[i].Request.App.Domain == "" && bfReqs[i].Request.App.Bundle != "" { 449 if bfReqs[i].Request.App.Bundle != "" { 450 var chunks = strings.Split(strings.Trim(bfReqs[i].Request.App.Bundle, "_"), ".") 451 452 if len(chunks) > 1 { 453 appCopy := *bfReqs[i].Request.App 454 appCopy.Domain = fmt.Sprintf("%s.%s", chunks[len(chunks)-(len(chunks)-1)], chunks[0]) 455 bfReqs[i].Request.App = &appCopy 456 } 457 } 458 } 459 460 if deviceCopy.DeviceType == 0 { 461 deviceCopy.DeviceType = fallBackDeviceType(request) 462 } 463 bfReqs[i].Request.Device = &deviceCopy 464 465 imp := request.Imp[i] 466 467 imp.Banner = nil 468 imp.Ext = nil 469 imp.Secure = &secure 470 if fatal, err := setBidFloor(&beachfrontExt, &imp, reqInfo); err != nil { 471 errs = append(errs, err) 472 if fatal { 473 failedRequestIndicies = append(failedRequestIndicies, i) 474 continue 475 } 476 } 477 478 if imp.Video.H == 0 && imp.Video.W == 0 { 479 imp.Video.W = defaultVideoWidth 480 imp.Video.H = defaultVideoHeight 481 } 482 483 if len(bfReqs[i].Request.Cur) == 0 { 484 bfReqs[i].Request.Cur = make([]string, 1) 485 bfReqs[i].Request.Cur[0] = "USD" 486 } 487 488 bfReqs[i].Request.Imp = nil 489 bfReqs[i].Request.Imp = make([]openrtb2.Imp, 1) 490 bfReqs[i].Request.Imp[0] = imp 491 492 } 493 494 if len(failedRequestIndicies) > 0 { 495 for i := 0; i < len(failedRequestIndicies); i++ { 496 bfReqs = removeVideoElement(bfReqs, failedRequestIndicies[i]) 497 } 498 499 } 500 return bfReqs, errs 501 } 502 503 func (a *BeachfrontAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 504 if response.StatusCode == http.StatusNoContent { 505 return nil, nil 506 } 507 508 if response.StatusCode >= http.StatusInternalServerError { 509 return nil, []error{&errortypes.BadServerResponse{ 510 Message: fmt.Sprintf("server error status code %d from %s. Run with request.debug = 1 for more info", response.StatusCode, externalRequest.Uri), 511 }} 512 } 513 514 if response.StatusCode >= http.StatusBadRequest { 515 return nil, []error{&errortypes.BadInput{ 516 Message: fmt.Sprintf("request error status code %d from %s. Run with request.debug = 1 for more info", response.StatusCode, externalRequest.Uri), 517 }} 518 } 519 520 if response.StatusCode != http.StatusOK { 521 return nil, []error{fmt.Errorf("unexpected status code %d from %s. Run with request.debug = 1 for more info", response.StatusCode, externalRequest.Uri)} 522 } 523 524 var bids []openrtb2.Bid 525 var errs = make([]error, 0) 526 var xtrnal openrtb2.BidRequest 527 528 if err := json.Unmarshal(externalRequest.Body, &xtrnal); err != nil { 529 errs = append(errs, err) 530 } else { 531 bids, errs = postprocess(response, xtrnal, externalRequest.Uri, internalRequest.ID) 532 } 533 534 if len(errs) != 0 { 535 return nil, errs 536 } 537 538 var dur beachfrontVideoBidExtension 539 bidResponse := adapters.NewBidderResponseWithBidsCapacity(BidCapacity) 540 541 for i := 0; i < len(bids); i++ { 542 543 if err := json.Unmarshal(bids[i].Ext, &dur); err == nil && dur.Duration > 0 { 544 545 impVideo := openrtb_ext.ExtBidPrebidVideo{ 546 Duration: int(dur.Duration), 547 } 548 549 if len(bids[i].Cat) > 0 { 550 impVideo.PrimaryCategory = bids[i].Cat[0] 551 } 552 553 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 554 Bid: &bids[i], 555 BidType: a.getBidType(externalRequest), 556 BidVideo: &impVideo, 557 }) 558 } else { 559 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 560 Bid: &bids[i], 561 BidType: a.getBidType(externalRequest), 562 }) 563 } 564 } 565 566 return bidResponse, errs 567 } 568 569 func setBidFloor(ext *openrtb_ext.ExtImpBeachfront, imp *openrtb2.Imp, reqInfo *adapters.ExtraRequestInfo) (bool, error) { 570 var initialImpBidfloor float64 = imp.BidFloor 571 var err error 572 573 if imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != "USD" && imp.BidFloor > 0 { 574 imp.BidFloor, err = reqInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD") 575 576 var convertedFromCurrency = imp.BidFloorCur 577 imp.BidFloorCur = "USD" 578 579 if err != nil { 580 if ext.BidFloor > minBidFloor { 581 imp.BidFloor = ext.BidFloor 582 return false, &errortypes.Warning{ 583 Message: fmt.Sprintf("The following error was recieved from the currency converter while attempting to convert the imp.bidfloor value of %.2f from %s to USD:\n%s\nThe provided value of imp.ext.beachfront.bidfloor, %.2f USD is being used as a fallback.", 584 initialImpBidfloor, 585 convertedFromCurrency, 586 err, 587 ext.BidFloor, 588 ), 589 } 590 } else { 591 return true, &errortypes.BadInput{ 592 Message: fmt.Sprintf("The following error was recieved from the currency converter while attempting to convert the imp.bidfloor value of %.2f from %s to USD:\n%s\nA value of imp.ext.beachfront.bidfloor was not provided. The bid is being skipped.", 593 initialImpBidfloor, 594 convertedFromCurrency, 595 err, 596 ), 597 } 598 } 599 } 600 } 601 602 if imp.BidFloor < ext.BidFloor { 603 imp.BidFloor = ext.BidFloor 604 } 605 606 if imp.BidFloor > minBidFloor { 607 imp.BidFloorCur = "USD" 608 } else { 609 imp.BidFloor = 0 610 imp.BidFloorCur = "" 611 } 612 613 return false, nil 614 } 615 616 func (a *BeachfrontAdapter) getBidType(externalRequest *adapters.RequestData) openrtb_ext.BidType { 617 t := strings.Split(externalRequest.Uri, "=")[0] 618 if t == a.extraInfo.VideoEndpoint { 619 return openrtb_ext.BidTypeVideo 620 } 621 622 return openrtb_ext.BidTypeBanner 623 } 624 625 func postprocess(response *adapters.ResponseData, xtrnal openrtb2.BidRequest, uri string, id string) ([]openrtb2.Bid, []error) { 626 var beachfrontResp []beachfrontResponseSlot 627 628 var openrtbResp openrtb2.BidResponse 629 630 if err := json.Unmarshal(response.Body, &openrtbResp); err != nil || len(openrtbResp.SeatBid) == 0 { 631 632 if err := json.Unmarshal(response.Body, &beachfrontResp); err != nil { 633 return nil, []error{&errortypes.BadServerResponse{ 634 Message: "server response failed to unmarshal as valid rtb. Run with request.debug = 1 for more info", 635 }} 636 } else { 637 return postprocessBanner(beachfrontResp, id) 638 } 639 } 640 641 return postprocessVideo(openrtbResp.SeatBid[0].Bid, xtrnal, uri, id) 642 } 643 644 func postprocessBanner(beachfrontResp []beachfrontResponseSlot, id string) ([]openrtb2.Bid, []error) { 645 646 var bids = make([]openrtb2.Bid, len(beachfrontResp)) 647 var errs = make([]error, 0) 648 649 for i := 0; i < len(beachfrontResp); i++ { 650 bids[i] = openrtb2.Bid{ 651 CrID: beachfrontResp[i].CrID, 652 ImpID: beachfrontResp[i].Slot, 653 Price: beachfrontResp[i].Price, 654 ID: fmt.Sprintf("%sBanner", beachfrontResp[i].Slot), 655 AdM: beachfrontResp[i].Adm, 656 H: int64(beachfrontResp[i].H), 657 W: int64(beachfrontResp[i].W), 658 } 659 } 660 661 return bids, errs 662 } 663 664 func postprocessVideo(bids []openrtb2.Bid, xtrnal openrtb2.BidRequest, uri string, id string) ([]openrtb2.Bid, []error) { 665 666 var errs = make([]error, 0) 667 668 if uri[len(uri)-len(nurlVideoEndpointSuffix):] == nurlVideoEndpointSuffix { 669 670 for i := 0; i < len(bids); i++ { 671 crid := extractNurlVideoCrid(bids[i].NURL) 672 673 bids[i].CrID = crid 674 bids[i].ImpID = xtrnal.Imp[i].ID 675 bids[i].H = xtrnal.Imp[i].Video.H 676 bids[i].W = xtrnal.Imp[i].Video.W 677 bids[i].ID = fmt.Sprintf("%sNurlVideo", xtrnal.Imp[i].ID) 678 } 679 680 } else { 681 for i := 0; i < len(bids); i++ { 682 bids[i].ID = fmt.Sprintf("%sAdmVideo", bids[i].ImpID) 683 } 684 685 } 686 return bids, errs 687 } 688 689 func extractNurlVideoCrid(nurl string) string { 690 chunky := strings.SplitAfter(nurl, ":") 691 if len(chunky) > 1 { 692 return strings.TrimSuffix(chunky[2], ":") 693 } 694 695 return "" 696 } 697 698 func getBeachfrontExtension(imp openrtb2.Imp) (openrtb_ext.ExtImpBeachfront, error) { 699 var err error 700 var bidderExt adapters.ExtImpBidder 701 var beachfrontExt openrtb_ext.ExtImpBeachfront 702 703 if err = json.Unmarshal(imp.Ext, &bidderExt); err != nil { 704 return beachfrontExt, &errortypes.BadInput{ 705 Message: fmt.Sprintf("ignoring imp id=%s, error while decoding extImpBidder, err: %s", imp.ID, err), 706 } 707 } 708 709 if err = json.Unmarshal(bidderExt.Bidder, &beachfrontExt); err != nil { 710 return beachfrontExt, &errortypes.BadInput{ 711 Message: fmt.Sprintf("ignoring imp id=%s, error while decoding extImpBeachfront, err: %s", imp.ID, err), 712 } 713 } 714 715 return beachfrontExt, err 716 } 717 718 func getDomain(page string) string { 719 protoURL := strings.Split(page, "//") 720 var domainPage string 721 722 if len(protoURL) > 1 { 723 domainPage = protoURL[1] 724 } else { 725 domainPage = protoURL[0] 726 } 727 728 return strings.Split(domainPage, "/")[0] 729 730 } 731 732 func isSecure(page string) int8 { 733 protoURL := strings.Split(page, "://") 734 735 if len(protoURL) > 1 && protoURL[0] == "https" { 736 return 1 737 } 738 739 return 0 740 741 } 742 743 func removeVideoElement(slice []beachfrontVideoRequest, s int) []beachfrontVideoRequest { 744 if len(slice) >= s+1 { 745 return append(slice[:s], slice[s+1:]...) 746 } 747 748 return []beachfrontVideoRequest{} 749 } 750 751 // Builder builds a new instance of the Beachfront adapter for the given bidder with the given config. 752 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 753 extraInfo, err := getExtraInfo(config.ExtraAdapterInfo) 754 if err != nil { 755 return nil, err 756 } 757 758 bidder := &BeachfrontAdapter{ 759 bannerEndpoint: config.Endpoint, 760 extraInfo: extraInfo, 761 } 762 return bidder, nil 763 } 764 765 func getExtraInfo(v string) (ExtraInfo, error) { 766 if len(v) == 0 { 767 return getDefaultExtraInfo(), nil 768 } 769 770 var extraInfo ExtraInfo 771 if err := json.Unmarshal([]byte(v), &extraInfo); err != nil { 772 return extraInfo, fmt.Errorf("invalid extra info: %v", err) 773 } 774 775 if extraInfo.VideoEndpoint == "" { 776 extraInfo.VideoEndpoint = defaultVideoEndpoint 777 } 778 779 return extraInfo, nil 780 } 781 782 func getDefaultExtraInfo() ExtraInfo { 783 return ExtraInfo{ 784 VideoEndpoint: defaultVideoEndpoint, 785 } 786 }