yjs / y-webrtc

WebRTC Connector for Yjs
MIT License
448 stars 109 forks source link

Abstract signaling server messages #62

Open byrond opened 7 months ago

byrond commented 7 months ago

Issue #11 provides a solution for using a different type of signaling server. However, certain parts of y-webrtc make assumptions about the messages being sent through the signaling server. This is a suggestion for refactoring some of the code to make it possible to swap out SignalingConn with a derived class.

In our case, we wanted to use Azure Web PubSub as the signaling server, and Microsoft uses slightly different message formats, event names, and terminology (i.e. "join groups" instead of "subscribe to topics", "group-message" instead of a "message" event, etc.).

Here is our example code where we have derived classes from SignalingConn and WebrtcProvider using the refactored y-webrtc in this PR. It uses the Azure Web PubSub client from Microsoft.

export class AzureWebPubSubSignalingConn extends SignalingConn {
  private clientConnected = false;

  private webPubSubClient!: WebPubSubClient;

  setupClient() {
    this.webPubSubClient = new WebPubSubClient(this.url);
    this.webPubSubClient.on('connected', (e) => {
      this.clientConnected = true;
      console.log(`connected (${this.url}) with ID ${e.connectionId}`);
      this.handleConnect();
    });
    this.webPubSubClient.on('disconnected', (e) => console.log(`disconnect (${this.url}): ${e.message}`));
    this.webPubSubClient.on('stopped', () => console.log(`stopped (${this.url})`));
    // Set an event handler for group messages before connecting, so we don't miss any.
    this.webPubSubClient.on('group-message', (e) => {
      this.handleMessage(e.message.group, e.message.data);
    });
    // Connect to the signaling server.
    this.webPubSubClient.start();
  }

  connected() {
    return this.clientConnected;
  }

  subscribe(roomName: string) {
    this.webPubSubClient.joinGroup(roomName);
  }

  unsubscribe(roomName: string) {
    this.webPubSubClient.leaveGroup(roomName);
  }

  publish(roomName: string, message: string | object) {
    let messageType: WebPubSubDataType = 'json';
    if (typeof message === 'string') {
      messageType = 'text';
    }
    this.webPubSubClient.sendToGroup(roomName, message, messageType);
  }

  destroy() {
    this.webPubSubClient.stop();
  }
}

export class AzureWebPubSubSignalingWebrtcProvider extends WebrtcProvider {
  connect() {
    this.shouldConnect = true;
    this.signalingUrls.forEach((url) => this.addSignalingConn(url, () => new AzureWebPubSubSignalingConn(url)));
    if (this.room) {
      this.room.connect();
    }
  }
}

The following refactoring was done:

Questions

Overriding WebrtcProvider just to change the class used for signaling connections seems excessive. Is there a way we can pass this into the base WebrtcProvider instead? Maybe create a factory method that we can override in a derived class.

This is the only line we need to change in the connect() method: const signalingConn = map.setIfUndefined(signalingConns, url, () => new SignalingConn(url))

What about this needs to be cleaned up to prevent introducing TypeScript errors if/when y-webrtc.js is converted to TS?

byrond commented 3 months ago

@dmonad do you have any feedback on this approach or if it is even feasible to do this level of refactoring in your module?

dmonad commented 3 months ago

Hi @byrond,

first of all, thanks for contributing to this repository!

I manage a lot of different tools, and I'm always hesitant to merge new features.

I prefer simplicity over extensibility because simple projects are easier to maintain. Any new feature that is introduced causes at least one more bug that I have to fix. At this time, this feature is not a priority for me.

That said, I think the approach is valid. I haven't done a full review yet. If you gather more support, I might merge this feature into the next major release.

Btw, this repository is fully typed using jsdoc comments (I prefer that over typescript files). If you do npm run lint it should give you type errors (not just syntax errors).