github.com/trigonella/mattermost-server@v5.11.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 plugin "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 client *plugin.Client 21 hooks Hooks 22 implemented [TotalHooksId]bool 23 } 24 25 func newSupervisor(pluginInfo *model.BundleInfo, parentLogger *mlog.Logger, apiImpl API) (retSupervisor *supervisor, retErr error) { 26 sup := supervisor{} 27 defer func() { 28 if retErr != nil { 29 sup.Shutdown() 30 } 31 }() 32 33 wrappedLogger := pluginInfo.WrapLogger(parentLogger) 34 35 hclogAdaptedLogger := &hclogAdapter{ 36 wrappedLogger: wrappedLogger.WithCallerSkip(1), 37 extrasKey: "wrapped_extras", 38 } 39 40 pluginMap := map[string]plugin.Plugin{ 41 "hooks": &hooksPlugin{ 42 log: wrappedLogger, 43 apiImpl: apiImpl, 44 }, 45 } 46 47 executable := filepath.Clean(filepath.Join( 48 ".", 49 pluginInfo.Manifest.GetExecutableForRuntime(runtime.GOOS, runtime.GOARCH), 50 )) 51 if strings.HasPrefix(executable, "..") { 52 return nil, fmt.Errorf("invalid backend executable") 53 } 54 executable = filepath.Join(pluginInfo.Path, executable) 55 56 sup.client = plugin.NewClient(&plugin.ClientConfig{ 57 HandshakeConfig: handshake, 58 Plugins: pluginMap, 59 Cmd: exec.Command(executable), 60 SyncStdout: wrappedLogger.With(mlog.String("source", "plugin_stdout")).StdLogWriter(), 61 SyncStderr: wrappedLogger.With(mlog.String("source", "plugin_stderr")).StdLogWriter(), 62 Logger: hclogAdaptedLogger, 63 StartTimeout: time.Second * 3, 64 }) 65 66 rpcClient, err := sup.client.Client() 67 if err != nil { 68 return nil, err 69 } 70 71 raw, err := rpcClient.Dispense("hooks") 72 if err != nil { 73 return nil, err 74 } 75 76 sup.hooks = raw.(Hooks) 77 78 impl, err := sup.hooks.Implemented() 79 if err != nil { 80 return nil, err 81 } 82 for _, hookName := range impl { 83 if hookId, ok := hookNameToId[hookName]; ok { 84 sup.implemented[hookId] = true 85 } 86 } 87 88 err = sup.Hooks().OnActivate() 89 if err != nil { 90 return nil, err 91 } 92 93 return &sup, nil 94 } 95 96 func (sup *supervisor) Shutdown() { 97 if sup.client != nil { 98 sup.client.Kill() 99 } 100 } 101 102 func (sup *supervisor) Hooks() Hooks { 103 return sup.hooks 104 } 105 106 func (sup *supervisor) Implements(hookId int) bool { 107 return sup.implemented[hookId] 108 }