Files
mattermost/app/app.go
Chris 8e19ba029f Reduce utils.Cfg references (#7650)
* app.UpdateConfig method

* test fix

* another test fix

* the config override option as-was is just error prone, remove it for now

* derp
2017-10-18 15:36:43 -07:00

274 lines
7.1 KiB
Go

// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package app
import (
"net/http"
"sync/atomic"
l4g "github.com/alecthomas/log4go"
"github.com/gorilla/mux"
"github.com/mattermost/mattermost-server/einterfaces"
ejobs "github.com/mattermost/mattermost-server/einterfaces/jobs"
"github.com/mattermost/mattermost-server/jobs"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/plugin/pluginenv"
"github.com/mattermost/mattermost-server/store"
"github.com/mattermost/mattermost-server/store/sqlstore"
"github.com/mattermost/mattermost-server/utils"
)
type App struct {
goroutineCount int32
goroutineExitSignal chan struct{}
Srv *Server
PluginEnv *pluginenv.Environment
PluginConfigListenerId string
EmailBatching *EmailBatchingJob
Hubs []*Hub
HubsStopCheckingForDeadlock chan bool
Jobs *jobs.JobServer
AccountMigration einterfaces.AccountMigrationInterface
Brand einterfaces.BrandInterface
Cluster einterfaces.ClusterInterface
Compliance einterfaces.ComplianceInterface
DataRetention einterfaces.DataRetentionInterface
Elasticsearch einterfaces.ElasticsearchInterface
Ldap einterfaces.LdapInterface
Metrics einterfaces.MetricsInterface
Mfa einterfaces.MfaInterface
Saml einterfaces.SamlInterface
newStore func() store.Store
}
var appCount = 0
// New creates a new App. You must call Shutdown when you're done with it.
// XXX: For now, only one at a time is allowed as some resources are still shared.
func New(options ...Option) *App {
appCount++
if appCount > 1 {
panic("Only one App should exist at a time. Did you forget to call Shutdown()?")
}
l4g.Info(utils.T("api.server.new_server.init.info"))
app := &App{
goroutineExitSignal: make(chan struct{}, 1),
Jobs: &jobs.JobServer{},
Srv: &Server{
Router: mux.NewRouter(),
},
}
app.initEnterprise()
for _, option := range options {
option(app)
}
if app.newStore == nil {
app.newStore = func() store.Store {
return store.NewLayeredStore(sqlstore.NewSqlSupplier(app.Config().SqlSettings, app.Metrics), app.Metrics, app.Cluster)
}
}
app.Srv.Store = app.newStore()
app.Jobs.Store = app.Srv.Store
app.Srv.Router.NotFoundHandler = http.HandlerFunc(app.Handle404)
app.Srv.WebSocketRouter = &WebSocketRouter{
app: app,
handlers: make(map[string]webSocketHandler),
}
return app
}
func (a *App) Shutdown() {
appCount--
l4g.Info(utils.T("api.server.stop_server.stopping.info"))
a.StopServer()
a.HubStop()
a.ShutDownPlugins()
a.WaitForGoroutines()
a.Srv.Store.Close()
a.Srv = nil
l4g.Info(utils.T("api.server.stop_server.stopped.info"))
}
var accountMigrationInterface func(*App) einterfaces.AccountMigrationInterface
func RegisterAccountMigrationInterface(f func(*App) einterfaces.AccountMigrationInterface) {
accountMigrationInterface = f
}
var clusterInterface func(*App) einterfaces.ClusterInterface
func RegisterClusterInterface(f func(*App) einterfaces.ClusterInterface) {
clusterInterface = f
}
var complianceInterface func(*App) einterfaces.ComplianceInterface
func RegisterComplianceInterface(f func(*App) einterfaces.ComplianceInterface) {
complianceInterface = f
}
var dataRetentionInterface func(*App) einterfaces.DataRetentionInterface
func RegisterDataRetentionInterface(f func(*App) einterfaces.DataRetentionInterface) {
dataRetentionInterface = f
}
var jobsDataRetentionJobInterface func(*App) ejobs.DataRetentionJobInterface
func RegisterJobsDataRetentionJobInterface(f func(*App) ejobs.DataRetentionJobInterface) {
jobsDataRetentionJobInterface = f
}
var jobsElasticsearchAggregatorInterface func(*App) ejobs.ElasticsearchAggregatorInterface
func RegisterJobsElasticsearchAggregatorInterface(f func(*App) ejobs.ElasticsearchAggregatorInterface) {
jobsElasticsearchAggregatorInterface = f
}
var jobsElasticsearchIndexerInterface func(*App) ejobs.ElasticsearchIndexerInterface
func RegisterJobsElasticsearchIndexerInterface(f func(*App) ejobs.ElasticsearchIndexerInterface) {
jobsElasticsearchIndexerInterface = f
}
var jobsLdapSyncInterface func(*App) ejobs.LdapSyncInterface
func RegisterJobsLdapSyncInterface(f func(*App) ejobs.LdapSyncInterface) {
jobsLdapSyncInterface = f
}
var ldapInterface func(*App) einterfaces.LdapInterface
func RegisterLdapInterface(f func(*App) einterfaces.LdapInterface) {
ldapInterface = f
}
var metricsInterface func(*App) einterfaces.MetricsInterface
func RegisterMetricsInterface(f func(*App) einterfaces.MetricsInterface) {
metricsInterface = f
}
var mfaInterface func(*App) einterfaces.MfaInterface
func RegisterMfaInterface(f func(*App) einterfaces.MfaInterface) {
mfaInterface = f
}
var samlInterface func(*App) einterfaces.SamlInterface
func RegisterSamlInterface(f func(*App) einterfaces.SamlInterface) {
samlInterface = f
}
func (a *App) initEnterprise() {
if accountMigrationInterface != nil {
a.AccountMigration = accountMigrationInterface(a)
}
a.Brand = einterfaces.GetBrandInterface()
if clusterInterface != nil {
a.Cluster = clusterInterface(a)
}
if complianceInterface != nil {
a.Compliance = complianceInterface(a)
}
a.Elasticsearch = einterfaces.GetElasticsearchInterface()
if ldapInterface != nil {
a.Ldap = ldapInterface(a)
utils.AddConfigListener(func(_, cfg *model.Config) {
if err := utils.ValidateLdapFilter(cfg, a.Ldap); err != nil {
panic(utils.T(err.Id))
}
})
}
if metricsInterface != nil {
a.Metrics = metricsInterface(a)
}
if mfaInterface != nil {
a.Mfa = mfaInterface(a)
}
if samlInterface != nil {
a.Saml = samlInterface(a)
utils.AddConfigListener(func(_, cfg *model.Config) {
a.Saml.ConfigureSP()
})
}
if dataRetentionInterface != nil {
a.DataRetention = dataRetentionInterface(a)
}
if jobsDataRetentionJobInterface != nil {
a.Jobs.DataRetentionJob = jobsDataRetentionJobInterface(a)
}
if jobsElasticsearchAggregatorInterface != nil {
a.Jobs.ElasticsearchAggregator = jobsElasticsearchAggregatorInterface(a)
}
if jobsElasticsearchIndexerInterface != nil {
a.Jobs.ElasticsearchIndexer = jobsElasticsearchIndexerInterface(a)
}
if jobsLdapSyncInterface != nil {
a.Jobs.LdapSync = jobsLdapSyncInterface(a)
}
}
func (a *App) Config() *model.Config {
return utils.Cfg
}
func (a *App) UpdateConfig(f func(*model.Config)) {
f(utils.Cfg)
}
// Go creates a goroutine, but maintains a record of it to ensure that execution completes before
// the app is destroyed.
func (a *App) Go(f func()) {
atomic.AddInt32(&a.goroutineCount, 1)
go func() {
f()
atomic.AddInt32(&a.goroutineCount, -1)
select {
case a.goroutineExitSignal <- struct{}{}:
default:
}
}()
}
// WaitForGoroutines blocks until all goroutines created by App.Go exit.
func (a *App) WaitForGoroutines() {
for atomic.LoadInt32(&a.goroutineCount) != 0 {
<-a.goroutineExitSignal
}
}
func (a *App) Handle404(w http.ResponseWriter, r *http.Request) {
err := model.NewAppError("Handle404", "api.context.404.app_error", nil, "", http.StatusNotFound)
err.Translate(utils.T)
l4g.Debug("%v: code=404 ip=%v", r.URL.Path, utils.GetIpAddress(r))
utils.RenderWebError(err, w, r)
}