Skip to content

Commit 6cbdf6c

Browse files
chenxicccclaude
andcommitted
简化分享状态同步:移除增量接口,改用 WebSocket 广播实时推送
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4cd6dc2 commit 6cbdf6c

8 files changed

Lines changed: 14 additions & 154 deletions

File tree

internal/app/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package app
55
// Version information variables, injected during build
66
// 版本信息变量,由构建时注入
77
var (
8-
Version string = "2.11.2"
8+
Version string = "2.11.3"
99
GitTag string = "2000.01.01.release"
1010
BuildTime string = "2000-01-01T00:00:00+0800"
1111
)

internal/dao/user_share_repository.go

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -238,26 +238,4 @@ func (r *userShareRepository) ListActiveNoteResIDs(ctx context.Context, uid int6
238238
return ids, nil
239239
}
240240

241-
// ListChangedNoteResIDs 返回 updated_at > since 的 note 分享记录,按状态分组
242-
// ListChangedNoteResIDs returns note share res_ids changed after since, grouped by status
243-
func (r *userShareRepository) ListChangedNoteResIDs(ctx context.Context, uid int64, since time.Time) ([]int64, []int64, error) {
244-
us := r.userShare(uid).UserShare
245-
ms, err := us.WithContext(ctx).
246-
Where(us.UID.Eq(uid), us.ResType.Eq("note"), us.UpdatedAt.Gt(timex.Time(since))).
247-
Find()
248-
if err != nil {
249-
return nil, nil, err
250-
}
251-
var active, revoked []int64
252-
for _, m := range ms {
253-
switch m.Status {
254-
case domain.UserShareStatusActive:
255-
active = append(active, m.ResID)
256-
case domain.UserShareStatusRevoked:
257-
revoked = append(revoked, m.ResID)
258-
}
259-
}
260-
return active, revoked, nil
261-
}
262-
263241
var _ domain.UserShareRepository = (*userShareRepository)(nil)

internal/domain/domain_user_share.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,4 @@ type UserShareRepository interface {
5151
// ListActiveNoteResIDs returns note res_ids for all active shares of a user
5252
// ListActiveNoteResIDs 返回该用户所有有效分享中 res_type='note' 的 res_id 列表
5353
ListActiveNoteResIDs(ctx context.Context, uid int64) ([]int64, error)
54-
// ListChangedNoteResIDs returns res_ids of note shares whose status changed after since,
55-
// split into active (added) and revoked (removed) slices.
56-
// ListChangedNoteResIDs 返回 updated_at > since 的 note 分享记录的 res_id,
57-
// 按状态分为 active(新增)和 revoked(取消)两组。
58-
ListChangedNoteResIDs(ctx context.Context, uid int64, since time.Time) (active []int64, revoked []int64, err error)
5954
}

internal/dto/share_dto.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -104,19 +104,3 @@ type ShareListItem struct {
104104
type ShareListResponse struct {
105105
Items []*ShareListItem `json:"items"` // Share list // 分享列表
106106
}
107-
108-
// ShareChangesRequest 获取分享变更请求
109-
// ShareChangesRequest request parameters for fetching share changes
110-
type ShareChangesRequest struct {
111-
Vault string `json:"vault" form:"vault" binding:"required"` // Vault name // 保险库名称
112-
Since int64 `json:"since" form:"since"` // Unix timestamp (ms); 0 means full refresh required // Unix 毫秒时间戳;0 表示需要全量拉取
113-
}
114-
115-
// ShareChangesData 分享路径变更响应数据
116-
// ShareChangesData response payload for share path changes
117-
type ShareChangesData struct {
118-
Added []string `json:"added"` // Newly shared note paths since Since // Since 之后新增的分享路径
119-
Removed []string `json:"removed"` // Cancelled share paths since Since // Since 之后取消的分享路径
120-
LastTime int64 `json:"lastTime"` // Timestamp to use as Since in next request // 下次请求使用的时间戳
121-
FullRefreshRequired bool `json:"fullRefreshRequired"` // Client must call /share-paths for full refresh // 客户端需调用 /share-paths 做全量刷新
122-
}

internal/dto/ws_dto.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ const (
175175
// SettingSyncClear sync clear all settings
176176
// SettingSyncClear 同步清理所有设置
177177
SettingSyncClear WebSocketSendAction = "SettingSyncClear"
178+
179+
// ---------------- Share ----------------
180+
181+
// ShareSyncRefresh notify clients to refresh share state
182+
// ShareSyncRefresh 通知客户端刷新分享状态
183+
ShareSyncRefresh WebSocketSendAction = "ShareSyncRefresh"
178184
)
179185

180186
// WSQueuedMessage represents a message item to be sent

internal/routers/api_router/handler_share.go

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ type ShareHandler struct {
2323
*Handler
2424
}
2525

26-
// NewShareHandler creates ShareHandler instance
27-
// NewShareHandler 创建 ShareHandler 实例
28-
func NewShareHandler(app *app.App) *ShareHandler {
26+
// NewShareHandler creates ShareHandler instance with WebSocket server
27+
// NewShareHandler 创建带 WebSocket 服务的 ShareHandler 实例
28+
func NewShareHandler(app *app.App, wss *pkgapp.WebsocketServer) *ShareHandler {
2929
return &ShareHandler{
30-
Handler: &Handler{App: app},
30+
Handler: NewHandlerWithWSS(app, wss),
3131
}
3232
}
3333

@@ -70,9 +70,8 @@ func (h *ShareHandler) Create(c *gin.Context) {
7070
}
7171

7272
response.ToResponse(code.Success.WithData(shareRes))
73+
h.WSS.BroadcastToUser(uid, code.Success, dto.ShareSyncRefresh)
7374
}
74-
75-
// GetShared retrieves shared note details
7675
// @Summary Get shared note details
7776
// @Description Get specific note content (restricted read-only access) via share token
7877
// @Tags Share
@@ -283,6 +282,7 @@ func (h *ShareHandler) Cancel(c *gin.Context) {
283282
}
284283

285284
response.ToResponse(code.Success)
285+
h.WSS.BroadcastToUser(uid, code.Success, dto.ShareSyncRefresh)
286286
}
287287

