diff --git a/client/client.go b/client/client.go index b891aaf8a..76cc16f9a 100644 --- a/client/client.go +++ b/client/client.go @@ -463,6 +463,9 @@ func (c *Client) Watch( case types.DocumentsUnwatchedEvent: p := doc.Presence(cli.String()) doc.RemoveOnlineClient(cli.String()) + if p == nil { + return nil, nil + } return &WatchResponse{ Type: DocumentUnwatched, @@ -521,6 +524,8 @@ func (c *Client) Watch( t := PresenceChanged if e.Type == document.WatchedEvent { t = DocumentWatched + } else if e.Type == document.UnwatchedEvent { + t = DocumentUnwatched } rch <- WatchResponse{Type: t, Presences: e.Presences} case <-ctx.Done(): diff --git a/pkg/document/document.go b/pkg/document/document.go index 3c6121eb7..d9ca6b2dd 100644 --- a/pkg/document/document.go +++ b/pkg/document/document.go @@ -43,6 +43,10 @@ const ( // enabling real-time synchronization. WatchedEvent DocEventType = "watched" + // UnwatchedEvent means that the client has disconnected from the server, + // disabling real-time synchronization. + UnwatchedEvent DocEventType = "unwatched" + // PresenceChangedEvent means that the presences of the clients who are editing // the document have changed. PresenceChangedEvent DocEventType = "presence-changed" diff --git a/pkg/document/internal_document.go b/pkg/document/internal_document.go index ee42a6e46..f71cbd43c 100644 --- a/pkg/document/internal_document.go +++ b/pkg/document/internal_document.go @@ -257,17 +257,29 @@ func (d *InternalDocument) ApplyChanges(changes ...*change.Change) ([]DocEvent, if c.PresenceChange() != nil { clientID := c.ID().ActorID().String() if _, ok := d.onlineClients.Load(clientID); ok { - event := DocEvent{ - Type: PresenceChangedEvent, - Presences: map[string]innerpresence.Presence{ - clientID: c.PresenceChange().Presence, - }, + switch c.PresenceChange().ChangeType { + case innerpresence.Put: + eventType := PresenceChangedEvent + if !d.presences.Has(clientID) { + eventType = WatchedEvent + } + event := DocEvent{ + Type: eventType, + Presences: map[string]innerpresence.Presence{ + clientID: c.PresenceChange().Presence, + }, + } + events = append(events, event) + case innerpresence.Clear: + event := DocEvent{ + Type: UnwatchedEvent, + Presences: map[string]innerpresence.Presence{ + clientID: d.Presence(clientID), + }, + } + events = append(events, event) + d.RemoveOnlineClient(clientID) } - - if !d.presences.Has(clientID) { - event.Type = WatchedEvent - } - events = append(events, event) } } diff --git a/test/integration/presence_test.go b/test/integration/presence_test.go index cd4ab6a6e..e2b37aa69 100644 --- a/test/integration/presence_test.go +++ b/test/integration/presence_test.go @@ -249,7 +249,7 @@ func TestPresence(t *testing.T) { }) } - if len(responsePairs) == 4 { + if len(responsePairs) == 3 { return } } @@ -285,23 +285,16 @@ func TestPresence(t *testing.T) { // 05. Unwatch the second client's document. expected = append(expected, watchResponsePair{ - Type: client.PresenceChanged, + Type: client.DocumentUnwatched, Presences: map[string]innerpresence.Presence{ - c2.ID().String(): nil, + c2.ID().String(): d2.MyPresence(), }, }) assert.NoError(t, c2.Detach(ctx, d2)) assert.NoError(t, c1.Sync(ctx, client.WithDocKey(helper.TestDocKey(t)))) + wgEvents.Wait() - expected = append(expected, watchResponsePair{ - Type: client.DocumentUnwatched, - Presences: map[string]innerpresence.Presence{ - c2.ID().String(): nil, - }, - }) cancel2() - - wgEvents.Wait() assert.Equal(t, expected, responsePairs) })