Skip to content

Commit 00626b3

Browse files
committed
feat: 获取仓库列表处加了缓存逻辑
1 parent 79486b3 commit 00626b3

3 files changed

Lines changed: 55 additions & 43 deletions

File tree

backend/biz/git/handler/v1/identity.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func NewGitIdentityHandler(i *do.Injector) (*GitIdentityHandler, error) {
3131

3232
g := w.Group("/api/v1/users/git-identities")
3333
g.Use(auth.Auth(), targetActive.TargetActive())
34-
g.GET("", web.BaseHandler(h.List))
34+
g.GET("", web.BindHandler(h.List))
3535
g.GET("/:id", web.BindHandler(h.Get))
3636
g.POST("", web.BindHandler(h.Add))
3737
g.PUT("/:id", web.BindHandler(h.Update))
@@ -49,12 +49,13 @@ func NewGitIdentityHandler(i *do.Injector) (*GitIdentityHandler, error) {
4949
// @Accept json
5050
// @Produce json
5151
// @Security MonkeyCodeAIAuth
52-
// @Success 200 {object} web.Resp{data=[]domain.GitIdentity} "成功"
53-
// @Failure 500 {object} web.Resp "服务器内部错误"
52+
// @Param flush query bool false "是否刷新缓存"
53+
// @Success 200 {object} web.Resp{data=[]domain.GitIdentity} "成功"
54+
// @Failure 500 {object} web.Resp "服务器内部错误"
5455
// @Router /api/v1/users/git-identities [get]
55-
func (h *GitIdentityHandler) List(c *web.Context) error {
56+
func (h *GitIdentityHandler) List(c *web.Context, req domain.ListGitIdentityReq) error {
5657
user := middleware.GetUser(c)
57-
list, err := h.usecase.List(c.Request().Context(), user.ID)
58+
list, err := h.usecase.List(c.Request().Context(), user.ID, req.Flush)
5859
if err != nil {
5960
return errcode.ErrDatabaseQuery.Wrap(err)
6061
}
@@ -69,15 +70,16 @@ func (h *GitIdentityHandler) List(c *web.Context) error {
6970
// @Accept json
7071
// @Produce json
7172
// @Security MonkeyCodeAIAuth
72-
// @Param id path string true "Git 身份认证ID"
73-
// @Success 200 {object} web.Resp{data=domain.GitIdentity} "成功"
73+
// @Param id path string true "Git 身份认证ID"
74+
// @Param flush query bool false "是否刷新缓存"
75+
// @Success 200 {object} web.Resp{data=domain.GitIdentity} "成功"
7476
// @Failure 400 {object} web.Resp "请求参数错误"
7577
// @Failure 404 {object} web.Resp "资源不存在"
7678
// @Failure 500 {object} web.Resp "服务器内部错误"
7779
// @Router /api/v1/users/git-identities/{id} [get]
7880
func (h *GitIdentityHandler) Get(c *web.Context, req domain.GetGitIdentityReq) error {
7981
user := middleware.GetUser(c)
80-
identity, err := h.usecase.Get(c.Request().Context(), user.ID, req.ID)
82+
identity, err := h.usecase.Get(c.Request().Context(), user.ID, req.ID, req.Flush)
8183
if err != nil {
8284
return err
8385
}

backend/biz/git/usecase/identity.go

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
7288
func (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

backend/domain/gitidentity.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import (
1212

1313
// GitIdentityUsecase Git 身份认证业务逻辑接口
1414
type GitIdentityUsecase interface {
15-
List(ctx context.Context, uid uuid.UUID) ([]*GitIdentity, error)
16-
Get(ctx context.Context, uid uuid.UUID, id uuid.UUID) (*GitIdentity, error)
15+
List(ctx context.Context, uid uuid.UUID, flush bool) ([]*GitIdentity, error)
16+
Get(ctx context.Context, uid uuid.UUID, id uuid.UUID, flush bool) (*GitIdentity, error)
1717
Add(ctx context.Context, uid uuid.UUID, req *AddGitIdentityReq) (*GitIdentity, error)
1818
Update(ctx context.Context, uid uuid.UUID, req *UpdateGitIdentityReq) error
1919
Delete(ctx context.Context, uid uuid.UUID, id uuid.UUID) error
@@ -92,9 +92,15 @@ type UpdateGitIdentityReq struct {
9292
OAuthExpiresAt *time.Time `json:"-"` // 内部使用,OAuth 过期时间
9393
}
9494

95+
// ListGitIdentityReq 获取 Git 身份认证列表请求
96+
type ListGitIdentityReq struct {
97+
Flush bool `query:"flush"`
98+
}
99+
95100
// GetGitIdentityReq 获取 Git 身份认证详情请求
96101
type GetGitIdentityReq struct {
97-
ID uuid.UUID `param:"id" validate:"required"`
102+
ID uuid.UUID `param:"id" validate:"required"`
103+
Flush bool `query:"flush"`
98104
}
99105

100106
// DeleteGitIdentityReq 删除 Git 身份认证请求

0 commit comments

Comments
 (0)