Added a plugin repository, stabilized

This commit is contained in:
diamondburned (Forefront) 2020-05-22 16:43:28 -07:00
parent 519066e136
commit 251f975dc7
4 changed files with 122 additions and 0 deletions

2
go.mod
View File

@ -1,3 +1,5 @@
module github.com/diamondburned/cchat
go 1.14
require github.com/pkg/errors v0.9.1

2
go.sum Normal file
View File

@ -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=

View File

@ -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
}

55
services/services.go Normal file
View File

@ -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
}