package dingtalk import ( "ai_scheduler/internal/config" "ai_scheduler/internal/data/constants" "ai_scheduler/internal/data/impl" "ai_scheduler/internal/data/model" "ai_scheduler/internal/entitys" "ai_scheduler/internal/pkg" "ai_scheduler/internal/pkg/l_request" "ai_scheduler/utils" "context" "encoding/json" "errors" "net/http" "time" "github.com/gofiber/fiber/v2/log" "github.com/redis/go-redis/v9" "xorm.io/builder" ) type Auth struct { redis *redis.Client cfg *config.Config botConfigImpl *impl.BotConfigImpl } func NewAuth(cfg *config.Config, redis *utils.Rdb, botConfigImpl *impl.BotConfigImpl) *Auth { return &Auth{ redis: redis.Rdb, cfg: cfg, botConfigImpl: botConfigImpl, } } func (a *Auth) GetAccessToken(ctx context.Context, clientId string, clientSecret string) (authInfo *AuthInfo, err error) { if clientId == "" { return nil, errors.New("clientId is empty") } accessToken := a.redis.Get(ctx, a.getKey(clientId)).Val() var expire time.Duration if accessToken == "" { dingTalkAuthRes, _err := a.getNewAccessToken(ctx, clientId, clientSecret) if _err != nil { return nil, _err } expire = time.Duration(dingTalkAuthRes.ExpireIn-3600) * time.Second err = a.redis.SetEx(ctx, a.getKey(clientId), dingTalkAuthRes.AccessToken, expire).Err() if err != nil { return } accessToken = dingTalkAuthRes.AccessToken } else { expire, _ = a.redis.TTL(ctx, a.getKey(clientId)).Result() } return &AuthInfo{ ClientId: clientId, ClientSecret: clientSecret, AccessToken: accessToken, Expire: expire, }, nil } func (a *Auth) getKey(clientId string) string { return a.cfg.Redis.Key + ":" + constants.DingTalkAuthBaseKeyPrefix + ":" + clientId } func (a *Auth) getKeyBot(botCode string) string { return a.cfg.Redis.Key + ":" + constants.DingTalkAuthBaseKeyBotPrefix + ":" + botCode } func (a *Auth) getNewAccessToken(ctx context.Context, clientId string, clientSecret string) (auth DingTalkAuthIRes, err error) { if clientId == "" || clientSecret == "" { err = errors.New("clientId or clientSecret is empty") return } req := l_request.Request{ Method: http.MethodPost, Url: "https://api.dingtalk.com/v1.0/oauth2/accessToken", Json: map[string]interface{}{ "appKey": clientId, "appSecret": clientSecret, }, } res, err := req.Send() if err != nil { return } err = json.Unmarshal(res.Content, &auth) return } func (a *Auth) GetTokenFromBotOption(ctx context.Context, botOption ...BotOption) (token *AuthInfo, err error) { botInfo := &Bot{} for _, option := range botOption { option(botInfo) } if botInfo.Id == 0 && botInfo.BotConfig == nil && botInfo.BotCode == "" { err = errors.New("botInfo is nil") return } if botInfo.BotConfig == nil { err = a.GetBotConfigFromModel(botInfo) if err != nil { return } } authInfo := a.redis.Get(ctx, a.getKeyBot(botInfo.BotConfig.RobotCode)).Val() if authInfo == "" { var botConfig entitys.DingTalkBot err = json.Unmarshal([]byte(botInfo.BotConfig.BotConfig), &botConfig) if err != nil { log.Infof("初始化“%s”失败:%s", botInfo.BotConfig.BotName, err.Error()) return } token, err = a.GetAccessToken(ctx, botConfig.ClientId, botConfig.ClientSecret) if err != nil { return } err = a.redis.SetEx(ctx, a.getKeyBot(botInfo.BotConfig.RobotCode), pkg.JsonStringIgonErr(token), token.Expire).Err() if err != nil { return } } else { var tokenData AuthInfo err = json.Unmarshal([]byte(authInfo), &tokenData) token = &tokenData } return } func (a *Auth) GetBotConfigFromModel(botInfo *Bot) (err error) { var ( botConfigDo model.AiBotConfig ) cond := builder.NewCond() if botInfo.Id > 0 { cond = cond.And(builder.Eq{"bot_id": botInfo.Id}) } if botInfo.BotCode != "" { cond = cond.And(builder.Eq{"robot_code": botInfo.BotCode}) } err = a.botConfigImpl.GetOneBySearchToStrut(&cond, &botConfigDo) if err != nil { return } if botConfigDo.BotID == 0 { err = errors.New("未找到机器人服务配置") return } botInfo.BotConfig = &botConfigDo return nil }