Move pluginCommands into Channels (#18974)

* Move pluginCommands into Channels

We move pluginCommands, pluginCommandsLock
into Channels.

We also move the plugin related route handlers
under Channels and move the init code under
NewChannels. To achieve this, the router initialization
is bumped up.

Along with it, we clean up some App methods
which were just wrappers over Channel methods.
Instead, we call the Channel method directly
to make things more readable and easy to understand.

```release-note
NONE
```

* fix tests

```release-note
NONE
```
Этот коммит содержится в:
Agniva De Sarker
2021-11-12 10:35:14 +05:30
коммит произвёл GitHub
родитель 27559c1c7b
Коммит a850704afe
21 изменённых файлов: 120 добавлений и 285 удалений

Просмотреть файл

@@ -151,7 +151,7 @@ func installMarketplacePlugin(c *Context, w http.ResponseWriter, r *http.Request
}
auditRec.AddMeta("plugin_id", pluginRequest.Id)
manifest, appErr := c.App.InstallMarketplacePlugin(pluginRequest)
manifest, appErr := c.App.Channels().InstallMarketplacePlugin(pluginRequest)
if appErr != nil {
c.Err = appErr
return
@@ -231,7 +231,7 @@ func removePlugin(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
err := c.App.RemovePlugin(c.Params.PluginId)
err := c.App.Channels().RemovePlugin(c.Params.PluginId)
if err != nil {
c.Err = err
return

Просмотреть файл

@@ -94,7 +94,7 @@ func TestPlugin(t *testing.T) {
assert.Equal(t, "testplugin", manifest.Id)
})
th.App.RemovePlugin(manifest.Id)
th.App.Channels().RemovePlugin(manifest.Id)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })

Просмотреть файл

@@ -81,6 +81,9 @@ func (s *Server) getFirstServerRunTimestamp() (int64, *model.AppError) {
return value, nil
}
func (a *App) Channels() *Channels {
return a.ch
}
func (a *App) Srv() *Server {
return a.ch.srv
}

Просмотреть файл

@@ -212,13 +212,8 @@ type AppIface interface {
HubRegister(webConn *WebConn)
// HubUnregister unregisters a connection from a hub.
HubUnregister(webConn *WebConn)
// InstallMarketplacePlugin installs a plugin listed in the marketplace server. It will get the plugin bundle
// from the prepackaged folder, if available, or remotely if EnableRemoteMarketplace is true.
InstallMarketplacePlugin(request *model.InstallMarketplacePluginRequest) (*model.Manifest, *model.AppError)
// InstallPlugin unpacks and installs a plugin but does not enable or activate it.
InstallPlugin(pluginFile io.ReadSeeker, replace bool) (*model.Manifest, *model.AppError)
// InstallPluginWithSignature verifies and installs plugin.
InstallPluginWithSignature(pluginFile, signature io.ReadSeeker) (*model.Manifest, *model.AppError)
// LimitedClientConfigWithComputed gets the configuration in a format suitable for sending to the client.
LimitedClientConfigWithComputed() map[string]string
// LogAuditRec logs an audit record using default LvlAuditCLI.
@@ -414,6 +409,7 @@ type AppIface interface {
BulkImportWithPath(c *request.Context, jsonlReader io.Reader, attachmentsReader *zip.Reader, dryRun bool, workers int, importPath string) (*model.AppError, int)
CancelJob(jobId string) *model.AppError
ChannelMembersToRemove(teamID *string) ([]*model.ChannelMember, *model.AppError)
Channels() *Channels
CheckAndSendUserLimitWarningEmails(c *request.Context) *model.AppError
CheckCanInviteToSharedChannel(channelId string) error
CheckCloudAccountAtLimit() (bool, *model.AppError)
@@ -809,7 +805,6 @@ type AppIface interface {
ImageProxyRemover() (f func(string) string)
ImportPermissions(jsonl io.Reader) error
InitPlugins(c *request.Context, pluginDir, webappPluginDir string)
InstallPluginFromData(data model.PluginEventData)
InvalidateAllEmailInvites() *model.AppError
InvalidateCacheForUser(userID string)
InviteGuestsToChannels(teamID string, guestsInvite *model.GuestsInvite, senderId string) *model.AppError
@@ -899,8 +894,6 @@ type AppIface interface {
RemoveFile(path string) *model.AppError
RemoveLdapPrivateCertificate() *model.AppError
RemoveLdapPublicCertificate() *model.AppError
RemovePlugin(id string) *model.AppError
RemovePluginFromData(data model.PluginEventData)
RemoveRecentCustomStatus(userID string, status *model.CustomStatus) *model.AppError
RemoveSamlIdpCertificate() *model.AppError
RemoveSamlPrivateCertificate() *model.AppError
@@ -990,7 +983,6 @@ type AppIface interface {
SetPluginKey(pluginID string, key string, value []byte) *model.AppError
SetPluginKeyWithExpiry(pluginID string, key string, value []byte, expireInSeconds int64) *model.AppError
SetPluginKeyWithOptions(pluginID string, key string, value []byte, options model.PluginKVSetOptions) (bool, *model.AppError)
SetPluginsEnvironment(pluginsEnvironment *plugin.Environment)
SetProfileImage(userID string, imageData *multipart.FileHeader) *model.AppError
SetProfileImageFromFile(userID string, file io.Reader) *model.AppError
SetProfileImageFromMultiPartFile(userID string, file multipart.File) *model.AppError
@@ -1014,7 +1006,6 @@ type AppIface interface {
SwitchEmailToOAuth(w http.ResponseWriter, r *http.Request, email, password, code, service string) (string, *model.AppError)
SwitchLdapToEmail(ldapPassword, code, email, newPassword string) (string, *model.AppError)
SwitchOAuthToEmail(email, password, requesterId string) (string, *model.AppError)
SyncPluginsActiveState()
TeamMembersToRemove(teamID *string) ([]*model.TeamMember, *model.AppError)
TelemetryId() string
TestElasticsearch(cfg *model.Config) *model.AppError
@@ -1028,7 +1019,6 @@ type AppIface interface {
TotalWebsocketConnections() int
TriggerWebhook(c *request.Context, payload *model.OutgoingWebhookPayload, hook *model.OutgoingWebhook, post *model.Post, channel *model.Channel)
UnregisterPluginCommand(pluginID, teamID, trigger string)
UnregisterPluginCommands(pluginID string)
UpdateActive(c *request.Context, user *model.User, active bool) (*model.User, *model.AppError)
UpdateChannelLastViewedAt(channelIDs []string, userID string) *model.AppError
UpdateChannelMemberNotifyProps(data map[string]string, channelID string, userID string) (*model.ChannelMember, *model.AppError)

Просмотреть файл

@@ -18,9 +18,11 @@ import (
type Channels struct {
srv *Server
pluginCommandsLock sync.RWMutex
pluginCommands []*PluginCommand
pluginsLock sync.RWMutex
pluginsEnvironment *plugin.Environment
pluginConfigListenerID string
pluginsLock sync.RWMutex
imageProxy *imageproxy.ImageProxy
@@ -44,10 +46,17 @@ func init() {
}
func NewChannels(s *Server) (*Channels, error) {
return &Channels{
ch := &Channels{
srv: s,
imageProxy: imageproxy.MakeImageProxy(s, s.httpService, s.Log),
}, nil
}
// Setup routes.
pluginsRoute := ch.srv.Router.PathPrefix("/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}").Subrouter()
pluginsRoute.HandleFunc("", ch.ServePluginRequest)
pluginsRoute.HandleFunc("/public/{public_file:.*}", ch.ServePluginPublicRequest)
pluginsRoute.HandleFunc("/{anything:.*}", ch.ServePluginRequest)
return ch, nil
}
func (ch *Channels) Start() error {

Просмотреть файл

@@ -423,7 +423,7 @@ func (a *App) doPluginRequest(c *request.Context, method, rawURL string, values
params["plugin_id"] = pluginID
r = mux.SetURLVars(r, params)
a.ch.srv.ServePluginRequest(w, r)
a.ch.ServePluginRequest(w, r)
resp := &http.Response{
StatusCode: w.status,

Просмотреть файл

@@ -12,6 +12,7 @@ import (
"testing"
"time"
"github.com/gorilla/mux"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
@@ -1381,6 +1382,7 @@ func TestPushNotificationRace(t *testing.T) {
configStore: memoryStore,
Store: mockStore,
products: make(map[string]Product),
Router: mux.NewRouter(),
}
ch, err := NewChannels(s)
require.NoError(t, err)

Просмотреть файл

@@ -1112,6 +1112,23 @@ func (a *OpenTracingAppLayer) ChannelMembersToRemove(teamID *string) ([]*model.C
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) Channels() *app.Channels {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.Channels")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.Channels()
return resultVar0
}
func (a *OpenTracingAppLayer) CheckAndSendUserLimitWarningEmails(c *request.Context) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CheckAndSendUserLimitWarningEmails")
@@ -10623,28 +10640,6 @@ func (a *OpenTracingAppLayer) InitPlugins(c *request.Context, pluginDir string,
a.app.InitPlugins(c, pluginDir, webappPluginDir)
}
func (a *OpenTracingAppLayer) InstallMarketplacePlugin(request *model.InstallMarketplacePluginRequest) (*model.Manifest, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.InstallMarketplacePlugin")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.InstallMarketplacePlugin(request)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) InstallPlugin(pluginFile io.ReadSeeker, replace bool) (*model.Manifest, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.InstallPlugin")
@@ -10667,43 +10662,6 @@ func (a *OpenTracingAppLayer) InstallPlugin(pluginFile io.ReadSeeker, replace bo
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) InstallPluginFromData(data model.PluginEventData) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.InstallPluginFromData")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
a.app.InstallPluginFromData(data)
}
func (a *OpenTracingAppLayer) InstallPluginWithSignature(pluginFile io.ReadSeeker, signature io.ReadSeeker) (*model.Manifest, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.InstallPluginWithSignature")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.InstallPluginWithSignature(pluginFile, signature)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) InvalidateAllEmailInvites() *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.InvalidateAllEmailInvites")
@@ -12769,43 +12727,6 @@ func (a *OpenTracingAppLayer) RemoveLdapPublicCertificate() *model.AppError {
return resultVar0
}
func (a *OpenTracingAppLayer) RemovePlugin(id string) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemovePlugin")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.RemovePlugin(id)
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))
ext.Error.Set(span, true)
}
return resultVar0
}
func (a *OpenTracingAppLayer) RemovePluginFromData(data model.PluginEventData) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemovePluginFromData")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
a.app.RemovePluginFromData(data)
}
func (a *OpenTracingAppLayer) RemoveRecentCustomStatus(userID string, status *model.CustomStatus) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemoveRecentCustomStatus")
@@ -14835,21 +14756,6 @@ func (a *OpenTracingAppLayer) SetPluginKeyWithOptions(pluginID string, key strin
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) SetPluginsEnvironment(pluginsEnvironment *plugin.Environment) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SetPluginsEnvironment")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
a.app.SetPluginsEnvironment(pluginsEnvironment)
}
func (a *OpenTracingAppLayer) SetProfileImage(userID string, imageData *multipart.FileHeader) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SetProfileImage")
@@ -15352,21 +15258,6 @@ func (a *OpenTracingAppLayer) SyncPlugins() *model.AppError {
return resultVar0
}
func (a *OpenTracingAppLayer) SyncPluginsActiveState() {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SyncPluginsActiveState")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
a.app.SyncPluginsActiveState()
}
func (a *OpenTracingAppLayer) SyncRolesAndMembership(c *request.Context, syncableID string, syncableType model.GroupSyncableType, includeRemovedMembers bool) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SyncRolesAndMembership")
@@ -15688,21 +15579,6 @@ func (a *OpenTracingAppLayer) UnregisterPluginCommand(pluginID string, teamID st
a.app.UnregisterPluginCommand(pluginID, teamID, trigger)
}
func (a *OpenTracingAppLayer) UnregisterPluginCommands(pluginID string) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UnregisterPluginCommands")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
a.app.UnregisterPluginCommands(pluginID)
}
func (a *OpenTracingAppLayer) UpdateActive(c *request.Context, user *model.User, active bool) (*model.User, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateActive")

Просмотреть файл

@@ -62,15 +62,11 @@ func (a *App) GetPluginsEnvironment() *plugin.Environment {
return a.ch.GetPluginsEnvironment()
}
func (a *App) SetPluginsEnvironment(pluginsEnvironment *plugin.Environment) {
a.ch.pluginsLock.Lock()
defer a.ch.pluginsLock.Unlock()
func (ch *Channels) SetPluginsEnvironment(pluginsEnvironment *plugin.Environment) {
ch.pluginsLock.Lock()
defer ch.pluginsLock.Unlock()
a.ch.pluginsEnvironment = pluginsEnvironment
}
func (a *App) SyncPluginsActiveState() {
a.ch.syncPluginsActiveState()
ch.pluginsEnvironment = pluginsEnvironment
}
func (ch *Channels) syncPluginsActiveState() {
@@ -452,7 +448,7 @@ func (ch *Channels) disablePlugin(id string) *model.AppError {
ch.srv.UpdateConfig(func(cfg *model.Config) {
cfg.PluginSettings.PluginStates[id] = &model.PluginState{Enable: false}
})
ch.srv.unregisterPluginCommands(id)
ch.unregisterPluginCommands(id)
// This call will implicitly invoke SyncPluginsActiveState which will deactivate disabled plugins.
if _, _, err := ch.srv.SaveConfig(ch.srv.Config(), true); err != nil {
@@ -994,7 +990,7 @@ func (ch *Channels) installFeatureFlagPlugins() {
}
}
_, err := ch.installMarketplacePlugin(&model.InstallMarketplacePluginRequest{
_, err := ch.InstallMarketplacePlugin(&model.InstallMarketplacePluginRequest{
Id: pluginID,
Version: version,
})

Просмотреть файл

@@ -832,7 +832,7 @@ func (api *PluginAPI) DisablePlugin(id string) *model.AppError {
}
func (api *PluginAPI) RemovePlugin(id string) *model.AppError {
return api.app.RemovePlugin(id)
return api.app.Channels().RemovePlugin(id)
}
func (api *PluginAPI) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) {

Просмотреть файл

@@ -119,7 +119,7 @@ func setupMultiPluginAPITest(t *testing.T, pluginCodes []string, pluginManifests
})
}
app.SetPluginsEnvironment(env)
app.ch.SetPluginsEnvironment(env)
return pluginDir
}
@@ -854,7 +854,7 @@ func TestPluginAPIGetPlugins(t *testing.T) {
require.True(t, activated)
pluginManifests = append(pluginManifests, manifest)
}
th.App.SetPluginsEnvironment(env)
th.App.ch.SetPluginsEnvironment(env)
// Deactivate the last one for testing
success := env.Deactivate(pluginIDs[len(pluginIDs)-1])
@@ -928,7 +928,7 @@ func TestInstallPlugin(t *testing.T) {
env, err := plugin.NewEnvironment(newPluginAPI, NewDriverImpl(app.Srv()), pluginDir, webappPluginDir, app.Log(), nil)
require.NoError(t, err)
app.SetPluginsEnvironment(env)
app.ch.SetPluginsEnvironment(env)
backend := filepath.Join(pluginDir, pluginID, "backend.exe")
utils.CompileGo(t, pluginCode, backend)
@@ -1604,7 +1604,7 @@ func TestAPIMetrics(t *testing.T) {
env, err := plugin.NewEnvironment(th.NewPluginAPI, NewDriverImpl(th.Server), pluginDir, webappPluginDir, th.App.Log(), metricsMock)
require.NoError(t, err)
th.App.SetPluginsEnvironment(env)
th.App.ch.SetPluginsEnvironment(env)
pluginID := model.NewId()
backend := filepath.Join(pluginDir, pluginID, "backend.exe")

Просмотреть файл

@@ -54,10 +54,10 @@ func (a *App) RegisterPluginCommand(pluginID string, command *model.Command) err
AutocompleteIconData: command.AutocompleteIconData,
}
a.Srv().pluginCommandsLock.Lock()
defer a.Srv().pluginCommandsLock.Unlock()
a.ch.pluginCommandsLock.Lock()
defer a.ch.pluginCommandsLock.Unlock()
for _, pc := range a.Srv().pluginCommands {
for _, pc := range a.ch.pluginCommands {
if pc.Command.Trigger == command.Trigger && pc.Command.TeamId == command.TeamId {
if pc.PluginId == pluginID {
pc.Command = command
@@ -66,7 +66,7 @@ func (a *App) RegisterPluginCommand(pluginID string, command *model.Command) err
}
}
a.Srv().pluginCommands = append(a.Srv().pluginCommands, &PluginCommand{
a.ch.pluginCommands = append(a.ch.pluginCommands, &PluginCommand{
Command: command,
PluginId: pluginID,
})
@@ -76,41 +76,37 @@ func (a *App) RegisterPluginCommand(pluginID string, command *model.Command) err
func (a *App) UnregisterPluginCommand(pluginID, teamID, trigger string) {
trigger = strings.ToLower(trigger)
a.Srv().pluginCommandsLock.Lock()
defer a.Srv().pluginCommandsLock.Unlock()
a.ch.pluginCommandsLock.Lock()
defer a.ch.pluginCommandsLock.Unlock()
var remaining []*PluginCommand
for _, pc := range a.Srv().pluginCommands {
for _, pc := range a.ch.pluginCommands {
if pc.Command.TeamId != teamID || pc.Command.Trigger != trigger {
remaining = append(remaining, pc)
}
}
a.Srv().pluginCommands = remaining
a.ch.pluginCommands = remaining
}
func (a *App) UnregisterPluginCommands(pluginID string) {
a.Srv().unregisterPluginCommands(pluginID)
}
func (s *Server) unregisterPluginCommands(pluginID string) {
s.pluginCommandsLock.Lock()
defer s.pluginCommandsLock.Unlock()
func (ch *Channels) unregisterPluginCommands(pluginID string) {
ch.pluginCommandsLock.Lock()
defer ch.pluginCommandsLock.Unlock()
var remaining []*PluginCommand
for _, pc := range s.pluginCommands {
for _, pc := range ch.pluginCommands {
if pc.PluginId != pluginID {
remaining = append(remaining, pc)
}
}
s.pluginCommands = remaining
ch.pluginCommands = remaining
}
func (a *App) PluginCommandsForTeam(teamID string) []*model.Command {
a.Srv().pluginCommandsLock.RLock()
defer a.Srv().pluginCommandsLock.RUnlock()
a.ch.pluginCommandsLock.RLock()
defer a.ch.pluginCommandsLock.RUnlock()
var commands []*model.Command
for _, pc := range a.Srv().pluginCommands {
for _, pc := range a.ch.pluginCommands {
if pc.Command.TeamId == "" || pc.Command.TeamId == teamID {
commands = append(commands, pc.Command)
}
@@ -126,14 +122,14 @@ func (a *App) tryExecutePluginCommand(c *request.Context, args *model.CommandArg
trigger = strings.ToLower(trigger)
var matched *PluginCommand
a.Srv().pluginCommandsLock.RLock()
for _, pc := range a.Srv().pluginCommands {
a.ch.pluginCommandsLock.RLock()
for _, pc := range a.ch.pluginCommands {
if (pc.Command.TeamId == "" || pc.Command.TeamId == args.TeamId) && pc.Command.Trigger == trigger {
matched = pc
break
}
}
a.Srv().pluginCommandsLock.RUnlock()
a.ch.pluginCommandsLock.RUnlock()
if matched == nil {
return nil, nil, nil
}

Просмотреть файл

@@ -106,7 +106,7 @@ func TestPluginCommand(t *testing.T) {
require.NotEqual(t, "plugin", commands.Trigger)
}
th.App.RemovePlugin(pluginIDs[0])
th.App.ch.RemovePlugin(pluginIDs[0])
})
t.Run("re-entrant command registration on config change", func(t *testing.T) {
@@ -207,7 +207,7 @@ func TestPluginCommand(t *testing.T) {
killed = true
}
th.App.RemovePlugin(pluginIDs[0])
th.App.ch.RemovePlugin(pluginIDs[0])
require.False(t, killed, "execute command appears to have deadlocked")
})
@@ -285,7 +285,7 @@ func TestPluginCommand(t *testing.T) {
require.Equal(t, model.CommandResponseTypeEphemeral, resp.ResponseType)
require.Equal(t, "text", resp.Text)
th.App.RemovePlugin(pluginIDs[0])
th.App.ch.RemovePlugin(pluginIDs[0])
})
t.Run("plugin has crashed before execution of command", func(t *testing.T) {
tearDown, pluginIDs, activationErrors := SetAppEnvironmentWithPlugins(t, []string{`
@@ -329,7 +329,7 @@ func TestPluginCommand(t *testing.T) {
require.Nil(t, resp)
require.NotNil(t, err)
require.Equal(t, err.Id, "model.plugin_command_error.error.app_error")
th.App.RemovePlugin(pluginIDs[0])
th.App.ch.RemovePlugin(pluginIDs[0])
})
t.Run("plugin has crashed due to the execution of the command", func(t *testing.T) {
@@ -374,7 +374,7 @@ func TestPluginCommand(t *testing.T) {
require.Nil(t, resp)
require.NotNil(t, err)
require.Equal(t, err.Id, "model.plugin_command_crash.error.app_error")
th.App.RemovePlugin(pluginIDs[0])
th.App.ch.RemovePlugin(pluginIDs[0])
})
}

Просмотреть файл

@@ -37,7 +37,7 @@ func SetAppEnvironmentWithPlugins(t *testing.T, pluginCode []string, app *App, a
env, err := plugin.NewEnvironment(apiFunc, NewDriverImpl(app.Srv()), pluginDir, webappPluginDir, app.Log(), nil)
require.NoError(t, err)
app.SetPluginsEnvironment(env)
app.ch.SetPluginsEnvironment(env)
pluginIDs := []string{}
activationErrors := []error{}
for _, code := range pluginCode {
@@ -1048,7 +1048,7 @@ func TestHookMetrics(t *testing.T) {
env, err := plugin.NewEnvironment(th.NewPluginAPI, NewDriverImpl(th.Server), pluginDir, webappPluginDir, th.App.Log(), metricsMock)
require.NoError(t, err)
th.App.SetPluginsEnvironment(env)
th.App.ch.SetPluginsEnvironment(env)
pluginID := model.NewId()
backend := filepath.Join(pluginDir, pluginID, "backend.exe")

Просмотреть файл

@@ -61,10 +61,6 @@ const managedPluginFileName = ".filestore"
// fileStorePluginFolder is the folder name in the file store of the plugin bundles installed.
const fileStorePluginFolder = "plugins"
func (a *App) InstallPluginFromData(data model.PluginEventData) {
a.ch.installPluginFromData(data)
}
func (ch *Channels) installPluginFromData(data model.PluginEventData) {
mlog.Debug("Installing plugin as per cluster message", mlog.String("plugin_id", data.Id))
@@ -111,10 +107,6 @@ func (ch *Channels) installPluginFromData(data model.PluginEventData) {
}
}
func (a *App) RemovePluginFromData(data model.PluginEventData) {
a.ch.removePluginFromData(data)
}
func (ch *Channels) removePluginFromData(data model.PluginEventData) {
mlog.Debug("Removing plugin as per cluster message", mlog.String("plugin_id", data.Id))
@@ -128,10 +120,6 @@ func (ch *Channels) removePluginFromData(data model.PluginEventData) {
}
// InstallPluginWithSignature verifies and installs plugin.
func (a *App) InstallPluginWithSignature(pluginFile, signature io.ReadSeeker) (*model.Manifest, *model.AppError) {
return a.ch.installPluginWithSignature(pluginFile, signature)
}
func (ch *Channels) installPluginWithSignature(pluginFile, signature io.ReadSeeker) (*model.Manifest, *model.AppError) {
return ch.installPlugin(pluginFile, signature, installPluginLocallyAlways)
}
@@ -189,11 +177,7 @@ func (ch *Channels) installPlugin(pluginFile, signature io.ReadSeeker, installat
// InstallMarketplacePlugin installs a plugin listed in the marketplace server. It will get the plugin bundle
// from the prepackaged folder, if available, or remotely if EnableRemoteMarketplace is true.
func (a *App) InstallMarketplacePlugin(request *model.InstallMarketplacePluginRequest) (*model.Manifest, *model.AppError) {
return a.ch.installMarketplacePlugin(request)
}
func (ch *Channels) installMarketplacePlugin(request *model.InstallMarketplacePluginRequest) (*model.Manifest, *model.AppError) {
func (ch *Channels) InstallMarketplacePlugin(request *model.InstallMarketplacePluginRequest) (*model.Manifest, *model.AppError) {
var pluginFile, signatureFile io.ReadSeeker
prepackagedPlugin, appErr := ch.getPrepackagedPlugin(request.Id, request.Version)
@@ -257,10 +241,6 @@ const (
installPluginLocallyAlways
)
func (a *App) installPluginLocally(pluginFile, signature io.ReadSeeker, installationStrategy pluginInstallationStrategy) (*model.Manifest, *model.AppError) {
return a.ch.installPluginLocally(pluginFile, signature, installationStrategy)
}
func (ch *Channels) installPluginLocally(pluginFile, signature io.ReadSeeker, installationStrategy pluginInstallationStrategy) (*model.Manifest, *model.AppError) {
pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil {
@@ -412,11 +392,7 @@ func (ch *Channels) installExtractedPlugin(manifest *model.Manifest, fromPluginD
return manifest, nil
}
func (a *App) RemovePlugin(id string) *model.AppError {
return a.ch.removePlugin(id)
}
func (ch *Channels) removePlugin(id string) *model.AppError {
func (ch *Channels) RemovePlugin(id string) *model.AppError {
// Disable plugin before removal to make sure this
// plugin remains disabled on re-install.
if err := ch.disablePlugin(id); err != nil {
@@ -457,10 +433,6 @@ func (ch *Channels) removePlugin(id string) *model.AppError {
return nil
}
func (a *App) removePluginLocally(id string) *model.AppError {
return a.ch.removePluginLocally(id)
}
func (ch *Channels) removePluginLocally(id string) *model.AppError {
pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil {
@@ -488,7 +460,7 @@ func (ch *Channels) removePluginLocally(id string) *model.AppError {
pluginsEnvironment.Deactivate(id)
pluginsEnvironment.RemovePlugin(id)
ch.srv.unregisterPluginCommands(id)
ch.unregisterPluginCommands(id)
if err := os.RemoveAll(pluginPath); err != nil {
return model.NewAppError("removePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError)

Просмотреть файл

@@ -73,7 +73,7 @@ func TestInstallPluginLocally(t *testing.T) {
th := Setup(t)
defer th.TearDown()
actualManifest, appErr := th.App.installPluginLocally(&nilReadSeeker{}, nil, installPluginLocallyOnlyIfNew)
actualManifest, appErr := th.App.ch.installPluginLocally(&nilReadSeeker{}, nil, installPluginLocallyOnlyIfNew)
require.NotNil(t, appErr)
assert.Equal(t, "app.plugin.extract.app_error", appErr.Id, appErr.Error())
require.Nil(t, actualManifest)
@@ -87,7 +87,7 @@ func TestInstallPluginLocally(t *testing.T) {
{"test", "test file"},
})
actualManifest, appErr := th.App.installPluginLocally(reader, nil, installPluginLocallyOnlyIfNew)
actualManifest, appErr := th.App.ch.installPluginLocally(reader, nil, installPluginLocallyOnlyIfNew)
require.NotNil(t, appErr)
assert.Equal(t, "app.plugin.manifest.app_error", appErr.Id, appErr.Error())
require.Nil(t, actualManifest)
@@ -106,7 +106,7 @@ func TestInstallPluginLocally(t *testing.T) {
{"plugin.json", string(manifestJSON)},
})
actualManifest, appError := th.App.installPluginLocally(reader, nil, installationStrategy)
actualManifest, appError := th.App.ch.installPluginLocally(reader, nil, installationStrategy)
if actualManifest != nil {
require.Equal(t, manifest, actualManifest)
}
@@ -134,7 +134,7 @@ func TestInstallPluginLocally(t *testing.T) {
require.NoError(t, err)
for _, bundleInfo := range bundleInfos {
err := th.App.removePluginLocally(bundleInfo.Manifest.Id)
err := th.App.ch.removePluginLocally(bundleInfo.Manifest.Id)
require.Nilf(t, err, "failed to remove existing plugin %s", bundleInfo.Manifest.Id)
}
}

Просмотреть файл

@@ -20,11 +20,11 @@ import (
"github.com/mattermost/mattermost-server/v6/utils"
)
func (s *Server) ServePluginRequest(w http.ResponseWriter, r *http.Request) {
pluginsEnvironment := s.Channels().GetPluginsEnvironment()
func (ch *Channels) ServePluginRequest(w http.ResponseWriter, r *http.Request) {
pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil {
err := model.NewAppError("ServePluginRequest", "app.plugin.disabled.app_error", nil, "Enable plugins to serve plugin requests", http.StatusNotImplemented)
s.Log.Error(err.Error())
mlog.Error(err.Error())
w.WriteHeader(err.StatusCode)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(err.ToJSON()))
@@ -34,7 +34,7 @@ func (s *Server) ServePluginRequest(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
hooks, err := pluginsEnvironment.HooksForPlugin(params["plugin_id"])
if err != nil {
s.Log.Error("Access to route for non-existent plugin",
mlog.Error("Access to route for non-existent plugin",
mlog.String("missing_plugin_id", params["plugin_id"]),
mlog.String("url", r.URL.String()),
mlog.Err(err))
@@ -42,7 +42,7 @@ func (s *Server) ServePluginRequest(w http.ResponseWriter, r *http.Request) {
return
}
s.servePluginRequest(w, r, hooks.ServeHTTP)
ch.servePluginRequest(w, r, hooks.ServeHTTP)
}
func (a *App) ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId, destinationPluginId string) {
@@ -80,7 +80,7 @@ func (a *App) ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, so
// ServePluginPublicRequest serves public plugin files
// at the URL http(s)://$SITE_URL/plugins/$PLUGIN_ID/public/{anything}
func (s *Server) ServePluginPublicRequest(w http.ResponseWriter, r *http.Request) {
func (ch *Channels) ServePluginPublicRequest(w http.ResponseWriter, r *http.Request) {
if strings.HasSuffix(r.URL.Path, "/") {
http.NotFound(w, r)
return
@@ -90,7 +90,7 @@ func (s *Server) ServePluginPublicRequest(w http.ResponseWriter, r *http.Request
vars := mux.Vars(r)
pluginID := vars["plugin_id"]
pluginsEnv := s.Channels().GetPluginsEnvironment()
pluginsEnv := ch.GetPluginsEnvironment()
// Check if someone has nullified the pluginsEnv in the meantime
if pluginsEnv == nil {
@@ -114,11 +114,11 @@ func (s *Server) ServePluginPublicRequest(w http.ResponseWriter, r *http.Request
http.ServeFile(w, r, publicFile)
}
func (s *Server) servePluginRequest(w http.ResponseWriter, r *http.Request, handler func(*plugin.Context, http.ResponseWriter, *http.Request)) {
func (ch *Channels) servePluginRequest(w http.ResponseWriter, r *http.Request, handler func(*plugin.Context, http.ResponseWriter, *http.Request)) {
token := ""
context := &plugin.Context{
RequestId: model.NewId(),
IPAddress: utils.GetIPAddress(r, s.Config().ServiceSettings.TrustedProxyIPHeader),
IPAddress: utils.GetIPAddress(r, ch.srv.Config().ServiceSettings.TrustedProxyIPHeader),
AcceptLanguage: r.Header.Get("Accept-Language"),
UserAgent: r.UserAgent(),
}
@@ -141,8 +141,8 @@ func (s *Server) servePluginRequest(w http.ResponseWriter, r *http.Request, hand
r.Header.Del("Mattermost-User-Id")
if token != "" {
session, err := New(ServerConnector(s.Channels())).GetSession(token)
defer s.userService.ReturnSessionToPool(session)
session, err := New(ServerConnector(ch)).GetSession(token)
defer ch.srv.userService.ReturnSessionToPool(session)
csrfCheckPassed := false
@@ -183,10 +183,10 @@ func (s *Server) servePluginRequest(w http.ResponseWriter, r *http.Request, hand
mlog.String("user_id", userID),
}
if *s.Config().ServiceSettings.ExperimentalStrictCSRFEnforcement {
s.Log.Warn(csrfErrorMessage, fields...)
if *ch.srv.Config().ServiceSettings.ExperimentalStrictCSRFEnforcement {
mlog.Warn(csrfErrorMessage, fields...)
} else {
s.Log.Debug(csrfErrorMessage, fields...)
mlog.Debug(csrfErrorMessage, fields...)
csrfCheckPassed = true
}
}
@@ -212,7 +212,7 @@ func (s *Server) servePluginRequest(w http.ResponseWriter, r *http.Request, hand
params := mux.Vars(r)
subpath, _ := utils.GetSubpathFromConfig(s.Config())
subpath, _ := utils.GetSubpathFromConfig(ch.srv.Config())
newQuery := r.URL.Query()
newQuery.Del("access_token")

Просмотреть файл

@@ -24,7 +24,7 @@ func TestServePluginPublicRequest(t *testing.T) {
require.NoError(t, err)
rr := httptest.NewRecorder()
handler := http.HandlerFunc(th.App.Srv().ServePluginPublicRequest)
handler := http.HandlerFunc(th.App.ch.ServePluginPublicRequest)
handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusNotFound, rr.Code)

Просмотреть файл

@@ -342,7 +342,7 @@ func TestServePluginRequest(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest("GET", "/plugins/foo/bar", nil)
th.App.ch.srv.ServePluginRequest(w, r)
th.App.ch.ServePluginRequest(w, r)
assert.Equal(t, http.StatusNotImplemented, w.Result().StatusCode)
}
@@ -386,7 +386,7 @@ func TestPrivateServePluginRequest(t *testing.T) {
request = mux.SetURLVars(request, map[string]string{"plugin_id": "id"})
th.App.ch.srv.servePluginRequest(recorder, request, handler)
th.App.ch.servePluginRequest(recorder, request, handler)
})
}
@@ -409,7 +409,7 @@ func TestHandlePluginRequest(t *testing.T) {
var assertions func(*http.Request)
router := mux.NewRouter()
router.HandleFunc("/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}/{anything:.*}", func(_ http.ResponseWriter, r *http.Request) {
th.App.ch.srv.servePluginRequest(nil, r, func(_ *plugin.Context, _ http.ResponseWriter, r *http.Request) {
th.App.ch.servePluginRequest(nil, r, func(_ *plugin.Context, _ http.ResponseWriter, r *http.Request) {
assertions(r)
})
})
@@ -621,7 +621,7 @@ func TestPluginSync(t *testing.T) {
appErr = th.App.DeletePublicKey("pub_key")
checkNoError(t, appErr)
appErr = th.App.RemovePlugin("testplugin")
appErr = th.App.ch.RemovePlugin("testplugin")
checkNoError(t, appErr)
})
})
@@ -758,7 +758,7 @@ func TestProcessPrepackagedPlugins(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, pluginBytes)
manifest, appErr := th.App.installPluginLocally(bytes.NewReader(pluginBytes), nil, installPluginLocallyAlways)
manifest, appErr := th.App.ch.installPluginLocally(bytes.NewReader(pluginBytes), nil, installPluginLocallyAlways)
require.Nil(t, appErr)
require.Equal(t, "testplugin", manifest.Id)
@@ -785,7 +785,7 @@ func TestProcessPrepackagedPlugins(t *testing.T) {
require.Len(t, pluginStatus, 1)
require.Equal(t, pluginStatus[0].PluginId, "testplugin")
appErr = th.App.RemovePlugin("testplugin")
appErr = th.App.ch.RemovePlugin("testplugin")
checkNoError(t, appErr)
pluginStatus, err = env.Statuses()
@@ -866,7 +866,7 @@ func TestProcessPrepackagedPlugins(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, pluginBytes)
manifest, appErr := th.App.installPluginLocally(bytes.NewReader(pluginBytes), nil, installPluginLocallyAlways)
manifest, appErr := th.App.ch.installPluginLocally(bytes.NewReader(pluginBytes), nil, installPluginLocallyAlways)
require.Nil(t, appErr)
require.Equal(t, "testplugin", manifest.Id)
@@ -896,7 +896,7 @@ func TestProcessPrepackagedPlugins(t *testing.T) {
require.Len(t, pluginStatus, 1)
require.Equal(t, pluginStatus[0].PluginId, "testplugin")
appErr = th.App.RemovePlugin("testplugin")
appErr = th.App.ch.RemovePlugin("testplugin")
checkNoError(t, appErr)
pluginStatus, err = env.Statuses()

Просмотреть файл

@@ -142,9 +142,6 @@ type Server struct {
configStore *config.Store
postActionCookieSecret []byte
pluginCommands []*PluginCommand
pluginCommandsLock sync.RWMutex
telemetryService *telemetry.TelemetryService
userService *users.UserService
teamService *teams.TeamService
@@ -213,6 +210,7 @@ func NewServer(options ...Option) (*Server, error) {
licenseListeners: map[string]func(*model.License, *model.License){},
hashSeed: maphash.MakeSeed(),
uploadLockMap: map[string]bool{},
timezones: timezones.New(),
products: make(map[string]Product),
}
@@ -245,6 +243,12 @@ func NewServer(options ...Option) (*Server, error) {
mlog.Error("Could not initiate logging", mlog.Err(err))
}
subpath, err := utils.GetSubpathFromConfig(s.Config())
if err != nil {
return nil, errors.Wrap(err, "failed to parse SiteURL subpath")
}
s.Router = s.RootRouter.PathPrefix(subpath).Subrouter()
// This is called after initLogging() to avoid a race condition.
mlog.Info("Server is initializing...", mlog.String("go_version", runtime.Version()))
@@ -253,9 +257,9 @@ func NewServer(options ...Option) (*Server, error) {
// Step 3: Initialize products.
// Depends on s.httpService.
for name, initializer := range products {
prod, err := initializer(s)
if err != nil {
return nil, errors.Wrapf(err, "error initializing product: %s", name)
prod, err2 := initializer(s)
if err2 != nil {
return nil, errors.Wrapf(err2, "error initializing product: %s", name)
}
s.products[name] = prod
@@ -280,8 +284,8 @@ func NewServer(options ...Option) (*Server, error) {
// At the moment we only have this implementation
// in the future the cache provider will be built based on the loaded config
s.CacheProvider = cache.NewProvider()
if err := s.CacheProvider.Connect(); err != nil {
return nil, errors.Wrapf(err, "Unable to connect to cache provider")
if err2 := s.CacheProvider.Connect(); err2 != nil {
return nil, errors.Wrapf(err2, "Unable to connect to cache provider")
}
// It is important to initialize the hub only after the global logger is set
@@ -326,7 +330,6 @@ func NewServer(options ...Option) (*Server, error) {
}
}
var err error
s.Store, err = s.newStore()
if err != nil {
return nil, errors.Wrap(err, "cannot create store")
@@ -532,17 +535,6 @@ func NewServer(options ...Option) (*Server, error) {
return nil, errors.Wrapf(err, "unable to ensure first run timestamp")
}
subpath, err := utils.GetSubpathFromConfig(s.Config())
if err != nil {
return nil, errors.Wrap(err, "failed to parse SiteURL subpath")
}
s.Router = s.RootRouter.PathPrefix(subpath).Subrouter()
pluginsRoute := s.Router.PathPrefix("/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}").Subrouter()
pluginsRoute.HandleFunc("", s.ServePluginRequest)
pluginsRoute.HandleFunc("/public/{public_file:.*}", s.ServePluginPublicRequest)
pluginsRoute.HandleFunc("/{anything:.*}", s.ServePluginRequest)
// If configured with a subpath, redirect 404s at the root back into the subpath.
if subpath != "/" {
s.RootRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -580,7 +572,6 @@ func NewServer(options ...Option) (*Server, error) {
}
}
s.timezones = timezones.New()
// Start email batching because it's not like the other jobs
s.AddConfigListener(func(_, _ *model.Config) {
s.EmailService.InitEmailBatching()

Просмотреть файл

@@ -327,7 +327,7 @@ func TestPublicFilesRequest(t *testing.T) {
require.NotNil(t, manifest)
require.True(t, activated)
th.App.SetPluginsEnvironment(env)
th.App.Channels().SetPluginsEnvironment(env)
req, _ := http.NewRequest("GET", "/plugins/com.mattermost.sample/public/hello.html", nil)
res := httptest.NewRecorder()