mirror of
https://github.com/navidrome/navidrome.git
synced 2026-05-03 06:51:16 +00:00
feat(plugins): optimize plugin change detection
Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
parent
2cc29793a6
commit
2cfa902123
@ -398,6 +398,22 @@ type PluginMetadata struct {
|
||||
SHA256 string
|
||||
}
|
||||
|
||||
// computeFileSHA256 computes the SHA-256 hash of a file without loading it into memory.
|
||||
// This is used for quick change detection before full plugin compilation.
|
||||
func computeFileSHA256(path string) (string, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
h := sha256.New()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// compiledPluginInfo holds the intermediate compilation result used by both
|
||||
// ExtractManifest and loadPluginWithConfig.
|
||||
type compiledPluginInfo struct {
|
||||
@ -549,11 +565,35 @@ func (m *Manager) SyncPlugins(ctx context.Context, folder string) error {
|
||||
|
||||
// Process files on disk
|
||||
for name, path := range filesOnDisk {
|
||||
dbPlugin, exists := pluginsInDB[name]
|
||||
|
||||
// Compute SHA256 first (lightweight operation) to check if plugin changed
|
||||
sha256Hash, err := computeFileSHA256(path)
|
||||
if err != nil {
|
||||
log.Error(ctx, "Failed to compute SHA256 for plugin", "plugin", name, "path", path, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// If plugin exists in DB with same hash, skip full manifest extraction
|
||||
if exists && dbPlugin.SHA256 == sha256Hash {
|
||||
// Plugin unchanged - just update path in case folder moved
|
||||
if dbPlugin.Path != path {
|
||||
dbPlugin.Path = path
|
||||
dbPlugin.UpdatedAt = now
|
||||
if err := repo.Put(dbPlugin); err != nil {
|
||||
log.Error(ctx, "Failed to update plugin path in DB", "plugin", name, err)
|
||||
}
|
||||
}
|
||||
delete(pluginsInDB, name)
|
||||
continue
|
||||
}
|
||||
|
||||
// Plugin is new or changed - need full manifest extraction
|
||||
metadata, err := m.ExtractManifest(path)
|
||||
if err != nil {
|
||||
log.Error(ctx, "Failed to extract manifest from plugin", "plugin", name, "path", path, err)
|
||||
// Store error in DB if plugin exists
|
||||
if dbPlugin, exists := pluginsInDB[name]; exists {
|
||||
if exists {
|
||||
dbPlugin.LastError = err.Error()
|
||||
dbPlugin.UpdatedAt = now
|
||||
if dbPlugin.Enabled {
|
||||
@ -567,29 +607,20 @@ func (m *Manager) SyncPlugins(ctx context.Context, folder string) error {
|
||||
log.Error(ctx, "Failed to update plugin in DB", "plugin", name, err)
|
||||
}
|
||||
}
|
||||
delete(pluginsInDB, name)
|
||||
continue
|
||||
}
|
||||
|
||||
dbPlugin, exists := pluginsInDB[name]
|
||||
if !exists {
|
||||
// New plugin - add to DB as disabled
|
||||
if err := m.addPluginToDB(ctx, repo, name, path, metadata); err != nil {
|
||||
log.Error(ctx, "Failed to add plugin to DB", "plugin", name, err)
|
||||
}
|
||||
} else if dbPlugin.SHA256 != metadata.SHA256 {
|
||||
} else {
|
||||
// Plugin changed - update DB
|
||||
if err := m.updatePluginInDB(ctx, repo, dbPlugin, path, metadata); err != nil {
|
||||
log.Error(ctx, "Failed to update plugin in DB", "plugin", name, err)
|
||||
}
|
||||
} else {
|
||||
// Plugin unchanged - update path in case folder moved
|
||||
if dbPlugin.Path != path {
|
||||
dbPlugin.Path = path
|
||||
dbPlugin.UpdatedAt = now
|
||||
if err := repo.Put(dbPlugin); err != nil {
|
||||
log.Error(ctx, "Failed to update plugin path in DB", "plugin", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Mark as processed
|
||||
delete(pluginsInDB, name)
|
||||
|
||||
@ -164,37 +164,47 @@ func (m *Manager) processPluginEvent(pluginName string, eventType notify.Event)
|
||||
}
|
||||
|
||||
case actionUpdate:
|
||||
// File changed - extract manifest, update DB, disable if enabled
|
||||
metadata, err := m.ExtractManifest(wasmPath)
|
||||
// File changed - check SHA256 first, then extract manifest if needed
|
||||
sha256Hash, err := computeFileSHA256(wasmPath)
|
||||
if err != nil {
|
||||
log.Error(m.ctx, "Failed to extract manifest from changed plugin", "plugin", pluginName, err)
|
||||
// Try to update error in DB if plugin exists
|
||||
if dbPlugin, getErr := repo.Get(pluginName); getErr == nil {
|
||||
dbPlugin.LastError = err.Error()
|
||||
dbPlugin.UpdatedAt = time.Now()
|
||||
if dbPlugin.Enabled {
|
||||
_ = m.UnloadPlugin(pluginName)
|
||||
dbPlugin.Enabled = false
|
||||
}
|
||||
_ = repo.Put(dbPlugin)
|
||||
}
|
||||
log.Error(m.ctx, "Failed to compute SHA256 for changed plugin", "plugin", pluginName, err)
|
||||
return
|
||||
}
|
||||
|
||||
dbPlugin, err := repo.Get(pluginName)
|
||||
if err != nil {
|
||||
// Plugin not in DB yet, add it
|
||||
// Plugin not in DB yet, need full manifest extraction to add it
|
||||
metadata, extractErr := m.ExtractManifest(wasmPath)
|
||||
if extractErr != nil {
|
||||
log.Error(m.ctx, "Failed to extract manifest from new plugin", "plugin", pluginName, extractErr)
|
||||
return
|
||||
}
|
||||
if addErr := m.addPluginToDB(m.ctx, repo, pluginName, wasmPath, metadata); addErr != nil {
|
||||
log.Error(m.ctx, "Failed to add plugin to DB", "plugin", pluginName, addErr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Check if actually changed
|
||||
if dbPlugin.SHA256 == metadata.SHA256 {
|
||||
// Check if actually changed using lightweight SHA256 comparison
|
||||
if dbPlugin.SHA256 == sha256Hash {
|
||||
return // No actual change
|
||||
}
|
||||
|
||||
// Plugin changed - now extract full manifest
|
||||
metadata, err := m.ExtractManifest(wasmPath)
|
||||
if err != nil {
|
||||
log.Error(m.ctx, "Failed to extract manifest from changed plugin", "plugin", pluginName, err)
|
||||
// Update error in DB
|
||||
dbPlugin.LastError = err.Error()
|
||||
dbPlugin.UpdatedAt = time.Now()
|
||||
if dbPlugin.Enabled {
|
||||
_ = m.UnloadPlugin(pluginName)
|
||||
dbPlugin.Enabled = false
|
||||
}
|
||||
_ = repo.Put(dbPlugin)
|
||||
return
|
||||
}
|
||||
|
||||
if err := m.updatePluginInDB(m.ctx, repo, dbPlugin, wasmPath, metadata); err != nil {
|
||||
log.Error(m.ctx, "Failed to update plugin in DB", "plugin", pluginName, err)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user