plugin/product: improve product hooks API (#20556)
* plugin/product: improve product hooks API * elaborate HookService.RegisterHooks method documentation * remove unnecessary re-assigns
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
fe23501d40
Коммит
90c687b728
@@ -301,8 +301,20 @@ func (env *Environment) Activate(id string) (manifest *model.Manifest, activated
|
||||
return pluginInfo.Manifest, true, nil
|
||||
}
|
||||
|
||||
func (env *Environment) AddProduct(productID string, hooks ProductHooks) {
|
||||
env.registeredProducts.Store(productID, newRegisteredProduct(productID, hooks))
|
||||
func (env *Environment) AddProduct(productID string, hooks any) error {
|
||||
prod, err := newAdapter(hooks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rp := ®isteredProduct{
|
||||
productID: productID,
|
||||
adapter: prod,
|
||||
}
|
||||
|
||||
env.registeredProducts.Store(productID, rp)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (env *Environment) RemoveProduct(productID string) {
|
||||
|
||||
@@ -21,6 +21,29 @@ import (
|
||||
"golang.org/x/tools/imports"
|
||||
)
|
||||
|
||||
var excludedPluginHooks = []string{
|
||||
"FileWillBeUploaded",
|
||||
"Implemented",
|
||||
"LoadPluginConfiguration",
|
||||
"InstallPlugin",
|
||||
"LogDebug",
|
||||
"LogError",
|
||||
"LogInfo",
|
||||
"LogWarn",
|
||||
"MessageWillBePosted",
|
||||
"MessageWillBeUpdated",
|
||||
"OnActivate",
|
||||
"PluginHTTP",
|
||||
"ServeHTTP",
|
||||
}
|
||||
|
||||
var excludedProductHooks = []string{
|
||||
"Implemented",
|
||||
"OnActivate",
|
||||
"OnDeactivate",
|
||||
"ServeHTTP",
|
||||
}
|
||||
|
||||
type IHookEntry struct {
|
||||
FuncName string
|
||||
Args *ast.FieldList
|
||||
@@ -360,6 +383,61 @@ func (s *apiRPCServer) {{.Name}}(args *{{.Name | obscure}}Args, returns *{{.Name
|
||||
{{end}}
|
||||
`
|
||||
|
||||
var productHooksTemplate = `// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// Code generated by "make pluginapi"
|
||||
// DO NOT EDIT
|
||||
|
||||
package plugin
|
||||
|
||||
{{range .HooksMethods}}
|
||||
type {{.Name}}IFace interface {
|
||||
{{.Name}}{{funcStyle .Params}} {{funcStyle .Return}}
|
||||
}
|
||||
|
||||
{{end}}
|
||||
|
||||
type hooksAdapter struct {
|
||||
implemented map[int]struct{}
|
||||
productHooks any
|
||||
}
|
||||
|
||||
func newAdapter(productHooks any) (*hooksAdapter, error) {
|
||||
a := &hooksAdapter{
|
||||
implemented: make(map[int]struct{}),
|
||||
}
|
||||
var tt reflect.Type
|
||||
ft := reflect.TypeOf(productHooks)
|
||||
{{range .HooksMethods}}
|
||||
// Assessing the type of the productHooks if it individually implements {{.Name}} interface.
|
||||
tt = reflect.TypeOf((*{{.Name}}IFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[{{.Name}}ID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("{{.Name}}"); ok{
|
||||
return nil, errors.New("hook has {{.Name}} method but does not implement plugin.{{.Name}} interface")
|
||||
}
|
||||
|
||||
{{end}}
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
{{range .HooksMethods}}
|
||||
func (a *hooksAdapter) {{.Name}}{{funcStyle .Params}} {{funcStyle .Return}} {
|
||||
if _, ok := a.implemented[{{.Name}}ID]; !ok {
|
||||
panic("product hooks must implement {{.Name}}")
|
||||
}
|
||||
|
||||
{{if .Return}}return a.productHooks.({{.Name}}IFace).{{.Name}}({{valuesOnly .Params}}){{else}}a.productHooks.({{.Name}}IFace).{{.Name}}({{valuesOnly .Params}}){{end}}
|
||||
|
||||
}
|
||||
|
||||
{{end}}
|
||||
|
||||
`
|
||||
|
||||
var apiTimerLayerTemplate = `// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
@@ -507,6 +585,39 @@ func generateHooksGlue(info *PluginInterfaceInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
func generateProductHooksInterfaces(info *PluginInterfaceInfo) {
|
||||
templateFunctions := map[string]interface{}{
|
||||
"funcStyle": func(fields *ast.FieldList) string { return FieldListToFuncList(fields, info.FileSet) },
|
||||
"valuesOnly": func(fields *ast.FieldList) string { return FieldListToNames(fields, false) },
|
||||
}
|
||||
|
||||
templateParams := HooksTemplateParams{}
|
||||
for _, hook := range info.Hooks {
|
||||
templateParams.HooksMethods = append(templateParams.HooksMethods, MethodParams{
|
||||
Name: hook.FuncName,
|
||||
Params: hook.Args,
|
||||
Return: hook.Results,
|
||||
})
|
||||
}
|
||||
|
||||
productHooksTemplate, err := template.New("hooks").Funcs(templateFunctions).Parse(productHooksTemplate)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
templateResult := &bytes.Buffer{}
|
||||
productHooksTemplate.Execute(templateResult, &templateParams)
|
||||
|
||||
formatted, err := imports.Process("", templateResult.Bytes(), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(getPluginPackageDir(), "product_hooks_generated.go"), formatted, 0664); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func generatePluginTimerLayer(info *PluginInterfaceInfo) {
|
||||
templateFunctions := map[string]interface{}{
|
||||
"funcStyle": func(fields *ast.FieldList) string { return FieldListToFuncList(fields, info.FileSet) },
|
||||
@@ -573,23 +684,11 @@ func getPluginPackageDir() string {
|
||||
return dirs[0]
|
||||
}
|
||||
|
||||
func removeExcluded(info *PluginInterfaceInfo) *PluginInterfaceInfo {
|
||||
func removeExcluded(info *PluginInterfaceInfo, excluded []string) *PluginInterfaceInfo {
|
||||
newIface := &PluginInterfaceInfo{
|
||||
FileSet: info.FileSet,
|
||||
}
|
||||
toBeExcluded := func(item string) bool {
|
||||
excluded := []string{
|
||||
"FileWillBeUploaded",
|
||||
"Implemented",
|
||||
"LoadPluginConfiguration",
|
||||
"InstallPlugin",
|
||||
"LogDebug",
|
||||
"LogError",
|
||||
"LogInfo",
|
||||
"LogWarn",
|
||||
"MessageWillBePosted",
|
||||
"MessageWillBeUpdated",
|
||||
"OnActivate",
|
||||
"PluginHTTP",
|
||||
"ServeHTTP",
|
||||
}
|
||||
for _, exclusion := range excluded {
|
||||
if exclusion == item {
|
||||
return true
|
||||
@@ -603,7 +702,7 @@ func removeExcluded(info *PluginInterfaceInfo) *PluginInterfaceInfo {
|
||||
hooksResult = append(hooksResult, hook)
|
||||
}
|
||||
}
|
||||
info.Hooks = hooksResult
|
||||
newIface.Hooks = hooksResult
|
||||
|
||||
apiResult := make([]IHookEntry, 0, len(info.API))
|
||||
for _, api := range info.API {
|
||||
@@ -611,20 +710,23 @@ func removeExcluded(info *PluginInterfaceInfo) *PluginInterfaceInfo {
|
||||
apiResult = append(apiResult, api)
|
||||
}
|
||||
}
|
||||
info.API = apiResult
|
||||
newIface.API = apiResult
|
||||
|
||||
return info
|
||||
return newIface
|
||||
}
|
||||
|
||||
func main() {
|
||||
pluginPackageDir := getPluginPackageDir()
|
||||
|
||||
log.Println("Generating plugin hooks glue")
|
||||
forRPC, err := getPluginInfo(pluginPackageDir)
|
||||
if err != nil {
|
||||
fmt.Println("Unable to get plugin info: " + err.Error())
|
||||
}
|
||||
generateHooksGlue(removeExcluded(forRPC))
|
||||
log.Println("Generating product hooks interfaces")
|
||||
generateProductHooksInterfaces(removeExcluded(forRPC, excludedProductHooks))
|
||||
|
||||
log.Println("Generating plugin hooks glue")
|
||||
generateHooksGlue(removeExcluded(forRPC, excludedPluginHooks))
|
||||
|
||||
// Generate plugin timer layers
|
||||
log.Println("Generating plugin timer glue")
|
||||
|
||||
@@ -4,144 +4,38 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
)
|
||||
|
||||
// ProductHooks is a subset of Hooks
|
||||
type ProductHooks interface {
|
||||
OnConfigurationChange() error
|
||||
MessageWillBePosted(ctx *Context, post *model.Post) (*model.Post, string)
|
||||
MessageWillBeUpdated(ctx *Context, newPost, oldPost *model.Post) (*model.Post, string)
|
||||
OnPluginClusterEvent(ctx *Context, ev model.PluginClusterEvent)
|
||||
OnWebSocketDisconnect(webConnID, userID string)
|
||||
OnWebSocketConnect(webConnID, userID string)
|
||||
WebSocketMessageHasBeenPosted(webConnID, userID string, req *model.WebSocketRequest)
|
||||
}
|
||||
|
||||
type registeredProduct struct {
|
||||
productID string
|
||||
implemented map[int]struct{}
|
||||
adapter Hooks
|
||||
productID string
|
||||
adapter Hooks
|
||||
}
|
||||
|
||||
func (rp *registeredProduct) Implements(hookId int) bool {
|
||||
_, ok := rp.implemented[hookId]
|
||||
adapter, ok := rp.adapter.(*hooksAdapter)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
_, ok = adapter.implemented[hookId]
|
||||
return ok
|
||||
}
|
||||
|
||||
type hooksAdapter struct {
|
||||
productHooks ProductHooks
|
||||
}
|
||||
|
||||
func newRegisteredProduct(pluginID string, productHooks ProductHooks) *registeredProduct {
|
||||
return ®isteredProduct{
|
||||
productID: pluginID,
|
||||
implemented: map[int]struct{}{
|
||||
OnConfigurationChangeID: {},
|
||||
MessageWillBePostedID: {},
|
||||
MessageWillBeUpdatedID: {},
|
||||
OnPluginClusterEventID: {},
|
||||
OnWebSocketConnectID: {},
|
||||
OnWebSocketDisconnectID: {},
|
||||
WebSocketMessageHasBeenPostedID: {},
|
||||
},
|
||||
adapter: &hooksAdapter{
|
||||
productHooks: productHooks,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnActivate() error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
// Implemented method is overridden intentionally to prevent calling it from outside.
|
||||
func (a *hooksAdapter) Implemented() ([]string, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// OnActivate is overridden intentionally as product should not call it.
|
||||
func (a *hooksAdapter) OnActivate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnDeactivate is overridden intentionally as product should not call it.
|
||||
func (a *hooksAdapter) OnDeactivate() error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnConfigurationChange() error {
|
||||
return a.productHooks.OnConfigurationChange()
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServeHTTP is overridden intentionally as product should not call it.
|
||||
func (a *hooksAdapter) ServeHTTP(c *Context, w http.ResponseWriter, r *http.Request) {}
|
||||
|
||||
func (a *hooksAdapter) ExecuteCommand(c *Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
|
||||
return nil, model.NewAppError("ExecuteCommand", "api.command.execute_command.start.app_error", nil, "not implemented", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) UserHasBeenCreated(c *Context, user *model.User) {}
|
||||
|
||||
func (a *hooksAdapter) UserWillLogIn(c *Context, user *model.User) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) UserHasLoggedIn(c *Context, user *model.User) {}
|
||||
|
||||
func (a *hooksAdapter) MessageWillBePosted(c *Context, post *model.Post) (*model.Post, string) {
|
||||
return a.productHooks.MessageWillBePosted(c, post)
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) MessageWillBeUpdated(c *Context, newPost, oldPost *model.Post) (*model.Post, string) {
|
||||
return a.productHooks.MessageWillBeUpdated(c, newPost, oldPost)
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) MessageHasBeenPosted(c *Context, post *model.Post) {}
|
||||
|
||||
func (a *hooksAdapter) MessageHasBeenUpdated(c *Context, newPost, oldPost *model.Post) {}
|
||||
|
||||
func (a *hooksAdapter) ChannelHasBeenCreated(c *Context, channel *model.Channel) {}
|
||||
|
||||
func (a *hooksAdapter) UserHasJoinedChannel(c *Context, channelMember *model.ChannelMember, actor *model.User) {
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) UserHasLeftChannel(c *Context, channelMember *model.ChannelMember, actor *model.User) {
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) UserHasJoinedTeam(c *Context, teamMember *model.TeamMember, actor *model.User) {
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) UserHasLeftTeam(c *Context, teamMember *model.TeamMember, actor *model.User) {}
|
||||
|
||||
func (a *hooksAdapter) FileWillBeUploaded(c *Context, info *model.FileInfo, file io.Reader, output io.Writer) (*model.FileInfo, string) {
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) ReactionHasBeenAdded(c *Context, reaction *model.Reaction) {}
|
||||
|
||||
func (a *hooksAdapter) ReactionHasBeenRemoved(c *Context, reaction *model.Reaction) {}
|
||||
|
||||
func (a *hooksAdapter) OnPluginClusterEvent(c *Context, ev model.PluginClusterEvent) {
|
||||
a.productHooks.OnPluginClusterEvent(c, ev)
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnWebSocketConnect(webConnID, userID string) {
|
||||
a.productHooks.OnWebSocketConnect(webConnID, userID)
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnWebSocketDisconnect(webConnID, userID string) {
|
||||
a.productHooks.OnWebSocketDisconnect(webConnID, userID)
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) WebSocketMessageHasBeenPosted(webConnID, userID string, req *model.WebSocketRequest) {
|
||||
a.productHooks.WebSocketMessageHasBeenPosted(webConnID, userID, req)
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) RunDataRetention(nowTime, batchSize int64) (int64, error) {
|
||||
return -1, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnInstall(c *Context, event model.OnInstallEvent) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnSendDailyTelemetry() {}
|
||||
|
||||
func (a *hooksAdapter) OnCloudLimitsUpdated(limits *model.ProductLimits) {}
|
||||
|
||||
580
plugin/product_hooks_generated.go
Обычный файл
580
plugin/product_hooks_generated.go
Обычный файл
@@ -0,0 +1,580 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// Code generated by "make pluginapi"
|
||||
// DO NOT EDIT
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
)
|
||||
|
||||
type OnConfigurationChangeIFace interface {
|
||||
OnConfigurationChange() error
|
||||
}
|
||||
|
||||
type ExecuteCommandIFace interface {
|
||||
ExecuteCommand(c *Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError)
|
||||
}
|
||||
|
||||
type UserHasBeenCreatedIFace interface {
|
||||
UserHasBeenCreated(c *Context, user *model.User)
|
||||
}
|
||||
|
||||
type UserWillLogInIFace interface {
|
||||
UserWillLogIn(c *Context, user *model.User) string
|
||||
}
|
||||
|
||||
type UserHasLoggedInIFace interface {
|
||||
UserHasLoggedIn(c *Context, user *model.User)
|
||||
}
|
||||
|
||||
type MessageWillBePostedIFace interface {
|
||||
MessageWillBePosted(c *Context, post *model.Post) (*model.Post, string)
|
||||
}
|
||||
|
||||
type MessageWillBeUpdatedIFace interface {
|
||||
MessageWillBeUpdated(c *Context, newPost, oldPost *model.Post) (*model.Post, string)
|
||||
}
|
||||
|
||||
type MessageHasBeenPostedIFace interface {
|
||||
MessageHasBeenPosted(c *Context, post *model.Post)
|
||||
}
|
||||
|
||||
type MessageHasBeenUpdatedIFace interface {
|
||||
MessageHasBeenUpdated(c *Context, newPost, oldPost *model.Post)
|
||||
}
|
||||
|
||||
type ChannelHasBeenCreatedIFace interface {
|
||||
ChannelHasBeenCreated(c *Context, channel *model.Channel)
|
||||
}
|
||||
|
||||
type UserHasJoinedChannelIFace interface {
|
||||
UserHasJoinedChannel(c *Context, channelMember *model.ChannelMember, actor *model.User)
|
||||
}
|
||||
|
||||
type UserHasLeftChannelIFace interface {
|
||||
UserHasLeftChannel(c *Context, channelMember *model.ChannelMember, actor *model.User)
|
||||
}
|
||||
|
||||
type UserHasJoinedTeamIFace interface {
|
||||
UserHasJoinedTeam(c *Context, teamMember *model.TeamMember, actor *model.User)
|
||||
}
|
||||
|
||||
type UserHasLeftTeamIFace interface {
|
||||
UserHasLeftTeam(c *Context, teamMember *model.TeamMember, actor *model.User)
|
||||
}
|
||||
|
||||
type FileWillBeUploadedIFace interface {
|
||||
FileWillBeUploaded(c *Context, info *model.FileInfo, file io.Reader, output io.Writer) (*model.FileInfo, string)
|
||||
}
|
||||
|
||||
type ReactionHasBeenAddedIFace interface {
|
||||
ReactionHasBeenAdded(c *Context, reaction *model.Reaction)
|
||||
}
|
||||
|
||||
type ReactionHasBeenRemovedIFace interface {
|
||||
ReactionHasBeenRemoved(c *Context, reaction *model.Reaction)
|
||||
}
|
||||
|
||||
type OnPluginClusterEventIFace interface {
|
||||
OnPluginClusterEvent(c *Context, ev model.PluginClusterEvent)
|
||||
}
|
||||
|
||||
type OnWebSocketConnectIFace interface {
|
||||
OnWebSocketConnect(webConnID, userID string)
|
||||
}
|
||||
|
||||
type OnWebSocketDisconnectIFace interface {
|
||||
OnWebSocketDisconnect(webConnID, userID string)
|
||||
}
|
||||
|
||||
type WebSocketMessageHasBeenPostedIFace interface {
|
||||
WebSocketMessageHasBeenPosted(webConnID, userID string, req *model.WebSocketRequest)
|
||||
}
|
||||
|
||||
type RunDataRetentionIFace interface {
|
||||
RunDataRetention(nowTime, batchSize int64) (int64, error)
|
||||
}
|
||||
|
||||
type OnInstallIFace interface {
|
||||
OnInstall(c *Context, event model.OnInstallEvent) error
|
||||
}
|
||||
|
||||
type OnSendDailyTelemetryIFace interface {
|
||||
OnSendDailyTelemetry()
|
||||
}
|
||||
|
||||
type OnCloudLimitsUpdatedIFace interface {
|
||||
OnCloudLimitsUpdated(limits *model.ProductLimits)
|
||||
}
|
||||
|
||||
type hooksAdapter struct {
|
||||
implemented map[int]struct{}
|
||||
productHooks any
|
||||
}
|
||||
|
||||
func newAdapter(productHooks any) (*hooksAdapter, error) {
|
||||
a := &hooksAdapter{
|
||||
implemented: make(map[int]struct{}),
|
||||
}
|
||||
var tt reflect.Type
|
||||
ft := reflect.TypeOf(productHooks)
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements OnConfigurationChange interface.
|
||||
tt = reflect.TypeOf((*OnConfigurationChangeIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[OnConfigurationChangeID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("OnConfigurationChange"); ok {
|
||||
return nil, errors.New("hook has OnConfigurationChange method but does not implement plugin.OnConfigurationChange interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements ExecuteCommand interface.
|
||||
tt = reflect.TypeOf((*ExecuteCommandIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[ExecuteCommandID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("ExecuteCommand"); ok {
|
||||
return nil, errors.New("hook has ExecuteCommand method but does not implement plugin.ExecuteCommand interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements UserHasBeenCreated interface.
|
||||
tt = reflect.TypeOf((*UserHasBeenCreatedIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[UserHasBeenCreatedID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("UserHasBeenCreated"); ok {
|
||||
return nil, errors.New("hook has UserHasBeenCreated method but does not implement plugin.UserHasBeenCreated interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements UserWillLogIn interface.
|
||||
tt = reflect.TypeOf((*UserWillLogInIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[UserWillLogInID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("UserWillLogIn"); ok {
|
||||
return nil, errors.New("hook has UserWillLogIn method but does not implement plugin.UserWillLogIn interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements UserHasLoggedIn interface.
|
||||
tt = reflect.TypeOf((*UserHasLoggedInIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[UserHasLoggedInID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("UserHasLoggedIn"); ok {
|
||||
return nil, errors.New("hook has UserHasLoggedIn method but does not implement plugin.UserHasLoggedIn interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements MessageWillBePosted interface.
|
||||
tt = reflect.TypeOf((*MessageWillBePostedIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[MessageWillBePostedID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("MessageWillBePosted"); ok {
|
||||
return nil, errors.New("hook has MessageWillBePosted method but does not implement plugin.MessageWillBePosted interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements MessageWillBeUpdated interface.
|
||||
tt = reflect.TypeOf((*MessageWillBeUpdatedIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[MessageWillBeUpdatedID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("MessageWillBeUpdated"); ok {
|
||||
return nil, errors.New("hook has MessageWillBeUpdated method but does not implement plugin.MessageWillBeUpdated interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements MessageHasBeenPosted interface.
|
||||
tt = reflect.TypeOf((*MessageHasBeenPostedIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[MessageHasBeenPostedID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("MessageHasBeenPosted"); ok {
|
||||
return nil, errors.New("hook has MessageHasBeenPosted method but does not implement plugin.MessageHasBeenPosted interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements MessageHasBeenUpdated interface.
|
||||
tt = reflect.TypeOf((*MessageHasBeenUpdatedIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[MessageHasBeenUpdatedID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("MessageHasBeenUpdated"); ok {
|
||||
return nil, errors.New("hook has MessageHasBeenUpdated method but does not implement plugin.MessageHasBeenUpdated interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements ChannelHasBeenCreated interface.
|
||||
tt = reflect.TypeOf((*ChannelHasBeenCreatedIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[ChannelHasBeenCreatedID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("ChannelHasBeenCreated"); ok {
|
||||
return nil, errors.New("hook has ChannelHasBeenCreated method but does not implement plugin.ChannelHasBeenCreated interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements UserHasJoinedChannel interface.
|
||||
tt = reflect.TypeOf((*UserHasJoinedChannelIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[UserHasJoinedChannelID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("UserHasJoinedChannel"); ok {
|
||||
return nil, errors.New("hook has UserHasJoinedChannel method but does not implement plugin.UserHasJoinedChannel interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements UserHasLeftChannel interface.
|
||||
tt = reflect.TypeOf((*UserHasLeftChannelIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[UserHasLeftChannelID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("UserHasLeftChannel"); ok {
|
||||
return nil, errors.New("hook has UserHasLeftChannel method but does not implement plugin.UserHasLeftChannel interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements UserHasJoinedTeam interface.
|
||||
tt = reflect.TypeOf((*UserHasJoinedTeamIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[UserHasJoinedTeamID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("UserHasJoinedTeam"); ok {
|
||||
return nil, errors.New("hook has UserHasJoinedTeam method but does not implement plugin.UserHasJoinedTeam interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements UserHasLeftTeam interface.
|
||||
tt = reflect.TypeOf((*UserHasLeftTeamIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[UserHasLeftTeamID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("UserHasLeftTeam"); ok {
|
||||
return nil, errors.New("hook has UserHasLeftTeam method but does not implement plugin.UserHasLeftTeam interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements FileWillBeUploaded interface.
|
||||
tt = reflect.TypeOf((*FileWillBeUploadedIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[FileWillBeUploadedID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("FileWillBeUploaded"); ok {
|
||||
return nil, errors.New("hook has FileWillBeUploaded method but does not implement plugin.FileWillBeUploaded interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements ReactionHasBeenAdded interface.
|
||||
tt = reflect.TypeOf((*ReactionHasBeenAddedIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[ReactionHasBeenAddedID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("ReactionHasBeenAdded"); ok {
|
||||
return nil, errors.New("hook has ReactionHasBeenAdded method but does not implement plugin.ReactionHasBeenAdded interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements ReactionHasBeenRemoved interface.
|
||||
tt = reflect.TypeOf((*ReactionHasBeenRemovedIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[ReactionHasBeenRemovedID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("ReactionHasBeenRemoved"); ok {
|
||||
return nil, errors.New("hook has ReactionHasBeenRemoved method but does not implement plugin.ReactionHasBeenRemoved interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements OnPluginClusterEvent interface.
|
||||
tt = reflect.TypeOf((*OnPluginClusterEventIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[OnPluginClusterEventID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("OnPluginClusterEvent"); ok {
|
||||
return nil, errors.New("hook has OnPluginClusterEvent method but does not implement plugin.OnPluginClusterEvent interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements OnWebSocketConnect interface.
|
||||
tt = reflect.TypeOf((*OnWebSocketConnectIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[OnWebSocketConnectID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("OnWebSocketConnect"); ok {
|
||||
return nil, errors.New("hook has OnWebSocketConnect method but does not implement plugin.OnWebSocketConnect interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements OnWebSocketDisconnect interface.
|
||||
tt = reflect.TypeOf((*OnWebSocketDisconnectIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[OnWebSocketDisconnectID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("OnWebSocketDisconnect"); ok {
|
||||
return nil, errors.New("hook has OnWebSocketDisconnect method but does not implement plugin.OnWebSocketDisconnect interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements WebSocketMessageHasBeenPosted interface.
|
||||
tt = reflect.TypeOf((*WebSocketMessageHasBeenPostedIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[WebSocketMessageHasBeenPostedID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("WebSocketMessageHasBeenPosted"); ok {
|
||||
return nil, errors.New("hook has WebSocketMessageHasBeenPosted method but does not implement plugin.WebSocketMessageHasBeenPosted interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements RunDataRetention interface.
|
||||
tt = reflect.TypeOf((*RunDataRetentionIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[RunDataRetentionID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("RunDataRetention"); ok {
|
||||
return nil, errors.New("hook has RunDataRetention method but does not implement plugin.RunDataRetention interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements OnInstall interface.
|
||||
tt = reflect.TypeOf((*OnInstallIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[OnInstallID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("OnInstall"); ok {
|
||||
return nil, errors.New("hook has OnInstall method but does not implement plugin.OnInstall interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements OnSendDailyTelemetry interface.
|
||||
tt = reflect.TypeOf((*OnSendDailyTelemetryIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[OnSendDailyTelemetryID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("OnSendDailyTelemetry"); ok {
|
||||
return nil, errors.New("hook has OnSendDailyTelemetry method but does not implement plugin.OnSendDailyTelemetry interface")
|
||||
}
|
||||
|
||||
// Assessing the type of the productHooks if it individually implements OnCloudLimitsUpdated interface.
|
||||
tt = reflect.TypeOf((*OnCloudLimitsUpdatedIFace)(nil)).Elem()
|
||||
|
||||
if ft.Implements(tt) {
|
||||
a.implemented[OnCloudLimitsUpdatedID] = struct{}{}
|
||||
} else if _, ok := ft.MethodByName("OnCloudLimitsUpdated"); ok {
|
||||
return nil, errors.New("hook has OnCloudLimitsUpdated method but does not implement plugin.OnCloudLimitsUpdated interface")
|
||||
}
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnConfigurationChange() error {
|
||||
if _, ok := a.implemented[OnConfigurationChangeID]; !ok {
|
||||
panic("product hooks must implement OnConfigurationChange")
|
||||
}
|
||||
|
||||
return a.productHooks.(OnConfigurationChangeIFace).OnConfigurationChange()
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) ExecuteCommand(c *Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
|
||||
if _, ok := a.implemented[ExecuteCommandID]; !ok {
|
||||
panic("product hooks must implement ExecuteCommand")
|
||||
}
|
||||
|
||||
return a.productHooks.(ExecuteCommandIFace).ExecuteCommand(c, args)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) UserHasBeenCreated(c *Context, user *model.User) {
|
||||
if _, ok := a.implemented[UserHasBeenCreatedID]; !ok {
|
||||
panic("product hooks must implement UserHasBeenCreated")
|
||||
}
|
||||
|
||||
a.productHooks.(UserHasBeenCreatedIFace).UserHasBeenCreated(c, user)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) UserWillLogIn(c *Context, user *model.User) string {
|
||||
if _, ok := a.implemented[UserWillLogInID]; !ok {
|
||||
panic("product hooks must implement UserWillLogIn")
|
||||
}
|
||||
|
||||
return a.productHooks.(UserWillLogInIFace).UserWillLogIn(c, user)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) UserHasLoggedIn(c *Context, user *model.User) {
|
||||
if _, ok := a.implemented[UserHasLoggedInID]; !ok {
|
||||
panic("product hooks must implement UserHasLoggedIn")
|
||||
}
|
||||
|
||||
a.productHooks.(UserHasLoggedInIFace).UserHasLoggedIn(c, user)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) MessageWillBePosted(c *Context, post *model.Post) (*model.Post, string) {
|
||||
if _, ok := a.implemented[MessageWillBePostedID]; !ok {
|
||||
panic("product hooks must implement MessageWillBePosted")
|
||||
}
|
||||
|
||||
return a.productHooks.(MessageWillBePostedIFace).MessageWillBePosted(c, post)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) MessageWillBeUpdated(c *Context, newPost, oldPost *model.Post) (*model.Post, string) {
|
||||
if _, ok := a.implemented[MessageWillBeUpdatedID]; !ok {
|
||||
panic("product hooks must implement MessageWillBeUpdated")
|
||||
}
|
||||
|
||||
return a.productHooks.(MessageWillBeUpdatedIFace).MessageWillBeUpdated(c, newPost, oldPost)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) MessageHasBeenPosted(c *Context, post *model.Post) {
|
||||
if _, ok := a.implemented[MessageHasBeenPostedID]; !ok {
|
||||
panic("product hooks must implement MessageHasBeenPosted")
|
||||
}
|
||||
|
||||
a.productHooks.(MessageHasBeenPostedIFace).MessageHasBeenPosted(c, post)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) MessageHasBeenUpdated(c *Context, newPost, oldPost *model.Post) {
|
||||
if _, ok := a.implemented[MessageHasBeenUpdatedID]; !ok {
|
||||
panic("product hooks must implement MessageHasBeenUpdated")
|
||||
}
|
||||
|
||||
a.productHooks.(MessageHasBeenUpdatedIFace).MessageHasBeenUpdated(c, newPost, oldPost)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) ChannelHasBeenCreated(c *Context, channel *model.Channel) {
|
||||
if _, ok := a.implemented[ChannelHasBeenCreatedID]; !ok {
|
||||
panic("product hooks must implement ChannelHasBeenCreated")
|
||||
}
|
||||
|
||||
a.productHooks.(ChannelHasBeenCreatedIFace).ChannelHasBeenCreated(c, channel)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) UserHasJoinedChannel(c *Context, channelMember *model.ChannelMember, actor *model.User) {
|
||||
if _, ok := a.implemented[UserHasJoinedChannelID]; !ok {
|
||||
panic("product hooks must implement UserHasJoinedChannel")
|
||||
}
|
||||
|
||||
a.productHooks.(UserHasJoinedChannelIFace).UserHasJoinedChannel(c, channelMember, actor)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) UserHasLeftChannel(c *Context, channelMember *model.ChannelMember, actor *model.User) {
|
||||
if _, ok := a.implemented[UserHasLeftChannelID]; !ok {
|
||||
panic("product hooks must implement UserHasLeftChannel")
|
||||
}
|
||||
|
||||
a.productHooks.(UserHasLeftChannelIFace).UserHasLeftChannel(c, channelMember, actor)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) UserHasJoinedTeam(c *Context, teamMember *model.TeamMember, actor *model.User) {
|
||||
if _, ok := a.implemented[UserHasJoinedTeamID]; !ok {
|
||||
panic("product hooks must implement UserHasJoinedTeam")
|
||||
}
|
||||
|
||||
a.productHooks.(UserHasJoinedTeamIFace).UserHasJoinedTeam(c, teamMember, actor)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) UserHasLeftTeam(c *Context, teamMember *model.TeamMember, actor *model.User) {
|
||||
if _, ok := a.implemented[UserHasLeftTeamID]; !ok {
|
||||
panic("product hooks must implement UserHasLeftTeam")
|
||||
}
|
||||
|
||||
a.productHooks.(UserHasLeftTeamIFace).UserHasLeftTeam(c, teamMember, actor)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) FileWillBeUploaded(c *Context, info *model.FileInfo, file io.Reader, output io.Writer) (*model.FileInfo, string) {
|
||||
if _, ok := a.implemented[FileWillBeUploadedID]; !ok {
|
||||
panic("product hooks must implement FileWillBeUploaded")
|
||||
}
|
||||
|
||||
return a.productHooks.(FileWillBeUploadedIFace).FileWillBeUploaded(c, info, file, output)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) ReactionHasBeenAdded(c *Context, reaction *model.Reaction) {
|
||||
if _, ok := a.implemented[ReactionHasBeenAddedID]; !ok {
|
||||
panic("product hooks must implement ReactionHasBeenAdded")
|
||||
}
|
||||
|
||||
a.productHooks.(ReactionHasBeenAddedIFace).ReactionHasBeenAdded(c, reaction)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) ReactionHasBeenRemoved(c *Context, reaction *model.Reaction) {
|
||||
if _, ok := a.implemented[ReactionHasBeenRemovedID]; !ok {
|
||||
panic("product hooks must implement ReactionHasBeenRemoved")
|
||||
}
|
||||
|
||||
a.productHooks.(ReactionHasBeenRemovedIFace).ReactionHasBeenRemoved(c, reaction)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnPluginClusterEvent(c *Context, ev model.PluginClusterEvent) {
|
||||
if _, ok := a.implemented[OnPluginClusterEventID]; !ok {
|
||||
panic("product hooks must implement OnPluginClusterEvent")
|
||||
}
|
||||
|
||||
a.productHooks.(OnPluginClusterEventIFace).OnPluginClusterEvent(c, ev)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnWebSocketConnect(webConnID, userID string) {
|
||||
if _, ok := a.implemented[OnWebSocketConnectID]; !ok {
|
||||
panic("product hooks must implement OnWebSocketConnect")
|
||||
}
|
||||
|
||||
a.productHooks.(OnWebSocketConnectIFace).OnWebSocketConnect(webConnID, userID)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnWebSocketDisconnect(webConnID, userID string) {
|
||||
if _, ok := a.implemented[OnWebSocketDisconnectID]; !ok {
|
||||
panic("product hooks must implement OnWebSocketDisconnect")
|
||||
}
|
||||
|
||||
a.productHooks.(OnWebSocketDisconnectIFace).OnWebSocketDisconnect(webConnID, userID)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) WebSocketMessageHasBeenPosted(webConnID, userID string, req *model.WebSocketRequest) {
|
||||
if _, ok := a.implemented[WebSocketMessageHasBeenPostedID]; !ok {
|
||||
panic("product hooks must implement WebSocketMessageHasBeenPosted")
|
||||
}
|
||||
|
||||
a.productHooks.(WebSocketMessageHasBeenPostedIFace).WebSocketMessageHasBeenPosted(webConnID, userID, req)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) RunDataRetention(nowTime, batchSize int64) (int64, error) {
|
||||
if _, ok := a.implemented[RunDataRetentionID]; !ok {
|
||||
panic("product hooks must implement RunDataRetention")
|
||||
}
|
||||
|
||||
return a.productHooks.(RunDataRetentionIFace).RunDataRetention(nowTime, batchSize)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnInstall(c *Context, event model.OnInstallEvent) error {
|
||||
if _, ok := a.implemented[OnInstallID]; !ok {
|
||||
panic("product hooks must implement OnInstall")
|
||||
}
|
||||
|
||||
return a.productHooks.(OnInstallIFace).OnInstall(c, event)
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnSendDailyTelemetry() {
|
||||
if _, ok := a.implemented[OnSendDailyTelemetryID]; !ok {
|
||||
panic("product hooks must implement OnSendDailyTelemetry")
|
||||
}
|
||||
|
||||
a.productHooks.(OnSendDailyTelemetryIFace).OnSendDailyTelemetry()
|
||||
|
||||
}
|
||||
|
||||
func (a *hooksAdapter) OnCloudLimitsUpdated(limits *model.ProductLimits) {
|
||||
if _, ok := a.implemented[OnCloudLimitsUpdatedID]; !ok {
|
||||
panic("product hooks must implement OnCloudLimitsUpdated")
|
||||
}
|
||||
|
||||
a.productHooks.(OnCloudLimitsUpdatedIFace).OnCloudLimitsUpdated(limits)
|
||||
|
||||
}
|
||||
Ссылка в новой задаче
Block a user