| 336 | } |
| 337 | |
| 338 | func (h *Host) withLoadedPluginFallbacks(files []pluginFile, items map[string]runtimeItemConfig, desired map[string]string) []pluginFile { |
| 339 | if h == nil || len(desired) == 0 { |
| 340 | return files |
| 341 | } |
| 342 | selected := make(map[string]struct{}, len(files)) |
| 343 | for _, file := range files { |
| 344 | id := strings.TrimSpace(file.ID) |
| 345 | if id != "" { |
| 346 | selected[id] = struct{}{} |
| 347 | } |
| 348 | } |
| 349 | ids := make([]string, 0, len(desired)) |
| 350 | for id := range desired { |
| 351 | ids = append(ids, id) |
| 352 | } |
| 353 | sort.Strings(ids) |
| 354 | |
| 355 | h.mu.Lock() |
| 356 | defer h.mu.Unlock() |
| 357 | for _, id := range ids { |
| 358 | if _, ok := selected[id]; ok { |
| 359 | continue |
| 360 | } |
| 361 | if item, ok := items[id]; ok && !item.Enabled { |
| 362 | continue |
| 363 | } |
| 364 | lp := h.loaded[id] |
| 365 | if lp == nil || strings.TrimSpace(lp.path) == "" { |
| 366 | continue |
| 367 | } |
| 368 | files = append(files, pluginFile{ |
| 369 | ID: id, |
| 370 | Path: lp.path, |
| 371 | Version: strings.TrimSpace(lp.version), |
| 372 | }) |
| 373 | selected[id] = struct{}{} |
| 374 | } |
| 375 | return files |
| 376 | } |
| 377 | |
| 378 | // UnloadPlugin removes one plugin from the active runtime and closes its dynamic library. |
| 379 | func (h *Host) UnloadPlugin(id string) bool { |