thread-master/old/backend/internal/model/threads_account/usecase/token_refresh.go

84 lines
2.5 KiB
Go
Raw Normal View History

package usecase
import (
"context"
"strings"
"time"
"haixun-backend/internal/library/clock"
app "haixun-backend/internal/library/errors"
"haixun-backend/internal/library/errors/code"
libthreads "haixun-backend/internal/library/threadsapi"
domusecase "haixun-backend/internal/model/threads_account/domain/usecase"
)
const defaultTokenRefreshLeadTime = 7 * 24 * time.Hour
func (u *threadsAccountUseCase) ResolveAccountAPIAccessToken(
ctx context.Context,
tenantID, ownerUID, accountID string,
) (string, error) {
account, err := u.assertOwned(ctx, tenantID, ownerUID, accountID)
if err != nil {
return "", err
}
secrets, err := u.secretsRepo.FindByAccountID(ctx, account.ID)
if err != nil {
return "", err
}
if secrets == nil || !isValidAPIToken(secrets) {
return "", app.For(code.ThreadsAccount).InputMissingRequired("此帳號尚未完成 Threads API 連線或 token 已過期")
}
return strings.TrimSpace(secrets.APIAccessToken), nil
}
func (u *threadsAccountUseCase) RefreshAccountAPIAccessToken(
ctx context.Context,
tenantID, ownerUID, accountID string,
) (*domusecase.SecretsData, error) {
token, err := u.ResolveAccountAPIAccessToken(ctx, tenantID, ownerUID, accountID)
if err != nil {
return nil, err
}
result, err := libthreads.RefreshAccessToken(ctx, token)
if err != nil {
return nil, app.For(code.ThreadsAccount).SvcThirdParty("Threads token refresh 失敗").WithCause(err)
}
expiresAt := int64(0)
if result.ExpiresIn > 0 {
expiresAt = libthreads.NsFromNow(result.ExpiresIn)
}
return u.SaveAPIAccessToken(ctx, accountID, result.AccessToken, expiresAt)
}
func (u *threadsAccountUseCase) ListTokenRefreshCandidates(
ctx context.Context,
leadTime time.Duration,
) ([]domusecase.TokenRefreshCandidate, error) {
if leadTime <= 0 {
leadTime = defaultTokenRefreshLeadTime
}
deadline := clock.NowUnixNano() + leadTime.Nanoseconds()
secretsList, err := u.secretsRepo.ListAPIAccessTokensExpiringBefore(ctx, deadline)
if err != nil {
return nil, err
}
out := make([]domusecase.TokenRefreshCandidate, 0, len(secretsList))
for _, secrets := range secretsList {
if secrets == nil || strings.TrimSpace(secrets.APIAccessToken) == "" {
continue
}
account, err := u.repo.FindByIDGlobal(ctx, secrets.AccountID)
if err != nil || account == nil {
continue
}
out = append(out, domusecase.TokenRefreshCandidate{
AccountID: account.ID,
TenantID: account.TenantID,
OwnerUID: account.OwnerUID,
ExpiresAt: secrets.APITokenExpiresAt,
})
}
return out, nil
}