github.com/levb/mattermost-server@v5.3.1+incompatible/plugin/supervisor.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package plugin 5 6 import ( 7 "fmt" 8 "os/exec" 9 "path/filepath" 10 "runtime" 11 "strings" 12 "time" 13 14 "github.com/hashicorp/go-plugin" 15 "github.com/mattermost/mattermost-server/mlog" 16 "github.com/mattermost/mattermost-server/model" 17 ) 18 19 type supervisor struct { 20 pluginId string 21 client *plugin.Client 22 hooks Hooks 23 implemented [TotalHooksId]bool 24 } 25 26 func newSupervisor(pluginInfo *model.BundleInfo, parentLogger *mlog.Logger, apiImpl API) (retSupervisor *supervisor, retErr error) { 27 supervisor := supervisor{} 28 defer func() { 29 if retErr != nil { 30 supervisor.Shutdown() 31 } 32 }() 33 34 wrappedLogger := pluginInfo.WrapLogger(parentLogger) 35 36 hclogAdaptedLogger := &hclogAdapter{ 37 wrappedLogger: wrappedLogger.WithCallerSkip(1), 38 extrasKey: "wrapped_extras", 39 } 40 41 pluginMap := map[string]plugin.Plugin{ 42 "hooks": &hooksPlugin{ 43 log: wrappedLogger, 44 apiImpl: apiImpl, 45 }, 46 } 47 48 executable := filepath.Clean(filepath.Join( 49 ".", 50 pluginInfo.Manifest.GetExecutableForRuntime(runtime.GOOS, runtime.GOARCH), 51 )) 52 if strings.HasPrefix(executable, "..") { 53 return nil, fmt.Errorf("invalid backend executable") 54 } 55 executable = filepath.Join(pluginInfo.Path, executable) 56 57 supervisor.client = plugin.NewClient(&plugin.ClientConfig{ 58 HandshakeConfig: handshake, 59 Plugins: pluginMap, 60 Cmd: exec.Command(executable), 61 SyncStdout: wrappedLogger.With(mlog.String("source", "plugin_stdout")).StdLogWriter(), 62 SyncStderr: wrappedLogger.With(mlog.String("source", "plugin_stderr")).StdLogWriter(), 63 Logger: hclogAdaptedLogger, 64 StartTimeout: time.Second * 3, 65 }) 66 67 rpcClient, err := supervisor.client.Client() 68 if err != nil { 69 return nil, err 70 } 71 72 raw, err := rpcClient.Dispense("hooks") 73 if err != nil { 74 return nil, err 75 } 76 77 supervisor.hooks = raw.(Hooks) 78 79 if impl, err := supervisor.hooks.Implemented(); err != nil { 80 return nil, err 81 } else { 82 for _, hookName := range impl { 83 if hookId, ok := hookNameToId[hookName]; ok { 84 supervisor.implemented[hookId] = true 85 } 86 } 87 } 88 89 err = supervisor.Hooks().OnActivate() 90 if err != nil { 91 return nil, err 92 } 93 94 return &supervisor, nil 95 } 96 97 func (sup *supervisor) Shutdown() { 98 if sup.client != nil { 99 sup.client.Kill() 100 } 101 } 102 103 func (sup *supervisor) Hooks() Hooks { 104 return sup.hooks 105 } 106 107 func (sup *supervisor) Implements(hookId int) bool { 108 return sup.implemented[hookId] 109 }