package tomo import "os" import "plugin" import "path/filepath" var pluginPaths []string func loadPlugins () { for _, dir := range pluginPaths { if dir != "" { loadPluginsFrom(dir) } } } func loadPluginsFrom (dir string) { entries, err := os.ReadDir(dir) // its no big deal if one of the dirs doesn't exist if err != nil { return } for _, entry := range entries { if entry.IsDir() { continue } if filepath.Ext(entry.Name()) != ".so" { continue } pluginPath := filepath.Join(dir, entry.Name()) loadPlugin(pluginPath) } } func loadPlugin (path string) { die := func (reason string) { println("tomo: could not load plugin at", path + ":", reason) } plugin, err := plugin.Open(path) if err != nil { die(err.Error()) return } // check for and obtain basic plugin functions name, ok := extract[func () string](plugin, "Name") if !ok { die("does not implement Name() string"); return } _, ok = extract[func () string](plugin, "Description") if !ok { die("does not implement Description() string"); return } println("tomo: loaded plugin", name()) } func extract[T any] (plugin *plugin.Plugin, name string) (value T, ok bool) { symbol, err := plugin.Lookup(name) if err != nil { return } value, ok = symbol.(T) return }