MM-56071: Track multiple threads (#25775)

We can have 2 types of threads open at the same time. One from
the thread view, and another from RHS.

We add another variable to distinguish between the 2 states.

In future, if we have the ability for more than 2 threads, then
we would need to track by threadID.

https://mattermost.atlassian.net/browse/MM-56071

```release-note
NONE
```
Этот коммит содержится в:
Agniva De Sarker
2023-12-21 08:42:58 +05:30
коммит произвёл GitHub
родитель 3f2351c71f
Коммит 7dcf5f85a5
7 изменённых файлов: 48 добавлений и 24 удалений

Просмотреть файл

@@ -441,7 +441,12 @@ func TestWebSocketPresence(t *testing.T) {
require.Nil(t, resp.Error) require.Nil(t, resp.Error)
require.Equal(t, resp.SeqReply, wsClient.Sequence-1, "bad sequence number") require.Equal(t, resp.SeqReply, wsClient.Sequence-1, "bad sequence number")
wsClient.UpdateActiveThread("threadID") wsClient.UpdateActiveThread(true, "threadID")
resp = <-wsClient.ResponseChannel
require.Nil(t, resp.Error)
require.Equal(t, resp.SeqReply, wsClient.Sequence-1, "bad sequence number")
wsClient.UpdateActiveThread(false, "threadID")
resp = <-wsClient.ResponseChannel resp = <-wsClient.ResponseChannel
require.Nil(t, resp.Error) require.Nil(t, resp.Error)
require.Equal(t, resp.SeqReply, wsClient.Sequence-1, "bad sequence number") require.Equal(t, resp.SeqReply, wsClient.Sequence-1, "bad sequence number")

Просмотреть файл

@@ -105,16 +105,17 @@ type WebConn struct {
// a reused connection. // a reused connection.
// It's theoretically possible for this number to wrap around. But we // It's theoretically possible for this number to wrap around. But we
// leave that as an edge-case. // leave that as an edge-case.
reuseCount int reuseCount int
sessionToken atomic.Value sessionToken atomic.Value
session atomic.Pointer[model.Session] session atomic.Pointer[model.Session]
connectionID atomic.Value connectionID atomic.Value
activeChannelID atomic.Value activeChannelID atomic.Value
activeTeamID atomic.Value activeTeamID atomic.Value
activeThreadChannelID atomic.Value activeRHSThreadChannelID atomic.Value
endWritePump chan struct{} activeThreadViewThreadChannelID atomic.Value
pumpFinished chan struct{} endWritePump chan struct{}
pluginPosted chan pluginWSPostedHook pumpFinished chan struct{}
pluginPosted chan pluginWSPostedHook
// These counters are to suppress spammy websocket.slow // These counters are to suppress spammy websocket.slow
// and websocket.full logs which happen continuously, if they // and websocket.full logs which happen continuously, if they
@@ -237,7 +238,8 @@ func (ps *PlatformService) NewWebConn(cfg *WebConnConfig, suite SuiteIFace, runn
wc.SetConnectionID(cfg.ConnectionID) wc.SetConnectionID(cfg.ConnectionID)
wc.SetActiveChannelID("") wc.SetActiveChannelID("")
wc.SetActiveTeamID("") wc.SetActiveTeamID("")
wc.SetActiveThreadChannelID("") wc.SetActiveRHSThreadChannelID("")
wc.SetActiveThreadViewThreadChannelID("")
ps.Go(func() { ps.Go(func() {
runner.RunMultiHook(func(hooks plugin.Hooks) bool { runner.RunMultiHook(func(hooks plugin.Hooks) bool {
@@ -316,14 +318,24 @@ func (wc *WebConn) GetActiveTeamID() string {
return wc.activeTeamID.Load().(string) return wc.activeTeamID.Load().(string)
} }
// GetActiveThreadChannelID returns the channel id of the active thread of the connection. // GetActiveRHSThreadChannelID returns the channel id of the active thread of the connection.
func (wc *WebConn) GetActiveThreadChannelID() string { func (wc *WebConn) GetActiveRHSThreadChannelID() string {
return wc.activeThreadChannelID.Load().(string) return wc.activeRHSThreadChannelID.Load().(string)
} }
// SetActiveThreadChannelID sets the channel id of the active thread of the connection. // SetActiveRHSThreadChannelID sets the channel id of the active thread of the connection.
func (wc *WebConn) SetActiveThreadChannelID(id string) { func (wc *WebConn) SetActiveRHSThreadChannelID(id string) {
wc.activeThreadChannelID.Store(id) wc.activeRHSThreadChannelID.Store(id)
}
// GetActiveThreadViewThreadChannelID returns the channel id of the active thread of the connection.
func (wc *WebConn) GetActiveThreadViewThreadChannelID() string {
return wc.activeThreadViewThreadChannelID.Load().(string)
}
// SetActiveThreadViewThreadChannelID sets the channel id of the active thread of the connection.
func (wc *WebConn) SetActiveThreadViewThreadChannelID(id string) {
wc.activeThreadViewThreadChannelID.Store(id)
} }
// areAllInactive returns whether all of the connections // areAllInactive returns whether all of the connections

Просмотреть файл

@@ -84,7 +84,11 @@ func (wr *WebSocketRouter) ServeWebSocket(conn *WebConn, r *model.WebSocketReque
} }
if thChannelID, ok := r.Data["thread_channel_id"].(string); ok { if thChannelID, ok := r.Data["thread_channel_id"].(string); ok {
// Set the channelID of the active thread. // Set the channelID of the active thread.
conn.SetActiveThreadChannelID(thChannelID) if isThreadView, ok := r.Data["is_thread_view"].(bool); ok && isThreadView {
conn.SetActiveThreadViewThreadChannelID(thChannelID)
} else {
conn.SetActiveRHSThreadChannelID(thChannelID)
}
} }
resp := model.NewWebSocketResponse(model.StatusOk, r.Seq, nil) resp := model.NewWebSocketResponse(model.StatusOk, r.Seq, nil)

Просмотреть файл

@@ -343,9 +343,10 @@ func (wsc *WebSocketClient) UpdateActiveTeam(teamID string) {
} }
// UpdateActiveThread sets the channel id of the current thread that the user is in. // UpdateActiveThread sets the channel id of the current thread that the user is in.
func (wsc *WebSocketClient) UpdateActiveThread(channelID string) { func (wsc *WebSocketClient) UpdateActiveThread(isThreadView bool, channelID string) {
data := map[string]any{ data := map[string]any{
"thread_channel_id": channelID, "thread_channel_id": channelID,
"is_thread_view": isThreadView,
} }
wsc.SendMessage(string(WebsocketPresenceIndicator), data) wsc.SendMessage(string(WebsocketPresenceIndicator), data)
} }

Просмотреть файл

@@ -67,6 +67,7 @@ describe('components/threading/ThreadViewer', () => {
postIds: [post.id], postIds: [post.id],
appsEnabled: true, appsEnabled: true,
rootPostId: post.id, rootPostId: post.id,
isThreadView: true,
}; };
test('should match snapshot', async () => { test('should match snapshot', async () => {

Просмотреть файл

@@ -49,7 +49,7 @@ export type Props = Attrs & {
postIds: string[]; postIds: string[];
highlightedPostId?: Post['id']; highlightedPostId?: Post['id'];
selectedPostFocusedAt?: number; selectedPostFocusedAt?: number;
isThreadView?: boolean; isThreadView: boolean;
inputPlaceholder?: string; inputPlaceholder?: string;
rootPostId: string; rootPostId: string;
fromSuppressed?: boolean; fromSuppressed?: boolean;
@@ -81,7 +81,7 @@ export default class ThreadViewer extends React.PureComponent<Props, State> {
} }
public componentWillUnmount() { public componentWillUnmount() {
WebSocketClient.updateActiveThread(''); WebSocketClient.updateActiveThread(this.props.isThreadView, '');
} }
public componentDidUpdate(prevProps: Props) { public componentDidUpdate(prevProps: Props) {
@@ -184,7 +184,7 @@ export default class ThreadViewer extends React.PureComponent<Props, State> {
} }
if (this.props.channel) { if (this.props.channel) {
WebSocketClient.updateActiveThread(this.props.channel?.id); WebSocketClient.updateActiveThread(this.props.isThreadView, this.props.channel?.id);
} }
this.setState({isLoading: false}); this.setState({isLoading: false});
}; };

Просмотреть файл

@@ -396,9 +396,10 @@ export default class WebSocketClient {
this.sendMessage('presence', data, callback); this.sendMessage('presence', data, callback);
} }
updateActiveThread(channelId: string, callback?: (msg: any) => void) { updateActiveThread(isThreadView: boolean, channelId: string, callback?: (msg: any) => void) {
const data = { const data = {
thread_channel_id: channelId, thread_channel_id: channelId,
is_thread_view: isThreadView,
}; };
this.sendMessage('presence', data, callback); this.sendMessage('presence', data, callback);
} }