Update VS Code to 1.37.0
This commit is contained in:
parent
b257c60636
commit
ba7285192c
@ -8,14 +8,14 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
env:
|
env:
|
||||||
- VSCODE_VERSION="1.36.1" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="linux"
|
- VSCODE_VERSION="1.37.0" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="linux"
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
env:
|
env:
|
||||||
- VSCODE_VERSION="1.36.1" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="alpine"
|
- VSCODE_VERSION="1.37.0" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="alpine"
|
||||||
- os: osx
|
- os: osx
|
||||||
env:
|
env:
|
||||||
- VSCODE_VERSION="1.36.1" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER"
|
- VSCODE_VERSION="1.37.0" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER"
|
||||||
before_install:
|
before_install:
|
||||||
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then export MINIFY="true"; fi
|
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then export MINIFY="true"; fi
|
||||||
script:
|
script:
|
||||||
|
18
README.md
18
README.md
@ -81,7 +81,7 @@ data collected to improve code-server.
|
|||||||
```shell
|
```shell
|
||||||
git clone https://github.com/microsoft/vscode
|
git clone https://github.com/microsoft/vscode
|
||||||
cd vscode
|
cd vscode
|
||||||
git checkout 1.36.1
|
git checkout 1.37.0
|
||||||
git clone https://github.com/cdr/code-server src/vs/server
|
git clone https://github.com/cdr/code-server src/vs/server
|
||||||
cd src/vs/server
|
cd src/vs/server
|
||||||
yarn patch:apply
|
yarn patch:apply
|
||||||
@ -109,23 +109,19 @@ directory.
|
|||||||
|
|
||||||
Our changes include:
|
Our changes include:
|
||||||
- Add a `code-server` schema.
|
- Add a `code-server` schema.
|
||||||
- Make the extension sidebar work in the browser. Mostly involves removing
|
|
||||||
Node-specific code for the `extensions` channel client and adding a
|
|
||||||
`gallery` channel.
|
|
||||||
- Allow multiple extension directories (both user and built-in).
|
- Allow multiple extension directories (both user and built-in).
|
||||||
- Rewrite assets used in the CSS (like icons) or as images to use the base URL.
|
- Rewrite assets requested by the browser to use the base URL.
|
||||||
- Change the loader to use the base URL.
|
- Modify the loader to use the base URL.
|
||||||
- Change the web socket to use the base URL and TLS if necessary.
|
- Modify the web socket to use the base URL and TLS if necessary.
|
||||||
- Set the favicon using a relative path.
|
- Send client-side telemetry through the server.
|
||||||
- Modify the file service to support writing from an asynchronous stream (for
|
|
||||||
uploading files).
|
|
||||||
- Add a file prefix to ignore for temporary files created during upload.
|
- Add a file prefix to ignore for temporary files created during upload.
|
||||||
- Insert our upload service for use in editor windows and explorer.
|
- Insert our upload service for use in editor windows and explorer.
|
||||||
- Modify the log level to get its initial setting from the server.
|
- Modify the log level to get its initial setting from the server.
|
||||||
- Get telemetry working by adding a channel for it.
|
|
||||||
- Change a regular expression used for mnemonics so it works on Firefox.
|
- Change a regular expression used for mnemonics so it works on Firefox.
|
||||||
- Make it possible for us to load code on the client.
|
- Make it possible for us to load code on the client.
|
||||||
- Modify the build process to include our code.
|
- Modify the build process to include our code.
|
||||||
|
- Fix a CSP issue within a webview.
|
||||||
|
- Fix an issue displaying extension contributions.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
[MIT](LICENSE)
|
[MIT](LICENSE)
|
||||||
|
58
scripts/build-json.js
Normal file
58
scripts/build-json.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// This builds the package and product JSON files for the final build.
|
||||||
|
const crypto = require("crypto");
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
const rootPath = path.resolve(__dirname, "..");
|
||||||
|
const sourcePath = process.argv[2];
|
||||||
|
const buildPath = process.argv[3];
|
||||||
|
const vscodeVersion = process.argv[4];
|
||||||
|
const codeServerVersion = process.argv[5];
|
||||||
|
const util = require(path.join(sourcePath, "build/lib/util"));
|
||||||
|
|
||||||
|
function computeChecksum(filename) {
|
||||||
|
return crypto.createHash("md5").update(fs.readFileSync(filename))
|
||||||
|
.digest("base64").replace(/=+$/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
const computeChecksums = (filenames) => {
|
||||||
|
const result = {};
|
||||||
|
filenames.forEach(function (filename) {
|
||||||
|
result[filename] = computeChecksum(path.join(buildPath, "out", filename));
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mergeAndWrite = (name, json = {}) => {
|
||||||
|
const aJson = JSON.parse(fs.readFileSync(path.join(sourcePath, `${name}.json`)));
|
||||||
|
const bJson = JSON.parse(fs.readFileSync(path.join(rootPath, "scripts", `${name}.json`)));
|
||||||
|
|
||||||
|
delete aJson.scripts;
|
||||||
|
delete aJson.dependencies;
|
||||||
|
delete aJson.devDependencies;
|
||||||
|
delete aJson.optionalDependencies;
|
||||||
|
|
||||||
|
fs.writeFileSync(path.join(buildPath, `${name}.json`), JSON.stringify({
|
||||||
|
...aJson,
|
||||||
|
...bJson,
|
||||||
|
...json,
|
||||||
|
}, null, 2));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const writeProduct = () => {
|
||||||
|
const checksums = computeChecksums([
|
||||||
|
"vs/workbench/workbench.web.api.js",
|
||||||
|
"vs/workbench/workbench.web.api.css",
|
||||||
|
"vs/code/browser/workbench/workbench.html",
|
||||||
|
"vs/code/browser/workbench/workbench.js",
|
||||||
|
"vs/server/src/cli.js",
|
||||||
|
"vs/server/src/uriTransformer.js",
|
||||||
|
"vs/server/src/login/index.html"
|
||||||
|
]);
|
||||||
|
const date = new Date().toISOString();
|
||||||
|
const commit = util.getVersion(rootPath);
|
||||||
|
mergeAndWrite("product", { commit, date, checksums });
|
||||||
|
mergeAndWrite("package", { codeServerVersion: `${codeServerVersion}-vsc${vscodeVersion}` });
|
||||||
|
};
|
||||||
|
|
||||||
|
writeProduct();
|
@ -1,23 +0,0 @@
|
|||||||
// This is used to merge JSON files (package.json and product.json) and delete a
|
|
||||||
// few entries we don't want. It's extremely simple, expects very specific
|
|
||||||
// input, and doesn't have any error handling.
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
const a = process.argv[2];
|
|
||||||
const b = process.argv[3];
|
|
||||||
const out = process.argv[4];
|
|
||||||
const json = JSON.parse(process.argv[5] || "{}");
|
|
||||||
|
|
||||||
const aJson = JSON.parse(fs.readFileSync(a));
|
|
||||||
const bJson = JSON.parse(fs.readFileSync(b));
|
|
||||||
|
|
||||||
delete aJson.scripts;
|
|
||||||
delete aJson.dependencies;
|
|
||||||
delete aJson.devDependencies;
|
|
||||||
delete aJson.optionalDependencies;
|
|
||||||
|
|
||||||
fs.writeFileSync(out, JSON.stringify({
|
|
||||||
...aJson,
|
|
||||||
...bJson,
|
|
||||||
...json,
|
|
||||||
}, null, 2));
|
|
@ -56,9 +56,9 @@ function prepend-loader() {
|
|||||||
# Copy code-server into VS Code then build it.
|
# Copy code-server into VS Code then build it.
|
||||||
function build-code-server() {
|
function build-code-server() {
|
||||||
copy-server
|
copy-server
|
||||||
|
yarn gulp compile-build --max-old-space-size=32384
|
||||||
|
|
||||||
local min=""
|
local min=""
|
||||||
export BUILD_SOURCEVERSION
|
|
||||||
BUILD_SOURCEVERSION=$(node -p "require('${sourcePath}/build/lib/git.js').getVersion('${rootPath}')")
|
|
||||||
if [[ -n "${minify}" ]] ; then
|
if [[ -n "${minify}" ]] ; then
|
||||||
min="-min"
|
min="-min"
|
||||||
yarn gulp minify-vscode --max-old-space-size=32384
|
yarn gulp minify-vscode --max-old-space-size=32384
|
||||||
@ -74,11 +74,9 @@ function build-code-server() {
|
|||||||
cd "${buildPath}" && yarn --production --force --build-from-source
|
cd "${buildPath}" && yarn --production --force --build-from-source
|
||||||
rm "${buildPath}/"{package.json,yarn.lock,.yarnrc}
|
rm "${buildPath}/"{package.json,yarn.lock,.yarnrc}
|
||||||
|
|
||||||
local packageJson="{\"codeServerVersion\": \"${codeServerVersion}-vsc${vscodeVersion}\"}"
|
|
||||||
cp -r "${sourcePath}/.build/extensions" "${buildPath}"
|
cp -r "${sourcePath}/.build/extensions" "${buildPath}"
|
||||||
node "${rootPath}/scripts/merge.js" "${sourcePath}/package.json" "${rootPath}/scripts/package.json" "${buildPath}/package.json" "${packageJson}"
|
|
||||||
node "${rootPath}/scripts/merge.js" "${sourcePath}/.build/product.json" "${rootPath}/scripts/product.json" "${buildPath}/product.json"
|
|
||||||
cp -r "${sourcePath}/out-vscode${min}" "${buildPath}/out"
|
cp -r "${sourcePath}/out-vscode${min}" "${buildPath}/out"
|
||||||
|
node "${rootPath}/scripts/build-json.js" "${sourcePath}" "${buildPath}" "${vscodeVersion}" "${codeServerVersion}"
|
||||||
|
|
||||||
# Only keep production dependencies for the server.
|
# Only keep production dependencies for the server.
|
||||||
cp "${rootPath}/"{package.json,yarn.lock} "${buildPath}/out/vs/server"
|
cp "${rootPath}/"{package.json,yarn.lock} "${buildPath}/out/vs/server"
|
||||||
@ -143,7 +141,7 @@ function build-task() {
|
|||||||
log "Pre-built VS Code ${vscodeVersion} has no built extensions" "error"
|
log "Pre-built VS Code ${vscodeVersion} has no built extensions" "error"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
yarn gulp extensions-build-package --max-old-space-size=32384
|
yarn gulp compile-extensions-build --max-old-space-size=32384
|
||||||
fi
|
fi
|
||||||
build-code-server
|
build-code-server
|
||||||
}
|
}
|
||||||
|
1649
scripts/vscode.patch
1649
scripts/vscode.patch
File diff suppressed because it is too large
Load Diff
47
src/api.ts
47
src/api.ts
@ -1,35 +1,34 @@
|
|||||||
import * as vscode from "vscode";
|
import { createCSSRule } from "vs/base/browser/dom";
|
||||||
|
import { Emitter, Event } from "vs/base/common/event";
|
||||||
|
import { IDisposable } from "vs/base/common/lifecycle";
|
||||||
|
import { URI } from "vs/base/common/uri";
|
||||||
|
import { generateUuid } from "vs/base/common/uuid";
|
||||||
import { localize } from "vs/nls";
|
import { localize } from "vs/nls";
|
||||||
import { SyncActionDescriptor } from "vs/platform/actions/common/actions";
|
import { SyncActionDescriptor } from "vs/platform/actions/common/actions";
|
||||||
import { Registry } from "vs/platform/registry/common/platform";
|
|
||||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions} from "vs/workbench/common/actions";
|
|
||||||
import { CommandsRegistry, ICommandService } from "vs/platform/commands/common/commands";
|
import { CommandsRegistry, ICommandService } from "vs/platform/commands/common/commands";
|
||||||
import { IStat, IWatchOptions, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileChange, FileWriteOptions, FileSystemProviderCapabilities, IFileService, FileType, IFileSystemProvider } from "vs/platform/files/common/files";
|
import { IConfigurationService } from "vs/platform/configuration/common/configuration";
|
||||||
import { IStorageService } from "vs/platform/storage/common/storage";
|
import { IContextMenuService } from "vs/platform/contextview/browser/contextView";
|
||||||
|
import { FileDeleteOptions, FileOpenOptions, FileOverwriteOptions, FileSystemProviderCapabilities, FileType, FileWriteOptions, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions } from "vs/platform/files/common/files";
|
||||||
|
import { IInstantiationService, ServiceIdentifier } from "vs/platform/instantiation/common/instantiation";
|
||||||
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
|
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
|
||||||
import { INotificationService } from "vs/platform/notification/common/notification";
|
import { INotificationService } from "vs/platform/notification/common/notification";
|
||||||
import { Emitter, Event } from "vs/base/common/event";
|
import { Registry } from "vs/platform/registry/common/platform";
|
||||||
import * as extHostTypes from "vs/workbench/api/common/extHostTypes";
|
import { IStorageService } from "vs/platform/storage/common/storage";
|
||||||
import { ServiceIdentifier, IInstantiationService } from "vs/platform/instantiation/common/instantiation";
|
|
||||||
import { URI } from "vs/base/common/uri";
|
|
||||||
import { ITreeItem, ITreeViewDataProvider, IViewsRegistry, ITreeViewDescriptor, Extensions as ViewsExtensions, IViewContainersRegistry, TreeItemCollapsibleState } from "vs/workbench/common/views";
|
|
||||||
import { CustomTreeViewPanel, CustomTreeView } from "vs/workbench/browser/parts/views/customView";
|
|
||||||
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ShowViewletAction } from "vs/workbench/browser/viewlet";
|
|
||||||
import { IExtensionService } from "vs/workbench/services/extensions/common/extensions";
|
|
||||||
import { ViewContainerViewlet } from "vs/workbench/browser/parts/views/viewsViewlet";
|
|
||||||
import { IConfigurationService } from "vs/platform/configuration/common/configuration";
|
|
||||||
import { IWorkbenchLayoutService } from "vs/workbench/services/layout/browser/layoutService";
|
|
||||||
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
|
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
|
||||||
import { IWorkspaceContextService } from "vs/platform/workspace/common/workspace";
|
|
||||||
import { IEditorService } from "vs/workbench/services/editor/common/editorService";
|
|
||||||
import { IThemeService } from "vs/platform/theme/common/themeService";
|
import { IThemeService } from "vs/platform/theme/common/themeService";
|
||||||
import { IContextMenuService } from "vs/platform/contextview/browser/contextView";
|
import { IWorkspaceContextService } from "vs/platform/workspace/common/workspace";
|
||||||
import { IViewletService } from "vs/workbench/services/viewlet/browser/viewlet";
|
import * as extHostTypes from "vs/workbench/api/common/extHostTypes";
|
||||||
|
import { CustomTreeView, CustomTreeViewPanel } from "vs/workbench/browser/parts/views/customView";
|
||||||
|
import { ViewContainerViewlet } from "vs/workbench/browser/parts/views/viewsViewlet";
|
||||||
|
import { Extensions as ViewletExtensions, ShowViewletAction, ViewletDescriptor, ViewletRegistry } from "vs/workbench/browser/viewlet";
|
||||||
|
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from "vs/workbench/common/actions";
|
||||||
|
import { Extensions as ViewsExtensions, ITreeItem, ITreeViewDataProvider, ITreeViewDescriptor, IViewContainersRegistry, IViewsRegistry, TreeItemCollapsibleState } from "vs/workbench/common/views";
|
||||||
import { IEditorGroupsService } from "vs/workbench/services/editor/common/editorGroupsService";
|
import { IEditorGroupsService } from "vs/workbench/services/editor/common/editorGroupsService";
|
||||||
import { createCSSRule } from "vs/base/browser/dom";
|
import { IEditorService } from "vs/workbench/services/editor/common/editorService";
|
||||||
import { IDisposable } from "vs/base/common/lifecycle";
|
import { IExtensionService } from "vs/workbench/services/extensions/common/extensions";
|
||||||
import { generateUuid } from "vs/base/common/uuid";
|
import { IWorkbenchLayoutService } from "vs/workbench/services/layout/browser/layoutService";
|
||||||
|
import { IViewletService } from "vs/workbench/services/viewlet/browser/viewlet";
|
||||||
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client-side implementation of VS Code's API.
|
* Client-side implementation of VS Code's API.
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
import { VSBuffer } from "vs/base/common/buffer";
|
import { VSBuffer } from "vs/base/common/buffer";
|
||||||
import { Emitter, Event } from "vs/base/common/event";
|
import { Emitter, Event } from "vs/base/common/event";
|
||||||
import { IDisposable } from "vs/base/common/lifecycle";
|
import { IDisposable } from "vs/base/common/lifecycle";
|
||||||
@ -9,18 +8,17 @@ import { transformOutgoingURIs } from "vs/base/common/uriIpc";
|
|||||||
import { IServerChannel } from "vs/base/parts/ipc/common/ipc";
|
import { IServerChannel } from "vs/base/parts/ipc/common/ipc";
|
||||||
import { IDiagnosticInfo } from "vs/platform/diagnostics/common/diagnosticsService";
|
import { IDiagnosticInfo } from "vs/platform/diagnostics/common/diagnosticsService";
|
||||||
import { IEnvironmentService } from "vs/platform/environment/common/environment";
|
import { IEnvironmentService } from "vs/platform/environment/common/environment";
|
||||||
import { IExtensionDescription, ExtensionIdentifier } from "vs/platform/extensions/common/extensions";
|
import { ExtensionIdentifier, IExtensionDescription } from "vs/platform/extensions/common/extensions";
|
||||||
import { FileDeleteOptions, FileOverwriteOptions, FileType, IStat, IWatchOptions, FileOpenOptions } from "vs/platform/files/common/files";
|
import { FileDeleteOptions, FileOpenOptions, FileOverwriteOptions, FileType, IStat, IWatchOptions } from "vs/platform/files/common/files";
|
||||||
|
import { DiskFileSystemProvider } from "vs/platform/files/node/diskFileSystemProvider";
|
||||||
import { ILogService } from "vs/platform/log/common/log";
|
import { ILogService } from "vs/platform/log/common/log";
|
||||||
import pkg from "vs/platform/product/node/package";
|
import pkg from "vs/platform/product/node/package";
|
||||||
import product from "vs/platform/product/node/product";
|
import product from "vs/platform/product/node/product";
|
||||||
import { IRemoteAgentEnvironment } from "vs/platform/remote/common/remoteAgentEnvironment";
|
import { IRemoteAgentEnvironment } from "vs/platform/remote/common/remoteAgentEnvironment";
|
||||||
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
|
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
|
||||||
import { ExtensionScanner, ExtensionScannerInput } from "vs/workbench/services/extensions/node/extensionPoints";
|
|
||||||
import { DiskFileSystemProvider } from "vs/workbench/services/files/node/diskFileSystemProvider";
|
|
||||||
|
|
||||||
import { getTranslations } from "vs/server/src/nls";
|
import { getTranslations } from "vs/server/src/nls";
|
||||||
import { getUriTransformer } from "vs/server/src/util";
|
import { getUriTransformer } from "vs/server/src/util";
|
||||||
|
import { ExtensionScanner, ExtensionScannerInput } from "vs/workbench/services/extensions/node/extensionPoints";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend the file provider to allow unwatching.
|
* Extend the file provider to allow unwatching.
|
||||||
@ -205,7 +203,7 @@ export class ExtensionEnvironmentChannel implements IServerChannel {
|
|||||||
appSettingsHome: this.environment.appSettingsHome,
|
appSettingsHome: this.environment.appSettingsHome,
|
||||||
settingsPath: this.environment.machineSettingsHome,
|
settingsPath: this.environment.machineSettingsHome,
|
||||||
logsPath: URI.file(this.environment.logsPath),
|
logsPath: URI.file(this.environment.logsPath),
|
||||||
extensionsPath: URI.file(this.environment.extensionsPath),
|
extensionsPath: URI.file(this.environment.extensionsPath!),
|
||||||
extensionHostLogsPath: URI.file(path.join(this.environment.logsPath, "extension-host")),
|
extensionHostLogsPath: URI.file(path.join(this.environment.logsPath, "extension-host")),
|
||||||
globalStorageHome: URI.file(this.environment.globalStorageHome),
|
globalStorageHome: URI.file(this.environment.globalStorageHome),
|
||||||
userHome: URI.file(this.environment.userHome),
|
userHome: URI.file(this.environment.userHome),
|
||||||
@ -237,7 +235,7 @@ export class ExtensionEnvironmentChannel implements IServerChannel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const scanInstalled = async (): Promise<IExtensionDescription[][]> => {
|
const scanInstalled = async (): Promise<IExtensionDescription[][]> => {
|
||||||
return scanMultiple(false, true, [this.environment.extensionsPath, ...this.environment.extraExtensionPaths]);
|
return scanMultiple(false, true, [this.environment.extensionsPath!, ...this.environment.extraExtensionPaths]);
|
||||||
};
|
};
|
||||||
|
|
||||||
return Promise.all([scanBuiltin(), scanInstalled()]).then((allExtensions) => {
|
return Promise.all([scanBuiltin(), scanInstalled()]).then((allExtensions) => {
|
||||||
|
41
src/cli.ts
41
src/cli.ts
@ -1,27 +1,16 @@
|
|||||||
import * as cp from "child_process";
|
import * as cp from "child_process";
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
|
|
||||||
import { main as vsCli } from "vs/code/node/cliProcessMain";
|
import { main as vsCli } from "vs/code/node/cliProcessMain";
|
||||||
import { validatePaths } from "vs/code/node/paths";
|
import { validatePaths } from "vs/code/node/paths";
|
||||||
import { parseMainProcessArgv } from "vs/platform/environment/node/argvHelper";
|
|
||||||
import { buildHelpMessage, buildVersionMessage, options } from "vs/platform/environment/node/argv";
|
|
||||||
import { ParsedArgs } from "vs/platform/environment/common/environment";
|
import { ParsedArgs } from "vs/platform/environment/common/environment";
|
||||||
|
import { buildHelpMessage, buildVersionMessage, Option as VsOption, options as vsOptions } from "vs/platform/environment/node/argv";
|
||||||
|
import { parseMainProcessArgv } from "vs/platform/environment/node/argvHelper";
|
||||||
import pkg from "vs/platform/product/node/package";
|
import pkg from "vs/platform/product/node/package";
|
||||||
import product from "vs/platform/product/node/product";
|
import product from "vs/platform/product/node/product";
|
||||||
|
|
||||||
import { ipcMain } from "vs/server/src/ipc";
|
import { ipcMain } from "vs/server/src/ipc";
|
||||||
|
import { enableCustomMarketplace } from "vs/server/src/marketplace";
|
||||||
product.extensionsGallery = {
|
|
||||||
serviceUrl: process.env.SERVICE_URL || "https://v1.extapi.coder.com",
|
|
||||||
itemUrl: process.env.ITEM_URL || "",
|
|
||||||
controlUrl: "",
|
|
||||||
recommendationsUrl: "",
|
|
||||||
...(product.extensionsGallery || {}),
|
|
||||||
};
|
|
||||||
|
|
||||||
import { MainServer } from "vs/server/src/server";
|
import { MainServer } from "vs/server/src/server";
|
||||||
import { enableExtensionTars } from "vs/server/src/tar";
|
import { AuthType, buildAllowedMessage, enumToArray, generateCertificate, generatePassword, localRequire, open, unpackExecutables } from "vs/server/src/util";
|
||||||
import { AuthType, buildAllowedMessage, generateCertificate, generatePassword, localRequire, open, unpackExecutables } from "vs/server/src/util";
|
|
||||||
|
|
||||||
const { logger } = localRequire<typeof import("@coder/logger/out/index")>("@coder/logger/out/index");
|
const { logger } = localRequire<typeof import("@coder/logger/out/index")>("@coder/logger/out/index");
|
||||||
|
|
||||||
@ -30,15 +19,19 @@ interface Args extends ParsedArgs {
|
|||||||
"base-path"?: string;
|
"base-path"?: string;
|
||||||
cert?: string;
|
cert?: string;
|
||||||
"cert-key"?: string;
|
"cert-key"?: string;
|
||||||
"extra-builtin-extensions-dir"?: string;
|
|
||||||
"extra-extensions-dir"?: string;
|
|
||||||
host?: string;
|
host?: string;
|
||||||
open?: string;
|
open?: string;
|
||||||
port?: string;
|
port?: string;
|
||||||
socket?: string;
|
socket?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore: Force `keyof Args` to work.
|
||||||
|
interface Option extends VsOption {
|
||||||
|
id: keyof Args;
|
||||||
|
}
|
||||||
|
|
||||||
const getArgs = (): Args => {
|
const getArgs = (): Args => {
|
||||||
|
const options = vsOptions as Option[];
|
||||||
// The last item is _ which is like -- so our options need to come before it.
|
// The last item is _ which is like -- so our options need to come before it.
|
||||||
const last = options.pop()!;
|
const last = options.pop()!;
|
||||||
|
|
||||||
@ -78,13 +71,7 @@ const getArgs = (): Args => {
|
|||||||
|
|
||||||
options.push(last);
|
options.push(last);
|
||||||
|
|
||||||
const args = validatePaths(parseMainProcessArgv(process.argv)) as Args;
|
return validatePaths(parseMainProcessArgv(process.argv));
|
||||||
["extra-extensions-dir", "extra-builtin-extensions-dir"].forEach((key) => {
|
|
||||||
if (typeof args[key] === "string") {
|
|
||||||
args[key] = [args[key]];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return args;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const startVscode = async (): Promise<void | void[]> => {
|
const startVscode = async (): Promise<void | void[]> => {
|
||||||
@ -100,7 +87,7 @@ const startVscode = async (): Promise<void | void[]> => {
|
|||||||
password: process.env.PASSWORD,
|
password: process.env.PASSWORD,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options.auth && Object.keys(AuthType).filter((k) => AuthType[k] === options.auth).length === 0) {
|
if (options.auth && enumToArray(AuthType).filter((t) => t === options.auth).length === 0) {
|
||||||
throw new Error(`'${options.auth}' is not a valid authentication type.`);
|
throw new Error(`'${options.auth}' is not a valid authentication type.`);
|
||||||
} else if (options.auth && !options.password) {
|
} else if (options.auth && !options.password) {
|
||||||
options.password = await generatePassword();
|
options.password = await generatePassword();
|
||||||
@ -116,7 +103,7 @@ const startVscode = async (): Promise<void | void[]> => {
|
|||||||
options.certKey = certKey;
|
options.certKey = certKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
enableExtensionTars();
|
enableCustomMarketplace();
|
||||||
|
|
||||||
const server = new MainServer({
|
const server = new MainServer({
|
||||||
...options,
|
...options,
|
||||||
@ -180,7 +167,7 @@ const startCli = (): boolean | Promise<void> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (shouldSpawnCliProcess()) {
|
if (shouldSpawnCliProcess()) {
|
||||||
enableExtensionTars();
|
enableCustomMarketplace();
|
||||||
return vsCli(args);
|
return vsCli(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,29 @@
|
|||||||
|
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 { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
|
||||||
|
import { ILocalizationsService } from "vs/platform/localizations/common/localizations";
|
||||||
|
import { LocalizationsService } from "vs/platform/localizations/electron-browser/localizationsService";
|
||||||
|
import { IUpdateService } from "vs/platform/update/common/update";
|
||||||
|
import { UpdateService } from "vs/platform/update/electron-browser/updateService";
|
||||||
|
import { TelemetryChannelClient } from "vs/server/src/telemetry";
|
||||||
|
import { IRemoteAgentService } from "vs/workbench/services/remote/common/remoteAgentService";
|
||||||
|
|
||||||
import { coderApi, vscodeApi } from "vs/server/src/api";
|
class TelemetryService extends TelemetryChannelClient {
|
||||||
|
public constructor(
|
||||||
|
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
||||||
|
) {
|
||||||
|
super(remoteAgentService.getConnection()!.getChannel("telemetry"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerSingleton(ILocalizationsService, LocalizationsService);
|
||||||
|
registerSingleton(IUpdateService, UpdateService);
|
||||||
|
registerSingleton(ITelemetryService, TelemetryService);
|
||||||
|
|
||||||
|
import "vs/workbench/contrib/update/electron-browser/update.contribution";
|
||||||
|
|
||||||
import "vs/css!./media/firefox";
|
import "vs/css!./media/firefox";
|
||||||
|
import { coderApi, vscodeApi } from "vs/server/src/api";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called by vs/workbench/browser/web.main.ts after the workbench has
|
* This is called by vs/workbench/browser/web.main.ts after the workbench has
|
||||||
@ -13,7 +34,7 @@ export const initialize = async (services: ServiceCollection): Promise<void> =>
|
|||||||
target.ide = coderApi(services);
|
target.ide = coderApi(services);
|
||||||
target.vscode = vscodeApi(services);
|
target.vscode = vscodeApi(services);
|
||||||
|
|
||||||
const event = new CustomEvent('ide-ready');
|
const event = new CustomEvent("ide-ready");
|
||||||
(event as any).ide = target.ide;
|
(event as any).ide = target.ide;
|
||||||
(event as any).vscode = target.vscode;
|
(event as any).vscode = target.vscode;
|
||||||
window.dispatchEvent(event);
|
window.dispatchEvent(event);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import * as cp from "child_process";
|
import * as cp from "child_process";
|
||||||
|
|
||||||
import { getPathFromAmdModule } from "vs/base/common/amd";
|
import { getPathFromAmdModule } from "vs/base/common/amd";
|
||||||
import { VSBuffer } from "vs/base/common/buffer";
|
import { VSBuffer } from "vs/base/common/buffer";
|
||||||
import { Emitter } from "vs/base/common/event";
|
import { Emitter } from "vs/base/common/event";
|
||||||
@ -7,11 +6,10 @@ import { ISocket } from "vs/base/parts/ipc/common/ipc.net";
|
|||||||
import { NodeSocket } from "vs/base/parts/ipc/node/ipc.net";
|
import { NodeSocket } from "vs/base/parts/ipc/node/ipc.net";
|
||||||
import { IEnvironmentService } from "vs/platform/environment/common/environment";
|
import { IEnvironmentService } from "vs/platform/environment/common/environment";
|
||||||
import { ILogService } from "vs/platform/log/common/log";
|
import { ILogService } from "vs/platform/log/common/log";
|
||||||
import { IExtHostReadyMessage } from "vs/workbench/services/extensions/common/extensionHostProtocol";
|
|
||||||
|
|
||||||
import { getNlsConfiguration } from "vs/server/src/nls";
|
import { getNlsConfiguration } from "vs/server/src/nls";
|
||||||
import { Protocol } from "vs/server/src/protocol";
|
import { Protocol } from "vs/server/src/protocol";
|
||||||
import { uriTransformerPath } from "vs/server/src/util";
|
import { uriTransformerPath } from "vs/server/src/util";
|
||||||
|
import { IExtHostReadyMessage } from "vs/workbench/services/extensions/common/extensionHostProtocol";
|
||||||
|
|
||||||
export abstract class Connection {
|
export abstract class Connection {
|
||||||
protected readonly _onClose = new Emitter<void>();
|
protected readonly _onClose = new Emitter<void>();
|
||||||
@ -126,8 +124,8 @@ export class ExtensionHostConnection extends Connection {
|
|||||||
proc.stderr.setEncoding("utf8").on("data", (d) => this.log.error("Extension host stderr", d));
|
proc.stderr.setEncoding("utf8").on("data", (d) => this.log.error("Extension host stderr", d));
|
||||||
proc.on("message", (event) => {
|
proc.on("message", (event) => {
|
||||||
if (event && event.type === "__$console") {
|
if (event && event.type === "__$console") {
|
||||||
const severity = this.log[event.severity] ? event.severity : "info";
|
const severity = (<any>this.log)[event.severity] ? event.severity : "info";
|
||||||
this.log[severity]("Extension host", event.arguments);
|
(<any>this.log)[severity]("Extension host", event.arguments);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
|
import * as appInsights from "applicationinsights";
|
||||||
import * as https from "https";
|
import * as https from "https";
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
|
|
||||||
import * as appInsights from "applicationinsights";
|
|
||||||
|
|
||||||
export class TelemetryClient implements appInsights.TelemetryClient {
|
export class TelemetryClient implements appInsights.TelemetryClient {
|
||||||
public config: any = {};
|
public config: any = {};
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import * as cp from "child_process";
|
import * as cp from "child_process";
|
||||||
|
|
||||||
import { Emitter } from "vs/base/common/event";
|
import { Emitter } from "vs/base/common/event";
|
||||||
|
|
||||||
enum ControlMessage {
|
enum ControlMessage {
|
||||||
|
@ -2,11 +2,11 @@ import * as fs from "fs";
|
|||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import * as tarStream from "tar-stream";
|
import * as tarStream from "tar-stream";
|
||||||
import * as util from "util";
|
import * as util from "util";
|
||||||
|
|
||||||
import * as nls from "vs/nls";
|
|
||||||
import * as vszip from "vs/base/node/zip";
|
|
||||||
import { CancellationToken } from "vs/base/common/cancellation";
|
import { CancellationToken } from "vs/base/common/cancellation";
|
||||||
import { mkdirp } from "vs/base/node/pfs";
|
import { mkdirp } from "vs/base/node/pfs";
|
||||||
|
import * as vszip from "vs/base/node/zip";
|
||||||
|
import * as nls from "vs/nls";
|
||||||
|
import product from "vs/platform/product/node/product";
|
||||||
|
|
||||||
// We will be overriding these, so keep a reference to the original.
|
// We will be overriding these, so keep a reference to the original.
|
||||||
const vszipExtract = vszip.extract;
|
const vszipExtract = vszip.extract;
|
||||||
@ -154,10 +154,18 @@ const extractTar = async (tarPath: string, targetPath: string, options: IExtract
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override original functionality so we can use extensions that are in a tar in
|
* Override original functionality so we can use a custom marketplace with
|
||||||
* addition to zips.
|
* either tars or zips.
|
||||||
*/
|
*/
|
||||||
export const enableExtensionTars = (): void => {
|
export const enableCustomMarketplace = (): void => {
|
||||||
|
(<any>product).extensionsGallery = { // Use `any` to override readonly.
|
||||||
|
serviceUrl: process.env.SERVICE_URL || "https://v1.extapi.coder.com",
|
||||||
|
itemUrl: process.env.ITEM_URL || "",
|
||||||
|
controlUrl: "",
|
||||||
|
recommendationsUrl: "",
|
||||||
|
...(product.extensionsGallery || {}),
|
||||||
|
};
|
||||||
|
|
||||||
const target = vszip as typeof vszip;
|
const target = vszip as typeof vszip;
|
||||||
target.zip = tar;
|
target.zip = tar;
|
||||||
target.extract = extract;
|
target.extract = extract;
|
@ -1,7 +1,6 @@
|
|||||||
import * as path from "path";
|
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
import * as path from "path";
|
||||||
import * as util from "util";
|
import * as util from "util";
|
||||||
|
|
||||||
import { getPathFromAmdModule } from "vs/base/common/amd";
|
import { getPathFromAmdModule } from "vs/base/common/amd";
|
||||||
import * as lp from "vs/base/node/languagePacks";
|
import * as lp from "vs/base/node/languagePacks";
|
||||||
import product from "vs/platform/product/node/product";
|
import product from "vs/platform/product/node/product";
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import * as net from "net";
|
import * as net from "net";
|
||||||
|
|
||||||
import { VSBuffer } from "vs/base/common/buffer";
|
import { VSBuffer } from "vs/base/common/buffer";
|
||||||
import { NodeSocket, WebSocketNodeSocket } from "vs/base/parts/ipc/node/ipc.net";
|
|
||||||
import { PersistentProtocol } from "vs/base/parts/ipc/common/ipc.net";
|
import { PersistentProtocol } from "vs/base/parts/ipc/common/ipc.net";
|
||||||
|
import { NodeSocket, WebSocketNodeSocket } from "vs/base/parts/ipc/node/ipc.net";
|
||||||
import { AuthRequest, ConnectionTypeRequest, HandshakeMessage } from "vs/platform/remote/common/remoteAgentConnection";
|
import { AuthRequest, ConnectionTypeRequest, HandshakeMessage } from "vs/platform/remote/common/remoteAgentConnection";
|
||||||
|
|
||||||
export interface SocketOptions {
|
export interface SocketOptions {
|
||||||
|
@ -4,31 +4,34 @@ import * as http from "http";
|
|||||||
import * as https from "https";
|
import * as https from "https";
|
||||||
import * as net from "net";
|
import * as net from "net";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import * as tls from "tls";
|
|
||||||
import * as util from "util";
|
|
||||||
import * as url from "url";
|
|
||||||
import * as querystring from "querystring";
|
import * as querystring from "querystring";
|
||||||
|
import * as tls from "tls";
|
||||||
|
import * as url from "url";
|
||||||
|
import * as util from "util";
|
||||||
import { Emitter } from "vs/base/common/event";
|
import { Emitter } from "vs/base/common/event";
|
||||||
import { sanitizeFilePath } from "vs/base/common/extpath";
|
import { sanitizeFilePath } from "vs/base/common/extpath";
|
||||||
import { UriComponents, URI } from "vs/base/common/uri";
|
import { Schemas } from "vs/base/common/network";
|
||||||
|
import { URI, UriComponents } from "vs/base/common/uri";
|
||||||
import { generateUuid } from "vs/base/common/uuid";
|
import { generateUuid } from "vs/base/common/uuid";
|
||||||
import { getMachineId } from 'vs/base/node/id';
|
import { getMachineId } from 'vs/base/node/id';
|
||||||
import { NLSConfiguration } from "vs/base/node/languagePacks";
|
import { NLSConfiguration } from "vs/base/node/languagePacks";
|
||||||
import { mkdirp, rimraf } from "vs/base/node/pfs";
|
import { mkdirp, rimraf } from "vs/base/node/pfs";
|
||||||
import { IPCServer, ClientConnectionEvent, StaticRouter } from "vs/base/parts/ipc/common/ipc";
|
import { ClientConnectionEvent, IPCServer, StaticRouter } from "vs/base/parts/ipc/common/ipc";
|
||||||
import { LogsDataCleaner } from "vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner";
|
import { LogsDataCleaner } from "vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner";
|
||||||
import { IConfigurationService } from "vs/platform/configuration/common/configuration";
|
import { IConfigurationService } from "vs/platform/configuration/common/configuration";
|
||||||
import { ConfigurationService } from "vs/platform/configuration/node/configurationService";
|
import { ConfigurationService } from "vs/platform/configuration/node/configurationService";
|
||||||
|
import { ExtensionHostDebugBroadcastChannel } from "vs/platform/debug/common/extensionHostDebugIpc";
|
||||||
import { IDialogService } from "vs/platform/dialogs/common/dialogs";
|
import { IDialogService } from "vs/platform/dialogs/common/dialogs";
|
||||||
import { DialogChannelClient } from "vs/platform/dialogs/node/dialogIpc";
|
import { DialogChannelClient } from "vs/platform/dialogs/node/dialogIpc";
|
||||||
import { IEnvironmentService, ParsedArgs } from "vs/platform/environment/common/environment";
|
import { IEnvironmentService, ParsedArgs } from "vs/platform/environment/common/environment";
|
||||||
import { EnvironmentService } from "vs/platform/environment/node/environmentService";
|
import { EnvironmentService } from "vs/platform/environment/node/environmentService";
|
||||||
import { IExtensionManagementService, IExtensionGalleryService } from "vs/platform/extensionManagement/common/extensionManagement";
|
import { ExtensionGalleryService } from "vs/platform/extensionManagement/common/extensionGalleryService";
|
||||||
import { ExtensionGalleryChannel } from "vs/platform/extensionManagement/node/extensionGalleryIpc";
|
import { IExtensionGalleryService, IExtensionManagementService } from "vs/platform/extensionManagement/common/extensionManagement";
|
||||||
import { ExtensionGalleryService } from "vs/platform/extensionManagement/node/extensionGalleryService";
|
import { ExtensionManagementChannel } from "vs/platform/extensionManagement/common/extensionManagementIpc";
|
||||||
import { ExtensionManagementChannel } from "vs/platform/extensionManagement/node/extensionManagementIpc";
|
|
||||||
import { ExtensionManagementService } from "vs/platform/extensionManagement/node/extensionManagementService";
|
import { ExtensionManagementService } from "vs/platform/extensionManagement/node/extensionManagementService";
|
||||||
|
import { IFileService } from "vs/platform/files/common/files";
|
||||||
|
import { FileService } from "vs/platform/files/common/fileService";
|
||||||
|
import { DiskFileSystemProvider } from "vs/platform/files/node/diskFileSystemProvider";
|
||||||
import { SyncDescriptor } from "vs/platform/instantiation/common/descriptors";
|
import { SyncDescriptor } from "vs/platform/instantiation/common/descriptors";
|
||||||
import { InstantiationService } from "vs/platform/instantiation/common/instantiationService";
|
import { InstantiationService } from "vs/platform/instantiation/common/instantiationService";
|
||||||
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
|
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
|
||||||
@ -38,31 +41,32 @@ import { LocalizationsChannel } from "vs/platform/localizations/node/localizatio
|
|||||||
import { getLogLevel, ILogService } from "vs/platform/log/common/log";
|
import { getLogLevel, ILogService } from "vs/platform/log/common/log";
|
||||||
import { LogLevelSetterChannel } from "vs/platform/log/common/logIpc";
|
import { LogLevelSetterChannel } from "vs/platform/log/common/logIpc";
|
||||||
import { SpdLogService } from "vs/platform/log/node/spdlogService";
|
import { SpdLogService } from "vs/platform/log/node/spdlogService";
|
||||||
import { IProductConfiguration } from "vs/platform/product/common/product";
|
import { IProductConfiguration, IProductService } from "vs/platform/product/common/product";
|
||||||
import pkg from "vs/platform/product/node/package";
|
import pkg from "vs/platform/product/node/package";
|
||||||
import product from "vs/platform/product/node/product";
|
import product from "vs/platform/product/node/product";
|
||||||
|
import { ProductService } from "vs/platform/product/node/productService";
|
||||||
import { ConnectionType, ConnectionTypeRequest } from "vs/platform/remote/common/remoteAgentConnection";
|
import { ConnectionType, ConnectionTypeRequest } from "vs/platform/remote/common/remoteAgentConnection";
|
||||||
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from "vs/platform/remote/common/remoteAgentFileSystemChannel";
|
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from "vs/platform/remote/common/remoteAgentFileSystemChannel";
|
||||||
import { IRequestService } from "vs/platform/request/node/request";
|
import { IRequestService } from "vs/platform/request/common/request";
|
||||||
|
import { RequestChannel } from "vs/platform/request/common/requestIpc";
|
||||||
import { RequestService } from "vs/platform/request/node/requestService";
|
import { RequestService } from "vs/platform/request/node/requestService";
|
||||||
import ErrorTelemetry from "vs/platform/telemetry/browser/errorTelemetry";
|
import ErrorTelemetry from "vs/platform/telemetry/browser/errorTelemetry";
|
||||||
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
|
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
|
||||||
import { NullTelemetryService, LogAppender, combinedAppender } from "vs/platform/telemetry/common/telemetryUtils";
|
import { ITelemetryServiceConfig, TelemetryService } from "vs/platform/telemetry/common/telemetryService";
|
||||||
import { TelemetryService, ITelemetryServiceConfig } from "vs/platform/telemetry/common/telemetryService";
|
import { combinedAppender, LogAppender, NullTelemetryService } from "vs/platform/telemetry/common/telemetryUtils";
|
||||||
import { AppInsightsAppender } from "vs/platform/telemetry/node/appInsightsAppender";
|
import { AppInsightsAppender } from "vs/platform/telemetry/node/appInsightsAppender";
|
||||||
import { resolveCommonProperties } from "vs/platform/telemetry/node/commonProperties";
|
import { resolveCommonProperties } from "vs/platform/telemetry/node/commonProperties";
|
||||||
import { RemoteExtensionLogFileName } from "vs/workbench/services/remote/common/remoteAgentService";
|
|
||||||
import { TelemetryChannel } from "vs/platform/telemetry/node/telemetryIpc";
|
|
||||||
import { UpdateChannel } from "vs/platform/update/node/updateIpc";
|
import { UpdateChannel } from "vs/platform/update/node/updateIpc";
|
||||||
import { IWorkbenchConstructionOptions } from "vs/workbench/workbench.web.api";
|
import { ExtensionEnvironmentChannel, FileProviderChannel } from "vs/server/src/channel";
|
||||||
|
import { Connection, ExtensionHostConnection, ManagementConnection } from "vs/server/src/connection";
|
||||||
import { Connection, ManagementConnection, ExtensionHostConnection } from "vs/server/src/connection";
|
|
||||||
import { ExtensionEnvironmentChannel, FileProviderChannel , } from "vs/server/src/channel";
|
|
||||||
import { TelemetryClient } from "vs/server/src/insights";
|
import { TelemetryClient } from "vs/server/src/insights";
|
||||||
import { getNlsConfiguration, getLocaleFromConfig } from "vs/server/src/nls";
|
import { getLocaleFromConfig, getNlsConfiguration } from "vs/server/src/nls";
|
||||||
import { Protocol } from "vs/server/src/protocol";
|
import { Protocol } from "vs/server/src/protocol";
|
||||||
|
import { TelemetryChannel } from "vs/server/src/telemetry";
|
||||||
import { UpdateService } from "vs/server/src/update";
|
import { UpdateService } from "vs/server/src/update";
|
||||||
import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from "vs/server/src/util";
|
import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from "vs/server/src/util";
|
||||||
|
import { RemoteExtensionLogFileName } from "vs/workbench/services/remote/common/remoteAgentService";
|
||||||
|
import { IWorkbenchConstructionOptions } from "vs/workbench/workbench.web.api";
|
||||||
|
|
||||||
export enum HttpCode {
|
export enum HttpCode {
|
||||||
Ok = 200,
|
Ok = 200,
|
||||||
@ -192,9 +196,9 @@ export abstract class Server {
|
|||||||
try {
|
try {
|
||||||
const payload = await this.preHandleRequest(request);
|
const payload = await this.preHandleRequest(request);
|
||||||
response.writeHead(payload.redirect ? HttpCode.Redirect : payload.code || HttpCode.Ok, {
|
response.writeHead(payload.redirect ? HttpCode.Redirect : payload.code || HttpCode.Ok, {
|
||||||
"Cache-Control": "max-age=86400", // TODO: ETag?
|
|
||||||
"Content-Type": getMediaMime(payload.filePath),
|
"Content-Type": getMediaMime(payload.filePath),
|
||||||
...(payload.redirect ? { Location: this.withBase(request, payload.redirect) } : {}),
|
...(payload.redirect ? { Location: this.withBase(request, payload.redirect) } : {}),
|
||||||
|
...(request.headers["service-worker"] ? { "Service-Worker-Allowed": this.options.basePath + "/" } : {}),
|
||||||
...payload.headers,
|
...payload.headers,
|
||||||
});
|
});
|
||||||
response.end(payload.content);
|
response.end(payload.content);
|
||||||
@ -438,7 +442,7 @@ export class MainServer extends Server {
|
|||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
switch (base) {
|
switch (base) {
|
||||||
case "/": return this.getRoot(request, parsedUrl);
|
case "/": return this.getRoot(request, parsedUrl);
|
||||||
case "/resources": return this.getResource(requestPath);
|
case "/vscode-resources": return this.getResource(requestPath);
|
||||||
case "/webview":
|
case "/webview":
|
||||||
if (requestPath.indexOf("/vscode-resource") === 0) {
|
if (requestPath.indexOf("/vscode-resource") === 0) {
|
||||||
return this.getResource(requestPath.replace(/^\/vscode-resource/, ""));
|
return this.getResource(requestPath.replace(/^\/vscode-resource/, ""));
|
||||||
@ -490,15 +494,19 @@ export class MainServer extends Server {
|
|||||||
NLS_CONFIGURATION: await getNlsConfiguration(locale, environment.userDataPath),
|
NLS_CONFIGURATION: await getNlsConfiguration(locale, environment.userDataPath),
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(options).forEach((key) => {
|
for (const key in options) {
|
||||||
content = content.replace(`"{{${key}}}"`, `'${JSON.stringify(options[key])}'`);
|
content = content.replace(`"{{${key}}}"`, `'${JSON.stringify(options[key as keyof Options])}'`);
|
||||||
});
|
}
|
||||||
content = content.replace('{{WEBVIEW_ENDPOINT}}', webviewEndpoint);
|
content = content.replace('{{WEBVIEW_ENDPOINT}}', webviewEndpoint);
|
||||||
|
|
||||||
return { content, filePath };
|
return { content, filePath };
|
||||||
}
|
}
|
||||||
|
|
||||||
private async connect(message: ConnectionTypeRequest, protocol: Protocol): Promise<void> {
|
private async connect(message: ConnectionTypeRequest, protocol: Protocol): Promise<void> {
|
||||||
|
if (product.commit && message.commit !== product.commit) {
|
||||||
|
throw new Error(`Version mismatch (${message.commit} instead of ${product.commit})`);
|
||||||
|
}
|
||||||
|
|
||||||
switch (message.desiredConnectionType) {
|
switch (message.desiredConnectionType) {
|
||||||
case ConnectionType.ExtensionHost:
|
case ConnectionType.ExtensionHost:
|
||||||
case ConnectionType.Management:
|
case ConnectionType.Management:
|
||||||
@ -552,16 +560,25 @@ export class MainServer extends Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async initializeServices(args: ParsedArgs): Promise<void> {
|
private async initializeServices(args: ParsedArgs): Promise<void> {
|
||||||
const router = new StaticRouter((ctx: any) => ctx.clientId === "renderer");
|
|
||||||
const environmentService = new EnvironmentService(args, process.execPath);
|
const environmentService = new EnvironmentService(args, process.execPath);
|
||||||
const logService = new SpdLogService(RemoteExtensionLogFileName, environmentService.logsPath, getLogLevel(environmentService));
|
const logService = new SpdLogService(RemoteExtensionLogFileName, environmentService.logsPath, getLogLevel(environmentService));
|
||||||
this.ipc.registerChannel("loglevel", new LogLevelSetterChannel(logService));
|
const fileService = new FileService(logService);
|
||||||
|
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(logService));
|
||||||
|
|
||||||
|
this.ipc.registerChannel("loglevel", new LogLevelSetterChannel(logService));
|
||||||
|
this.ipc.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel());
|
||||||
|
|
||||||
|
const router = new StaticRouter((ctx: any) => ctx.clientId === "renderer");
|
||||||
this.services.set(ILogService, logService);
|
this.services.set(ILogService, logService);
|
||||||
this.services.set(IEnvironmentService, environmentService);
|
this.services.set(IEnvironmentService, environmentService);
|
||||||
this.services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.machineSettingsResource]));
|
this.services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.machineSettingsResource]));
|
||||||
this.services.set(IRequestService, new SyncDescriptor(RequestService));
|
this.services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||||
|
this.services.set(IFileService, fileService);
|
||||||
|
this.services.set(IProductService, new SyncDescriptor(ProductService));
|
||||||
|
this.services.set(IDialogService, new DialogChannelClient(this.ipc.getChannel("dialog", router)));
|
||||||
this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
|
this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
|
||||||
|
this.services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
|
||||||
|
|
||||||
if (!environmentService.args["disable-telemetry"]) {
|
if (!environmentService.args["disable-telemetry"]) {
|
||||||
this.services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [{
|
this.services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [{
|
||||||
appender: combinedAppender(
|
appender: combinedAppender(
|
||||||
@ -582,8 +599,6 @@ export class MainServer extends Server {
|
|||||||
} else {
|
} else {
|
||||||
this.services.set(ITelemetryService, NullTelemetryService);
|
this.services.set(ITelemetryService, NullTelemetryService);
|
||||||
}
|
}
|
||||||
this.services.set(IDialogService, new DialogChannelClient(this.ipc.getChannel("dialog", router)));
|
|
||||||
this.services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
|
|
||||||
|
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
const instantiationService = new InstantiationService(this.services);
|
const instantiationService = new InstantiationService(this.services);
|
||||||
@ -592,19 +607,23 @@ export class MainServer extends Server {
|
|||||||
this.ipc.registerChannel("localizations", new LocalizationsChannel(localizationService));
|
this.ipc.registerChannel("localizations", new LocalizationsChannel(localizationService));
|
||||||
instantiationService.invokeFunction(() => {
|
instantiationService.invokeFunction(() => {
|
||||||
instantiationService.createInstance(LogsDataCleaner);
|
instantiationService.createInstance(LogsDataCleaner);
|
||||||
this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, new FileProviderChannel(environmentService, logService));
|
|
||||||
const telemetryService = this.services.get(ITelemetryService) as ITelemetryService;
|
|
||||||
this.ipc.registerChannel("remoteextensionsenvironment", new ExtensionEnvironmentChannel(environmentService, logService, telemetryService));
|
|
||||||
const extensionsService = this.services.get(IExtensionManagementService) as IExtensionManagementService;
|
const extensionsService = this.services.get(IExtensionManagementService) as IExtensionManagementService;
|
||||||
|
const telemetryService = this.services.get(ITelemetryService) as ITelemetryService;
|
||||||
|
|
||||||
const extensionsChannel = new ExtensionManagementChannel(extensionsService, (context) => getUriTransformer(context.remoteAuthority));
|
const extensionsChannel = new ExtensionManagementChannel(extensionsService, (context) => getUriTransformer(context.remoteAuthority));
|
||||||
this.ipc.registerChannel("extensions", extensionsChannel);
|
const extensionsEnvironmentChannel = new ExtensionEnvironmentChannel(environmentService, logService, telemetryService);
|
||||||
const galleryService = this.services.get(IExtensionGalleryService) as IExtensionGalleryService;
|
const fileChannel = new FileProviderChannel(environmentService, logService);
|
||||||
const galleryChannel = new ExtensionGalleryChannel(galleryService);
|
const requestChannel = new RequestChannel(this.services.get(IRequestService) as IRequestService);
|
||||||
this.ipc.registerChannel("gallery", galleryChannel);
|
|
||||||
const telemetryChannel = new TelemetryChannel(telemetryService);
|
const telemetryChannel = new TelemetryChannel(telemetryService);
|
||||||
this.ipc.registerChannel("telemetry", telemetryChannel);
|
|
||||||
const updateChannel = new UpdateChannel(instantiationService.createInstance(UpdateService));
|
const updateChannel = new UpdateChannel(instantiationService.createInstance(UpdateService));
|
||||||
|
|
||||||
|
this.ipc.registerChannel("extensions", extensionsChannel);
|
||||||
|
this.ipc.registerChannel("remoteextensionsenvironment", extensionsEnvironmentChannel);
|
||||||
|
this.ipc.registerChannel("request", requestChannel);
|
||||||
|
this.ipc.registerChannel("telemetry", telemetryChannel);
|
||||||
this.ipc.registerChannel("update", updateChannel);
|
this.ipc.registerChannel("update", updateChannel);
|
||||||
|
this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, fileChannel);
|
||||||
resolve(new ErrorTelemetry(telemetryService));
|
resolve(new ErrorTelemetry(telemetryService));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
49
src/telemetry.ts
Normal file
49
src/telemetry.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { ITelemetryData } from "vs/base/common/actions";
|
||||||
|
import { Event } from "vs/base/common/event";
|
||||||
|
import { IChannel, IServerChannel } from "vs/base/parts/ipc/common/ipc";
|
||||||
|
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from "vs/platform/telemetry/common/gdprTypings";
|
||||||
|
import { ITelemetryInfo, ITelemetryService } from "vs/platform/telemetry/common/telemetry";
|
||||||
|
|
||||||
|
export class TelemetryChannel implements IServerChannel {
|
||||||
|
constructor(private service: ITelemetryService) {}
|
||||||
|
|
||||||
|
listen(_: unknown, event: string): Event<any> {
|
||||||
|
throw new Error(`Invalid listen ${event}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
call(_: unknown, command: string, args?: any): Promise<any> {
|
||||||
|
switch (command) {
|
||||||
|
case "publicLog": return this.service.publicLog(args[0], args[1], args[2]);
|
||||||
|
case "publicLog2": return this.service.publicLog2(args[0], args[1], args[2]);
|
||||||
|
case "setEnabled": return Promise.resolve(this.service.setEnabled(args[0]));
|
||||||
|
case "getTelemetryInfo": return this.service.getTelemetryInfo();
|
||||||
|
}
|
||||||
|
throw new Error(`Invalid call ${command}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TelemetryChannelClient implements ITelemetryService {
|
||||||
|
_serviceBrand: any;
|
||||||
|
|
||||||
|
constructor(private readonly channel: IChannel) {}
|
||||||
|
|
||||||
|
public publicLog(eventName: string, data?: ITelemetryData, anonymizeFilePaths?: boolean): Promise<void> {
|
||||||
|
return this.channel.call("publicLog", [eventName, data, anonymizeFilePaths]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>, anonymizeFilePaths?: boolean): Promise<void> {
|
||||||
|
return this.channel.call("publicLog2", [eventName, data, anonymizeFilePaths]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setEnabled(value: boolean): void {
|
||||||
|
this.channel.call("setEnable", [value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTelemetryInfo(): Promise<ITelemetryInfo> {
|
||||||
|
return this.channel.call("getTelemetryInfo");
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isOptedIn(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -1,23 +1,24 @@
|
|||||||
import * as cp from "child_process";
|
import * as cp from "child_process";
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
import { Stream } from "stream";
|
||||||
import * as util from "util";
|
import * as util from "util";
|
||||||
import * as zlib from 'zlib';
|
import { toVSBufferReadableStream } from "vs/base/common/buffer";
|
||||||
|
|
||||||
import { CancellationToken } from "vs/base/common/cancellation";
|
import { CancellationToken } from "vs/base/common/cancellation";
|
||||||
|
import { URI } from "vs/base/common/uri";
|
||||||
import * as pfs from "vs/base/node/pfs";
|
import * as pfs from "vs/base/node/pfs";
|
||||||
import { asJson, download } from "vs/base/node/request";
|
|
||||||
import { IConfigurationService } from "vs/platform/configuration/common/configuration";
|
import { IConfigurationService } from "vs/platform/configuration/common/configuration";
|
||||||
import { IEnvironmentService } from "vs/platform/environment/common/environment";
|
import { IEnvironmentService } from "vs/platform/environment/common/environment";
|
||||||
|
import { IFileService } from "vs/platform/files/common/files";
|
||||||
import { ILogService } from "vs/platform/log/common/log";
|
import { ILogService } from "vs/platform/log/common/log";
|
||||||
import pkg from "vs/platform/product/node/package";
|
import pkg from "vs/platform/product/node/package";
|
||||||
import { IRequestService } from "vs/platform/request/node/request";
|
import { asJson, IRequestService } from "vs/platform/request/common/request";
|
||||||
import { State, UpdateType, StateType, AvailableForDownload } from "vs/platform/update/common/update";
|
import { AvailableForDownload, State, StateType, UpdateType } from "vs/platform/update/common/update";
|
||||||
import { AbstractUpdateService } from "vs/platform/update/electron-main/abstractUpdateService";
|
import { AbstractUpdateService } from "vs/platform/update/electron-main/abstractUpdateService";
|
||||||
|
|
||||||
import { ipcMain } from "vs/server/src/ipc";
|
import { ipcMain } from "vs/server/src/ipc";
|
||||||
|
import { extract } from "vs/server/src/marketplace";
|
||||||
import { tmpdir } from "vs/server/src/util";
|
import { tmpdir } from "vs/server/src/util";
|
||||||
import { extract } from "vs/server/src/tar";
|
import * as zlib from "zlib";
|
||||||
|
|
||||||
interface IUpdate {
|
interface IUpdate {
|
||||||
name: string;
|
name: string;
|
||||||
@ -30,7 +31,8 @@ export class UpdateService extends AbstractUpdateService {
|
|||||||
@IConfigurationService configurationService: IConfigurationService,
|
@IConfigurationService configurationService: IConfigurationService,
|
||||||
@IEnvironmentService environmentService: IEnvironmentService,
|
@IEnvironmentService environmentService: IEnvironmentService,
|
||||||
@IRequestService requestService: IRequestService,
|
@IRequestService requestService: IRequestService,
|
||||||
@ILogService logService: ILogService
|
@ILogService logService: ILogService,
|
||||||
|
@IFileService private readonly fileService: IFileService,
|
||||||
) {
|
) {
|
||||||
super(null, configurationService, environmentService, requestService, logService);
|
super(null, configurationService, environmentService, requestService, logService);
|
||||||
}
|
}
|
||||||
@ -92,10 +94,13 @@ export class UpdateService extends AbstractUpdateService {
|
|||||||
const context = await this.requestService.request({ url }, CancellationToken.None);
|
const context = await this.requestService.request({ url }, CancellationToken.None);
|
||||||
// Decompress the gzip as we download. If the gzip encoding is set then
|
// Decompress the gzip as we download. If the gzip encoding is set then
|
||||||
// the request service already does this.
|
// the request service already does this.
|
||||||
|
// HACK: This uses knowledge of the internals of the request service.
|
||||||
if (target !== "darwin" && context.res.headers["content-encoding"] !== "gzip") {
|
if (target !== "darwin" && context.res.headers["content-encoding"] !== "gzip") {
|
||||||
context.stream = context.stream.pipe(zlib.createGunzip());
|
const stream = (context.res as any as Stream);
|
||||||
|
stream.removeAllListeners();
|
||||||
|
context.stream = toVSBufferReadableStream(stream.pipe(zlib.createGunzip()));
|
||||||
}
|
}
|
||||||
await download(downloadPath, context);
|
await this.fileService.writeFile(URI.file(downloadPath), context.stream);
|
||||||
await extract(downloadPath, extractPath, undefined, CancellationToken.None);
|
await extract(downloadPath, extractPath, undefined, CancellationToken.None);
|
||||||
const newBinary = path.join(extractPath, releaseName, "code-server");
|
const newBinary = path.join(extractPath, releaseName, "code-server");
|
||||||
if (!pfs.exists(newBinary)) {
|
if (!pfs.exists(newBinary)) {
|
||||||
|
115
src/upload.ts
115
src/upload.ts
@ -1,18 +1,17 @@
|
|||||||
import { generateUuid } from "vs/base/common/uuid";
|
|
||||||
import { DesktopDragAndDropData } from "vs/base/browser/ui/list/listView";
|
import { DesktopDragAndDropData } from "vs/base/browser/ui/list/listView";
|
||||||
import { VSBuffer, VSBufferReadable } from "vs/base/common/buffer";
|
import { VSBuffer, VSBufferReadableStream } from "vs/base/common/buffer";
|
||||||
import { Emitter, Event } from "vs/base/common/event";
|
|
||||||
import { Disposable } from "vs/base/common/lifecycle";
|
import { Disposable } from "vs/base/common/lifecycle";
|
||||||
import * as path from "vs/base/common/path";
|
import * as path from "vs/base/common/path";
|
||||||
import { URI } from "vs/base/common/uri";
|
import { URI } from "vs/base/common/uri";
|
||||||
|
import { generateUuid } from "vs/base/common/uuid";
|
||||||
import { IFileService } from "vs/platform/files/common/files";
|
import { IFileService } from "vs/platform/files/common/files";
|
||||||
import { createDecorator, ServiceIdentifier, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator, IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { INotificationService, Severity } from "vs/platform/notification/common/notification";
|
import { INotificationService, Severity } from "vs/platform/notification/common/notification";
|
||||||
import { IProgress, IProgressStep, IProgressService, ProgressLocation } from "vs/platform/progress/common/progress";
|
import { IProgress, IProgressService, IProgressStep, ProgressLocation } from "vs/platform/progress/common/progress";
|
||||||
|
import { IWindowsService } from "vs/platform/windows/common/windows";
|
||||||
|
import { IWorkspaceContextService } from "vs/platform/workspace/common/workspace";
|
||||||
import { ExplorerItem } from "vs/workbench/contrib/files/common/explorerModel";
|
import { ExplorerItem } from "vs/workbench/contrib/files/common/explorerModel";
|
||||||
import { IEditorGroup } from "vs/workbench/services/editor/common/editorGroupsService";
|
import { IEditorGroup } from "vs/workbench/services/editor/common/editorGroupsService";
|
||||||
import { IWorkspaceContextService } from "vs/platform/workspace/common/workspace";
|
|
||||||
import { IWindowsService } from "vs/platform/windows/common/windows";
|
|
||||||
import { IEditorService } from "vs/workbench/services/editor/common/editorService";
|
import { IEditorService } from "vs/workbench/services/editor/common/editorService";
|
||||||
|
|
||||||
export const IUploadService = createDecorator<IUploadService>("uploadService");
|
export const IUploadService = createDecorator<IUploadService>("uploadService");
|
||||||
@ -208,20 +207,15 @@ class Upload {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
const reader = new Reader(file);
|
const reader = new Reader(file);
|
||||||
reader.onData((data) => {
|
reader.on("data", (data) => {
|
||||||
if (data && data.length > 0) {
|
if (data && data.byteLength > 0) {
|
||||||
this.uploaded += data.byteLength;
|
this.uploaded += data.byteLength;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
reader.onAbort(() => {
|
|
||||||
const remaining = file.size - reader.offset;
|
|
||||||
if (remaining > 0) {
|
|
||||||
this.uploaded += remaining;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.uploadingFiles.set(filePath, reader);
|
this.uploadingFiles.set(filePath, reader);
|
||||||
await this.fileService.writeFile(tempUri, reader);
|
await this.fileService.writeFile(tempUri, reader);
|
||||||
if (reader.aborted) {
|
if (reader.aborted) {
|
||||||
|
this.uploaded += (file.size - reader.offset);
|
||||||
await this.fileService.del(tempUri);
|
await this.fileService.del(tempUri);
|
||||||
} else {
|
} else {
|
||||||
await this.fileService.move(tempUri, uri, true);
|
await this.fileService.move(tempUri, uri, true);
|
||||||
@ -292,17 +286,14 @@ class Upload {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Reader implements VSBufferReadable {
|
class Reader implements VSBufferReadableStream {
|
||||||
private _offset = 0;
|
private _offset = 0;
|
||||||
private readonly size = 32000; // ~32kb max while reading in the file.
|
private readonly size = 32000; // ~32kb max while reading in the file.
|
||||||
private readonly _onData = new Emitter<Uint8Array | null>();
|
|
||||||
public readonly onData: Event<Uint8Array | null> = this._onData.event;
|
|
||||||
|
|
||||||
private _aborted = false;
|
private _aborted = false;
|
||||||
private readonly _onAbort = new Emitter<void>();
|
|
||||||
public readonly onAbort: Event<void> = this._onAbort.event;
|
|
||||||
|
|
||||||
private readonly reader = new FileReader();
|
private readonly reader = new FileReader();
|
||||||
|
private paused = true;
|
||||||
|
private buffer?: VSBuffer;
|
||||||
|
private callbacks = new Map<string, Array<(...args: any[]) => void>>();
|
||||||
|
|
||||||
public constructor(private readonly file: File) {
|
public constructor(private readonly file: File) {
|
||||||
this.reader.addEventListener("load", this.onLoad);
|
this.reader.addEventListener("load", this.onLoad);
|
||||||
@ -311,35 +302,71 @@ class Reader implements VSBufferReadable {
|
|||||||
public get offset(): number { return this._offset; }
|
public get offset(): number { return this._offset; }
|
||||||
public get aborted(): boolean { return this._aborted; }
|
public get aborted(): boolean { return this._aborted; }
|
||||||
|
|
||||||
|
public on(event: "data" | "error" | "end", callback: (...args:any[]) => void): void {
|
||||||
|
if (!this.callbacks.has(event)) {
|
||||||
|
this.callbacks.set(event, []);
|
||||||
|
}
|
||||||
|
this.callbacks.get(event)!.push(callback);
|
||||||
|
if (this.aborted) {
|
||||||
|
return this.emit("error", new Error("stream has been aborted"));
|
||||||
|
} else if (this.done) {
|
||||||
|
return this.emit("error", new Error("stream has ended"));
|
||||||
|
} else if (event === "end") { // Once this is being listened to we can safely start outputting data.
|
||||||
|
this.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public abort = (): void => {
|
public abort = (): void => {
|
||||||
this._aborted = true;
|
this._aborted = true;
|
||||||
this.reader.abort();
|
this.reader.abort();
|
||||||
this.reader.removeEventListener("load", this.onLoad);
|
this.reader.removeEventListener("load", this.onLoad);
|
||||||
this._onAbort.fire();
|
this.emit("end");
|
||||||
}
|
}
|
||||||
|
|
||||||
public read = async (): Promise<VSBuffer | null> => {
|
public pause(): void {
|
||||||
return new Promise<VSBuffer | null>((resolve) => {
|
this.paused = true;
|
||||||
const disposables = [
|
|
||||||
this.onAbort(() => {
|
|
||||||
disposables.forEach((d) => d.dispose());
|
|
||||||
resolve(null);
|
|
||||||
}),
|
|
||||||
this.onData((data) => {
|
|
||||||
disposables.forEach((d) => d.dispose());
|
|
||||||
resolve(data && VSBuffer.wrap(data));
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
if (this.aborted || this.offset >= this.file.size) {
|
|
||||||
return this._onData.fire(null);
|
|
||||||
}
|
|
||||||
const slice = this.file.slice(this.offset, this.offset + this.size);
|
|
||||||
this._offset += this.size;
|
|
||||||
this.reader.readAsArrayBuffer(slice);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private onLoad = () => {
|
public resume(): void {
|
||||||
this._onData.fire(new Uint8Array(this.reader.result as ArrayBuffer));
|
if (this.paused) {
|
||||||
|
this.paused = false;
|
||||||
|
this.readNextChunk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy(): void {
|
||||||
|
this.abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
private onLoad = (): void => {
|
||||||
|
this.buffer = VSBuffer.wrap(new Uint8Array(this.reader.result as ArrayBuffer));
|
||||||
|
if (!this.paused) {
|
||||||
|
this.readNextChunk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readNextChunk(): void {
|
||||||
|
if (this.buffer) {
|
||||||
|
this._offset += this.buffer.byteLength;
|
||||||
|
this.emit("data", this.buffer);
|
||||||
|
this.buffer = undefined;
|
||||||
|
}
|
||||||
|
if (!this.paused) { // Could be paused during the data event.
|
||||||
|
if (this.done) {
|
||||||
|
this.emit("end");
|
||||||
|
} else {
|
||||||
|
this.reader.readAsArrayBuffer(this.file.slice(this.offset, this.offset + this.size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private emit(event: "data" | "error" | "end", ...args: any[]): void {
|
||||||
|
if (this.callbacks.has(event)) {
|
||||||
|
this.callbacks.get(event)!.forEach((cb) => cb(...args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private get done(): boolean {
|
||||||
|
return this.offset >= this.file.size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
src/util.ts
16
src/util.ts
@ -63,12 +63,12 @@ export const generatePassword = async (length: number = 24): Promise<string> =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getMediaMime = (filePath?: string): string => {
|
export const getMediaMime = (filePath?: string): string => {
|
||||||
return filePath && (vsGetMediaMime(filePath) || {
|
return filePath && (vsGetMediaMime(filePath) || (<{[index: string]: string}>{
|
||||||
".css": "text/css",
|
".css": "text/css",
|
||||||
".html": "text/html",
|
".html": "text/html",
|
||||||
".js": "text/javascript",
|
".js": "text/javascript",
|
||||||
".json": "application/json",
|
".json": "application/json",
|
||||||
}[extname(filePath)]) || "text/plain";
|
})[extname(filePath)]) || "text/plain";
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isWsl = async (): Promise<boolean> => {
|
export const isWsl = async (): Promise<boolean> => {
|
||||||
@ -113,8 +113,16 @@ export const unpackExecutables = async (): Promise<void> => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const buildAllowedMessage = (t: typeof AuthType): string => {
|
export const enumToArray = (t: any): string[] => {
|
||||||
const values = <string[]>Object.keys(t).map((k) => t[k]);
|
const values = <string[]>[];
|
||||||
|
for (const k in t) {
|
||||||
|
values.push(t[k]);
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const buildAllowedMessage = (t: any): string => {
|
||||||
|
const values = enumToArray(t);
|
||||||
return `Allowed value${values.length === 1 ? " is" : "s are"} ${values.map((t) => `'${t}'`).join(",")}`;
|
return `Allowed value${values.length === 1 ? " is" : "s are"} ${values.map((t) => `'${t}'`).join(",")}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user