package dingdingapi import ( "bytes" "crypto/hmac" "crypto/sha256" "net/http" "strings" "sync" "time" "git.rosy.net.cn/baseapi/platformapi" "git.rosy.net.cn/baseapi/utils" ) const ( prodURL = "https://oapi.dingtalk.com" ) const ( getTokenAction = "gettoken" snsGetTokenAction = "sns/gettoken" ) const ( ResponseCodeSuccess = 0 ) type API struct { token string appID string secret string client *http.Client config *platformapi.APIConfig locker sync.RWMutex } func New(appID, secret string, config ...*platformapi.APIConfig) *API { curConfig := platformapi.DefAPIConfig if len(config) > 0 { curConfig = *config[0] } return &API{ appID: appID, secret: secret, client: &http.Client{Timeout: curConfig.ClientTimeout}, config: &curConfig, } } func (a *API) GetAppID() string { return a.appID } func (a *API) GetSecret() string { return a.secret } func isSNSAction(action string) bool { return strings.Index(action, "sns/") == 0 } func (a *API) SetToken(newToken string) bool { curToken := a.GetToken() if curToken != newToken { a.locker.Lock() defer a.locker.Unlock() a.token = newToken return true } return false } func (a *API) GetToken() string { a.locker.RLock() defer a.locker.RUnlock() return a.token } func (a *API) RetrieveToken() (token string, err error) { result, err := a.AccessAPI(getTokenAction, nil, nil) if err != nil { return "", err } token = utils.Interface2String(result["access_token"]) a.SetToken(token) return token, nil } func (a *API) signParams(timestamp int64) string { mac := hmac.New(sha256.New, []byte(a.GetSecret())) mac.Write([]byte(utils.Int64ToStr(timestamp))) return string(mac.Sum(nil)) } func (a *API) AccessAPI(action string, params map[string]interface{}, bodyMap map[string]interface{}) (retVal map[string]interface{}, err error) { params2 := make(map[string]interface{}) for k, v := range params { params2[k] = v } if action == getTokenAction { params2["appkey"] = a.GetAppID() params2["appsecret"] = a.GetSecret() } else if action == snsGetTokenAction { params2["appid"] = a.GetAppID() params2["appsecret"] = a.GetSecret() } else if !isSNSAction(action) { accessToken := a.GetToken() if accessToken == "" { panic("token is empty!") } params2["access_token"] = accessToken } else { params2["appkey"] = a.GetAppID() timestamp := time.Now().Unix() params2["timestamp"] = timestamp params2["signature"] = a.signParams(timestamp) } fullURL := utils.GenerateGetURL(prodURL, action, params2) // baseapi.SugarLogger.Debug(fullURL) err = platformapi.AccessPlatformAPIWithRetry(a.client, func() *http.Request { var request *http.Request if bodyMap == nil { request, _ = http.NewRequest(http.MethodGet, fullURL, nil) } else { request, _ = http.NewRequest(http.MethodPost, fullURL, bytes.NewReader(utils.MustMarshal(bodyMap))) } return request }, a.config, func(jsonResult1 map[string]interface{}) (result string, err error) { errCode := int(utils.MustInterface2Int64(jsonResult1["errcode"])) if errCode == ResponseCodeSuccess { retVal = jsonResult1 return platformapi.ErrLevelSuccess, nil } newErr := utils.NewErrorIntCode(utils.Interface2String(jsonResult1["errmsg"]), errCode) return platformapi.ErrLevelCodeIsNotOK, newErr }) return retVal, err }