|
| 1 | +package kernel |
| 2 | + |
| 3 | +import ( |
| 4 | + "crypto/md5" |
| 5 | + "encoding/json" |
| 6 | + "fmt" |
| 7 | + "github.com/ArtisanCloud/go-libs/exception" |
| 8 | + http2 "github.com/ArtisanCloud/go-libs/http" |
| 9 | + httpContract "github.com/ArtisanCloud/go-libs/http/contract" |
| 10 | + "github.com/ArtisanCloud/go-libs/object" |
| 11 | + "github.com/ArtisanCloud/go-wechat/src/kernel/contract" |
| 12 | + response2 "github.com/ArtisanCloud/go-wechat/src/kernel/response" |
| 13 | + "net/http" |
| 14 | + "time" |
| 15 | +) |
| 16 | + |
| 17 | +type AccessToken struct { |
| 18 | + App *ApplicationInterface |
| 19 | + |
| 20 | + *http2.HttpRequest |
| 21 | + *http2.HttpResponse |
| 22 | + |
| 23 | + RequestMethod string |
| 24 | + EndpointToGetToken string |
| 25 | + QueryName string |
| 26 | + Token object.HashMap |
| 27 | + TokenKey string |
| 28 | + CachePrefix string |
| 29 | + |
| 30 | + *CacheToken |
| 31 | + |
| 32 | + GetCredentials func() *object.StringMap |
| 33 | +} |
| 34 | + |
| 35 | +func NewAccessToken(app *ApplicationInterface) *AccessToken { |
| 36 | + config := (*app).GetContainer().GetConfig() |
| 37 | + |
| 38 | + token := &AccessToken{ |
| 39 | + App: app, |
| 40 | + HttpRequest: http2.NewHttpRequest(config), |
| 41 | + |
| 42 | + RequestMethod: "GET", |
| 43 | + EndpointToGetToken: "", |
| 44 | + QueryName: "", |
| 45 | + Token: nil, |
| 46 | + TokenKey: "access_token", |
| 47 | + CachePrefix: "ac.go.wechat.kernel.access_token.", |
| 48 | + |
| 49 | + CacheToken: &CacheToken{}, |
| 50 | + } |
| 51 | + |
| 52 | + return token |
| 53 | +} |
| 54 | + |
| 55 | +func (accessToken *AccessToken) GetRefreshedToken() *response2.ResponseGetToken { |
| 56 | + return accessToken.GetToken(true) |
| 57 | +} |
| 58 | + |
| 59 | +func (accessToken *AccessToken) GetToken(refresh bool) (resToken *response2.ResponseGetToken) { |
| 60 | + cacheKey := accessToken.getCacheKey() |
| 61 | + cache := accessToken.getCache() |
| 62 | + |
| 63 | + // get token from cache |
| 64 | + if !refresh && cache.Has(cacheKey) { |
| 65 | + value, err := cache.Get(cacheKey, nil) |
| 66 | + if err == nil { |
| 67 | + token := value.(*object.HashMap) |
| 68 | + return &response2.ResponseGetToken{ |
| 69 | + AccessToken: (*token)[accessToken.TokenKey].(string), |
| 70 | + ExpiresIn: (*token)["expires_in"].(int), |
| 71 | + } |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + // request token from wx |
| 76 | + response := accessToken.requestToken(accessToken.GetCredentials()) |
| 77 | + |
| 78 | + //// save token into cache |
| 79 | + resToken = response.(*response2.ResponseGetToken) |
| 80 | + var expireIn int = 7200 |
| 81 | + if resToken.ExpiresIn > 0 { |
| 82 | + expireIn = resToken.ExpiresIn |
| 83 | + } |
| 84 | + accessToken.SetToken(resToken.AccessToken, expireIn) |
| 85 | + |
| 86 | + // tbd dispatch a event for AccessTokenRefresh |
| 87 | + |
| 88 | + return resToken |
| 89 | +} |
| 90 | + |
| 91 | +func (accessToken *AccessToken) SetToken(token string, lifeTime int) (tokenInterface contract.AccessTokenInterface, err error) { |
| 92 | + if lifeTime <= 0 { |
| 93 | + lifeTime = 7200 |
| 94 | + } |
| 95 | + |
| 96 | + // set token into cache |
| 97 | + cache := accessToken.getCache() |
| 98 | + err = cache.Set(accessToken.getCacheKey(), &object.HashMap{ |
| 99 | + accessToken.TokenKey: token, |
| 100 | + "expires_in": lifeTime, |
| 101 | + }, time.Duration(lifeTime)*time.Second) |
| 102 | + |
| 103 | + defer (&exception.Exception{}).HandleException(nil, "accessToken.set.token", nil) |
| 104 | + if !cache.Has(accessToken.getCacheKey()) { |
| 105 | + panic("Failed to cache access token.") |
| 106 | + return nil, err |
| 107 | + } |
| 108 | + return accessToken, err |
| 109 | + |
| 110 | +} |
| 111 | + |
| 112 | +func (accessToken *AccessToken) Refresh() contract.AccessTokenInterface { |
| 113 | + |
| 114 | + return nil |
| 115 | +} |
| 116 | + |
| 117 | +func (accessToken *AccessToken) requestToken(credentials *object.StringMap) httpContract.ResponseContract { |
| 118 | + |
| 119 | + // tbf |
| 120 | + return &response2.ResponseGetToken{ |
| 121 | + AccessToken: "FwhFYGuWs47wxxUQHf5gbOIwMBe8ohu3EUnhF-x6uw4VX55-m46bnQUHLJ1nM5R0WAVfrLHvdn6XJtkMkzRkN_E75edrNzWK6IZxx3RwUJNowZEg3dcU3NEygFGfzUEGLS5fiB4GtNPOi-HKUhQumAMcP0lncEij2Hjg95FTqS4YBRNVG4OL92h8RAiP-yllfDvt2URk6tntGe4HaxAGdA", |
| 122 | + ExpiresIn: 7200, |
| 123 | + ResponseWX: &response2.ResponseWX{ |
| 124 | + ErrCode: 0, |
| 125 | + ErrMSG: "ok", |
| 126 | + }, |
| 127 | + } |
| 128 | + |
| 129 | + res := accessToken.sendRequest(credentials) |
| 130 | + token := res.(*response2.ResponseGetToken) |
| 131 | + defer (&exception.Exception{}).HandleException(nil, "accessToken.request.token", nil) |
| 132 | + if token == nil || token.AccessToken == "" { |
| 133 | + panic(fmt.Sprintf("Request access_token fail: %v", res)) |
| 134 | + return nil |
| 135 | + } |
| 136 | + |
| 137 | + return token |
| 138 | +} |
| 139 | + |
| 140 | +func (accessToken *AccessToken) ApplyToRequest(request *http.Request, requestOptions *object.HashMap) *http.Request { |
| 141 | + |
| 142 | + // query Access Token map |
| 143 | + mapToken := accessToken.getQuery() |
| 144 | + q := request.URL.Query() |
| 145 | + for key, value := range *mapToken { |
| 146 | + q.Set(key, value) |
| 147 | + } |
| 148 | + request.URL.RawQuery = q.Encode() |
| 149 | + |
| 150 | + return request |
| 151 | +} |
| 152 | + |
| 153 | +func (accessToken *AccessToken) sendRequest(credential *object.StringMap) httpContract.ResponseContract { |
| 154 | + |
| 155 | + key := "json" |
| 156 | + if accessToken.RequestMethod == "GET" { |
| 157 | + key = "query" |
| 158 | + } |
| 159 | + options := &object.HashMap{ |
| 160 | + key: credential, |
| 161 | + } |
| 162 | + |
| 163 | + res := &response2.ResponseGetToken{} |
| 164 | + |
| 165 | + accessToken.SetHttpClient(accessToken.GetHttpClient()).PerformRequest( |
| 166 | + accessToken.getEndpoint(), |
| 167 | + accessToken.RequestMethod, |
| 168 | + options, |
| 169 | + res, |
| 170 | + ) |
| 171 | + return res |
| 172 | +} |
| 173 | + |
| 174 | +func (accessToken *AccessToken) getCacheKey() string { |
| 175 | + data, _ := json.Marshal(accessToken.GetCredentials()) |
| 176 | + buffer := md5.Sum(data) |
| 177 | + |
| 178 | + return accessToken.CachePrefix + string(buffer[:]) |
| 179 | +} |
| 180 | + |
| 181 | +func (accessToken *AccessToken) getQuery() *object.StringMap { |
| 182 | + // set the current token key |
| 183 | + var key string |
| 184 | + if accessToken.QueryName != "" { |
| 185 | + key = accessToken.QueryName |
| 186 | + } else { |
| 187 | + key = accessToken.TokenKey |
| 188 | + } |
| 189 | + |
| 190 | + // get token string map |
| 191 | + resToken := accessToken.GetToken(false) |
| 192 | + arrayReturn := &object.StringMap{ |
| 193 | + key: resToken.AccessToken, |
| 194 | + } |
| 195 | + |
| 196 | + return arrayReturn |
| 197 | + |
| 198 | +} |
| 199 | + |
| 200 | +func (accessToken *AccessToken) getEndpoint() string { |
| 201 | + defer (&exception.Exception{}).HandleException(nil, "accessToken.get.endpoint", accessToken) |
| 202 | + if accessToken.EndpointToGetToken == "" { |
| 203 | + panic("No endpoint for access token request.") |
| 204 | + return "" |
| 205 | + } |
| 206 | + |
| 207 | + return accessToken.EndpointToGetToken |
| 208 | +} |
| 209 | + |
| 210 | +func (accessToken *AccessToken) getTokenKey() string { |
| 211 | + return accessToken.TokenKey |
| 212 | +} |
0 commit comments