diff --git a/internal/daemon/server.go b/internal/daemon/server.go index 6abdf51..8ae29b4 100644 --- a/internal/daemon/server.go +++ b/internal/daemon/server.go @@ -499,11 +499,10 @@ func (s *Server) captureOutput(name string, h *sessionHandle) { now := time.Now() h.stoppedAt = &now - if meta, err := s.storage.LoadMeta(name); err == nil { + s.storage.UpdateMeta(name, func(meta *SessionMeta) { meta.State = StateStopped meta.StoppedAt = &now - s.storage.SaveMeta(name, meta) - } + }) }() buf := make([]byte, ReadBufferSize) @@ -622,15 +621,16 @@ func (s *Server) handleRead(req Request) Response { result = string(output) } - if req.Cursor != "" { - if meta.Cursors == nil { - meta.Cursors = make(map[string]int64) + storage.UpdateMeta(req.Name, func(m *SessionMeta) { + if req.Cursor != "" { + if m.Cursors == nil { + m.Cursors = make(map[string]int64) + } + m.Cursors[req.Cursor] = totalLen + } else { + m.ReadPos = totalLen } - meta.Cursors[req.Cursor] = totalLen - } else { - meta.ReadPos = totalLen - } - storage.SaveMeta(req.Name, meta) + }) default: output, err := storage.ReadAll(req.Name) if err != nil { @@ -682,15 +682,16 @@ func (s *Server) handleReadTUI(req Request, h *sessionHandle, screen *vterm.Scre result = screen.Render() } - if req.Cursor != "" { - if meta.Cursors == nil { - meta.Cursors = make(map[string]int64) + s.storage.UpdateMeta(req.Name, func(m *SessionMeta) { + if req.Cursor != "" { + if m.Cursors == nil { + m.Cursors = make(map[string]int64) + } + m.Cursors[req.Cursor] = currentVersion + } else { + m.ReadPos = currentVersion } - meta.Cursors[req.Cursor] = currentVersion - } else { - meta.ReadPos = currentVersion - } - s.storage.SaveMeta(req.Name, meta) + }) default: result = screen.Render() } @@ -924,11 +925,10 @@ func (s *Server) handleStop(req Request) Response { now := time.Now() h.stoppedAt = &now - if meta, err := s.storage.LoadMeta(req.Name); err == nil { + s.storage.UpdateMeta(req.Name, func(meta *SessionMeta) { meta.State = StateStopped meta.StoppedAt = &now - s.storage.SaveMeta(req.Name, meta) - } + }) return Response{Success: true} } @@ -1188,9 +1188,10 @@ func (s *Server) handleResize(req Request) Response { } s.mu.Unlock() - meta.Cols = cols - meta.Rows = rows - if err := storage.SaveMeta(req.Name, meta); err != nil { + if err := storage.UpdateMeta(req.Name, func(m *SessionMeta) { + m.Cols = cols + m.Rows = rows + }); err != nil { return Response{Success: false, Error: fmt.Sprintf("save meta: %v", err)} } diff --git a/internal/daemon/storage.go b/internal/daemon/storage.go index d593807..3384916 100644 --- a/internal/daemon/storage.go +++ b/internal/daemon/storage.go @@ -36,5 +36,6 @@ type OutputStorage interface { LoadMeta(session string) (*SessionMeta, error) SaveMeta(session string, meta *SessionMeta) error + UpdateMeta(session string, fn func(meta *SessionMeta)) error ListSessions() ([]string, error) } diff --git a/internal/daemon/storage_file.go b/internal/daemon/storage_file.go index 20d082d..d15bb96 100644 --- a/internal/daemon/storage_file.go +++ b/internal/daemon/storage_file.go @@ -207,6 +207,18 @@ func (s *FileStorage) saveMetaLocked(session string, meta *SessionMeta) error { return nil } +func (s *FileStorage) UpdateMeta(session string, fn func(meta *SessionMeta)) error { + s.mu.Lock() + defer s.mu.Unlock() + + meta, err := s.loadMetaLocked(session) + if err != nil { + return err + } + fn(meta) + return s.saveMetaLocked(session, meta) +} + func (s *FileStorage) ListSessions() ([]string, error) { s.mu.RLock() defer s.mu.RUnlock() diff --git a/internal/daemon/storage_memory.go b/internal/daemon/storage_memory.go index 63a4d2e..6ba0a15 100644 --- a/internal/daemon/storage_memory.go +++ b/internal/daemon/storage_memory.go @@ -162,6 +162,18 @@ func (s *MemoryStorage) SaveMeta(session string, meta *SessionMeta) error { return nil } +func (s *MemoryStorage) UpdateMeta(session string, fn func(meta *SessionMeta)) error { + s.mu.Lock() + defer s.mu.Unlock() + + meta, exists := s.metas[session] + if !exists { + return fmt.Errorf("session %q not found", session) + } + fn(meta) + return nil +} + func (s *MemoryStorage) ListSessions() ([]string, error) { s.mu.RLock() defer s.mu.RUnlock()