Skip to content

Commit 84f22aa

Browse files
chenxicccclaude
andcommitted
fix(ws): add NoteDeleteAck and FileDeleteAck to prevent hash orphan on disconnect
Previously, noteDelete/fileDelete removed hash from hashManager in the on-send callback (when message entered TCP buffer), before server confirmation. If TCP dropped between send and server receipt, the hash was permanently gone — on reconnect, the path skipped delNotes and the server file became a permanent orphan. Introduce NoteDeleteAck/FileDeleteAck responses (symmetric with existing NoteModifyAck/NoteRenameAck pattern): server sends Ack with lastTime and path after processing the delete. Client defers hash removal to Ack receipt; on reconnect, unconfirmed paths remain in hashManager and flow into delNotes naturally. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 29154ce commit 84f22aa

5 files changed

Lines changed: 28 additions & 2 deletions

File tree

internal/dto/file_dto_ws.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ type FileUploadAckMessage struct {
7575
Path string `json:"path"` // File path // 文件路径
7676
}
7777

78+
// FileDeleteAckMessage file delete operation ACK, sent back to sender after server processes FileDelete
79+
// FileDeleteAckMessage 文件删除操作 ACK,服务端处理完 FileDelete 后回发给发送方
80+
type FileDeleteAckMessage struct {
81+
LastTime int64 `json:"lastTime"` // Server write timestamp // 服务端写入时间戳
82+
Path string `json:"path"` // File path // 文件路径
83+
}
84+
7885
// FileSyncRenameMessage message structure for file rename during sync
7986
// FileSyncRenameMessage 同步过程中文件重命名的消息结构
8087
type FileSyncRenameMessage struct {

internal/dto/note_dto_ws.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,10 @@ type NoteModifyAckMessage struct {
7575
type NoteRenameAckMessage struct {
7676
LastTime int64 `json:"lastTime"` // Server write timestamp // 服务端写入时间戳
7777
}
78+
79+
// NoteDeleteAckMessage note delete operation ACK, sent back to sender after server processes NoteDelete
80+
// NoteDeleteAckMessage 笔记删除操作 ACK,服务端处理完 NoteDelete 后回发给发送方
81+
type NoteDeleteAckMessage struct {
82+
LastTime int64 `json:"lastTime"` // Server write timestamp // 服务端写入时间戳
83+
Path string `json:"path"` // Note path // 笔记路径
84+
}

internal/dto/ws_dto.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ const (
136136
// NoteRenameAck note rename operation ack
137137
// NoteRenameAck 笔记重命名操作 ack
138138
NoteRenameAck WebSocketSendAction = "NoteRenameAck"
139+
// NoteDeleteAck note delete operation ack
140+
// NoteDeleteAck 笔记删除操作 ack
141+
NoteDeleteAck WebSocketSendAction = "NoteDeleteAck"
139142

140143
// ---------------- File ----------------
141144

@@ -166,6 +169,9 @@ const (
166169
// FileUploadAck file upload complete ack
167170
// FileUploadAck 文件上传完成 ack
168171
FileUploadAck WebSocketSendAction = "FileUploadAck"
172+
// FileDeleteAck file delete operation ack
173+
// FileDeleteAck 文件删除操作 ack
174+
FileDeleteAck WebSocketSendAction = "FileDeleteAck"
169175

170176
// ---------------- Setting ----------------
171177

internal/routers/websocket_router/ws_file.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,10 @@ func (h *FileWSHandler) FileDelete(c *pkgapp.WebsocketClient, msg *pkgapp.WebSoc
412412
return
413413
}
414414

415-
c.ToResponse(code.Success)
415+
c.ToResponse(code.Success.WithData(dto.FileDeleteAckMessage{
416+
LastTime: fileSvc.UpdatedTimestamp,
417+
Path: fileSvc.Path,
418+
}).WithVault(params.Vault), string(dto.FileDeleteAck))
416419

417420
// Broadcast file deletion message
418421
// 广播文件删除消息

internal/routers/websocket_router/ws_note.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,10 @@ func (h *NoteWSHandler) NoteDelete(c *pkgapp.WebsocketClient, msg *pkgapp.WebSoc
524524
return
525525
}
526526

527-
c.ToResponse(code.Success)
527+
c.ToResponse(code.Success.WithData(dto.NoteDeleteAckMessage{
528+
LastTime: note.UpdatedTimestamp,
529+
Path: note.Path,
530+
}).WithVault(params.Vault), string(dto.NoteDeleteAck))
528531
c.BroadcastResponse(code.Success.WithData(
529532
dto.NoteSyncDeleteMessage{
530533
Path: note.Path,

0 commit comments

Comments
 (0)