github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/plugin/client_rpc.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  //go:generate go run interface_generator/main.go
     5  
     6  package plugin
     7  
     8  import (
     9  	"bytes"
    10  	"encoding/gob"
    11  	"encoding/json"
    12  	"fmt"
    13  	"io"
    14  	"io/ioutil"
    15  	"log"
    16  	"net/http"
    17  	"net/rpc"
    18  	"os"
    19  	"reflect"
    20  
    21  	"github.com/dyatlov/go-opengraph/opengraph"
    22  	"github.com/hashicorp/go-plugin"
    23  
    24  	"github.com/mattermost/mattermost-server/v5/mlog"
    25  	"github.com/mattermost/mattermost-server/v5/model"
    26  )
    27  
    28  var hookNameToId map[string]int = make(map[string]int)
    29  
    30  type hooksRPCClient struct {
    31  	client      *rpc.Client
    32  	log         *mlog.Logger
    33  	muxBroker   *plugin.MuxBroker
    34  	apiImpl     API
    35  	implemented [TotalHooksId]bool
    36  }
    37  
    38  type hooksRPCServer struct {
    39  	impl         interface{}
    40  	muxBroker    *plugin.MuxBroker
    41  	apiRPCClient *apiRPCClient
    42  }
    43  
    44  // Implements hashicorp/go-plugin/plugin.Plugin interface to connect the hooks of a plugin
    45  type hooksPlugin struct {
    46  	hooks   interface{}
    47  	apiImpl API
    48  	log     *mlog.Logger
    49  }
    50  
    51  func (p *hooksPlugin) Server(b *plugin.MuxBroker) (interface{}, error) {
    52  	return &hooksRPCServer{impl: p.hooks, muxBroker: b}, nil
    53  }
    54  
    55  func (p *hooksPlugin) Client(b *plugin.MuxBroker, client *rpc.Client) (interface{}, error) {
    56  	return &hooksRPCClient{client: client, log: p.log, muxBroker: b, apiImpl: p.apiImpl}, nil
    57  }
    58  
    59  type apiRPCClient struct {
    60  	client    *rpc.Client
    61  	muxBroker *plugin.MuxBroker
    62  }
    63  
    64  type apiRPCServer struct {
    65  	impl      API
    66  	muxBroker *plugin.MuxBroker
    67  }
    68  
    69  // ErrorString is a fallback for sending unregistered implementations of the error interface across
    70  // rpc. For example, the errorString type from the github.com/pkg/errors package cannot be
    71  // registered since it is not exported, but this precludes common error handling paradigms.
    72  // ErrorString merely preserves the string description of the error, while satisfying the error
    73  // interface itself to allow other registered types (such as model.AppError) to be sent unmodified.
    74  type ErrorString struct {
    75  	Err string
    76  }
    77  
    78  func (e ErrorString) Error() string {
    79  	return e.Err
    80  }
    81  
    82  func encodableError(err error) error {
    83  	if err == nil {
    84  		return nil
    85  	}
    86  	if _, ok := err.(*model.AppError); ok {
    87  		return err
    88  	}
    89  
    90  	return &ErrorString{
    91  		Err: err.Error(),
    92  	}
    93  }
    94  
    95  // Registering some types used by MM for encoding/gob used by rpc
    96  func init() {
    97  	gob.Register([]*model.SlackAttachment{})
    98  	gob.Register([]interface{}{})
    99  	gob.Register(map[string]interface{}{})
   100  	gob.Register(&model.AppError{})
   101  	gob.Register(&ErrorString{})
   102  	gob.Register(&opengraph.OpenGraph{})
   103  	gob.Register(&model.AutocompleteDynamicListArg{})
   104  	gob.Register(&model.AutocompleteStaticListArg{})
   105  	gob.Register(&model.AutocompleteTextArg{})
   106  }
   107  
   108  // These enforce compile time checks to make sure types implement the interface
   109  // If you are getting an error here, you probably need to run `make pluginapi` to
   110  // autogenerate RPC glue code
   111  var _ plugin.Plugin = &hooksPlugin{}
   112  var _ Hooks = &hooksRPCClient{}
   113  
   114  //
   115  // Below are special cases for hooks or APIs that can not be auto generated
   116  //
   117  
   118  func (g *hooksRPCClient) Implemented() (impl []string, err error) {
   119  	err = g.client.Call("Plugin.Implemented", struct{}{}, &impl)
   120  	for _, hookName := range impl {
   121  		if hookId, ok := hookNameToId[hookName]; ok {
   122  			g.implemented[hookId] = true
   123  		}
   124  	}
   125  	return
   126  }
   127  
   128  // Implemented replies with the names of the hooks that are implemented.
   129  func (s *hooksRPCServer) Implemented(args struct{}, reply *[]string) error {
   130  	ifaceType := reflect.TypeOf((*Hooks)(nil)).Elem()
   131  	implType := reflect.TypeOf(s.impl)
   132  	selfType := reflect.TypeOf(s)
   133  	var methods []string
   134  	for i := 0; i < ifaceType.NumMethod(); i++ {
   135  		method := ifaceType.Method(i)
   136  		if m, ok := implType.MethodByName(method.Name); !ok {
   137  			continue
   138  		} else if m.Type.NumIn() != method.Type.NumIn()+1 {
   139  			continue
   140  		} else if m.Type.NumOut() != method.Type.NumOut() {
   141  			continue
   142  		} else {
   143  			match := true
   144  			for j := 0; j < method.Type.NumIn(); j++ {
   145  				if m.Type.In(j+1) != method.Type.In(j) {
   146  					match = false
   147  					break
   148  				}
   149  			}
   150  			for j := 0; j < method.Type.NumOut(); j++ {
   151  				if m.Type.Out(j) != method.Type.Out(j) {
   152  					match = false
   153  					break
   154  				}
   155  			}
   156  			if !match {
   157  				continue
   158  			}
   159  		}
   160  		if _, ok := selfType.MethodByName(method.Name); !ok {
   161  			continue
   162  		}
   163  		methods = append(methods, method.Name)
   164  	}
   165  	*reply = methods
   166  	return encodableError(nil)
   167  }
   168  
   169  type Z_OnActivateArgs struct {
   170  	APIMuxId uint32
   171  }
   172  
   173  type Z_OnActivateReturns struct {
   174  	A error
   175  }
   176  
   177  func (g *hooksRPCClient) OnActivate() error {
   178  	muxId := g.muxBroker.NextId()
   179  	go g.muxBroker.AcceptAndServe(muxId, &apiRPCServer{
   180  		impl:      g.apiImpl,
   181  		muxBroker: g.muxBroker,
   182  	})
   183  
   184  	_args := &Z_OnActivateArgs{
   185  		APIMuxId: muxId,
   186  	}
   187  	_returns := &Z_OnActivateReturns{}
   188  
   189  	if err := g.client.Call("Plugin.OnActivate", _args, _returns); err != nil {
   190  		g.log.Error("RPC call to OnActivate plugin failed.", mlog.Err(err))
   191  	}
   192  	return _returns.A
   193  }
   194  
   195  func (s *hooksRPCServer) OnActivate(args *Z_OnActivateArgs, returns *Z_OnActivateReturns) error {
   196  	connection, err := s.muxBroker.Dial(args.APIMuxId)
   197  	if err != nil {
   198  		return err
   199  	}
   200  
   201  	s.apiRPCClient = &apiRPCClient{
   202  		client:    rpc.NewClient(connection),
   203  		muxBroker: s.muxBroker,
   204  	}
   205  
   206  	if mmplugin, ok := s.impl.(interface {
   207  		SetAPI(api API)
   208  		SetHelpers(helpers Helpers)
   209  	}); ok {
   210  		mmplugin.SetAPI(s.apiRPCClient)
   211  		mmplugin.SetHelpers(&HelpersImpl{API: s.apiRPCClient})
   212  	}
   213  
   214  	if mmplugin, ok := s.impl.(interface {
   215  		OnConfigurationChange() error
   216  	}); ok {
   217  		if err := mmplugin.OnConfigurationChange(); err != nil {
   218  			fmt.Fprintf(os.Stderr, "[ERROR] call to OnConfigurationChange failed, error: %v", err.Error())
   219  		}
   220  	}
   221  
   222  	// Capture output of standard logger because go-plugin
   223  	// redirects it.
   224  	log.SetOutput(os.Stderr)
   225  
   226  	if hook, ok := s.impl.(interface {
   227  		OnActivate() error
   228  	}); ok {
   229  		returns.A = encodableError(hook.OnActivate())
   230  	}
   231  	return nil
   232  }
   233  
   234  type Z_LoadPluginConfigurationArgsArgs struct {
   235  }
   236  
   237  type Z_LoadPluginConfigurationArgsReturns struct {
   238  	A []byte
   239  }
   240  
   241  func (g *apiRPCClient) LoadPluginConfiguration(dest interface{}) error {
   242  	_args := &Z_LoadPluginConfigurationArgsArgs{}
   243  	_returns := &Z_LoadPluginConfigurationArgsReturns{}
   244  	if err := g.client.Call("Plugin.LoadPluginConfiguration", _args, _returns); err != nil {
   245  		log.Printf("RPC call to LoadPluginConfiguration API failed: %s", err.Error())
   246  	}
   247  	if err := json.Unmarshal(_returns.A, dest); err != nil {
   248  		log.Printf("LoadPluginConfiguration API failed to unmarshal: %s", err.Error())
   249  	}
   250  	return nil
   251  }
   252  
   253  func (s *apiRPCServer) LoadPluginConfiguration(args *Z_LoadPluginConfigurationArgsArgs, returns *Z_LoadPluginConfigurationArgsReturns) error {
   254  	var config interface{}
   255  	if hook, ok := s.impl.(interface {
   256  		LoadPluginConfiguration(dest interface{}) error
   257  	}); ok {
   258  		if err := hook.LoadPluginConfiguration(&config); err != nil {
   259  			return err
   260  		}
   261  	}
   262  	b, err := json.Marshal(config)
   263  	if err != nil {
   264  		return err
   265  	}
   266  	returns.A = b
   267  	return nil
   268  }
   269  
   270  func init() {
   271  	hookNameToId["ServeHTTP"] = ServeHTTPId
   272  }
   273  
   274  type Z_ServeHTTPArgs struct {
   275  	ResponseWriterStream uint32
   276  	Request              *http.Request
   277  	Context              *Context
   278  	RequestBodyStream    uint32
   279  }
   280  
   281  func (g *hooksRPCClient) ServeHTTP(c *Context, w http.ResponseWriter, r *http.Request) {
   282  	if !g.implemented[ServeHTTPId] {
   283  		http.NotFound(w, r)
   284  		return
   285  	}
   286  
   287  	serveHTTPStreamId := g.muxBroker.NextId()
   288  	go func() {
   289  		connection, err := g.muxBroker.Accept(serveHTTPStreamId)
   290  		if err != nil {
   291  			g.log.Error("Plugin failed to ServeHTTP, muxBroker couldn't accept connection", mlog.Uint32("serve_http_stream_id", serveHTTPStreamId), mlog.Err(err))
   292  			return
   293  		}
   294  		defer connection.Close()
   295  
   296  		rpcServer := rpc.NewServer()
   297  		if err := rpcServer.RegisterName("Plugin", &httpResponseWriterRPCServer{w: w, log: g.log}); err != nil {
   298  			g.log.Error("Plugin failed to ServeHTTP, couldn't register RPC name", mlog.Err(err))
   299  			return
   300  		}
   301  		rpcServer.ServeConn(connection)
   302  	}()
   303  
   304  	requestBodyStreamId := uint32(0)
   305  	if r.Body != nil {
   306  		requestBodyStreamId = g.muxBroker.NextId()
   307  		go func() {
   308  			bodyConnection, err := g.muxBroker.Accept(requestBodyStreamId)
   309  			if err != nil {
   310  				g.log.Error("Plugin failed to ServeHTTP, muxBroker couldn't Accept request body connection", mlog.Err(err))
   311  				return
   312  			}
   313  			defer bodyConnection.Close()
   314  			serveIOReader(r.Body, bodyConnection)
   315  		}()
   316  	}
   317  
   318  	forwardedRequest := &http.Request{
   319  		Method:     r.Method,
   320  		URL:        r.URL,
   321  		Proto:      r.Proto,
   322  		ProtoMajor: r.ProtoMajor,
   323  		ProtoMinor: r.ProtoMinor,
   324  		Header:     r.Header,
   325  		Host:       r.Host,
   326  		RemoteAddr: r.RemoteAddr,
   327  		RequestURI: r.RequestURI,
   328  	}
   329  
   330  	if err := g.client.Call("Plugin.ServeHTTP", Z_ServeHTTPArgs{
   331  		Context:              c,
   332  		ResponseWriterStream: serveHTTPStreamId,
   333  		Request:              forwardedRequest,
   334  		RequestBodyStream:    requestBodyStreamId,
   335  	}, nil); err != nil {
   336  		g.log.Error("Plugin failed to ServeHTTP, RPC call failed", mlog.Err(err))
   337  		http.Error(w, "500 internal server error", http.StatusInternalServerError)
   338  	}
   339  }
   340  
   341  func (s *hooksRPCServer) ServeHTTP(args *Z_ServeHTTPArgs, returns *struct{}) error {
   342  	connection, err := s.muxBroker.Dial(args.ResponseWriterStream)
   343  	if err != nil {
   344  		fmt.Fprintf(os.Stderr, "[ERROR] Can't connect to remote response writer stream, error: %v", err.Error())
   345  		return err
   346  	}
   347  	w := connectHTTPResponseWriter(connection)
   348  	defer w.Close()
   349  
   350  	r := args.Request
   351  	if args.RequestBodyStream != 0 {
   352  		connection, err := s.muxBroker.Dial(args.RequestBodyStream)
   353  		if err != nil {
   354  			fmt.Fprintf(os.Stderr, "[ERROR] Can't connect to remote request body stream, error: %v", err.Error())
   355  			return err
   356  		}
   357  		r.Body = connectIOReader(connection)
   358  	} else {
   359  		r.Body = ioutil.NopCloser(&bytes.Buffer{})
   360  	}
   361  	defer r.Body.Close()
   362  
   363  	if hook, ok := s.impl.(interface {
   364  		ServeHTTP(c *Context, w http.ResponseWriter, r *http.Request)
   365  	}); ok {
   366  		hook.ServeHTTP(args.Context, w, r)
   367  	} else {
   368  		http.NotFound(w, r)
   369  	}
   370  
   371  	return nil
   372  }
   373  
   374  type Z_PluginHTTPArgs struct {
   375  	Request     *http.Request
   376  	RequestBody []byte
   377  }
   378  
   379  type Z_PluginHTTPReturns struct {
   380  	Response     *http.Response
   381  	ResponseBody []byte
   382  }
   383  
   384  func (g *apiRPCClient) PluginHTTP(request *http.Request) *http.Response {
   385  	forwardedRequest := &http.Request{
   386  		Method:     request.Method,
   387  		URL:        request.URL,
   388  		Proto:      request.Proto,
   389  		ProtoMajor: request.ProtoMajor,
   390  		ProtoMinor: request.ProtoMinor,
   391  		Header:     request.Header,
   392  		Host:       request.Host,
   393  		RemoteAddr: request.RemoteAddr,
   394  		RequestURI: request.RequestURI,
   395  	}
   396  
   397  	requestBody, err := ioutil.ReadAll(request.Body)
   398  	if err != nil {
   399  		log.Printf("RPC call to PluginHTTP API failed: %s", err.Error())
   400  		return nil
   401  	}
   402  	request.Body.Close()
   403  	request.Body = nil
   404  
   405  	_args := &Z_PluginHTTPArgs{
   406  		Request:     forwardedRequest,
   407  		RequestBody: requestBody,
   408  	}
   409  
   410  	_returns := &Z_PluginHTTPReturns{}
   411  	if err := g.client.Call("Plugin.PluginHTTP", _args, _returns); err != nil {
   412  		log.Printf("RPC call to PluginHTTP API failed: %s", err.Error())
   413  		return nil
   414  	}
   415  
   416  	_returns.Response.Body = ioutil.NopCloser(bytes.NewBuffer(_returns.ResponseBody))
   417  
   418  	return _returns.Response
   419  }
   420  
   421  func (s *apiRPCServer) PluginHTTP(args *Z_PluginHTTPArgs, returns *Z_PluginHTTPReturns) error {
   422  	args.Request.Body = ioutil.NopCloser(bytes.NewBuffer(args.RequestBody))
   423  
   424  	if hook, ok := s.impl.(interface {
   425  		PluginHTTP(request *http.Request) *http.Response
   426  	}); ok {
   427  		response := hook.PluginHTTP(args.Request)
   428  
   429  		responseBody, err := ioutil.ReadAll(response.Body)
   430  		if err != nil {
   431  			return encodableError(fmt.Errorf("RPC call to PluginHTTP API failed: %s", err.Error()))
   432  		}
   433  		response.Body.Close()
   434  		response.Body = nil
   435  
   436  		returns.Response = response
   437  		returns.ResponseBody = responseBody
   438  	} else {
   439  		return encodableError(fmt.Errorf("API PluginHTTP called but not implemented."))
   440  	}
   441  	return nil
   442  }
   443  
   444  func init() {
   445  	hookNameToId["FileWillBeUploaded"] = FileWillBeUploadedId
   446  }
   447  
   448  type Z_FileWillBeUploadedArgs struct {
   449  	A                     *Context
   450  	B                     *model.FileInfo
   451  	UploadedFileStream    uint32
   452  	ReplacementFileStream uint32
   453  }
   454  
   455  type Z_FileWillBeUploadedReturns struct {
   456  	A *model.FileInfo
   457  	B string
   458  }
   459  
   460  func (g *hooksRPCClient) FileWillBeUploaded(c *Context, info *model.FileInfo, file io.Reader, output io.Writer) (*model.FileInfo, string) {
   461  	if !g.implemented[FileWillBeUploadedId] {
   462  		return info, ""
   463  	}
   464  
   465  	uploadedFileStreamId := g.muxBroker.NextId()
   466  	go func() {
   467  		uploadedFileConnection, err := g.muxBroker.Accept(uploadedFileStreamId)
   468  		if err != nil {
   469  			g.log.Error("Plugin failed to serve upload file stream. MuxBroker could not Accept connection", mlog.Err(err))
   470  			return
   471  		}
   472  		defer uploadedFileConnection.Close()
   473  		serveIOReader(file, uploadedFileConnection)
   474  	}()
   475  
   476  	replacementDone := make(chan bool)
   477  	replacementFileStreamId := g.muxBroker.NextId()
   478  	go func() {
   479  		defer close(replacementDone)
   480  
   481  		replacementFileConnection, err := g.muxBroker.Accept(replacementFileStreamId)
   482  		if err != nil {
   483  			g.log.Error("Plugin failed to serve replacement file stream. MuxBroker could not Accept connection", mlog.Err(err))
   484  			return
   485  		}
   486  		defer replacementFileConnection.Close()
   487  		if _, err := io.Copy(output, replacementFileConnection); err != nil {
   488  			g.log.Error("Error reading replacement file.", mlog.Err(err))
   489  		}
   490  	}()
   491  
   492  	_args := &Z_FileWillBeUploadedArgs{c, info, uploadedFileStreamId, replacementFileStreamId}
   493  	_returns := &Z_FileWillBeUploadedReturns{A: _args.B}
   494  	if err := g.client.Call("Plugin.FileWillBeUploaded", _args, _returns); err != nil {
   495  		g.log.Error("RPC call FileWillBeUploaded to plugin failed.", mlog.Err(err))
   496  	}
   497  
   498  	// Ensure the io.Copy from the replacementFileConnection above completes.
   499  	<-replacementDone
   500  
   501  	return _returns.A, _returns.B
   502  }
   503  
   504  func (s *hooksRPCServer) FileWillBeUploaded(args *Z_FileWillBeUploadedArgs, returns *Z_FileWillBeUploadedReturns) error {
   505  	uploadFileConnection, err := s.muxBroker.Dial(args.UploadedFileStream)
   506  	if err != nil {
   507  		fmt.Fprintf(os.Stderr, "[ERROR] Can't connect to remote upload file stream, error: %v", err.Error())
   508  		return err
   509  	}
   510  	defer uploadFileConnection.Close()
   511  	fileReader := connectIOReader(uploadFileConnection)
   512  	defer fileReader.Close()
   513  
   514  	replacementFileConnection, err := s.muxBroker.Dial(args.ReplacementFileStream)
   515  	if err != nil {
   516  		fmt.Fprintf(os.Stderr, "[ERROR] Can't connect to remote replacement file stream, error: %v", err.Error())
   517  		return err
   518  	}
   519  	defer replacementFileConnection.Close()
   520  	returnFileWriter := replacementFileConnection
   521  
   522  	if hook, ok := s.impl.(interface {
   523  		FileWillBeUploaded(c *Context, info *model.FileInfo, file io.Reader, output io.Writer) (*model.FileInfo, string)
   524  	}); ok {
   525  		returns.A, returns.B = hook.FileWillBeUploaded(args.A, args.B, fileReader, returnFileWriter)
   526  	} else {
   527  		return fmt.Errorf("Hook FileWillBeUploaded called but not implemented.")
   528  	}
   529  	return nil
   530  }
   531  
   532  // MessageWillBePosted is in this file because of the difficulty of identifying which fields need special behaviour.
   533  // The special behaviour needed is decoding the returned post into the original one to avoid the unintentional removal
   534  // of fields by older plugins.
   535  func init() {
   536  	hookNameToId["MessageWillBePosted"] = MessageWillBePostedId
   537  }
   538  
   539  type Z_MessageWillBePostedArgs struct {
   540  	A *Context
   541  	B *model.Post
   542  }
   543  
   544  type Z_MessageWillBePostedReturns struct {
   545  	A *model.Post
   546  	B string
   547  }
   548  
   549  func (g *hooksRPCClient) MessageWillBePosted(c *Context, post *model.Post) (*model.Post, string) {
   550  	_args := &Z_MessageWillBePostedArgs{c, post}
   551  	_returns := &Z_MessageWillBePostedReturns{A: _args.B}
   552  	if g.implemented[MessageWillBePostedId] {
   553  		if err := g.client.Call("Plugin.MessageWillBePosted", _args, _returns); err != nil {
   554  			g.log.Error("RPC call MessageWillBePosted to plugin failed.", mlog.Err(err))
   555  		}
   556  	}
   557  	return _returns.A, _returns.B
   558  }
   559  
   560  func (s *hooksRPCServer) MessageWillBePosted(args *Z_MessageWillBePostedArgs, returns *Z_MessageWillBePostedReturns) error {
   561  	if hook, ok := s.impl.(interface {
   562  		MessageWillBePosted(c *Context, post *model.Post) (*model.Post, string)
   563  	}); ok {
   564  		returns.A, returns.B = hook.MessageWillBePosted(args.A, args.B)
   565  
   566  	} else {
   567  		return encodableError(fmt.Errorf("Hook MessageWillBePosted called but not implemented."))
   568  	}
   569  	return nil
   570  }
   571  
   572  // MessageWillBeUpdated is in this file because of the difficulty of identifying which fields need special behaviour.
   573  // The special behaviour needed is decoding the returned post into the original one to avoid the unintentional removal
   574  // of fields by older plugins.
   575  func init() {
   576  	hookNameToId["MessageWillBeUpdated"] = MessageWillBeUpdatedId
   577  }
   578  
   579  type Z_MessageWillBeUpdatedArgs struct {
   580  	A *Context
   581  	B *model.Post
   582  	C *model.Post
   583  }
   584  
   585  type Z_MessageWillBeUpdatedReturns struct {
   586  	A *model.Post
   587  	B string
   588  }
   589  
   590  func (g *hooksRPCClient) MessageWillBeUpdated(c *Context, newPost, oldPost *model.Post) (*model.Post, string) {
   591  	_args := &Z_MessageWillBeUpdatedArgs{c, newPost, oldPost}
   592  	_returns := &Z_MessageWillBeUpdatedReturns{A: _args.B}
   593  	if g.implemented[MessageWillBeUpdatedId] {
   594  		if err := g.client.Call("Plugin.MessageWillBeUpdated", _args, _returns); err != nil {
   595  			g.log.Error("RPC call MessageWillBeUpdated to plugin failed.", mlog.Err(err))
   596  		}
   597  	}
   598  	return _returns.A, _returns.B
   599  }
   600  
   601  func (s *hooksRPCServer) MessageWillBeUpdated(args *Z_MessageWillBeUpdatedArgs, returns *Z_MessageWillBeUpdatedReturns) error {
   602  	if hook, ok := s.impl.(interface {
   603  		MessageWillBeUpdated(c *Context, newPost, oldPost *model.Post) (*model.Post, string)
   604  	}); ok {
   605  		returns.A, returns.B = hook.MessageWillBeUpdated(args.A, args.B, args.C)
   606  
   607  	} else {
   608  		return encodableError(fmt.Errorf("Hook MessageWillBeUpdated called but not implemented."))
   609  	}
   610  	return nil
   611  }
   612  
   613  type Z_LogDebugArgs struct {
   614  	A string
   615  	B []interface{}
   616  }
   617  
   618  type Z_LogDebugReturns struct {
   619  }
   620  
   621  func (g *apiRPCClient) LogDebug(msg string, keyValuePairs ...interface{}) {
   622  	stringifiedPairs := stringifyToObjects(keyValuePairs)
   623  	_args := &Z_LogDebugArgs{msg, stringifiedPairs}
   624  	_returns := &Z_LogDebugReturns{}
   625  	if err := g.client.Call("Plugin.LogDebug", _args, _returns); err != nil {
   626  		log.Printf("RPC call to LogDebug API failed: %s", err.Error())
   627  	}
   628  
   629  }
   630  
   631  func (s *apiRPCServer) LogDebug(args *Z_LogDebugArgs, returns *Z_LogDebugReturns) error {
   632  	if hook, ok := s.impl.(interface {
   633  		LogDebug(msg string, keyValuePairs ...interface{})
   634  	}); ok {
   635  		hook.LogDebug(args.A, args.B...)
   636  	} else {
   637  		return encodableError(fmt.Errorf("API LogDebug called but not implemented."))
   638  	}
   639  	return nil
   640  }
   641  
   642  type Z_LogInfoArgs struct {
   643  	A string
   644  	B []interface{}
   645  }
   646  
   647  type Z_LogInfoReturns struct {
   648  }
   649  
   650  func (g *apiRPCClient) LogInfo(msg string, keyValuePairs ...interface{}) {
   651  	stringifiedPairs := stringifyToObjects(keyValuePairs)
   652  	_args := &Z_LogInfoArgs{msg, stringifiedPairs}
   653  	_returns := &Z_LogInfoReturns{}
   654  	if err := g.client.Call("Plugin.LogInfo", _args, _returns); err != nil {
   655  		log.Printf("RPC call to LogInfo API failed: %s", err.Error())
   656  	}
   657  
   658  }
   659  
   660  func (s *apiRPCServer) LogInfo(args *Z_LogInfoArgs, returns *Z_LogInfoReturns) error {
   661  	if hook, ok := s.impl.(interface {
   662  		LogInfo(msg string, keyValuePairs ...interface{})
   663  	}); ok {
   664  		hook.LogInfo(args.A, args.B...)
   665  	} else {
   666  		return encodableError(fmt.Errorf("API LogInfo called but not implemented."))
   667  	}
   668  	return nil
   669  }
   670  
   671  type Z_LogWarnArgs struct {
   672  	A string
   673  	B []interface{}
   674  }
   675  
   676  type Z_LogWarnReturns struct {
   677  }
   678  
   679  func (g *apiRPCClient) LogWarn(msg string, keyValuePairs ...interface{}) {
   680  	stringifiedPairs := stringifyToObjects(keyValuePairs)
   681  	_args := &Z_LogWarnArgs{msg, stringifiedPairs}
   682  	_returns := &Z_LogWarnReturns{}
   683  	if err := g.client.Call("Plugin.LogWarn", _args, _returns); err != nil {
   684  		log.Printf("RPC call to LogWarn API failed: %s", err.Error())
   685  	}
   686  
   687  }
   688  
   689  func (s *apiRPCServer) LogWarn(args *Z_LogWarnArgs, returns *Z_LogWarnReturns) error {
   690  	if hook, ok := s.impl.(interface {
   691  		LogWarn(msg string, keyValuePairs ...interface{})
   692  	}); ok {
   693  		hook.LogWarn(args.A, args.B...)
   694  	} else {
   695  		return encodableError(fmt.Errorf("API LogWarn called but not implemented."))
   696  	}
   697  	return nil
   698  }
   699  
   700  type Z_LogErrorArgs struct {
   701  	A string
   702  	B []interface{}
   703  }
   704  
   705  type Z_LogErrorReturns struct {
   706  }
   707  
   708  func (g *apiRPCClient) LogError(msg string, keyValuePairs ...interface{}) {
   709  	stringifiedPairs := stringifyToObjects(keyValuePairs)
   710  	_args := &Z_LogErrorArgs{msg, stringifiedPairs}
   711  	_returns := &Z_LogErrorReturns{}
   712  	if err := g.client.Call("Plugin.LogError", _args, _returns); err != nil {
   713  		log.Printf("RPC call to LogError API failed: %s", err.Error())
   714  	}
   715  }
   716  
   717  func (s *apiRPCServer) LogError(args *Z_LogErrorArgs, returns *Z_LogErrorReturns) error {
   718  	if hook, ok := s.impl.(interface {
   719  		LogError(msg string, keyValuePairs ...interface{})
   720  	}); ok {
   721  		hook.LogError(args.A, args.B...)
   722  	} else {
   723  		return encodableError(fmt.Errorf("API LogError called but not implemented."))
   724  	}
   725  	return nil
   726  }
   727  
   728  type Z_InstallPluginArgs struct {
   729  	PluginStreamID uint32
   730  	B              bool
   731  }
   732  
   733  type Z_InstallPluginReturns struct {
   734  	A *model.Manifest
   735  	B *model.AppError
   736  }
   737  
   738  func (g *apiRPCClient) InstallPlugin(file io.Reader, replace bool) (*model.Manifest, *model.AppError) {
   739  	pluginStreamID := g.muxBroker.NextId()
   740  
   741  	go func() {
   742  		uploadPluginConnection, err := g.muxBroker.Accept(pluginStreamID)
   743  		if err != nil {
   744  			log.Print("Plugin failed to upload plugin. MuxBroker could not Accept connection", mlog.Err(err))
   745  			return
   746  		}
   747  		defer uploadPluginConnection.Close()
   748  		serveIOReader(file, uploadPluginConnection)
   749  	}()
   750  
   751  	_args := &Z_InstallPluginArgs{pluginStreamID, replace}
   752  	_returns := &Z_InstallPluginReturns{}
   753  	if err := g.client.Call("Plugin.InstallPlugin", _args, _returns); err != nil {
   754  		log.Print("RPC call InstallPlugin to plugin failed.", mlog.Err(err))
   755  	}
   756  
   757  	return _returns.A, _returns.B
   758  }
   759  
   760  func (s *apiRPCServer) InstallPlugin(args *Z_InstallPluginArgs, returns *Z_InstallPluginReturns) error {
   761  	hook, ok := s.impl.(interface {
   762  		InstallPlugin(file io.Reader, replace bool) (*model.Manifest, *model.AppError)
   763  	})
   764  	if !ok {
   765  		return encodableError(fmt.Errorf("API InstallPlugin called but not implemented."))
   766  	}
   767  
   768  	receivePluginConnection, err := s.muxBroker.Dial(args.PluginStreamID)
   769  	if err != nil {
   770  		fmt.Fprintf(os.Stderr, "[ERROR] Can't connect to remote plugin stream, error: %v", err.Error())
   771  		return err
   772  	}
   773  	pluginReader := connectIOReader(receivePluginConnection)
   774  	defer pluginReader.Close()
   775  
   776  	returns.A, returns.B = hook.InstallPlugin(pluginReader, args.B)
   777  	return nil
   778  }