make hooks optional, short circuit if unimplemented (#7263)
Этот коммит содержится в:
@@ -3,41 +3,87 @@ package rpcplugin
|
||||
import (
|
||||
"io"
|
||||
"net/rpc"
|
||||
"reflect"
|
||||
|
||||
"github.com/mattermost/platform/plugin"
|
||||
)
|
||||
|
||||
type LocalHooks struct {
|
||||
hooks plugin.Hooks
|
||||
hooks interface{}
|
||||
muxer *Muxer
|
||||
remoteAPI *RemoteAPI
|
||||
}
|
||||
|
||||
func (h *LocalHooks) OnActivate(args int64, reply *struct{}) error {
|
||||
stream := h.muxer.Connect(args)
|
||||
if h.remoteAPI != nil {
|
||||
h.remoteAPI.Close()
|
||||
// Implemented replies with the names of the hooks that are implemented.
|
||||
func (h *LocalHooks) Implemented(args struct{}, reply *[]string) error {
|
||||
ifaceType := reflect.TypeOf((*plugin.Hooks)(nil)).Elem()
|
||||
implType := reflect.TypeOf(h.hooks)
|
||||
selfType := reflect.TypeOf(h)
|
||||
var methods []string
|
||||
for i := 0; i < ifaceType.NumMethod(); i++ {
|
||||
method := ifaceType.Method(i)
|
||||
if m, ok := implType.MethodByName(method.Name); !ok {
|
||||
continue
|
||||
} else if m.Type.NumIn() != method.Type.NumIn()+1 {
|
||||
continue
|
||||
} else if m.Type.NumOut() != method.Type.NumOut() {
|
||||
continue
|
||||
} else {
|
||||
match := true
|
||||
for j := 0; j < method.Type.NumIn(); j++ {
|
||||
if m.Type.In(j+1) != method.Type.In(j) {
|
||||
match = false
|
||||
break
|
||||
}
|
||||
}
|
||||
for j := 0; j < method.Type.NumOut(); j++ {
|
||||
if m.Type.Out(j) != method.Type.Out(j) {
|
||||
match = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !match {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if _, ok := selfType.MethodByName(method.Name); !ok {
|
||||
continue
|
||||
}
|
||||
methods = append(methods, method.Name)
|
||||
}
|
||||
h.remoteAPI = ConnectAPI(stream, h.muxer)
|
||||
return h.hooks.OnActivate(h.remoteAPI)
|
||||
*reply = methods
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *LocalHooks) OnDeactivate(args, reply *struct{}) error {
|
||||
err := h.hooks.OnDeactivate()
|
||||
func (h *LocalHooks) OnActivate(args int64, reply *struct{}) error {
|
||||
if h.remoteAPI != nil {
|
||||
h.remoteAPI.Close()
|
||||
h.remoteAPI = nil
|
||||
}
|
||||
return err
|
||||
if hook, ok := h.hooks.(interface {
|
||||
OnActivate(plugin.API) error
|
||||
}); ok {
|
||||
stream := h.muxer.Connect(args)
|
||||
h.remoteAPI = ConnectAPI(stream, h.muxer)
|
||||
return hook.OnActivate(h.remoteAPI)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type RemoteHooks struct {
|
||||
client *rpc.Client
|
||||
muxer *Muxer
|
||||
apiCloser io.Closer
|
||||
func (h *LocalHooks) OnDeactivate(args, reply *struct{}) (err error) {
|
||||
if hook, ok := h.hooks.(interface {
|
||||
OnDeactivate() error
|
||||
}); ok {
|
||||
err = hook.OnDeactivate()
|
||||
}
|
||||
if h.remoteAPI != nil {
|
||||
h.remoteAPI.Close()
|
||||
h.remoteAPI = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ServeHooks(hooks plugin.Hooks, conn io.ReadWriteCloser, muxer *Muxer) {
|
||||
func ServeHooks(hooks interface{}, conn io.ReadWriteCloser, muxer *Muxer) {
|
||||
server := rpc.NewServer()
|
||||
server.Register(&LocalHooks{
|
||||
hooks: hooks,
|
||||
@@ -46,32 +92,72 @@ func ServeHooks(hooks plugin.Hooks, conn io.ReadWriteCloser, muxer *Muxer) {
|
||||
server.ServeConn(conn)
|
||||
}
|
||||
|
||||
const (
|
||||
remoteOnActivate = iota
|
||||
remoteOnDeactivate
|
||||
maxRemoteHookCount
|
||||
)
|
||||
|
||||
type RemoteHooks struct {
|
||||
client *rpc.Client
|
||||
muxer *Muxer
|
||||
apiCloser io.Closer
|
||||
implemented [maxRemoteHookCount]bool
|
||||
}
|
||||
|
||||
var _ plugin.Hooks = (*RemoteHooks)(nil)
|
||||
|
||||
func (h *RemoteHooks) Implemented() (impl []string, err error) {
|
||||
err = h.client.Call("LocalHooks.Implemented", struct{}{}, &impl)
|
||||
return
|
||||
}
|
||||
|
||||
func (h *RemoteHooks) OnActivate(api plugin.API) error {
|
||||
id, stream := h.muxer.Serve()
|
||||
if h.apiCloser != nil {
|
||||
h.apiCloser.Close()
|
||||
h.apiCloser = nil
|
||||
}
|
||||
if !h.implemented[remoteOnActivate] {
|
||||
return nil
|
||||
}
|
||||
id, stream := h.muxer.Serve()
|
||||
h.apiCloser = stream
|
||||
go ServeAPI(api, stream, h.muxer)
|
||||
return h.client.Call("LocalHooks.OnActivate", id, nil)
|
||||
}
|
||||
|
||||
func (h *RemoteHooks) OnDeactivate() error {
|
||||
if !h.implemented[remoteOnDeactivate] {
|
||||
return nil
|
||||
}
|
||||
return h.client.Call("LocalHooks.OnDeactivate", struct{}{}, nil)
|
||||
}
|
||||
|
||||
func (h *RemoteHooks) Close() error {
|
||||
if h.apiCloser != nil {
|
||||
h.apiCloser.Close()
|
||||
h.apiCloser = nil
|
||||
}
|
||||
return h.client.Close()
|
||||
}
|
||||
|
||||
func ConnectHooks(conn io.ReadWriteCloser, muxer *Muxer) *RemoteHooks {
|
||||
return &RemoteHooks{
|
||||
func ConnectHooks(conn io.ReadWriteCloser, muxer *Muxer) (*RemoteHooks, error) {
|
||||
remote := &RemoteHooks{
|
||||
client: rpc.NewClient(conn),
|
||||
muxer: muxer,
|
||||
}
|
||||
implemented, err := remote.Implemented()
|
||||
if err != nil {
|
||||
remote.Close()
|
||||
return nil, err
|
||||
}
|
||||
for _, method := range implemented {
|
||||
switch method {
|
||||
case "OnActivate":
|
||||
remote.implemented[remoteOnActivate] = true
|
||||
case "OnDeactivate":
|
||||
remote.implemented[remoteOnDeactivate] = true
|
||||
}
|
||||
}
|
||||
return remote, nil
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user