From 225f9095cad1151624adcbe752d887b478286b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Wi=C4=99cek?= Date: Tue, 21 May 2024 15:24:04 +0200 Subject: [PATCH 1/8] fix: do not log.fatal inside UI loop --- ui/ui.go | 3 +-- ui/views/compact/compact.go | 17 +++++++++++++---- ui/widgets/tasks/tasks.go | 15 ++++++++------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/ui/ui.go b/ui/ui.go index 3c2ce2d..fc648fd 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -57,7 +57,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case common.ErrMsg: - m.log.Fatal(msg.Error()) + m.log.Error(msg.Error()) return m, tea.Quit case tea.KeyMsg: @@ -79,7 +79,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { "width", msg.Width, "height", msg.Height) m.ctx.WindowSize.Set(msg.Width, msg.Height) - } m.viewCompact, cmd = m.viewCompact.Update(msg) diff --git a/ui/views/compact/compact.go b/ui/views/compact/compact.go index aa851a5..a5054eb 100644 --- a/ui/views/compact/compact.go +++ b/ui/views/compact/compact.go @@ -128,7 +128,11 @@ func (m Model) Update(msg tea.Msg) (common.View, tea.Cmd) { } if len(views) == 0 { - m.widgetTasks.SetTasks(nil) + if err := m.widgetTasks.SetTasks(nil); err != nil { + cmds = append(cmds, common.ErrCmd(err)) + return m, tea.Batch(cmds...) + } + m.widgetViewsTabs.SetTabs(nil) } else { tabs := viewsToTabs(views) @@ -210,7 +214,12 @@ func (m Model) Update(msg tea.Msg) (common.View, tea.Cmd) { if id == "" { m.log.Info("Received: LoadingTasksFromViewMsg empty") - m.widgetTasks.SetTasks(nil) + + if err := m.widgetTasks.SetTasks(nil); err != nil { + cmds = append(cmds, common.ErrCmd(err)) + return m, tea.Batch(cmds...) + } + break } @@ -326,8 +335,8 @@ func (m *Model) reloadTasks(viewId string) error { if err != nil { return err } - m.widgetTasks.SetTasks(tasks) - return nil + + return m.widgetTasks.SetTasks(tasks) } func (m *Model) handleWorkspaceChangePreview(id string) tea.Cmd { diff --git a/ui/widgets/tasks/tasks.go b/ui/widgets/tasks/tasks.go index f804aca..80a9684 100644 --- a/ui/widgets/tasks/tasks.go +++ b/ui/widgets/tasks/tasks.go @@ -219,7 +219,8 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { for _, task := range tasks { m.log.Debug("Opening task in the web browser", "url", task.Url) if err := common.OpenUrlInWebBrowser(task.Url); err != nil { - m.log.Fatal(err) + cmds = append(cmds, common.ErrCmd(err)) + return m, tea.Batch(cmds...) } } @@ -227,7 +228,8 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { task := m.componenetTasksTable.GetHighlightedTask() m.log.Debug("Opening task in the web browser", "url", task.Url) if err := common.OpenUrlInWebBrowser(task.Url); err != nil { - m.log.Fatal(err) + cmds = append(cmds, common.ErrCmd(err)) + return m, tea.Batch(cmds...) } case key.Matches(msg, m.keyMap.ToggleSidebar): @@ -298,20 +300,19 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { return m, tea.Batch(cmds...) } -func (m *Model) SetTasks(tasks []clickup.Task) { +func (m *Model) SetTasks(tasks []clickup.Task) error { m.showSpinner = false m.componenetTasksTable.SetTasks(tasks) if len(tasks) == 0 { m.componenetTasksSidebar.SetHidden(true) - return + return nil } // TODO: check if it should yield at all or move it to cmd id := tasks[0].Id - if err := m.componenetTasksSidebar.SetTask(id); err != nil { - m.log.Fatal(err) - } + + return m.componenetTasksSidebar.SetTask(id) } func (m Model) View() string { From a992408780d12322a52be7cc2fd8fbebb52c69ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Wi=C4=99cek?= Date: Tue, 21 May 2024 15:24:22 +0200 Subject: [PATCH 2/8] fix: json names on clickup.Team --- pkg/clickup/team.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/clickup/team.go b/pkg/clickup/team.go index a2a2f25..9f2c011 100644 --- a/pkg/clickup/team.go +++ b/pkg/clickup/team.go @@ -5,10 +5,10 @@ import "encoding/json" type Workspace = Team type Team struct { - Id string - Name string - Color string - Avatar string + Id string `json:"id"` + Name string `json:"name"` + Color string `json:"color"` + Avatar string `json:"avatar"` Members []interface{} `json:"members"` } From 8502570adef956a28b8e3470733b2c0b6143c1c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Wi=C4=99cek?= Date: Tue, 21 May 2024 15:24:37 +0200 Subject: [PATCH 3/8] fix: json names on clickup.Space --- pkg/clickup/space.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/clickup/space.go b/pkg/clickup/space.go index 66e03cd..36cb670 100644 --- a/pkg/clickup/space.go +++ b/pkg/clickup/space.go @@ -6,7 +6,7 @@ import ( ) type Space struct { - Id string + Id string `json:"id"` Name string `json:"name"` Statuses []SpaceStatus `json:"statuses"` Features []interface{} `json:"-"` From 09ada8036d20eaea84adf7d599dbb7586414ac86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Wi=C4=99cek?= Date: Tue, 21 May 2024 15:47:43 +0200 Subject: [PATCH 4/8] fix: dumping cache, errgroup wasnt waiting for gorutine --- pkg/cache/cache.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index 3dffa0e..dd455b3 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -202,7 +202,7 @@ func (c *Cache) Dump() error { } } - return nil + return errgroup.Wait() } func (c *Cache) saveToFile(path string, filename string, value interface{}) error { From a20dba5c0f427526eee1edcf1e650f206e4a9ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Wi=C4=99cek?= Date: Thu, 23 May 2024 15:33:09 +0200 Subject: [PATCH 5/8] checkpoint --- api/api.go | 264 ++++++++++++++++----- main.go | 3 +- pkg/cache/cache.go | 235 ++++++++++++------ ui/common/commands.go | 16 ++ ui/components/tasks-sidebar/tasksidebar.go | 6 +- ui/components/views-tabs/viewstabs.go | 65 +---- ui/ui.go | 12 + ui/views/compact/compact.go | 69 +++--- ui/widgets/tasks/tasks.go | 25 ++ 9 files changed, 474 insertions(+), 221 deletions(-) diff --git a/api/api.go b/api/api.go index a035e97..0d7b8b0 100644 --- a/api/api.go +++ b/api/api.go @@ -2,6 +2,7 @@ package api import ( "log/slog" + "time" "github.com/charmbracelet/log" @@ -11,19 +12,28 @@ import ( const ( // Cache namespace - CacheNamespaceTeams = "teams" - CacheNamespaceSpaces = "spaces" - CacheNamespaceFolders = "folders" - CacheNamespaceLists = "lists" - CacheNamespaceViews = "views" - CacheNamespaceTasks = "tasks" - CacheNamespaceTask = "task" + CacheNamespaceTeams cache.Namespace = "teams" + CacheNamespaceSpaces cache.Namespace = "spaces" + CacheNamespaceFolders cache.Namespace = "folders" + CacheNamespaceLists cache.Namespace = "lists" + CacheNamespaceViews cache.Namespace = "views" + CacheNamespaceTask cache.Namespace = "tasks" + CacheNamespaceTasksList cache.Namespace = "tasks-list" + CacheNamespaceTasksView cache.Namespace = "tasks-view" +) + +const ( + TTL = 10 + GarbageCollectorInterval = 5 ) type Api struct { Clickup *clickup.Client Cache *cache.Cache logger *log.Logger + + gcCloseChan chan struct{} + interval time.Duration } func NewApi(logger *log.Logger, cache *cache.Cache, token string) Api { @@ -35,16 +45,38 @@ func NewApi(logger *log.Logger, cache *cache.Cache, token string) Api { slog.New(log.WithPrefix(log.GetPrefix()+"/ClickUp")), ) - return Api{ - Clickup: clickup, - logger: log, - Cache: cache, + api := Api{ + Clickup: clickup, + logger: log, + Cache: cache, + gcCloseChan: make(chan struct{}), + interval: GarbageCollectorInterval * time.Second, + } + + go api.garbageCollector() + return api +} + +func (m *Api) garbageCollector() { + ticker := time.NewTicker(m.interval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + m.logger.Debug("Garbage Collector: starting") + // now := time.Now().Unix() + if err := m.InvalidateCache(); err != nil { + panic(err) + } + case <-m.gcCloseChan: + return + } } } func (m *Api) GetSpaces(teamId string) ([]clickup.Space, error) { - m.logger.Debug("Getting spaces for a team", - "teamId", teamId) + m.logger.Debug("Getting spaces for a team", "teamId", teamId) cacheNamespace := CacheNamespaceSpaces @@ -72,6 +104,25 @@ func (m *Api) GetSpaces(teamId string) ([]clickup.Space, error) { return spaces, nil } +func (m *Api) syncSpaces(entry cache.Entry) error { + m.logger.Debug("Sync spaces for a team", "teamId", entry.Key) + + client := m.Clickup + + m.logger.Debugf("Fetching spaces from API") + data, err := client.GetSpaces(entry.Key) + if err != nil { + return err + } + m.logger.Debugf("Found %d spaces for team: %s", len(data), entry.Key) + + entry.UpdatedTimestamp = time.Now().Unix() + entry.Value = data + m.Cache.Update(entry) + + return nil +} + // Alias for GetTeams since they are the same thing func (m *Api) GetWorkspaces() ([]clickup.Workspace, error) { return m.GetTeams() @@ -105,6 +156,25 @@ func (m *Api) GetTeams() ([]clickup.Team, error) { return teams, nil } +func (m *Api) syncTeams(entry cache.Entry) error { + m.logger.Debug("Sync Authorized Teams (Workspaces)") + + client := m.Clickup + + m.logger.Debugf("Fetching teams from API") + data, err := client.GetTeams() + if err != nil { + return err + } + m.logger.Debugf("Found %d teams", len(data)) + + entry.UpdatedTimestamp = time.Now().Unix() + entry.Value = data + m.Cache.Update(entry) + + return nil +} + func (m *Api) GetFolders(spaceId string) ([]clickup.Folder, error) { m.logger.Debug("Getting folders for a space", "space", spaceId) @@ -134,6 +204,26 @@ func (m *Api) GetFolders(spaceId string) ([]clickup.Folder, error) { return folders, nil } +func (m *Api) syncFolders(entry cache.Entry) error { + spaceId := entry.Key + m.logger.Debug("Sync folders for a space", "space", spaceId) + + client := m.Clickup + + m.logger.Debugf("Fetching folders from API") + data, err := client.GetFolders(spaceId) + if err != nil { + return err + } + m.logger.Debugf("Found %d folders for space: %s", len(data), spaceId) + + entry.UpdatedTimestamp = time.Now().Unix() + entry.Value = data + m.Cache.Update(entry) + + return nil +} + func (m *Api) GetLists(folderId string) ([]clickup.List, error) { m.logger.Debug("Getting lists for a folder", "folderId", folderId) @@ -163,6 +253,26 @@ func (m *Api) GetLists(folderId string) ([]clickup.List, error) { return lists, nil } +func (m *Api) syncLists(entry cache.Entry) error { + folderId := entry.Key + m.logger.Debug("Getting lists for a folder", "folderId", folderId) + + client := m.Clickup + + m.logger.Debugf("Fetching lists from API") + data, err := client.GetListsFromFolder(folderId) + if err != nil { + return err + } + m.logger.Debugf("Found %d lists for folder: %s", len(data), folderId) + + entry.UpdatedTimestamp = time.Now().Unix() + entry.Value = data + m.Cache.Update(entry) + + return nil +} + func (m *Api) GetTask(taskId string) (clickup.Task, error) { m.logger.Debug("Getting a task", "taskId", taskId) @@ -192,11 +302,31 @@ func (m *Api) GetTask(taskId string) (clickup.Task, error) { return task, nil } +func (m *Api) syncTask(entry cache.Entry) error { + taskId := entry.Key + m.logger.Debug("Sync a task", "taskId", taskId) + + client := m.Clickup + + m.logger.Debug("Fetching task from API") + data, err := client.GetTask(taskId) + if err != nil { + return err + } + m.logger.Debug("Found task", "task", taskId) + + entry.UpdatedTimestamp = time.Now().Unix() + entry.Value = data + m.Cache.Update(entry) + + return nil +} + func (m *Api) GetTasksFromList(listId string) ([]clickup.Task, error) { m.logger.Debug("Getting tasks for a list", "listId", listId) - cacheNamespace := CacheNamespaceTasks + cacheNamespace := CacheNamespaceTasksList data, ok := m.Cache.Get(cacheNamespace, listId) if ok { var tasks []clickup.Task @@ -225,7 +355,7 @@ func (m *Api) GetTasksFromView(viewId string) ([]clickup.Task, error) { m.logger.Debug("Getting tasks for a view", "viewId", viewId) - cacheNamespace := CacheNamespaceTasks + cacheNamespace := CacheNamespaceTasksView data, ok := m.Cache.Get(cacheNamespace, viewId) if ok { var tasks []clickup.Task @@ -250,6 +380,26 @@ func (m *Api) GetTasksFromView(viewId string) ([]clickup.Task, error) { return tasks, nil } +func (m *Api) syncTasksFromView(entry cache.Entry) error { + viewId := entry.Key + m.logger.Debug("Sync tasks for a view", "viewId", viewId) + + client := m.Clickup + + m.logger.Debug("Fetching tasks from API") + data, err := client.GetTasksFromView(viewId) + if err != nil { + return err + } + m.logger.Debugf("Found %d tasks in view %s", len(data), viewId) + + entry.UpdatedTimestamp = time.Now().Unix() + entry.Value = data + m.Cache.Update(entry) + + return nil +} + func (m *Api) GetViewsFromFolder(folderId string) ([]clickup.View, error) { m.logger.Debug("Getting views for folder", "folder", folderId) @@ -391,7 +541,7 @@ func (m *Api) GetViewsFromWorkspace(workspaceId string) ([]clickup.View, error) } //nolint:unused -func (m *Api) getFromCache(namespace string, key string, v interface{}) (bool, error) { +func (m *Api) getFromCache(namespace cache.Namespace, key string, v interface{}) (bool, error) { data, ok := m.Cache.Get(namespace, key) if !ok { return false, nil @@ -410,59 +560,53 @@ func (m *Api) InvalidateCache() error { entries := m.Cache.GetEntries() m.logger.Debug("Found cache entries", "count", len(entries)) - if err := m.Cache.Invalidate(); err != nil { - m.logger.Error("Failed to invalidate cache", "error", err) - return err - } + // if err := m.Cache.Invalidate(); err != nil { + // m.logger.Error("Failed to invalidate cache", "error", err) + // return err + // } + now := time.Now().Unix() for _, entry := range entries { + if entry.UpdatedTimestamp+TTL > now { + continue + } + + var err error + + m.logger.Debug("Invalidating cache", "namespace", entry.Namespace) switch entry.Namespace { case CacheNamespaceTeams: - m.logger.Debug("Invalidating teams cache") - _, err := m.GetTeams() - if err != nil { - m.logger.Error("Failed to invalidate teams cache", "error", err) - } + err = m.syncTeams(entry) case CacheNamespaceSpaces: - m.logger.Debug("Invalidating spaces cache") - _, err := m.GetSpaces(entry.Key) - if err != nil { - m.logger.Error("Failed to invalidate spaces cache", "error", err) - } + err = m.syncSpaces(entry) case CacheNamespaceFolders: - m.logger.Debug("Invalidating folders cache") - _, err := m.GetFolders(entry.Key) - if err != nil { - m.logger.Error("Failed to invalidate folders cache", "error", err) - } + err = m.syncFolders(entry) case CacheNamespaceLists: - m.logger.Debug("Invalidating lists cache") - _, err := m.GetLists(entry.Key) - if err != nil { - m.logger.Error("Failed to invalidate lists cache", "error", err) - } - case CacheNamespaceViews: - m.logger.Debug("Invalidating views cache") - _, err := m.GetViewsFromSpace(entry.Key) - if err != nil { - m.logger.Error("Failed to invalidate views cache", "error", err) - } - case CacheNamespaceTasks: - m.logger.Debug("Invalidating tasks cache") - _, err := m.GetTasksFromList(entry.Key) - if err != nil { - m.logger.Error("Failed to invalidate tasks cache", "error", err) - } + err = m.syncLists(entry) + + // TODO: + // case CacheNamespaceViews: + // m.logger.Debug("Invalidating views cache") + // _, err := m.GetViewsFromSpace(entry.Key) + // if err != nil { + // m.logger.Error("Failed to invalidate views cache", "error", err) + // } + // case CacheNamespaceTasksList: + // m.logger.Debug("Invalidating tasks cache") + // _, err := m.GetTasksFromList(entry.Key) + // if err != nil { + // m.logger.Error("Failed to invalidate tasks cache", "error", err) + // } + case CacheNamespaceTasksView: + err = m.syncTasksFromView(entry) case CacheNamespaceTask: - m.logger.Debug("Invalidating task cache") - _, err := m.GetTask(entry.Key) - if err != nil { - m.logger.Error("Failed to invalidate task cache", "error", err) - } - default: - m.logger.Debug("Invalidating cache", - "namespace", entry.Namespace, "key", entry.Key) + err = m.syncTask(entry) + } + + if err != nil { + m.logger.Error("Failed to invalidate task cache", "error", err) } } + return nil } diff --git a/main.go b/main.go index 9eecf11..592b986 100644 --- a/main.go +++ b/main.go @@ -111,7 +111,7 @@ func main() { ) defer func() { - if err := cache.Dump(); err != nil { + if err := cache.Close(); err != nil { termLogger.Fatal(err) } }() @@ -149,6 +149,7 @@ func main() { logger.Info("Initializing program...") p := tea.NewProgram(mainModel, tea.WithAltScreen()) if _, err := p.Run(); err != nil { + cache.Close() termLogger.Fatal(err) } } diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index dd455b3..c3d0a07 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -8,36 +8,114 @@ import ( "path/filepath" "strings" "sync" + "time" "golang.org/x/sync/errgroup" ) -type Entry struct { - // The key of the Entry - Key string +const ( + TTL = 3 * 60 // 3m + StaleInterval = 30 * 60 // 30m + GarbageCollectorInterval = 3 // 5s +) - // The namespace of the Entryl - Namespace string +type Entry struct { + Value interface{} `json:"value"` + Key string `json:"key"` + Namespace Namespace `json:"namespace"` + Stale bool `json:"stale"` + AccessedTimestamp int64 `json:"accessedtimestamp"` + CreatedTimestamp int64 `json:"createdtimestamp"` + UpdatedTimestamp int64 `json:"updatedTimestamp"` } -type Data map[string]interface{} +type Key string -type Cache struct { - logger *slog.Logger +type Data map[string]Entry + +type Namespace string - data map[string]Data - path string - mutex sync.RWMutex +type Cache struct { + logger *slog.Logger + data map[Namespace]Data + closeChan chan struct{} + path string + interval time.Duration + mutex sync.RWMutex } func NewCache(logger *slog.Logger, path string) *Cache { - return &Cache{ - path: path, - data: map[string]Data{}, - logger: logger, + c := &Cache{ + path: path, + data: map[Namespace]Data{}, + logger: logger, + interval: GarbageCollectorInterval * time.Second, + closeChan: make(chan struct{}), + } + + go c.garbageCollector() + + return c +} + +func (c *Cache) garbageCollector() { + ticker := time.NewTicker(c.interval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + c.logger.Debug("Garbage Collector: starting") + now := time.Now().Unix() + entries := c.GetEntries() + for _, entry := range entries { + entryId := string(entry.Namespace) + "/" + entry.Key + if !entry.Stale { + if now > entry.AccessedTimestamp+StaleInterval { + c.logger.Debug("Garbage Collector: marking as stale", "entry", entryId) + entry.Stale = true + c.Update(entry) + } + + continue + } + + if now > entry.UpdatedTimestamp+TTL { + c.logger.Debug("Garbage Collector: deleting stale", "entry", entryId) + c.Delete(entry.Namespace, entry.Key) + } + } + + case <-c.closeChan: + return + } } } +func (c *Cache) Delete(namespace Namespace, key string) { + c.logger.Debug("Removing", "entry", string(namespace)+"/"+key) + c.mutex.Lock() + delete(c.data[namespace], key) + c.mutex.Unlock() +} + +func (c *Cache) Update(entry Entry) { + c.logger.Debug("Updating", "entry", string(entry.Namespace)+"/"+entry.Key) + c.mutex.Lock() + c.data[entry.Namespace][entry.Key] = entry + c.mutex.Unlock() +} + +func (c *Cache) close() { + c.closeChan <- struct{}{} +} + +func (c *Cache) Close() error { + c.close() + + return c.Dump() +} + func filterDir(files []os.DirEntry) []os.DirEntry { var dirs []os.DirEntry for _, file := range files { @@ -57,20 +135,23 @@ func (c *Cache) getNamespacesFromCacheFiles() ([]os.DirEntry, error) { return filterDir(namespaces), nil } -func (c *Cache) loadKey(namespace string, key string) (interface{}, error) { - c.logger.Debug("Loading key", "key", namespace+"/"+key) +func (c *Cache) loadKey(namespace Namespace, key string) (Entry, error) { + keyId := fmt.Sprintf("%s/%s", namespace, key) + path := fmt.Sprintf("%s/%s/%s.json", c.path, namespace, key) + + c.logger.Debug("Loading key", "key", keyId) - rawData, err := c.loadFromFile( - fmt.Sprintf("%s/%s/%s.json", - c.path, namespace, key)) + var entry Entry + + entry, err := c.loadFromFile(path) if err != nil { - return nil, err + return entry, fmt.Errorf("loading key error id=%s err=%w", keyId, err) } - return rawData, nil + return entry, nil } -func (c *Cache) loadNamespace(namespace string) (Data, error) { +func (c *Cache) loadNamespace(namespace Namespace) (Data, error) { c.logger.Debug("Loading namespace", "namespace", namespace) keys, err := os.ReadDir(fmt.Sprintf("%s/%s", c.path, namespace)) @@ -97,7 +178,7 @@ func (c *Cache) loadNamespace(namespace string) (Data, error) { } func (c *Cache) Load() error { - c.logger.Debug("Loading cache from path...", "path", c.path) + c.logger.Debug("Loading cache", "path", c.path) namespaces, err := c.getNamespacesFromCacheFiles() if err != nil { return err @@ -113,13 +194,14 @@ func (c *Cache) Load() error { // nested function to prevent loop closure func(namespace os.DirEntry) { errgroup.Go(func() error { - data, err := c.loadNamespace(namespace.Name()) + ns := Namespace(namespace.Name()) + data, err := c.loadNamespace(ns) if err != nil { return err } c.mutex.Lock() - c.data[namespace.Name()] = data + c.data[ns] = data c.mutex.Unlock() return nil @@ -130,12 +212,13 @@ func (c *Cache) Load() error { return errgroup.Wait() } -func (c *Cache) GetNamespace(namespace string) Data { +func (c *Cache) GetNamespace(namespace Namespace) Data { c.mutex.Lock() v, ok := c.data[namespace] if !ok { - v = Data{} + c.logger.Debug("Namespace not found. Creating a new one", "namespace", namespace) + v = make(Data) } c.mutex.Unlock() @@ -145,7 +228,7 @@ func (c *Cache) GetNamespace(namespace string) Data { // Get returns the value of the key in the namespace // and a boolean indicating if the key exists in the cache -func (c *Cache) Get(namespace string, key string) (interface{}, bool) { +func (c *Cache) Get(namespace Namespace, key string) (interface{}, bool) { data := c.GetNamespace(namespace) // Check if the key exists in the cache @@ -164,48 +247,72 @@ func (c *Cache) Get(namespace string, key string) (interface{}, bool) { c.logger.Debug("Key found in cache", "namespace", namespace, "key", key) - return value, true + value.AccessedTimestamp = time.Now().Unix() + c.data[namespace][key] = value + + return value.Value, true } -func (c *Cache) Set(namespace string, key string, value interface{}) { +func (c *Cache) Set(namespace Namespace, key string, value interface{}) { c.logger.Debug("Caching", "namespace", namespace, "key", key) data := c.GetNamespace(namespace) c.mutex.Lock() - data[key] = value - c.mutex.Unlock() - - path := fmt.Sprintf("%s/%s", c.path, namespace) - filename := fmt.Sprintf("%s.json", key) - - if err := c.saveToFile(path, filename, value); err != nil { - c.logger.Error(err.Error()) - panic(err) + ts := time.Now().Unix() + data[key] = Entry{ + Key: key, + Namespace: namespace, + Value: value, + AccessedTimestamp: ts, + CreatedTimestamp: ts, + UpdatedTimestamp: ts, + Stale: false, } + + c.data[namespace] = data + c.mutex.Unlock() } func (c *Cache) Dump() error { c.logger.Debug("Dumping cache") + if err := c.Invalidate(); err != nil { + return err + } + errgroup := new(errgroup.Group) - for namespace, data := range c.data { - for key, value := range data { - func(namespace string, key string, value interface{}) { - errgroup.Go(func() error { - path := fmt.Sprintf("%s/%s", c.path, namespace) - filename := fmt.Sprintf("%s.json", key) - return c.saveToFile(path, filename, value) - }) - }(namespace, key, value) + for namespace, data := range c.data { + for key := range data { + c.mutex.Lock() + entry := c.data[namespace][key] + errgroup.Go(func() error { + return c.saveEntryToFile(entry) + }) + c.mutex.Unlock() } } return errgroup.Wait() } -func (c *Cache) saveToFile(path string, filename string, value interface{}) error { +func (c *Cache) saveEntryToFile(entry Entry) error { + namespace := entry.Namespace + key := entry.Key + path := fmt.Sprintf("%s/%s", c.path, namespace) + filename := fmt.Sprintf("%s.json", key) + + c.logger.Debug("Writing entry", "namespaces", namespace, "key", key) + + if err := c.saveToFile(path, filename, entry); err != nil { + return err + } + + return nil +} + +func (c *Cache) saveToFile(path string, filename string, entry Entry) error { if err := os.MkdirAll(path, 0777); err != nil { c.logger.Error(err.Error()) panic(err) @@ -220,7 +327,7 @@ func (c *Cache) saveToFile(path string, filename string, value interface{}) erro } defer f.Close() - data, err := json.Marshal(value) + data, err := json.Marshal(entry) if err != nil { return err } @@ -233,16 +340,17 @@ func (c *Cache) saveToFile(path string, filename string, value interface{}) erro return nil } -func (c *Cache) loadFromFile(filepath string) (interface{}, error) { +func (c *Cache) loadFromFile(filepath string) (Entry, error) { + var data Entry + f, err := os.Open(filepath) if err != nil { - return nil, err + return data, err } defer f.Close() - var data interface{} if err := json.NewDecoder(f).Decode(&data); err != nil { - return nil, err + return data, err } return data, nil @@ -266,15 +374,9 @@ func (c *Cache) GetEntries() []Entry { c.logger.Debug("Getting all cache entries", "entries", len(c.data)) - j, _ := json.Marshal(c.data) - c.logger.Debug(string(j)) - - for ns, data := range c.data { - for key := range data { - entries = append(entries, Entry{ - Namespace: ns, - Key: key, - }) + for _, data := range c.data { + for _, entry := range data { + entries = append(entries, entry) } } @@ -284,9 +386,6 @@ func (c *Cache) GetEntries() []Entry { func (c *Cache) Invalidate() error { c.logger.Debug("Invalidating all cache entries") - // Clear the in-memory cache - c.data = make(map[string]Data) - contents, err := filepath.Glob(c.path + "/*") if err != nil { return err @@ -311,7 +410,7 @@ func (c *Cache) Invalidate_Deprecated() error { c.logger.Debug("Invalidating all cache entries") // Clear the in-memory cache - c.data = make(map[string]Data) + c.data = make(map[Namespace]Data) // Remove subdirectories and nested files within the cache directory subdirs, err := os.ReadDir(c.path) diff --git a/ui/common/commands.go b/ui/common/commands.go index 3051467..7f164d6 100644 --- a/ui/common/commands.go +++ b/ui/common/commands.go @@ -91,3 +91,19 @@ func ErrCmd(err ErrMsg) tea.Cmd { return err } } + +type UITickMsg int64 + +func UITickCmd(ts int64) tea.Cmd { + return func() tea.Msg { + return UITickMsg(ts) + } +} + +type RefreshMsg string + +func RefreshCmd() tea.Cmd { + return func() tea.Msg { + return RefreshMsg("") + } +} diff --git a/ui/components/tasks-sidebar/tasksidebar.go b/ui/components/tasks-sidebar/tasksidebar.go index 4ef0319..e446e34 100644 --- a/ui/components/tasks-sidebar/tasksidebar.go +++ b/ui/components/tasks-sidebar/tasksidebar.go @@ -125,15 +125,19 @@ func (m Model) renderTask(task clickup.Task) string { divider := strings.Repeat("-", runewidth.StringWidth(header)) s.WriteString(divider) - r, _ := glamour.NewTermRenderer( + r, err := glamour.NewTermRenderer( glamour.WithAutoStyle(), glamour.WithWordWrap(m.viewport.Width), ) + if err != nil { + return err.Error() + } out, err := r.Render(task.MarkdownDescription) if err != nil { return err.Error() } + s.WriteString(out) return s.String() diff --git a/ui/components/views-tabs/viewstabs.go b/ui/components/views-tabs/viewstabs.go index 7aa7751..383c67c 100644 --- a/ui/components/views-tabs/viewstabs.go +++ b/ui/components/views-tabs/viewstabs.go @@ -156,14 +156,14 @@ func (m Model) View() string { tabPrefix + strings.Join(s, ""), ) } - m.log.Debugf("Rendering %d tabs", len(m.tabs)) + // m.log.Debugf("Rendering %d tabs", len(m.tabs)) moreTabsIcon := " + " // selectedTabVisible := false for _, tab := range m.tabs { // for i, tab := range m.tabs { - m.log.Debugf("Rendering tab: %s %s", tab.Name, tab.Id) + // m.log.Debugf("Rendering tab: %s %s", tab.Name, tab.Id) // m.EndIdx = i t := "" @@ -196,67 +196,6 @@ func (m Model) View() string { ) } -// func (m Model) View() string { -// bColor := lipgloss.Color("#FFF") -// if m.Focused { -// bColor = lipgloss.Color("#8909FF") -// } -// -// borderMargin := 0 -// if m.ifBorders { -// borderMargin = 2 -// } -// -// style := lipgloss.NewStyle(). -// BorderStyle(lipgloss.RoundedBorder()). -// BorderForeground(bColor). -// BorderBottom(m.ifBorders). -// BorderRight(m.ifBorders). -// BorderTop(m.ifBorders). -// BorderLeft(m.ifBorders). -// Height(1). -// MaxHeight(1 + borderMargin). -// Width(m.size.Width - borderMargin). -// MaxWidth(m.size.Width + borderMargin) -// -// s := new(strings.Builder) -// s.WriteString(" Views |") -// -// if len(m.tabs) == 0 { -// s.WriteString(" ") -// return style.Render(s.String()) -// } -// m.log.Debugf("Rendering %d tabs", len(m.tabs)) -// -// moreTabsIcon := " + " -// for i, tab := range m.tabs { -// m.log.Debugf("Rendering tab: %s %s", tab.Name, tab.Id) -// // m.EndIdx = i -// -// t := "" -// tabContent := " " + tab.Name + " " -// if m.SelectedTab == tab.Id { -// t = activeTabStyle.Render(tabContent) -// } else { -// t = inactiveTabStyle.Render(tabContent) -// } -// -// content := " " + t + " " -// -// if lipgloss.Width(s.String()+content+moreTabsIcon) >= m.size.Width-borderMargin { -// s.WriteString(moreTabsIcon) -// break -// } -// s.WriteString(content) -// -// if i != len(m.tabs)-1 { -// s.WriteString("|") -// } -// } -// -// return style.Render(s.String()) -// } - func (m Model) Init() tea.Cmd { m.log.Info("Initializing...") return nil diff --git a/ui/ui.go b/ui/ui.go index fc648fd..fc09ce1 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -2,6 +2,7 @@ package ui import ( "strings" + "time" "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" @@ -79,6 +80,16 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { "width", msg.Width, "height", msg.Height) m.ctx.WindowSize.Set(msg.Width, msg.Height) + + case common.UITickMsg: + ts := int64(msg) + if time.Now().Unix() > ts { + m.log.Debug("Fire refresh tick") + cmds = append(cmds, common.UITickCmd(time.Now().Unix()+3)) + cmds = append(cmds, common.RefreshCmd()) + return m, tea.Batch(cmds...) + } + cmds = append(cmds, common.UITickCmd(ts)) } m.viewCompact, cmd = m.viewCompact.Update(msg) @@ -146,5 +157,6 @@ func (m Model) Init() tea.Cmd { return tea.Batch( m.viewCompact.Init(), m.dialogHelp.Init(), + common.UITickCmd(time.Now().Unix()+3), ) } diff --git a/ui/views/compact/compact.go b/ui/views/compact/compact.go index a5054eb..b748ccf 100644 --- a/ui/views/compact/compact.go +++ b/ui/views/compact/compact.go @@ -18,19 +18,23 @@ import ( const ViewId = "viewCompact" -type Model struct { - ctx *context.UserContext - log *log.Logger - ViewId common.ViewId - state common.WidgetId - size common.Size +type State struct { + Widget common.WidgetId + View string +} +type Model struct { + ctx *context.UserContext + ViewId common.ViewId + log *log.Logger + state State spinner spinner.Model + size common.Size showSpinner bool widgetNavigator navigator.Model - widgetViewsTabs viewstabs.Model widgetTasks tasks.Model + widgetViewsTabs viewstabs.Model } func (m Model) GetSize() common.Size { @@ -50,7 +54,7 @@ func (m Model) Init() tea.Cmd { } func (m Model) KeyMap() help.KeyMap { - switch m.state { + switch m.state.Widget { case navigator.WidgetId: return m.widgetNavigator.KeyMap() case viewstabs.WidgetId: @@ -79,26 +83,26 @@ func (m Model) Update(msg tea.Msg) (common.View, tea.Cmd) { case tea.KeyMsg: switch keypress := msg.String(); keypress { case "tab": - switch m.state { + switch m.state.Widget { case navigator.WidgetId: - m.state = tasks.WidgetId + m.state.Widget = tasks.WidgetId m.widgetTasks = m.widgetTasks.SetFocused(true) m.widgetViewsTabs = m.widgetViewsTabs.SetFocused(false) m.widgetNavigator = m.widgetNavigator.SetFocused(false) case viewstabs.WidgetId: - m.state = navigator.WidgetId + m.state.Widget = navigator.WidgetId m.widgetTasks = m.widgetTasks.SetFocused(false) m.widgetViewsTabs = m.widgetViewsTabs.SetFocused(false) m.widgetNavigator = m.widgetNavigator.SetFocused(true) case tasks.WidgetId: - m.state = viewstabs.WidgetId + m.state.Widget = viewstabs.WidgetId m.widgetTasks = m.widgetTasks.SetFocused(false) m.widgetViewsTabs = m.widgetViewsTabs.SetFocused(true) m.widgetNavigator = m.widgetNavigator.SetFocused(false) } } - switch m.state { + switch m.state.Widget { case navigator.WidgetId: m.widgetNavigator, cmd = m.widgetNavigator.Update(msg) case viewstabs.WidgetId: @@ -140,7 +144,8 @@ func (m Model) Update(msg tea.Msg) (common.View, tea.Cmd) { initTab := m.widgetViewsTabs.SelectedTab - if err := m.reloadTasks(initTab); err != nil { + m.state.View = initTab + if err := m.widgetTasks.ReloadTasks(initTab); err != nil { cmds = append(cmds, common.ErrCmd(err)) return m, tea.Batch(cmds...) } @@ -194,7 +199,7 @@ func (m Model) Update(msg tea.Msg) (common.View, tea.Cmd) { id := string(msg) m.log.Info("Received: ListChangeMsg", "id", id) // TODO: make state change as func - m.state = m.widgetTasks.WidgetId + m.state.Widget = m.widgetTasks.WidgetId m.widgetTasks = m.widgetTasks.SetFocused(true) m.widgetViewsTabs = m.widgetViewsTabs.SetFocused(false) m.widgetNavigator = m.widgetNavigator.SetFocused(false) @@ -214,7 +219,6 @@ func (m Model) Update(msg tea.Msg) (common.View, tea.Cmd) { if id == "" { m.log.Info("Received: LoadingTasksFromViewMsg empty") - if err := m.widgetTasks.SetTasks(nil); err != nil { cmds = append(cmds, common.ErrCmd(err)) return m, tea.Batch(cmds...) @@ -223,18 +227,34 @@ func (m Model) Update(msg tea.Msg) (common.View, tea.Cmd) { break } + m.state.View = id m.log.Info("Received: LoadingTasksFromViewMsg", "id", id) - if err := m.reloadTasks(id); err != nil { + if err := m.widgetTasks.ReloadTasks(id); err != nil { cmds = append(cmds, common.ErrCmd(err)) return m, tea.Batch(cmds...) } case tasks.LostFocusMsg: m.log.Info("Received: tasks.LostFocusMsg") - m.state = navigator.WidgetId + m.state.Widget = navigator.WidgetId m.widgetTasks = m.widgetTasks.SetFocused(false) m.widgetViewsTabs = m.widgetViewsTabs.SetFocused(false) m.widgetNavigator = m.widgetNavigator.SetFocused(true) + + case common.RefreshMsg: + m.log.Info("Received: common.RefreshMsg") + if m.state.View == "" { + if err := m.widgetTasks.SetTasks(nil); err != nil { + cmds = append(cmds, common.ErrCmd(err)) + return m, tea.Batch(cmds...) + } + + break + } + if err := m.widgetTasks.ReloadTasks(m.state.View); err != nil { + cmds = append(cmds, common.ErrCmd(err)) + return m, tea.Batch(cmds...) + } } m.widgetViewsTabs, cmd = m.widgetViewsTabs.Update(msg) @@ -311,7 +331,9 @@ func InitialModel(ctx *context.UserContext, logger *log.Logger) common.View { widgetViewsTabs: widgetViewsTabs, widgetNavigator: widgetNavigator, widgetTasks: widgetTasks, - state: widgetNavigator.WidgetId, + state: State{ + Widget: widgetNavigator.WidgetId, + }, } } @@ -330,15 +352,6 @@ func viewsToTabs(views []clickup.View) []viewstabs.Tab { return tabs } -func (m *Model) reloadTasks(viewId string) error { - tasks, err := m.ctx.Api.GetTasksFromView(viewId) - if err != nil { - return err - } - - return m.widgetTasks.SetTasks(tasks) -} - func (m *Model) handleWorkspaceChangePreview(id string) tea.Cmd { views, err := m.ctx.Api.GetViewsFromWorkspace(id) if err != nil { diff --git a/ui/widgets/tasks/tasks.go b/ui/widgets/tasks/tasks.go index 80a9684..840ce46 100644 --- a/ui/widgets/tasks/tasks.go +++ b/ui/widgets/tasks/tasks.go @@ -289,6 +289,12 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { } cmds = append(cmds, cmd) + + case spinner.TickMsg: + if m.showSpinner { + m.spinner, cmd = m.spinner.Update(msg) + cmds = append(cmds, cmd) + } } m.componenetTasksTable, cmd = m.componenetTasksTable.Update(msg) @@ -454,6 +460,25 @@ func (m *Model) SetSize(s common.Size) { m.size = s } +func (m *Model) ReloadTasks(viewId string) error { + tasks, err := m.ctx.Api.GetTasksFromView(viewId) + if err != nil { + return err + } + + m.showSpinner = false + m.componenetTasksTable.SetTasks(tasks) + + if len(tasks) == 0 { + m.componenetTasksSidebar.SetHidden(true) + return nil + } + + id := m.componenetTasksSidebar.SelectedTask.Id + + return m.componenetTasksSidebar.SetTask(id) +} + func (m *Model) Init() error { m.log.Info("Initializing...") return nil From 02e7f815ce74c64c640b92276de9b3e82c47816e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Wi=C4=99cek?= Date: Mon, 27 May 2024 14:38:29 +0200 Subject: [PATCH 6/8] conflicts --- api/api.go | 16 ++++++++-------- pkg/cache/cache.go | 41 +++++++++++++---------------------------- 2 files changed, 21 insertions(+), 36 deletions(-) diff --git a/api/api.go b/api/api.go index 094a9cf..32b41f4 100644 --- a/api/api.go +++ b/api/api.go @@ -103,7 +103,7 @@ func (m *Api) syncSpaces(entry cache.Entry) error { } m.logger.Debugf("Found %d spaces for team: %s", len(data), entry.Key) - entry.UpdatedTimestamp = time.Now().Unix() + entry.UpdatedTs = time.Now().Unix() entry.Value = data m.Cache.Update(entry) @@ -142,7 +142,7 @@ func (m *Api) syncTeams(entry cache.Entry) error { } m.logger.Debugf("Found %d teams", len(data)) - entry.UpdatedTimestamp = time.Now().Unix() + entry.UpdatedTs = time.Now().Unix() entry.Value = data m.Cache.Update(entry) @@ -177,7 +177,7 @@ func (m *Api) syncFolders(entry cache.Entry) error { } m.logger.Debugf("Found %d folders for space: %s", len(data), spaceId) - entry.UpdatedTimestamp = time.Now().Unix() + entry.UpdatedTs = time.Now().Unix() entry.Value = data m.Cache.Update(entry) @@ -212,7 +212,7 @@ func (m *Api) syncLists(entry cache.Entry) error { } m.logger.Debugf("Found %d lists for folder: %s", len(data), folderId) - entry.UpdatedTimestamp = time.Now().Unix() + entry.UpdatedTs = time.Now().Unix() entry.Value = data m.Cache.Update(entry) @@ -247,7 +247,7 @@ func (m *Api) syncTask(entry cache.Entry) error { } m.logger.Debug("Found task", "task", taskId) - entry.UpdatedTimestamp = time.Now().Unix() + entry.UpdatedTs = time.Now().Unix() entry.Value = data m.Cache.Update(entry) @@ -297,7 +297,7 @@ func (m *Api) syncTasksFromView(entry cache.Entry) error { } m.logger.Debugf("Found %d tasks in view %s", len(data), viewId) - entry.UpdatedTimestamp = time.Now().Unix() + entry.UpdatedTs = time.Now().Unix() entry.Value = data m.Cache.Update(entry) @@ -420,13 +420,13 @@ func (m *Api) InvalidateCache() error { now := time.Now().Unix() for _, entry := range entries { - if entry.UpdatedTimestamp+TTL > now { + if entry.UpdatedTs+TTL > now { continue } var err error - m.logger.Debug("Invalidating cache", "namespace", entry.Namespace, "key", entry.Key.String()) + m.logger.Debug("Invalidating cache", "namespace", entry.Namespace, "key", entry.Key.String()) switch entry.Namespace { case CacheNamespaceTeams: diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index 3b7b9cf..fd8a6a8 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -75,7 +75,6 @@ func NewCache(logger *slog.Logger, path string) *Cache { logger: logger, interval: GarbageCollectorInterval * time.Second, closeChan: make(chan struct{}), - } go c.garbageCollector() @@ -253,18 +252,6 @@ func (c *Cache) GetEntries() []Entry { return entries } -func (c *Cache) saveEntryToFile(entry Entry) error { - namespace := entry.Namespace - key := entry.Key - path := fmt.Sprintf("%s/%s", c.path, namespace) - filename := fmt.Sprintf("%s.json", key) - - c.logger.Debug("Writing entry", "namespaces", namespace, "key", key) - - - return c.clearCacheDir() -} - func (c *Cache) clearCacheDir() error { c.logger.Debug("Clearing cache dir") @@ -273,6 +260,18 @@ func (c *Cache) clearCacheDir() error { return err } + for _, item := range contents { + if strings.Contains(item, ".gitkeep") { + continue + } + + c.logger.Debug("Removing:", "path", item) + + if err = os.RemoveAll(item); err != nil { + return err + } + } + return nil } @@ -340,19 +339,6 @@ func (c *Cache) getNamespacesFromCacheFiles() ([]Namespace, error) { return ns, nil } -func (c *Cache) GetEntries() []Entry { - entries := []Entry{} - c.logger.Debug("Getting all cache entries", - "entries", len(c.data)) - - for _, data := range c.data { - for _, entry := range data { - entries = append(entries, entry) - } - } - return entries -} - func (c *Cache) Invalidate() error { c.logger.Debug("Invalidating all cache entries") @@ -382,8 +368,7 @@ func (c *Cache) loadKey(namespace Namespace, key Key) (Entry, error) { c.logger.Debug("Loading key", "key", keyId) - return c.loadFromFile( - fmt.Sprintf("%s/%s/%s.json", c.path, namespace, key)) + return c.loadFromFile(path) } func (c *Cache) loadNamespace(namespace Namespace) (Data, error) { From a0dcb34fa0300a1ba75b5527c7ac948d60627896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Wi=C4=99cek?= Date: Mon, 27 May 2024 14:40:48 +0200 Subject: [PATCH 7/8] conf --- pkg/cache/cache.go | 47 +++++++++++++--------------------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index fd8a6a8..c6b7931 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -175,8 +175,7 @@ func (c *Cache) getNamespace(namespace Namespace) Data { v, ok := c.data[namespace] if !ok { - c.logger.Debug("Namespace not found. Creating a new one", "namespace", namespace) - v = make(Data) + v = Data{} } c.mutex.Unlock() @@ -222,10 +221,6 @@ func (c *Cache) Set(namespace Namespace, key Key, value interface{}) { func (c *Cache) Dump() error { c.logger.Debug("Dumping cache") - if err := c.Invalidate(); err != nil { - return err - } - errgroup := new(errgroup.Group) for _, entry := range c.GetEntries() { func(entry Entry) { @@ -252,6 +247,15 @@ func (c *Cache) GetEntries() []Entry { return entries } +func (c *Cache) Invalidate() error { + c.logger.Debug("Invalidating all cache entries") + + // Clear the in-memory cache + c.data = make(map[Namespace]Data) + + return c.clearCacheDir() +} + func (c *Cache) clearCacheDir() error { c.logger.Debug("Clearing cache dir") @@ -339,36 +343,11 @@ func (c *Cache) getNamespacesFromCacheFiles() ([]Namespace, error) { return ns, nil } -func (c *Cache) Invalidate() error { - c.logger.Debug("Invalidating all cache entries") - - contents, err := filepath.Glob(c.path + "/*") - if err != nil { - return err - } - - for _, item := range contents { - if strings.Contains(item, ".gitkeep") { - continue - } - - c.logger.Debug("Removing:", "path", item) - - if err = os.RemoveAll(item); err != nil { - return err - } - } - - return nil -} - func (c *Cache) loadKey(namespace Namespace, key Key) (Entry, error) { - keyId := fmt.Sprintf("%s/%s", namespace, key) - path := fmt.Sprintf("%s/%s/%s.json", c.path, namespace, key) - - c.logger.Debug("Loading key", "key", keyId) + c.logger.Debug("Loading key", "key", fmt.Sprintf("%s/%s", namespace, key)) - return c.loadFromFile(path) + return c.loadFromFile( + fmt.Sprintf("%s/%s/%s.json", c.path, namespace, key)) } func (c *Cache) loadNamespace(namespace Namespace) (Data, error) { From 2a411f201121810272fe9217ba0a093983e8b969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Wi=C4=99cek?= Date: Mon, 27 May 2024 14:43:31 +0200 Subject: [PATCH 8/8] zxc --- pkg/cache/cache.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index c6b7931..0eabad0 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -60,7 +60,8 @@ func (k Key) String() string { } type Cache struct { - logger *slog.Logger + logger *slog.Logger + data map[Namespace]Data path string mutex sync.RWMutex @@ -142,7 +143,7 @@ func (c *Cache) Update(entry Entry) { } func (c *Cache) Load() error { - c.logger.Debug("Loading cache", "path", c.path) + c.logger.Debug("Loading cache from path...", "path", c.path) namespaces, err := c.getNamespacesFromCacheFiles() if err != nil { return err @@ -202,7 +203,6 @@ func (c *Cache) Set(namespace Namespace, key Key, value interface{}) { data := c.getNamespace(namespace) ts := time.Now().Unix() - c.mutex.Lock() data[key] = Entry{