mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
* MM-26575: Move app initialization inside Websocket router out of handler The websocket router struct is shared amongst multiple handlers. Therefore, there is a race condition while setting the app field and reading from it. We move the initialization of the app field when the router struct is initialized. And we also remove the initializations of some app fields which caused race conditions by being written from multiple goroutines. They are already being written once inside the AppInitializedOnce.Do method and it's redundant to set them again to the same value. * Add missing fields in server connector Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
115 lines
2.8 KiB
Go
115 lines
2.8 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package app
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/mattermost/mattermost-server/v5/mlog"
|
|
"github.com/mattermost/mattermost-server/v5/model"
|
|
"github.com/mattermost/mattermost-server/v5/utils"
|
|
)
|
|
|
|
type webSocketHandler interface {
|
|
ServeWebSocket(*WebConn, *model.WebSocketRequest)
|
|
}
|
|
|
|
type WebSocketRouter struct {
|
|
server *Server
|
|
app *App
|
|
handlers map[string]webSocketHandler
|
|
}
|
|
|
|
func (wr *WebSocketRouter) Handle(action string, handler webSocketHandler) {
|
|
wr.handlers[action] = handler
|
|
}
|
|
|
|
func (wr *WebSocketRouter) ServeWebSocket(conn *WebConn, r *model.WebSocketRequest) {
|
|
wr.app.InitServer()
|
|
|
|
if r.Action == "" {
|
|
err := model.NewAppError("ServeWebSocket", "api.web_socket_router.no_action.app_error", nil, "", http.StatusBadRequest)
|
|
returnWebSocketError(wr.app, conn, r, err)
|
|
return
|
|
}
|
|
|
|
if r.Seq <= 0 {
|
|
err := model.NewAppError("ServeWebSocket", "api.web_socket_router.bad_seq.app_error", nil, "", http.StatusBadRequest)
|
|
returnWebSocketError(wr.app, conn, r, err)
|
|
return
|
|
}
|
|
|
|
if r.Action == model.WEBSOCKET_AUTHENTICATION_CHALLENGE {
|
|
if conn.GetSessionToken() != "" {
|
|
return
|
|
}
|
|
|
|
token, ok := r.Data["token"].(string)
|
|
if !ok {
|
|
conn.WebSocket.Close()
|
|
return
|
|
}
|
|
|
|
session, err := wr.app.GetSession(token)
|
|
if err != nil {
|
|
conn.WebSocket.Close()
|
|
return
|
|
}
|
|
|
|
conn.SetSession(session)
|
|
conn.SetSessionToken(session.Token)
|
|
conn.UserId = session.UserId
|
|
|
|
wr.app.HubRegister(conn)
|
|
|
|
wr.app.Srv().Go(func() {
|
|
wr.app.SetStatusOnline(session.UserId, false)
|
|
wr.app.UpdateLastActivityAtIfNeeded(*session)
|
|
})
|
|
|
|
resp := model.NewWebSocketResponse(model.STATUS_OK, r.Seq, nil)
|
|
hub := wr.app.GetHubForUserId(conn.UserId)
|
|
if hub == nil {
|
|
return
|
|
}
|
|
hub.SendMessage(conn, resp)
|
|
|
|
return
|
|
}
|
|
|
|
if !conn.IsAuthenticated() {
|
|
err := model.NewAppError("ServeWebSocket", "api.web_socket_router.not_authenticated.app_error", nil, "", http.StatusUnauthorized)
|
|
returnWebSocketError(wr.app, conn, r, err)
|
|
return
|
|
}
|
|
|
|
handler, ok := wr.handlers[r.Action]
|
|
if !ok {
|
|
err := model.NewAppError("ServeWebSocket", "api.web_socket_router.bad_action.app_error", nil, "", http.StatusInternalServerError)
|
|
returnWebSocketError(wr.app, conn, r, err)
|
|
return
|
|
}
|
|
|
|
handler.ServeWebSocket(conn, r)
|
|
}
|
|
|
|
func returnWebSocketError(app *App, conn *WebConn, r *model.WebSocketRequest, err *model.AppError) {
|
|
mlog.Error(
|
|
"websocket routing error.",
|
|
mlog.Int64("seq", r.Seq),
|
|
mlog.String("user_id", conn.UserId),
|
|
mlog.String("system_message", err.SystemMessage(utils.T)),
|
|
mlog.Err(err),
|
|
)
|
|
|
|
hub := app.GetHubForUserId(conn.UserId)
|
|
if hub == nil {
|
|
return
|
|
}
|
|
|
|
err.DetailedError = ""
|
|
errorResp := model.NewWebSocketError(r.Seq, err)
|
|
hub.SendMessage(conn, errorResp)
|
|
}
|