package plugin import ( "encoding/json" "fmt" "os" "path" "sync" ) const databaseFile = pluginsFolder + "/plugins.json" type PluginDatabase struct { // Map with the plugin name as the key Plugins map[string]*PluginInstall `json:"plugins"` saveMutex sync.Mutex } var pluginDatabase = PluginDatabase{} func (d *PluginDatabase) Load() error { file, err := os.Open(databaseFile) if os.IsNotExist(err) { d.Plugins = make(map[string]*PluginInstall) return nil } if err != nil { return fmt.Errorf("failed to open plugin database: %v", err) } defer file.Close() if err := json.NewDecoder(file).Decode(d); err != nil { return fmt.Errorf("failed to decode plugin database: %v", err) } return nil } func (d *PluginDatabase) Save() error { d.saveMutex.Lock() defer d.saveMutex.Unlock() file, err := os.Create(databaseFile + ".tmp") if err != nil { return fmt.Errorf("failed to create plugin database tmp: %v", err) } defer file.Close() encoder := json.NewEncoder(file) encoder.SetIndent("", " ") if err := encoder.Encode(d); err != nil { return fmt.Errorf("failed to encode plugin database: %v", err) } if err := os.Rename(databaseFile+".tmp", databaseFile); err != nil { return fmt.Errorf("failed to move plugin database to active file: %v", err) } return nil } // Find all extract directories that are not referenced in the Plugins map and remove them func (d *PluginDatabase) CleanupExtractDirectories() error { extractDirectories, err := os.ReadDir(pluginsExtractsFolder) if err != nil { return fmt.Errorf("failed to read extract directories: %v", err) } for _, extractDir := range extractDirectories { found := false for _, pluginInstall := range d.Plugins { for _, extractedFolder := range pluginInstall.ExtractedVersions { if extractDir.Name() == extractedFolder { found = true break } } if found { break } } if !found { if err := os.RemoveAll(path.Join(pluginsExtractsFolder, extractDir.Name())); err != nil { return fmt.Errorf("failed to remove extract directory: %v", err) } } } return nil }