vaadin / collaboration-engine

The simplest way to build real-time collaboration into web apps
https://vaadin.com/collaboration
Other
3 stars 1 forks source link

Introduce a data access API for each of the supported high-level use cases. #36

Closed Legioth closed 2 years ago

Legioth commented 3 years ago

Collaboration Engine does currently have three different use cases that are supported by high-level APIs:

Each use case is backed by low-level primitive mechanisms provided through TopicConnection and it is in theory possible to implement custom integrations by manually modifying topic contents or listening to changes according to the conventions used by the high-level components. At the same time, this requires using quite low-level APIs and also relying on implementation details on the exact structure used for storing different types of data in the topics.

Some examples of use cases where it would be useful to create custom integrations:

To deal with this, I propose the concept of collaboration data access object classes for various use cases. Each instance would be managing its own TopicConnection which in practice means that it would need a CollaborationEngine reference, a ConnectionContext, a topic id, and a UserInfo object. There could also be a shorthand constructor that uses CollaborationEngine.getInstance() and creates a ComponentConnectionContext based on a provided Component instance.

The exact functionality of each class would be tailored to the use cases as follows

Presence

Key concepts:

Using those mechanisms, a simple list of active users could be shown in a VerticalLayout using in this way:

VerticalLayout users = new VerticalLayout();
PresenceCollaborationDao dao = new PresenceCollaborationDao(users, topicId, ownUserInfo);
dao.setPresence(ownUserInfo, true);
dao.setNewUserHandler(newUserInfo -> {
  Component card = createUserCard(newUserInfo);
  users.add(card);
  return () -> avatarGroup.remove(card);
});

Similarly to CollaborationAvatarGroup, any presence registered using setPresence through the DAO would be automatically removed when the connection context of the DAO is deactivated and added back if it's reactivated. Similarly to other CE concepts, there would be initial add events for all current items users connecting and also corresponding remove events when disconnecting.

Related tickets:

Form editing

Key concepts:

Usage would follow the same pattern as for presence. Values and highlights can be set directly using void setValue(String property, JsonNode value) and void setHighlight(String property, UserInfo user, boolean highlight). Listening to value changes is through void setValueChangeHandler(SerializableBiConsumer<String, JsonValue> handler) while highlight handling is again structured to associate removal as a Registration returned from the add handler void setHighlightHandler(SerializableBiFunction<String, UserInfo, Registration> handler).

Edit: Field highlighting also needs to shift around a fieldIndex value for some cases. This means that the API might have to be slightly more complex.

Messages

Message handling is slightly more complex since the DAO would also have to deal with persistence. This is handled through additional constructors that receive a CollaborationMessagePersister instance in addition to the general parameters.

Key concepts:

The unread count for the messages in a specific topic could then be implemented like this

public class UnreadCount extends Span {
  private int count;

  public UnreadCount(String topicId, UserInfo localUser, CollaborationMessagePersister persister) {
      MessageCollaborationDao dao = new MessageCollaborationDao(this, topicId, localUser, persister);
      dao.setActivationHandler(topic -> {
          reset();
          return null; // Registration triggered when deactivating
      });
      dao.setNewMessageHandler(message -> {
          setCount(count + 1);
      });
  }

  public void reset() {
    setCount(0);
  }

  private void setCount(int count) {
      this.count = count;
      setText(Integer.toString(count));
  }
}

This example uses a generic setActivationHandler method that is present in all the DAO classes. It is directly connected to the activation status of the underlying topic connection. All DAO classes would also have a setTopic method that behaves in the same way as in the high-level components.

Related tickets:

heruan commented 2 years ago

All the use cases are now provided by the three Collaboration Managers.