Added a plugin repository, stabilized
This commit is contained in:
parent
519066e136
commit
251f975dc7
2
go.mod
2
go.mod
|
@ -1,3 +1,5 @@
|
||||||
module github.com/diamondburned/cchat
|
module github.com/diamondburned/cchat
|
||||||
|
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
|
require github.com/pkg/errors v0.9.1
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
@ -0,0 +1,63 @@
|
||||||
|
// Package plugins provides a source for cchat services as Go plugins. This
|
||||||
|
// package looks in UserConfigDir()/cchat/plugins/ by default.
|
||||||
|
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 {
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Package services provides a global repository of cchat services. It also
|
||||||
|
// supports additional sources.
|
||||||
|
//
|
||||||
|
// Registering services
|
||||||
|
//
|
||||||
|
// To register a service, it's best to call RegisterService() in the package's
|
||||||
|
// init(). This allows for dash imports:
|
||||||
|
//
|
||||||
|
// _ "git.sr.ht/~user/cchat-abc"
|
||||||
|
//
|
||||||
|
// Registering sources
|
||||||
|
//
|
||||||
|
// Sources are simply functions that manage other services. An example of this
|
||||||
|
// would be the plugins package. Note that only packages that can error out on
|
||||||
|
// load should do this. A package can call RegisterService() multiple times.
|
||||||
|
//
|
||||||
|
// For examples on using RegisterSource(), check the plugins package.
|
||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/diamondburned/cchat"
|
||||||
|
)
|
||||||
|
|
||||||
|
var services []cchat.Service
|
||||||
|
|
||||||
|
// RegisterService adds a service.
|
||||||
|
func RegisterService(service ...cchat.Service) {
|
||||||
|
services = append(services, service...)
|
||||||
|
}
|
||||||
|
|
||||||
|
var sources []func() []error
|
||||||
|
var sourceErrs []error
|
||||||
|
var sourceOnce sync.Once
|
||||||
|
|
||||||
|
// RegisterSource adds a service source. Services are expected to call
|
||||||
|
// RegisterService() on source().
|
||||||
|
func RegisterSource(source func() []error) {
|
||||||
|
sources = append(sources, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns all services. It will also fetch the plugins from all sources.
|
||||||
|
// Future calls will not fetch the plugins again.
|
||||||
|
func Get() ([]cchat.Service, []error) {
|
||||||
|
sourceOnce.Do(func() {
|
||||||
|
sourceErrs = []error{} // mark as non-nil
|
||||||
|
for _, src := range sources {
|
||||||
|
sourceErrs = append(sourceErrs, src()...)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// why are we here, just to suffer
|
||||||
|
return services, sourceErrs
|
||||||
|
}
|
Loading…
Reference in New Issue