Skip to content

Commit

Permalink
Fixes live share support
Browse files Browse the repository at this point in the history
  • Loading branch information
eamodio committed Jul 13, 2021
1 parent f77cf30 commit 9a47409
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 166 deletions.
11 changes: 5 additions & 6 deletions package.json
Expand Up @@ -195,7 +195,7 @@
"onStartupFinished"
],
"capabilities": {
"virtualWorkspaces": false,
"virtualWorkspaces": true,
"untrustedWorkspaces": {
"supported": "limited"
}
Expand Down Expand Up @@ -9703,17 +9703,16 @@
"iconv-lite": "0.6.3",
"lodash-es": "4.17.21",
"sortablejs": "1.13.0",
"vscode-codicons": "0.0.17",
"vsls": "1.0.3015"
"vscode-codicons": "0.0.17"
},
"devDependencies": {
"@types/chroma-js": "2.1.3",
"@types/lodash-es": "4.17.4",
"@types/node": "14.17.4",
"@types/sortablejs": "1.10.6",
"@types/vscode": "1.57.0",
"@typescript-eslint/eslint-plugin": "4.28.2",
"@typescript-eslint/parser": "4.28.2",
"@typescript-eslint/eslint-plugin": "4.28.3",
"@typescript-eslint/parser": "4.28.3",
"circular-dependency-plugin": "5.2.2",
"clean-webpack-plugin": "3.0.0",
"copy-webpack-plugin": "9.0.1",
Expand All @@ -9738,7 +9737,7 @@
"terser-webpack-plugin": "5.1.4",
"ts-loader": "9.2.3",
"typescript": "4.4.0-beta",
"vsce": "1.95.0",
"vsce": "1.95.1",
"webpack": "5.44.0",
"webpack-bundle-analyzer": "4.4.2",
"webpack-cli": "4.2.0"
Expand Down
93 changes: 93 additions & 0 deletions src/@types/vsls.d.ts
@@ -0,0 +1,93 @@
import { CancellationToken, Disposable, Event, TreeDataProvider, Uri } from 'vscode';

export interface LiveShareExtension {
getApi(version: string): Promise<LiveShare | null>;
}

export interface LiveShare {
readonly session: Session;
readonly onDidChangeSession: Event<SessionChangeEvent>;

share(options?: ShareOptions): Promise<Uri | null>;
shareService(name: string): Promise<SharedService | null>;
unshareService(name: string): Promise<void>;
getSharedService(name: string): Promise<SharedServiceProxy | null>;
convertLocalUriToShared(localUri: Uri): Uri;
convertSharedUriToLocal(sharedUri: Uri): Uri;
getContacts(emails: string[]): Promise<Contacts>;
}

export const enum Access {
None = 0,
ReadOnly = 1,
ReadWrite = 3,
Owner = 0xff,
}

export const enum Role {
None = 0,
Host = 1,
Guest = 2,
}

export interface Session {
readonly id: string | null;
readonly role: Role;
readonly access: Access;
}

export interface SessionChangeEvent {
readonly session: Session;
}

export interface Contact {
readonly onDidChange: Event<string[]>;
readonly id: string;
readonly email: string;
readonly displayName?: string;
readonly status?: string;
readonly avatarUri?: string;

invite(options?: ContactInviteOptions): Promise<boolean>;
}

export interface Contacts {
readonly contacts: { [email: string]: Contact };
dispose(): Promise<void>;
}

export interface ContactInviteOptions {
useEmail?: boolean;
}

export interface SharedService {
readonly isServiceAvailable: boolean;
readonly onDidChangeIsServiceAvailable: Event<boolean>;

onRequest(name: string, handler: RequestHandler): void;
onNotify(name: string, handler: NotifyHandler): void;
notify(name: string, args: object): void;
}

export interface SharedServiceProxy {
readonly isServiceAvailable: boolean;
readonly onDidChangeIsServiceAvailable: Event<boolean>;

onNotify(name: string, handler: NotifyHandler): void;
request(name: string, args: any[], cancellation?: CancellationToken): Promise<any>;
notify(name: string, args: object): void;
}

export interface SharedServiceProxyError extends Error {}

export interface SharedServiceResponseError extends Error {
remoteStack?: string;
}

export interface RequestHandler {
(args: any[], cancellation: CancellationToken): any | Promise<any>;
}

export interface NotifyHandler {
(args: object): void;
}
4 changes: 1 addition & 3 deletions src/git/gitService.ts
Expand Up @@ -8,7 +8,6 @@ import {
env,
Event,
EventEmitter,
Extension,
extensions,
ProgressLocation,
Range,
Expand Down Expand Up @@ -4275,10 +4274,9 @@ export class GitService implements Disposable {
@log()
static async getBuiltInGitApi(): Promise<BuiltInGitApi | undefined> {
try {
const extension = extensions.getExtension('vscode.git') as Extension<GitExtension>;
const extension = extensions.getExtension<GitExtension>('vscode.git');
if (extension != null) {
const gitExtension = extension.isActive ? extension.exports : await extension.activate();

return gitExtension.getAPI(1);
}
} catch {}
Expand Down
2 changes: 1 addition & 1 deletion src/vsls/guest.ts
@@ -1,6 +1,6 @@
'use strict';
import { CancellationToken, Disposable, window, WorkspaceFolder } from 'vscode';
import { LiveShare, SharedServiceProxy } from 'vsls';
import type { LiveShare, SharedServiceProxy } from '../@types/vsls';
import { setEnabled } from '../extension';
import { GitCommandOptions, Repository, RepositoryChangeEvent } from '../git/git';
import { Logger } from '../logger';
Expand Down
2 changes: 1 addition & 1 deletion src/vsls/host.ts
@@ -1,6 +1,6 @@
'use strict';
import { CancellationToken, Disposable, Uri, workspace, WorkspaceFoldersChangeEvent } from 'vscode';
import { LiveShare, SharedService } from 'vsls';
import type { LiveShare, SharedService } from '../@types/vsls';
import { Container } from '../container';
import { git } from '../git/git';
import { GitUri } from '../git/gitUri';
Expand Down
37 changes: 22 additions & 15 deletions src/vsls/vsls.ts
@@ -1,6 +1,6 @@
'use strict';
import { Disposable, workspace } from 'vscode';
import { getApi, LiveShare, Role, SessionChangeEvent } from 'vsls';
import { Disposable, extensions, workspace } from 'vscode';
import type { LiveShare, LiveShareExtension, SessionChangeEvent } from '../@types/vsls';
import { ContextKeys, DocumentSchemes, setContext } from '../constants';
import { Container } from '../container';
import { Logger } from '../logger';
Expand Down Expand Up @@ -40,7 +40,7 @@ export class VslsController implements Disposable {
private _onReady: (() => void) | undefined;
private _waitForReady: Promise<void> | undefined;

private _api: Promise<LiveShare | null> | undefined;
private _api: Promise<LiveShare | undefined> | undefined;

constructor() {
void this.initialize();
Expand All @@ -60,7 +60,7 @@ export class VslsController implements Disposable {
this._waitForReady = new Promise(resolve => (this._onReady = resolve));
}

this._api = getApi();
this._api = this.getLiveShareApi();
const api = await this._api;
if (api == null) {
void setContext(ContextKeys.Vsls, false);
Expand All @@ -83,6 +83,18 @@ export class VslsController implements Disposable {
}
}

private async getLiveShareApi(): Promise<LiveShare | undefined> {
try {
const extension = extensions.getExtension<LiveShareExtension>('ms-vsliveshare.vsliveshare');
if (extension != null) {
const liveshareExtension = extension.isActive ? extension.exports : await extension.activate();
return (await liveshareExtension.getApi('1.0.3015')) ?? undefined;
}
} catch {}

return undefined;
}

get isMaybeGuest() {
return this._guest !== undefined || this._waitForReady !== undefined;
}
Expand Down Expand Up @@ -112,7 +124,7 @@ export class VslsController implements Disposable {
0: (emails: string[]) => `length=${emails.length}`,
},
})
async getContacts(emails: string[]) {
private async getContacts(emails: string[]) {
const api = await this._api;
if (api == null) return undefined;

Expand Down Expand Up @@ -144,7 +156,7 @@ export class VslsController implements Disposable {

@debug()
@timeout(250)
maybeGetPresence(email: string | undefined) {
maybeGetPresence(email: string | undefined): Promise<ContactPresence | undefined> {
return Container.vsls.getContactPresence(email);
}

Expand Down Expand Up @@ -178,23 +190,18 @@ export class VslsController implements Disposable {
}

private async onLiveShareSessionChanged(api: LiveShare, e: SessionChangeEvent) {
if (this._host !== undefined) {
this._host.dispose();
}

if (this._guest !== undefined) {
this._guest.dispose();
}
this._host?.dispose();
this._guest?.dispose();

switch (e.session.role) {
case Role.Host:
case 1 /*Role.Host*/:
this.setReadonly(false);
void setContext(ContextKeys.Vsls, 'host');
if (Container.config.liveshare.allowGuestAccess) {
this._host = await VslsHostService.share(api);
}
break;
case Role.Guest:
case 2 /*Role.Guest*/:
this.setReadonly(true);
void setContext(ContextKeys.Vsls, 'guest');
this._guest = await VslsGuestService.connect(api);
Expand Down

0 comments on commit 9a47409

Please sign in to comment.