Compare commits
15 Commits
2.1650-vsc
...
2.1665-vsc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d5db8313a | ||
|
|
73cf8f34e3 | ||
|
|
766efd6079 | ||
|
|
87485948ad | ||
|
|
7e4a73ce2d | ||
|
|
2f0878d9b7 | ||
|
|
f65c9b23fc | ||
|
|
cd859d117f | ||
|
|
e22964915a | ||
|
|
197d0b6ca9 | ||
|
|
422503ef98 | ||
|
|
ea36345d2c | ||
|
|
a89d83cbba | ||
|
|
83ff31b620 | ||
|
|
3a9b032c72 |
@@ -61,7 +61,7 @@ deploy:
|
|||||||
|
|
||||||
- provider: script
|
- provider: script
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
script: docker build -f ./scripts/ci.dockerfile -t codercom/code-server:"$TAG" -t codercom/code-server:v2 . && docker push codercom/code-server:"$TAG" && docker push codercom/code-server:v2
|
script: docker build -f ./scripts/ci.dockerfile -t codercom/code-server:"$TAG" -t codercom/code-server:v2 -t codercom/code-server . && docker push codercom/code-server:"$TAG" && docker push codercom/code-server:v2 && docker push codercom/code-server
|
||||||
on:
|
on:
|
||||||
repo: cdr/code-server
|
repo: cdr/code-server
|
||||||
branch: master
|
branch: master
|
||||||
|
|||||||
@@ -22,10 +22,11 @@ docker run -it -p 127.0.0.1:8080:8080 -v "${HOME}/.local/share/code-server:/home
|
|||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
- Minimum GLIBC version of 2.17 and a minimum version of GLIBCXX of 3.4.15.
|
- 64-bit host.
|
||||||
- This is the main requirement for building Visual Studio Code. We cannot go lower than this.
|
- At least 1GB of RAM.
|
||||||
- A 64-bit host with at least 1GB RAM and 2 cores.
|
- 2 cores or more are recommended (1 core works but not optimally).
|
||||||
- 1 core hosts would work but not optimally.
|
- Secure connection over HTTPS or localhost (required for service workers).
|
||||||
|
- For Linux: GLIBC 2.17 or later and GLIBCXX 3.4.15 or later.
|
||||||
- Docker (for Docker versions of `code-server`).
|
- Docker (for Docker versions of `code-server`).
|
||||||
|
|
||||||
### Run over SSH
|
### Run over SSH
|
||||||
|
|||||||
13
docker-compose.yml
Normal file
13
docker-compose.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
code-server:
|
||||||
|
container_name: code-server
|
||||||
|
image: codercom/code-server
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
volumes:
|
||||||
|
- "${PWD}:/home/coder/project"
|
||||||
|
- "${HOME}/.local/share/code-server:/home/coder/.local/share/code-server"
|
||||||
|
environment:
|
||||||
|
PASSWORD: ${PASSWORD}
|
||||||
@@ -1,19 +1,8 @@
|
|||||||
diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts
|
diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts
|
||||||
index 6d41e85e42..f845d0bf9e 100644
|
index 6d41e85e42..64f39687a4 100644
|
||||||
--- a/src/vs/base/common/network.ts
|
--- a/src/vs/base/common/network.ts
|
||||||
+++ b/src/vs/base/common/network.ts
|
+++ b/src/vs/base/common/network.ts
|
||||||
@@ -48,7 +48,9 @@ export namespace Schemas {
|
@@ -96,12 +96,12 @@ class RemoteAuthoritiesImpl {
|
||||||
|
|
||||||
export const command: string = 'command';
|
|
||||||
|
|
||||||
- export const vscodeRemote: string = 'vscode-remote';
|
|
||||||
+ // NOTE@coder: Changed this so it'll be reflected in the explorer to prevent
|
|
||||||
+ // confusion with vscode-remote itself.
|
|
||||||
+ export const vscodeRemote: string = 'code-server';
|
|
||||||
|
|
||||||
export const vscodeRemoteResource: string = 'vscode-remote-resource';
|
|
||||||
|
|
||||||
@@ -96,12 +98,12 @@ class RemoteAuthoritiesImpl {
|
|
||||||
if (host && host.indexOf(':') !== -1) {
|
if (host && host.indexOf(':') !== -1) {
|
||||||
host = `[${host}]`;
|
host = `[${host}]`;
|
||||||
}
|
}
|
||||||
@@ -50,6 +39,21 @@ index a657f4a4d9..66bd13dffa 100644
|
|||||||
} else if (typeof process === 'object') {
|
} else if (typeof process === 'object') {
|
||||||
_isWindows = (process.platform === 'win32');
|
_isWindows = (process.platform === 'win32');
|
||||||
_isMacintosh = (process.platform === 'darwin');
|
_isMacintosh = (process.platform === 'darwin');
|
||||||
|
diff --git a/src/vs/base/common/processes.ts b/src/vs/base/common/processes.ts
|
||||||
|
index c52f7b3774..5635cfac8a 100644
|
||||||
|
--- a/src/vs/base/common/processes.ts
|
||||||
|
+++ b/src/vs/base/common/processes.ts
|
||||||
|
@@ -110,7 +110,9 @@ export function sanitizeProcessEnvironment(env: IProcessEnvironment, ...preserve
|
||||||
|
/^ELECTRON_.+$/,
|
||||||
|
/^GOOGLE_API_KEY$/,
|
||||||
|
/^VSCODE_.+$/,
|
||||||
|
- /^SNAP(|_.*)$/
|
||||||
|
+ /^SNAP(|_.*)$/,
|
||||||
|
+ /^NBIN_BYPASS$/,
|
||||||
|
+ /^LAUNCH_VSCODE$/
|
||||||
|
];
|
||||||
|
const envKeys = Object.keys(env);
|
||||||
|
envKeys
|
||||||
diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js
|
diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js
|
||||||
index 3ae24454cb..fac8679290 100644
|
index 3ae24454cb..fac8679290 100644
|
||||||
--- a/src/vs/base/node/languagePacks.js
|
--- a/src/vs/base/node/languagePacks.js
|
||||||
@@ -615,6 +619,34 @@ index 84c46faa36..957e8412e1 100644
|
|||||||
|
|
||||||
if (!this.configuration.userDataProvider) {
|
if (!this.configuration.userDataProvider) {
|
||||||
const remoteUserDataUri = this.getRemoteUserDataUri();
|
const remoteUserDataUri = this.getRemoteUserDataUri();
|
||||||
|
diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts
|
||||||
|
index 53de865d8f..df234821a9 100644
|
||||||
|
--- a/src/vs/workbench/common/resources.ts
|
||||||
|
+++ b/src/vs/workbench/common/resources.ts
|
||||||
|
@@ -15,6 +15,7 @@ import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob';
|
||||||
|
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||||
|
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||||
|
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||||
|
+import { Schemas } from 'vs/base/common/network';
|
||||||
|
|
||||||
|
export class ResourceContextKey extends Disposable implements IContextKey<URI> {
|
||||||
|
|
||||||
|
@@ -63,7 +64,7 @@ export class ResourceContextKey extends Disposable implements IContextKey<URI> {
|
||||||
|
set(value: URI | null) {
|
||||||
|
if (!ResourceContextKey._uriEquals(this._resourceKey.get(), value)) {
|
||||||
|
this._resourceKey.set(value);
|
||||||
|
- this._schemeKey.set(value ? value.scheme : null);
|
||||||
|
+ this._schemeKey.set(value ? (value.scheme === Schemas.vscodeRemote ? Schemas.file : value.scheme) : null);
|
||||||
|
this._filenameKey.set(value ? basename(value) : null);
|
||||||
|
this._langIdKey.set(value ? this._modeService.getModeIdByFilepathOrFirstLine(value) : null);
|
||||||
|
this._extensionKey.set(value ? extname(value) : null);
|
||||||
|
@@ -200,4 +201,4 @@ export class ResourceGlobMatcher extends Disposable {
|
||||||
|
|
||||||
|
return !!expressionForRoot(resourcePathToMatch);
|
||||||
|
}
|
||||||
|
-}
|
||||||
|
\ No newline at end of file
|
||||||
|
+}
|
||||||
diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts
|
diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts
|
||||||
index 1f4cd95f65..061931cbde 100644
|
index 1f4cd95f65..061931cbde 100644
|
||||||
--- a/src/vs/workbench/contrib/files/browser/files.contribution.ts
|
--- a/src/vs/workbench/contrib/files/browser/files.contribution.ts
|
||||||
|
|||||||
@@ -3,15 +3,16 @@ import { URI } from "vs/base/common/uri";
|
|||||||
import { registerSingleton } from "vs/platform/instantiation/common/extensions";
|
import { registerSingleton } from "vs/platform/instantiation/common/extensions";
|
||||||
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
|
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
|
||||||
import { ILocalizationsService } from "vs/platform/localizations/common/localizations";
|
import { ILocalizationsService } from "vs/platform/localizations/common/localizations";
|
||||||
import { LocalizationsService } from "vs/workbench/services/localizations/electron-browser/localizationsService";
|
import { PersistentConnectionEventType } from "vs/platform/remote/common/remoteAgentConnection";
|
||||||
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
|
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
|
||||||
import { coderApi, vscodeApi } from "vs/server/src/browser/api";
|
import { coderApi, vscodeApi } from "vs/server/src/browser/api";
|
||||||
import { IUploadService, UploadService } from "vs/server/src/browser/upload";
|
import { IUploadService, UploadService } from "vs/server/src/browser/upload";
|
||||||
import { INodeProxyService, NodeProxyChannelClient } from "vs/server/src/common/nodeProxy";
|
import { INodeProxyService, NodeProxyChannelClient } from "vs/server/src/common/nodeProxy";
|
||||||
import { TelemetryChannelClient } from "vs/server/src/common/telemetry";
|
import { TelemetryChannelClient } from "vs/server/src/common/telemetry";
|
||||||
|
import { split } from "vs/server/src/common/util";
|
||||||
import "vs/workbench/contrib/localizations/browser/localizations.contribution";
|
import "vs/workbench/contrib/localizations/browser/localizations.contribution";
|
||||||
|
import { LocalizationsService } from "vs/workbench/services/localizations/electron-browser/localizationsService";
|
||||||
import { IRemoteAgentService } from "vs/workbench/services/remote/common/remoteAgentService";
|
import { IRemoteAgentService } from "vs/workbench/services/remote/common/remoteAgentService";
|
||||||
import { PersistentConnectionEventType } from "vs/platform/remote/common/remoteAgentConnection";
|
|
||||||
|
|
||||||
class TelemetryService extends TelemetryChannelClient {
|
class TelemetryService extends TelemetryChannelClient {
|
||||||
public constructor(
|
public constructor(
|
||||||
@@ -79,7 +80,7 @@ export const withQuery = (url: string, replace: Query): string => {
|
|||||||
const uri = URI.parse(url);
|
const uri = URI.parse(url);
|
||||||
const query = { ...replace };
|
const query = { ...replace };
|
||||||
uri.query.split("&").forEach((kv) => {
|
uri.query.split("&").forEach((kv) => {
|
||||||
const [key, value] = kv.split("=", 2);
|
const [key, value] = split(kv, "=");
|
||||||
if (!(key in query)) {
|
if (!(key in query)) {
|
||||||
query[key] = value;
|
query[key] = value;
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/common/util.ts
Normal file
10
src/common/util.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Split a string up to the delimiter. If the delimiter doesn't exist the first
|
||||||
|
* item will have all the text and the second item will be an empty string.
|
||||||
|
*/
|
||||||
|
export const split = (str: string, delimiter: string): [string, string] => {
|
||||||
|
const index = str.indexOf(delimiter);
|
||||||
|
return index !== -1
|
||||||
|
? [str.substring(0, index).trim(), str.substring(index + 1)]
|
||||||
|
: [str, ""];
|
||||||
|
};
|
||||||
@@ -90,7 +90,7 @@ const startVscode = async (): Promise<void | void[]> => {
|
|||||||
basePath: args["base-path"],
|
basePath: args["base-path"],
|
||||||
cert: args.cert,
|
cert: args.cert,
|
||||||
certKey: args["cert-key"],
|
certKey: args["cert-key"],
|
||||||
folderUri: extra.length > 1 ? extra[extra.length - 1] : undefined,
|
openUri: extra.length > 1 ? extra[extra.length - 1] : undefined,
|
||||||
host: args.host,
|
host: args.host,
|
||||||
password: process.env.PASSWORD,
|
password: process.env.PASSWORD,
|
||||||
};
|
};
|
||||||
@@ -204,6 +204,7 @@ export class WrapperProcess {
|
|||||||
logger.info("Relaunching...");
|
logger.info("Relaunching...");
|
||||||
this.started = undefined;
|
this.started = undefined;
|
||||||
if (this.process) {
|
if (this.process) {
|
||||||
|
this.process.removeAllListeners();
|
||||||
this.process.kill();
|
this.process.kill();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -223,7 +224,9 @@ export class WrapperProcess {
|
|||||||
public start(): Promise<void> {
|
public start(): Promise<void> {
|
||||||
if (!this.started) {
|
if (!this.started) {
|
||||||
const child = this.spawn();
|
const child = this.spawn();
|
||||||
this.started = ipcMain.handshake(child);
|
this.started = ipcMain.handshake(child).then(() => {
|
||||||
|
child.once("exit", (code) => exit(code!));
|
||||||
|
});
|
||||||
this.process = child;
|
this.process = child;
|
||||||
}
|
}
|
||||||
return this.started;
|
return this.started;
|
||||||
@@ -234,6 +237,7 @@ export class WrapperProcess {
|
|||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
LAUNCH_VSCODE: "true",
|
LAUNCH_VSCODE: "true",
|
||||||
|
VSCODE_PARENT_PID: process.pid.toString(),
|
||||||
},
|
},
|
||||||
stdio: ["inherit", "inherit", "inherit", "ipc"],
|
stdio: ["inherit", "inherit", "inherit", "ipc"],
|
||||||
});
|
});
|
||||||
@@ -254,6 +258,20 @@ process.exit = function (code?: number) {
|
|||||||
console.warn(err.stack);
|
console.warn(err.stack);
|
||||||
} as (code?: number) => never;
|
} as (code?: number) => never;
|
||||||
|
|
||||||
|
// Copy the extension host behavior of killing oneself if the parent dies. This
|
||||||
|
// also exists in bootstrap-fork.js but spawning with that won't work because we
|
||||||
|
// override process.exit.
|
||||||
|
if (typeof process.env.VSCODE_PARENT_PID !== "undefined") {
|
||||||
|
const parentPid = parseInt(process.env.VSCODE_PARENT_PID, 10);
|
||||||
|
setInterval(() => {
|
||||||
|
try {
|
||||||
|
process.kill(parentPid, 0); // Throws an exception if the process doesn't exist anymore.
|
||||||
|
} catch (e) {
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
// It's possible that the pipe has closed (for example if you run code-server
|
// It's possible that the pipe has closed (for example if you run code-server
|
||||||
// --version | head -1). Assume that means we're done.
|
// --version | head -1). Assume that means we're done.
|
||||||
if (!process.stdout.isTTY) {
|
if (!process.stdout.isTTY) {
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ import { resolveCommonProperties } from "vs/platform/telemetry/node/commonProper
|
|||||||
import { UpdateChannel } from "vs/platform/update/electron-main/updateIpc";
|
import { UpdateChannel } from "vs/platform/update/electron-main/updateIpc";
|
||||||
import { INodeProxyService, NodeProxyChannel } from "vs/server/src/common/nodeProxy";
|
import { INodeProxyService, NodeProxyChannel } from "vs/server/src/common/nodeProxy";
|
||||||
import { TelemetryChannel } from "vs/server/src/common/telemetry";
|
import { TelemetryChannel } from "vs/server/src/common/telemetry";
|
||||||
|
import { split } from "vs/server/src/common/util";
|
||||||
import { ExtensionEnvironmentChannel, FileProviderChannel, NodeProxyService } from "vs/server/src/node/channel";
|
import { ExtensionEnvironmentChannel, FileProviderChannel, NodeProxyService } from "vs/server/src/node/channel";
|
||||||
import { Connection, ExtensionHostConnection, ManagementConnection } from "vs/server/src/node/connection";
|
import { Connection, ExtensionHostConnection, ManagementConnection } from "vs/server/src/node/connection";
|
||||||
import { TelemetryClient } from "vs/server/src/node/insights";
|
import { TelemetryClient } from "vs/server/src/node/insights";
|
||||||
@@ -115,7 +116,7 @@ export interface ServerOptions {
|
|||||||
readonly connectionToken?: string;
|
readonly connectionToken?: string;
|
||||||
readonly cert?: string;
|
readonly cert?: string;
|
||||||
readonly certKey?: string;
|
readonly certKey?: string;
|
||||||
readonly folderUri?: string;
|
readonly openUri?: string;
|
||||||
readonly host?: string;
|
readonly host?: string;
|
||||||
readonly password?: string;
|
readonly password?: string;
|
||||||
readonly port?: number;
|
readonly port?: number;
|
||||||
@@ -212,8 +213,8 @@ export abstract class Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected withBase(request: http.IncomingMessage, path: string): string {
|
protected withBase(request: http.IncomingMessage, path: string): string {
|
||||||
const split = request.url ? request.url.split("?", 2) : [];
|
const [, query] = request.url ? split(request.url, "?") : [];
|
||||||
return `${this.protocol}://${request.headers.host}${this.options.basePath}${path}${split.length === 2 ? `?${split[1]}` : ""}`;
|
return `${this.protocol}://${request.headers.host}${this.options.basePath}${path}${query ? `?${query}` : ""}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private isAllowedRequestPath(path: string): boolean {
|
private isAllowedRequestPath(path: string): boolean {
|
||||||
@@ -440,8 +441,8 @@ export abstract class Server {
|
|||||||
const cookies: { [key: string]: string } = {};
|
const cookies: { [key: string]: string } = {};
|
||||||
if (request.headers.cookie) {
|
if (request.headers.cookie) {
|
||||||
request.headers.cookie.split(";").forEach((keyValue) => {
|
request.headers.cookie.split(";").forEach((keyValue) => {
|
||||||
const [key, value] = keyValue.split("=", 2);
|
const [key, value] = split(keyValue, "=");
|
||||||
cookies[key.trim()] = decodeURI(value);
|
cookies[key] = decodeURI(value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return cookies as T;
|
return cookies as T;
|
||||||
@@ -474,6 +475,9 @@ export class MainServer extends Server {
|
|||||||
private readonly proxyTimeout = 5000;
|
private readonly proxyTimeout = 5000;
|
||||||
|
|
||||||
private settings: Settings = {};
|
private settings: Settings = {};
|
||||||
|
private heartbeatTimer?: NodeJS.Timeout;
|
||||||
|
private heartbeatInterval = 60000;
|
||||||
|
private lastHeartbeat = 0;
|
||||||
|
|
||||||
public constructor(options: ServerOptions, args: ParsedArgs) {
|
public constructor(options: ServerOptions, args: ParsedArgs) {
|
||||||
super(options);
|
super(options);
|
||||||
@@ -491,6 +495,7 @@ export class MainServer extends Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async handleWebSocket(socket: net.Socket, parsedUrl: url.UrlWithParsedQuery): Promise<void> {
|
protected async handleWebSocket(socket: net.Socket, parsedUrl: url.UrlWithParsedQuery): Promise<void> {
|
||||||
|
this.heartbeat();
|
||||||
if (!parsedUrl.query.reconnectionToken) {
|
if (!parsedUrl.query.reconnectionToken) {
|
||||||
throw new Error("Reconnection token is missing from query parameters");
|
throw new Error("Reconnection token is missing from query parameters");
|
||||||
}
|
}
|
||||||
@@ -514,12 +519,13 @@ export class MainServer extends Server {
|
|||||||
parsedUrl: url.UrlWithParsedQuery,
|
parsedUrl: url.UrlWithParsedQuery,
|
||||||
request: http.IncomingMessage,
|
request: http.IncomingMessage,
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
|
this.heartbeat();
|
||||||
switch (base) {
|
switch (base) {
|
||||||
case "/": return this.getRoot(request, parsedUrl);
|
case "/": return this.getRoot(request, parsedUrl);
|
||||||
case "/resource":
|
case "/resource":
|
||||||
case "/vscode-remote-resource":
|
case "/vscode-remote-resource":
|
||||||
if (typeof parsedUrl.query.path === "string") {
|
if (typeof parsedUrl.query.path === "string") {
|
||||||
return this.getResource(parsedUrl.query.path);
|
return this.getAnyResource(parsedUrl.query.path);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "/tar":
|
case "/tar":
|
||||||
@@ -546,9 +552,9 @@ export class MainServer extends Server {
|
|||||||
util.promisify(fs.readFile)(filePath, "utf8"),
|
util.promisify(fs.readFile)(filePath, "utf8"),
|
||||||
this.getFirstValidPath([
|
this.getFirstValidPath([
|
||||||
{ path: parsedUrl.query.workspace, workspace: true },
|
{ path: parsedUrl.query.workspace, workspace: true },
|
||||||
{ path: parsedUrl.query.folder },
|
{ path: parsedUrl.query.folder, workspace: false },
|
||||||
(await this.readSettings()).lastVisited,
|
(await this.readSettings()).lastVisited,
|
||||||
{ path: this.options.folderUri }
|
{ path: this.options.openUri }
|
||||||
]),
|
]),
|
||||||
this.servicesPromise,
|
this.servicesPromise,
|
||||||
]);
|
]);
|
||||||
@@ -592,7 +598,9 @@ export class MainServer extends Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Choose the first valid path.
|
* Choose the first valid path. If `workspace` is undefined then either a
|
||||||
|
* workspace or a directory are acceptable. Otherwise it must be a file if a
|
||||||
|
* workspace or a directory otherwise.
|
||||||
*/
|
*/
|
||||||
private async getFirstValidPath(startPaths: Array<StartPath | undefined>): Promise<{ uri: URI, workspace?: boolean} | undefined> {
|
private async getFirstValidPath(startPaths: Array<StartPath | undefined>): Promise<{ uri: URI, workspace?: boolean} | undefined> {
|
||||||
const logger = this.services.get(ILogService) as ILogService;
|
const logger = this.services.get(ILogService) as ILogService;
|
||||||
@@ -607,9 +615,8 @@ export class MainServer extends Server {
|
|||||||
const uri = URI.file(sanitizeFilePath(paths[j], cwd));
|
const uri = URI.file(sanitizeFilePath(paths[j], cwd));
|
||||||
try {
|
try {
|
||||||
const stat = await util.promisify(fs.stat)(uri.fsPath);
|
const stat = await util.promisify(fs.stat)(uri.fsPath);
|
||||||
// Workspace must be a file.
|
if (typeof startPath.workspace === "undefined" || startPath.workspace !== stat.isDirectory()) {
|
||||||
if (!!startPath.workspace !== stat.isDirectory()) {
|
return { uri, workspace: !stat.isDirectory() };
|
||||||
return { uri, workspace: startPath.workspace };
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.warn(error.message);
|
logger.warn(error.message);
|
||||||
@@ -876,4 +883,48 @@ export class MainServer extends Server {
|
|||||||
(this.services.get(ILogService) as ILogService).warn(error.message);
|
(this.services.get(ILogService) as ILogService).warn(error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the file path for the heartbeat file.
|
||||||
|
*/
|
||||||
|
private get heartbeatPath(): string {
|
||||||
|
const environment = this.services.get(IEnvironmentService) as IEnvironmentService;
|
||||||
|
return path.join(environment.userDataPath, "heartbeat");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all online connections regardless of type.
|
||||||
|
*/
|
||||||
|
private get onlineConnections(): Connection[] {
|
||||||
|
const online = <Connection[]>[];
|
||||||
|
this.connections.forEach((connections) => {
|
||||||
|
connections.forEach((connection) => {
|
||||||
|
if (typeof connection.offline === "undefined") {
|
||||||
|
online.push(connection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return online;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write to the heartbeat file if we haven't already done so within the
|
||||||
|
* timeout and start or reset a timer that keeps running as long as there are
|
||||||
|
* active connections. Failures are logged as warnings.
|
||||||
|
*/
|
||||||
|
private heartbeat(): void {
|
||||||
|
const now = Date.now();
|
||||||
|
if (now - this.lastHeartbeat >= this.heartbeatInterval) {
|
||||||
|
util.promisify(fs.writeFile)(this.heartbeatPath, "").catch((error) => {
|
||||||
|
(this.services.get(ILogService) as ILogService).warn(error.message);
|
||||||
|
});
|
||||||
|
this.lastHeartbeat = now;
|
||||||
|
clearTimeout(this.heartbeatTimer!); // We can clear undefined so ! is fine.
|
||||||
|
this.heartbeatTimer = setTimeout(() => {
|
||||||
|
if (this.onlineConnections.length > 0) {
|
||||||
|
this.heartbeat();
|
||||||
|
}
|
||||||
|
}, this.heartbeatInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,22 +4,19 @@ module.exports = (remoteAuthority) => {
|
|||||||
return {
|
return {
|
||||||
transformIncoming: (uri) => {
|
transformIncoming: (uri) => {
|
||||||
switch (uri.scheme) {
|
switch (uri.scheme) {
|
||||||
case "code-server": return { scheme: "file", path: uri.path };
|
case "vscode-remote": return { scheme: "file", path: uri.path };
|
||||||
case "file": return { scheme: "code-server", path: uri.path };
|
|
||||||
default: return uri;
|
default: return uri;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
transformOutgoing: (uri) => {
|
transformOutgoing: (uri) => {
|
||||||
switch (uri.scheme) {
|
switch (uri.scheme) {
|
||||||
case "code-server": return { scheme: "file", path: uri.path };
|
case "file": return { scheme: "vscode-remote", authority: remoteAuthority, path: uri.path };
|
||||||
case "file": return { scheme: "code-server", authority: remoteAuthority, path: uri.path };
|
|
||||||
default: return uri;
|
default: return uri;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
transformOutgoingScheme: (scheme) => {
|
transformOutgoingScheme: (scheme) => {
|
||||||
switch (scheme) {
|
switch (scheme) {
|
||||||
case "code-server": return "file";
|
case "file": return "vscode-remote";
|
||||||
case "file": return "code-server";
|
|
||||||
default: return scheme;
|
default: return scheme;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1256,9 +1256,9 @@ minizlib@^1.1.1:
|
|||||||
minipass "^2.2.1"
|
minipass "^2.2.1"
|
||||||
|
|
||||||
mixin-deep@^1.2.0:
|
mixin-deep@^1.2.0:
|
||||||
version "1.3.1"
|
version "1.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
|
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
|
||||||
integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==
|
integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
|
||||||
dependencies:
|
dependencies:
|
||||||
for-in "^1.0.2"
|
for-in "^1.0.2"
|
||||||
is-extendable "^1.0.1"
|
is-extendable "^1.0.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user