Reset status to away after web conn disconnect if necessary (#8988)
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
437f9f5b64
Коммит
2114e96f00
@@ -227,6 +227,9 @@ func (a *App) AttachDeviceId(sessionId string, deviceId string, expiresAt int64)
|
|||||||
|
|
||||||
func (a *App) UpdateLastActivityAtIfNeeded(session model.Session) {
|
func (a *App) UpdateLastActivityAtIfNeeded(session model.Session) {
|
||||||
now := model.GetMillis()
|
now := model.GetMillis()
|
||||||
|
|
||||||
|
a.UpdateWebConnUserActivity(session, now)
|
||||||
|
|
||||||
if now-session.LastActivityAt < model.SESSION_ACTIVITY_TIMEOUT {
|
if now-session.LastActivityAt < model.SESSION_ACTIVITY_TIMEOUT {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,22 @@ func (a *App) GetUserStatusesByIds(userIds []string) ([]*model.Status, *model.Ap
|
|||||||
return statusMap, nil
|
return statusMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetStatusLastActivityAt sets the last activity at for a user on the local app server and updates
|
||||||
|
// status to away if needed. Used by the WS to set status to away if an 'online' device disconnects
|
||||||
|
// while an 'away' device is still connected
|
||||||
|
func (a *App) SetStatusLastActivityAt(userId string, activityAt int64) {
|
||||||
|
var status *model.Status
|
||||||
|
var err *model.AppError
|
||||||
|
if status, err = a.GetStatus(userId); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
status.LastActivityAt = activityAt
|
||||||
|
|
||||||
|
a.AddStatusCacheSkipClusterSend(status)
|
||||||
|
a.SetStatusAwayIfNeeded(userId, false)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) SetStatusOnline(userId string, sessionId string, manual bool) {
|
func (a *App) SetStatusOnline(userId string, sessionId string, manual bool) {
|
||||||
if !*a.Config().ServiceSettings.EnableUserStatuses {
|
if !*a.Config().ServiceSettings.EnableUserStatuses {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ type WebConn struct {
|
|||||||
Send chan model.WebSocketMessage
|
Send chan model.WebSocketMessage
|
||||||
sessionToken atomic.Value
|
sessionToken atomic.Value
|
||||||
session atomic.Value
|
session atomic.Value
|
||||||
|
LastUserActivityAt int64
|
||||||
UserId string
|
UserId string
|
||||||
T goi18n.TranslateFunc
|
T goi18n.TranslateFunc
|
||||||
Locale string
|
Locale string
|
||||||
@@ -52,14 +53,15 @@ func (a *App) NewWebConn(ws *websocket.Conn, session model.Session, t goi18n.Tra
|
|||||||
}
|
}
|
||||||
|
|
||||||
wc := &WebConn{
|
wc := &WebConn{
|
||||||
App: a,
|
App: a,
|
||||||
Send: make(chan model.WebSocketMessage, SEND_QUEUE_SIZE),
|
Send: make(chan model.WebSocketMessage, SEND_QUEUE_SIZE),
|
||||||
WebSocket: ws,
|
WebSocket: ws,
|
||||||
UserId: session.UserId,
|
LastUserActivityAt: model.GetMillis(),
|
||||||
T: t,
|
UserId: session.UserId,
|
||||||
Locale: locale,
|
T: t,
|
||||||
endWritePump: make(chan struct{}, 2),
|
Locale: locale,
|
||||||
pumpFinished: make(chan struct{}, 1),
|
endWritePump: make(chan struct{}, 2),
|
||||||
|
pumpFinished: make(chan struct{}, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
wc.SetSession(&session)
|
wc.SetSession(&session)
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ const (
|
|||||||
DEADLOCK_WARN = (BROADCAST_QUEUE_SIZE * 99) / 100 // number of buffered messages before printing stack trace
|
DEADLOCK_WARN = (BROADCAST_QUEUE_SIZE * 99) / 100 // number of buffered messages before printing stack trace
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type WebConnActivityMessage struct {
|
||||||
|
UserId string
|
||||||
|
SessionToken string
|
||||||
|
ActivityAt int64
|
||||||
|
}
|
||||||
|
|
||||||
type Hub struct {
|
type Hub struct {
|
||||||
// connectionCount should be kept first.
|
// connectionCount should be kept first.
|
||||||
// See https://github.com/mattermost/mattermost-server/pull/7281
|
// See https://github.com/mattermost/mattermost-server/pull/7281
|
||||||
@@ -35,6 +41,7 @@ type Hub struct {
|
|||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
didStop chan struct{}
|
didStop chan struct{}
|
||||||
invalidateUser chan string
|
invalidateUser chan string
|
||||||
|
activity chan *WebConnActivityMessage
|
||||||
ExplicitStop bool
|
ExplicitStop bool
|
||||||
goroutineId int
|
goroutineId int
|
||||||
}
|
}
|
||||||
@@ -48,6 +55,7 @@ func (a *App) NewWebHub() *Hub {
|
|||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
didStop: make(chan struct{}),
|
didStop: make(chan struct{}),
|
||||||
invalidateUser: make(chan string),
|
invalidateUser: make(chan string),
|
||||||
|
activity: make(chan *WebConnActivityMessage),
|
||||||
ExplicitStop: false,
|
ExplicitStop: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -330,6 +338,13 @@ func (a *App) InvalidateWebConnSessionCacheForUser(userId string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) UpdateWebConnUserActivity(session model.Session, activityAt int64) {
|
||||||
|
hub := a.GetHubForUserId(session.UserId)
|
||||||
|
if hub != nil {
|
||||||
|
hub.UpdateActivity(session.UserId, session.Token, activityAt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Hub) Register(webConn *WebConn) {
|
func (h *Hub) Register(webConn *WebConn) {
|
||||||
h.register <- webConn
|
h.register <- webConn
|
||||||
|
|
||||||
@@ -355,6 +370,10 @@ func (h *Hub) InvalidateUser(userId string) {
|
|||||||
h.invalidateUser <- userId
|
h.invalidateUser <- userId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Hub) UpdateActivity(userId, sessionToken string, activityAt int64) {
|
||||||
|
h.activity <- &WebConnActivityMessage{UserId: userId, SessionToken: sessionToken, ActivityAt: activityAt}
|
||||||
|
}
|
||||||
|
|
||||||
func getGoroutineId() int {
|
func getGoroutineId() int {
|
||||||
var buf [64]byte
|
var buf [64]byte
|
||||||
n := runtime.Stack(buf[:], false)
|
n := runtime.Stack(buf[:], false)
|
||||||
@@ -395,15 +414,34 @@ func (h *Hub) Start() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(connections.ForUser(webCon.UserId)) == 0 {
|
conns := connections.ForUser(webCon.UserId)
|
||||||
|
if len(conns) == 0 {
|
||||||
h.app.Go(func() {
|
h.app.Go(func() {
|
||||||
h.app.SetStatusOffline(webCon.UserId, false)
|
h.app.SetStatusOffline(webCon.UserId, false)
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
var latestActivity int64 = 0
|
||||||
|
for _, conn := range conns {
|
||||||
|
if conn.LastUserActivityAt > latestActivity {
|
||||||
|
latestActivity = conn.LastUserActivityAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if h.app.IsUserAway(latestActivity) {
|
||||||
|
h.app.Go(func() {
|
||||||
|
h.app.SetStatusLastActivityAt(webCon.UserId, latestActivity)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case userId := <-h.invalidateUser:
|
case userId := <-h.invalidateUser:
|
||||||
for _, webCon := range connections.ForUser(userId) {
|
for _, webCon := range connections.ForUser(userId) {
|
||||||
webCon.InvalidateCache()
|
webCon.InvalidateCache()
|
||||||
}
|
}
|
||||||
|
case activity := <-h.activity:
|
||||||
|
for _, webCon := range connections.ForUser(activity.UserId) {
|
||||||
|
if webCon.GetSessionToken() == activity.SessionToken {
|
||||||
|
webCon.LastUserActivityAt = activity.ActivityAt
|
||||||
|
}
|
||||||
|
}
|
||||||
case msg := <-h.broadcast:
|
case msg := <-h.broadcast:
|
||||||
candidates := connections.All()
|
candidates := connections.All()
|
||||||
if msg.Broadcast.UserId != "" {
|
if msg.Broadcast.UserId != "" {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user