We create the basic boilerplate to pass services
to each product. The basic idea is to have a map
containing service names and the services.

The server will pass all services to all products.
But it is on the product, to choose what services
they will actually consume.

Each product will cast the received service to
an interface with the methods that product requires.

https://mattermost.atlassian.net/browse/MM-40813

```release-note
NONE
```
Этот коммит содержится в:
Agniva De Sarker
2022-02-21 21:41:04 +05:30
коммит произвёл GitHub
родитель e96daef1e1
Коммит dbf779b828
13 изменённых файлов: 194 добавлений и 98 удалений

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

@@ -111,7 +111,7 @@ func (s *Server) configureAudit(adt *audit.Audit, bAllowAdvancedLogging bool) er
dsn := *s.Config().ExperimentalAuditSettings.AdvancedLoggingConfig
if bAllowAdvancedLogging && dsn != "" {
var err error
logConfigSrc, err = config.NewLogConfigSrc(dsn, s.configStore)
logConfigSrc, err = config.NewLogConfigSrc(dsn, s.configStore.Store)
if err != nil {
return fmt.Errorf("invalid config source for audit, %w", err)
}

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

@@ -4,6 +4,7 @@
package app
import (
"fmt"
"runtime"
"strings"
"sync"
@@ -20,9 +21,26 @@ import (
"github.com/pkg/errors"
)
// configSvc is a consumer interface to work
// with any config related task with the server.
type configSvc interface {
Config() *model.Config
AddConfigListener(listener func(*model.Config, *model.Config)) string
RemoveConfigListener(id string)
UpdateConfig(f func(*model.Config))
SaveConfig(newCfg *model.Config, sendConfigChangeClusterMessage bool) (*model.Config, *model.Config, *model.AppError)
}
// namer is an interface which enforces that
// all services can return their names.
type namer interface {
Name() ServiceKey
}
// Channels contains all channels related state.
type Channels struct {
srv *Server
srv *Server
cfgSvc configSvc
postActionCookieSecret []byte
@@ -65,17 +83,44 @@ type Channels struct {
}
func init() {
RegisterProduct("channels", func(s *Server) (Product, error) {
return NewChannels(s)
RegisterProduct("channels", func(s *Server, services map[ServiceKey]interface{}) (Product, error) {
return NewChannels(s, services)
})
}
func NewChannels(s *Server) (*Channels, error) {
func NewChannels(s *Server, services map[ServiceKey]interface{}) (*Channels, error) {
ch := &Channels{
srv: s,
imageProxy: imageproxy.MakeImageProxy(s, s.httpService, s.Log),
uploadLockMap: map[string]bool{},
}
// To get another service:
// 1. Prepare the service interface
// 2. Add the field to *Channels
// 3. Add the service key to the slice.
// 4. Add a new case in the switch statement.
requiredServices := []ServiceKey{ConfigKey}
for _, svcKey := range requiredServices {
svc, ok := services[svcKey]
if !ok {
return nil, fmt.Errorf("Service %s not passed", svcKey)
}
switch svcKey {
// Keep adding more services here
case ConfigKey:
cfgSvc, ok := svc.(configSvc)
if !ok {
return nil, errors.New("Config service did not satisfy ConfigSvc interface")
}
_, ok = svc.(namer)
if !ok {
return nil, errors.New("Config service does not contain Name method")
}
ch.cfgSvc = cfgSvc
}
}
// We are passing a partially filled Channels struct so that the enterprise
// methods can have access to app methods.
// Otherwise, passing server would mean it has to call s.Channels(),
@@ -119,7 +164,7 @@ func NewChannels(s *Server) (*Channels, error) {
func (ch *Channels) Start() error {
// Start plugins
ctx := request.EmptyContext()
ch.initPlugins(ctx, *ch.srv.Config().PluginSettings.Directory, *ch.srv.Config().PluginSettings.ClientDirectory)
ch.initPlugins(ctx, *ch.cfgSvc.Config().PluginSettings.Directory, *ch.cfgSvc.Config().PluginSettings.ClientDirectory)
ch.AddConfigListener(func(prevCfg, cfg *model.Config) {
// We compute the difference between configs
@@ -142,7 +187,7 @@ func (ch *Channels) Start() error {
// Do only if some plugin related settings has changed.
if hasDiff {
if *cfg.PluginSettings.Enable {
ch.initPlugins(ctx, *cfg.PluginSettings.Directory, *ch.srv.Config().PluginSettings.ClientDirectory)
ch.initPlugins(ctx, *cfg.PluginSettings.Directory, *ch.cfgSvc.Config().PluginSettings.ClientDirectory)
} else {
ch.ShutDownPlugins()
}

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

@@ -31,8 +31,82 @@ const (
ErrorTermsOfServiceNoRowsFound = "app.terms_of_service.get.no_rows.app_error"
)
// configWrapper is an adapter struct that only exposes the
// config related functionality to be passed down to other products.
type configWrapper struct {
srv *Server
*config.Store
}
func (w *configWrapper) Name() ServiceKey {
return ConfigKey
}
func (w *configWrapper) Config() *model.Config {
return w.Store.Get()
}
func (w *configWrapper) AddConfigListener(listener func(*model.Config, *model.Config)) string {
return w.Store.AddListener(listener)
}
func (w *configWrapper) RemoveConfigListener(id string) {
w.Store.RemoveListener(id)
}
func (w *configWrapper) UpdateConfig(f func(*model.Config)) {
if w.Store.IsReadOnly() {
return
}
old := w.Config()
updated := old.Clone()
f(updated)
if _, _, err := w.Store.Set(updated); err != nil {
mlog.Error("Failed to update config", mlog.Err(err))
}
}
func (w *configWrapper) SaveConfig(newCfg *model.Config, sendConfigChangeClusterMessage bool) (*model.Config, *model.Config, *model.AppError) {
oldCfg, newCfg, err := w.Store.Set(newCfg)
if errors.Cause(err) == config.ErrReadOnlyConfiguration {
return nil, nil, model.NewAppError("saveConfig", "ent.cluster.save_config.error", nil, err.Error(), http.StatusForbidden)
} else if err != nil {
return nil, nil, model.NewAppError("saveConfig", "app.save_config.app_error", nil, err.Error(), http.StatusInternalServerError)
}
if w.srv.startMetrics && *w.Config().MetricsSettings.Enable {
if w.srv.Metrics != nil {
w.srv.Metrics.Register()
}
w.srv.SetupMetricsServer()
} else {
w.srv.StopMetricsServer()
}
if w.srv.Cluster != nil {
err := w.srv.Cluster.ConfigChanged(w.Store.RemoveEnvironmentOverrides(oldCfg),
w.Store.RemoveEnvironmentOverrides(newCfg), sendConfigChangeClusterMessage)
if err != nil {
return nil, nil, err
}
}
return oldCfg, newCfg, nil
}
func (w *configWrapper) ReloadConfig() error {
if err := w.Store.Load(); err != nil {
return err
}
return nil
}
func (s *Server) Config() *model.Config {
return s.configStore.Get()
return s.configStore.Config()
}
func (s *Server) ConfigStore() *configWrapper {
return s.configStore
}
func (a *App) Config() *model.Config {
@@ -48,15 +122,7 @@ func (a *App) EnvironmentConfig(filter func(reflect.StructField) bool) map[strin
}
func (s *Server) UpdateConfig(f func(*model.Config)) {
if s.configStore.IsReadOnly() {
return
}
old := s.Config()
updated := old.Clone()
f(updated)
if _, _, err := s.configStore.Set(updated); err != nil {
mlog.Error("Failed to update config", mlog.Err(err))
}
s.configStore.UpdateConfig(f)
}
func (a *App) UpdateConfig(f func(*model.Config)) {
@@ -64,10 +130,7 @@ func (a *App) UpdateConfig(f func(*model.Config)) {
}
func (s *Server) ReloadConfig() error {
if err := s.configStore.Load(); err != nil {
return err
}
return nil
return s.configStore.ReloadConfig()
}
func (a *App) ReloadConfig() error {
@@ -90,7 +153,7 @@ func (a *App) LimitedClientConfig() map[string]string {
// will be called with two arguments: the old config and the new config. AddConfigListener returns a unique ID
// for the listener that can later be used to remove it.
func (s *Server) AddConfigListener(listener func(*model.Config, *model.Config)) string {
return s.configStore.AddListener(listener)
return s.configStore.AddConfigListener(listener)
}
func (a *App) AddConfigListener(listener func(*model.Config, *model.Config)) string {
@@ -99,7 +162,7 @@ func (a *App) AddConfigListener(listener func(*model.Config, *model.Config)) str
// Removes a listener function by the unique ID returned when AddConfigListener was called
func (s *Server) RemoveConfigListener(id string) {
s.configStore.RemoveListener(id)
s.configStore.RemoveConfigListener(id)
}
func (a *App) RemoveConfigListener(id string) {
@@ -303,8 +366,8 @@ func (a *App) PostActionCookieSecret() []byte {
}
func (ch *Channels) regenerateClientConfig() {
clientConfig := config.GenerateClientConfig(ch.srv.Config(), ch.srv.TelemetryId(), ch.srv.License())
limitedClientConfig := config.GenerateLimitedClientConfig(ch.srv.Config(), ch.srv.TelemetryId(), ch.srv.License())
clientConfig := config.GenerateClientConfig(ch.cfgSvc.Config(), ch.srv.TelemetryId(), ch.srv.License())
limitedClientConfig := config.GenerateLimitedClientConfig(ch.cfgSvc.Config(), ch.srv.TelemetryId(), ch.srv.License())
if clientConfig["EnableCustomTermsOfService"] == "true" {
termsOfService, err := ch.srv.Store.TermsOfService().GetLatest(true)
@@ -402,31 +465,7 @@ func (a *App) GetEnvironmentConfig(filter func(reflect.StructField) bool) map[st
// SaveConfig replaces the active configuration, optionally notifying cluster peers.
// It returns both the previous and current configs.
func (s *Server) SaveConfig(newCfg *model.Config, sendConfigChangeClusterMessage bool) (*model.Config, *model.Config, *model.AppError) {
oldCfg, newCfg, err := s.configStore.Set(newCfg)
if errors.Cause(err) == config.ErrReadOnlyConfiguration {
return nil, nil, model.NewAppError("saveConfig", "ent.cluster.save_config.error", nil, err.Error(), http.StatusForbidden)
} else if err != nil {
return nil, nil, model.NewAppError("saveConfig", "app.save_config.app_error", nil, err.Error(), http.StatusInternalServerError)
}
if s.startMetrics && *s.Config().MetricsSettings.Enable {
if s.Metrics != nil {
s.Metrics.Register()
}
s.SetupMetricsServer()
} else {
s.StopMetricsServer()
}
if s.Cluster != nil {
err := s.Cluster.ConfigChanged(s.configStore.RemoveEnvironmentOverrides(oldCfg),
s.configStore.RemoveEnvironmentOverrides(newCfg), sendConfigChangeClusterMessage)
if err != nil {
return nil, nil, err
}
}
return oldCfg, newCfg, nil
return s.configStore.SaveConfig(newCfg, sendConfigChangeClusterMessage)
}
// SaveConfig replaces the active configuration, optionally notifying cluster peers.

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

@@ -1403,12 +1403,15 @@ func TestPushNotificationRace(t *testing.T) {
Return(&model.Preference{Value: "test"}, nil)
mockStore.On("Preference").Return(&mockPreferenceStore)
s := &Server{
configStore: memoryStore,
Store: mockStore,
products: make(map[string]Product),
Router: mux.NewRouter(),
Store: mockStore,
products: make(map[string]Product),
Router: mux.NewRouter(),
}
ch, err := NewChannels(s)
s.configStore = &configWrapper{srv: s, Store: memoryStore}
serviceMap := map[ServiceKey]interface{}{
ConfigKey: s.configStore,
}
ch, err := NewChannels(s, serviceMap)
require.NoError(t, err)
s.products["channels"] = ch

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

@@ -50,7 +50,7 @@ func Config(dsn string, readOnly bool, configDefaults *model.Config) Option {
return errors.Wrap(err, "failed to apply Config option")
}
s.configStore = configStore
s.configStore = &configWrapper{srv: s, Store: configStore}
return nil
}
}
@@ -58,7 +58,7 @@ func Config(dsn string, readOnly bool, configDefaults *model.Config) Option {
// ConfigStore applies the given config store, typically to replace the traditional sources with a memory store for testing.
func ConfigStore(configStore *config.Store) Option {
return func(s *Server) error {
s.configStore = configStore
s.configStore = &configWrapper{srv: s, Store: configStore}
return nil
}

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

@@ -43,7 +43,7 @@ type pluginSignaturePath struct {
// To get the plugins environment when the plugins are disabled, manually acquire the plugins
// lock instead.
func (ch *Channels) GetPluginsEnvironment() *plugin.Environment {
if !*ch.srv.Config().PluginSettings.Enable {
if !*ch.cfgSvc.Config().PluginSettings.Enable {
return nil
}
@@ -79,7 +79,7 @@ func (ch *Channels) syncPluginsActiveState() {
return
}
config := ch.srv.Config().PluginSettings
config := ch.cfgSvc.Config().PluginSettings
if *config.Enable {
availablePlugins, err := pluginsEnvironment.Available()
@@ -100,7 +100,7 @@ func (ch *Channels) syncPluginsActiveState() {
// Tie Apps proxy disabled status to the feature flag.
if pluginID == "com.mattermost.apps" {
if !ch.srv.Config().FeatureFlags.AppsEnabled {
if !ch.cfgSvc.Config().FeatureFlags.AppsEnabled {
pluginEnabled = false
}
}
@@ -174,10 +174,10 @@ func (ch *Channels) initPlugins(c *request.Context, pluginDir, webappPluginDir s
ch.pluginsLock.RLock()
pluginsEnvironment := ch.pluginsEnvironment
ch.pluginsLock.RUnlock()
if pluginsEnvironment != nil || !*ch.srv.Config().PluginSettings.Enable {
if pluginsEnvironment != nil || !*ch.cfgSvc.Config().PluginSettings.Enable {
ch.syncPluginsActiveState()
if pluginsEnvironment != nil {
pluginsEnvironment.TogglePluginHealthCheckJob(*ch.srv.Config().PluginSettings.EnableHealthCheck)
pluginsEnvironment.TogglePluginHealthCheckJob(*ch.cfgSvc.Config().PluginSettings.EnableHealthCheck)
}
return
}
@@ -207,7 +207,7 @@ func (ch *Channels) initPlugins(c *request.Context, pluginDir, webappPluginDir s
ch.pluginsEnvironment = env
ch.pluginsLock.Unlock()
ch.pluginsEnvironment.TogglePluginHealthCheckJob(*ch.srv.Config().PluginSettings.EnableHealthCheck)
ch.pluginsEnvironment.TogglePluginHealthCheckJob(*ch.cfgSvc.Config().PluginSettings.EnableHealthCheck)
if err := ch.syncPlugins(); err != nil {
mlog.Error("Failed to sync plugins from the file store", mlog.Err(err))
@@ -274,7 +274,7 @@ func (ch *Channels) syncPlugins() *model.AppError {
go func(pluginID string) {
defer wg.Done()
// Only handle managed plugins with .filestore flag file.
_, err := os.Stat(filepath.Join(*ch.srv.Config().PluginSettings.Directory, pluginID, managedPluginFileName))
_, err := os.Stat(filepath.Join(*ch.cfgSvc.Config().PluginSettings.Directory, pluginID, managedPluginFileName))
if os.IsNotExist(err) {
mlog.Warn("Skipping sync for unmanaged plugin", mlog.String("plugin_id", pluginID))
} else if err != nil {
@@ -307,7 +307,7 @@ func (ch *Channels) syncPlugins() *model.AppError {
defer reader.Close()
var signature filestore.ReadCloseSeeker
if *ch.srv.Config().PluginSettings.RequirePluginSignature {
if *ch.cfgSvc.Config().PluginSettings.RequirePluginSignature {
signature, appErr = ch.srv.fileReader(plugin.signaturePath)
if appErr != nil {
mlog.Error("Failed to open plugin signature from file store.", mlog.Err(appErr))
@@ -401,12 +401,12 @@ func (ch *Channels) enablePlugin(id string) *model.AppError {
return model.NewAppError("EnablePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusNotFound)
}
ch.srv.UpdateConfig(func(cfg *model.Config) {
ch.cfgSvc.UpdateConfig(func(cfg *model.Config) {
cfg.PluginSettings.PluginStates[id] = &model.PluginState{Enable: true}
})
// This call will implicitly invoke SyncPluginsActiveState which will activate enabled plugins.
if _, _, err := ch.srv.SaveConfig(ch.srv.Config(), true); err != nil {
if _, _, err := ch.cfgSvc.SaveConfig(ch.cfgSvc.Config(), true); err != nil {
if err.Id == "ent.cluster.save_config.error" {
return model.NewAppError("EnablePlugin", "app.plugin.cluster.save_config.app_error", nil, "", http.StatusInternalServerError)
}
@@ -447,13 +447,13 @@ func (ch *Channels) disablePlugin(id string) *model.AppError {
return model.NewAppError("DisablePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusNotFound)
}
ch.srv.UpdateConfig(func(cfg *model.Config) {
ch.cfgSvc.UpdateConfig(func(cfg *model.Config) {
cfg.PluginSettings.PluginStates[id] = &model.PluginState{Enable: false}
})
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 {
if _, _, err := ch.cfgSvc.SaveConfig(ch.cfgSvc.Config(), true); err != nil {
return model.NewAppError("DisablePlugin", "app.plugin.config.app_error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -561,7 +561,7 @@ func (ch *Channels) getPrepackagedPlugin(pluginID, version string) (*plugin.Prep
// If version is empty, the latest compatible version is used.
func (ch *Channels) getRemoteMarketplacePlugin(pluginID, version string) (*model.BaseMarketplacePlugin, *model.AppError) {
marketplaceClient, err := marketplace.NewClient(
*ch.srv.Config().PluginSettings.MarketplaceURL,
*ch.cfgSvc.Config().PluginSettings.MarketplaceURL,
ch.srv.HTTPService(),
)
if err != nil {
@@ -835,8 +835,8 @@ func (ch *Channels) getPluginsFromFilePaths(fileStorePaths []string) map[string]
pluginSignaturePathMap := make(map[string]*pluginSignaturePath)
fsPrefix := ""
if *ch.srv.Config().FileSettings.DriverName == model.ImageDriverS3 {
ptr := ch.srv.Config().FileSettings.AmazonS3PathPrefix
if *ch.cfgSvc.Config().FileSettings.DriverName == model.ImageDriverS3 {
ptr := ch.cfgSvc.Config().FileSettings.AmazonS3PathPrefix
if ptr != nil && *ptr != "" {
fsPrefix = *ptr + "/"
}
@@ -936,12 +936,12 @@ func (ch *Channels) processPrepackagedPlugin(pluginPath *pluginSignaturePath) (*
}
// Skip installing the plugin at all if automatic prepackaged plugins is disabled
if !*ch.srv.Config().PluginSettings.AutomaticPrepackagedPlugins {
if !*ch.cfgSvc.Config().PluginSettings.AutomaticPrepackagedPlugins {
return plugin, nil
}
// Skip installing if the plugin is has not been previously enabled.
pluginState := ch.srv.Config().PluginSettings.PluginStates[plugin.Manifest.Id]
pluginState := ch.cfgSvc.Config().PluginSettings.PluginStates[plugin.Manifest.Id]
if pluginState == nil || !pluginState.Enable {
return plugin, nil
}
@@ -956,16 +956,16 @@ func (ch *Channels) processPrepackagedPlugin(pluginPath *pluginSignaturePath) (*
// installFeatureFlagPlugins handles the automatic installation/upgrade of plugins from feature flags
func (ch *Channels) installFeatureFlagPlugins() {
ffControledPlugins := ch.srv.Config().FeatureFlags.Plugins()
ffControledPlugins := ch.cfgSvc.Config().FeatureFlags.Plugins()
// Respect the automatic prepackaged disable setting
if !*ch.srv.Config().PluginSettings.AutomaticPrepackagedPlugins {
if !*ch.cfgSvc.Config().PluginSettings.AutomaticPrepackagedPlugins {
return
}
for pluginID, version := range ffControledPlugins {
// Skip installing if the plugin has been previously disabled.
pluginState := ch.srv.Config().PluginSettings.PluginStates[pluginID]
pluginState := ch.cfgSvc.Config().PluginSettings.PluginStates[pluginID]
if pluginState != nil && !pluginState.Enable {
ch.srv.Log.Debug("Not auto installing/upgrade because plugin was disabled", mlog.String("plugin_id", pluginID), mlog.String("version", version))
continue

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

@@ -83,7 +83,7 @@ func (ch *Channels) installPluginFromData(data model.PluginEventData) {
defer reader.Close()
var signature filestore.ReadCloseSeeker
if *ch.srv.Config().PluginSettings.RequirePluginSignature {
if *ch.cfgSvc.Config().PluginSettings.RequirePluginSignature {
signature, appErr = ch.srv.fileReader(plugin.signaturePath)
if appErr != nil {
mlog.Error("Failed to open plugin signature from file store.", mlog.Err(appErr))
@@ -196,7 +196,7 @@ func (ch *Channels) InstallMarketplacePlugin(request *model.InstallMarketplacePl
signatureFile = bytes.NewReader(prepackagedPlugin.Signature)
}
if *ch.srv.Config().PluginSettings.EnableRemoteMarketplace && pluginFile == nil {
if *ch.cfgSvc.Config().PluginSettings.EnableRemoteMarketplace && pluginFile == nil {
var plugin *model.BaseMarketplacePlugin
plugin, appErr = ch.getRemoteMarketplacePlugin(request.Id, request.Version)
if appErr != nil {
@@ -353,7 +353,7 @@ func (ch *Channels) installExtractedPlugin(manifest *model.Manifest, fromPluginD
}
}
pluginPath := filepath.Join(*ch.srv.Config().PluginSettings.Directory, manifest.Id)
pluginPath := filepath.Join(*ch.cfgSvc.Config().PluginSettings.Directory, manifest.Id)
err = utils.CopyDir(fromPluginDir, pluginPath)
if err != nil {
return nil, model.NewAppError("installExtractedPlugin", "app.plugin.mvdir.app_error", nil, err.Error(), http.StatusInternalServerError)
@@ -375,9 +375,9 @@ func (ch *Channels) installExtractedPlugin(manifest *model.Manifest, fromPluginD
}
// Activate the plugin if enabled.
pluginState := ch.srv.Config().PluginSettings.PluginStates[manifest.Id]
pluginState := ch.cfgSvc.Config().PluginSettings.PluginStates[manifest.Id]
if pluginState != nil && pluginState.Enable {
if manifest.Id == "com.mattermost.apps" && !ch.srv.Config().FeatureFlags.AppsEnabled {
if manifest.Id == "com.mattermost.apps" && !ch.cfgSvc.Config().FeatureFlags.AppsEnabled {
return manifest, nil
}
updatedManifest, _, err := pluginsEnvironment.Activate(manifest.Id)

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

@@ -118,7 +118,7 @@ func (ch *Channels) servePluginRequest(w http.ResponseWriter, r *http.Request, h
token := ""
context := &plugin.Context{
RequestId: model.NewId(),
IPAddress: utils.GetIPAddress(r, ch.srv.Config().ServiceSettings.TrustedProxyIPHeader),
IPAddress: utils.GetIPAddress(r, ch.cfgSvc.Config().ServiceSettings.TrustedProxyIPHeader),
AcceptLanguage: r.Header.Get("Accept-Language"),
UserAgent: r.UserAgent(),
}
@@ -183,7 +183,7 @@ func (ch *Channels) servePluginRequest(w http.ResponseWriter, r *http.Request, h
mlog.String("user_id", userID),
}
if *ch.srv.Config().ServiceSettings.ExperimentalStrictCSRFEnforcement {
if *ch.cfgSvc.Config().ServiceSettings.ExperimentalStrictCSRFEnforcement {
mlog.Warn(csrfErrorMessage, fields...)
} else {
mlog.Debug(csrfErrorMessage, fields...)
@@ -212,7 +212,7 @@ func (ch *Channels) servePluginRequest(w http.ResponseWriter, r *http.Request, h
params := mux.Vars(r)
subpath, _ := utils.GetSubpathFromConfig(ch.srv.Config())
subpath, _ := utils.GetSubpathFromConfig(ch.cfgSvc.Config())
newQuery := r.URL.Query()
newQuery.Del("access_token")

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

@@ -81,7 +81,7 @@ func (ch *Channels) verifyPlugin(plugin, signature io.ReadSeeker) *model.AppErro
if err := verifySignature(bytes.NewReader(mattermostPluginPublicKey), plugin, signature); err == nil {
return nil
}
publicKeys := ch.srv.Config().PluginSettings.SignaturePublicKeyFiles
publicKeys := ch.cfgSvc.Config().PluginSettings.SignaturePublicKeyFiles
for _, pk := range publicKeys {
pkBytes, appErr := ch.srv.getPublicKey(pk)
if appErr != nil {

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

@@ -80,7 +80,7 @@ func (ch *Channels) getClusterPluginStatuses() (model.PluginStatuses, *model.App
return nil, err
}
if ch.srv.Cluster != nil && *ch.srv.Config().ClusterSettings.Enable {
if ch.srv.Cluster != nil && *ch.cfgSvc.Config().ClusterSettings.Enable {
clusterPluginStatuses, err := ch.srv.Cluster.GetPluginStatuses()
if err != nil {
return nil, model.NewAppError("GetClusterPluginStatuses", "app.plugin.get_cluster_plugin_statuses.app_error", nil, err.Error(), http.StatusInternalServerError)

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

@@ -8,8 +8,8 @@ type Product interface {
Stop() error
}
var products = make(map[string]func(*Server) (Product, error))
var products = make(map[string]func(*Server, map[ServiceKey]interface{}) (Product, error))
func RegisterProduct(name string, f func(*Server) (Product, error)) {
func RegisterProduct(name string, f func(*Server, map[ServiceKey]interface{}) (Product, error)) {
products[name] = f
}

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

@@ -86,6 +86,12 @@ import (
// declaring this as var to allow overriding in tests
var SentryDSN = "placeholder_sentry_dsn"
type ServiceKey string
const (
ConfigKey ServiceKey = "config"
)
type Server struct {
sqlStore *sqlstore.SqlStore
Store store.Store
@@ -150,7 +156,7 @@ type Server struct {
searchConfigListenerId string
searchLicenseListenerId string
loggerLicenseListenerId string
configStore *config.Store
configStore *configWrapper
telemetryService *telemetry.TelemetryService
userService *users.UserService
@@ -231,7 +237,7 @@ func NewServer(options ...Option) (*Server, error) {
return nil, errors.Wrap(err, "failed to load config")
}
s.configStore = configStore
s.configStore = &configWrapper{srv: s, Store: configStore}
}
// Step 2: Logging
@@ -250,10 +256,13 @@ func NewServer(options ...Option) (*Server, error) {
s.httpService = httpservice.MakeHTTPService(s)
serviceMap := map[ServiceKey]interface{}{
ConfigKey: s.configStore,
}
// Step 3: Initialize products.
// Depends on s.httpService.
for name, initializer := range products {
prod, err2 := initializer(s)
prod, err2 := initializer(s, serviceMap)
if err2 != nil {
return nil, errors.Wrapf(err2, "error initializing product: %s", name)
}
@@ -755,7 +764,7 @@ func (s *Server) initLogging() error {
s.NotificationsLog = l.With(mlog.String("logSource", "notifications"))
}
if err := s.configureLogger("logging", s.Log, &s.Config().LogSettings, s.configStore, config.GetLogFileLocation); err != nil {
if err := s.configureLogger("logging", s.Log, &s.Config().LogSettings, s.configStore.Store, config.GetLogFileLocation); err != nil {
// if the config is locked then a unit test has already configured and locked the logger; not an error.
if !errors.Is(err, mlog.ErrConfigurationLock) {
// revert to default logger if the config is invalid
@@ -771,7 +780,7 @@ func (s *Server) initLogging() error {
mlog.InitGlobalLogger(s.Log)
notificationLogSettings := config.GetLogSettingsFromNotificationsLogSettings(&s.Config().NotificationLogSettings)
if err := s.configureLogger("notification logging", s.NotificationsLog, notificationLogSettings, s.configStore, config.GetNotificationsLogFileLocation); err != nil {
if err := s.configureLogger("notification logging", s.NotificationsLog, notificationLogSettings, s.configStore.Store, config.GetNotificationsLogFileLocation); err != nil {
if !errors.Is(err, mlog.ErrConfigurationLock) {
mlog.Error("Error configuring notification logger", mlog.Err(err))
return err

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

@@ -85,7 +85,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
s, err := NewServer(func(server *Server) error {
configStore := config.NewTestMemoryStore()
configStore.Set(&cfg)
server.configStore = configStore
server.configStore = &configWrapper{srv: server, Store: configStore}
return nil
})
require.NoError(t, err)
@@ -111,7 +111,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
s, err := NewServer(func(server *Server) error {
configStore := config.NewTestMemoryStore()
configStore.Set(&cfg)
server.configStore = configStore
server.configStore = &configWrapper{srv: server, Store: configStore}
return nil
})
require.NoError(t, err)
@@ -124,7 +124,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
s, err := NewServer(func(server *Server) error {
configStore := config.NewTestMemoryStore()
configStore.Set(&cfg)
server.configStore = configStore
server.configStore = &configWrapper{srv: server, Store: configStore}
server.licenseValue.Store(model.NewTestLicense())
return nil
})
@@ -169,7 +169,7 @@ func TestStartServerNoS3Bucket(t *testing.T) {
s, err := NewServer(func(server *Server) error {
configStore, _ := config.NewFileStore("config.json", true)
store, _ := config.NewStoreFromBacking(configStore, nil, false)
server.configStore = store
server.configStore = &configWrapper{srv: server, Store: store}
server.UpdateConfig(func(cfg *model.Config) {
cfg.FileSettings = model.FileSettings{
DriverName: model.NewString(model.ImageDriverS3),