package bookmarks import ( "io" "os" "strings" "github.com/fsnotify/fsnotify" folderCreate "github.com/unjx-de/go-folder" "go.uber.org/zap" "gopkg.in/yaml.v3" ) const StorageDir = "storage/" const IconsDir = StorageDir + "icons/" const bookmarksFolder = "internal/bookmarks/" const configFile = "config.yaml" func NewBookmarkService() *Config { c := Config{} c.createFolderStructure() c.copyDefaultConfigIfNotExisting() c.parseBookmarks() go c.watchBookmarks() return &c } func (c *Config) createFolderStructure() { folders := []string{StorageDir, IconsDir} err := folderCreate.CreateFolders(folders, 0755) if err != nil { zap.L().Fatal("cannot create folder", zap.Error(err)) } zap.L().Debug("folders created", zap.Strings("folders", folders)) } func (c *Config) copyDefaultConfigIfNotExisting() { _, err := os.Open(StorageDir + configFile) if err != nil { zap.L().Debug(configFile + " not existing, creating...") source, _ := os.Open(bookmarksFolder + configFile) defer source.Close() destination, err := os.Create(StorageDir + configFile) if err != nil { zap.L().Error(err.Error()) return } defer destination.Close() _, err = io.Copy(destination, source) if err != nil { zap.L().Error(err.Error()) return } zap.L().Debug(configFile + " created") } else { zap.L().Debug(configFile + " existing, skipping creation") } } func (c *Config) readBookmarksFile() []byte { file, err := os.Open(StorageDir + configFile) if err != nil { zap.L().Error(err.Error()) return nil } defer file.Close() byteValue, err := io.ReadAll(file) if err != nil { zap.L().Error(err.Error()) return nil } return byteValue } func (c *Config) replaceIconString() { for _, v := range c.Parsed.Applications { for i, bookmark := range v.Entries { if !strings.Contains(bookmark.Icon, "http") { v.Entries[i].Icon = "/" + IconsDir + bookmark.Icon } } } } func (c *Config) parseBookmarks() { byteValue := c.readBookmarksFile() err := yaml.Unmarshal(byteValue, &c.Parsed) if err != nil { zap.L().Error(err.Error()) return } c.replaceIconString() } func (c *Config) watchBookmarks() { watcher, err := fsnotify.NewWatcher() if err != nil { zap.L().Error(err.Error()) } defer watcher.Close() done := make(chan bool) go func() { for { select { case _ = <-watcher.Events: c.parseBookmarks() zap.L().Debug("bookmarks changed", zap.Int("applications", len(c.Parsed.Applications)), zap.Int("links", len(c.Parsed.Links))) case err := <-watcher.Errors: zap.L().Error(err.Error()) } } }() if err := watcher.Add(StorageDir + configFile); err != nil { zap.L().Fatal("cannot add watcher") } <-done }