diff options
Diffstat (limited to 'plugin/supervisor.go')
-rw-r--r-- | plugin/supervisor.go | 101 |
1 files changed, 93 insertions, 8 deletions
diff --git a/plugin/supervisor.go b/plugin/supervisor.go index f20df7040..58a7aa783 100644 --- a/plugin/supervisor.go +++ b/plugin/supervisor.go @@ -1,13 +1,98 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. +// See LICENSE.txt for license information. package plugin -// Supervisor provides the interface for an object that controls the execution of a plugin. This -// type is only relevant to the server, and isn't used by the plugins themselves. -type Supervisor interface { - Start(API) error - Wait() error - Stop() error - Hooks() Hooks +import ( + "fmt" + "os/exec" + "path/filepath" + "strings" + "time" + + "github.com/hashicorp/go-plugin" + "github.com/mattermost/mattermost-server/mlog" + "github.com/mattermost/mattermost-server/model" +) + +type Supervisor struct { + pluginId string + client *plugin.Client + hooks Hooks + implemented [TotalHooksId]bool +} + +func NewSupervisor(pluginInfo *model.BundleInfo, parentLogger *mlog.Logger, apiImpl API) (*Supervisor, error) { + supervisor := Supervisor{} + + wrappedLogger := pluginInfo.WrapLogger(parentLogger) + + hclogAdaptedLogger := &HclogAdapter{ + wrappedLogger: wrappedLogger.WithCallerSkip(1), + extrasKey: "wrapped_extras", + } + + pluginMap := map[string]plugin.Plugin{ + "hooks": &HooksPlugin{ + log: wrappedLogger, + apiImpl: apiImpl, + }, + } + + executable := filepath.Clean(filepath.Join(".", pluginInfo.Manifest.Backend.Executable)) + if strings.HasPrefix(executable, "..") { + return nil, fmt.Errorf("invalid backend executable") + } + executable = filepath.Join(pluginInfo.Path, executable) + + supervisor.client = plugin.NewClient(&plugin.ClientConfig{ + HandshakeConfig: Handshake, + Plugins: pluginMap, + Cmd: exec.Command(executable), + SyncStdout: wrappedLogger.With(mlog.String("source", "plugin_stdout")).StdLogWriter(), + SyncStderr: wrappedLogger.With(mlog.String("source", "plugin_stderr")).StdLogWriter(), + Logger: hclogAdaptedLogger, + StartTimeout: time.Second * 3, + }) + + rpcClient, err := supervisor.client.Client() + if err != nil { + return nil, err + } + + raw, err := rpcClient.Dispense("hooks") + if err != nil { + return nil, err + } + + supervisor.hooks = raw.(Hooks) + + if impl, err := supervisor.hooks.Implemented(); err != nil { + return nil, err + } else { + for _, hookName := range impl { + if hookId, ok := HookNameToId[hookName]; ok { + supervisor.implemented[hookId] = true + } + } + } + + err = supervisor.Hooks().OnActivate() + if err != nil { + return nil, err + } + + return &supervisor, nil +} + +func (sup *Supervisor) Shutdown() { + sup.client.Kill() +} + +func (sup *Supervisor) Hooks() Hooks { + return sup.hooks +} + +func (sup *Supervisor) Implements(hookId int) bool { + return sup.implemented[hookId] } |