288288
// UpdatePassword updates share password
@@ -439,39 +439,6 @@ func (h *ShareHandler) NoteSharePaths(c *gin.Context) {
439439
response.ToResponse(code.Success.WithData(paths))
440440
}
441441

442-
// NoteShareChanges returns share path changes since a given timestamp for a vault
443-
// NoteShareChanges 返回指定 vault 下 since 时间戳之后的分享路径变更,供客户端增量同步
444-
// @Summary Get share path changes since timestamp
445-
// @Tags Share
446-
// @Security UserAuthToken
447-
// @Param token header string true "Auth Token"
448-
// @Param params query dto.ShareChangesRequest true "Query Parameters"
449-
// @Success 200 {object} pkgapp.Res{data=dto.ShareChangesData} "Success"
450-
// @Router /api/notes/share-changes [get]
451-
func (h *ShareHandler) NoteShareChanges(c *gin.Context) {
452-
response := pkgapp.NewResponse(c)
453-
params := &dto.ShareChangesRequest{}
454-
if valid, errs := pkgapp.BindAndValid(c, params); !valid {
455-
response.ToResponse(code.ErrorInvalidParams.WithDetails(errs.ErrorsToString()).WithData(errs.MapsToString()))
456-
return
457-
}
458-
459-
uid := pkgapp.GetUID(c)
460-
ctx := c.Request.Context()
461-
462-
data, err := h.App.ShareService.GetNoteShareChangesByVault(ctx, uid, params.Vault, params.Since)
463-
if err != nil {
464-
if cObj, ok := err.(*code.Code); ok {
465-
response.ToResponse(cObj)
466-
} else {
467-
response.ToResponse(code.Failed.WithDetails(err.Error()))
468-
}
469-
return
470-
}
471-
472-
response.ToResponse(code.Success.WithData(data))
473-
}
474-
475442
// logError records error log, including Trace ID
476443
// logError 记录错误日志,包含 Trace ID
477444
func (h *ShareHandler) logError(ctx context.Context, method string, err error) {

internal/routers/router.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func NewRouter(frontendFiles embed.FS, appContainer *app.App, uni *ut.UniversalT
162162
noteHistoryHandler := api_router.NewNoteHistoryHandler(appContainer, wss)
163163
versionHandler := api_router.NewVersionHandler(appContainer)
164164
adminControlHandler := api_router.NewAdminControlHandler(appContainer, wss)
165-
shareHandler := api_router.NewShareHandler(appContainer)
165+
shareHandler := api_router.NewShareHandler(appContainer, wss)
166166
storageHandler := api_router.NewStorageHandler(appContainer)
167167
backupHandler := api_router.NewBackupHandler(appContainer)
168168
gitSyncHandler := api_router.NewGitSyncHandler(appContainer)
@@ -241,7 +241,6 @@ func NewRouter(frontendFiles embed.FS, appContainer *app.App, uni *ut.UniversalT
241241
auth.GET("/notes", noteHandler.List)
242242
auth.DELETE("/note/recycle-clear", noteHandler.RecycleClear)
243243
auth.GET("/notes/share-paths", shareHandler.NoteSharePaths)
244-
auth.GET("/notes/share-changes", shareHandler.NoteShareChanges)
245244

246245
auth.GET("/folder", folderHandler.Get)
247246
auth.POST("/folder", folderHandler.Create)

internal/service/share_service.go

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,6 @@ type ShareService interface {
8484
// GetActiveNotePathsByVault 返回指定 vault 下所有有效分享的笔记路径列表
8585
GetActiveNotePathsByVault(ctx context.Context, uid int64, vaultName string) ([]string, error)
8686

87-
// GetNoteShareChangesByVault returns share path changes since sinceMs for a vault
88-
// GetNoteShareChangesByVault 返回指定 vault 下 sinceMs 之后的分享路径变更
89-
GetNoteShareChangesByVault(ctx context.Context, uid int64, vaultName string, sinceMs int64) (*dto.ShareChangesData, error)
90-
9187
// Shutdown shuts down the service and flushes remaining data
9288
// Shutdown 关闭服务并同步最后的数据
9389
Shutdown(ctx context.Context) error
@@ -693,71 +689,6 @@ func (s *shareService) GetActiveNotePathsByVault(ctx context.Context, uid int64,
693689
return paths, nil
694690
}
695691

696-
// GetNoteShareChangesByVault 返回指定 vault 下 sinceMs 之后的分享路径变更(两步查询,避免跨库 JOIN)
697-
// GetNoteShareChangesByVault returns note share path changes since sinceMs for a vault (two-step query, no cross-DB JOIN)
698-
func (s *shareService) GetNoteShareChangesByVault(ctx context.Context, uid int64, vaultName string, sinceMs int64) (*dto.ShareChangesData, error) {
699-
// since=0 表示客户端无本地缓存,需要全量刷新 / since=0 means client has no cache, require full refresh
700-
if sinceMs == 0 {
701-
return &dto.ShareChangesData{
702-
FullRefreshRequired: true,
703-
Added: []string{},
704-
Removed: []string{},
705-
LastTime: time.Now().UnixMilli(),
706-
}, nil
707-
}
708-
709-
vault, err := s.vaultRepo.GetByName(ctx, vaultName, uid)
710-
if err != nil || vault == nil {
711-
return nil, code.ErrorVaultNotFound
712-
}
713-
714-
since := time.UnixMilli(sinceMs)
715-
716-
// 步骤1:查询 user_shares 中变更的 note res_id(无跨库 JOIN)
717-
// Step 1: query changed note res_ids from user_shares (no cross-DB JOIN)
718-
activeIDs, revokedIDs, err := s.repo.ListChangedNoteResIDs(ctx, uid, since)
719-
if err != nil {
720-
return nil, err
721-
}
722-
723-
result := &dto.ShareChangesData{
724-
Added: []string{},
725-
Removed: []string{},
726-
LastTime: time.Now().UnixMilli(),
727-
}
728-
729-
// 步骤2:合并 ID 列表,一次批量查询 notes,按 vault 过滤后按来源分拆
730-
// Step 2: merge ID lists, single batch query for notes, filter by vault and split by source
731-
allIDs := make([]int64, 0, len(activeIDs)+len(revokedIDs))
732-
allIDs = append(allIDs, activeIDs...)
733-
allIDs = append(allIDs, revokedIDs...)
734-
735-
if len(allIDs) > 0 {
736-
activeSet := make(map[int64]struct{}, len(activeIDs))
737-
for _, id := range activeIDs {
738-
activeSet[id] = struct{}{}
739-
}
740-
741-
notes, err := s.noteRepo.ListByIDs(ctx, allIDs, uid)
742-
if err == nil {
743-
for _, n := range notes {
744-
if n.VaultID != vault.ID {
745-
continue
746-
}
747-
if _, ok := activeSet[n.ID]; ok {
748-
if n.Action != domain.NoteActionDelete {
749-
result.Added = append(result.Added, n.Path)
750-
}
751-
} else {
752-
result.Removed = append(result.Removed, n.Path)
753-
}
754-
}
755-
}
756-
}
757-
758-
return result, nil
759-
}
760-
761692
// GetSharedNote retrieves specific shared note details
762693
// GetSharedNote 获取分享的单条笔记详情
763694
func (s *shareService) GetSharedNote(ctx context.Context, shareToken string, noteID int64, password string) (*dto.NoteDTO, error) {

0 commit comments

Comments
 (0)