func InvalidateCacheForChannel(channelId string) { hub.invalidateChannel <- channelId if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().InvalidateCacheForChannel(channelId) } }
func Publish(message *model.WebSocketEvent) { hub.Broadcast(message) if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().Publish(message) } }
func InvalidateCacheForUser(userId string) { hub.invalidateUser <- userId if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().InvalidateCacheForUser(userId) } }
func AddStatusCache(status *model.Status) { statusCache.Add(status.UserId, status) if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().UpdateStatus(status) } }
func AddStatusCache(status *model.Status) { AddStatusCacheSkipClusterSend(status) if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().UpdateStatus(status) } }
func InvalidateCacheForUser(userId string) { InvalidateCacheForUserSkipClusterSend(userId) if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().InvalidateCacheForUser(userId) } }
func getClusterStatus(c *Context, w http.ResponseWriter, r *http.Request) { infos := make([]*model.ClusterInfo, 0) if einterfaces.GetClusterInterface() != nil { infos = einterfaces.GetClusterInterface().GetClusterInfos() } w.Write([]byte(model.ClusterInfosToJson(infos))) }
func RemoveAllSessionsForUserId(userId string) { RemoveAllSessionsForUserIdSkipClusterSend(userId) if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().RemoveAllSessionsForUserId(userId) } }
func Publish(message *model.WebSocketEvent) { message.DoPreComputeJson() for _, hub := range hubs { hub.Broadcast(message) } if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().Publish(message) } }
func getClusterStatus(c *Context, w http.ResponseWriter, r *http.Request) { if !c.HasSystemAdminPermissions("getClusterStatus") { return } infos := make([]*model.ClusterInfo, 0) if einterfaces.GetClusterInterface() != nil { infos = einterfaces.GetClusterInterface().GetClusterInfos() } w.Write([]byte(model.ClusterInfosToJson(infos))) }
func InvalidateCacheForChannelPosts(channelId string) { InvalidateCacheForChannelPostsSkipClusterSend(channelId) if cluster := einterfaces.GetClusterInterface(); cluster != nil { cluster.InvalidateCacheForChannelPosts(channelId) } }
func invalidateAllCaches(c *Context, w http.ResponseWriter, r *http.Request) { debug.FreeOSMemory() InvalidateAllCaches() if einterfaces.GetClusterInterface() != nil { err := einterfaces.GetClusterInterface().InvalidateAllCaches() if err != nil { c.Err = err return } } w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") ReturnStatusOK(w) }
func RemoveAllSessionsForUserId(userId string) { keys := sessionCache.Keys() for _, key := range keys { if ts, ok := sessionCache.Get(key); ok { session := ts.(*model.Session) if session.UserId == userId { sessionCache.Remove(key) } } } if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().RemoveAllSessionsForUserId(userId) } }
func getLogs(c *Context, w http.ResponseWriter, r *http.Request) { lines, err := GetLogs() if err != nil { c.Err = err return } if einterfaces.GetClusterInterface() != nil { clines, err := einterfaces.GetClusterInterface().GetLogs() if err != nil { c.Err = err return } lines = append(lines, clines...) } w.Write([]byte(model.ArrayToJson(lines))) }
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { now := time.Now() l4g.Debug("%v", r.URL.Path) c := &Context{} c.T, c.Locale = utils.GetTranslationsAndLocale(w, r) c.RequestId = model.NewId() c.IpAddress = GetIpAddress(r) c.TeamId = mux.Vars(r)["team_id"] token := "" isTokenFromQueryString := false // Attempt to parse token out of the header authHeader := r.Header.Get(model.HEADER_AUTH) if len(authHeader) > 6 && strings.ToUpper(authHeader[0:6]) == model.HEADER_BEARER { // Default session token token = authHeader[7:] } else if len(authHeader) > 5 && strings.ToLower(authHeader[0:5]) == model.HEADER_TOKEN { // OAuth token token = authHeader[6:] } // Attempt to parse the token from the cookie if len(token) == 0 { if cookie, err := r.Cookie(model.SESSION_COOKIE_TOKEN); err == nil { token = cookie.Value if (h.requireSystemAdmin || h.requireUser) && !h.trustRequester { if r.Header.Get(model.HEADER_REQUESTED_WITH) != model.HEADER_REQUESTED_WITH_XML { c.Err = model.NewLocAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token+" Appears to bea CSRF attempt") token = "" } } } } // Attempt to parse token out of the query string if len(token) == 0 { token = r.URL.Query().Get("access_token") isTokenFromQueryString = true } if *utils.Cfg.ServiceSettings.SiteURL != "" { c.SetSiteURL(*utils.Cfg.ServiceSettings.SiteURL) } else { protocol := GetProtocol(r) c.SetSiteURL(protocol + "://" + r.Host) } w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId) w.Header().Set(model.HEADER_VERSION_ID, fmt.Sprintf("%v.%v.%v", model.CurrentVersion, model.BuildNumber, utils.CfgHash)) if einterfaces.GetClusterInterface() != nil { w.Header().Set(model.HEADER_CLUSTER_ID, einterfaces.GetClusterInterface().GetClusterId()) } // Instruct the browser not to display us in an iframe unless is the same origin for anti-clickjacking if !h.isApi { w.Header().Set("X-Frame-Options", "SAMEORIGIN") w.Header().Set("Content-Security-Policy", "frame-ancestors 'self'") } else { // All api response bodies will be JSON formatted by default w.Header().Set("Content-Type", "application/json") if r.Method == "GET" { w.Header().Set("Expires", "0") } } if len(token) != 0 { session := GetSession(token) if session == nil || session.IsExpired() { c.RemoveSessionCookie(w, r) if h.requireUser || h.requireSystemAdmin { c.Err = model.NewLocAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token) c.Err.StatusCode = http.StatusUnauthorized } } else if !session.IsOAuth && isTokenFromQueryString { c.Err = model.NewLocAppError("ServeHTTP", "api.context.token_provided.app_error", nil, "token="+token) c.Err.StatusCode = http.StatusUnauthorized } else { c.Session = *session } } if h.isApi || h.isTeamIndependent { c.setTeamURL(c.GetSiteURL(), false) c.Path = r.URL.Path } else { splitURL := strings.Split(r.URL.Path, "/") c.setTeamURL(c.GetSiteURL()+"/"+splitURL[1], true) c.Path = "/" + strings.Join(splitURL[2:], "/") } if c.Err == nil && h.requireUser { c.UserRequired() } if c.Err == nil && h.requireSystemAdmin { c.SystemAdminRequired() } if c.Err == nil && h.isUserActivity && token != "" && len(c.Session.UserId) > 0 { SetStatusOnline(c.Session.UserId, c.Session.Id, false) } if c.Err == nil { h.handleFunc(c, w, r) } // Handle errors that have occoured if c.Err != nil { c.Err.Translate(c.T) c.Err.RequestId = c.RequestId c.LogError(c.Err) c.Err.Where = r.URL.Path // Block out detailed error when not in developer mode if !*utils.Cfg.ServiceSettings.EnableDeveloper { c.Err.DetailedError = "" } if h.isApi { w.WriteHeader(c.Err.StatusCode) w.Write([]byte(c.Err.ToJson())) if einterfaces.GetMetricsInterface() != nil { einterfaces.GetMetricsInterface().IncrementHttpError() } } else { if c.Err.StatusCode == http.StatusUnauthorized { http.Redirect(w, r, c.GetTeamURL()+"/?redirect="+url.QueryEscape(r.URL.Path), http.StatusTemporaryRedirect) } else { RenderWebError(c.Err, w, r) } } } if h.isApi && einterfaces.GetMetricsInterface() != nil { einterfaces.GetMetricsInterface().IncrementHttpRequest() if r.URL.Path != model.API_URL_SUFFIX+"/users/websocket" { elapsed := float64(time.Since(now)) / float64(time.Second) einterfaces.GetMetricsInterface().ObserveHttpRequestDuration(elapsed) } } }
func main() { parseCmds() if errstr := doLoadConfig(flagConfigFile); errstr != "" { l4g.Exit("Unable to load mattermost configuration file: ", errstr) return } if flagRunCmds { utils.ConfigureCmdLineLog() } utils.InitTranslations(utils.Cfg.LocalizationSettings) utils.TestConnection(utils.Cfg) pwd, _ := os.Getwd() l4g.Info(utils.T("mattermost.current_version"), model.CurrentVersion, model.BuildNumber, model.BuildDate, model.BuildHash, model.BuildHashEnterprise) l4g.Info(utils.T("mattermost.entreprise_enabled"), model.BuildEnterpriseReady) l4g.Info(utils.T("mattermost.working_dir"), pwd) l4g.Info(utils.T("mattermost.config_file"), utils.FindConfigFile(flagConfigFile)) // Enable developer settings if this is a "dev" build if model.BuildNumber == "dev" { *utils.Cfg.ServiceSettings.EnableDeveloper = true } cmdUpdateDb30() if flagCpuProfile { f, err := os.Create(utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation) + ".cpu.prof") if err != nil { l4g.Error("Error creating cpu profile log: " + err.Error()) } l4g.Info("CPU Profiler is logging to " + utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation) + ".cpu.prof") pprof.StartCPUProfile(f) } if flagBlockProfile { l4g.Info("Block Profiler is logging to " + utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation) + ".blk.prof") runtime.SetBlockProfileRate(1) } if flagMemProfile { l4g.Info("Memory Profiler is logging to " + utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation) + ".mem.prof") } api.NewServer(flagHttpProfiler) api.InitApi() web.InitWeb() if model.BuildEnterpriseReady == "true" { api.LoadLicense() } if !utils.IsLicensed && len(utils.Cfg.SqlSettings.DataSourceReplicas) > 1 { l4g.Critical(utils.T("store.sql.read_replicas_not_licensed.critical")) return } if flagRunCmds { runCmds() } else { resetStatuses() api.StartServer() // If we allow testing then listen for manual testing URL hits if utils.Cfg.ServiceSettings.EnableTesting { manualtesting.InitManualTesting() } setDiagnosticId() go runSecurityAndDiagnosticsJob() if complianceI := einterfaces.GetComplianceInterface(); complianceI != nil { complianceI.StartComplianceDailyJob() } if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().StartInterNodeCommunication() } // wait for kill signal before attempting to gracefully shutdown // the running service c := make(chan os.Signal) signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) <-c if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().StopInterNodeCommunication() } api.StopServer() if flagCpuProfile { l4g.Info("Closing CPU Profiler") pprof.StopCPUProfile() } if flagBlockProfile { f, err := os.Create(utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation) + ".blk.prof") if err != nil { l4g.Error("Error creating block profile log: " + err.Error()) } l4g.Info("Writing Block Profiler to: " + utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation) + ".blk.prof") pprof.Lookup("block").WriteTo(f, 0) f.Close() runtime.SetBlockProfileRate(0) } if flagMemProfile { f, err := os.Create(utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation) + ".mem.prof") if err != nil { l4g.Error("Error creating memory profile file: " + err.Error()) } l4g.Info("Writing Memory Profiler to: " + utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation) + ".mem.prof") runtime.GC() if err := pprof.WriteHeapProfile(f); err != nil { l4g.Error("Error creating memory profile: " + err.Error()) } f.Close() } } }
func runServer(configFileLocation string) { if errstr := doLoadConfig(configFileLocation); errstr != "" { l4g.Exit("Unable to load mattermost configuration file: ", errstr) return } utils.InitTranslations(utils.Cfg.LocalizationSettings) utils.TestConnection(utils.Cfg) pwd, _ := os.Getwd() l4g.Info(utils.T("mattermost.current_version"), model.CurrentVersion, model.BuildNumber, model.BuildDate, model.BuildHash, model.BuildHashEnterprise) l4g.Info(utils.T("mattermost.entreprise_enabled"), model.BuildEnterpriseReady) l4g.Info(utils.T("mattermost.working_dir"), pwd) l4g.Info(utils.T("mattermost.config_file"), utils.FindConfigFile(configFileLocation)) // Enable developer settings if this is a "dev" build if model.BuildNumber == "dev" { *utils.Cfg.ServiceSettings.EnableDeveloper = true } cmdUpdateDb30() app.NewServer() app.InitStores() api.InitRouter() api.InitApi() web.InitWeb() if model.BuildEnterpriseReady == "true" { api.LoadLicense() } if !utils.IsLicensed && len(utils.Cfg.SqlSettings.DataSourceReplicas) > 1 { l4g.Warn(utils.T("store.sql.read_replicas_not_licensed.critical")) utils.Cfg.SqlSettings.DataSourceReplicas = utils.Cfg.SqlSettings.DataSourceReplicas[:1] } if !utils.IsLicensed { utils.Cfg.TeamSettings.MaxNotificationsPerChannel = &MaxNotificationsPerChannelDefault } resetStatuses() app.StartServer() // If we allow testing then listen for manual testing URL hits if utils.Cfg.ServiceSettings.EnableTesting { manualtesting.InitManualTesting() } setDiagnosticId() go runSecurityAndDiagnosticsJob() if complianceI := einterfaces.GetComplianceInterface(); complianceI != nil { complianceI.StartComplianceDailyJob() } if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().StartInterNodeCommunication() } if einterfaces.GetMetricsInterface() != nil { einterfaces.GetMetricsInterface().StartServer() } // wait for kill signal before attempting to gracefully shutdown // the running service c := make(chan os.Signal) signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) <-c if einterfaces.GetClusterInterface() != nil { einterfaces.GetClusterInterface().StopInterNodeCommunication() } if einterfaces.GetMetricsInterface() != nil { einterfaces.GetMetricsInterface().StopServer() } app.StopServer() }
func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) teamId := params["id"] name := params["name"] skipIntensiveQueries := false var systemUserCount int64 if r := <-Srv.Store.User().AnalyticsUniqueUserCount(""); r.Err != nil { c.Err = r.Err return } else { systemUserCount = r.Data.(int64) if systemUserCount > int64(*utils.Cfg.AnalyticsSettings.MaxUsersForStatistics) { l4g.Debug("More than %v users on the system, intensive queries skipped", *utils.Cfg.AnalyticsSettings.MaxUsersForStatistics) skipIntensiveQueries = true } } if name == "standard" { var rows model.AnalyticsRows = make([]*model.AnalyticsRow, 8) rows[0] = &model.AnalyticsRow{"channel_open_count", 0} rows[1] = &model.AnalyticsRow{"channel_private_count", 0} rows[2] = &model.AnalyticsRow{"post_count", 0} rows[3] = &model.AnalyticsRow{"unique_user_count", 0} rows[4] = &model.AnalyticsRow{"team_count", 0} rows[5] = &model.AnalyticsRow{"total_websocket_connections", 0} rows[6] = &model.AnalyticsRow{"total_master_db_connections", 0} rows[7] = &model.AnalyticsRow{"total_read_db_connections", 0} openChan := Srv.Store.Channel().AnalyticsTypeCount(teamId, model.CHANNEL_OPEN) privateChan := Srv.Store.Channel().AnalyticsTypeCount(teamId, model.CHANNEL_PRIVATE) teamChan := Srv.Store.Team().AnalyticsTeamCount() var userChan store.StoreChannel if teamId != "" { userChan = Srv.Store.User().AnalyticsUniqueUserCount(teamId) } var postChan store.StoreChannel if !skipIntensiveQueries { postChan = Srv.Store.Post().AnalyticsPostCount(teamId, false, false) } if r := <-openChan; r.Err != nil { c.Err = r.Err return } else { rows[0].Value = float64(r.Data.(int64)) } if r := <-privateChan; r.Err != nil { c.Err = r.Err return } else { rows[1].Value = float64(r.Data.(int64)) } if postChan == nil { rows[2].Value = -1 } else { if r := <-postChan; r.Err != nil { c.Err = r.Err return } else { rows[2].Value = float64(r.Data.(int64)) } } if userChan == nil { rows[3].Value = float64(systemUserCount) } else { if r := <-userChan; r.Err != nil { c.Err = r.Err return } else { rows[3].Value = float64(r.Data.(int64)) } } if r := <-teamChan; r.Err != nil { c.Err = r.Err return } else { rows[4].Value = float64(r.Data.(int64)) } // If in HA mode then aggregrate all the stats if einterfaces.GetClusterInterface() != nil && *utils.Cfg.ClusterSettings.Enable { stats, err := einterfaces.GetClusterInterface().GetClusterStats() if err != nil { c.Err = err return } totalSockets := TotalWebsocketConnections() totalMasterDb := Srv.Store.TotalMasterDbConnections() totalReadDb := Srv.Store.TotalReadDbConnections() for _, stat := range stats { totalSockets = totalSockets + stat.TotalWebsocketConnections totalMasterDb = totalMasterDb + stat.TotalMasterDbConnections totalReadDb = totalReadDb + stat.TotalReadDbConnections } rows[5].Value = float64(totalSockets) rows[6].Value = float64(totalMasterDb) rows[7].Value = float64(totalReadDb) } else { rows[5].Value = float64(TotalWebsocketConnections()) rows[6].Value = float64(Srv.Store.TotalMasterDbConnections()) rows[7].Value = float64(Srv.Store.TotalReadDbConnections()) } w.Write([]byte(rows.ToJson())) } else if name == "post_counts_day" { if skipIntensiveQueries { rows := model.AnalyticsRows{&model.AnalyticsRow{"", -1}} w.Write([]byte(rows.ToJson())) return } if r := <-Srv.Store.Post().AnalyticsPostCountsByDay(teamId); r.Err != nil { c.Err = r.Err return } else { w.Write([]byte(r.Data.(model.AnalyticsRows).ToJson())) } } else if name == "user_counts_with_posts_day" { if skipIntensiveQueries { rows := model.AnalyticsRows{&model.AnalyticsRow{"", -1}} w.Write([]byte(rows.ToJson())) return } if r := <-Srv.Store.Post().AnalyticsUserCountsWithPostsByDay(teamId); r.Err != nil { c.Err = r.Err return } else { w.Write([]byte(r.Data.(model.AnalyticsRows).ToJson())) } } else if name == "extra_counts" { var rows model.AnalyticsRows = make([]*model.AnalyticsRow, 6) rows[0] = &model.AnalyticsRow{"file_post_count", 0} rows[1] = &model.AnalyticsRow{"hashtag_post_count", 0} rows[2] = &model.AnalyticsRow{"incoming_webhook_count", 0} rows[3] = &model.AnalyticsRow{"outgoing_webhook_count", 0} rows[4] = &model.AnalyticsRow{"command_count", 0} rows[5] = &model.AnalyticsRow{"session_count", 0} iHookChan := Srv.Store.Webhook().AnalyticsIncomingCount(teamId) oHookChan := Srv.Store.Webhook().AnalyticsOutgoingCount(teamId) commandChan := Srv.Store.Command().AnalyticsCommandCount(teamId) sessionChan := Srv.Store.Session().AnalyticsSessionCount() var fileChan store.StoreChannel var hashtagChan store.StoreChannel if !skipIntensiveQueries { fileChan = Srv.Store.Post().AnalyticsPostCount(teamId, true, false) hashtagChan = Srv.Store.Post().AnalyticsPostCount(teamId, false, true) } if fileChan == nil { rows[0].Value = -1 } else { if r := <-fileChan; r.Err != nil { c.Err = r.Err return } else { rows[0].Value = float64(r.Data.(int64)) } } if hashtagChan == nil { rows[1].Value = -1 } else { if r := <-hashtagChan; r.Err != nil { c.Err = r.Err return } else { rows[1].Value = float64(r.Data.(int64)) } } if r := <-iHookChan; r.Err != nil { c.Err = r.Err return } else { rows[2].Value = float64(r.Data.(int64)) } if r := <-oHookChan; r.Err != nil { c.Err = r.Err return } else { rows[3].Value = float64(r.Data.(int64)) } if r := <-commandChan; r.Err != nil { c.Err = r.Err return } else { rows[4].Value = float64(r.Data.(int64)) } if r := <-sessionChan; r.Err != nil { c.Err = r.Err return } else { rows[5].Value = float64(r.Data.(int64)) } w.Write([]byte(rows.ToJson())) } else { c.SetInvalidParam("getAnalytics", "name") } }