invoker.go raw
1 // Copyright 2022 Huawei Technologies Co.,Ltd.
2 //
3 // Licensed to the Apache Software Foundation (ASF) under one
4 // or more contributor license agreements. See the NOTICE file
5 // distributed with this work for additional information
6 // regarding copyright ownership. The ASF licenses this file
7 // to you under the Apache License, Version 2.0 (the
8 // "License"); you may not use this file except in compliance
9 // with the License. You may obtain a copy of the License at
10 //
11 // http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing,
14 // software distributed under the License is distributed on an
15 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 // KIND, either express or implied. See the License for the
17 // specific language governing permissions and limitations
18 // under the License.
19
20 package invoker
21
22 import (
23 "time"
24
25 "github.com/huaweicloud/huaweicloud-sdk-go-v3/core"
26 "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth"
27 "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/def"
28 "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/exchange"
29 "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/invoker/retry"
30 )
31
32 type RetryChecker func(interface{}, error) bool
33
34 type BaseInvoker struct {
35 Exchange *exchange.SdkExchange
36
37 client *core.HcHttpClient
38 request interface{}
39 meta *def.HttpRequestDef
40 headers map[string]string
41
42 retryTimes int
43 retryChecker RetryChecker
44 backoffStrategy retry.Strategy
45 }
46
47 func NewBaseInvoker(client *core.HcHttpClient, request interface{}, meta *def.HttpRequestDef) *BaseInvoker {
48 exch := &exchange.SdkExchange{
49 ApiReference: &exchange.ApiReference{
50 Method: meta.Method,
51 Path: meta.Path,
52 },
53 Attributes: make(map[string]interface{}),
54 }
55
56 return &BaseInvoker{
57 Exchange: exch,
58 client: client,
59 request: request,
60 meta: meta,
61 headers: make(map[string]string),
62 }
63 }
64
65 func (b *BaseInvoker) ReplaceCredentialWhen(fun func(auth.ICredential) auth.ICredential) *BaseInvoker {
66 b.client.WithCredential(fun(b.client.GetCredential()))
67 return b
68 }
69
70 // Deprecated: This function will be removed in the future version, use AddHeaders instead.
71 func (b *BaseInvoker) AddHeader(headers map[string]string) *BaseInvoker {
72 return b.AddHeaders(headers)
73 }
74
75 func (b *BaseInvoker) AddHeaders(headers map[string]string) *BaseInvoker {
76 if headers != nil {
77 for k, v := range headers {
78 b.headers[k] = v
79 }
80 }
81 return b
82 }
83
84 func (b *BaseInvoker) WithRetry(retryTimes int, checker RetryChecker, backoffStrategy retry.Strategy) *BaseInvoker {
85 b.retryTimes = retryTimes
86 b.retryChecker = checker
87 b.backoffStrategy = backoffStrategy
88 return b
89 }
90
91 func (b *BaseInvoker) Invoke() (interface{}, error) {
92 if b.retryTimes == 0 || b.retryChecker == nil {
93 return b.client.SyncInvokeWithExtraHeaders(b.request, b.meta, b.Exchange, b.headers)
94 }
95
96 var execTimes int
97 var resp interface{}
98 var err error
99 for {
100 resp, err = b.client.SyncInvokeWithExtraHeaders(b.request, b.meta, b.Exchange, b.headers)
101 execTimes++
102
103 if execTimes > b.retryTimes || !b.retryChecker(resp, err) {
104 break
105 }
106
107 delay := b.backoffStrategy.ComputeDelayBeforeNextRetry(int32(execTimes))
108 if delay > 0 {
109 time.Sleep(time.Duration(delay) * time.Millisecond)
110 }
111 }
112 return resp, err
113 }
114