[MM-48883] Remove app package dependency for products (#21853)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
61317883bf
Коммит
8d90c7042f
@@ -23,6 +23,8 @@ import (
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
)
|
||||
|
||||
const ServerKey product.ServiceKey = "server"
|
||||
|
||||
// licenseSvc is added to act as a starting point for future integrated products.
|
||||
// It has the same signature and functionality with the license related APIs of the plugin-api.
|
||||
type licenseSvc interface {
|
||||
@@ -86,19 +88,24 @@ type Channels struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterProduct("channels", ProductManifest{
|
||||
Initializer: func(s *Server, services map[ServiceKey]any) (Product, error) {
|
||||
return NewChannels(s, services)
|
||||
product.RegisterProduct("channels", product.Manifest{
|
||||
Initializer: func(services map[product.ServiceKey]any) (product.Product, error) {
|
||||
return NewChannels(services)
|
||||
},
|
||||
Dependencies: map[ServiceKey]struct{}{
|
||||
ConfigKey: {},
|
||||
LicenseKey: {},
|
||||
FilestoreKey: {},
|
||||
Dependencies: map[product.ServiceKey]struct{}{
|
||||
ServerKey: {},
|
||||
product.ConfigKey: {},
|
||||
product.LicenseKey: {},
|
||||
product.FilestoreKey: {},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func NewChannels(s *Server, services map[ServiceKey]any) (*Channels, error) {
|
||||
func NewChannels(services map[product.ServiceKey]any) (*Channels, error) {
|
||||
s, ok := services[ServerKey].(*Server)
|
||||
if !ok {
|
||||
return nil, errors.New("server not passed")
|
||||
}
|
||||
ch := &Channels{
|
||||
srv: s,
|
||||
imageProxy: imageproxy.MakeImageProxy(s.platform, s.httpService, s.Log()),
|
||||
@@ -112,10 +119,10 @@ func NewChannels(s *Server, services map[ServiceKey]any) (*Channels, error) {
|
||||
// 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,
|
||||
LicenseKey,
|
||||
FilestoreKey,
|
||||
requiredServices := []product.ServiceKey{
|
||||
product.ConfigKey,
|
||||
product.LicenseKey,
|
||||
product.FilestoreKey,
|
||||
}
|
||||
for _, svcKey := range requiredServices {
|
||||
svc, ok := services[svcKey]
|
||||
@@ -124,19 +131,19 @@ func NewChannels(s *Server, services map[ServiceKey]any) (*Channels, error) {
|
||||
}
|
||||
switch svcKey {
|
||||
// Keep adding more services here
|
||||
case ConfigKey:
|
||||
case product.ConfigKey:
|
||||
cfgSvc, ok := svc.(product.ConfigService)
|
||||
if !ok {
|
||||
return nil, errors.New("Config service did not satisfy ConfigSvc interface")
|
||||
}
|
||||
ch.cfgSvc = cfgSvc
|
||||
case FilestoreKey:
|
||||
case product.FilestoreKey:
|
||||
filestore, ok := svc.(filestore.FileBackend)
|
||||
if !ok {
|
||||
return nil, errors.New("Filestore service did not satisfy FileBackend interface")
|
||||
}
|
||||
ch.filestore = filestore
|
||||
case LicenseKey:
|
||||
case product.LicenseKey:
|
||||
svc, ok := svc.(licenseSvc)
|
||||
if !ok {
|
||||
return nil, errors.New("License service did not satisfy licenseSvc interface")
|
||||
@@ -198,7 +205,7 @@ func NewChannels(s *Server, services map[ServiceKey]any) (*Channels, error) {
|
||||
}
|
||||
|
||||
ch.routerSvc = newRouterService()
|
||||
services[RouterKey] = ch.routerSvc
|
||||
services[product.RouterKey] = ch.routerSvc
|
||||
|
||||
// Setup routes.
|
||||
pluginsRoute := ch.srv.Router.PathPrefix("/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}").Subrouter()
|
||||
@@ -206,29 +213,29 @@ func NewChannels(s *Server, services map[ServiceKey]any) (*Channels, error) {
|
||||
pluginsRoute.HandleFunc("/public/{public_file:.*}", ch.ServePluginPublicRequest)
|
||||
pluginsRoute.HandleFunc("/{anything:.*}", ch.ServePluginRequest)
|
||||
|
||||
services[PostKey] = &postServiceWrapper{
|
||||
services[product.PostKey] = &postServiceWrapper{
|
||||
app: &App{ch: ch},
|
||||
}
|
||||
|
||||
services[PermissionsKey] = &permissionsServiceWrapper{
|
||||
services[product.PermissionsKey] = &permissionsServiceWrapper{
|
||||
app: &App{ch: ch},
|
||||
}
|
||||
|
||||
services[TeamKey] = &teamServiceWrapper{
|
||||
services[product.TeamKey] = &teamServiceWrapper{
|
||||
app: &App{ch: ch},
|
||||
}
|
||||
|
||||
services[BotKey] = &botServiceWrapper{
|
||||
services[product.BotKey] = &botServiceWrapper{
|
||||
app: &App{ch: ch},
|
||||
}
|
||||
|
||||
services[HooksKey] = &hooksService{
|
||||
services[product.HooksKey] = &hooksService{
|
||||
ch: ch,
|
||||
}
|
||||
|
||||
services[UserKey] = &App{ch: ch}
|
||||
services[product.UserKey] = &App{ch: ch}
|
||||
|
||||
services[PreferencesKey] = &preferencesServiceWrapper{
|
||||
services[product.PreferencesKey] = &preferencesServiceWrapper{
|
||||
app: &App{ch: ch},
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ type licenseWrapper struct {
|
||||
srv *Server
|
||||
}
|
||||
|
||||
func (w *licenseWrapper) Name() ServiceKey {
|
||||
return LicenseKey
|
||||
func (w *licenseWrapper) Name() product.ServiceKey {
|
||||
return product.LicenseKey
|
||||
}
|
||||
|
||||
func (w *licenseWrapper) GetLicense() *model.License {
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/mattermost/mattermost-server/v6/app/platform"
|
||||
"github.com/mattermost/mattermost-server/v6/config"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/product"
|
||||
fmocks "github.com/mattermost/mattermost-server/v6/shared/filestore/mocks"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/i18n"
|
||||
"github.com/mattermost/mattermost-server/v6/store/storetest/mocks"
|
||||
@@ -1440,7 +1441,7 @@ func TestPushNotificationRace(t *testing.T) {
|
||||
Return(&model.Preference{Value: "test"}, nil)
|
||||
mockStore.On("Preference").Return(&mockPreferenceStore)
|
||||
s := &Server{
|
||||
products: make(map[string]Product),
|
||||
products: make(map[string]product.Product),
|
||||
Router: mux.NewRouter(),
|
||||
}
|
||||
var err error
|
||||
@@ -1449,12 +1450,13 @@ func TestPushNotificationRace(t *testing.T) {
|
||||
}, platform.SetFileStore(&fmocks.FileBackend{}))
|
||||
s.SetStore(mockStore)
|
||||
require.NoError(t, err)
|
||||
serviceMap := map[ServiceKey]any{
|
||||
ConfigKey: s.platform,
|
||||
LicenseKey: &licenseWrapper{s},
|
||||
FilestoreKey: s.FileBackend(),
|
||||
serviceMap := map[product.ServiceKey]any{
|
||||
ServerKey: s,
|
||||
product.ConfigKey: s.platform,
|
||||
product.LicenseKey: &licenseWrapper{s},
|
||||
product.FilestoreKey: s.FileBackend(),
|
||||
}
|
||||
ch, err := NewChannels(s, serviceMap)
|
||||
ch, err := NewChannels(serviceMap)
|
||||
require.NoError(t, err)
|
||||
s.products["channels"] = ch
|
||||
|
||||
|
||||
@@ -6,27 +6,13 @@ package app
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/product"
|
||||
)
|
||||
|
||||
type Product interface {
|
||||
Start() error
|
||||
Stop() error
|
||||
}
|
||||
|
||||
type ProductManifest struct {
|
||||
Initializer func(*Server, map[ServiceKey]any) (Product, error)
|
||||
Dependencies map[ServiceKey]struct{}
|
||||
}
|
||||
|
||||
var products = make(map[string]ProductManifest)
|
||||
|
||||
func RegisterProduct(name string, m ProductManifest) {
|
||||
products[name] = m
|
||||
}
|
||||
|
||||
func (s *Server) initializeProducts(
|
||||
productMap map[string]ProductManifest,
|
||||
serviceMap map[ServiceKey]any,
|
||||
productMap map[string]product.Manifest,
|
||||
serviceMap map[product.ServiceKey]any,
|
||||
) error {
|
||||
// create a product map to consume
|
||||
pmap := make(map[string]struct{})
|
||||
@@ -57,7 +43,7 @@ func (s *Server) initializeProducts(
|
||||
|
||||
// some products can register themselves/their services
|
||||
initializer := manifest.Initializer
|
||||
prod, err := initializer(s, serviceMap)
|
||||
prod, err := initializer(serviceMap)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error initializing product %q: %w", product, err)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package app
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/product"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -16,7 +17,7 @@ const (
|
||||
|
||||
type productA struct{}
|
||||
|
||||
func newProductA(s *Server, m map[ServiceKey]any) (Product, error) {
|
||||
func newProductA(m map[product.ServiceKey]any) (product.Product, error) {
|
||||
m[testSrvKey1] = nil
|
||||
return &productA{}, nil
|
||||
}
|
||||
@@ -26,7 +27,7 @@ func (p *productA) Stop() error { return nil }
|
||||
|
||||
type productB struct{}
|
||||
|
||||
func newProductB(s *Server, m map[ServiceKey]any) (Product, error) {
|
||||
func newProductB(m map[product.ServiceKey]any) (product.Product, error) {
|
||||
m[testSrvKey2] = nil
|
||||
return &productB{}, nil
|
||||
}
|
||||
@@ -36,35 +37,35 @@ func (p *productB) Stop() error { return nil }
|
||||
|
||||
func TestInitializeProducts(t *testing.T) {
|
||||
t.Run("2 products and no circular dependency", func(t *testing.T) {
|
||||
serviceMap := map[ServiceKey]any{
|
||||
ConfigKey: nil,
|
||||
LicenseKey: nil,
|
||||
FilestoreKey: nil,
|
||||
ClusterKey: nil,
|
||||
serviceMap := map[product.ServiceKey]any{
|
||||
product.ConfigKey: nil,
|
||||
product.LicenseKey: nil,
|
||||
product.FilestoreKey: nil,
|
||||
product.ClusterKey: nil,
|
||||
}
|
||||
|
||||
products := map[string]ProductManifest{
|
||||
products := map[string]product.Manifest{
|
||||
"productA": {
|
||||
Initializer: newProductA,
|
||||
Dependencies: map[ServiceKey]struct{}{
|
||||
ConfigKey: {},
|
||||
LicenseKey: {},
|
||||
FilestoreKey: {},
|
||||
ClusterKey: {},
|
||||
Dependencies: map[product.ServiceKey]struct{}{
|
||||
product.ConfigKey: {},
|
||||
product.LicenseKey: {},
|
||||
product.FilestoreKey: {},
|
||||
product.ClusterKey: {},
|
||||
},
|
||||
},
|
||||
"productB": {
|
||||
Initializer: newProductB,
|
||||
Dependencies: map[ServiceKey]struct{}{
|
||||
ConfigKey: {},
|
||||
testSrvKey1: {},
|
||||
FilestoreKey: {},
|
||||
ClusterKey: {},
|
||||
Dependencies: map[product.ServiceKey]struct{}{
|
||||
product.ConfigKey: {},
|
||||
testSrvKey1: {},
|
||||
product.FilestoreKey: {},
|
||||
product.ClusterKey: {},
|
||||
},
|
||||
},
|
||||
}
|
||||
server := &Server{
|
||||
products: make(map[string]Product),
|
||||
products: make(map[string]product.Product),
|
||||
}
|
||||
|
||||
err := server.initializeProducts(products, serviceMap)
|
||||
@@ -73,36 +74,36 @@ func TestInitializeProducts(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("2 products and circular dependency", func(t *testing.T) {
|
||||
serviceMap := map[ServiceKey]any{
|
||||
ConfigKey: nil,
|
||||
LicenseKey: nil,
|
||||
FilestoreKey: nil,
|
||||
ClusterKey: nil,
|
||||
serviceMap := map[product.ServiceKey]any{
|
||||
product.ConfigKey: nil,
|
||||
product.LicenseKey: nil,
|
||||
product.FilestoreKey: nil,
|
||||
product.ClusterKey: nil,
|
||||
}
|
||||
|
||||
products := map[string]ProductManifest{
|
||||
products := map[string]product.Manifest{
|
||||
"productA": {
|
||||
Initializer: newProductA,
|
||||
Dependencies: map[ServiceKey]struct{}{
|
||||
ConfigKey: {},
|
||||
LicenseKey: {},
|
||||
FilestoreKey: {},
|
||||
ClusterKey: {},
|
||||
testSrvKey2: {},
|
||||
Dependencies: map[product.ServiceKey]struct{}{
|
||||
product.ConfigKey: {},
|
||||
product.LicenseKey: {},
|
||||
product.FilestoreKey: {},
|
||||
product.ClusterKey: {},
|
||||
testSrvKey2: {},
|
||||
},
|
||||
},
|
||||
"productB": {
|
||||
Initializer: newProductB,
|
||||
Dependencies: map[ServiceKey]struct{}{
|
||||
ConfigKey: {},
|
||||
testSrvKey1: {},
|
||||
FilestoreKey: {},
|
||||
ClusterKey: {},
|
||||
Dependencies: map[product.ServiceKey]struct{}{
|
||||
product.ConfigKey: {},
|
||||
testSrvKey1: {},
|
||||
product.FilestoreKey: {},
|
||||
product.ClusterKey: {},
|
||||
},
|
||||
},
|
||||
}
|
||||
server := &Server{
|
||||
products: make(map[string]Product),
|
||||
products: make(map[string]product.Product),
|
||||
}
|
||||
|
||||
err := server.initializeProducts(products, serviceMap)
|
||||
@@ -110,19 +111,19 @@ func TestInitializeProducts(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("2 products and one w/o any dependency", func(t *testing.T) {
|
||||
serviceMap := map[ServiceKey]any{
|
||||
ConfigKey: nil,
|
||||
LicenseKey: nil,
|
||||
FilestoreKey: nil,
|
||||
ClusterKey: nil,
|
||||
serviceMap := map[product.ServiceKey]any{
|
||||
product.ConfigKey: nil,
|
||||
product.LicenseKey: nil,
|
||||
product.FilestoreKey: nil,
|
||||
product.ClusterKey: nil,
|
||||
}
|
||||
|
||||
products := map[string]ProductManifest{
|
||||
products := map[string]product.Manifest{
|
||||
"productA": {
|
||||
Initializer: newProductA,
|
||||
Dependencies: map[ServiceKey]struct{}{
|
||||
ConfigKey: {},
|
||||
LicenseKey: {},
|
||||
Dependencies: map[product.ServiceKey]struct{}{
|
||||
product.ConfigKey: {},
|
||||
product.LicenseKey: {},
|
||||
},
|
||||
},
|
||||
"productB": {
|
||||
@@ -130,7 +131,7 @@ func TestInitializeProducts(t *testing.T) {
|
||||
},
|
||||
}
|
||||
server := &Server{
|
||||
products: make(map[string]Product),
|
||||
products: make(map[string]product.Product),
|
||||
}
|
||||
|
||||
err := server.initializeProducts(products, serviceMap)
|
||||
|
||||
@@ -75,30 +75,6 @@ import (
|
||||
// declaring this as var to allow overriding in tests
|
||||
var SentryDSN = "placeholder_sentry_dsn"
|
||||
|
||||
type ServiceKey string
|
||||
|
||||
const (
|
||||
ChannelKey ServiceKey = "channel"
|
||||
ConfigKey ServiceKey = "config"
|
||||
LicenseKey ServiceKey = "license"
|
||||
FilestoreKey ServiceKey = "filestore"
|
||||
FileInfoStoreKey ServiceKey = "fileinfostore"
|
||||
ClusterKey ServiceKey = "cluster"
|
||||
CloudKey ServiceKey = "cloud"
|
||||
PostKey ServiceKey = "post"
|
||||
TeamKey ServiceKey = "team"
|
||||
UserKey ServiceKey = "user"
|
||||
PermissionsKey ServiceKey = "permissions"
|
||||
RouterKey ServiceKey = "router"
|
||||
BotKey ServiceKey = "bot"
|
||||
LogKey ServiceKey = "log"
|
||||
HooksKey ServiceKey = "hooks"
|
||||
KVStoreKey ServiceKey = "kvstore"
|
||||
StoreKey ServiceKey = "storekey"
|
||||
SystemKey ServiceKey = "systemkey"
|
||||
PreferencesKey ServiceKey = "preferenceskey"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
// RootRouter is the starting point for all HTTP requests to the server.
|
||||
RootRouter *mux.Router
|
||||
@@ -160,7 +136,7 @@ type Server struct {
|
||||
|
||||
tracer *tracing.Tracer
|
||||
|
||||
products map[string]Product
|
||||
products map[string]product.Product
|
||||
|
||||
hooksManager *product.HooksManager
|
||||
}
|
||||
@@ -187,7 +163,7 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
RootRouter: rootRouter,
|
||||
LocalRouter: localRouter,
|
||||
timezones: timezones.New(),
|
||||
products: make(map[string]Product),
|
||||
products: make(map[string]product.Product),
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
@@ -262,24 +238,25 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
// ensure app implements `product.UserService`
|
||||
var _ product.UserService = (*App)(nil)
|
||||
|
||||
serviceMap := map[ServiceKey]any{
|
||||
ChannelKey: &channelsWrapper{srv: s},
|
||||
ConfigKey: s.platform,
|
||||
LicenseKey: s.licenseWrapper,
|
||||
FilestoreKey: s.platform.FileBackend(),
|
||||
FileInfoStoreKey: &fileInfoWrapper{srv: s},
|
||||
ClusterKey: s.platform,
|
||||
UserKey: New(ServerConnector(s.Channels())),
|
||||
LogKey: s.platform.Log(),
|
||||
CloudKey: &cloudWrapper{cloud: s.Cloud},
|
||||
KVStoreKey: s.platform,
|
||||
StoreKey: store.NewStoreServiceAdapter(s.Store()),
|
||||
SystemKey: &systemServiceAdapter{server: s},
|
||||
serviceMap := map[product.ServiceKey]any{
|
||||
ServerKey: s,
|
||||
product.ChannelKey: &channelsWrapper{srv: s},
|
||||
product.ConfigKey: s.platform,
|
||||
product.LicenseKey: s.licenseWrapper,
|
||||
product.FilestoreKey: s.platform.FileBackend(),
|
||||
product.FileInfoStoreKey: &fileInfoWrapper{srv: s},
|
||||
product.ClusterKey: s.platform,
|
||||
product.UserKey: New(ServerConnector(s.Channels())),
|
||||
product.LogKey: s.platform.Log(),
|
||||
product.CloudKey: &cloudWrapper{cloud: s.Cloud},
|
||||
product.KVStoreKey: s.platform,
|
||||
product.StoreKey: store.NewStoreServiceAdapter(s.Store()),
|
||||
product.SystemKey: &systemServiceAdapter{server: s},
|
||||
}
|
||||
|
||||
// Step 4: Initialize products.
|
||||
// Depends on s.httpService.
|
||||
err = s.initializeProducts(products, serviceMap)
|
||||
err = s.initializeProducts(product.GetProducts(), serviceMap)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to initialize products")
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user