@@ -5,8 +5,10 @@ import (
55 "fmt"
66 "log/slog"
77 "strings"
8+ "time"
89
910 "github.com/google/uuid"
11+ "github.com/patrickmn/go-cache"
1012 "github.com/samber/do"
1113
1214 "github.com/chaitin/MonkeyCode/backend/config"
@@ -27,6 +29,7 @@ type GitIdentityUsecase struct {
2729 repo domain.GitIdentityRepo
2830 tokenProvider * TokenProvider
2931 logger * slog.Logger
32+ repoCache * cache.Cache
3033}
3134
3235// NewGitIdentityUsecase 创建 Git 身份认证用例
@@ -36,11 +39,12 @@ func NewGitIdentityUsecase(i *do.Injector) (domain.GitIdentityUsecase, error) {
3639 repo : do.MustInvoke [domain.GitIdentityRepo ](i ),
3740 tokenProvider : do.MustInvoke [* TokenProvider ](i ),
3841 logger : do.MustInvoke [* slog.Logger ](i ).With ("module" , "GitIdentityUsecase" ),
42+ repoCache : cache .New (1 * time .Hour , 10 * time .Minute ),
3943 }, nil
4044}
4145
4246// List 获取用户的 Git 身份认证列表
43- func (u * GitIdentityUsecase ) List (ctx context.Context , uid uuid.UUID ) ([]* domain.GitIdentity , error ) {
47+ func (u * GitIdentityUsecase ) List (ctx context.Context , uid uuid.UUID , flush bool ) ([]* domain.GitIdentity , error ) {
4448 identities , err := u .repo .List (ctx , uid )
4549 if err != nil {
4650 u .logger .ErrorContext (ctx , "failed to list git identities" , "error" , err , "user_id" , uid )
@@ -49,26 +53,38 @@ func (u *GitIdentityUsecase) List(ctx context.Context, uid uuid.UUID) ([]*domain
4953 return cvt .Iter (identities , func (_ int , identity * db.GitIdentity ) * domain.GitIdentity {
5054 tmp := cvt .From (identity , & domain.GitIdentity {})
5155 if client := u .gitClienter (identity ); client != nil {
52- token , err := u .tokenProvider .GetToken (ctx , identity .ID )
53- if err != nil {
54- u .logger .WarnContext (ctx , "failed to get token" , "error" , err , "platform" , identity .Platform , "identity_id" , identity .ID )
55- return tmp
56- }
57- repos , err := client .Repositories (ctx , & domain.RepositoryOptions {
58- Token : token ,
59- InstallID : identity .InstallationID ,
60- IsOAuth : identity .OauthRefreshToken != "" ,
61- })
62- if err != nil {
63- u .logger .WarnContext (ctx , "failed to get authorized repositories" , "error" , err , "platform" , identity .Platform , "identity_id" , identity .ID )
64- } else {
65- tmp .AuthorizedRepositories = repos
66- }
56+ tmp .AuthorizedRepositories = u .getReposWithCache (ctx , uid , identity , client , flush )
6757 }
6858 return tmp
6959 }), nil
7060}
7161
62+ // getReposWithCache 从缓存获取仓库列表,miss 或 flush 时调用远端
63+ func (u * GitIdentityUsecase ) getReposWithCache (ctx context.Context , uid uuid.UUID , identity * db.GitIdentity , client domain.GitClienter , flush bool ) []domain.AuthRepository {
64+ cacheKey := uid .String () + ":" + identity .ID .String ()
65+ if ! flush {
66+ if cached , ok := u .repoCache .Get (cacheKey ); ok {
67+ return cached .([]domain.AuthRepository )
68+ }
69+ }
70+ token , err := u .tokenProvider .GetToken (ctx , identity .ID )
71+ if err != nil {
72+ u .logger .WarnContext (ctx , "failed to get token" , "error" , err , "platform" , identity .Platform , "identity_id" , identity .ID )
73+ return nil
74+ }
75+ repos , err := client .Repositories (ctx , & domain.RepositoryOptions {
76+ Token : token ,
77+ InstallID : identity .InstallationID ,
78+ IsOAuth : identity .OauthRefreshToken != "" ,
79+ })
80+ if err != nil {
81+ u .logger .WarnContext (ctx , "failed to get authorized repositories" , "error" , err , "platform" , identity .Platform , "identity_id" , identity .ID )
82+ return nil
83+ }
84+ u .repoCache .Set (cacheKey , repos , cache .DefaultExpiration )
85+ return repos
86+ }
87+
7288func (u * GitIdentityUsecase ) gitClienter (identity * db.GitIdentity ) domain.GitClienter {
7389 switch identity .Platform {
7490 case consts .GitPlatformGithub :
@@ -85,7 +101,7 @@ func (u *GitIdentityUsecase) gitClienter(identity *db.GitIdentity) domain.GitCli
85101}
86102
87103// Get 获取单个 Git 身份认证(仅限当前用户)
88- func (u * GitIdentityUsecase ) Get (ctx context.Context , uid uuid.UUID , id uuid.UUID ) (* domain.GitIdentity , error ) {
104+ func (u * GitIdentityUsecase ) Get (ctx context.Context , uid uuid.UUID , id uuid.UUID , flush bool ) (* domain.GitIdentity , error ) {
89105 identity , err := u .repo .GetByUserID (ctx , uid , id )
90106 if err != nil {
91107 if db .IsNotFound (err ) {
@@ -97,21 +113,7 @@ func (u *GitIdentityUsecase) Get(ctx context.Context, uid uuid.UUID, id uuid.UUI
97113 gi := cvt .From (identity , & domain.GitIdentity {})
98114
99115 if client := u .gitClienter (identity ); client != nil {
100- token , err := u .tokenProvider .GetToken (ctx , identity .ID )
101- if err != nil {
102- u .logger .WarnContext (ctx , "failed to get token" , "error" , err , "platform" , identity .Platform , "identity_id" , id )
103- return gi , nil
104- }
105- repos , err := client .Repositories (ctx , & domain.RepositoryOptions {
106- Token : token ,
107- InstallID : identity .InstallationID ,
108- IsOAuth : identity .OauthRefreshToken != "" ,
109- })
110- if err != nil {
111- u .logger .WarnContext (ctx , "failed to get authorized repositories" , "error" , err , "platform" , identity .Platform , "identity_id" , id )
112- } else {
113- gi .AuthorizedRepositories = repos
114- }
116+ gi .AuthorizedRepositories = u .getReposWithCache (ctx , uid , identity , client , flush )
115117 }
116118
117119 return gi , nil
@@ -134,6 +136,7 @@ func (u *GitIdentityUsecase) Update(ctx context.Context, uid uuid.UUID, req *dom
134136 return err
135137 }
136138 u .tokenProvider .ClearCache (req .ID )
139+ u .repoCache .Delete (uid .String () + ":" + req .ID .String ())
137140 return nil
138141}
139142
@@ -164,6 +167,7 @@ func (u *GitIdentityUsecase) Delete(ctx context.Context, uid uuid.UUID, id uuid.
164167 return err
165168 }
166169 u .tokenProvider .ClearCache (id )
170+ u .repoCache .Delete (uid .String () + ":" + id .String ())
167171 return nil
168172}
169173
0 commit comments