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  }