plugin: wire in plugin loader for node creation

License: MIT
Signed-off-by: Kacper Łukawski <kacluk98@gmail.com>
This commit is contained in:
Kacper Łukawski 2018-03-10 21:40:46 +01:00 committed by Steven Allen
parent d0c27272ad
commit a1e654cd38
6 changed files with 175 additions and 147 deletions

View File

@ -51,6 +51,33 @@ const (
heapProfile = "ipfs.memprof"
)
func loadPlugins(repoPath string) (*loader.PluginLoader, error) {
pluginpath := filepath.Join(repoPath, "plugins")
// check if repo is accessible before loading plugins
var plugins *loader.PluginLoader
ok, err := checkPermissions(repoPath)
if err != nil {
return nil, err
}
if !ok {
pluginpath = ""
}
plugins, err = loader.NewPluginLoader(pluginpath)
if err != nil {
log.Error("error loading plugins: ", err)
}
if err := plugins.Initialize(); err != nil {
log.Error("error initializing plugins: ", err)
}
if err := plugins.Run(); err != nil {
log.Error("error running plugins: ", err)
}
return plugins, nil
}
// main roadmap:
// - parse the commandline to get a cmdInvocation
// - if user requests help, print it and exit.
@ -116,12 +143,18 @@ func mainRet() int {
}
log.Debugf("config path is %s", repoPath)
plugins, err := loadPlugins(repoPath)
if err != nil {
return nil, err
}
// this sets up the function that will initialize the node
// this is so that we can construct the node lazily.
return &oldcmds.Context{
ConfigRoot: repoPath,
LoadConfig: loadConfig,
ReqLog: &oldcmds.ReqLog{},
Plugins: plugins,
ConstructNode: func() (n *core.IpfsNode, err error) {
if req == nil {
return nil, errors.New("constructing node without a request")
@ -179,21 +212,6 @@ func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
if client != nil && !req.Command.External {
exctr = client.(cmds.Executor)
} else {
cctx := env.(*oldcmds.Context)
pluginpath := filepath.Join(cctx.ConfigRoot, "plugins")
// check if repo is accessible before loading plugins
ok, err := checkPermissions(cctx.ConfigRoot)
if err != nil {
return nil, err
}
if !ok {
pluginpath = ""
}
if _, err := loader.LoadPlugins(pluginpath); err != nil {
log.Error("error loading plugins: ", err)
}
exctr = cmds.NewExecutor(req.Root)
}

View File

@ -6,9 +6,10 @@ import (
"strings"
"time"
"github.com/ipfs/go-ipfs/core"
core "github.com/ipfs/go-ipfs/core"
coreapi "github.com/ipfs/go-ipfs/core/coreapi"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
loader "github.com/ipfs/go-ipfs/plugin/loader"
"gx/ipfs/QmPdvMtgpnMuU68mWhGtzCxnddXJoV96tT9aPcNbQsqPaM/go-ipfs-cmds"
config "gx/ipfs/QmYyzmMnhNTtoXx5ttgUaRdHHckYnQWjPL98hgLAR2QLDD/go-ipfs-config"
@ -23,6 +24,8 @@ type Context struct {
ConfigRoot string
ReqLog *ReqLog
Plugins *loader.PluginLoader
config *config.Config
LoadConfig func(path string) (*config.Config, error)

View File

@ -1,63 +0,0 @@
package loader
import (
"github.com/ipfs/go-ipfs/core/coredag"
"github.com/ipfs/go-ipfs/plugin"
"github.com/ipfs/go-ipfs/repo/fsrepo"
"gx/ipfs/QmWLWmRVSiagqP15jczsGME1qpob6HDbtbHAY2he9W5iUo/opentracing-go"
ipld "gx/ipfs/QmcKKBwfz6FyQdHR2jsXrrF6XeSBXYL86anmWNewpFpoF5/go-ipld-format"
)
func initialize(plugins []plugin.Plugin) error {
for _, p := range plugins {
err := p.Init()
if err != nil {
return err
}
}
return nil
}
func run(plugins []plugin.Plugin) error {
for _, pl := range plugins {
switch pl := pl.(type) {
case plugin.PluginIPLD:
err := runIPLDPlugin(pl)
if err != nil {
return err
}
case plugin.PluginTracer:
err := runTracerPlugin(pl)
if err != nil {
return err
}
case plugin.PluginDatastore:
err := fsrepo.AddDatastoreConfigHandler(pl.DatastoreTypeName(), pl.DatastoreConfigParser())
if err != nil {
return err
}
default:
panic(pl)
}
}
return nil
}
func runIPLDPlugin(pl plugin.PluginIPLD) error {
err := pl.RegisterBlockDecoders(ipld.DefaultBlockDecoder)
if err != nil {
return err
}
return pl.RegisterInputEncParsers(coredag.DefaultInputEncParsers)
}
func runTracerPlugin(pl plugin.PluginTracer) error {
tracer, err := pl.InitTracer()
if err != nil {
return err
}
opentracing.SetGlobalTracer(tracer)
return nil
}

View File

@ -1,67 +0,0 @@
package loader
import (
"fmt"
"os"
"github.com/ipfs/go-ipfs/plugin"
logging "gx/ipfs/QmcuXC5cxs79ro2cUuHs4HQ2bkDLJUYokwL8aivcX6HW3C/go-log"
)
var log = logging.Logger("plugin/loader")
var loadPluginsFunc = func(string) ([]plugin.Plugin, error) {
return nil, nil
}
// LoadPlugins loads and initializes plugins.
func LoadPlugins(pluginDir string) ([]plugin.Plugin, error) {
plMap := make(map[string]plugin.Plugin)
for _, v := range preloadPlugins {
plMap[v.Name()] = v
}
if pluginDir != "" {
newPls, err := loadDynamicPlugins(pluginDir)
if err != nil {
return nil, err
}
for _, pl := range newPls {
if ppl, ok := plMap[pl.Name()]; ok {
// plugin is already preloaded
return nil, fmt.Errorf(
"plugin: %s, is duplicated in version: %s, "+
"while trying to load dynamically: %s",
ppl.Name(), ppl.Version(), pl.Version())
}
plMap[pl.Name()] = pl
}
}
pls := make([]plugin.Plugin, 0, len(plMap))
for _, v := range plMap {
pls = append(pls, v)
}
err := initialize(pls)
if err != nil {
return nil, err
}
err = run(pls)
return nil, err
}
func loadDynamicPlugins(pluginDir string) ([]plugin.Plugin, error) {
_, err := os.Stat(pluginDir)
if os.IsNotExist(err) {
return nil, nil
}
if err != nil {
return nil, err
}
return loadPluginsFunc(pluginDir)
}

125
plugin/loader/loader.go Normal file
View File

@ -0,0 +1,125 @@
package loader
import (
"fmt"
"github.com/ipfs/go-ipfs/core/coredag"
"github.com/ipfs/go-ipfs/plugin"
"github.com/ipfs/go-ipfs/repo/fsrepo"
"os"
opentracing "gx/ipfs/QmWLWmRVSiagqP15jczsGME1qpob6HDbtbHAY2he9W5iUo/opentracing-go"
ipld "gx/ipfs/QmcKKBwfz6FyQdHR2jsXrrF6XeSBXYL86anmWNewpFpoF5/go-ipld-format"
logging "gx/ipfs/QmcuXC5cxs79ro2cUuHs4HQ2bkDLJUYokwL8aivcX6HW3C/go-log"
)
var log = logging.Logger("plugin/loader")
var loadPluginsFunc = func(string) ([]plugin.Plugin, error) {
return nil, nil
}
// PluginLoader keeps track of loaded plugins
type PluginLoader struct {
plugins []plugin.Plugin
}
// NewPluginLoader creates new plugin loader
func NewPluginLoader(pluginDir string) (*PluginLoader, error) {
plMap := make(map[string]plugin.Plugin)
for _, v := range preloadPlugins {
plMap[v.Name()] = v
}
if pluginDir != "" {
newPls, err := loadDynamicPlugins(pluginDir)
if err != nil {
return nil, err
}
for _, pl := range newPls {
if ppl, ok := plMap[pl.Name()]; ok {
// plugin is already preloaded
return nil, fmt.Errorf(
"plugin: %s, is duplicated in version: %s, "+
"while trying to load dynamically: %s",
ppl.Name(), ppl.Version(), pl.Version())
}
plMap[pl.Name()] = pl
}
}
loader := &PluginLoader{plugins: make([]plugin.Plugin, 0, len(plMap))}
for _, v := range plMap {
loader.plugins = append(loader.plugins, v)
}
return loader, nil
}
func loadDynamicPlugins(pluginDir string) ([]plugin.Plugin, error) {
_, err := os.Stat(pluginDir)
if os.IsNotExist(err) {
return nil, nil
}
if err != nil {
return nil, err
}
return loadPluginsFunc(pluginDir)
}
//Initialize all loaded plugins
func (loader *PluginLoader) Initialize() error {
for _, p := range loader.plugins {
err := p.Init()
if err != nil {
return err
}
}
return nil
}
//Run the plugins
func (loader *PluginLoader) Run() error {
for _, pl := range loader.plugins {
switch pl := pl.(type) {
case plugin.PluginIPLD:
err := runIPLDPlugin(pl)
if err != nil {
return err
}
case plugin.PluginTracer:
err := runTracerPlugin(pl)
if err != nil {
return err
}
case plugin.PluginDatastore:
err := fsrepo.AddDatastoreConfigHandler(pl.DatastoreTypeName(), pl.DatastoreConfigParser())
if err != nil {
return err
}
default:
panic(pl)
}
}
return nil
}
func runIPLDPlugin(pl plugin.PluginIPLD) error {
err := pl.RegisterBlockDecoders(ipld.DefaultBlockDecoder)
if err != nil {
return err
}
return pl.RegisterInputEncParsers(coredag.DefaultInputEncParsers)
}
func runTracerPlugin(pl plugin.PluginTracer) error {
tracer, err := pl.InitTracer()
if err != nil {
return err
}
opentracing.SetGlobalTracer(tracer)
return nil
}

View File

@ -75,7 +75,19 @@ var measureConfig = []byte(`{
}`)
func TestDefaultDatastoreConfig(t *testing.T) {
loader.LoadPlugins("")
loader, err := loader.NewPluginLoader("")
if err != nil {
t.Fatal(err)
}
err = loader.Initialize()
if err != nil {
t.Fatal(err)
}
err = loader.Run()
if err != nil {
t.Fatal(err)
}
dir, err := ioutil.TempDir("", "ipfs-datastore-config-test")
if err != nil {