Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
import { ILiveShareApi } from '../../../common/application/types';
import { IAsyncDisposable } from '../../../common/types';
import { ClassType } from '../../../ioc/types';
import { ILiveShareHasRole, ILiveShareParticipant } from './types';
export interface IRoleBasedObject extends IAsyncDisposable, ILiveShareParticipant {
}
// tslint:disable:no-any
export class RoleBasedFactory> implements ILiveShareHasRole {
private ctorArgs: ConstructorParameters[];
private firstTime: boolean = true;
private createPromise: Promise | undefined;
private sessionChangedEmitter = new vscode.EventEmitter();
private _role: vsls.Role = vsls.Role.None;
constructor(private liveShare: ILiveShareApi, private hostCtor: CtorType, private guestCtor: CtorType, ...args: ConstructorParameters) {
this.ctorArgs = args;
this.createPromise = this.createBasedOnRole(); // We need to start creation immediately or one side may call before we init.
}
public get sessionChanged(): vscode.Event {
return this.sessionChangedEmitter.event;
}
public get role(): vsls.Role {
return this._role;
}
public get(): Promise {
// Make sure only one create happens at a time
service.onNotify(NOTIFICATION_WINDOW_INTERACTION, async (args: any) => {
const { peerNumber, url, data } = args;
if (peerNumber === liveShare.session.peerNumber) {
// This is a re-broadcasted event from
// the same user.
return;
}
const window = windowManager.getByUrl(url);
window!.browserPage!.send(data.type, data.params);
if (liveShare.session.role === vsls.Role.Host) {
service.notify(NOTIFICATION_WINDOW_INTERACTION, args);
}
});
}
public async onAttach(api: vsls.LiveShare | null): Promise {
await super.onAttach(api);
if (api) {
const service = await this.waitForService();
// Wait for sync up
const synced = service ? await service.request(LiveShareCommands.syncRequest, []) : undefined;
if (!synced && api.session && api.session.role !== vsls.Role.None) {
throw new Error(localize.DataScience.liveShareSyncFailure());
}
if (service) {
// Listen to responses
service.onNotify(LiveShareCommands.serverResponse, this.onServerResponse);
// Request all of the responses since this guest was started. We likely missed a bunch
service.notify(LiveShareCommands.catchupRequest, { since: this.startTime });
}
}
}
public async onDetach(api: vsls.LiveShare | null): Promise {
await super.onDetach(api);
// clear our cached servers if our role is no longer host or none
const newRole = api === null || (api.session && api.session.role !== vsls.Role.Guest) ?
vsls.Role.Host : vsls.Role.Guest;
if (newRole !== vsls.Role.Host) {
await this.serverCache.dispose();
}
}
import { LiveShare } from '../constants';
// tslint:disable:no-any
interface IMessageArgs {
args: string;
}
// This class is used to register two communication between a host and all of its guests
export class PostOffice implements IAsyncDisposable {
private name: string;
private startedPromise: Deferred | undefined;
private hostServer: vsls.SharedService | null = null;
private guestServer: vsls.SharedServiceProxy | null = null;
private currentRole: vsls.Role = vsls.Role.None;
private currentPeerCount: number = 0;
private peerCountChangedEmitter: vscode.EventEmitter = new vscode.EventEmitter();
private commandMap: { [key: string]: { thisArg: any; callback(...args: any[]): void } } = {};
constructor(
name: string,
private liveShareApi: ILiveShareApi,
private hostArgsTranslator?: (api: vsls.LiveShare | null, command: string, role: vsls.Role, args: any[]) => void) {
this.name = name;
// Note to self, could the callbacks be keeping things alive that we don't want to be alive?
}
public get peerCount() {
return this.currentPeerCount;
}
private async createBasedOnRole(): Promise {
// Figure out our role to compute the object to create. Default is host. This
// allows for the host object to keep existing if we suddenly start a new session.
// For a guest, starting a new session resets the entire workspace.
const api = await this.liveShare.getApi();
let ctor: CtorType = this.hostCtor;
let role: vsls.Role = vsls.Role.Host;
if (api) {
// Create based on role.
if (api.session && api.session.role === vsls.Role.Host) {
ctor = this.hostCtor;
} else if (api.session && api.session.role === vsls.Role.Guest) {
ctor = this.guestCtor;
role = vsls.Role.Guest;
}
}
this._role = role;
// Create our object
const obj = new ctor(...this.ctorArgs);
// Rewrite the object's dispose so we can get rid of our own state.
private registerGuestCommands(api: vsls.LiveShare) {
if (api && api.session && api.session.role === vsls.Role.Guest && this.guestServer !== null) {
const keys = Object.keys(this.commandMap);
keys.forEach(k => {
if (this.guestServer !== null) { // Hygiene is too dumb to recognize the if above
this.guestServer.onNotify(this.escapeCommandName(k), a => this.onGuestNotify(k, a as IMessageArgs));
}
});
}
}
private async synchronizeCreate(): Promise {
// Create a new pending wait if necessary
if (this.postOffice.peerCount > 0 || this.postOffice.role === vsls.Role.Guest) {
const key = uuid();
const waitable = createDeferred();
this.pendingSyncs.set(key, { count: this.postOffice.peerCount, waitable });
// Make sure all providers have an active interactive window
await this.postOffice.postCommand(LiveShareCommands.interactiveWindowCreate, this.id, key);
// Wait for the waitable to be signaled or the peer count on the post office to change
await waitable.promise;
}
}
ev.added.filter(e => e.role === vsls.Role.Guest).length -
ev.removed.filter(e => e.role === vsls.Role.Guest).length;
loadChannelHistory(channelId: string): Promise {
if (!!this.liveshare) {
const { role } = this.liveshare.session;
if (role === vsls.Role.Host) {
return this.hostService.fetchMessagesHistory();
} else if (role === vsls.Role.Guest) {
return this.guestService.fetchMessagesHistory();
}
}
}