github.com/prebid/prebid-server/v2@v2.18.0/adapters/gamoshi/gamoshi.go (about)

     1  package gamoshi
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"strconv"
     8  
     9  	"github.com/prebid/openrtb/v20/openrtb2"
    10  	"github.com/prebid/prebid-server/v2/adapters"
    11  	"github.com/prebid/prebid-server/v2/config"
    12  	"github.com/prebid/prebid-server/v2/errortypes"
    13  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    14  )
    15  
    16  type GamoshiAdapter struct {
    17  	URI string
    18  }
    19  
    20  func (a *GamoshiAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    21  
    22  	errs := make([]error, 0, len(request.Imp))
    23  	if len(request.Imp) == 0 {
    24  		err := &errortypes.BadInput{
    25  			Message: "No impressions in the bid request",
    26  		}
    27  		errs = append(errs, err)
    28  		return nil, errs
    29  	}
    30  
    31  	// As of now, Gamoshi supports only banner and video impressions
    32  
    33  	validImpExists := false
    34  	for i := 0; i < len(request.Imp); i++ {
    35  		if request.Imp[i].Banner != nil {
    36  			bannerCopy := *request.Imp[i].Banner
    37  			if bannerCopy.W == nil && bannerCopy.H == nil && len(bannerCopy.Format) > 0 {
    38  				firstFormat := bannerCopy.Format[0]
    39  				bannerCopy.W = &(firstFormat.W)
    40  				bannerCopy.H = &(firstFormat.H)
    41  			}
    42  			request.Imp[i].Banner = &bannerCopy
    43  			validImpExists = true
    44  		} else if request.Imp[i].Video != nil {
    45  			validImpExists = true
    46  		} else {
    47  			err := &errortypes.BadInput{
    48  				Message: fmt.Sprintf("Gamoshi only supports banner and video media types. Ignoring imp id=%s", request.Imp[i].ID),
    49  			}
    50  			errs = append(errs, err)
    51  			request.Imp = append(request.Imp[:i], request.Imp[i+1:]...)
    52  			i--
    53  		}
    54  	}
    55  
    56  	if !validImpExists {
    57  		err := &errortypes.BadInput{
    58  			Message: fmt.Sprintf("No valid impression in the bid request"),
    59  		}
    60  		errs = append(errs, err)
    61  		return nil, errs
    62  	}
    63  
    64  	reqJSON, err := json.Marshal(request)
    65  	if err != nil {
    66  		errs = append(errs, err)
    67  		return nil, errs
    68  	}
    69  	errors := make([]error, 0, 1)
    70  
    71  	var bidderExt adapters.ExtImpBidder
    72  	err = json.Unmarshal(request.Imp[0].Ext, &bidderExt)
    73  
    74  	if err != nil {
    75  		err = &errortypes.BadInput{
    76  			Message: "ext.bidder not provided",
    77  		}
    78  		errors = append(errors, err)
    79  		return nil, errors
    80  	}
    81  	var gamoshiExt openrtb_ext.ExtImpGamoshi
    82  	err = json.Unmarshal(bidderExt.Bidder, &gamoshiExt)
    83  	if err != nil {
    84  		err = &errortypes.BadInput{
    85  			Message: "ext.bidder.supplyPartnerId not provided",
    86  		}
    87  		errors = append(errors, err)
    88  		return nil, errors
    89  	}
    90  
    91  	if gamoshiExt.SupplyPartnerId == "" {
    92  		err = &errortypes.BadInput{
    93  			Message: "supplyPartnerId is empty",
    94  		}
    95  		errors = append(errors, err)
    96  		return nil, errors
    97  	}
    98  
    99  	thisURI := a.URI
   100  	if len(thisURI) == 0 {
   101  		thisURI = "https://rtb.gamoshi.io"
   102  	}
   103  	thisURI = thisURI + "/r/" + gamoshiExt.SupplyPartnerId + "/bidr?bidder=prebid-server"
   104  	headers := http.Header{}
   105  	headers.Add("Content-Type", "application/json;charset=utf-8")
   106  	headers.Add("Accept", "application/json")
   107  	headers.Add("x-openrtb-version", "2.4")
   108  
   109  	if request.Device != nil {
   110  		addHeaderIfNonEmpty(headers, "User-Agent", request.Device.UA)
   111  		addHeaderIfNonEmpty(headers, "X-Forwarded-For", request.Device.IP)
   112  		addHeaderIfNonEmpty(headers, "Accept-Language", request.Device.Language)
   113  		if request.Device.DNT != nil {
   114  			addHeaderIfNonEmpty(headers, "DNT", strconv.Itoa(int(*request.Device.DNT)))
   115  		}
   116  	}
   117  
   118  	return []*adapters.RequestData{{
   119  		Method:  "POST",
   120  		Uri:     thisURI,
   121  		Body:    reqJSON,
   122  		Headers: headers,
   123  		ImpIDs:  openrtb_ext.GetImpIDs(request.Imp),
   124  	}}, errors
   125  }
   126  
   127  func (a *GamoshiAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
   128  
   129  	if response.StatusCode == http.StatusNoContent {
   130  		return nil, nil
   131  	}
   132  
   133  	if response.StatusCode == http.StatusBadRequest {
   134  		return nil, []error{&errortypes.BadInput{
   135  			Message: fmt.Sprintf("Unexpected status code: %d. ", response.StatusCode),
   136  		}}
   137  	}
   138  
   139  	if response.StatusCode != http.StatusOK {
   140  		return nil, []error{&errortypes.BadServerResponse{
   141  			Message: fmt.Sprintf("unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
   142  		}}
   143  	}
   144  
   145  	var bidResp openrtb2.BidResponse
   146  	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
   147  		return nil, []error{&errortypes.BadServerResponse{
   148  			Message: fmt.Sprintf("bad server response: %v. ", err),
   149  		}}
   150  	}
   151  
   152  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))
   153  	sb := bidResp.SeatBid[0]
   154  	for i := 0; i < len(sb.Bid); i++ {
   155  		bid := sb.Bid[i]
   156  		bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   157  			Bid:     &bid,
   158  			BidType: getMediaType(bid.ImpID, internalRequest.Imp),
   159  		})
   160  	}
   161  	return bidResponse, nil
   162  }
   163  
   164  // Adding header fields to request header
   165  func addHeaderIfNonEmpty(headers http.Header, headerName string, headerValue string) {
   166  	if len(headerValue) > 0 {
   167  		headers.Add(headerName, headerValue)
   168  	}
   169  }
   170  
   171  func getMediaType(impId string, imps []openrtb2.Imp) openrtb_ext.BidType {
   172  	for _, imp := range imps {
   173  		if imp.ID == impId {
   174  			if imp.Video != nil {
   175  				return openrtb_ext.BidTypeVideo
   176  			}
   177  			return openrtb_ext.BidTypeBanner
   178  		}
   179  	}
   180  	return openrtb_ext.BidTypeBanner
   181  }
   182  
   183  // Builder builds a new instance of the Gamoshi adapter for the given bidder with the given config.
   184  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
   185  	bidder := &GamoshiAdapter{
   186  		URI: config.Endpoint,
   187  	}
   188  	return bidder, nil
   189  }