Skip to content
This repository was archived by the owner on Nov 25, 2024. It is now read-only.

Commit 3dcca40

Browse files
authored
Fix potential state reset when trying to join a room (#3040)
When trying to join a room in short sequence, it is possible that a state reset occurs. This fixes it by using `singleflight`.
1 parent f956a8c commit 3dcca40

File tree

3 files changed

+36
-8
lines changed

3 files changed

+36
-8
lines changed

clientapi/routing/routing.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,16 @@ import (
2020
"strings"
2121

2222
"github.com/gorilla/mux"
23-
"github.com/matrix-org/dendrite/setup/base"
24-
userapi "github.com/matrix-org/dendrite/userapi/api"
2523
"github.com/matrix-org/gomatrixserverlib/fclient"
2624
"github.com/matrix-org/gomatrixserverlib/spec"
2725
"github.com/matrix-org/util"
2826
"github.com/nats-io/nats.go"
2927
"github.com/prometheus/client_golang/prometheus"
3028
"github.com/sirupsen/logrus"
29+
"golang.org/x/sync/singleflight"
30+
31+
"github.com/matrix-org/dendrite/setup/base"
32+
userapi "github.com/matrix-org/dendrite/userapi/api"
3133

3234
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
3335
"github.com/matrix-org/dendrite/clientapi/api"
@@ -84,6 +86,14 @@ func Setup(
8486
unstableFeatures["org.matrix."+msc] = true
8587
}
8688

89+
// singleflight protects /join endpoints from being invoked
90+
// multiple times from the same user and room, otherwise
91+
// a state reset can occur. This also avoids unneeded
92+
// state calculations.
93+
// TODO: actually fix this in the roomserver, as there are
94+
// possibly other ways that can result in a stat reset.
95+
sf := singleflight.Group{}
96+
8797
if cfg.Matrix.WellKnownClientName != "" {
8898
logrus.Infof("Setting m.homeserver base_url as %s at /.well-known/matrix/client", cfg.Matrix.WellKnownClientName)
8999
wkMux.Handle("/client", httputil.MakeExternalAPI("wellknown", func(r *http.Request) util.JSONResponse {
@@ -264,9 +274,17 @@ func Setup(
264274
if err != nil {
265275
return util.ErrorResponse(err)
266276
}
267-
return JoinRoomByIDOrAlias(
268-
req, device, rsAPI, userAPI, vars["roomIDOrAlias"],
269-
)
277+
// Only execute a join for roomIDOrAlias and UserID once. If there is a join in progress
278+
// it waits for it to complete and returns that result for subsequent requests.
279+
resp, _, _ := sf.Do(vars["roomIDOrAlias"]+device.UserID, func() (any, error) {
280+
return JoinRoomByIDOrAlias(
281+
req, device, rsAPI, userAPI, vars["roomIDOrAlias"],
282+
), nil
283+
})
284+
// once all joins are processed, drop them from the cache. Further requests
285+
// will be processed as usual.
286+
sf.Forget(vars["roomIDOrAlias"] + device.UserID)
287+
return resp.(util.JSONResponse)
270288
}, httputil.WithAllowGuests()),
271289
).Methods(http.MethodPost, http.MethodOptions)
272290

@@ -300,9 +318,17 @@ func Setup(
300318
if err != nil {
301319
return util.ErrorResponse(err)
302320
}
303-
return JoinRoomByIDOrAlias(
304-
req, device, rsAPI, userAPI, vars["roomID"],
305-
)
321+
// Only execute a join for roomID and UserID once. If there is a join in progress
322+
// it waits for it to complete and returns that result for subsequent requests.
323+
resp, _, _ := sf.Do(vars["roomID"]+device.UserID, func() (any, error) {
324+
return JoinRoomByIDOrAlias(
325+
req, device, rsAPI, userAPI, vars["roomID"],
326+
), nil
327+
})
328+
// once all joins are processed, drop them from the cache. Further requests
329+
// will be processed as usual.
330+
sf.Forget(vars["roomID"] + device.UserID)
331+
return resp.(util.JSONResponse)
306332
}, httputil.WithAllowGuests()),
307333
).Methods(http.MethodPost, http.MethodOptions)
308334
v3mux.Handle("/rooms/{roomID}/leave",

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ require (
4545
golang.org/x/crypto v0.9.0
4646
golang.org/x/image v0.5.0
4747
golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e
48+
golang.org/x/sync v0.1.0
4849
golang.org/x/term v0.8.0
4950
gopkg.in/h2non/bimg.v1 v1.1.9
5051
gopkg.in/yaml.v2 v2.4.0

go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
614614
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
615615
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
616616
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
617+
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
617618
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
618619
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
619620
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

0 commit comments

Comments
 (0)