github.com/prebid/prebid-server@v0.275.0/adapters/mobilefuse/mobilefuse.go (about) 1 package mobilefuse 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strconv" 8 "text/template" 9 10 "github.com/prebid/openrtb/v19/openrtb2" 11 "github.com/prebid/prebid-server/adapters" 12 "github.com/prebid/prebid-server/config" 13 "github.com/prebid/prebid-server/errortypes" 14 "github.com/prebid/prebid-server/macros" 15 "github.com/prebid/prebid-server/openrtb_ext" 16 ) 17 18 type MobileFuseAdapter struct { 19 EndpointTemplate *template.Template 20 } 21 22 type ExtMf struct { 23 MediaType string `json:"media_type"` 24 } 25 26 type BidExt struct { 27 Mf ExtMf `json:"mf"` 28 } 29 30 type ExtSkadn struct { 31 Skadn json.RawMessage `json:"skadn"` 32 } 33 34 // Builder builds a new instance of the MobileFuse adapter for the given bidder with the given config. 35 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 36 template, err := template.New("endpointTemplate").Parse(config.Endpoint) 37 if err != nil { 38 return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) 39 } 40 41 bidder := &MobileFuseAdapter{ 42 EndpointTemplate: template, 43 } 44 return bidder, nil 45 } 46 47 func (adapter *MobileFuseAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 48 var adapterRequests []*adapters.RequestData 49 50 adapterRequest, errs := adapter.makeRequest(request) 51 52 if errs == nil { 53 adapterRequests = append(adapterRequests, adapterRequest) 54 } 55 56 return adapterRequests, errs 57 } 58 59 func (adapter *MobileFuseAdapter) MakeBids(incomingRequest *openrtb2.BidRequest, outgoingRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 60 if response.StatusCode == http.StatusNoContent { 61 return nil, nil 62 } 63 64 if response.StatusCode == http.StatusBadRequest { 65 return nil, []error{&errortypes.BadInput{ 66 Message: fmt.Sprintf("Unexpected status code: %d.", response.StatusCode), 67 }} 68 } 69 70 if response.StatusCode != http.StatusOK { 71 return nil, []error{&errortypes.BadServerResponse{ 72 Message: fmt.Sprintf("Unexpected status code: %d.", response.StatusCode), 73 }} 74 } 75 76 var incomingBidResponse openrtb2.BidResponse 77 78 if err := json.Unmarshal(response.Body, &incomingBidResponse); err != nil { 79 return nil, []error{err} 80 } 81 82 outgoingBidResponse := adapters.NewBidderResponseWithBidsCapacity(1) 83 84 for _, seatbid := range incomingBidResponse.SeatBid { 85 for i := range seatbid.Bid { 86 bidType := getBidType(seatbid.Bid[i]) 87 seatbid.Bid[i].Ext = nil 88 89 outgoingBidResponse.Bids = append(outgoingBidResponse.Bids, &adapters.TypedBid{ 90 Bid: &seatbid.Bid[i], 91 BidType: bidType, 92 }) 93 } 94 } 95 96 return outgoingBidResponse, nil 97 } 98 99 func (adapter *MobileFuseAdapter) makeRequest(bidRequest *openrtb2.BidRequest) (*adapters.RequestData, []error) { 100 var errs []error 101 102 mobileFuseExtension, errs := getFirstMobileFuseExtension(bidRequest) 103 if errs != nil { 104 return nil, errs 105 } 106 107 endpoint, err := adapter.getEndpoint(mobileFuseExtension) 108 if err != nil { 109 return nil, append(errs, err) 110 } 111 112 validImps, err := getValidImps(bidRequest, mobileFuseExtension) 113 if err != nil { 114 errs = append(errs, err) 115 return nil, errs 116 } 117 118 mobileFuseBidRequest := *bidRequest 119 mobileFuseBidRequest.Imp = validImps 120 body, err := json.Marshal(mobileFuseBidRequest) 121 if err != nil { 122 return nil, append(errs, err) 123 } 124 125 headers := http.Header{} 126 headers.Add("Content-Type", "application/json;charset=utf-8") 127 headers.Add("Accept", "application/json") 128 129 return &adapters.RequestData{ 130 Method: "POST", 131 Uri: endpoint, 132 Body: body, 133 Headers: headers, 134 }, errs 135 } 136 137 func getFirstMobileFuseExtension(request *openrtb2.BidRequest) (*openrtb_ext.ExtImpMobileFuse, []error) { 138 var mobileFuseImpExtension openrtb_ext.ExtImpMobileFuse 139 var errs []error 140 141 for _, imp := range request.Imp { 142 var bidder_imp_extension adapters.ExtImpBidder 143 144 err := json.Unmarshal(imp.Ext, &bidder_imp_extension) 145 146 if err != nil { 147 errs = append(errs, err) 148 continue 149 } 150 151 err = json.Unmarshal(bidder_imp_extension.Bidder, &mobileFuseImpExtension) 152 153 if err != nil { 154 errs = append(errs, err) 155 continue 156 } 157 158 break 159 } 160 161 return &mobileFuseImpExtension, errs 162 } 163 164 func getMobileFuseExtensionForImp(imp *openrtb2.Imp, mobileFuseImpExtension *openrtb_ext.ExtImpMobileFuse) error { 165 var bidder_imp_extension adapters.ExtImpBidder 166 167 err := json.Unmarshal(imp.Ext, &bidder_imp_extension) 168 if err != nil { 169 return err 170 } 171 172 return json.Unmarshal(bidder_imp_extension.Bidder, &mobileFuseImpExtension) 173 } 174 175 func (adapter *MobileFuseAdapter) getEndpoint(ext *openrtb_ext.ExtImpMobileFuse) (string, error) { 176 publisher_id := strconv.Itoa(ext.PublisherId) 177 178 url, err := macros.ResolveMacros(adapter.EndpointTemplate, macros.EndpointTemplateParams{PublisherID: publisher_id}) 179 if err != nil { 180 return "", err 181 } 182 183 if ext.TagidSrc == "ext" { 184 url += "&tagid_src=ext" 185 } 186 187 return url, nil 188 } 189 190 func getValidImps(bidRequest *openrtb2.BidRequest, ext *openrtb_ext.ExtImpMobileFuse) ([]openrtb2.Imp, error) { 191 var validImps []openrtb2.Imp 192 193 for _, imp := range bidRequest.Imp { 194 if imp.Banner != nil || imp.Video != nil || imp.Native != nil { 195 err := getMobileFuseExtensionForImp(&imp, ext) 196 if err != nil { 197 return nil, err 198 } 199 200 imp.TagID = strconv.Itoa(ext.PlacementId) 201 202 var extSkadn ExtSkadn 203 err = json.Unmarshal(imp.Ext, &extSkadn) 204 if err != nil { 205 return nil, err 206 } 207 208 if extSkadn.Skadn != nil { 209 imp.Ext, err = json.Marshal(map[string]json.RawMessage{"skadn": extSkadn.Skadn}) 210 if err != nil { 211 return nil, err 212 } 213 } else { 214 imp.Ext = nil 215 } 216 217 validImps = append(validImps, imp) 218 } 219 } 220 221 if len(validImps) == 0 { 222 return nil, fmt.Errorf("No valid imps") 223 } 224 225 return validImps, nil 226 } 227 228 func getBidType(bid openrtb2.Bid) openrtb_ext.BidType { 229 if bid.Ext != nil { 230 var bidExt BidExt 231 err := json.Unmarshal(bid.Ext, &bidExt) 232 if err == nil { 233 if bidExt.Mf.MediaType == "video" { 234 return openrtb_ext.BidTypeVideo 235 } else if bidExt.Mf.MediaType == "native" { 236 return openrtb_ext.BidTypeNative 237 } 238 } 239 } 240 241 return openrtb_ext.BidTypeBanner 242 }