Archived
1
0
This repository has been archived on 2024-09-09. You can view files and clone it, but cannot push or open issues or pull requests.
code-server/packages/ide/src/client.ts

134 lines
5.0 KiB
TypeScript
Raw Normal View History

2019-01-19 01:04:24 +01:00
import { Event } from "@coder/events";
2019-01-08 01:46:19 +01:00
import { field, logger, time, Time } from "@coder/logger";
2019-01-19 01:04:24 +01:00
import { InitData, ISharedProcessData } from "@coder/protocol";
2019-01-30 22:40:01 +01:00
import { retry } from "./retry";
2019-01-31 00:46:17 +01:00
import { upload } from "./upload";
import { client } from "./fill/client";
import { clipboard } from "./fill/clipboard";
2019-01-31 23:19:12 +01:00
import { INotificationService, IProgressService } from "./fill/notification";
2019-01-08 01:46:19 +01:00
/**
* A general abstraction of an IDE client.
2019-01-08 01:46:19 +01:00
*
* Everything the client provides is asynchronous so you can wait on what
* you need from it without blocking anything else.
*
* It also provides task management to help asynchronously load and time code.
2019-01-08 01:46:19 +01:00
*/
2019-02-06 17:18:24 +01:00
export abstract class IdeClient {
2019-01-30 22:40:01 +01:00
public readonly retry = retry;
public readonly clipboard = clipboard;
2019-01-31 00:46:17 +01:00
public readonly upload = upload;
2019-01-08 01:46:19 +01:00
private start: Time | undefined;
private readonly tasks = <string[]>[];
private finishedTaskCount = 0;
private readonly loadTime: Time;
private readonly sharedProcessDataPromise: Promise<ISharedProcessData>;
public constructor() {
logger.info("Loading IDE");
this.loadTime = time(2500);
this.sharedProcessDataPromise = new Promise((resolve): void => {
client.onSharedProcessActive(resolve);
});
window.addEventListener("contextmenu", (event) => {
event.preventDefault();
2019-01-08 01:46:19 +01:00
});
// Prevent Firefox from trying to reconnect when the page unloads.
window.addEventListener("unload", () => {
this.retry.block();
logger.info("Unloaded");
});
this.initialize().then(() => {
logger.info("Load completed", field("duration", this.loadTime));
}).catch((error) => {
logger.error(error.message);
logger.warn("Load completed with errors", field("duration", this.loadTime));
});
2019-01-08 01:46:19 +01:00
}
/**
* Wrap a task in some logging, timing, and progress updates. Can optionally
* wait on other tasks which won't count towards this task's time.
*/
public async task<T>(description: string, duration: number, task: () => Promise<T>): Promise<T>;
public async task<T, V>(description: string, duration: number, task: (v: V) => Promise<T>, t: Promise<V>): Promise<T>;
public async task<T, V1, V2>(description: string, duration: number, task: (v1: V1, v2: V2) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>): Promise<T>;
public async task<T, V1, V2, V3>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>): Promise<T>;
public async task<T, V1, V2, V3, V4>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>): Promise<T>;
public async task<T, V1, V2, V3, V4, V5>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4, v5: V5) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>, t5: Promise<V5>): Promise<T>;
public async task<T, V1, V2, V3, V4, V5, V6>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4, v5: V5, v6: V6) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>, t5: Promise<V5>, t6: Promise<V6>): Promise<T>;
public async task<T>(
2019-01-08 01:46:19 +01:00
description: string, duration: number = 100, task: (...args: any[]) => Promise<T>, ...after: Array<Promise<any>> // tslint:disable-line no-any
): Promise<T> {
this.tasks.push(description);
if (!this.start) {
this.start = time(1000);
}
let start: Time | undefined;
try {
const waitFor = await (after && after.length > 0 ? Promise.all(after) : Promise.resolve([]));
start = time(duration);
logger.info(description);
const value = await task(...waitFor);
logger.info(`Finished "${description}"`, field("duration", start));
const index = this.tasks.indexOf(description);
if (index !== -1) {
this.tasks.splice(index, 1);
}
++this.finishedTaskCount;
if (this.tasks.length === 0) {
logger.info("Finished all queued tasks", field("duration", this.start), field("count", this.finishedTaskCount));
this.start = undefined;
}
return value;
} catch (error) {
logger.error(`Failed "${description}"`, field("duration", typeof start !== "undefined" ? start : "not started"), field("error", error));
throw error;
}
}
/**
* A promise that resolves with initialization data.
*/
public get initData(): Promise<InitData> {
return client.initData;
}
/**
* An event that fires every time the shared process (re-)starts.
*/
2019-01-19 01:04:24 +01:00
public get onSharedProcessActive(): Event<ISharedProcessData> {
return client.onSharedProcessActive;
}
/**
* A promise that resolves with *initial* shared process data.
*/
public get sharedProcessData(): Promise<ISharedProcessData> {
return this.sharedProcessDataPromise;
}
2019-01-30 22:40:01 +01:00
public set notificationService(service: INotificationService) {
this.retry.notificationService = service;
this.upload.notificationService = service;
}
public set progressService(service: IProgressService) {
this.upload.progressService = service;
}
/**
* Initialize the IDE.
*/
protected abstract initialize(): Promise<void>;
2019-01-08 01:46:19 +01:00
}