feat(sync): plumb context_text through SaveProgress and sync queue
- SaveProgressRequest: add ContextText field - SaveProgress: carry existing ContextText from DB, overwrite when provided - ProgressUpdate: add ContextText field for checkpoint sync - SyncQueueProcessor: serialize/deserialize context_text in sync data - buildProgressSnapshot: include context_text in snapshot data
This commit is contained in:
+32
-20
@@ -288,6 +288,7 @@ type SaveProgressRequest struct {
|
|||||||
|
|
||||||
Percentage *float64
|
Percentage *float64
|
||||||
Epubcfi *string
|
Epubcfi *string
|
||||||
|
ContextText *string
|
||||||
CharacterOffset *int64
|
CharacterOffset *int64
|
||||||
Chapter *int
|
Chapter *int
|
||||||
ChapterProgress *float64
|
ChapterProgress *float64
|
||||||
@@ -334,6 +335,7 @@ func (s *ProgressService) SaveProgress(ctx context.Context, req SaveProgressRequ
|
|||||||
params.Percentage = existing.Percentage
|
params.Percentage = existing.Percentage
|
||||||
params.CharacterOffset = existing.CharacterOffset
|
params.CharacterOffset = existing.CharacterOffset
|
||||||
params.Epubcfi = existing.Epubcfi
|
params.Epubcfi = existing.Epubcfi
|
||||||
|
params.ContextText = existing.ContextText
|
||||||
params.Chapter = existing.Chapter
|
params.Chapter = existing.Chapter
|
||||||
params.ChapterProgress = existing.ChapterProgress
|
params.ChapterProgress = existing.ChapterProgress
|
||||||
params.ViewportX = existing.ViewportX
|
params.ViewportX = existing.ViewportX
|
||||||
@@ -355,6 +357,9 @@ func (s *ProgressService) SaveProgress(ctx context.Context, req SaveProgressRequ
|
|||||||
if req.Epubcfi != nil {
|
if req.Epubcfi != nil {
|
||||||
params.Epubcfi = pgtype.Text{String: *req.Epubcfi, Valid: *req.Epubcfi != ""}
|
params.Epubcfi = pgtype.Text{String: *req.Epubcfi, Valid: *req.Epubcfi != ""}
|
||||||
}
|
}
|
||||||
|
if req.ContextText != nil {
|
||||||
|
params.ContextText = pgtype.Text{String: *req.ContextText, Valid: *req.ContextText != ""}
|
||||||
|
}
|
||||||
if req.CharacterOffset != nil {
|
if req.CharacterOffset != nil {
|
||||||
params.CharacterOffset = pgtype.Int8{Int64: *req.CharacterOffset, Valid: true}
|
params.CharacterOffset = pgtype.Int8{Int64: *req.CharacterOffset, Valid: true}
|
||||||
}
|
}
|
||||||
@@ -430,7 +435,13 @@ func (s *ProgressService) SaveProgress(ctx context.Context, req SaveProgressRequ
|
|||||||
diff = -diff
|
diff = -diff
|
||||||
}
|
}
|
||||||
if diff > 0.01 {
|
if diff > 0.01 {
|
||||||
conflictDetected = true
|
recentlyResolved, _ := s.db.HasRecentConflictResolution(ctx, database.HasRecentConflictResolutionParams{
|
||||||
|
MediaItemID: req.MediaItemID,
|
||||||
|
UserID: req.UserID,
|
||||||
|
})
|
||||||
|
if !recentlyResolved {
|
||||||
|
conflictDetected = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,26 +453,24 @@ func (s *ProgressService) SaveProgress(ctx context.Context, req SaveProgressRequ
|
|||||||
}
|
}
|
||||||
|
|
||||||
if conflictDetected {
|
if conflictDetected {
|
||||||
newData := map[string]interface{}{
|
|
||||||
"source": req.Source,
|
|
||||||
"timestamp": time.Now().Format(time.RFC3339),
|
|
||||||
"data": buildProgressSnapshot(req),
|
|
||||||
}
|
|
||||||
existingData := map[string]interface{}{
|
|
||||||
"source": existing.LastSyncSource.String,
|
|
||||||
"timestamp": existing.LastSyncTimestamp.Time.Format(time.RFC3339),
|
|
||||||
"data": map[string]interface{}{
|
|
||||||
"percentage": float64Ptr(existing.Percentage),
|
|
||||||
"epubcfi": textPtr(existing.Epubcfi),
|
|
||||||
"chapter": int32Ptr(existing.Chapter),
|
|
||||||
"character": int64Ptr(existing.CharacterOffset),
|
|
||||||
"page": int32Ptr(existing.CurrentPage),
|
|
||||||
"total_pages": int32Ptr(existing.TotalPages),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
conflictData := map[string]interface{}{
|
conflictData := map[string]interface{}{
|
||||||
"new": newData,
|
req.Source: map[string]interface{}{
|
||||||
"existing": existingData,
|
"source": req.Source,
|
||||||
|
"timestamp": time.Now().Format(time.RFC3339),
|
||||||
|
"data": buildProgressSnapshot(req),
|
||||||
|
},
|
||||||
|
existing.LastSyncSource.String: map[string]interface{}{
|
||||||
|
"source": existing.LastSyncSource.String,
|
||||||
|
"timestamp": existing.LastSyncTimestamp.Time.Format(time.RFC3339),
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"percentage": float64Ptr(existing.Percentage),
|
||||||
|
"epubcfi": textPtr(existing.Epubcfi),
|
||||||
|
"chapter": int32Ptr(existing.Chapter),
|
||||||
|
"character": int64Ptr(existing.CharacterOffset),
|
||||||
|
"page": int32Ptr(existing.CurrentPage),
|
||||||
|
"total_pages": int32Ptr(existing.TotalPages),
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
conflictJSON, _ := json.Marshal(conflictData)
|
conflictJSON, _ := json.Marshal(conflictData)
|
||||||
_, err := s.db.CreateSyncConflict(ctx, database.CreateSyncConflictParams{
|
_, err := s.db.CreateSyncConflict(ctx, database.CreateSyncConflictParams{
|
||||||
@@ -508,6 +517,9 @@ func buildProgressSnapshot(req SaveProgressRequest) map[string]interface{} {
|
|||||||
if req.Epubcfi != nil {
|
if req.Epubcfi != nil {
|
||||||
data["epubcfi"] = *req.Epubcfi
|
data["epubcfi"] = *req.Epubcfi
|
||||||
}
|
}
|
||||||
|
if req.ContextText != nil {
|
||||||
|
data["context_text"] = *req.ContextText
|
||||||
|
}
|
||||||
if req.Chapter != nil {
|
if req.Chapter != nil {
|
||||||
data["chapter"] = *req.Chapter
|
data["chapter"] = *req.Chapter
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ type ProgressUpdate struct {
|
|||||||
UserID pgtype.UUID
|
UserID pgtype.UUID
|
||||||
Percentage float64
|
Percentage float64
|
||||||
Epubcfi *string
|
Epubcfi *string
|
||||||
|
ContextText *string
|
||||||
Chapter *int
|
Chapter *int
|
||||||
Character *int64
|
Character *int64
|
||||||
Page *int
|
Page *int
|
||||||
@@ -122,6 +123,9 @@ func (p *SyncQueueProcessor) enqueueProgressUpdate(ctx context.Context, update *
|
|||||||
if update.Epubcfi != nil {
|
if update.Epubcfi != nil {
|
||||||
syncData["epubcfi"] = *update.Epubcfi
|
syncData["epubcfi"] = *update.Epubcfi
|
||||||
}
|
}
|
||||||
|
if update.ContextText != nil {
|
||||||
|
syncData["context_text"] = *update.ContextText
|
||||||
|
}
|
||||||
if update.Chapter != nil {
|
if update.Chapter != nil {
|
||||||
syncData["chapter"] = *update.Chapter
|
syncData["chapter"] = *update.Chapter
|
||||||
}
|
}
|
||||||
@@ -331,6 +335,9 @@ func (p *SyncQueueProcessor) syncProgress(ctx context.Context, userID pgtype.UUI
|
|||||||
if v, ok := syncData["epubcfi"].(string); ok {
|
if v, ok := syncData["epubcfi"].(string); ok {
|
||||||
req.Epubcfi = &v
|
req.Epubcfi = &v
|
||||||
}
|
}
|
||||||
|
if v, ok := syncData["context_text"].(string); ok {
|
||||||
|
req.ContextText = &v
|
||||||
|
}
|
||||||
if v, ok := syncData["chapter"].(float64); ok {
|
if v, ok := syncData["chapter"].(float64); ok {
|
||||||
ch := int(v)
|
ch := int(v)
|
||||||
req.Chapter = &ch
|
req.Chapter = &ch
|
||||||
|
|||||||
Reference in New Issue
Block a user