Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT: collaboration concept #12677

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions collaboration-concept.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Collaboration Concept

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would start with a short motivational and overview, e.g.

"Collaboration is an often asked for feature in Theia. In this document we analyze the collaboration feature of VS Code, specify technical requirements and architecture for Theia and give an overview over the API concept."

Collaboration is an often requested for feature in Theia.
In this document we analyze the collaboration feature of VS Code, specify technical requirements and architecture for Theia and give an overview over the API concept.

## Microsoft VSCode Live Share Extension
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"VS Code offers collaboration support via the official Microsoft Live Share Extension. It offers the following features:"

At the end it would be nice to mention that we can't reuse the same protocol nor offer the same API to extensions because both have a proprietary license.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know, APIs cannot be licensed, only the implementation. If we were to offer a drop-in replacement for Microsoft's vsls that uses our custom collaboration feature implementation, we shouldn't infringe on any license agreements (fair use). See also Oracle v. Google.


The official Microsoft [Live Share Extension](https://visualstudio.microsoft.com/services/live-share/) implements collaboration support for the following features:

- Editor Syncing (Text + Client markers for each user)
- Host Syncing (i.e. other users follow the host into their currently selected file + position)
- Terminal Syncing (if enabled). Both input+output is synced
- Debug Syncing (if enabled). Both users and host can step through the code as if it were on one machine. Breakpoints are synced as well.
- Plugin Syncing (i.e. external user has access to all installed plugins/extensions of the host user)
- Chat Functionality
- Mechanism for making the API available to other extensions, see [vsls](https://www.npmjs.com/package/vsls)

Similar to the tunnel feature, the connection between host and other users can be accomplished using hole-punching.
I.e. a single central server serves as an intermediary to exchange messages. No messages are being exchanged directly between users.
If possible - for example, if the users are on the same network - the extension will try to connect directly to the host,
see [here](https://learn.microsoft.com/en-us/visualstudio/liveshare/reference/connectivity#connection-modes).
Comment on lines +18 to +21
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the "i.e." following the mention of "hole punching" as this term means establishing a direct connection through each peer's NAT by "punching holes" with the help of an intermediary server to know where to hit. I've also successfully managed to do hole punching in the past using UDP while TCP was more finicky (still worked). The implication means we'd need a UDP transport for direct connections? But that's only if you truly want to do hole punching over the internet.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hole punching might not be the correct term here, right. In the end, all that we need to accomplish is that users can communicate with each other through some means, be it some intermediary server or whatever.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine if your goal is to abstract the API from how the communication might happen. Although properly laying down the expected modes of communication would help in designing said API: P2P vs Server-centric, how to handle auth/identity/permissions, etc...

If the goal is to be highly generic then the act of creating sessions must be defined at least partially by the embedding layer for the target IDE:

  1. Define the communication implementation (a.k.a "driver"? i.e. connect to some server and request a new room)
  2. Said driver may implement auth (i.e. prompt the user for credentials in the IDE? defer to some OAuth service?)


## Requirements for Theia Collaboration Feature

### Functional Requirements

The protocol/implementation that this new collaboration feature is supposed to be using therefore has a few different tasks for different widgets/features

1. Document syncing akin to yjs monaco binding + Awareness information exchange (i.e. broadcast information to all users)
2. Virtual File System coming from the host user
3. Frontend message proxying for debug sync (i.e. debug launch or monaco language service requests need to be proxied to the plugin host and the results send back)
4. Terminal input + output syncing requires a yjs like approach for input and a broadcast for output
5. Broadcast required for Chat functionality
Copy link
Member

@sdirix sdirix Jul 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also list other potential requirements like:

  • privacy (e.g. allow to configure an own message server without going through one central public instance)
  • encryption
  • authentication
  • extensibility (for customized messages between plugins, similar to what VS Code offers)

6. Extensibility (for customized messages between plugins, similar to what VS Code offers with `vsls`)

### Non-Functional Requirements

The requirements above are purely about the functionality of the collaboration feature. The following requirements are still necessary to be met to find adoption in Theia.

1. Privacy (e.g. allow to configure an own message server without going through one central public instance)
2. Encryption
3. Authentication

### Messaging System Architecture

For the technical requirements above, we effectively need a two different kind of message types:

1. Broadcasting actions to all users:
1. Document entry events (yjs shared data types sync; monaco editor + terminal input)
2. Awareness information broadcast, i.e. current cursor position in monaco/custom editor
3. Chat functionality
4. Output of host terminal
2. Proxy message to host (with result or without):
1. Debug launch (notification)
2. File System information
3. Monaco language services (i.e. LSP requests)

The following diagram shows the Session creation/entry negotiations. In all cases where the User/Host communicate directly in the diagram, the intermediary server provides the messaging exchange infrastructure (using a hole-punching mechanism). The host is always the user that provides the workspace

```mermaid
sequenceDiagram
participant Host
participant I as Intermediary
participant User
Host->>I: Create Collab Session
I->>Host: Return with Session ID
Host-->>User: Sends Session ID via chat
User->>Host: Request Session Entry
Host->>User: Allow Session Entry (with permissions)
User->>Host: Download Workspace Info
```

Diagram outlining the broadcasting mechanism. We skip the Intermediary here, since it only proxies messages between users. Also note that we don’t need a host, since in this message scenario, all users have “equal rights”. This example uses the notification for file changes, but can be used for broadcasts for debugging or terminal output

```mermaid
sequenceDiagram
participant U1 as User A
participant U2 as User B
participant U3 as User C

Note over U1: Modifies a file

par U1 to U2
U1-)U2: Send file notification event
and U1 to U2
U1-)U3: Send file notification event
end
par
Note over U2: Updates modified file
Note over U3: Updates modified file
end
```

Proxy host messaging example:

```mermaid
sequenceDiagram
participant P as Plugin Host
participant Host as Host User
participant User
Note over User: Opens File
Note over User: Performs Completion
User->>Host: Requests Completion
Host->>P: Request Completion
P->>Host: Return Completion
Host->>User: Return Completion
Note over User: Show Completion
```

## Coordination/Messaging Server

For the messages architecture above, we need a coordination or messaging server. The server serves exactly two purposes:

1. Opening up the host system to the world. The host and the coordination server negotiate a new collab session. This can be as simple as an HTTP call to this server. The coordination server then creates a virtual room and assigns the host that originated the call as its host.
2. Communication between collaborators within a session. For example, a broadcast notification needs to be send to the coordination server first, which then relays the message to all other participants.

Assuming the server is built specifically for Theia, we can reuse some of Theia’s dependencies for this, i.e. socket-io for bidirectional, high-performance messaging on top of HTTP.


## API Concept
Copy link
Member

@paul-marechal paul-marechal Jul 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of API are we talking about here? Theia Extension API? VS Code Extension API?

Should we inject the vsls package the same way we do with the vscode API so that extensions relying on this package can work in Theia?

Should we take care to properly implement the groundwork feature in the framework before exposing it through the plugin API? (By contrast with webviews which are baked-in the plugin-ext package at the moment.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of API are we talking about here? Theia Extension API? VS Code Extension API?

Neither, the collaboration messaging infrastructure should be implemented independently of Theia (maybe another Eclipse project?) so that it can be reused for other IDEs as well. The API concept provided in here is for a general JS/TS library that can be used in Theia.

Should we inject the vsls package the same way we do with the vscode API so that extensions relying on this package can work in Theia?

Yes, that would be the mid-term plan. I wouldn't try to introduce a new Theia-only API to the plugin-ext. We should aim to replace the vsls package in the plugin host.

Copy link
Member

@paul-marechal paul-marechal Aug 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then is it fair to assume that this library must support at least what vsls supports? That would make for a good starting point when designing the API.


The following outlines the API that is supposed to be used to implement the technical requirements above.
All 3 message types (broadcast, request, notification) can be accomplished using this approach.

```ts
// Message type:
export type DocumentUpdateInfo = {
documentUri: string
text: string
range: Range
}
export const DocumentUpdate: Broadcast<DocumentUpdateInfo> = {
kind: 'Broadcast',
method: 'DocumentUpdate'
};
// Alternatively Notification<P>/Request<P>

// Message listener:
session.onBroadcast(DocumentUpdate, /** automatically typed as `DocumentUpdateInfo` */ updateInfo => {

});
// alternatively onRequest/onNotification

// Message sender:
session.sendBroadcast(DocumentUpdate, /** automatically typed as `DocumentUpdateInfo` */ {
documentUri,
text,
range
});
// alternatively sendRequest/sendNotification
```
Loading