Skip to main content
Glama
orneryd

M.I.M.I.R - Multi-agent Intelligent Memory & Insight Repository

by orneryd
plugin.go4.94 kB
// Package plugin provides a plugin system for loading APOC function packages. // // This package allows APOC function packages to be loaded/unloaded at runtime, // enabling dynamic extension of Cypher query capabilities. package plugin import ( "fmt" "sync" "github.com/orneryd/nornicdb/apoc/registry" "github.com/orneryd/nornicdb/apoc/storage" ) // Plugin represents a loadable APOC function package. type Plugin interface { // Name returns the plugin name (e.g., "coll", "text", "math") Name() string // Version returns the plugin version Version() string // Description returns a description of the plugin Description() string // Register registers all functions in this plugin Register(reg *registry.FunctionRegistry) error // Initialize initializes the plugin with storage Initialize(store storage.Storage) error // Cleanup cleans up plugin resources Cleanup() error } // PluginManager manages loaded plugins. type PluginManager struct { plugins map[string]Plugin storage storage.Storage mu sync.RWMutex } // NewPluginManager creates a new plugin manager. func NewPluginManager(store storage.Storage) *PluginManager { return &PluginManager{ plugins: make(map[string]Plugin), storage: store, } } // Load loads a plugin and registers its functions. func (pm *PluginManager) Load(plugin Plugin) error { pm.mu.Lock() defer pm.mu.Unlock() name := plugin.Name() if _, exists := pm.plugins[name]; exists { return fmt.Errorf("plugin %s already loaded", name) } // Initialize plugin with storage if err := plugin.Initialize(pm.storage); err != nil { return fmt.Errorf("failed to initialize plugin %s: %w", name, err) } // Register functions if err := plugin.Register(registry.GetGlobalRegistry()); err != nil { return fmt.Errorf("failed to register plugin %s: %w", name, err) } pm.plugins[name] = plugin return nil } // Unload unloads a plugin and unregisters its functions. func (pm *PluginManager) Unload(name string) error { pm.mu.Lock() defer pm.mu.Unlock() plugin, exists := pm.plugins[name] if !exists { return fmt.Errorf("plugin %s not loaded", name) } // Cleanup plugin if err := plugin.Cleanup(); err != nil { return fmt.Errorf("failed to cleanup plugin %s: %w", name, err) } // Unregister functions reg := registry.GetGlobalRegistry() for _, funcName := range reg.ListByCategory(name) { reg.Unregister(funcName) } delete(pm.plugins, name) return nil } // IsLoaded checks if a plugin is loaded. func (pm *PluginManager) IsLoaded(name string) bool { pm.mu.RLock() defer pm.mu.RUnlock() _, exists := pm.plugins[name] return exists } // List returns all loaded plugin names. func (pm *PluginManager) List() []string { pm.mu.RLock() defer pm.mu.RUnlock() names := make([]string, 0, len(pm.plugins)) for name := range pm.plugins { names = append(names, name) } return names } // Get retrieves a loaded plugin. func (pm *PluginManager) Get(name string) (Plugin, bool) { pm.mu.RLock() defer pm.mu.RUnlock() plugin, exists := pm.plugins[name] return plugin, exists } // LoadAll loads multiple plugins. func (pm *PluginManager) LoadAll(plugins []Plugin) error { for _, plugin := range plugins { if err := pm.Load(plugin); err != nil { return err } } return nil } // UnloadAll unloads all plugins. func (pm *PluginManager) UnloadAll() error { pm.mu.Lock() names := make([]string, 0, len(pm.plugins)) for name := range pm.plugins { names = append(names, name) } pm.mu.Unlock() for _, name := range names { if err := pm.Unload(name); err != nil { return err } } return nil } // PluginInfo returns information about a loaded plugin. type PluginInfo struct { Name string Version string Description string Functions []string } // Info returns information about a loaded plugin. func (pm *PluginManager) Info(name string) (*PluginInfo, error) { pm.mu.RLock() plugin, exists := pm.plugins[name] pm.mu.RUnlock() if !exists { return nil, fmt.Errorf("plugin %s not loaded", name) } reg := registry.GetGlobalRegistry() functions := reg.ListByCategory(name) return &PluginInfo{ Name: plugin.Name(), Version: plugin.Version(), Description: plugin.Description(), Functions: functions, }, nil } // AllInfo returns information about all loaded plugins. func (pm *PluginManager) AllInfo() []*PluginInfo { pm.mu.RLock() defer pm.mu.RUnlock() infos := make([]*PluginInfo, 0, len(pm.plugins)) for name := range pm.plugins { if info, err := pm.Info(name); err == nil { infos = append(infos, info) } } return infos } // Global plugin manager instance var globalManager *PluginManager var managerOnce sync.Once // GetGlobalManager returns the global plugin manager. func GetGlobalManager(store storage.Storage) *PluginManager { managerOnce.Do(func() { globalManager = NewPluginManager(store) }) return globalManager }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/orneryd/Mimir'

If you have feedback or need assistance with the MCP directory API, please join our Discord server