summaryrefslogtreecommitdiffstats
path: root/plugin/pluginenv
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/pluginenv')
-rw-r--r--plugin/pluginenv/environment.go64
-rw-r--r--plugin/pluginenv/environment_test.go48
2 files changed, 103 insertions, 9 deletions
diff --git a/plugin/pluginenv/environment.go b/plugin/pluginenv/environment.go
index 26511c651..f53021f74 100644
--- a/plugin/pluginenv/environment.go
+++ b/plugin/pluginenv/environment.go
@@ -223,35 +223,59 @@ func (env *Environment) Shutdown() (errs []error) {
return
}
-type EnvironmentHooks struct {
+type MultiPluginHooks struct {
env *Environment
}
-func (env *Environment) Hooks() *EnvironmentHooks {
- return &EnvironmentHooks{env}
+type SinglePluginHooks struct {
+ env *Environment
+ pluginId string
}
-// OnConfigurationChange invokes the OnConfigurationChange hook for all plugins. Any errors
-// encountered will be returned.
-func (h *EnvironmentHooks) OnConfigurationChange() (errs []error) {
+func (env *Environment) Hooks() *MultiPluginHooks {
+ return &MultiPluginHooks{
+ env: env,
+ }
+}
+
+func (env *Environment) HooksForPlugin(id string) *SinglePluginHooks {
+ return &SinglePluginHooks{
+ env: env,
+ pluginId: id,
+ }
+}
+
+func (h *MultiPluginHooks) invoke(f func(plugin.Hooks) error) (errs []error) {
h.env.mutex.RLock()
defer h.env.mutex.RUnlock()
+
for _, activePlugin := range h.env.activePlugins {
if activePlugin.Supervisor == nil {
continue
}
- if err := activePlugin.Supervisor.Hooks().OnConfigurationChange(); err != nil {
- errs = append(errs, errors.Wrapf(err, "OnConfigurationChange error for %v", activePlugin.BundleInfo.Manifest.Id))
+ if err := f(activePlugin.Supervisor.Hooks()); err != nil {
+ errs = append(errs, errors.Wrapf(err, "hook error for %v", activePlugin.BundleInfo.Manifest.Id))
}
}
return
}
+// OnConfigurationChange invokes the OnConfigurationChange hook for all plugins. Any errors
+// encountered will be returned.
+func (h *MultiPluginHooks) OnConfigurationChange() []error {
+ return h.invoke(func(hooks plugin.Hooks) error {
+ if err := hooks.OnConfigurationChange(); err != nil {
+ return errors.Wrapf(err, "error calling OnConfigurationChange hook")
+ }
+ return nil
+ })
+}
+
// ServeHTTP invokes the ServeHTTP hook for the plugin identified by the request or responds with a
// 404 not found.
//
// It expects the request's context to have a plugin_id set.
-func (h *EnvironmentHooks) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+func (h *MultiPluginHooks) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if id := r.Context().Value("plugin_id"); id != nil {
if idstr, ok := id.(string); ok {
h.env.mutex.RLock()
@@ -264,3 +288,25 @@ func (h *EnvironmentHooks) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
http.NotFound(w, r)
}
+
+func (h *SinglePluginHooks) invoke(f func(plugin.Hooks) error) error {
+ h.env.mutex.RLock()
+ defer h.env.mutex.RUnlock()
+
+ if activePlugin, ok := h.env.activePlugins[h.pluginId]; ok && activePlugin.Supervisor != nil {
+ if err := f(activePlugin.Supervisor.Hooks()); err != nil {
+ return errors.Wrapf(err, "hook error for plugin: %v", activePlugin.BundleInfo.Manifest.Id)
+ }
+ return nil
+ }
+ return fmt.Errorf("unable to invoke hook for plugin: %v", h.pluginId)
+}
+
+// ExecuteCommand invokes the ExecuteCommand hook for the plugin.
+func (h *SinglePluginHooks) ExecuteCommand(args *model.CommandArgs) (resp *model.CommandResponse, appErr *model.AppError, err error) {
+ err = h.invoke(func(hooks plugin.Hooks) error {
+ resp, appErr = hooks.ExecuteCommand(args)
+ return nil
+ })
+ return
+}
diff --git a/plugin/pluginenv/environment_test.go b/plugin/pluginenv/environment_test.go
index 988e5b08f..2a52b3830 100644
--- a/plugin/pluginenv/environment_test.go
+++ b/plugin/pluginenv/environment_test.go
@@ -355,3 +355,51 @@ func TestEnvironment_ConcurrentHookInvocations(t *testing.T) {
wg.Wait()
}
+
+func TestEnvironment_HooksForPlugins(t *testing.T) {
+ dir := initTmpDir(t, map[string]string{
+ "foo/plugin.json": `{"id": "foo", "backend": {}}`,
+ })
+ defer os.RemoveAll(dir)
+
+ var provider MockProvider
+ defer provider.AssertExpectations(t)
+
+ env, err := New(
+ SearchPath(dir),
+ APIProvider(provider.API),
+ SupervisorProvider(provider.Supervisor),
+ )
+ require.NoError(t, err)
+ defer env.Shutdown()
+
+ var api struct{ plugin.API }
+ var supervisor MockSupervisor
+ defer supervisor.AssertExpectations(t)
+ var hooks plugintest.Hooks
+ defer hooks.AssertExpectations(t)
+
+ provider.On("API").Return(&api, nil)
+ provider.On("Supervisor").Return(&supervisor, nil)
+
+ supervisor.On("Start", &api).Return(nil)
+ supervisor.On("Stop").Return(nil)
+ supervisor.On("Hooks").Return(&hooks)
+
+ hooks.On("OnDeactivate").Return(nil)
+ hooks.On("ExecuteCommand", mock.AnythingOfType("*model.CommandArgs")).Return(&model.CommandResponse{
+ Text: "bar",
+ }, nil)
+
+ assert.NoError(t, env.ActivatePlugin("foo"))
+ assert.Equal(t, env.ActivePluginIds(), []string{"foo"})
+
+ resp, appErr, err := env.HooksForPlugin("foo").ExecuteCommand(&model.CommandArgs{
+ Command: "/foo",
+ })
+ assert.Equal(t, "bar", resp.Text)
+ assert.Nil(t, appErr)
+ assert.NoError(t, err)
+
+ assert.Empty(t, env.Shutdown())
+}