cchat/services/plugins/plugins.go

79 lines
1.7 KiB
Go

// Package plugins provides a source for cchat services as Go plugins. This
// package looks in UserConfigDir()/cchat/plugins/ by default.
//
// Usage
//
// The package can easily be used by just dash importing it:
//
// _ "github.com/diamondburned/cchat/services/plugins"
//
package plugins
import (
"io/ioutil"
"os"
"path/filepath"
"plugin"
"github.com/diamondburned/cchat/services"
"github.com/pkg/errors"
)
var pluginPath string
// SetPluginPath sets the plugin path before loading plugins. This only works
// until LoadPlugins is called.
func SetPluginPath(path string) {
pluginPath = path
}
// TryConfigPath returns a path to $cfgDir/suffix. cfgDir is from
// os.UserConfigDir.
func TryConfigPath(suffix ...string) (string, error) {
d, err := os.UserConfigDir()
if err != nil {
return "", err
}
return filepath.Join(append([]string{d}, suffix...)...), nil
}
func init() {
services.RegisterSource(loadPlugins)
}
func loadPlugins() (errs []error) {
if pluginPath == "" {
p, err := TryConfigPath("cchat", "plugins")
if err != nil {
errs = []error{errors.Wrap(err, "Failed to get config path")}
return
}
pluginPath = p
}
d, err := ioutil.ReadDir(pluginPath)
if err != nil {
// If the directory does not exist, then make one and exit.
if os.IsNotExist(err) {
if err := os.MkdirAll(pluginPath, 0755); err != nil {
errs = []error{errors.Wrap(err, "Failed to make plugins dir")}
}
return
}
errs = []error{errors.Wrap(err, "Failed to read plugin path")}
return
}
for _, f := range d {
// We only need the plugin to call its init() function.
_, err := plugin.Open(filepath.Join(pluginPath, f.Name()))
if err != nil {
errs = append(errs, errors.Wrap(err, "Failed to open plugin"))
continue
}
}
return
}