Return response if session tries to join room again.

This commit is contained in:
Joachim Bauch 2023-09-05 15:24:36 +02:00
parent 92690f4613
commit 35135433c2
No known key found for this signature in database
GPG key ID: 77C1D22D53E15F02
5 changed files with 171 additions and 6 deletions

View file

@ -24,6 +24,7 @@ package signaling
import (
"encoding/json"
"fmt"
"log"
"net/url"
"sort"
"strings"
@ -220,9 +221,9 @@ func (r *ServerMessage) String() string {
}
type Error struct {
Code string `json:"code"`
Message string `json:"message"`
Details interface{} `json:"details,omitempty"`
Code string `json:"code"`
Message string `json:"message"`
Details json.RawMessage `json:"details,omitempty"`
}
func NewError(code string, message string) *Error {
@ -230,10 +231,19 @@ func NewError(code string, message string) *Error {
}
func NewErrorDetail(code string, message string, details interface{}) *Error {
var rawDetails json.RawMessage
if details != nil {
var err error
if rawDetails, err = json.Marshal(details); err != nil {
log.Printf("Could not marshal details %+v for error %s with %s: %s", details, code, message, err)
return NewError("internal_error", "Could not marshal error details")
}
}
return &Error{
Code: code,
Message: message,
Details: details,
Details: rawDetails,
}
}
@ -511,6 +521,10 @@ type RoomServerMessage struct {
Properties *json.RawMessage `json:"properties,omitempty"`
}
type RoomErrorDetails struct {
Room *RoomServerMessage `json:"room"`
}
// Type "message"
const (

View file

@ -417,6 +417,36 @@ func (s *ClientSession) SubscribeEvents() error {
return s.events.RegisterSessionListener(s.publicId, s.backend, s)
}
func (s *ClientSession) UpdateRoomSessionId(roomSessionId string) error {
s.mu.Lock()
defer s.mu.Unlock()
if s.roomSessionId == roomSessionId {
return nil
}
if err := s.hub.roomSessions.SetRoomSession(s, roomSessionId); err != nil {
return err
}
if roomSessionId != "" {
if room := s.GetRoom(); room != nil {
log.Printf("Session %s updated room session id to %s in room %s", s.PublicId(), roomSessionId, room.Id())
} else {
log.Printf("Session %s updated room session id to %s in unknown room", s.PublicId(), roomSessionId)
}
} else {
if room := s.GetRoom(); room != nil {
log.Printf("Session %s cleared room session id in room %s", s.PublicId(), room.Id())
} else {
log.Printf("Session %s cleared room session id in unknown room", s.PublicId())
}
}
s.roomSessionId = roomSessionId
return nil
}
func (s *ClientSession) SubscribeRoomEvents(roomid string, roomSessionId string) error {
s.mu.Lock()
defer s.mu.Unlock()

View file

@ -460,6 +460,26 @@ Message format (Server -> Client):
the current room or the properties of a room change.
Message format (Server -> Client if already joined before):
{
"id": "unique-request-id-from-request",
"type": "error",
"error": {
"code": "already_joined",
"message": "Human readable error message",
"details": {
"roomid": "the-room-id",
"properties": {
...additional room properties...
}
}
}
}
- Sent if a client tried to join a room it is already in.
### Backend validation
Rooms are managed by the Nextcloud backend, so the signaling server has to

18
hub.go
View file

@ -1256,6 +1256,24 @@ func (h *Hub) processRoom(client *Client, message *ClientMessage) {
if session != nil {
if room := h.getRoomForBackend(roomId, session.Backend()); room != nil && room.HasSession(session) {
// Session already is in that room, no action needed.
roomSessionId := message.Room.SessionId
if roomSessionId == "" {
// TODO(jojo): Better make the session id required in the request.
log.Printf("User did not send a room session id, assuming session %s", session.PublicId())
roomSessionId = session.PublicId()
}
if err := session.UpdateRoomSessionId(roomSessionId); err != nil {
log.Printf("Error updating room session id for session %s: %s", session.PublicId(), err)
}
session.SendMessage(message.NewErrorServerMessage(
NewErrorDetail("already_joined", "Already joined this room.", &RoomErrorDetails{
Room: &RoomServerMessage{
RoomId: room.id,
Properties: room.properties,
},
}),
))
return
}
}

View file

@ -22,6 +22,7 @@
package signaling
import (
"bytes"
"context"
"crypto/ecdsa"
"crypto/ed25519"
@ -58,6 +59,10 @@ const (
testTimeout = 10 * time.Second
)
var (
testRoomProperties = []byte("{\"prop1\":\"value1\"}")
)
var (
clusteredTests = []string{
"local",
@ -403,8 +408,9 @@ func processRoomRequest(t *testing.T, w http.ResponseWriter, r *http.Request, re
response := &BackendClientResponse{
Type: "room",
Room: &BackendClientRoomResponse{
Version: BackendVersion,
RoomId: request.Room.RoomId,
Version: BackendVersion,
RoomId: request.Room.RoomId,
Properties: (*json.RawMessage)(&testRoomProperties),
},
}
switch request.Room.RoomId {
@ -2628,6 +2634,83 @@ func TestJoinRoom(t *testing.T) {
}
}
func TestJoinRoomTwice(t *testing.T) {
hub, _, _, server := CreateHubForTest(t)
client := NewTestClient(t, server, hub)
defer client.CloseWithBye()
if err := client.SendHello(testDefaultUserId); err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
defer cancel()
hello, err := client.RunUntilHello(ctx)
if err != nil {
t.Fatal(err)
}
// Join room by id.
roomId := "test-room"
if room, err := client.JoinRoom(ctx, roomId); err != nil {
t.Fatal(err)
} else if room.Room.RoomId != roomId {
t.Fatalf("Expected room %s, got %s", roomId, room.Room.RoomId)
} else if !bytes.Equal(testRoomProperties, *room.Room.Properties) {
t.Fatalf("Expected room properties %s, got %s", string(testRoomProperties), string(*room.Room.Properties))
}
// We will receive a "joined" event.
if err := client.RunUntilJoined(ctx, hello.Hello); err != nil {
t.Error(err)
}
msg := &ClientMessage{
Id: "ABCD",
Type: "room",
Room: &RoomClientMessage{
RoomId: roomId,
SessionId: roomId + "-" + client.publicId + "-2",
},
}
if err := client.WriteJSON(msg); err != nil {
t.Fatal(err)
}
message, err := client.RunUntilMessage(ctx)
if err != nil {
t.Fatal(err)
}
if err := checkUnexpectedClose(err); err != nil {
t.Fatal(err)
}
if msg.Id != message.Id {
t.Errorf("expected message id %s, got %s", msg.Id, message.Id)
} else if err := checkMessageType(message, "error"); err != nil {
t.Fatal(err)
} else if expected := "already_joined"; message.Error.Code != expected {
t.Errorf("expected error %s, got %s", expected, message.Error.Code)
} else if message.Error.Details == nil {
t.Fatal("expected error details")
}
var roomMsg RoomErrorDetails
if err := json.Unmarshal(message.Error.Details, &roomMsg); err != nil {
t.Fatal(err)
} else if roomMsg.Room == nil {
t.Fatalf("expected room details, got %+v", message)
}
if roomMsg.Room.RoomId != roomId {
t.Fatalf("Expected room %s, got %+v", roomId, roomMsg.Room)
} else if !bytes.Equal(testRoomProperties, *roomMsg.Room.Properties) {
t.Fatalf("Expected room properties %s, got %s", string(testRoomProperties), string(*roomMsg.Room.Properties))
}
}
func TestExpectAnonymousJoinRoom(t *testing.T) {
hub, _, _, server := CreateHubForTest(t)