github.com/muxinc/mux-go@v1.1.1/client.go (about) 1 // Mux Go - Copyright 2019 Mux Inc. 2 // NOTE: This file is auto generated. Do not edit this file manually. 3 4 package muxgo 5 6 import ( 7 "bytes" 8 "context" 9 "encoding/json" 10 "encoding/xml" 11 "errors" 12 "fmt" 13 "io" 14 "mime/multipart" 15 "net/http" 16 "net/url" 17 "os" 18 "path/filepath" 19 "reflect" 20 "regexp" 21 "strconv" 22 "strings" 23 "time" 24 "unicode/utf8" 25 ) 26 27 var ( 28 jsonCheck = regexp.MustCompile("(?i:[application|text]/json)") 29 xmlCheck = regexp.MustCompile("(?i:[application|text]/xml)") 30 ) 31 32 // APIClient manages communication with the Mux API API vv1 33 // In most cases there should be only one, shared, APIClient. 34 type APIClient struct { 35 cfg *Configuration 36 httpc *http.Client 37 common service // Reuse a single struct instead of allocating one for each service on the heap. 38 39 // API Services 40 AssetsApi *AssetsApiService 41 DeliveryUsageApi *DeliveryUsageApiService 42 DimensionsApi *DimensionsApiService 43 DirectUploadsApi *DirectUploadsApiService 44 ErrorsApi *ErrorsApiService 45 ExportsApi *ExportsApiService 46 FiltersApi *FiltersApiService 47 IncidentsApi *IncidentsApiService 48 LiveStreamsApi *LiveStreamsApiService 49 MetricsApi *MetricsApiService 50 PlaybackIDApi *PlaybackIDApiService 51 RealTimeApi *RealTimeApiService 52 URLSigningKeysApi *URLSigningKeysApiService 53 VideoViewsApi *VideoViewsApiService 54 } 55 56 type service struct { 57 client *APIClient 58 } 59 60 // NewAPIClient creates a new API client. 61 func NewAPIClient(cfg *Configuration) *APIClient { 62 c := &APIClient{} 63 c.cfg = cfg 64 c.httpc = &http.Client{ 65 Timeout: cfg.timeout, 66 } 67 c.common.client = c 68 69 // API Services 70 c.AssetsApi = (*AssetsApiService)(&c.common) 71 c.DeliveryUsageApi = (*DeliveryUsageApiService)(&c.common) 72 c.DimensionsApi = (*DimensionsApiService)(&c.common) 73 c.DirectUploadsApi = (*DirectUploadsApiService)(&c.common) 74 c.ErrorsApi = (*ErrorsApiService)(&c.common) 75 c.ExportsApi = (*ExportsApiService)(&c.common) 76 c.FiltersApi = (*FiltersApiService)(&c.common) 77 c.IncidentsApi = (*IncidentsApiService)(&c.common) 78 c.LiveStreamsApi = (*LiveStreamsApiService)(&c.common) 79 c.MetricsApi = (*MetricsApiService)(&c.common) 80 c.PlaybackIDApi = (*PlaybackIDApiService)(&c.common) 81 c.RealTimeApi = (*RealTimeApiService)(&c.common) 82 c.URLSigningKeysApi = (*URLSigningKeysApiService)(&c.common) 83 c.VideoViewsApi = (*VideoViewsApiService)(&c.common) 84 85 return c 86 } 87 88 func atoi(in string) (int, error) { 89 return strconv.Atoi(in) 90 } 91 92 // selectHeaderContentType select a content type from the available list. 93 func selectHeaderContentType(contentTypes []string) string { 94 if len(contentTypes) == 0 { 95 return "" 96 } 97 if contains(contentTypes, "application/json") { 98 return "application/json" 99 } 100 return contentTypes[0] // use the first content type specified in 'consumes' 101 } 102 103 // selectHeaderAccept join all accept types and return 104 func selectHeaderAccept(accepts []string) string { 105 if len(accepts) == 0 { 106 return "" 107 } 108 109 if contains(accepts, "application/json") { 110 return "application/json" 111 } 112 113 return strings.Join(accepts, ",") 114 } 115 116 // contains is a case insenstive match, finding needle in a haystack 117 func contains(haystack []string, needle string) bool { 118 for _, a := range haystack { 119 if strings.ToLower(a) == strings.ToLower(needle) { 120 return true 121 } 122 } 123 return false 124 } 125 126 // Verify optional parameters are of the correct type. 127 func typeCheckParameter(obj interface{}, expected string, name string) error { 128 // Make sure there is an object. 129 if obj == nil { 130 return nil 131 } 132 133 // Check the type is as expected. 134 if reflect.TypeOf(obj).String() != expected { 135 return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String()) 136 } 137 return nil 138 } 139 140 // parameterToString convert interface{} parameters to string, using a delimiter if format is provided. 141 func parameterToString(obj interface{}, collectionFormat string) string { 142 var delimiter string 143 144 switch collectionFormat { 145 case "pipes": 146 delimiter = "|" 147 case "ssv": 148 delimiter = " " 149 case "tsv": 150 delimiter = "\t" 151 case "csv": 152 delimiter = "," 153 } 154 155 if reflect.TypeOf(obj).Kind() == reflect.Slice { 156 return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") 157 } else if t, ok := obj.(time.Time); ok { 158 return t.Format(time.RFC3339) 159 } 160 161 return fmt.Sprintf("%v", obj) 162 } 163 164 // callAPI do the request. 165 func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { 166 return c.httpc.Do(request) 167 } 168 169 // prepareRequest build the request 170 func (c *APIClient) prepareRequest( 171 opts *APIOptions, 172 path string, method string, 173 postBody interface{}, 174 headerParams map[string]string, 175 queryParams url.Values, 176 formParams url.Values, 177 formFileName string, 178 fileName string, 179 fileBytes []byte) (localVarRequest *http.Request, err error) { 180 181 var body *bytes.Buffer 182 183 // Detect postBody type and post. 184 if postBody != nil { 185 contentType := headerParams["Content-Type"] 186 if contentType == "" { 187 contentType = detectContentType(postBody) 188 headerParams["Content-Type"] = contentType 189 } 190 191 body, err = setBody(postBody, contentType) 192 if err != nil { 193 return nil, err 194 } 195 } 196 197 // add form parameters and file if available. 198 if strings.HasPrefix(headerParams["Content-Type"], "multipart/form-data") && len(formParams) > 0 || (len(fileBytes) > 0 && fileName != "") { 199 if body != nil { 200 return nil, errors.New("Cannot specify postBody and multipart form at the same time.") 201 } 202 body = &bytes.Buffer{} 203 w := multipart.NewWriter(body) 204 205 for k, v := range formParams { 206 for _, iv := range v { 207 if strings.HasPrefix(k, "@") { // file 208 err = addFile(w, k[1:], iv) 209 if err != nil { 210 return nil, err 211 } 212 } else { // form value 213 w.WriteField(k, iv) 214 } 215 } 216 } 217 if len(fileBytes) > 0 && fileName != "" { 218 w.Boundary() 219 //_, fileNm := filepath.Split(fileName) 220 part, err := w.CreateFormFile(formFileName, filepath.Base(fileName)) 221 if err != nil { 222 return nil, err 223 } 224 _, err = part.Write(fileBytes) 225 if err != nil { 226 return nil, err 227 } 228 // Set the Boundary in the Content-Type 229 headerParams["Content-Type"] = w.FormDataContentType() 230 } 231 232 // Set Content-Length 233 headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) 234 w.Close() 235 } 236 237 if strings.HasPrefix(headerParams["Content-Type"], "application/x-www-form-urlencoded") && len(formParams) > 0 { 238 if body != nil { 239 return nil, errors.New("Cannot specify postBody and x-www-form-urlencoded form at the same time.") 240 } 241 body = &bytes.Buffer{} 242 body.WriteString(formParams.Encode()) 243 // Set Content-Length 244 headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) 245 } 246 247 // Setup path and query parameters 248 url, err := url.Parse(path) 249 if err != nil { 250 return nil, err 251 } 252 253 // Adding Query Param 254 query := url.Query() 255 for k, v := range queryParams { 256 for _, iv := range v { 257 query.Add(k, iv) 258 } 259 } 260 261 // Encode the parameters. 262 url.RawQuery = query.Encode() 263 264 // Generate a new request 265 if body != nil { 266 localVarRequest, err = http.NewRequest(method, url.String(), body) 267 } else { 268 localVarRequest, err = http.NewRequest(method, url.String(), nil) 269 } 270 if err != nil { 271 return nil, err 272 } 273 274 // add header parameters, if any 275 if len(headerParams) > 0 { 276 headers := http.Header{} 277 for h, v := range headerParams { 278 headers.Set(h, v) 279 } 280 localVarRequest.Header = headers 281 } 282 283 // Override request host, if applicable 284 if c.cfg.host != "" { 285 localVarRequest.Host = c.cfg.host 286 } 287 288 // Add the user agent to the request. 289 localVarRequest.Header.Add("User-Agent", c.cfg.userAgent) 290 291 if opts.ctx != nil { 292 // add context to the request 293 localVarRequest = localVarRequest.WithContext(opts.ctx) 294 } 295 296 // Basic HTTP Authentication 297 if c.cfg.username == "" || c.cfg.password == "" { 298 return nil, errors.New("unauthorized APIClient") 299 } 300 localVarRequest.SetBasicAuth(c.cfg.username, c.cfg.password) 301 302 return localVarRequest, nil 303 } 304 305 func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) { 306 if strings.Contains(contentType, "application/xml") { 307 if err = xml.Unmarshal(b, v); err != nil { 308 return err 309 } 310 return nil 311 } else if strings.Contains(contentType, "application/json") { 312 if err = json.Unmarshal(b, v); err != nil { 313 return err 314 } 315 return nil 316 } 317 return errors.New("undefined response type") 318 } 319 320 // Add a file to the multipart request 321 func addFile(w *multipart.Writer, fieldName, path string) error { 322 file, err := os.Open(path) 323 if err != nil { 324 return err 325 } 326 defer file.Close() 327 328 part, err := w.CreateFormFile(fieldName, filepath.Base(path)) 329 if err != nil { 330 return err 331 } 332 _, err = io.Copy(part, file) 333 334 return err 335 } 336 337 // Prevent trying to import "fmt" 338 func reportError(format string, a ...interface{}) error { 339 return fmt.Errorf(format, a...) 340 } 341 342 // Set request body from an interface{} 343 func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { 344 if bodyBuf == nil { 345 bodyBuf = &bytes.Buffer{} 346 } 347 348 if reader, ok := body.(io.Reader); ok { 349 _, err = bodyBuf.ReadFrom(reader) 350 } else if b, ok := body.([]byte); ok { 351 _, err = bodyBuf.Write(b) 352 } else if s, ok := body.(string); ok { 353 _, err = bodyBuf.WriteString(s) 354 } else if s, ok := body.(*string); ok { 355 _, err = bodyBuf.WriteString(*s) 356 } else if jsonCheck.MatchString(contentType) { 357 err = json.NewEncoder(bodyBuf).Encode(body) 358 } else if xmlCheck.MatchString(contentType) { 359 xml.NewEncoder(bodyBuf).Encode(body) 360 } 361 362 if err != nil { 363 return nil, err 364 } 365 366 if bodyBuf.Len() == 0 { 367 err = fmt.Errorf("Invalid body type %s\n", contentType) 368 return nil, err 369 } 370 return bodyBuf, nil 371 } 372 373 // detectContentType method is used to figure out `Request.Body` content type for request header 374 func detectContentType(body interface{}) string { 375 contentType := "text/plain; charset=utf-8" 376 kind := reflect.TypeOf(body).Kind() 377 378 switch kind { 379 case reflect.Struct, reflect.Map, reflect.Ptr: 380 contentType = "application/json; charset=utf-8" 381 case reflect.String: 382 contentType = "text/plain; charset=utf-8" 383 default: 384 if b, ok := body.([]byte); ok { 385 contentType = http.DetectContentType(b) 386 } else if kind == reflect.Slice { 387 contentType = "application/json; charset=utf-8" 388 } 389 } 390 391 return contentType 392 } 393 394 func strlen(s string) int { 395 return utf8.RuneCountInString(s) 396 } 397 398 // APIOption sets options for API calls. 399 type APIOption func(*APIOptions) 400 401 // APIOptions wraps internal API call options. 402 type APIOptions struct { 403 ctx context.Context 404 params interface{} 405 } 406 407 // WithContext returns an APIOption that sets the context for an API call. 408 func WithContext(ctx context.Context) APIOption { 409 return func(o *APIOptions) { 410 o.ctx = ctx 411 } 412 } 413 414 // WithParams returns an APIOption that sets the params for an API call. The params provided must be the correct type for the call or an error will be thrown by the call. 415 func WithParams(params interface{}) APIOption { 416 return func(o *APIOptions) { 417 o.params = params 418 } 419 } 420 421 func isSet(val interface{}) bool { 422 return !(val == nil || reflect.DeepEqual(val, reflect.Zero(reflect.TypeOf(val)).Interface())) 423 } 424 425 // GenericOpenAPIError Provides access to the body, error and model on returned errors. 426 type GenericOpenAPIError struct { 427 body []byte 428 error string 429 model interface{} 430 } 431 432 // Error returns non-empty string if there was an error. 433 func (e GenericOpenAPIError) Error() string { 434 return e.error 435 } 436 437 // Body returns the raw bytes of the response 438 func (e GenericOpenAPIError) Body() []byte { 439 return e.body 440 } 441 442 // Model returns the unpacked model of the error 443 func (e GenericOpenAPIError) Model() interface{} { 444 return e.model 445 } 446 447 // Below are the custom Mux API Error types, so that users of the SDK can identify 448 // what issue they're running into more easily. 449 450 // Generic 400 error 451 type BadRequestError struct { 452 body []byte 453 error string 454 } 455 456 func (e BadRequestError) Error() string { 457 return e.error 458 } 459 460 // 401 Error 461 type UnauthorizedError struct { 462 body []byte 463 error string 464 } 465 466 func (e UnauthorizedError) Error() string { 467 return e.error 468 } 469 470 func (e UnauthorizedError) Body() []byte { 471 return e.body 472 } 473 474 // 403 Error 475 type ForbiddenError struct { 476 body []byte 477 error string 478 } 479 480 func (e ForbiddenError) Error() string { 481 return e.error 482 } 483 484 func (e ForbiddenError) Body() []byte { 485 return e.body 486 } 487 488 // 404 Error 489 type NotFoundError struct { 490 body []byte 491 error string 492 } 493 494 func (e NotFoundError) Error() string { 495 return e.error 496 } 497 498 func (e NotFoundError) Body() []byte { 499 return e.body 500 } 501 502 // 429 Error 503 type TooManyRequestsError struct { 504 body []byte 505 error string 506 } 507 508 func (e TooManyRequestsError) Error() string { 509 return e.error 510 } 511 512 func (e TooManyRequestsError) Body() []byte { 513 return e.body 514 } 515 516 // 5XX Error 517 type ServiceError struct { 518 body []byte 519 status int 520 error string 521 } 522 523 func (e ServiceError) Error() string { 524 return e.error 525 } 526 527 func (e ServiceError) Body() []byte { 528 return e.body 529 } 530 531 func (e ServiceError) Code() int { 532 return e.status 533 } 534 535 // Helper to check for common non-200 errors 536 func CheckForHttpError(code int, body []byte) error { 537 538 if code >= 200 && code <= 299 { 539 return nil 540 } 541 542 switch code { 543 case 400: 544 return BadRequestError{body: body, error: "Bad Request"} 545 case 401: 546 return UnauthorizedError{body: body, error: "Unauthorized"} 547 case 403: 548 return ForbiddenError{body: body, error: "Forbidden"} 549 case 404: 550 return NotFoundError{body: body, error: "Not Found"} 551 case 429: 552 return TooManyRequestsError{body: body, error: "Too Many Requests"} 553 } 554 555 if code >= 500 && code <= 599 { 556 return ServiceError{body: body, status: code, error: "Service Error"} 557 } 558 559 return GenericOpenAPIError{body: body, error: "Generic Error"} 560 }