github.com/mad-app/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  }