Compare commits
84 Commits
1.408-vsc1
...
1.939-vsc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bc6e1a457 | ||
|
|
e61ea796c6 | ||
|
|
d073622629 | ||
|
|
5f40ebb845 | ||
|
|
c56e2797cc | ||
|
|
166efcb17e | ||
|
|
206e107a9a | ||
|
|
12c8b5d337 | ||
|
|
4aa20fd864 | ||
|
|
0cd4e46055 | ||
|
|
f51823b51f | ||
|
|
55bfeab208 | ||
|
|
309d15cefd | ||
|
|
95006a435a | ||
|
|
4d576ab4d4 | ||
|
|
d5b03ef60e | ||
|
|
c3a38e3fea | ||
|
|
cc8c7e2cee | ||
|
|
e0f1787ce6 | ||
|
|
50e6108012 | ||
|
|
630ccfcacc | ||
|
|
c4c26058ef | ||
|
|
8a4da542ae | ||
|
|
e907dbe7e6 | ||
|
|
22b485acd9 | ||
|
|
b8f222acf2 | ||
|
|
aabb2ecda7 | ||
|
|
dfabc070b9 | ||
|
|
da420cdda9 | ||
|
|
c6a46e4753 | ||
|
|
742dd6f597 | ||
|
|
6c3ff1d6f0 | ||
|
|
db57aa229f | ||
|
|
f7342ede69 | ||
|
|
b781ccde9c | ||
|
|
8f62b2bff2 | ||
|
|
7047be859c | ||
|
|
2785e2219a | ||
|
|
4b217fba00 | ||
|
|
3fae68bbab | ||
|
|
a2f20aa25c | ||
|
|
94b8b9a5cf | ||
|
|
bbd8b27fc7 | ||
|
|
6361635b55 | ||
|
|
d2da4cfc43 | ||
|
|
a1136b3a02 | ||
|
|
4dd74b31b9 | ||
|
|
bc0f6eb65d | ||
|
|
6737d3da18 | ||
|
|
eb0f773146 | ||
|
|
ebac84899e | ||
|
|
0b7a090a73 | ||
|
|
a95019f38d | ||
|
|
15948c1af6 | ||
|
|
e73eb74208 | ||
|
|
278c59b920 | ||
|
|
5a1eb858a9 | ||
|
|
3c1dfb1170 | ||
|
|
09a02eb9e9 | ||
|
|
2bd7281fa0 | ||
|
|
e12fcd3a0d | ||
|
|
4af84fcaf6 | ||
|
|
c607015a26 | ||
|
|
217515344e | ||
|
|
dcf409aecb | ||
|
|
2683b7c734 | ||
|
|
3a672d725a | ||
|
|
f484781693 | ||
|
|
97f5b07003 | ||
|
|
7481395353 | ||
|
|
033ef151ca | ||
|
|
3fec7f432c | ||
|
|
4887078423 | ||
|
|
91deaece47 | ||
|
|
03ad2a17b2 | ||
|
|
a4cca6b759 | ||
|
|
6105bba0a4 | ||
|
|
259095eae2 | ||
|
|
38a0706b18 | ||
|
|
c7ae12c2ed | ||
|
|
3331f9b28d | ||
|
|
def4104c53 | ||
|
|
4eb5331ddc | ||
|
|
3bb5c0bbe5 |
@@ -7,3 +7,4 @@ doc/
|
||||
.travis.yml
|
||||
LICENSE
|
||||
README.md
|
||||
node_modules
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,6 +1,8 @@
|
||||
lib
|
||||
/lib
|
||||
node_modules
|
||||
dist
|
||||
out
|
||||
.DS_Store
|
||||
release
|
||||
.vscode
|
||||
.cache
|
||||
|
||||
1
.node-version
Normal file
1
.node-version
Normal file
@@ -0,0 +1 @@
|
||||
10.15.1
|
||||
13
.travis.yml
13
.travis.yml
@@ -1,16 +1,17 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 8.15.0
|
||||
- 10.15.1
|
||||
env:
|
||||
- VSCODE_VERSION="1.32.0" MAJOR_VERSION="1" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER-vsc$VSCODE_VERSION"
|
||||
- VSCODE_VERSION="1.33.1" MAJOR_VERSION="1" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER-vsc$VSCODE_VERSION"
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: ubuntu
|
||||
dist: trusty
|
||||
- os: osx
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libxkbfile-dev
|
||||
libsecret-1-dev; fi
|
||||
- npm install -g yarn@1.12.3
|
||||
script:
|
||||
- scripts/build.sh
|
||||
before_deploy:
|
||||
@@ -35,4 +36,8 @@ deploy:
|
||||
on:
|
||||
repo: codercom/code-server
|
||||
branch: master
|
||||
cache: yarn
|
||||
cache:
|
||||
yarn: true
|
||||
timeout: 1000
|
||||
directories:
|
||||
- .cache
|
||||
|
||||
39
Dockerfile
39
Dockerfile
@@ -1,4 +1,4 @@
|
||||
FROM node:8.15.0
|
||||
FROM node:10.15.1
|
||||
|
||||
# Install VS Code's deps. These are the only two it seems we need.
|
||||
RUN apt-get update && apt-get install -y \
|
||||
@@ -13,21 +13,42 @@ COPY . .
|
||||
|
||||
# In the future, we can use https://github.com/yarnpkg/rfcs/pull/53 to make yarn use the node_modules
|
||||
# directly which should be fast as it is slow because it populates its own cache every time.
|
||||
RUN yarn && yarn task build:server:binary
|
||||
RUN yarn && NODE_ENV=production yarn task build:server:binary
|
||||
|
||||
# We deploy with ubuntu so that devs have a familiar environment.
|
||||
FROM ubuntu:18.10
|
||||
WORKDIR /root/project
|
||||
COPY --from=0 /src/packages/server/cli-linux-x64 /usr/local/bin/code-server
|
||||
EXPOSE 8443
|
||||
FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
openssl \
|
||||
net-tools \
|
||||
git \
|
||||
locales
|
||||
locales \
|
||||
sudo \
|
||||
dumb-init \
|
||||
vim \
|
||||
curl \
|
||||
wget
|
||||
|
||||
RUN locale-gen en_US.UTF-8
|
||||
# We unfortunately cannot use update-locale because docker will not use the env variables
|
||||
# configured in /etc/default/locale so we need to set it manually.
|
||||
ENV LANG=en_US.UTF-8
|
||||
ENTRYPOINT ["code-server"]
|
||||
ENV LC_ALL=en_US.UTF-8
|
||||
|
||||
RUN adduser --gecos '' --disabled-password coder && \
|
||||
echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
|
||||
|
||||
USER coder
|
||||
# We create first instead of just using WORKDIR as when WORKDIR creates, the user is root.
|
||||
RUN mkdir -p /home/coder/project && \
|
||||
chmod g+rw /home/coder/project;
|
||||
|
||||
WORKDIR /home/coder/project
|
||||
|
||||
# This assures we have a volume mounted even if the user forgot to do bind mount.
|
||||
# XXX: Workaround for GH-459 and for OpenShift compatibility.
|
||||
VOLUME [ "/home/coder/project" ]
|
||||
|
||||
COPY --from=0 /src/packages/server/cli-linux-x64 /usr/local/bin/code-server
|
||||
EXPOSE 8443
|
||||
|
||||
ENTRYPOINT ["dumb-init", "code-server"]
|
||||
|
||||
23
README.md
23
README.md
@@ -2,14 +2,14 @@
|
||||
|
||||
[](https://github.com/codercom/code-server/issues)
|
||||
[](https://github.com/codercom/code-server/releases/latest)
|
||||
[](#)
|
||||
[](https://discord.gg/zxSwN8Z)
|
||||
[](https://github.com/codercom/code-server/blob/master/LICENSE)
|
||||
[](https://discord.gg/zxSwN8Z)
|
||||
|
||||
`code-server` is [VS Code](https://github.com/Microsoft/vscode) running on a remote server, accessible through the browser.
|
||||
|
||||
Try it out:
|
||||
```bash
|
||||
docker run -t -p 127.0.0.1:8443:8443 -v "${PWD}:/root/project" codercom/code-server code-server --allow-http --no-auth
|
||||
docker run -it -p 127.0.0.1:8443:8443 -v "${PWD}:/home/coder/project" codercom/code-server --allow-http --no-auth
|
||||
```
|
||||
|
||||
- Code on your Chromebook, tablet, and laptop with a consistent dev environment.
|
||||
@@ -23,9 +23,9 @@ docker run -t -p 127.0.0.1:8443:8443 -v "${PWD}:/root/project" codercom/code-ser
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Hosted
|
||||
### Run over SSH
|
||||
|
||||
[Try `code-server` now](https://coder.com/signup) for free at coder.com.
|
||||
Use [sshcode](https://github.com/codercom/sshcode) for a simple setup.
|
||||
|
||||
### Docker
|
||||
|
||||
@@ -57,14 +57,21 @@ How to [secure your setup](/doc/security/ssl.md).
|
||||
- Creating custom VS Code extensions and debugging them doesn't work.
|
||||
|
||||
### Future
|
||||
|
||||
- **Stay up to date!** Get notified about new releases of code-server.
|
||||

|
||||
- Windows support.
|
||||
- Electron and Chrome OS applications to bridge the gap between local<->remote.
|
||||
- Run VS Code unit tests against our builds to ensure features work as expected.
|
||||
|
||||
### Notes
|
||||
### Extensions
|
||||
|
||||
- At the moment we can't use the official VSCode Marketplace. We've created a custom extension marketplace focused around open-sourced extensions. However, if you have access to the `.vsix` file, you can manually install the extension.
|
||||
At the moment we can't use the official VSCode Marketplace. We've created a custom extension marketplace focused around open-sourced extensions. However, if you have access to the `.vsix` file, you can manually install the extension.
|
||||
|
||||
## Telemetry
|
||||
|
||||
Use the `--disable-telemetry` flag or set `DISABLE_TELEMETRY=true` to disable tracking ENTIRELY.
|
||||
|
||||
We use data collected to improve code-server.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
140
build/tasks.ts
140
build/tasks.ts
@@ -4,21 +4,22 @@ import * as fse from "fs-extra";
|
||||
import * as os from "os";
|
||||
import * as path from "path";
|
||||
import * as zlib from "zlib";
|
||||
import * as https from "https";
|
||||
import * as tar from "tar";
|
||||
|
||||
const isWin = os.platform() === "win32";
|
||||
const libPath = path.join(__dirname, "../lib");
|
||||
const vscodePath = path.join(libPath, "vscode");
|
||||
const defaultExtensionsPath = path.join(libPath, "extensions");
|
||||
const pkgsPath = path.join(__dirname, "../packages");
|
||||
const defaultExtensionsPath = path.join(libPath, "VSCode-linux-x64/resources/app/extensions");
|
||||
const vscodeVersion = process.env.VSCODE_VERSION || "1.32.0";
|
||||
const vscodeVersion = process.env.VSCODE_VERSION || "1.33.1";
|
||||
const vsSourceUrl = `https://codesrv-ci.cdr.sh/vstar-${vscodeVersion}.tar.gz`;
|
||||
|
||||
const buildServerBinary = register("build:server:binary", async (runner) => {
|
||||
await ensureInstalled();
|
||||
await copyForDefaultExtensions();
|
||||
await Promise.all([
|
||||
buildBootstrapFork(),
|
||||
buildWeb(),
|
||||
buildDefaultExtensions(),
|
||||
buildServerBundle(),
|
||||
buildAppBrowser(),
|
||||
]);
|
||||
@@ -47,19 +48,11 @@ const buildServerBinaryCopy = register("build:server:binary:copy", async (runner
|
||||
const bootstrapForkPath = path.join(pkgsPath, "vscode", "out", "bootstrap-fork.js");
|
||||
const webOutputPath = path.join(pkgsPath, "web", "out");
|
||||
const browserAppOutputPath = path.join(pkgsPath, "app", "browser", "out");
|
||||
const nodePtyModule = path.join(pkgsPath, "protocol", "node_modules", "node-pty-prebuilt", "build", "Release", "pty.node");
|
||||
const spdlogModule = path.join(pkgsPath, "protocol", "node_modules", "spdlog", "build", "Release", "spdlog.node");
|
||||
let ripgrepPath = path.join(pkgsPath, "..", "lib", "vscode", "node_modules", "vscode-ripgrep", "bin", "rg");
|
||||
if (isWin) {
|
||||
ripgrepPath += ".exe";
|
||||
}
|
||||
|
||||
if (!fs.existsSync(nodePtyModule)) {
|
||||
throw new Error("Could not find pty.node. Ensure all packages have been installed");
|
||||
}
|
||||
if (!fs.existsSync(spdlogModule)) {
|
||||
throw new Error("Could not find spdlog.node. Ensure all packages have been installed");
|
||||
}
|
||||
if (!fs.existsSync(webOutputPath)) {
|
||||
throw new Error("Web bundle must be built");
|
||||
}
|
||||
@@ -74,24 +67,22 @@ const buildServerBinaryCopy = register("build:server:binary:copy", async (runner
|
||||
}
|
||||
fse.copySync(defaultExtensionsPath, path.join(cliBuildPath, "extensions"));
|
||||
fs.writeFileSync(path.join(cliBuildPath, "bootstrap-fork.js.gz"), zlib.gzipSync(fs.readFileSync(bootstrapForkPath)));
|
||||
const cpDir = (dir: string, subdir: "auth" | "unauth", rootPath: string): void => {
|
||||
const cpDir = (dir: string, rootPath: string, subdir?: "login"): void => {
|
||||
const stat = fs.statSync(dir);
|
||||
if (stat.isDirectory()) {
|
||||
const paths = fs.readdirSync(dir);
|
||||
paths.forEach((p) => cpDir(path.join(dir, p), subdir, rootPath));
|
||||
paths.forEach((p) => cpDir(path.join(dir, p), rootPath, subdir));
|
||||
} else if (stat.isFile()) {
|
||||
const newPath = path.join(cliBuildPath, "web", subdir, path.relative(rootPath, dir));
|
||||
const newPath = path.join(cliBuildPath, "web", subdir || "", path.relative(rootPath, dir));
|
||||
fse.mkdirpSync(path.dirname(newPath));
|
||||
fs.writeFileSync(newPath + ".gz", zlib.gzipSync(fs.readFileSync(dir)));
|
||||
} else {
|
||||
// Nothing
|
||||
}
|
||||
};
|
||||
cpDir(webOutputPath, "auth", webOutputPath);
|
||||
cpDir(browserAppOutputPath, "unauth", browserAppOutputPath);
|
||||
cpDir(webOutputPath, webOutputPath);
|
||||
cpDir(browserAppOutputPath, browserAppOutputPath, "login");
|
||||
fse.mkdirpSync(path.join(cliBuildPath, "dependencies"));
|
||||
fse.copySync(nodePtyModule, path.join(cliBuildPath, "dependencies", "pty.node"));
|
||||
fse.copySync(spdlogModule, path.join(cliBuildPath, "dependencies", "spdlog.node"));
|
||||
fse.copySync(ripgrepPath, path.join(cliBuildPath, "dependencies", "rg"));
|
||||
});
|
||||
|
||||
@@ -129,97 +120,50 @@ const buildWeb = register("build:web", async (runner) => {
|
||||
await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build"]);
|
||||
});
|
||||
|
||||
const extDirPath = path.join("lib", "vscode-default-extensions");
|
||||
const copyForDefaultExtensions = register("build:copy-vscode", async (runner) => {
|
||||
if (!fs.existsSync(defaultExtensionsPath)) {
|
||||
await ensureClean();
|
||||
await ensureInstalled();
|
||||
await new Promise((resolve, reject): void => {
|
||||
fse.remove(extDirPath, (err) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
await new Promise((resolve, reject): void => {
|
||||
fse.copy(vscodePath, extDirPath, (err) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const buildDefaultExtensions = register("build:default-extensions", async (runner) => {
|
||||
if (!fs.existsSync(defaultExtensionsPath)) {
|
||||
await copyForDefaultExtensions();
|
||||
runner.cwd = extDirPath;
|
||||
const resp = await runner.execute(isWin ? "npx.cmd" : "npx", [isWin ? "gulp.cmd" : "gulp", "vscode-linux-x64", "--max-old-space-size=32384"]);
|
||||
if (resp.exitCode !== 0) {
|
||||
throw new Error(`Failed to build default extensions: ${resp.stderr}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const ensureInstalled = register("vscode:install", async (runner) => {
|
||||
await ensureCloned();
|
||||
runner.cwd = libPath;
|
||||
|
||||
runner.cwd = vscodePath;
|
||||
const install = await runner.execute(isWin ? "yarn.cmd" : "yarn", []);
|
||||
if (install.exitCode !== 0) {
|
||||
throw new Error(`Failed to install vscode dependencies: ${install.stderr}`);
|
||||
}
|
||||
});
|
||||
if (fs.existsSync(vscodePath) && fs.existsSync(defaultExtensionsPath)) {
|
||||
const pkgVersion = JSON.parse(fs.readFileSync(path.join(vscodePath, "package.json")).toString("utf8")).version;
|
||||
if (pkgVersion === vscodeVersion) {
|
||||
runner.cwd = vscodePath;
|
||||
|
||||
const ensureCloned = register("vscode:clone", async (runner) => {
|
||||
if (fs.existsSync(vscodePath)) {
|
||||
await ensureClean();
|
||||
} else {
|
||||
fse.mkdirpSync(libPath);
|
||||
runner.cwd = libPath;
|
||||
const clone = await runner.execute("git", ["clone", "https://github.com/microsoft/vscode", "--branch", vscodeVersion, "--single-branch", "--depth=1"]);
|
||||
if (clone.exitCode !== 0) {
|
||||
throw new Error(`Failed to clone: ${clone.exitCode}`);
|
||||
const reset = await runner.execute("git", ["reset", "--hard"]);
|
||||
if (reset.exitCode !== 0) {
|
||||
throw new Error(`Failed to clean git repository: ${reset.stderr}`);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
runner.cwd = vscodePath;
|
||||
const checkout = await runner.execute("git", ["checkout", vscodeVersion]);
|
||||
if (checkout.exitCode !== 0) {
|
||||
throw new Error(`Failed to checkout: ${checkout.stderr}`);
|
||||
}
|
||||
});
|
||||
fse.removeSync(libPath);
|
||||
fse.mkdirpSync(libPath);
|
||||
|
||||
const ensureClean = register("vscode:clean", async (runner) => {
|
||||
runner.cwd = vscodePath;
|
||||
await new Promise<void>((resolve, reject): void => {
|
||||
https.get(vsSourceUrl, (res) => {
|
||||
if (res.statusCode !== 200) {
|
||||
return reject(res.statusMessage);
|
||||
}
|
||||
|
||||
const status = await runner.execute("git", ["status", "--porcelain"]);
|
||||
if (status.stdout.trim() !== "") {
|
||||
const clean = await runner.execute("git", ["clean", "-f", "-d", "-X"]);
|
||||
if (clean.exitCode !== 0) {
|
||||
throw new Error(`Failed to clean git repository: ${clean.stderr}`);
|
||||
}
|
||||
const removeUnstaged = await runner.execute("git", ["checkout", "--", "."]);
|
||||
if (removeUnstaged.exitCode !== 0) {
|
||||
throw new Error(`Failed to remove unstaged files: ${removeUnstaged.stderr}`);
|
||||
}
|
||||
}
|
||||
const fetch = await runner.execute("git", ["fetch", "--prune"]);
|
||||
if (fetch.exitCode !== 0) {
|
||||
throw new Error(`Failed to fetch latest changes: ${fetch.stderr}`);
|
||||
}
|
||||
res.pipe(tar.x({
|
||||
C: libPath,
|
||||
}).on("finish", () => {
|
||||
resolve();
|
||||
}).on("error", (err: Error) => {
|
||||
reject(err);
|
||||
}));
|
||||
}).on("error", (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const ensurePatched = register("vscode:patch", async (runner) => {
|
||||
if (!fs.existsSync(vscodePath)) {
|
||||
throw new Error("vscode must be cloned to patch");
|
||||
}
|
||||
await ensureClean();
|
||||
await ensureInstalled();
|
||||
|
||||
runner.cwd = vscodePath;
|
||||
const patchPath = path.join(__dirname, "../scripts/vscode.patch");
|
||||
@@ -250,9 +194,9 @@ register("package", async (runner, releaseTag) => {
|
||||
});
|
||||
|
||||
runner.cwd = releasePath;
|
||||
await os.platform() === "linux"
|
||||
await (os.platform() === "linux"
|
||||
? runner.execute("tar", ["-cvzf", `${archiveName}.tar.gz`, `${archiveName}`])
|
||||
: runner.execute("zip", ["-r", `${archiveName}.zip`, `${archiveName}`]);
|
||||
: runner.execute("zip", ["-r", `${archiveName}.zip`, `${archiveName}`]));
|
||||
});
|
||||
|
||||
run();
|
||||
|
||||
@@ -56,7 +56,7 @@ If you're just starting out, we recommend [installing code-server locally](../..
|
||||
> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../../security/ssl.md)
|
||||
- Finally, run
|
||||
```
|
||||
sudo ./code-server-linux -p 80
|
||||
sudo ./code-server -p 80
|
||||
```
|
||||
- When you visit the public IP for your AWS instance, you will be greeted with this page. Code-server is using a self-signed SSL certificate for easy setup. To proceed to the IDE, click **"Advanced"**<img src ="../../assets/chrome_warning.png">
|
||||
- Then click **"proceed anyway"**<img src="../../assets/chrome_confirm.png">
|
||||
|
||||
@@ -39,7 +39,7 @@ If you're just starting out, we recommend [installing code-server locally](../..
|
||||
> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../../security/ssl.md)
|
||||
- Finally start the code-server
|
||||
```
|
||||
sudo ./code-server-linux -p 80
|
||||
sudo ./code-server -p 80
|
||||
```
|
||||
> For instructions on how to keep the server running after you end your SSH session please checkout [how to use systemd](https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/) to start linux based services if they are killed
|
||||
- When you visit the public IP for your Digital Ocean instance, you will be greeted with this page. Code-server is using a self-signed SSL certificate for easy setup. To proceed to the IDE, click **"Advanced"**<img src ="../../assets/chrome_warning.png">
|
||||
|
||||
@@ -54,7 +54,7 @@ chmod +x code-server
|
||||
|
||||
- Start the code-server
|
||||
```
|
||||
sudo ./code-server-linux -p 80
|
||||
sudo ./code-server -p 80
|
||||
```
|
||||
|
||||
> For instructions on how to keep the server running after you end your SSH session please checkout [how to use systemd](https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/) to start linux based services if they are killed
|
||||
|
||||
BIN
doc/assets/release.gif
Normal file
BIN
doc/assets/release.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
@@ -6,7 +6,7 @@
|
||||
|
||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/codercom/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
||||
|
||||
This document pertains to Coder specific implementations of VS Code. For documentation on how to use VS Code itself, please refer to the official [documentation for VS Code](https://code.visualstudio.com/docs)
|
||||
This document pertains to Coder specific implementations of VS Code. For documentation on how to use VS Code itself, please refer to the official [documentation for VS Code](https://code.visualstudio.com/docs)
|
||||
|
||||
It takes just a few minutes to get your own self-hosted server running. If you've got a machine running macOS, Windows, or Linux, you're ready to start the binary which listens on port `8443` by default.
|
||||
|
||||
@@ -34,43 +34,48 @@ It takes just a few minutes to get your own self-hosted server running. If you'v
|
||||
code-server can be ran with a number of arguments to customize your working directory, host, port, and SSL certificate.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ code-server [WORKDIR]
|
||||
Usage: code-server [options]
|
||||
|
||||
ARGUMENTS
|
||||
WORKDIR [default: (directory to binary)] Specify working dir
|
||||
Run VS Code on a remote server.
|
||||
|
||||
OPTIONS
|
||||
-d, --data-dir=data-dir
|
||||
-h, --host=host [default: 0.0.0.0]
|
||||
-o, --open Open in browser on startup
|
||||
-p, --port=port [default: 8443] Port to bind on
|
||||
-v, --version show CLI version
|
||||
--allow-http
|
||||
--cert=cert
|
||||
--cert-key=cert-key
|
||||
--help show CLI help
|
||||
--no-auth
|
||||
--password=password
|
||||
Options:
|
||||
-V, --version output the version number
|
||||
--cert <value>
|
||||
--cert-key <value>
|
||||
-e, --extensions-dir <dir> Set the root path for extensions.
|
||||
-d --user-data-dir <dir> Specifies the directory that user data is kept in, useful when running as root.
|
||||
--data-dir <value> DEPRECATED: Use '--user-data-dir' instead. Customize where user-data is stored.
|
||||
-h, --host <value> Customize the hostname. (default: "0.0.0.0")
|
||||
-o, --open Open in the browser on startup.
|
||||
-p, --port <number> Port to bind on. (default: 8443)
|
||||
-N, --no-auth Start without requiring authentication.
|
||||
-H, --allow-http Allow http connections.
|
||||
-P, --password <value> Specify a password for authentication.
|
||||
--disable-telemetry Disables ALL telemetry.
|
||||
--help output usage information
|
||||
```
|
||||
|
||||
### Data Directory
|
||||
Use `code-server -d (path/to/directory)` or `code-server --data-dir=(path/to/directory)`, excluding the parentheses to specify the root folder that VS Code will start in
|
||||
Use `code-server -d (path/to/directory)` or `code-server --data-dir=(path/to/directory)`, excluding the parentheses to specify the root folder that VS Code will start in.
|
||||
|
||||
### Host
|
||||
By default, code-server will use `0.0.0.0` as its address. This can be changed by using `code-server -h` or `code-server --host=` followed by the address you want to use.
|
||||
By default, code-server will use `0.0.0.0` as its address. This can be changed by using `code-server -h` or `code-server --host=` followed by the address you want to use.
|
||||
> Example: `code-server -h 127.0.0.1`
|
||||
|
||||
### Open
|
||||
You can have the server automatically open the VS Code in your browser on startup by using the `code server -o` or `code-server --open` flags
|
||||
You can have the server automatically open the VS Code in your browser on startup by using the `code-server -o` or `code-server --open` flags
|
||||
|
||||
### Port
|
||||
By default, code-server will use `8443` as its port. This can be changed by using `code-server -p` or `code-server --port=` followed by the port you want to use.
|
||||
### Port
|
||||
By default, code-server will use `8443` as its port. This can be changed by using `code-server -p` or `code-server --port=` followed by the port you want to use.
|
||||
> Example: `code-server -p 9000`
|
||||
|
||||
### Telemetry
|
||||
Disable all telemetry with `code-server --disable-telemetry`.
|
||||
|
||||
### Cert and Cert Key
|
||||
To encrypt the traffic between the browser and server use `code-server --cert=` followed by the path to your `.cer` file. Additionally, you can use certificate keys with `code-server --cert-key` followed by the path to your `.key` file.
|
||||
> Example (certificate and key): `code-server --cert /etc/letsencrypt/live/example.com/fullchain.cer --cert-key /etc/letsencrypt/live/example.com/fullchain.key`
|
||||
> Example (if you are using Letsencrypt or similar): `code-server --cert /etc/letsencrypt/live/example.com/fullchain.pem --cert-key /etc/letsencrypt/live/example.com/privkey.key`
|
||||
|
||||
> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../security/ssl.md)
|
||||
|
||||
@@ -115,4 +120,4 @@ OPTIONS
|
||||
*Important:* For more details about Apache reverse proxy configuration checkout the [documentation](https://httpd.apache.org/docs/current/mod/mod_proxy.html) - especially the [Securing your Server](https://httpd.apache.org/docs/current/mod/mod_proxy.html#access) section
|
||||
|
||||
### Help
|
||||
Use `code-server -h` or `code-server --help` to view the usage for the cli. This is also shown at the beginning of this section.
|
||||
Use `code-server --help` to view the usage for the CLI. This is also shown at the beginning of this section.
|
||||
|
||||
12
package.json
12
package.json
@@ -15,7 +15,9 @@
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^5.0.4",
|
||||
"@types/node": "^10.12.18",
|
||||
"@types/tar": "^4.0.0",
|
||||
"@types/trash": "^4.3.1",
|
||||
"cache-loader": "^2.0.1",
|
||||
"cross-env": "^5.2.0",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^2.1.0",
|
||||
@@ -34,6 +36,8 @@
|
||||
"sass-loader": "^7.1.0",
|
||||
"string-replace-loader": "^2.1.1",
|
||||
"style-loader": "^0.23.1",
|
||||
"tar": "^4.4.8",
|
||||
"terser-webpack-plugin": "^1.2.3",
|
||||
"ts-loader": "^5.3.3",
|
||||
"ts-node": "^7.0.1",
|
||||
"tsconfig-paths": "^3.8.0",
|
||||
@@ -42,6 +46,7 @@
|
||||
"typescript": "^3.2.2",
|
||||
"typescript-tslint-plugin": "^0.2.1",
|
||||
"uglifyjs-webpack-plugin": "^2.1.1",
|
||||
"url-loader": "^1.1.2",
|
||||
"util": "^0.11.1",
|
||||
"webpack": "^4.28.4",
|
||||
"webpack-bundle-analyzer": "^3.0.3",
|
||||
@@ -49,10 +54,17 @@
|
||||
"webpack-dev-middleware": "^3.5.0",
|
||||
"webpack-dev-server": "^3.1.14",
|
||||
"webpack-hot-middleware": "^2.24.3",
|
||||
"webpack-pwa-manifest": "^4.0.0",
|
||||
"workbox-webpack-plugin": "^4.1.0",
|
||||
"write-file-webpack-plugin": "^4.5.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"bindings": "1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-loader": "^0.6.0",
|
||||
"node-pty": "0.8.1",
|
||||
"spdlog": "0.8.1",
|
||||
"webpack-merge": "^4.2.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,22 +7,24 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="login">
|
||||
<div class="back"> <- Back </div>
|
||||
<h4 class="title">code-server</h4>
|
||||
<h2 class="subtitle">
|
||||
Enter server password
|
||||
</h2>
|
||||
<div class="mdc-text-field">
|
||||
<input type="password" id="password" class="mdc-text-field__input" required>
|
||||
<label class="mdc-floating-label" for="password">Password</label>
|
||||
<div class="mdc-line-ripple"></div>
|
||||
</div>
|
||||
<button id="submit" class="mdc-button mdc-button--unelevated">
|
||||
<span class="mdc-button__label">Enter IDE</span>
|
||||
</button>
|
||||
<div id="error-display"></div>
|
||||
</div>
|
||||
<form id="login-form">
|
||||
<div class="login">
|
||||
<div class="back">
|
||||
<- Back </div> <h4 class="title">code-server</h4>
|
||||
<h2 class="subtitle">
|
||||
Enter server password
|
||||
</h2>
|
||||
<div class="mdc-text-field">
|
||||
<input type="password" id="password" class="mdc-text-field__input" required>
|
||||
<label class="mdc-floating-label" for="password">Password</label>
|
||||
<div class="mdc-line-ripple"></div>
|
||||
</div>
|
||||
<button id="submit" class="mdc-button mdc-button--unelevated">
|
||||
<span class="mdc-button__label">Enter IDE</span>
|
||||
</button>
|
||||
<div id="error-display"></div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -20,12 +20,17 @@ window.addEventListener("message", (event) => {
|
||||
});
|
||||
|
||||
const password = document.getElementById("password") as HTMLInputElement;
|
||||
const submit = document.getElementById("submit") as HTMLButtonElement;
|
||||
if (!submit) {
|
||||
throw new Error("No submit button found");
|
||||
const form = document.getElementById("login-form") as HTMLFormElement;
|
||||
|
||||
if (!form) {
|
||||
throw new Error("No password form found");
|
||||
}
|
||||
submit.addEventListener("click", () => {
|
||||
document.cookie = `password=${password.value}`;
|
||||
|
||||
form.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
document.cookie = `password=${password.value}; `
|
||||
+ `path=${location.pathname.replace(/\/login\/?$/, "/")}; `
|
||||
+ `domain=${location.hostname}`;
|
||||
location.reload();
|
||||
});
|
||||
|
||||
@@ -38,4 +43,4 @@ const errorDisplay = document.getElementById("error-display") as HTMLDivElement;
|
||||
|
||||
if (document.referrer === document.location.href && matches) {
|
||||
errorDisplay.innerText = "Password is incorrect!";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,10 @@ const root = path.resolve(__dirname, "../../..");
|
||||
|
||||
module.exports = merge(
|
||||
require(path.join(root, "scripts/webpack.client.config.js"))({
|
||||
entry: path.join(root, "packages/app/browser/src/app.ts"),
|
||||
template: path.join(root, "packages/app/browser/src/app.html"),
|
||||
dirname: __dirname,
|
||||
entry: path.join(__dirname, "src/app.ts"),
|
||||
name: "login",
|
||||
template: path.join(__dirname, "src/app.html"),
|
||||
}), {
|
||||
output: {
|
||||
path: path.join(__dirname, "out"),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -5,15 +5,12 @@ const root = path.resolve(__dirname, "../..");
|
||||
|
||||
module.exports = merge(
|
||||
require(path.join(root, "scripts/webpack.node.config.js"))({
|
||||
// Options.
|
||||
dirname: __dirname,
|
||||
name: "dns",
|
||||
}), {
|
||||
externals: {
|
||||
"node-named": "commonjs node-named",
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, "out"),
|
||||
filename: "main.js",
|
||||
},
|
||||
entry: [
|
||||
"./packages/dns/src/dns.ts"
|
||||
],
|
||||
|
||||
5
packages/ide-api/api.d.ts
vendored
5
packages/ide-api/api.d.ts
vendored
@@ -136,12 +136,17 @@ interface ICommandRegistry {
|
||||
registerCommand(command: ICommand): IDisposable;
|
||||
}
|
||||
|
||||
interface IStorageService {
|
||||
save(): Promise<void>;
|
||||
}
|
||||
|
||||
declare namespace ide {
|
||||
export const client: {};
|
||||
|
||||
export const workbench: {
|
||||
readonly statusbarService: IStatusbarService;
|
||||
readonly notificationService: INotificationService;
|
||||
readonly storageService: IStorageService;
|
||||
readonly menuRegistry: IMenuRegistry;
|
||||
readonly commandRegistry: ICommandRegistry;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coder/ide-api",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"typings": "api.d.ts",
|
||||
"author": "Coder",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -34,6 +34,12 @@ export abstract class IdeClient {
|
||||
this.loadTime = time(2500);
|
||||
|
||||
let appWindow: Window | undefined;
|
||||
|
||||
window.addEventListener("beforeunload", (e) => {
|
||||
e.preventDefault(); // FireFox
|
||||
e.returnValue = ""; // Chrome
|
||||
});
|
||||
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.data === "app") {
|
||||
appWindow = event.source as Window;
|
||||
@@ -41,7 +47,16 @@ export abstract class IdeClient {
|
||||
});
|
||||
|
||||
this.sharedProcessData = new Promise((resolve): void => {
|
||||
client.onSharedProcessActive(resolve);
|
||||
let d = client.onSharedProcessActive((data) => {
|
||||
d.dispose();
|
||||
d = client.onSharedProcessActive(() => {
|
||||
d.dispose();
|
||||
this.retry.notificationService.error(
|
||||
new Error("Disconnected from shared process. Searching, installing, enabling, and disabling extensions will not work until the page is refreshed."),
|
||||
);
|
||||
});
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener("contextmenu", (event) => {
|
||||
@@ -65,10 +80,6 @@ export abstract class IdeClient {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a task in some logging, timing, and progress updates. Can optionally
|
||||
* wait on other tasks which won't count towards this task's time.
|
||||
*/
|
||||
public async task<T>(description: string, duration: number, task: () => Promise<T>): Promise<T>;
|
||||
public async task<T, V>(description: string, duration: number, task: (v: V) => Promise<T>, t: Promise<V>): Promise<T>;
|
||||
public async task<T, V1, V2>(description: string, duration: number, task: (v1: V1, v2: V2) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>): Promise<T>;
|
||||
@@ -76,6 +87,10 @@ export abstract class IdeClient {
|
||||
public async task<T, V1, V2, V3, V4>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>): Promise<T>;
|
||||
public async task<T, V1, V2, V3, V4, V5>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4, v5: V5) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>, t5: Promise<V5>): Promise<T>;
|
||||
public async task<T, V1, V2, V3, V4, V5, V6>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4, v5: V5, v6: V6) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>, t5: Promise<V5>, t6: Promise<V6>): Promise<T>;
|
||||
/**
|
||||
* Wrap a task in some logging, timing, and progress updates. Can optionally
|
||||
* wait on other tasks which won't count towards this task's time.
|
||||
*/
|
||||
public async task<T>(
|
||||
description: string, duration: number = 100, task: (...args: any[]) => Promise<T>, ...after: Array<Promise<any>> // tslint:disable-line no-any
|
||||
): Promise<T> {
|
||||
|
||||
@@ -11,7 +11,7 @@ class WebsocketConnection implements ReadWriteConnection {
|
||||
private activeSocket: WebSocket | undefined;
|
||||
private readonly messageBuffer = <Uint8Array[]>[];
|
||||
private readonly socketTimeoutDelay = 60 * 1000;
|
||||
private readonly retryName = "Socket";
|
||||
private readonly retry = retry.register("Socket", () => this.connect());
|
||||
private isUp: boolean = false;
|
||||
private closed: boolean = false;
|
||||
|
||||
@@ -26,11 +26,14 @@ class WebsocketConnection implements ReadWriteConnection {
|
||||
public readonly onMessage = this.messageEmitter.event;
|
||||
|
||||
public constructor() {
|
||||
retry.register(this.retryName, () => this.connect());
|
||||
retry.block(this.retryName);
|
||||
retry.run(this.retryName);
|
||||
this.retry.block();
|
||||
this.retry.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send data across the socket. If closed, will error. If connecting, will
|
||||
* queue.
|
||||
*/
|
||||
public send(data: Buffer | Uint8Array): void {
|
||||
if (this.closed) {
|
||||
throw new Error("web socket is closed");
|
||||
@@ -42,6 +45,9 @@ class WebsocketConnection implements ReadWriteConnection {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close socket connection.
|
||||
*/
|
||||
public close(): void {
|
||||
this.closed = true;
|
||||
this.dispose();
|
||||
@@ -75,8 +81,8 @@ class WebsocketConnection implements ReadWriteConnection {
|
||||
field("wasClean", event.wasClean),
|
||||
);
|
||||
if (!this.closed) {
|
||||
retry.block(this.retryName);
|
||||
retry.run(this.retryName);
|
||||
this.retry.block();
|
||||
this.retry.run();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -108,15 +114,19 @@ class WebsocketConnection implements ReadWriteConnection {
|
||||
}, this.socketTimeoutDelay);
|
||||
|
||||
await new Promise((resolve, reject): void => {
|
||||
const onClose = (): void => {
|
||||
const doReject = (): void => {
|
||||
clearTimeout(socketWaitTimeout);
|
||||
socket.removeEventListener("close", onClose);
|
||||
socket.removeEventListener("error", doReject);
|
||||
socket.removeEventListener("close", doReject);
|
||||
reject();
|
||||
};
|
||||
socket.addEventListener("close", onClose);
|
||||
socket.addEventListener("error", doReject);
|
||||
socket.addEventListener("close", doReject);
|
||||
|
||||
socket.addEventListener("open", async () => {
|
||||
socket.addEventListener("open", () => {
|
||||
clearTimeout(socketWaitTimeout);
|
||||
socket.removeEventListener("error", doReject);
|
||||
socket.removeEventListener("close", doReject);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -132,7 +132,7 @@ export class Dialog {
|
||||
public show(): void {
|
||||
if (!this.cachedActiveElement) {
|
||||
this.cachedActiveElement = document.activeElement as HTMLElement;
|
||||
(document.getElementById("workbench.main.container") || document.body).appendChild(this.overlay);
|
||||
(document.querySelector(".monaco-workbench") || document.body).appendChild(this.overlay);
|
||||
document.addEventListener("keydown", this.onKeydown);
|
||||
if (this.input) {
|
||||
this.input.focus();
|
||||
|
||||
@@ -45,7 +45,8 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
|
||||
},
|
||||
set: (value: string): void => {
|
||||
if (value) {
|
||||
value = value.replace(/file:\/\//g, "/resource");
|
||||
const resourceBaseUrl = location.pathname.replace(/\/$/, "") + "/resource";
|
||||
value = value.replace(/file:\/\//g, resourceBaseUrl);
|
||||
}
|
||||
oldSrc!.set!.call(img, value);
|
||||
},
|
||||
@@ -66,7 +67,8 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
|
||||
},
|
||||
set: (value: string): void => {
|
||||
if (value) {
|
||||
value = value.replace(/file:\/\//g, "/resource");
|
||||
const resourceBaseUrl = location.pathname.replace(/\/$/, "") + "/resource";
|
||||
value = value.replace(/file:\/\//g, resourceBaseUrl);
|
||||
}
|
||||
oldInnerHtml!.set!.call(style, value);
|
||||
},
|
||||
@@ -80,7 +82,8 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
|
||||
if (sheet && !overridden) {
|
||||
const oldInsertRule = sheet.insertRule;
|
||||
sheet.insertRule = (rule: string, index?: number): void => {
|
||||
rule = rule.replace(/file:\/\//g, "/resource");
|
||||
const resourceBaseUrl = location.pathname.replace(/\/$/, "") + "/resource";
|
||||
rule = rule.replace(/file:\/\//g, resourceBaseUrl);
|
||||
oldInsertRule.call(sheet, rule, index);
|
||||
};
|
||||
overridden = true;
|
||||
@@ -137,12 +140,17 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
|
||||
};
|
||||
},
|
||||
});
|
||||
view.src = require("!!file-loader?name=[path][name].[ext]!./webview.html");
|
||||
Object.defineProperty(view, "src", {
|
||||
set: (): void => { /* Nope. */ },
|
||||
});
|
||||
(view as any).getWebContents = (): void => undefined; // tslint:disable-line no-any
|
||||
(view as any).send = (channel: string, ...args: any[]): void => { // tslint:disable-line no-any
|
||||
if (args[0] && typeof args[0] === "object" && args[0].contents) {
|
||||
// TODO
|
||||
args[0].contents = (args[0].contents as string).replace(/"(file:\/\/[^"]*)"/g, (m1) => `"/resource${m1}"`);
|
||||
args[0].contents = (args[0].contents as string).replace(/"vscode-resource:([^"]*)"/g, (m, m1) => `"/resource${m1}"`);
|
||||
const resourceBaseUrl = location.pathname.replace(/\/$/, "") + "/resource";
|
||||
args[0].contents = (args[0].contents as string).replace(/"(file:\/\/[^"]*)"/g, (m1) => `"${resourceBaseUrl}${m1}"`);
|
||||
args[0].contents = (args[0].contents as string).replace(/"vscode-resource:([^"]*)"/g, (m, m1) => `"${resourceBaseUrl}${m1}"`);
|
||||
args[0].contents = (args[0].contents as string).replace(/style-src vscode-core-resource:/g, "style-src 'self'");
|
||||
}
|
||||
if (view.contentWindow) {
|
||||
@@ -178,6 +186,10 @@ class Clipboard {
|
||||
public writeText(value: string): Promise<void> {
|
||||
return clipboard.writeText(value);
|
||||
}
|
||||
|
||||
public readText(): Promise<string> {
|
||||
return clipboard.readText();
|
||||
}
|
||||
}
|
||||
|
||||
class Shell {
|
||||
|
||||
8
packages/ide/src/fill/webview.html
Normal file
8
packages/ide/src/fill/webview.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="width: 100%; height: 100%">
|
||||
<head>
|
||||
<title>Virtual Document</title>
|
||||
</head>
|
||||
<body style="margin: 0; overflow: hidden; width: 100%; height: 100%">
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,14 +1,64 @@
|
||||
import { logger, field } from "@coder/logger";
|
||||
import { NotificationService, INotificationHandle, INotificationService, Severity } from "./fill/notification";
|
||||
|
||||
// tslint:disable no-any can have different return values
|
||||
|
||||
interface IRetryItem {
|
||||
/**
|
||||
* How many times this item has been retried.
|
||||
*/
|
||||
count?: number;
|
||||
delay?: number; // In seconds.
|
||||
end?: number; // In ms.
|
||||
fn(): any | Promise<any>; // tslint:disable-line no-any can have different return values
|
||||
|
||||
/**
|
||||
* In seconds.
|
||||
*/
|
||||
delay?: number;
|
||||
|
||||
/**
|
||||
* In milliseconds.
|
||||
*/
|
||||
end?: number;
|
||||
|
||||
/**
|
||||
* Function to run when retrying.
|
||||
*/
|
||||
fn(): any;
|
||||
|
||||
/**
|
||||
* Timer for running this item.
|
||||
*/
|
||||
timeout?: number | NodeJS.Timer;
|
||||
|
||||
/**
|
||||
* Whether the item is retrying or waiting to retry.
|
||||
*/
|
||||
running?: boolean;
|
||||
showInNotification: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* An retry-able instance.
|
||||
*/
|
||||
export interface RetryInstance {
|
||||
/**
|
||||
* Run this retry.
|
||||
*/
|
||||
run(error?: Error): void;
|
||||
|
||||
/**
|
||||
* Block on this instance.
|
||||
*/
|
||||
block(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A retry-able instance that doesn't use a promise so it must be manually
|
||||
* ran again on failure and recovered on success.
|
||||
*/
|
||||
export interface ManualRetryInstance extends RetryInstance {
|
||||
/**
|
||||
* Mark this item as recovered.
|
||||
*/
|
||||
recover(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -21,11 +71,11 @@ interface IRetryItem {
|
||||
* to the user explaining what is happening with an option to immediately retry.
|
||||
*/
|
||||
export class Retry {
|
||||
private items = new Map<string, IRetryItem>();
|
||||
private readonly items = new Map<string, IRetryItem>();
|
||||
|
||||
// Times are in seconds.
|
||||
private readonly retryMinDelay = 1;
|
||||
private readonly retryMaxDelay = 10;
|
||||
private readonly retryMaxDelay = 3;
|
||||
private readonly maxImmediateRetries = 5;
|
||||
private readonly retryExponent = 1.5;
|
||||
private blocked: string | boolean | undefined;
|
||||
@@ -50,8 +100,49 @@ export class Retry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Block retries when we know they will fail (for example when starting Wush
|
||||
* back up). If a name is passed, that service will still be allowed to retry
|
||||
* Register a function to retry that starts/connects to a service.
|
||||
*
|
||||
* The service is automatically retried or recovered when the promise resolves
|
||||
* or rejects. If the service dies after starting, it must be manually
|
||||
* retried.
|
||||
*/
|
||||
public register(name: string, fn: () => Promise<any>): RetryInstance;
|
||||
/**
|
||||
* Register a function to retry that starts/connects to a service.
|
||||
*
|
||||
* Must manually retry if it fails to start again or dies after restarting and
|
||||
* manually recover if it succeeds in starting again.
|
||||
*/
|
||||
public register(name: string, fn: () => any): ManualRetryInstance;
|
||||
/**
|
||||
* Register a function to retry that starts/connects to a service.
|
||||
*/
|
||||
public register(name: string, fn: () => any): RetryInstance | ManualRetryInstance {
|
||||
if (this.items.has(name)) {
|
||||
throw new Error(`"${name}" is already registered`);
|
||||
}
|
||||
this.items.set(name, { fn });
|
||||
|
||||
return {
|
||||
block: (): void => this.block(name),
|
||||
run: (error?: Error): void => this.run(name, error),
|
||||
recover: (): void => this.recover(name),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-register a function to retry.
|
||||
*/
|
||||
public unregister(name: string): void {
|
||||
if (!this.items.has(name)) {
|
||||
throw new Error(`"${name}" is not registered`);
|
||||
}
|
||||
this.items.delete(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Block retries when we know they will fail (for example when the socket is
|
||||
* down ). If a name is passed, that service will still be allowed to retry
|
||||
* (unless we have already blocked).
|
||||
*
|
||||
* Blocking without a name will override a block with a name.
|
||||
@@ -68,7 +159,7 @@ export class Retry {
|
||||
/**
|
||||
* Unblock retries and run any that are pending.
|
||||
*/
|
||||
public unblock(): void {
|
||||
private unblock(): void {
|
||||
this.blocked = false;
|
||||
this.items.forEach((item, name) => {
|
||||
if (item.running) {
|
||||
@@ -77,35 +168,10 @@ export class Retry {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a function to retry that starts/connects to a service.
|
||||
*
|
||||
* If the function returns a promise, it will automatically be retried,
|
||||
* recover, & unblock after calling `run` once (otherwise they need to be
|
||||
* called manually).
|
||||
*/
|
||||
// tslint:disable-next-line no-any can have different return values
|
||||
public register(name: string, fn: () => any | Promise<any>, showInNotification: boolean = true): void {
|
||||
if (this.items.has(name)) {
|
||||
throw new Error(`"${name}" is already registered`);
|
||||
}
|
||||
this.items.set(name, { fn, showInNotification });
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a function to retry.
|
||||
*/
|
||||
public unregister(name: string): void {
|
||||
if (!this.items.has(name)) {
|
||||
throw new Error(`"${name}" is not registered`);
|
||||
}
|
||||
this.items.delete(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry a service.
|
||||
*/
|
||||
public run(name: string, error?: Error): void {
|
||||
private run(name: string, error?: Error): void {
|
||||
if (!this.items.has(name)) {
|
||||
throw new Error(`"${name}" is not registered`);
|
||||
}
|
||||
@@ -149,7 +215,7 @@ export class Retry {
|
||||
/**
|
||||
* Reset a service after a successfully recovering.
|
||||
*/
|
||||
public recover(name: string): void {
|
||||
private recover(name: string): void {
|
||||
if (!this.items.has(name)) {
|
||||
throw new Error(`"${name}" is not registered`);
|
||||
}
|
||||
@@ -191,9 +257,9 @@ export class Retry {
|
||||
if (this.blocked === name) {
|
||||
this.unblock();
|
||||
}
|
||||
}).catch(() => {
|
||||
}).catch((error) => {
|
||||
endItem();
|
||||
this.run(name);
|
||||
this.run(name, error);
|
||||
});
|
||||
} else {
|
||||
endItem();
|
||||
@@ -214,8 +280,7 @@ export class Retry {
|
||||
|
||||
const now = Date.now();
|
||||
const items = Array.from(this.items.entries()).filter(([_, item]) => {
|
||||
return item.showInNotification
|
||||
&& typeof item.end !== "undefined"
|
||||
return typeof item.end !== "undefined"
|
||||
&& item.end > now
|
||||
&& item.delay && item.delay >= this.notificationThreshold;
|
||||
}).sort((a, b) => {
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
"build": "tsc -p tsconfig.build.json && cp ./out/packages/logger/src/* ./out && rm -rf out/packages && ../../node_modules/.bin/webpack --config ./webpack.config.js",
|
||||
"postinstall": "if [ ! -d out ];then npm run build; fi"
|
||||
},
|
||||
"version": "1.0.3",
|
||||
"version": "1.1.3",
|
||||
"main": "out/main.js",
|
||||
"types": "out/index.d.ts",
|
||||
"author": "Coder",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@google-cloud/logging": "^4.5.2"
|
||||
}
|
||||
}
|
||||
|
||||
12
packages/logger/src/extender.test.ts
Normal file
12
packages/logger/src/extender.test.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { field, logger } from "./logger";
|
||||
import { createStackdriverExtender } from "./extender";
|
||||
|
||||
describe("Extender", () => {
|
||||
it("should add stackdriver extender", () => {
|
||||
logger.extend(createStackdriverExtender("coder-dev-1", "logging-package-tests"));
|
||||
});
|
||||
|
||||
it("should log", async () => {
|
||||
logger.debug("Bananas!", field("frog", { hi: "wow" }));
|
||||
});
|
||||
});
|
||||
63
packages/logger/src/extender.ts
Normal file
63
packages/logger/src/extender.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import * as gcl from "@google-cloud/logging";
|
||||
import { Extender, logger, field } from "./logger";
|
||||
|
||||
export const createStackdriverExtender = (projectId: string, logId: string): Extender => {
|
||||
enum GcpLogSeverity {
|
||||
DEFAULT = 0,
|
||||
DEBUG = 100,
|
||||
INFO = 200,
|
||||
NOTICE = 300,
|
||||
WARNING = 400,
|
||||
ERROR = 500,
|
||||
CRITICAL = 600,
|
||||
ALERT = 700,
|
||||
EMERGENCY = 800,
|
||||
}
|
||||
|
||||
const logging = new gcl.Logging({
|
||||
autoRetry: true,
|
||||
projectId,
|
||||
});
|
||||
|
||||
const log = logging.log(logId);
|
||||
const convertSeverity = (severity: "trace" | "info" | "warn" | "debug" | "error"): GcpLogSeverity => {
|
||||
switch (severity) {
|
||||
case "trace":
|
||||
case "debug":
|
||||
return GcpLogSeverity.DEBUG;
|
||||
case "info":
|
||||
return GcpLogSeverity.INFO;
|
||||
case "error":
|
||||
return GcpLogSeverity.ERROR;
|
||||
case "warn":
|
||||
return GcpLogSeverity.WARNING;
|
||||
}
|
||||
};
|
||||
|
||||
return (options): void => {
|
||||
const severity = convertSeverity(options.type);
|
||||
// tslint:disable-next-line:no-any
|
||||
const metadata = {} as any;
|
||||
if (options.fields) {
|
||||
options.fields.forEach((f) => {
|
||||
if (!f) {
|
||||
return;
|
||||
}
|
||||
metadata[f.identifier] = f.value;
|
||||
});
|
||||
}
|
||||
|
||||
const entry = log.entry({
|
||||
// tslint:disable-next-line:no-any
|
||||
severity: severity as any,
|
||||
}, {
|
||||
...metadata,
|
||||
message: options.message,
|
||||
});
|
||||
|
||||
log.write(entry).catch((ex) => {
|
||||
logger.named("GCP").error("Failed to log", field("error", ex));
|
||||
});
|
||||
};
|
||||
|
||||
};
|
||||
@@ -59,6 +59,14 @@ export const field = <T>(name: string, value: T): Field<T> => {
|
||||
return new Field(name, value);
|
||||
};
|
||||
|
||||
export type Extender = (msg: {
|
||||
message: string,
|
||||
level: Level,
|
||||
type: "trace" | "info" | "warn" | "debug" | "error",
|
||||
fields?: FieldArray,
|
||||
section?: string,
|
||||
}) => void;
|
||||
|
||||
/**
|
||||
* This formats & builds text for logging.
|
||||
* It should only be used to build one log item at a time since it stores the
|
||||
@@ -221,6 +229,7 @@ export class Logger {
|
||||
private _formatter: Formatter,
|
||||
private readonly name?: string,
|
||||
private readonly defaultFields?: FieldArray,
|
||||
private readonly extenders: Extender[] = [],
|
||||
) {
|
||||
if (name) {
|
||||
this.nameColor = this.hashStringToColor(name);
|
||||
@@ -248,6 +257,10 @@ export class Logger {
|
||||
this.muted = true;
|
||||
}
|
||||
|
||||
public extend(extender: Extender): void {
|
||||
this.extenders.push(extender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs information.
|
||||
*/
|
||||
@@ -328,7 +341,7 @@ export class Logger {
|
||||
* Each name is deterministically generated a color.
|
||||
*/
|
||||
public named(name: string, ...fields: FieldArray): Logger {
|
||||
const l = new Logger(this._formatter, name, fields);
|
||||
const l = new Logger(this._formatter, name, fields, this.extenders);
|
||||
if (this.muted) {
|
||||
l.mute();
|
||||
}
|
||||
@@ -393,6 +406,16 @@ export class Logger {
|
||||
console.log(...this._formatter.flush());
|
||||
}
|
||||
// tslint:enable no-console
|
||||
|
||||
this.extenders.forEach((extender) => {
|
||||
extender({
|
||||
section: this.name,
|
||||
fields: options.fields,
|
||||
level: options.level,
|
||||
message: options.message as string,
|
||||
type: options.type,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,16 +1,34 @@
|
||||
const path = require("path");
|
||||
const merge = require("webpack-merge");
|
||||
|
||||
module.exports = merge(require(path.join(__dirname, "../../scripts", "webpack.general.config.js"))(), {
|
||||
devtool: "none",
|
||||
mode: "production",
|
||||
target: "node",
|
||||
output: {
|
||||
path: path.join(__dirname, "out"),
|
||||
filename: "main.js",
|
||||
libraryTarget: "commonjs",
|
||||
},
|
||||
entry: [
|
||||
"./packages/logger/src/index.ts"
|
||||
],
|
||||
});
|
||||
module.exports = [
|
||||
merge(require(path.join(__dirname, "../../scripts", "webpack.general.config.js"))(), {
|
||||
devtool: "none",
|
||||
mode: "production",
|
||||
target: "node",
|
||||
output: {
|
||||
path: path.join(__dirname, "out"),
|
||||
filename: "main.js",
|
||||
libraryTarget: "commonjs",
|
||||
},
|
||||
entry: [
|
||||
"./packages/logger/src/index.ts"
|
||||
],
|
||||
}),
|
||||
merge(require(path.join(__dirname, "../../scripts", "webpack.general.config.js"))(), {
|
||||
devtool: "none",
|
||||
mode: "production",
|
||||
target: "node",
|
||||
output: {
|
||||
path: path.join(__dirname, "out"),
|
||||
filename: "extender.js",
|
||||
libraryTarget: "commonjs",
|
||||
},
|
||||
externals: {
|
||||
"@google-cloud/logging": "commonjs @google-cloud/logging",
|
||||
},
|
||||
entry: [
|
||||
"./packages/logger/src/extender.ts"
|
||||
],
|
||||
}),
|
||||
];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,8 +33,7 @@
|
||||
"@coder/(.*)/test": "<rootDir>/$1/test",
|
||||
"@coder/(.*)": "<rootDir>/$1/src",
|
||||
"vs/(.*)": "<rootDir>/../lib/vscode/src/vs/$1",
|
||||
"vszip": "<rootDir>/../lib/vscode/src/vs/base/node/zip.ts",
|
||||
"^node-pty": "node-pty-prebuilt"
|
||||
"vszip": "<rootDir>/../lib/vscode/src/vs/base/node/zip.ts"
|
||||
},
|
||||
"transform": {
|
||||
"^.+\\.tsx?$": "ts-jest"
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
"dependencies": {
|
||||
"express": "^4.16.4",
|
||||
"google-protobuf": "^3.6.1",
|
||||
"node-pty-prebuilt": "^0.7.6",
|
||||
"spdlog": "^0.7.2",
|
||||
"trash": "^4.3.0",
|
||||
"ws": "^6.1.2"
|
||||
},
|
||||
|
||||
@@ -5,8 +5,8 @@ import { Emitter } from "@coder/events";
|
||||
import { logger, field } from "@coder/logger";
|
||||
import { ReadWriteConnection, InitData, SharedProcessData } from "../common/connection";
|
||||
import { Module, ServerProxy } from "../common/proxy";
|
||||
import { stringify, parse, moduleToProto, protoToModule, protoToOperatingSystem } from "../common/util";
|
||||
import { Ping, ServerMessage, ClientMessage, MethodMessage, NamedProxyMessage, NumberedProxyMessage, SuccessMessage, FailMessage, EventMessage, CallbackMessage } from "../proto";
|
||||
import { argumentToProto, protoToArgument, moduleToProto, protoToModule, protoToOperatingSystem } from "../common/util";
|
||||
import { Argument, Ping, ServerMessage, ClientMessage, Method, Event, Callback } from "../proto";
|
||||
import { FsModule, ChildProcessModule, NetModule, NodePtyModule, SpdlogModule, TrashModule } from "./modules";
|
||||
|
||||
// tslint:disable no-any
|
||||
@@ -24,8 +24,8 @@ export class Client {
|
||||
private messageId = 0;
|
||||
private callbackId = 0;
|
||||
private readonly proxies = new Map<number | Module, ProxyData>();
|
||||
private readonly successEmitter = new Emitter<SuccessMessage>();
|
||||
private readonly failEmitter = new Emitter<FailMessage>();
|
||||
private readonly successEmitter = new Emitter<Method.Success>();
|
||||
private readonly failEmitter = new Emitter<Method.Fail>();
|
||||
private readonly eventEmitter = new Emitter<{ event: string; args: any[]; }>();
|
||||
|
||||
private _initData: InitData | undefined;
|
||||
@@ -129,19 +129,13 @@ export class Client {
|
||||
field("event listeners", this.eventEmitter.counts),
|
||||
]);
|
||||
|
||||
const message = new FailMessage();
|
||||
const message = new Method.Fail();
|
||||
const error = new Error("disconnected");
|
||||
message.setResponse(stringify(error));
|
||||
message.setResponse(argumentToProto(error));
|
||||
this.failEmitter.emit(message);
|
||||
|
||||
this.eventEmitter.emit({ event: "exit", args: [1] });
|
||||
this.eventEmitter.emit({ event: "close", args: [] });
|
||||
try {
|
||||
this.eventEmitter.emit({ event: "error", args: [error] });
|
||||
} catch (error) {
|
||||
// If nothing is listening, EventEmitter will throw an error.
|
||||
}
|
||||
this.eventEmitter.emit({ event: "done", args: [true] });
|
||||
this.eventEmitter.emit({ event: "disconnected", args: [error] });
|
||||
this.eventEmitter.emit({ event: "done", args: [] });
|
||||
};
|
||||
|
||||
connection.onDown(() => handleDisconnect());
|
||||
@@ -149,6 +143,12 @@ export class Client {
|
||||
clearTimeout(this.pingTimeout as any);
|
||||
this.pingTimeout = undefined;
|
||||
handleDisconnect();
|
||||
this.proxies.clear();
|
||||
this.successEmitter.dispose();
|
||||
this.failEmitter.dispose();
|
||||
this.eventEmitter.dispose();
|
||||
this.initDataEmitter.dispose();
|
||||
this.sharedProcessActiveEmitter.dispose();
|
||||
});
|
||||
connection.onUp(() => this.disconnected = false);
|
||||
|
||||
@@ -174,19 +174,30 @@ export class Client {
|
||||
* Make a remote call for a proxy's method using proto.
|
||||
*/
|
||||
private remoteCall(proxyId: number | Module, method: string, args: any[]): Promise<any> {
|
||||
if (this.disconnected) {
|
||||
return Promise.reject(new Error("disconnected"));
|
||||
if (typeof proxyId === "number" && (this.disconnected || !this.proxies.has(proxyId))) {
|
||||
// Can assume killing or closing works because a disconnected proxy is
|
||||
// disposed on the server's side, and a non-existent proxy has already
|
||||
// been disposed.
|
||||
switch (method) {
|
||||
case "close":
|
||||
case "kill":
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject(
|
||||
new Error(`Unable to call "${method}" on proxy ${proxyId}: disconnected`),
|
||||
);
|
||||
}
|
||||
|
||||
const message = new MethodMessage();
|
||||
const message = new Method();
|
||||
const id = this.messageId++;
|
||||
let proxyMessage: NamedProxyMessage | NumberedProxyMessage;
|
||||
let proxyMessage: Method.Named | Method.Numbered;
|
||||
if (typeof proxyId === "string") {
|
||||
proxyMessage = new NamedProxyMessage();
|
||||
proxyMessage = new Method.Named();
|
||||
proxyMessage.setModule(moduleToProto(proxyId));
|
||||
message.setNamedProxy(proxyMessage);
|
||||
} else {
|
||||
proxyMessage = new NumberedProxyMessage();
|
||||
proxyMessage = new Method.Numbered();
|
||||
proxyMessage.setProxyId(proxyId);
|
||||
message.setNumberedProxy(proxyMessage);
|
||||
}
|
||||
@@ -206,16 +217,14 @@ export class Client {
|
||||
return callbackId;
|
||||
};
|
||||
|
||||
const stringifiedArgs = args.map((a) => stringify(a, storeCallback));
|
||||
logger.trace(() => [
|
||||
"sending",
|
||||
field("id", id),
|
||||
field("proxyId", proxyId),
|
||||
field("method", method),
|
||||
field("args", stringifiedArgs),
|
||||
]);
|
||||
|
||||
proxyMessage.setArgsList(stringifiedArgs);
|
||||
proxyMessage.setArgsList(args.map((a) => argumentToProto(a, storeCallback)));
|
||||
|
||||
const clientMessage = new ClientMessage();
|
||||
clientMessage.setMethod(message);
|
||||
@@ -223,7 +232,7 @@ export class Client {
|
||||
|
||||
// The server will send back a fail or success message when the method
|
||||
// has completed, so we listen for that based on the message's unique ID.
|
||||
const promise = new Promise((resolve, reject): void => {
|
||||
const promise = new Promise((resolve, reject): void => {
|
||||
const dispose = (): void => {
|
||||
d1.dispose();
|
||||
d2.dispose();
|
||||
@@ -237,12 +246,12 @@ export class Client {
|
||||
|
||||
const d1 = this.successEmitter.event(id, (message) => {
|
||||
dispose();
|
||||
resolve(this.parse(message.getResponse()));
|
||||
resolve(this.protoToArgument(message.getResponse(), promise));
|
||||
});
|
||||
|
||||
const d2 = this.failEmitter.event(id, (message) => {
|
||||
dispose();
|
||||
reject(parse(message.getResponse()));
|
||||
reject(protoToArgument(message.getResponse()));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -253,42 +262,54 @@ export class Client {
|
||||
* Handle all messages from the server.
|
||||
*/
|
||||
private async handleMessage(message: ServerMessage): Promise<void> {
|
||||
if (message.hasInit()) {
|
||||
const init = message.getInit()!;
|
||||
this._initData = {
|
||||
dataDirectory: init.getDataDirectory(),
|
||||
homeDirectory: init.getHomeDirectory(),
|
||||
tmpDirectory: init.getTmpDirectory(),
|
||||
workingDirectory: init.getWorkingDirectory(),
|
||||
os: protoToOperatingSystem(init.getOperatingSystem()),
|
||||
shell: init.getShell(),
|
||||
builtInExtensionsDirectory: init.getBuiltinExtensionsDir(),
|
||||
};
|
||||
this.initDataEmitter.emit(this._initData);
|
||||
} else if (message.hasSuccess()) {
|
||||
this.emitSuccess(message.getSuccess()!);
|
||||
} else if (message.hasFail()) {
|
||||
this.emitFail(message.getFail()!);
|
||||
} else if (message.hasEvent()) {
|
||||
await this.emitEvent(message.getEvent()!);
|
||||
} else if (message.hasCallback()) {
|
||||
await this.runCallback(message.getCallback()!);
|
||||
} else if (message.hasSharedProcessActive()) {
|
||||
const sharedProcessActiveMessage = message.getSharedProcessActive()!;
|
||||
this.sharedProcessActiveEmitter.emit({
|
||||
socketPath: sharedProcessActiveMessage.getSocketPath(),
|
||||
logPath: sharedProcessActiveMessage.getLogPath(),
|
||||
});
|
||||
} else if (message.hasPong()) {
|
||||
// Nothing to do since pings are on a timer rather than waiting for the
|
||||
// next pong in case a message from either the client or server is dropped
|
||||
// which would break the ping cycle.
|
||||
} else {
|
||||
throw new Error("unknown message type");
|
||||
switch (message.getMsgCase()) {
|
||||
case ServerMessage.MsgCase.INIT:
|
||||
const init = message.getInit()!;
|
||||
this._initData = {
|
||||
dataDirectory: init.getDataDirectory(),
|
||||
homeDirectory: init.getHomeDirectory(),
|
||||
tmpDirectory: init.getTmpDirectory(),
|
||||
workingDirectory: init.getWorkingDirectory(),
|
||||
os: protoToOperatingSystem(init.getOperatingSystem()),
|
||||
shell: init.getShell(),
|
||||
extensionsDirectory: init.getExtensionsDirectory(),
|
||||
builtInExtensionsDirectory: init.getBuiltinExtensionsDir(),
|
||||
};
|
||||
this.initDataEmitter.emit(this._initData);
|
||||
break;
|
||||
case ServerMessage.MsgCase.SUCCESS:
|
||||
this.emitSuccess(message.getSuccess()!);
|
||||
break;
|
||||
case ServerMessage.MsgCase.FAIL:
|
||||
this.emitFail(message.getFail()!);
|
||||
break;
|
||||
case ServerMessage.MsgCase.EVENT:
|
||||
await this.emitEvent(message.getEvent()!);
|
||||
break;
|
||||
case ServerMessage.MsgCase.CALLBACK:
|
||||
await this.runCallback(message.getCallback()!);
|
||||
break;
|
||||
case ServerMessage.MsgCase.SHARED_PROCESS_ACTIVE:
|
||||
const sharedProcessActiveMessage = message.getSharedProcessActive()!;
|
||||
this.sharedProcessActiveEmitter.emit({
|
||||
socketPath: sharedProcessActiveMessage.getSocketPath(),
|
||||
logPath: sharedProcessActiveMessage.getLogPath(),
|
||||
});
|
||||
break;
|
||||
case ServerMessage.MsgCase.PONG:
|
||||
// Nothing to do since pings are on a timer rather than waiting for the
|
||||
// next pong in case a message from either the client or server is dropped
|
||||
// which would break the ping cycle.
|
||||
break;
|
||||
default:
|
||||
throw new Error("unknown message type");
|
||||
}
|
||||
}
|
||||
|
||||
private emitSuccess(message: SuccessMessage): void {
|
||||
/**
|
||||
* Convert message to a success event.
|
||||
*/
|
||||
private emitSuccess(message: Method.Success): void {
|
||||
logger.trace(() => [
|
||||
"received resolve",
|
||||
field("id", message.getId()),
|
||||
@@ -297,7 +318,10 @@ export class Client {
|
||||
this.successEmitter.emit(message.getId(), message);
|
||||
}
|
||||
|
||||
private emitFail(message: FailMessage): void {
|
||||
/**
|
||||
* Convert message to a fail event.
|
||||
*/
|
||||
private emitFail(message: Method.Fail): void {
|
||||
logger.trace(() => [
|
||||
"received reject",
|
||||
field("id", message.getId()),
|
||||
@@ -313,7 +337,7 @@ export class Client {
|
||||
* request before it emits. Instead, emit all events from the server so all
|
||||
* events are always caught on the client.
|
||||
*/
|
||||
private async emitEvent(message: EventMessage): Promise<void> {
|
||||
private async emitEvent(message: Event): Promise<void> {
|
||||
const eventMessage = message.getNamedEvent()! || message.getNumberedEvent()!;
|
||||
const proxyId = message.getNamedEvent()
|
||||
? protoToModule(message.getNamedEvent()!.getModule())
|
||||
@@ -324,10 +348,9 @@ export class Client {
|
||||
"received event",
|
||||
field("proxyId", proxyId),
|
||||
field("event", event),
|
||||
field("args", eventMessage.getArgsList()),
|
||||
]);
|
||||
|
||||
const args = eventMessage.getArgsList().map((a) => this.parse(a));
|
||||
const args = eventMessage.getArgsList().map((a) => this.protoToArgument(a));
|
||||
this.eventEmitter.emit(proxyId, { event, args });
|
||||
}
|
||||
|
||||
@@ -339,7 +362,7 @@ export class Client {
|
||||
* also only be used when passed together with the method. If they are sent
|
||||
* afterward, they may never be called due to timing issues.
|
||||
*/
|
||||
private async runCallback(message: CallbackMessage): Promise<void> {
|
||||
private async runCallback(message: Callback): Promise<void> {
|
||||
const callbackMessage = message.getNamedCallback()! || message.getNumberedCallback()!;
|
||||
const proxyId = message.getNamedCallback()
|
||||
? protoToModule(message.getNamedCallback()!.getModule())
|
||||
@@ -350,16 +373,15 @@ export class Client {
|
||||
"running callback",
|
||||
field("proxyId", proxyId),
|
||||
field("callbackId", callbackId),
|
||||
field("args", callbackMessage.getArgsList()),
|
||||
]);
|
||||
const args = callbackMessage.getArgsList().map((a) => this.parse(a));
|
||||
const args = callbackMessage.getArgsList().map((a) => this.protoToArgument(a));
|
||||
this.getProxy(proxyId).callbacks.get(callbackId)!(...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the ping loop. Does nothing if already pinging.
|
||||
*/
|
||||
private startPinging = (): void => {
|
||||
private readonly startPinging = (): void => {
|
||||
if (typeof this.pingTimeout !== "undefined") {
|
||||
return;
|
||||
}
|
||||
@@ -450,12 +472,12 @@ export class Client {
|
||||
callbacks: new Map(),
|
||||
});
|
||||
|
||||
instance.onDone((disconnected: boolean) => {
|
||||
instance.onDone(() => {
|
||||
const log = (): void => {
|
||||
logger.trace(() => [
|
||||
typeof proxyId === "number" ? "disposed proxy" : "disposed proxy callbacks",
|
||||
field("proxyId", proxyId),
|
||||
field("disconnected", disconnected),
|
||||
field("disconnected", this.disconnected),
|
||||
field("callbacks", Array.from(this.proxies.values()).reduce((count, proxy) => count + proxy.callbacks.size, 0)),
|
||||
field("success listeners", this.successEmitter.counts),
|
||||
field("fail listeners", this.failEmitter.counts),
|
||||
@@ -471,7 +493,7 @@ export class Client {
|
||||
this.eventEmitter.dispose(proxyId);
|
||||
log();
|
||||
};
|
||||
if (!disconnected) {
|
||||
if (!this.disconnected) {
|
||||
instance.dispose().then(dispose).catch(dispose);
|
||||
} else {
|
||||
dispose();
|
||||
@@ -496,10 +518,16 @@ export class Client {
|
||||
await this.getProxy(proxyId).promise;
|
||||
}
|
||||
|
||||
private parse(value?: string, promise?: Promise<any>): any {
|
||||
return parse(value, undefined, (id) => this.createProxy(id, promise));
|
||||
/**
|
||||
* Same as protoToArgument except provides createProxy.
|
||||
*/
|
||||
private protoToArgument(value?: Argument, promise?: Promise<any>): any {
|
||||
return protoToArgument(value, undefined, (id) => this.createProxy(id, promise));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a proxy. Error if it doesn't exist.
|
||||
*/
|
||||
private getProxy(proxyId: number | Module): ProxyData {
|
||||
if (!this.proxies.has(proxyId)) {
|
||||
throw new Error(`proxy ${proxyId} disposed too early`);
|
||||
|
||||
@@ -6,6 +6,8 @@ import { ClientProxy } from "../../common/proxy";
|
||||
import { ChildProcessModuleProxy, ChildProcessProxy, ChildProcessProxies } from "../../node/modules/child_process";
|
||||
import { Readable, Writable } from "./stream";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class ChildProcess extends ClientProxy<ChildProcessProxy> implements cp.ChildProcess {
|
||||
public readonly stdin: stream.Writable;
|
||||
public readonly stdout: stream.Readable;
|
||||
@@ -23,10 +25,10 @@ export class ChildProcess extends ClientProxy<ChildProcessProxy> implements cp.C
|
||||
this.stderr = new Readable(proxyPromises.then((p) => p.stderr!));
|
||||
this.stdio = [this.stdin, this.stdout, this.stderr];
|
||||
|
||||
this.proxy.getPid().then((pid) => {
|
||||
this.catch(this.proxy.getPid().then((pid) => {
|
||||
this._pid = pid;
|
||||
this._connected = true;
|
||||
});
|
||||
}));
|
||||
this.on("disconnect", () => this._connected = false);
|
||||
this.on("exit", () => {
|
||||
this._connected = false;
|
||||
@@ -48,19 +50,19 @@ export class ChildProcess extends ClientProxy<ChildProcessProxy> implements cp.C
|
||||
|
||||
public kill(): void {
|
||||
this._killed = true;
|
||||
this.proxy.kill();
|
||||
this.catch(this.proxy.kill());
|
||||
}
|
||||
|
||||
public disconnect(): void {
|
||||
this.proxy.disconnect();
|
||||
this.catch(this.proxy.disconnect());
|
||||
}
|
||||
|
||||
public ref(): void {
|
||||
this.proxy.ref();
|
||||
this.catch(this.proxy.ref());
|
||||
}
|
||||
|
||||
public unref(): void {
|
||||
this.proxy.unref();
|
||||
this.catch(this.proxy.unref());
|
||||
}
|
||||
|
||||
public send(
|
||||
@@ -87,6 +89,14 @@ export class ChildProcess extends ClientProxy<ChildProcessProxy> implements cp.C
|
||||
|
||||
return true; // Always true since we can't get this synchronously.
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit and close the process when disconnected.
|
||||
*/
|
||||
protected handleDisconnect(): void {
|
||||
this.emit("exit", 1);
|
||||
this.emit("close");
|
||||
}
|
||||
}
|
||||
|
||||
export class ChildProcessModule {
|
||||
|
||||
@@ -1,15 +1,50 @@
|
||||
import * as fs from "fs";
|
||||
import { callbackify } from "util";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { ClientProxy, Batch } from "../../common/proxy";
|
||||
import { IEncodingOptions, IEncodingOptionsCallback } from "../../common/util";
|
||||
import { FsModuleProxy, Stats as IStats, WatcherProxy, WriteStreamProxy } from "../../node/modules/fs";
|
||||
import { Writable } from "./stream";
|
||||
|
||||
// tslint:disable no-any
|
||||
// tslint:disable completed-docs
|
||||
|
||||
class StatBatch extends Batch<IStats, { path: fs.PathLike }> {
|
||||
public constructor(private readonly proxy: FsModuleProxy) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected remoteCall(batch: { path: fs.PathLike }[]): Promise<(IStats | Error)[]> {
|
||||
return this.proxy.statBatch(batch);
|
||||
}
|
||||
}
|
||||
|
||||
class LstatBatch extends Batch<IStats, { path: fs.PathLike }> {
|
||||
public constructor(private readonly proxy: FsModuleProxy) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected remoteCall(batch: { path: fs.PathLike }[]): Promise<(IStats | Error)[]> {
|
||||
return this.proxy.lstatBatch(batch);
|
||||
}
|
||||
}
|
||||
|
||||
class ReaddirBatch extends Batch<Buffer[] | fs.Dirent[] | string[], { path: fs.PathLike, options: IEncodingOptions }> {
|
||||
public constructor(private readonly proxy: FsModuleProxy) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected remoteCall(queue: { path: fs.PathLike, options: IEncodingOptions }[]): Promise<(Buffer[] | fs.Dirent[] | string[] | Error)[]> {
|
||||
return this.proxy.readdirBatch(queue);
|
||||
}
|
||||
}
|
||||
|
||||
class Watcher extends ClientProxy<WatcherProxy> implements fs.FSWatcher {
|
||||
public close(): void {
|
||||
this.proxy.close();
|
||||
this.catch(this.proxy.close());
|
||||
}
|
||||
|
||||
protected handleDisconnect(): void {
|
||||
this.emit("close");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +58,20 @@ class WriteStream extends Writable<WriteStreamProxy> implements fs.WriteStream {
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this.proxy.close();
|
||||
this.catch(this.proxy.close());
|
||||
}
|
||||
}
|
||||
|
||||
export class FsModule {
|
||||
public constructor(private readonly proxy: FsModuleProxy) {}
|
||||
private readonly statBatch: StatBatch;
|
||||
private readonly lstatBatch: LstatBatch;
|
||||
private readonly readdirBatch: ReaddirBatch;
|
||||
|
||||
public constructor(private readonly proxy: FsModuleProxy) {
|
||||
this.statBatch = new StatBatch(this.proxy);
|
||||
this.lstatBatch = new LstatBatch(this.proxy);
|
||||
this.readdirBatch = new ReaddirBatch(this.proxy);
|
||||
}
|
||||
|
||||
public access = (path: fs.PathLike, mode: number | undefined | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => {
|
||||
if (typeof mode === "function") {
|
||||
@@ -72,9 +115,7 @@ export class FsModule {
|
||||
}
|
||||
|
||||
public exists = (path: fs.PathLike, callback: (exists: boolean) => void): void => {
|
||||
callbackify(this.proxy.exists)(path, (exists) => {
|
||||
callback!(exists as any);
|
||||
});
|
||||
this.proxy.exists(path).then((exists) => callback(exists)).catch(() => callback(false));
|
||||
}
|
||||
|
||||
public fchmod = (fd: number, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
@@ -124,7 +165,7 @@ export class FsModule {
|
||||
}
|
||||
|
||||
public lstat = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => {
|
||||
callbackify(this.proxy.lstat)(path, (error, stats) => {
|
||||
callbackify(this.lstatBatch.add)({ path }, (error, stats) => {
|
||||
callback(error, stats && new Stats(stats));
|
||||
});
|
||||
}
|
||||
@@ -175,7 +216,7 @@ export class FsModule {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
callbackify(this.proxy.readdir)(path, options, callback!);
|
||||
callbackify(this.readdirBatch.add)({ path, options }, callback!);
|
||||
}
|
||||
|
||||
public readlink = (path: fs.PathLike, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, linkString: string | Buffer) => void): void => {
|
||||
@@ -203,7 +244,7 @@ export class FsModule {
|
||||
}
|
||||
|
||||
public stat = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => {
|
||||
callbackify(this.proxy.stat)(path, (error, stats) => {
|
||||
callbackify(this.statBatch.add)({ path }, (error, stats) => {
|
||||
callback(error, stats && new Stats(stats));
|
||||
});
|
||||
}
|
||||
@@ -276,17 +317,7 @@ export class FsModule {
|
||||
}
|
||||
|
||||
class Stats implements fs.Stats {
|
||||
public readonly atime: Date;
|
||||
public readonly mtime: Date;
|
||||
public readonly ctime: Date;
|
||||
public readonly birthtime: Date;
|
||||
|
||||
public constructor(private readonly stats: IStats) {
|
||||
this.atime = new Date(stats.atime);
|
||||
this.mtime = new Date(stats.mtime);
|
||||
this.ctime = new Date(stats.ctime);
|
||||
this.birthtime = new Date(stats.birthtime);
|
||||
}
|
||||
public constructor(private readonly stats: IStats) {}
|
||||
|
||||
public get dev(): number { return this.stats.dev; }
|
||||
public get ino(): number { return this.stats.ino; }
|
||||
@@ -298,6 +329,10 @@ class Stats implements fs.Stats {
|
||||
public get size(): number { return this.stats.size; }
|
||||
public get blksize(): number { return this.stats.blksize; }
|
||||
public get blocks(): number { return this.stats.blocks; }
|
||||
public get atime(): Date { return this.stats.atime; }
|
||||
public get mtime(): Date { return this.stats.mtime; }
|
||||
public get ctime(): Date { return this.stats.ctime; }
|
||||
public get birthtime(): Date { return this.stats.birthtime; }
|
||||
public get atimeMs(): number { return this.stats.atimeMs; }
|
||||
public get mtimeMs(): number { return this.stats.mtimeMs; }
|
||||
public get ctimeMs(): number { return this.stats.ctimeMs; }
|
||||
|
||||
@@ -4,6 +4,8 @@ import { ClientProxy } from "../../common/proxy";
|
||||
import { NetModuleProxy, NetServerProxy, NetSocketProxy } from "../../node/modules/net";
|
||||
import { Duplex } from "./stream";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class Socket extends Duplex<NetSocketProxy> implements net.Socket {
|
||||
private _connecting: boolean = false;
|
||||
private _destroyed: boolean = false;
|
||||
@@ -29,9 +31,8 @@ export class Socket extends Duplex<NetSocketProxy> implements net.Socket {
|
||||
if (callback) {
|
||||
this.on("connect", callback as () => void);
|
||||
}
|
||||
this.proxy.connect(options, host);
|
||||
|
||||
return this;
|
||||
return this.catch(this.proxy.connect(options, host));
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
@@ -117,24 +118,30 @@ export class Socket extends Duplex<NetSocketProxy> implements net.Socket {
|
||||
}
|
||||
|
||||
public unref(): void {
|
||||
this.proxy.unref();
|
||||
this.catch(this.proxy.unref());
|
||||
}
|
||||
|
||||
public ref(): void {
|
||||
this.proxy.ref();
|
||||
this.catch(this.proxy.ref());
|
||||
}
|
||||
}
|
||||
|
||||
export class Server extends ClientProxy<NetServerProxy> implements net.Server {
|
||||
private socketId = 0;
|
||||
private readonly sockets = new Map<number, net.Socket>();
|
||||
private _listening: boolean = false;
|
||||
|
||||
public constructor(proxyPromise: Promise<NetServerProxy> | NetServerProxy) {
|
||||
super(proxyPromise);
|
||||
|
||||
this.proxy.onConnection((socketProxy) => {
|
||||
this.emit("connection", new Socket(socketProxy));
|
||||
});
|
||||
this.catch(this.proxy.onConnection((socketProxy) => {
|
||||
const socket = new Socket(socketProxy);
|
||||
const socketId = this.socketId++;
|
||||
this.sockets.set(socketId, socket);
|
||||
socket.on("error", () => this.sockets.delete(socketId));
|
||||
socket.on("close", () => this.sockets.delete(socketId));
|
||||
this.emit("connection", socket);
|
||||
}));
|
||||
|
||||
this.on("listening", () => this._listening = true);
|
||||
this.on("error", () => this._listening = false);
|
||||
@@ -154,9 +161,7 @@ export class Server extends ClientProxy<NetServerProxy> implements net.Server {
|
||||
this.on("listening", callback as () => void);
|
||||
}
|
||||
|
||||
this.proxy.listen(handle, hostname, backlog);
|
||||
|
||||
return this;
|
||||
return this.catch(this.proxy.listen(handle, hostname, backlog));
|
||||
}
|
||||
|
||||
public get connections(): number {
|
||||
@@ -180,26 +185,25 @@ export class Server extends ClientProxy<NetServerProxy> implements net.Server {
|
||||
if (callback) {
|
||||
this.on("close", callback);
|
||||
}
|
||||
this.proxy.close();
|
||||
|
||||
return this;
|
||||
return this.catch(this.proxy.close());
|
||||
}
|
||||
|
||||
public ref(): this {
|
||||
this.proxy.ref();
|
||||
|
||||
return this;
|
||||
return this.catch(this.proxy.ref());
|
||||
}
|
||||
|
||||
public unref(): this {
|
||||
this.proxy.unref();
|
||||
|
||||
return this;
|
||||
return this.catch(this.proxy.unref());
|
||||
}
|
||||
|
||||
public getConnections(cb: (error: Error | null, count: number) => void): void {
|
||||
cb(null, this.sockets.size);
|
||||
}
|
||||
|
||||
protected handleDisconnect(): void {
|
||||
this.emit("close");
|
||||
}
|
||||
}
|
||||
|
||||
type NodeNet = typeof net;
|
||||
|
||||
@@ -2,17 +2,28 @@ import * as pty from "node-pty";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { NodePtyModuleProxy, NodePtyProcessProxy } from "../../node/modules/node-pty";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class NodePtyProcess extends ClientProxy<NodePtyProcessProxy> implements pty.IPty {
|
||||
private _pid = -1;
|
||||
private _process = "";
|
||||
|
||||
public constructor(proxyPromise: Promise<NodePtyProcessProxy>) {
|
||||
super(proxyPromise);
|
||||
this.proxy.getPid().then((pid) => this._pid = pid);
|
||||
this.proxy.getProcess().then((process) => this._process = process);
|
||||
public constructor(
|
||||
private readonly moduleProxy: NodePtyModuleProxy,
|
||||
private readonly file: string,
|
||||
private readonly args: string[] | string,
|
||||
private readonly options: pty.IPtyForkOptions,
|
||||
) {
|
||||
super(moduleProxy.spawn(file, args, options));
|
||||
this.on("process", (process) => this._process = process);
|
||||
}
|
||||
|
||||
protected initialize(proxyPromise: Promise<NodePtyProcessProxy>): void {
|
||||
super.initialize(proxyPromise);
|
||||
this.catch(this.proxy.getPid().then((p) => this._pid = p));
|
||||
this.catch(this.proxy.getProcess().then((p) => this._process = p));
|
||||
}
|
||||
|
||||
public get pid(): number {
|
||||
return this._pid;
|
||||
}
|
||||
@@ -22,15 +33,21 @@ export class NodePtyProcess extends ClientProxy<NodePtyProcessProxy> implements
|
||||
}
|
||||
|
||||
public resize(columns: number, rows: number): void {
|
||||
this.proxy.resize(columns, rows);
|
||||
this.catch(this.proxy.resize(columns, rows));
|
||||
}
|
||||
|
||||
public write(data: string): void {
|
||||
this.proxy.write(data);
|
||||
this.catch(this.proxy.write(data));
|
||||
}
|
||||
|
||||
public kill(signal?: string): void {
|
||||
this.proxy.kill(signal);
|
||||
this.catch(this.proxy.kill(signal));
|
||||
}
|
||||
|
||||
protected handleDisconnect(): void {
|
||||
this._process += " (disconnected)";
|
||||
this.emit("data", "\r\n\nLost connection...\r\n\n");
|
||||
this.initialize(this.moduleProxy.spawn(this.file, this.args, this.options));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +57,6 @@ export class NodePtyModule implements NodePty {
|
||||
public constructor(private readonly proxy: NodePtyModuleProxy) {}
|
||||
|
||||
public spawn = (file: string, args: string[] | string, options: pty.IPtyForkOptions): pty.IPty => {
|
||||
return new NodePtyProcess(this.proxy.spawn(file, args, options));
|
||||
return new NodePtyProcess(this.proxy, file, args, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,33 @@ import * as spdlog from "spdlog";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { RotatingLoggerProxy, SpdlogModuleProxy } from "../../node/modules/spdlog";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
class RotatingLogger extends ClientProxy<RotatingLoggerProxy> implements spdlog.RotatingLogger {
|
||||
public async trace (message: string): Promise<void> { this.proxy.trace(message); }
|
||||
public async debug (message: string): Promise<void> { this.proxy.debug(message); }
|
||||
public async info (message: string): Promise<void> { this.proxy.info(message); }
|
||||
public async warn (message: string): Promise<void> { this.proxy.warn(message); }
|
||||
public async error (message: string): Promise<void> { this.proxy.error(message); }
|
||||
public async critical (message: string): Promise<void> { this.proxy.critical(message); }
|
||||
public async setLevel (level: number): Promise<void> { this.proxy.setLevel(level); }
|
||||
public async clearFormatters (): Promise<void> { this.proxy.clearFormatters(); }
|
||||
public async flush (): Promise<void> { this.proxy.flush(); }
|
||||
public async drop (): Promise<void> { this.proxy.drop(); }
|
||||
public constructor(
|
||||
private readonly moduleProxy: SpdlogModuleProxy,
|
||||
private readonly name: string,
|
||||
private readonly filename: string,
|
||||
private readonly filesize: number,
|
||||
private readonly filecount: number,
|
||||
) {
|
||||
super(moduleProxy.createLogger(name, filename, filesize, filecount));
|
||||
}
|
||||
|
||||
public trace (message: string): void { this.catch(this.proxy.trace(message)); }
|
||||
public debug (message: string): void { this.catch(this.proxy.debug(message)); }
|
||||
public info (message: string): void { this.catch(this.proxy.info(message)); }
|
||||
public warn (message: string): void { this.catch(this.proxy.warn(message)); }
|
||||
public error (message: string): void { this.catch(this.proxy.error(message)); }
|
||||
public critical (message: string): void { this.catch(this.proxy.critical(message)); }
|
||||
public setLevel (level: number): void { this.catch(this.proxy.setLevel(level)); }
|
||||
public clearFormatters (): void { this.catch(this.proxy.clearFormatters()); }
|
||||
public flush (): void { this.catch(this.proxy.flush()); }
|
||||
public drop (): void { this.catch(this.proxy.drop()); }
|
||||
|
||||
protected handleDisconnect(): void {
|
||||
this.initialize(this.moduleProxy.createLogger(this.name, this.filename, this.filesize, this.filecount));
|
||||
}
|
||||
}
|
||||
|
||||
export class SpdlogModule {
|
||||
@@ -21,12 +37,20 @@ export class SpdlogModule {
|
||||
public constructor(private readonly proxy: SpdlogModuleProxy) {
|
||||
this.RotatingLogger = class extends RotatingLogger {
|
||||
public constructor(name: string, filename: string, filesize: number, filecount: number) {
|
||||
super(proxy.createLogger(name, filename, filesize, filecount));
|
||||
super(proxy, name, filename, filesize, filecount);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public setAsyncMode = (bufferSize: number, flushInterval: number): void => {
|
||||
this.proxy.setAsyncMode(bufferSize, flushInterval);
|
||||
public setAsyncMode = (bufferSize: number, flushInterval: number): Promise<void> => {
|
||||
return this.proxy.setAsyncMode(bufferSize, flushInterval);
|
||||
}
|
||||
|
||||
public createRotatingLogger(name: string, filename: string, filesize: number, filecount: number): RotatingLogger {
|
||||
return new RotatingLogger(this.proxy, name, filename, filesize, filecount);
|
||||
}
|
||||
|
||||
public createRotatingLoggerAsync(name: string, filename: string, filesize: number, filecount: number): Promise<RotatingLogger> {
|
||||
return Promise.resolve(this.createRotatingLogger(name, filename, filesize, filecount));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ import { callbackify } from "util";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { DuplexProxy, IReadableProxy, WritableProxy } from "../../node/modules/stream";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class Writable<T extends WritableProxy = WritableProxy> extends ClientProxy<T> implements stream.Writable {
|
||||
public get writable(): boolean {
|
||||
throw new Error("not implemented");
|
||||
@@ -41,13 +43,11 @@ export class Writable<T extends WritableProxy = WritableProxy> extends ClientPro
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
this.proxy.destroy();
|
||||
this.catch(this.proxy.destroy());
|
||||
}
|
||||
|
||||
public setDefaultEncoding(encoding: string): this {
|
||||
this.proxy.setDefaultEncoding(encoding);
|
||||
|
||||
return this;
|
||||
return this.catch(this.proxy.setDefaultEncoding(encoding));
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
@@ -81,6 +81,11 @@ export class Writable<T extends WritableProxy = WritableProxy> extends ClientPro
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected handleDisconnect(): void {
|
||||
this.emit("close");
|
||||
this.emit("finish");
|
||||
}
|
||||
}
|
||||
|
||||
export class Readable<T extends IReadableProxy = IReadableProxy> extends ClientProxy<T> implements stream.Readable {
|
||||
@@ -146,13 +151,16 @@ export class Readable<T extends IReadableProxy = IReadableProxy> extends ClientP
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
this.proxy.destroy();
|
||||
this.catch(this.proxy.destroy());
|
||||
}
|
||||
|
||||
public setEncoding(encoding: string): this {
|
||||
this.proxy.setEncoding(encoding);
|
||||
return this.catch(this.proxy.setEncoding(encoding));
|
||||
}
|
||||
|
||||
return this;
|
||||
protected handleDisconnect(): void {
|
||||
this.emit("close");
|
||||
this.emit("end");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,8 +234,11 @@ export class Duplex<T extends DuplexProxy = DuplexProxy> extends Writable<T> imp
|
||||
}
|
||||
|
||||
public setEncoding(encoding: string): this {
|
||||
this.proxy.setEncoding(encoding);
|
||||
return this.catch(this.proxy.setEncoding(encoding));
|
||||
}
|
||||
|
||||
return this;
|
||||
protected handleDisconnect(): void {
|
||||
super.handleDisconnect();
|
||||
this.emit("end");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import * as trash from "trash";
|
||||
import { TrashModuleProxy } from "../../node/modules/trash";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class TrashModule {
|
||||
public constructor(private readonly proxy: TrashModuleProxy) {}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ export interface InitData {
|
||||
readonly homeDirectory: string;
|
||||
readonly tmpDirectory: string;
|
||||
readonly shell: string;
|
||||
readonly extensionsDirectory: string;
|
||||
readonly builtInExtensionsDirectory: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,21 +29,77 @@ const unpromisify = <T extends ServerProxy>(proxyPromise: Promise<T>): T => {
|
||||
* need a bunch of `then` calls everywhere.
|
||||
*/
|
||||
export abstract class ClientProxy<T extends ServerProxy> extends EventEmitter {
|
||||
protected readonly proxy: T;
|
||||
private _proxy: T | undefined;
|
||||
|
||||
/**
|
||||
* You can specify not to bind events in order to avoid emitting twice for
|
||||
* duplex streams.
|
||||
*/
|
||||
public constructor(proxyPromise: Promise<T> | T, bindEvents: boolean = true) {
|
||||
public constructor(
|
||||
proxyPromise: Promise<T> | T,
|
||||
private readonly bindEvents: boolean = true,
|
||||
) {
|
||||
super();
|
||||
this.proxy = isPromise(proxyPromise) ? unpromisify(proxyPromise) : proxyPromise;
|
||||
if (bindEvents) {
|
||||
this.proxy.onEvent((event, ...args): void => {
|
||||
this.emit(event, ...args);
|
||||
this.initialize(proxyPromise);
|
||||
if (this.bindEvents) {
|
||||
this.on("disconnected", (error) => {
|
||||
try {
|
||||
this.emit("error", error);
|
||||
} catch (error) {
|
||||
// If nothing is listening, EventEmitter will throw an error.
|
||||
}
|
||||
this.handleDisconnect();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an event listener.
|
||||
*/
|
||||
public off(event: string, cb: (...args: any[]) => void): this {
|
||||
// Fill it here because the fill we're using to provide EventEmitter for the
|
||||
// browser doesn't appear to include `off`.
|
||||
this.removeListener(event, cb);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
protected get proxy(): T {
|
||||
if (!this._proxy) {
|
||||
throw new Error("not initialized");
|
||||
}
|
||||
|
||||
return this._proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the proxy by unpromisifying if necessary and binding to its
|
||||
* events.
|
||||
*/
|
||||
protected initialize(proxyPromise: Promise<T> | T): void {
|
||||
this._proxy = isPromise(proxyPromise) ? unpromisify(proxyPromise) : proxyPromise;
|
||||
if (this.bindEvents) {
|
||||
this.catch(this.proxy.onEvent((event, ...args): void => {
|
||||
this.emit(event, ...args);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform necessary cleanup on disconnect (or reconnect).
|
||||
*/
|
||||
protected abstract handleDisconnect(): void;
|
||||
|
||||
/**
|
||||
* Emit an error event if the promise errors.
|
||||
*/
|
||||
protected catch(promise?: Promise<any>): this {
|
||||
if (promise) {
|
||||
promise.catch((e) => this.emit("error", e));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,6 +110,9 @@ export abstract class ClientProxy<T extends ServerProxy> extends EventEmitter {
|
||||
* from those child proxies and fail to dispose them properly.
|
||||
*/
|
||||
export interface ServerProxy {
|
||||
/**
|
||||
* Dispose the proxy.
|
||||
*/
|
||||
dispose(): Promise<void>;
|
||||
|
||||
/**
|
||||
@@ -73,6 +132,9 @@ export interface ServerProxy {
|
||||
onEvent(cb: (event: string, ...args: any[]) => void): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported top-level module proxies.
|
||||
*/
|
||||
export enum Module {
|
||||
Fs = "fs",
|
||||
ChildProcess = "child_process",
|
||||
@@ -81,3 +143,82 @@ export enum Module {
|
||||
NodePty = "node-pty",
|
||||
Trash = "trash",
|
||||
}
|
||||
|
||||
interface BatchItem<T, A> {
|
||||
args: A;
|
||||
resolve: (t: T) => void;
|
||||
reject: (e: Error) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch remote calls.
|
||||
*/
|
||||
export abstract class Batch<T, A> {
|
||||
private idleTimeout: number | NodeJS.Timer | undefined;
|
||||
private maxTimeout: number | NodeJS.Timer | undefined;
|
||||
private batch = <BatchItem<T, A>[]>[];
|
||||
|
||||
public constructor(
|
||||
/**
|
||||
* Flush after reaching this amount of time.
|
||||
*/
|
||||
private readonly maxTime: number = 1000,
|
||||
/**
|
||||
* Flush after reaching this count.
|
||||
*/
|
||||
private readonly maxCount: number = 100,
|
||||
/**
|
||||
* Flush after not receiving more requests for this amount of time.
|
||||
* This is pretty low by default so essentially we just end up batching
|
||||
* requests that are all made at the same time.
|
||||
*/
|
||||
private readonly idleTime: number = 1,
|
||||
) {}
|
||||
|
||||
public add = (args: A): Promise<T> => {
|
||||
return new Promise((resolve, reject): void => {
|
||||
this.batch.push({
|
||||
args,
|
||||
resolve,
|
||||
reject,
|
||||
});
|
||||
if (this.batch.length >= this.maxCount) {
|
||||
this.flush();
|
||||
} else {
|
||||
clearTimeout(this.idleTimeout as any);
|
||||
this.idleTimeout = setTimeout(this.flush, this.idleTime);
|
||||
if (typeof this.maxTimeout === "undefined") {
|
||||
this.maxTimeout = setTimeout(this.flush, this.maxTime);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform remote call for a batch.
|
||||
*/
|
||||
protected abstract remoteCall(batch: A[]): Promise<(T | Error)[]>;
|
||||
|
||||
/**
|
||||
* Flush out the current batch.
|
||||
*/
|
||||
private readonly flush = (): void => {
|
||||
clearTimeout(this.idleTimeout as any);
|
||||
clearTimeout(this.maxTimeout as any);
|
||||
this.maxTimeout = undefined;
|
||||
|
||||
const batch = this.batch;
|
||||
this.batch = [];
|
||||
|
||||
this.remoteCall(batch.map((q) => q.args)).then((results) => {
|
||||
batch.forEach((item, i) => {
|
||||
const result = results[i];
|
||||
if (result && result instanceof Error) {
|
||||
item.reject(result);
|
||||
} else {
|
||||
item.resolve(result);
|
||||
}
|
||||
});
|
||||
}).catch((error) => batch.forEach((item) => item.reject(error)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Module as ProtoModule, WorkingInitMessage } from "../proto";
|
||||
import { Argument, Module as ProtoModule, WorkingInit } from "../proto";
|
||||
import { OperatingSystem } from "../common/connection";
|
||||
import { Module, ServerProxy } from "./proxy";
|
||||
|
||||
@@ -29,227 +29,151 @@ export type IEncodingOptions = {
|
||||
|
||||
export type IEncodingOptionsCallback = IEncodingOptions | ((err: NodeJS.ErrnoException, ...args: any[]) => void);
|
||||
|
||||
interface StringifiedError {
|
||||
type: "error";
|
||||
data: {
|
||||
message: string;
|
||||
stack?: string;
|
||||
code?: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface StringifiedBuffer {
|
||||
type: "buffer";
|
||||
data: number[];
|
||||
}
|
||||
|
||||
interface StringifiedObject {
|
||||
type: "object";
|
||||
data: { [key: string]: StringifiedValue };
|
||||
}
|
||||
|
||||
interface StringifiedArray {
|
||||
type: "array";
|
||||
data: StringifiedValue[];
|
||||
}
|
||||
|
||||
interface StringifiedProxy {
|
||||
type: "proxy";
|
||||
data: {
|
||||
id: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface StringifiedFunction {
|
||||
type: "function";
|
||||
data: {
|
||||
id: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface StringifiedUndefined {
|
||||
type: "undefined";
|
||||
}
|
||||
|
||||
type StringifiedValue = StringifiedFunction | StringifiedProxy
|
||||
| StringifiedUndefined | StringifiedObject | StringifiedArray
|
||||
| StringifiedBuffer | StringifiedError | number | string | boolean | null;
|
||||
|
||||
const isPrimitive = (value: any): value is number | string | boolean | null => {
|
||||
return typeof value === "number"
|
||||
|| typeof value === "string"
|
||||
|| typeof value === "boolean"
|
||||
|| value === null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stringify an argument or a return value.
|
||||
* Convert an argument to proto.
|
||||
* If sending a function is possible, provide `storeFunction`.
|
||||
* If sending a proxy is possible, provide `storeProxy`.
|
||||
*/
|
||||
export const stringify = (
|
||||
export const argumentToProto = (
|
||||
value: any,
|
||||
storeFunction?: (fn: () => void) => number,
|
||||
storeProxy?: (proxy: ServerProxy) => number,
|
||||
): string => {
|
||||
const convert = (currentValue: any): StringifiedValue => {
|
||||
// Errors don't stringify at all. They just become "{}".
|
||||
// For some reason when running in Jest errors aren't instances of Error,
|
||||
// so also check against the values.
|
||||
): Argument => {
|
||||
const convert = (currentValue: any): Argument => {
|
||||
const message = new Argument();
|
||||
|
||||
if (currentValue instanceof Error
|
||||
|| (currentValue && typeof currentValue.message !== "undefined"
|
||||
&& typeof currentValue.stack !== "undefined")) {
|
||||
return {
|
||||
type: "error",
|
||||
data: {
|
||||
message: currentValue.message,
|
||||
stack: currentValue.stack,
|
||||
code: (currentValue as NodeJS.ErrnoException).code,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// With stringify, Uint8Array gets turned into objects with each index
|
||||
// becoming a key for some reason. Then trying to do something like write
|
||||
// that data results in [object Object] being written. Stringify them like
|
||||
// a Buffer instead. Also handle Buffer so it doesn't get caught by the
|
||||
// object check and to get the same type.
|
||||
if (currentValue instanceof Uint8Array || currentValue instanceof Buffer) {
|
||||
return {
|
||||
type: "buffer",
|
||||
data: Array.from(currentValue),
|
||||
};
|
||||
}
|
||||
|
||||
if (Array.isArray(currentValue)) {
|
||||
return {
|
||||
type: "array",
|
||||
data: currentValue.map((a) => convert(a)),
|
||||
};
|
||||
}
|
||||
|
||||
if (isProxy(currentValue)) {
|
||||
const arg = new Argument.ErrorValue();
|
||||
arg.setMessage(currentValue.message);
|
||||
arg.setStack(currentValue.stack);
|
||||
arg.setCode(currentValue.code);
|
||||
message.setError(arg);
|
||||
} else if (currentValue instanceof Uint8Array || currentValue instanceof Buffer) {
|
||||
const arg = new Argument.BufferValue();
|
||||
arg.setData(currentValue);
|
||||
message.setBuffer(arg);
|
||||
} else if (Array.isArray(currentValue)) {
|
||||
const arg = new Argument.ArrayValue();
|
||||
arg.setDataList(currentValue.map(convert));
|
||||
message.setArray(arg);
|
||||
} else if (isProxy(currentValue)) {
|
||||
if (!storeProxy) {
|
||||
throw new Error("no way to serialize proxy");
|
||||
}
|
||||
|
||||
return {
|
||||
type: "proxy",
|
||||
data: {
|
||||
id: storeProxy(currentValue),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (currentValue !== null && typeof currentValue === "object") {
|
||||
const converted: { [key: string]: StringifiedValue } = {};
|
||||
const arg = new Argument.ProxyValue();
|
||||
arg.setId(storeProxy(currentValue));
|
||||
message.setProxy(arg);
|
||||
} else if (currentValue instanceof Date
|
||||
|| (currentValue && typeof currentValue.getTime === "function")) {
|
||||
const arg = new Argument.DateValue();
|
||||
arg.setDate(currentValue.toString());
|
||||
message.setDate(arg);
|
||||
} else if (currentValue !== null && typeof currentValue === "object") {
|
||||
const arg = new Argument.ObjectValue();
|
||||
const map = arg.getDataMap();
|
||||
Object.keys(currentValue).forEach((key) => {
|
||||
converted[key] = convert(currentValue[key]);
|
||||
map.set(key, convert(currentValue[key]));
|
||||
});
|
||||
|
||||
return {
|
||||
type: "object",
|
||||
data: converted,
|
||||
};
|
||||
}
|
||||
|
||||
// `undefined` can't be stringified.
|
||||
if (typeof currentValue === "undefined") {
|
||||
return {
|
||||
type: "undefined",
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof currentValue === "function") {
|
||||
if (!storeFunction) {
|
||||
throw new Error("no way to serialize function");
|
||||
message.setObject(arg);
|
||||
} else if (currentValue === null) {
|
||||
message.setNull(new Argument.NullValue());
|
||||
} else {
|
||||
switch (typeof currentValue) {
|
||||
case "undefined":
|
||||
message.setUndefined(new Argument.UndefinedValue());
|
||||
break;
|
||||
case "function":
|
||||
if (!storeFunction) {
|
||||
throw new Error("no way to serialize function");
|
||||
}
|
||||
const arg = new Argument.FunctionValue();
|
||||
arg.setId(storeFunction(currentValue));
|
||||
message.setFunction(arg);
|
||||
break;
|
||||
case "number":
|
||||
message.setNumber(currentValue);
|
||||
break;
|
||||
case "string":
|
||||
message.setString(currentValue);
|
||||
break;
|
||||
case "boolean":
|
||||
message.setBoolean(currentValue);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`cannot convert ${typeof currentValue} to proto`);
|
||||
}
|
||||
|
||||
return {
|
||||
type: "function",
|
||||
data: {
|
||||
id: storeFunction(currentValue),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (!isPrimitive(currentValue)) {
|
||||
throw new Error(`cannot stringify ${typeof currentValue}`);
|
||||
}
|
||||
|
||||
return currentValue;
|
||||
return message;
|
||||
};
|
||||
|
||||
return JSON.stringify(convert(value));
|
||||
return convert(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse an argument.
|
||||
* Convert proto to an argument.
|
||||
* If running a remote callback is supported, provide `runCallback`.
|
||||
* If using a remote proxy is supported, provide `createProxy`.
|
||||
*/
|
||||
export const parse = (
|
||||
value?: string,
|
||||
export const protoToArgument = (
|
||||
message?: Argument,
|
||||
runCallback?: (id: number, args: any[]) => void,
|
||||
createProxy?: (id: number) => ServerProxy,
|
||||
): any => {
|
||||
const convert = (currentValue: StringifiedValue): any => {
|
||||
if (currentValue && !isPrimitive(currentValue)) {
|
||||
// Would prefer a switch but the types don't seem to work.
|
||||
if (currentValue.type === "buffer") {
|
||||
return Buffer.from(currentValue.data);
|
||||
}
|
||||
|
||||
if (currentValue.type === "error") {
|
||||
const error = new Error(currentValue.data.message);
|
||||
if (typeof currentValue.data.code !== "undefined") {
|
||||
(error as NodeJS.ErrnoException).code = currentValue.data.code;
|
||||
}
|
||||
(error as any).originalStack = currentValue.data.stack;
|
||||
const convert = (currentMessage: Argument): any => {
|
||||
switch (currentMessage.getMsgCase()) {
|
||||
case Argument.MsgCase.ERROR:
|
||||
const errorMessage = currentMessage.getError()!;
|
||||
const error = new Error(errorMessage.getMessage());
|
||||
(error as NodeJS.ErrnoException).code = errorMessage.getCode();
|
||||
(error as any).originalStack = errorMessage.getStack();
|
||||
|
||||
return error;
|
||||
}
|
||||
case Argument.MsgCase.BUFFER:
|
||||
return Buffer.from(currentMessage.getBuffer()!.getData() as Uint8Array);
|
||||
case Argument.MsgCase.ARRAY:
|
||||
return currentMessage.getArray()!.getDataList().map((a) => convert(a));
|
||||
case Argument.MsgCase.PROXY:
|
||||
if (!createProxy) {
|
||||
throw new Error("no way to create proxy");
|
||||
}
|
||||
|
||||
if (currentValue.type === "object") {
|
||||
const converted: { [key: string]: any } = {};
|
||||
Object.keys(currentValue.data).forEach((key) => {
|
||||
converted[key] = convert(currentValue.data[key]);
|
||||
return createProxy(currentMessage.getProxy()!.getId());
|
||||
case Argument.MsgCase.DATE:
|
||||
return new Date(currentMessage.getDate()!.getDate());
|
||||
case Argument.MsgCase.OBJECT:
|
||||
const obj: { [Key: string]: any } = {};
|
||||
currentMessage.getObject()!.getDataMap().forEach((argument, key) => {
|
||||
obj[key] = convert(argument);
|
||||
});
|
||||
|
||||
return converted;
|
||||
}
|
||||
|
||||
if (currentValue.type === "array") {
|
||||
return currentValue.data.map(convert);
|
||||
}
|
||||
|
||||
if (currentValue.type === "undefined") {
|
||||
return obj;
|
||||
case Argument.MsgCase.UNDEFINED:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (currentValue.type === "function") {
|
||||
case Argument.MsgCase.NULL:
|
||||
return null;
|
||||
case Argument.MsgCase.FUNCTION:
|
||||
if (!runCallback) {
|
||||
throw new Error("no way to run remote callback");
|
||||
}
|
||||
|
||||
return (...args: any[]): void => {
|
||||
return runCallback(currentValue.data.id, args);
|
||||
return runCallback(currentMessage.getFunction()!.getId(), args);
|
||||
};
|
||||
}
|
||||
|
||||
if (currentValue.type === "proxy") {
|
||||
if (!createProxy) {
|
||||
throw new Error("no way to create proxy");
|
||||
}
|
||||
|
||||
return createProxy(currentValue.data.id);
|
||||
}
|
||||
case Argument.MsgCase.NUMBER:
|
||||
return currentMessage.getNumber();
|
||||
case Argument.MsgCase.STRING:
|
||||
return currentMessage.getString();
|
||||
case Argument.MsgCase.BOOLEAN:
|
||||
return currentMessage.getBoolean();
|
||||
default:
|
||||
throw new Error("cannot convert unexpected proto to argument");
|
||||
}
|
||||
|
||||
return currentValue;
|
||||
};
|
||||
|
||||
return value && convert(JSON.parse(value));
|
||||
return message && convert(message);
|
||||
};
|
||||
|
||||
export const protoToModule = (protoModule: ProtoModule): Module => {
|
||||
@@ -276,20 +200,20 @@ export const moduleToProto = (moduleName: Module): ProtoModule => {
|
||||
}
|
||||
};
|
||||
|
||||
export const protoToOperatingSystem = (protoOp: WorkingInitMessage.OperatingSystem): OperatingSystem => {
|
||||
export const protoToOperatingSystem = (protoOp: WorkingInit.OperatingSystem): OperatingSystem => {
|
||||
switch (protoOp) {
|
||||
case WorkingInitMessage.OperatingSystem.WINDOWS: return OperatingSystem.Windows;
|
||||
case WorkingInitMessage.OperatingSystem.LINUX: return OperatingSystem.Linux;
|
||||
case WorkingInitMessage.OperatingSystem.MAC: return OperatingSystem.Mac;
|
||||
case WorkingInit.OperatingSystem.WINDOWS: return OperatingSystem.Windows;
|
||||
case WorkingInit.OperatingSystem.LINUX: return OperatingSystem.Linux;
|
||||
case WorkingInit.OperatingSystem.MAC: return OperatingSystem.Mac;
|
||||
default: throw new Error(`unsupported operating system ${protoOp}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const platformToProto = (platform: NodeJS.Platform): WorkingInitMessage.OperatingSystem => {
|
||||
export const platformToProto = (platform: NodeJS.Platform): WorkingInit.OperatingSystem => {
|
||||
switch (platform) {
|
||||
case "win32": return WorkingInitMessage.OperatingSystem.WINDOWS;
|
||||
case "linux": return WorkingInitMessage.OperatingSystem.LINUX;
|
||||
case "darwin": return WorkingInitMessage.OperatingSystem.MAC;
|
||||
case "win32": return WorkingInit.OperatingSystem.WINDOWS;
|
||||
case "linux": return WorkingInit.OperatingSystem.LINUX;
|
||||
case "darwin": return WorkingInit.OperatingSystem.MAC;
|
||||
default: throw new Error(`unrecognized platform "${platform}"`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,6 +3,8 @@ import { ServerProxy } from "../../common/proxy";
|
||||
import { preserveEnv } from "../../common/util";
|
||||
import { WritableProxy, ReadableProxy } from "./stream";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export type ForkProvider = (modulePath: string, args?: string[], options?: cp.ForkOptions) => cp.ChildProcess;
|
||||
|
||||
export class ChildProcessProxy implements ServerProxy {
|
||||
@@ -26,7 +28,7 @@ export class ChildProcessProxy implements ServerProxy {
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async send(message: any): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise((resolve, reject): void => {
|
||||
this.process.send(message, (error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
@@ -46,8 +48,8 @@ export class ChildProcessProxy implements ServerProxy {
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
this.kill();
|
||||
setTimeout(() => this.kill("SIGKILL"), 5000); // Double tap.
|
||||
this.process.kill();
|
||||
setTimeout(() => this.process.kill("SIGKILL"), 5000); // Double tap.
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
@@ -62,9 +64,9 @@ export class ChildProcessProxy implements ServerProxy {
|
||||
|
||||
export interface ChildProcessProxies {
|
||||
childProcess: ChildProcessProxy;
|
||||
stdin?: WritableProxy;
|
||||
stdout?: ReadableProxy;
|
||||
stderr?: ReadableProxy;
|
||||
stdin?: WritableProxy | null;
|
||||
stdout?: ReadableProxy | null;
|
||||
stderr?: ReadableProxy | null;
|
||||
}
|
||||
|
||||
export class ChildProcessModuleProxy {
|
||||
|
||||
@@ -4,6 +4,8 @@ import { ServerProxy } from "../../common/proxy";
|
||||
import { IEncodingOptions } from "../../common/util";
|
||||
import { WritableProxy } from "./stream";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
/**
|
||||
* A serializable version of fs.Stats.
|
||||
*/
|
||||
@@ -22,10 +24,10 @@ export interface Stats {
|
||||
mtimeMs: number;
|
||||
ctimeMs: number;
|
||||
birthtimeMs: number;
|
||||
atime: Date | string;
|
||||
mtime: Date | string;
|
||||
ctime: Date | string;
|
||||
birthtime: Date | string;
|
||||
atime: Date;
|
||||
mtime: Date;
|
||||
ctime: Date;
|
||||
birthtime: Date;
|
||||
_isFile: boolean;
|
||||
_isDirectory: boolean;
|
||||
_isBlockDevice: boolean;
|
||||
@@ -41,13 +43,13 @@ export class WriteStreamProxy extends WritableProxy<fs.WriteStream> {
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
super.dispose();
|
||||
await super.dispose();
|
||||
this.stream.close();
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
super.onEvent(cb);
|
||||
await super.onEvent(cb);
|
||||
this.stream.on("open", (fd) => cb("open", fd));
|
||||
}
|
||||
}
|
||||
@@ -109,7 +111,7 @@ export class FsModuleProxy {
|
||||
}
|
||||
|
||||
public exists(path: fs.PathLike): Promise<boolean> {
|
||||
return promisify(fs.exists)(path);
|
||||
return promisify(fs.exists)(path); // tslint:disable-line deprecation
|
||||
}
|
||||
|
||||
public fchmod(fd: number, mode: string | number): Promise<void> {
|
||||
@@ -156,6 +158,10 @@ export class FsModuleProxy {
|
||||
return this.makeStatsSerializable(await promisify(fs.lstat)(path));
|
||||
}
|
||||
|
||||
public async lstatBatch(args: { path: fs.PathLike }[]): Promise<(Stats | Error)[]> {
|
||||
return Promise.all(args.map((a) => this.lstat(a.path).catch((e) => e)));
|
||||
}
|
||||
|
||||
public mkdir(path: fs.PathLike, mode: number | string | fs.MakeDirectoryOptions | undefined | null): Promise<void> {
|
||||
return promisify(fs.mkdir)(path, mode);
|
||||
}
|
||||
@@ -169,7 +175,7 @@ export class FsModuleProxy {
|
||||
}
|
||||
|
||||
public read(fd: number, length: number, position: number | null): Promise<{ bytesRead: number, buffer: Buffer }> {
|
||||
const buffer = new Buffer(length);
|
||||
const buffer = Buffer.alloc(length);
|
||||
|
||||
return promisify(fs.read)(fd, buffer, 0, length, position);
|
||||
}
|
||||
@@ -182,6 +188,10 @@ export class FsModuleProxy {
|
||||
return promisify(fs.readdir)(path, options);
|
||||
}
|
||||
|
||||
public readdirBatch(args: { path: fs.PathLike, options: IEncodingOptions }[]): Promise<(Buffer[] | fs.Dirent[] | string[] | Error)[]> {
|
||||
return Promise.all(args.map((a) => this.readdir(a.path, a.options).catch((e) => e)));
|
||||
}
|
||||
|
||||
public readlink(path: fs.PathLike, options: IEncodingOptions): Promise<string | Buffer> {
|
||||
return promisify(fs.readlink)(path, options);
|
||||
}
|
||||
@@ -202,6 +212,10 @@ export class FsModuleProxy {
|
||||
return this.makeStatsSerializable(await promisify(fs.stat)(path));
|
||||
}
|
||||
|
||||
public async statBatch(args: { path: fs.PathLike }[]): Promise<(Stats | Error)[]> {
|
||||
return Promise.all(args.map((a) => this.stat(a.path).catch((e) => e)));
|
||||
}
|
||||
|
||||
public symlink(target: fs.PathLike, path: fs.PathLike, type?: fs.symlink.Type | null): Promise<void> {
|
||||
return promisify(fs.symlink)(target, path, type);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import * as net from "net";
|
||||
import { ServerProxy } from "../../common/proxy";
|
||||
import { DuplexProxy } from "./stream";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class NetSocketProxy extends DuplexProxy<net.Socket> {
|
||||
public async connect(options: number | string | net.SocketConnectOpts, host?: string): Promise<void> {
|
||||
this.stream.connect(options as any, host as any); // tslint:disable-line no-any this works fine
|
||||
@@ -28,7 +30,7 @@ export class NetSocketProxy extends DuplexProxy<net.Socket> {
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
super.onEvent(cb);
|
||||
await super.onEvent(cb);
|
||||
this.stream.on("connect", () => cb("connect"));
|
||||
this.stream.on("lookup", (error, address, family, host) => cb("lookup", error, address, family, host));
|
||||
this.stream.on("timeout", () => cb("timeout"));
|
||||
|
||||
@@ -4,6 +4,8 @@ import * as pty from "node-pty";
|
||||
import { ServerProxy } from "../../common/proxy";
|
||||
import { preserveEnv } from "../../common/util";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
/**
|
||||
* Server-side IPty proxy.
|
||||
*/
|
||||
@@ -22,7 +24,7 @@ export class NodePtyProcessProxy implements ServerProxy {
|
||||
}
|
||||
}, 200);
|
||||
|
||||
this.onDone(() => clearInterval(timer));
|
||||
this.process.on("exit", () => clearInterval(timer));
|
||||
}
|
||||
|
||||
public async getPid(): Promise<number> {
|
||||
@@ -50,8 +52,8 @@ export class NodePtyProcessProxy implements ServerProxy {
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
this.kill();
|
||||
setTimeout(() => this.kill("SIGKILL"), 5000); // Double tap.
|
||||
this.process.kill();
|
||||
setTimeout(() => this.process.kill("SIGKILL"), 5000); // Double tap.
|
||||
this.emitter.removeAllListeners();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ import { EventEmitter } from "events";
|
||||
import * as spdlog from "spdlog";
|
||||
import { ServerProxy } from "../../common/proxy";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class RotatingLoggerProxy implements ServerProxy {
|
||||
private readonly emitter = new EventEmitter();
|
||||
|
||||
@@ -24,7 +26,7 @@ export class RotatingLoggerProxy implements ServerProxy {
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
this.flush();
|
||||
await this.flush();
|
||||
this.emitter.emit("dispose");
|
||||
this.emitter.removeAllListeners();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import * as stream from "stream";
|
||||
import { ServerProxy } from "../../common/proxy";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class WritableProxy<T extends stream.Writable = stream.Writable> implements ServerProxy {
|
||||
public constructor(protected readonly stream: T) {}
|
||||
|
||||
@@ -100,7 +102,7 @@ export class DuplexProxy<T extends stream.Duplex = stream.Duplex> extends Writab
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
super.onEvent(cb);
|
||||
await super.onEvent(cb);
|
||||
this.stream.on("data", (chunk) => cb("data", chunk));
|
||||
this.stream.on("end", () => cb("end"));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import * as trash from "trash";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class TrashModuleProxy {
|
||||
public async trash(path: string, options?: trash.Options): Promise<void> {
|
||||
return trash(path, options);
|
||||
|
||||
@@ -3,8 +3,8 @@ import * as os from "os";
|
||||
import { field, logger} from "@coder/logger";
|
||||
import { ReadWriteConnection } from "../common/connection";
|
||||
import { Module, ServerProxy } from "../common/proxy";
|
||||
import { isPromise, isProxy, moduleToProto, parse, platformToProto, protoToModule, stringify } from "../common/util";
|
||||
import { CallbackMessage, ClientMessage, EventMessage, FailMessage, MethodMessage, NamedCallbackMessage, NamedEventMessage, NumberedCallbackMessage, NumberedEventMessage, Pong, ServerMessage, SuccessMessage, WorkingInitMessage } from "../proto";
|
||||
import { isPromise, isProxy, moduleToProto, protoToArgument, platformToProto, protoToModule, argumentToProto } from "../common/util";
|
||||
import { Argument, Callback, ClientMessage, Event, Method, Pong, ServerMessage, WorkingInit } from "../proto";
|
||||
import { ChildProcessModuleProxy, ForkProvider, FsModuleProxy, NetModuleProxy, NodePtyModuleProxy, SpdlogModuleProxy, TrashModuleProxy } from "./modules";
|
||||
|
||||
// tslint:disable no-any
|
||||
@@ -14,6 +14,7 @@ export interface ServerOptions {
|
||||
readonly dataDirectory: string;
|
||||
readonly cacheDirectory: string;
|
||||
readonly builtInExtensionsDirectory: string;
|
||||
readonly extensionsDirectory: string;
|
||||
readonly fork?: ForkProvider;
|
||||
}
|
||||
|
||||
@@ -22,11 +23,14 @@ interface ProxyData {
|
||||
instance: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle messages from the client.
|
||||
*/
|
||||
export class Server {
|
||||
private proxyId = 0;
|
||||
private readonly proxies = new Map<number | Module, ProxyData>();
|
||||
private disconnected: boolean = false;
|
||||
private responseTimeout = 10000;
|
||||
private readonly responseTimeout = 10000;
|
||||
|
||||
public constructor(
|
||||
private readonly connection: ReadWriteConnection,
|
||||
@@ -57,7 +61,9 @@ export class Server {
|
||||
|
||||
this.proxies.forEach((proxy, proxyId) => {
|
||||
if (isProxy(proxy.instance)) {
|
||||
proxy.instance.dispose();
|
||||
proxy.instance.dispose().catch((error) => {
|
||||
logger.error(error.message);
|
||||
});
|
||||
}
|
||||
this.removeProxy(proxyId);
|
||||
});
|
||||
@@ -84,14 +90,15 @@ export class Server {
|
||||
logger.error(error.message, field("error", error));
|
||||
});
|
||||
|
||||
const initMsg = new WorkingInitMessage();
|
||||
const initMsg = new WorkingInit();
|
||||
initMsg.setDataDirectory(this.options.dataDirectory);
|
||||
initMsg.setWorkingDirectory(this.options.workingDirectory);
|
||||
initMsg.setBuiltinExtensionsDir(this.options.builtInExtensionsDirectory);
|
||||
initMsg.setExtensionsDirectory(this.options.extensionsDirectory);
|
||||
initMsg.setHomeDirectory(os.homedir());
|
||||
initMsg.setTmpDirectory(os.tmpdir());
|
||||
initMsg.setOperatingSystem(platformToProto(os.platform()));
|
||||
initMsg.setShell(os.userInfo().shell || global.process.env.SHELL);
|
||||
initMsg.setShell(os.userInfo().shell || global.process.env.SHELL || "");
|
||||
const srvMsg = new ServerMessage();
|
||||
srvMsg.setInit(initMsg);
|
||||
connection.send(srvMsg.serializeBinary());
|
||||
@@ -101,29 +108,32 @@ export class Server {
|
||||
* Handle all messages from the client.
|
||||
*/
|
||||
private async handleMessage(message: ClientMessage): Promise<void> {
|
||||
if (message.hasMethod()) {
|
||||
await this.runMethod(message.getMethod()!);
|
||||
} else if (message.hasPing()) {
|
||||
logger.trace("ping");
|
||||
const srvMsg = new ServerMessage();
|
||||
srvMsg.setPong(new Pong());
|
||||
this.connection.send(srvMsg.serializeBinary());
|
||||
} else {
|
||||
throw new Error("unknown message type");
|
||||
switch (message.getMsgCase()) {
|
||||
case ClientMessage.MsgCase.METHOD:
|
||||
await this.runMethod(message.getMethod()!);
|
||||
break;
|
||||
case ClientMessage.MsgCase.PING:
|
||||
logger.trace("ping");
|
||||
const srvMsg = new ServerMessage();
|
||||
srvMsg.setPong(new Pong());
|
||||
this.connection.send(srvMsg.serializeBinary());
|
||||
break;
|
||||
default:
|
||||
throw new Error("unknown message type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a method on a proxy.
|
||||
*/
|
||||
private async runMethod(message: MethodMessage): Promise<void> {
|
||||
private async runMethod(message: Method): Promise<void> {
|
||||
const proxyMessage = message.getNamedProxy()! || message.getNumberedProxy()!;
|
||||
const id = proxyMessage.getId();
|
||||
const proxyId = message.hasNamedProxy()
|
||||
? protoToModule(message.getNamedProxy()!.getModule())
|
||||
: message.getNumberedProxy()!.getProxyId();
|
||||
const method = proxyMessage.getMethod();
|
||||
const args = proxyMessage.getArgsList().map((a) => parse(
|
||||
const args = proxyMessage.getArgsList().map((a) => protoToArgument(
|
||||
a,
|
||||
(id, args) => this.sendCallback(proxyId, id, args),
|
||||
));
|
||||
@@ -133,14 +143,13 @@ export class Server {
|
||||
field("id", id),
|
||||
field("proxyId", proxyId),
|
||||
field("method", method),
|
||||
field("args", proxyMessage.getArgsList()),
|
||||
]);
|
||||
|
||||
let response: any;
|
||||
try {
|
||||
const proxy = this.getProxy(proxyId);
|
||||
if (typeof proxy.instance[method] !== "function") {
|
||||
throw new Error(`"${method}" is not a function`);
|
||||
throw new Error(`"${method}" is not a function on proxy ${proxyId}`);
|
||||
}
|
||||
|
||||
response = proxy.instance[method](...args);
|
||||
@@ -153,7 +162,7 @@ export class Server {
|
||||
|
||||
// Proxies must always return promises.
|
||||
if (!isPromise(response)) {
|
||||
throw new Error('"${method}" must return a promise');
|
||||
throw new Error(`"${method}" must return a promise`);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
@@ -175,27 +184,25 @@ export class Server {
|
||||
* Send a callback to the client.
|
||||
*/
|
||||
private sendCallback(proxyId: number | Module, callbackId: number, args: any[]): void {
|
||||
const stringifiedArgs = args.map((a) => this.stringify(a));
|
||||
logger.trace(() => [
|
||||
"sending callback",
|
||||
field("proxyId", proxyId),
|
||||
field("callbackId", callbackId),
|
||||
field("args", stringifiedArgs),
|
||||
]);
|
||||
|
||||
const message = new CallbackMessage();
|
||||
let callbackMessage: NamedCallbackMessage | NumberedCallbackMessage;
|
||||
const message = new Callback();
|
||||
let callbackMessage: Callback.Named | Callback.Numbered;
|
||||
if (typeof proxyId === "string") {
|
||||
callbackMessage = new NamedCallbackMessage();
|
||||
callbackMessage = new Callback.Named();
|
||||
callbackMessage.setModule(moduleToProto(proxyId));
|
||||
message.setNamedCallback(callbackMessage);
|
||||
} else {
|
||||
callbackMessage = new NumberedCallbackMessage();
|
||||
callbackMessage = new Callback.Numbered();
|
||||
callbackMessage.setProxyId(proxyId);
|
||||
message.setNumberedCallback(callbackMessage);
|
||||
}
|
||||
callbackMessage.setCallbackId(callbackId);
|
||||
callbackMessage.setArgsList(stringifiedArgs);
|
||||
callbackMessage.setArgsList(args.map((a) => this.argumentToProto(a)));
|
||||
|
||||
const serverMessage = new ServerMessage();
|
||||
serverMessage.setCallback(message);
|
||||
@@ -203,15 +210,23 @@ export class Server {
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a proxy and bind events to send them back to the client.
|
||||
* Store a numbered proxy and bind events to send them back to the client.
|
||||
*/
|
||||
private storeProxy(instance: ServerProxy): number;
|
||||
/**
|
||||
* Store a unique proxy and bind events to send them back to the client.
|
||||
*/
|
||||
private storeProxy(instance: any, moduleProxyId: Module): Module;
|
||||
/**
|
||||
* Store a proxy and bind events to send them back to the client.
|
||||
*/
|
||||
private storeProxy(instance: ServerProxy | any, moduleProxyId?: Module): number | Module {
|
||||
// In case we disposed while waiting for a function to return.
|
||||
if (this.disconnected) {
|
||||
if (isProxy(instance)) {
|
||||
instance.dispose();
|
||||
instance.dispose().catch((error) => {
|
||||
logger.error(error.message);
|
||||
});
|
||||
}
|
||||
|
||||
throw new Error("disposed");
|
||||
@@ -226,16 +241,22 @@ export class Server {
|
||||
this.proxies.set(proxyId, { instance });
|
||||
|
||||
if (isProxy(instance)) {
|
||||
instance.onEvent((event, ...args) => this.sendEvent(proxyId, event, ...args));
|
||||
instance.onEvent((event, ...args) => this.sendEvent(proxyId, event, ...args)).catch((error) => {
|
||||
logger.error(error.message);
|
||||
});
|
||||
instance.onDone(() => {
|
||||
// It might have finished because we disposed it due to a disconnect.
|
||||
if (!this.disconnected) {
|
||||
this.sendEvent(proxyId, "done");
|
||||
this.getProxy(proxyId).disposeTimeout = setTimeout(() => {
|
||||
instance.dispose();
|
||||
instance.dispose().catch((error) => {
|
||||
logger.error(error.message);
|
||||
});
|
||||
this.removeProxy(proxyId);
|
||||
}, this.responseTimeout);
|
||||
}
|
||||
}).catch((error) => {
|
||||
logger.error(error.message);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -246,27 +267,25 @@ export class Server {
|
||||
* Send an event to the client.
|
||||
*/
|
||||
private sendEvent(proxyId: number | Module, event: string, ...args: any[]): void {
|
||||
const stringifiedArgs = args.map((a) => this.stringify(a));
|
||||
logger.trace(() => [
|
||||
"sending event",
|
||||
field("proxyId", proxyId),
|
||||
field("event", event),
|
||||
field("args", stringifiedArgs),
|
||||
]);
|
||||
|
||||
const message = new EventMessage();
|
||||
let eventMessage: NamedEventMessage | NumberedEventMessage;
|
||||
const message = new Event();
|
||||
let eventMessage: Event.Named | Event.Numbered;
|
||||
if (typeof proxyId === "string") {
|
||||
eventMessage = new NamedEventMessage();
|
||||
eventMessage = new Event.Named();
|
||||
eventMessage.setModule(moduleToProto(proxyId));
|
||||
message.setNamedEvent(eventMessage);
|
||||
} else {
|
||||
eventMessage = new NumberedEventMessage();
|
||||
eventMessage = new Event.Numbered();
|
||||
eventMessage.setProxyId(proxyId);
|
||||
message.setNumberedEvent(eventMessage);
|
||||
}
|
||||
eventMessage.setEvent(event);
|
||||
eventMessage.setArgsList(stringifiedArgs);
|
||||
eventMessage.setArgsList(args.map((a) => this.argumentToProto(a)));
|
||||
|
||||
const serverMessage = new ServerMessage();
|
||||
serverMessage.setEvent(message);
|
||||
@@ -277,16 +296,14 @@ export class Server {
|
||||
* Send a response back to the client.
|
||||
*/
|
||||
private sendResponse(id: number, response: any): void {
|
||||
const stringifiedResponse = this.stringify(response);
|
||||
logger.trace(() => [
|
||||
"sending resolve",
|
||||
field("id", id),
|
||||
field("response", stringifiedResponse),
|
||||
]);
|
||||
|
||||
const successMessage = new SuccessMessage();
|
||||
const successMessage = new Method.Success();
|
||||
successMessage.setId(id);
|
||||
successMessage.setResponse(stringifiedResponse);
|
||||
successMessage.setResponse(this.argumentToProto(response));
|
||||
|
||||
const serverMessage = new ServerMessage();
|
||||
serverMessage.setSuccess(successMessage);
|
||||
@@ -297,16 +314,15 @@ export class Server {
|
||||
* Send an exception back to the client.
|
||||
*/
|
||||
private sendException(id: number, error: Error): void {
|
||||
const stringifiedError = stringify(error);
|
||||
logger.trace(() => [
|
||||
"sending reject",
|
||||
field("id", id) ,
|
||||
field("response", stringifiedError),
|
||||
field("message", error.message),
|
||||
]);
|
||||
|
||||
const failedMessage = new FailMessage();
|
||||
const failedMessage = new Method.Fail();
|
||||
failedMessage.setId(id);
|
||||
failedMessage.setResponse(stringifiedError);
|
||||
failedMessage.setResponse(argumentToProto(error));
|
||||
|
||||
const serverMessage = new ServerMessage();
|
||||
serverMessage.setFail(failedMessage);
|
||||
@@ -327,10 +343,16 @@ export class Server {
|
||||
]);
|
||||
}
|
||||
|
||||
private stringify(value: any): string {
|
||||
return stringify(value, undefined, (p) => this.storeProxy(p));
|
||||
/**
|
||||
* Same as argumentToProto but provides storeProxy.
|
||||
*/
|
||||
private argumentToProto(value: any): Argument {
|
||||
return argumentToProto(value, undefined, (p) => this.storeProxy(p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a proxy. Error if it doesn't exist.
|
||||
*/
|
||||
private getProxy(proxyId: number | Module): ProxyData {
|
||||
if (!this.proxies.has(proxyId)) {
|
||||
throw new Error(`proxy ${proxyId} disposed too early`);
|
||||
|
||||
@@ -6,7 +6,7 @@ import "vscode.proto";
|
||||
message ClientMessage {
|
||||
oneof msg {
|
||||
// node.proto
|
||||
MethodMessage method = 20;
|
||||
Method method = 20;
|
||||
Ping ping = 21;
|
||||
}
|
||||
}
|
||||
@@ -15,20 +15,20 @@ message ClientMessage {
|
||||
message ServerMessage {
|
||||
oneof msg {
|
||||
// node.proto
|
||||
FailMessage fail = 13;
|
||||
SuccessMessage success = 14;
|
||||
EventMessage event = 19;
|
||||
CallbackMessage callback = 22;
|
||||
Method.Fail fail = 13;
|
||||
Method.Success success = 14;
|
||||
Event event = 19;
|
||||
Callback callback = 22;
|
||||
Pong pong = 18;
|
||||
|
||||
WorkingInitMessage init = 16;
|
||||
WorkingInit init = 16;
|
||||
|
||||
// vscode.proto
|
||||
SharedProcessActiveMessage shared_process_active = 17;
|
||||
SharedProcessActive shared_process_active = 17;
|
||||
}
|
||||
}
|
||||
|
||||
message WorkingInitMessage {
|
||||
message WorkingInit {
|
||||
string home_directory = 1;
|
||||
string tmp_directory = 2;
|
||||
string data_directory = 3;
|
||||
@@ -41,4 +41,5 @@ message WorkingInitMessage {
|
||||
OperatingSystem operating_system = 5;
|
||||
string shell = 6;
|
||||
string builtin_extensions_dir = 7;
|
||||
string extensions_directory = 8;
|
||||
}
|
||||
|
||||
66
packages/protocol/src/proto/client_pb.d.ts
vendored
66
packages/protocol/src/proto/client_pb.d.ts
vendored
@@ -8,8 +8,8 @@ import * as vscode_pb from "./vscode_pb";
|
||||
export class ClientMessage extends jspb.Message {
|
||||
hasMethod(): boolean;
|
||||
clearMethod(): void;
|
||||
getMethod(): node_pb.MethodMessage | undefined;
|
||||
setMethod(value?: node_pb.MethodMessage): void;
|
||||
getMethod(): node_pb.Method | undefined;
|
||||
setMethod(value?: node_pb.Method): void;
|
||||
|
||||
hasPing(): boolean;
|
||||
clearPing(): void;
|
||||
@@ -29,7 +29,7 @@ export class ClientMessage extends jspb.Message {
|
||||
|
||||
export namespace ClientMessage {
|
||||
export type AsObject = {
|
||||
method?: node_pb.MethodMessage.AsObject,
|
||||
method?: node_pb.Method.AsObject,
|
||||
ping?: node_pb.Ping.AsObject,
|
||||
}
|
||||
|
||||
@@ -43,23 +43,23 @@ export namespace ClientMessage {
|
||||
export class ServerMessage extends jspb.Message {
|
||||
hasFail(): boolean;
|
||||
clearFail(): void;
|
||||
getFail(): node_pb.FailMessage | undefined;
|
||||
setFail(value?: node_pb.FailMessage): void;
|
||||
getFail(): node_pb.Method.Fail | undefined;
|
||||
setFail(value?: node_pb.Method.Fail): void;
|
||||
|
||||
hasSuccess(): boolean;
|
||||
clearSuccess(): void;
|
||||
getSuccess(): node_pb.SuccessMessage | undefined;
|
||||
setSuccess(value?: node_pb.SuccessMessage): void;
|
||||
getSuccess(): node_pb.Method.Success | undefined;
|
||||
setSuccess(value?: node_pb.Method.Success): void;
|
||||
|
||||
hasEvent(): boolean;
|
||||
clearEvent(): void;
|
||||
getEvent(): node_pb.EventMessage | undefined;
|
||||
setEvent(value?: node_pb.EventMessage): void;
|
||||
getEvent(): node_pb.Event | undefined;
|
||||
setEvent(value?: node_pb.Event): void;
|
||||
|
||||
hasCallback(): boolean;
|
||||
clearCallback(): void;
|
||||
getCallback(): node_pb.CallbackMessage | undefined;
|
||||
setCallback(value?: node_pb.CallbackMessage): void;
|
||||
getCallback(): node_pb.Callback | undefined;
|
||||
setCallback(value?: node_pb.Callback): void;
|
||||
|
||||
hasPong(): boolean;
|
||||
clearPong(): void;
|
||||
@@ -68,13 +68,13 @@ export class ServerMessage extends jspb.Message {
|
||||
|
||||
hasInit(): boolean;
|
||||
clearInit(): void;
|
||||
getInit(): WorkingInitMessage | undefined;
|
||||
setInit(value?: WorkingInitMessage): void;
|
||||
getInit(): WorkingInit | undefined;
|
||||
setInit(value?: WorkingInit): void;
|
||||
|
||||
hasSharedProcessActive(): boolean;
|
||||
clearSharedProcessActive(): void;
|
||||
getSharedProcessActive(): vscode_pb.SharedProcessActiveMessage | undefined;
|
||||
setSharedProcessActive(value?: vscode_pb.SharedProcessActiveMessage): void;
|
||||
getSharedProcessActive(): vscode_pb.SharedProcessActive | undefined;
|
||||
setSharedProcessActive(value?: vscode_pb.SharedProcessActive): void;
|
||||
|
||||
getMsgCase(): ServerMessage.MsgCase;
|
||||
serializeBinary(): Uint8Array;
|
||||
@@ -89,13 +89,13 @@ export class ServerMessage extends jspb.Message {
|
||||
|
||||
export namespace ServerMessage {
|
||||
export type AsObject = {
|
||||
fail?: node_pb.FailMessage.AsObject,
|
||||
success?: node_pb.SuccessMessage.AsObject,
|
||||
event?: node_pb.EventMessage.AsObject,
|
||||
callback?: node_pb.CallbackMessage.AsObject,
|
||||
fail?: node_pb.Method.Fail.AsObject,
|
||||
success?: node_pb.Method.Success.AsObject,
|
||||
event?: node_pb.Event.AsObject,
|
||||
callback?: node_pb.Callback.AsObject,
|
||||
pong?: node_pb.Pong.AsObject,
|
||||
init?: WorkingInitMessage.AsObject,
|
||||
sharedProcessActive?: vscode_pb.SharedProcessActiveMessage.AsObject,
|
||||
init?: WorkingInit.AsObject,
|
||||
sharedProcessActive?: vscode_pb.SharedProcessActive.AsObject,
|
||||
}
|
||||
|
||||
export enum MsgCase {
|
||||
@@ -110,7 +110,7 @@ export namespace ServerMessage {
|
||||
}
|
||||
}
|
||||
|
||||
export class WorkingInitMessage extends jspb.Message {
|
||||
export class WorkingInit extends jspb.Message {
|
||||
getHomeDirectory(): string;
|
||||
setHomeDirectory(value: string): void;
|
||||
|
||||
@@ -123,8 +123,8 @@ export class WorkingInitMessage extends jspb.Message {
|
||||
getWorkingDirectory(): string;
|
||||
setWorkingDirectory(value: string): void;
|
||||
|
||||
getOperatingSystem(): WorkingInitMessage.OperatingSystem;
|
||||
setOperatingSystem(value: WorkingInitMessage.OperatingSystem): void;
|
||||
getOperatingSystem(): WorkingInit.OperatingSystem;
|
||||
setOperatingSystem(value: WorkingInit.OperatingSystem): void;
|
||||
|
||||
getShell(): string;
|
||||
setShell(value: string): void;
|
||||
@@ -132,25 +132,29 @@ export class WorkingInitMessage extends jspb.Message {
|
||||
getBuiltinExtensionsDir(): string;
|
||||
setBuiltinExtensionsDir(value: string): void;
|
||||
|
||||
getExtensionsDirectory(): string;
|
||||
setExtensionsDirectory(value: string): void;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): WorkingInitMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: WorkingInitMessage): WorkingInitMessage.AsObject;
|
||||
toObject(includeInstance?: boolean): WorkingInit.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: WorkingInit): WorkingInit.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: WorkingInitMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): WorkingInitMessage;
|
||||
static deserializeBinaryFromReader(message: WorkingInitMessage, reader: jspb.BinaryReader): WorkingInitMessage;
|
||||
static serializeBinaryToWriter(message: WorkingInit, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): WorkingInit;
|
||||
static deserializeBinaryFromReader(message: WorkingInit, reader: jspb.BinaryReader): WorkingInit;
|
||||
}
|
||||
|
||||
export namespace WorkingInitMessage {
|
||||
export namespace WorkingInit {
|
||||
export type AsObject = {
|
||||
homeDirectory: string,
|
||||
tmpDirectory: string,
|
||||
dataDirectory: string,
|
||||
workingDirectory: string,
|
||||
operatingSystem: WorkingInitMessage.OperatingSystem,
|
||||
operatingSystem: WorkingInit.OperatingSystem,
|
||||
shell: string,
|
||||
builtinExtensionsDir: string,
|
||||
extensionsDirectory: string,
|
||||
}
|
||||
|
||||
export enum OperatingSystem {
|
||||
|
||||
@@ -12,12 +12,13 @@ var goog = jspb;
|
||||
var global = Function('return this')();
|
||||
|
||||
var node_pb = require('./node_pb.js');
|
||||
goog.object.extend(proto, node_pb);
|
||||
var vscode_pb = require('./vscode_pb.js');
|
||||
goog.object.extend(proto, vscode_pb);
|
||||
goog.exportSymbol('proto.ClientMessage', null, global);
|
||||
goog.exportSymbol('proto.ServerMessage', null, global);
|
||||
goog.exportSymbol('proto.WorkingInitMessage', null, global);
|
||||
goog.exportSymbol('proto.WorkingInitMessage.OperatingSystem', null, global);
|
||||
|
||||
goog.exportSymbol('proto.WorkingInit', null, global);
|
||||
goog.exportSymbol('proto.WorkingInit.OperatingSystem', null, global);
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
@@ -33,8 +34,55 @@ proto.ClientMessage = function(opt_data) {
|
||||
};
|
||||
goog.inherits(proto.ClientMessage, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.ClientMessage.displayName = 'proto.ClientMessage';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.ServerMessage = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, proto.ServerMessage.oneofGroups_);
|
||||
};
|
||||
goog.inherits(proto.ServerMessage, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.ServerMessage.displayName = 'proto.ServerMessage';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.WorkingInit = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.WorkingInit, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.WorkingInit.displayName = 'proto.WorkingInit';
|
||||
}
|
||||
|
||||
/**
|
||||
* Oneof group definitions for this message. Each group defines the field
|
||||
* numbers belonging to that group. When of these fields' value is set, all
|
||||
@@ -89,8 +137,8 @@ proto.ClientMessage.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.ClientMessage.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
method: (f = msg.getMethod()) && node_pb.MethodMessage.toObject(includeInstance, f),
|
||||
var obj = {
|
||||
method: (f = msg.getMethod()) && node_pb.Method.toObject(includeInstance, f),
|
||||
ping: (f = msg.getPing()) && node_pb.Ping.toObject(includeInstance, f)
|
||||
};
|
||||
|
||||
@@ -129,8 +177,8 @@ proto.ClientMessage.deserializeBinaryFromReader = function(msg, reader) {
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 20:
|
||||
var value = new node_pb.MethodMessage;
|
||||
reader.readMessage(value,node_pb.MethodMessage.deserializeBinaryFromReader);
|
||||
var value = new node_pb.Method;
|
||||
reader.readMessage(value,node_pb.Method.deserializeBinaryFromReader);
|
||||
msg.setMethod(value);
|
||||
break;
|
||||
case 21:
|
||||
@@ -172,7 +220,7 @@ proto.ClientMessage.serializeBinaryToWriter = function(message, writer) {
|
||||
writer.writeMessage(
|
||||
20,
|
||||
f,
|
||||
node_pb.MethodMessage.serializeBinaryToWriter
|
||||
node_pb.Method.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getPing();
|
||||
@@ -187,21 +235,24 @@ proto.ClientMessage.serializeBinaryToWriter = function(message, writer) {
|
||||
|
||||
|
||||
/**
|
||||
* optional MethodMessage method = 20;
|
||||
* @return {?proto.MethodMessage}
|
||||
* optional Method method = 20;
|
||||
* @return {?proto.Method}
|
||||
*/
|
||||
proto.ClientMessage.prototype.getMethod = function() {
|
||||
return /** @type{?proto.MethodMessage} */ (
|
||||
jspb.Message.getWrapperField(this, node_pb.MethodMessage, 20));
|
||||
return /** @type{?proto.Method} */ (
|
||||
jspb.Message.getWrapperField(this, node_pb.Method, 20));
|
||||
};
|
||||
|
||||
|
||||
/** @param {?proto.MethodMessage|undefined} value */
|
||||
/** @param {?proto.Method|undefined} value */
|
||||
proto.ClientMessage.prototype.setMethod = function(value) {
|
||||
jspb.Message.setOneofWrapperField(this, 20, proto.ClientMessage.oneofGroups_[0], value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
*/
|
||||
proto.ClientMessage.prototype.clearMethod = function() {
|
||||
this.setMethod(undefined);
|
||||
};
|
||||
@@ -209,7 +260,7 @@ proto.ClientMessage.prototype.clearMethod = function() {
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {!boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.ClientMessage.prototype.hasMethod = function() {
|
||||
return jspb.Message.getField(this, 20) != null;
|
||||
@@ -232,6 +283,9 @@ proto.ClientMessage.prototype.setPing = function(value) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
*/
|
||||
proto.ClientMessage.prototype.clearPing = function() {
|
||||
this.setPing(undefined);
|
||||
};
|
||||
@@ -239,7 +293,7 @@ proto.ClientMessage.prototype.clearPing = function() {
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {!boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.ClientMessage.prototype.hasPing = function() {
|
||||
return jspb.Message.getField(this, 21) != null;
|
||||
@@ -247,23 +301,6 @@ proto.ClientMessage.prototype.hasPing = function() {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.ServerMessage = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, proto.ServerMessage.oneofGroups_);
|
||||
};
|
||||
goog.inherits(proto.ServerMessage, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
proto.ServerMessage.displayName = 'proto.ServerMessage';
|
||||
}
|
||||
/**
|
||||
* Oneof group definitions for this message. Each group defines the field
|
||||
* numbers belonging to that group. When of these fields' value is set, all
|
||||
@@ -323,14 +360,14 @@ proto.ServerMessage.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.ServerMessage.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
fail: (f = msg.getFail()) && node_pb.FailMessage.toObject(includeInstance, f),
|
||||
success: (f = msg.getSuccess()) && node_pb.SuccessMessage.toObject(includeInstance, f),
|
||||
event: (f = msg.getEvent()) && node_pb.EventMessage.toObject(includeInstance, f),
|
||||
callback: (f = msg.getCallback()) && node_pb.CallbackMessage.toObject(includeInstance, f),
|
||||
var obj = {
|
||||
fail: (f = msg.getFail()) && node_pb.Method.Fail.toObject(includeInstance, f),
|
||||
success: (f = msg.getSuccess()) && node_pb.Method.Success.toObject(includeInstance, f),
|
||||
event: (f = msg.getEvent()) && node_pb.Event.toObject(includeInstance, f),
|
||||
callback: (f = msg.getCallback()) && node_pb.Callback.toObject(includeInstance, f),
|
||||
pong: (f = msg.getPong()) && node_pb.Pong.toObject(includeInstance, f),
|
||||
init: (f = msg.getInit()) && proto.WorkingInitMessage.toObject(includeInstance, f),
|
||||
sharedProcessActive: (f = msg.getSharedProcessActive()) && vscode_pb.SharedProcessActiveMessage.toObject(includeInstance, f)
|
||||
init: (f = msg.getInit()) && proto.WorkingInit.toObject(includeInstance, f),
|
||||
sharedProcessActive: (f = msg.getSharedProcessActive()) && vscode_pb.SharedProcessActive.toObject(includeInstance, f)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -368,23 +405,23 @@ proto.ServerMessage.deserializeBinaryFromReader = function(msg, reader) {
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 13:
|
||||
var value = new node_pb.FailMessage;
|
||||
reader.readMessage(value,node_pb.FailMessage.deserializeBinaryFromReader);
|
||||
var value = new node_pb.Method.Fail;
|
||||
reader.readMessage(value,node_pb.Method.Fail.deserializeBinaryFromReader);
|
||||
msg.setFail(value);
|
||||
break;
|
||||
case 14:
|
||||
var value = new node_pb.SuccessMessage;
|
||||
reader.readMessage(value,node_pb.SuccessMessage.deserializeBinaryFromReader);
|
||||
var value = new node_pb.Method.Success;
|
||||
reader.readMessage(value,node_pb.Method.Success.deserializeBinaryFromReader);
|
||||
msg.setSuccess(value);
|
||||
break;
|
||||
case 19:
|
||||
var value = new node_pb.EventMessage;
|
||||
reader.readMessage(value,node_pb.EventMessage.deserializeBinaryFromReader);
|
||||
var value = new node_pb.Event;
|
||||
reader.readMessage(value,node_pb.Event.deserializeBinaryFromReader);
|
||||
msg.setEvent(value);
|
||||
break;
|
||||
case 22:
|
||||
var value = new node_pb.CallbackMessage;
|
||||
reader.readMessage(value,node_pb.CallbackMessage.deserializeBinaryFromReader);
|
||||
var value = new node_pb.Callback;
|
||||
reader.readMessage(value,node_pb.Callback.deserializeBinaryFromReader);
|
||||
msg.setCallback(value);
|
||||
break;
|
||||
case 18:
|
||||
@@ -393,13 +430,13 @@ proto.ServerMessage.deserializeBinaryFromReader = function(msg, reader) {
|
||||
msg.setPong(value);
|
||||
break;
|
||||
case 16:
|
||||
var value = new proto.WorkingInitMessage;
|
||||
reader.readMessage(value,proto.WorkingInitMessage.deserializeBinaryFromReader);
|
||||
var value = new proto.WorkingInit;
|
||||
reader.readMessage(value,proto.WorkingInit.deserializeBinaryFromReader);
|
||||
msg.setInit(value);
|
||||
break;
|
||||
case 17:
|
||||
var value = new vscode_pb.SharedProcessActiveMessage;
|
||||
reader.readMessage(value,vscode_pb.SharedProcessActiveMessage.deserializeBinaryFromReader);
|
||||
var value = new vscode_pb.SharedProcessActive;
|
||||
reader.readMessage(value,vscode_pb.SharedProcessActive.deserializeBinaryFromReader);
|
||||
msg.setSharedProcessActive(value);
|
||||
break;
|
||||
default:
|
||||
@@ -436,7 +473,7 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
|
||||
writer.writeMessage(
|
||||
13,
|
||||
f,
|
||||
node_pb.FailMessage.serializeBinaryToWriter
|
||||
node_pb.Method.Fail.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getSuccess();
|
||||
@@ -444,7 +481,7 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
|
||||
writer.writeMessage(
|
||||
14,
|
||||
f,
|
||||
node_pb.SuccessMessage.serializeBinaryToWriter
|
||||
node_pb.Method.Success.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getEvent();
|
||||
@@ -452,7 +489,7 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
|
||||
writer.writeMessage(
|
||||
19,
|
||||
f,
|
||||
node_pb.EventMessage.serializeBinaryToWriter
|
||||
node_pb.Event.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getCallback();
|
||||
@@ -460,7 +497,7 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
|
||||
writer.writeMessage(
|
||||
22,
|
||||
f,
|
||||
node_pb.CallbackMessage.serializeBinaryToWriter
|
||||
node_pb.Callback.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getPong();
|
||||
@@ -476,7 +513,7 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
|
||||
writer.writeMessage(
|
||||
16,
|
||||
f,
|
||||
proto.WorkingInitMessage.serializeBinaryToWriter
|
||||
proto.WorkingInit.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getSharedProcessActive();
|
||||
@@ -484,28 +521,31 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
|
||||
writer.writeMessage(
|
||||
17,
|
||||
f,
|
||||
vscode_pb.SharedProcessActiveMessage.serializeBinaryToWriter
|
||||
vscode_pb.SharedProcessActive.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional FailMessage fail = 13;
|
||||
* @return {?proto.FailMessage}
|
||||
* optional Method.Fail fail = 13;
|
||||
* @return {?proto.Method.Fail}
|
||||
*/
|
||||
proto.ServerMessage.prototype.getFail = function() {
|
||||
return /** @type{?proto.FailMessage} */ (
|
||||
jspb.Message.getWrapperField(this, node_pb.FailMessage, 13));
|
||||
return /** @type{?proto.Method.Fail} */ (
|
||||
jspb.Message.getWrapperField(this, node_pb.Method.Fail, 13));
|
||||
};
|
||||
|
||||
|
||||
/** @param {?proto.FailMessage|undefined} value */
|
||||
/** @param {?proto.Method.Fail|undefined} value */
|
||||
proto.ServerMessage.prototype.setFail = function(value) {
|
||||
jspb.Message.setOneofWrapperField(this, 13, proto.ServerMessage.oneofGroups_[0], value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
*/
|
||||
proto.ServerMessage.prototype.clearFail = function() {
|
||||
this.setFail(undefined);
|
||||
};
|
||||
@@ -513,7 +553,7 @@ proto.ServerMessage.prototype.clearFail = function() {
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {!boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.ServerMessage.prototype.hasFail = function() {
|
||||
return jspb.Message.getField(this, 13) != null;
|
||||
@@ -521,21 +561,24 @@ proto.ServerMessage.prototype.hasFail = function() {
|
||||
|
||||
|
||||
/**
|
||||
* optional SuccessMessage success = 14;
|
||||
* @return {?proto.SuccessMessage}
|
||||
* optional Method.Success success = 14;
|
||||
* @return {?proto.Method.Success}
|
||||
*/
|
||||
proto.ServerMessage.prototype.getSuccess = function() {
|
||||
return /** @type{?proto.SuccessMessage} */ (
|
||||
jspb.Message.getWrapperField(this, node_pb.SuccessMessage, 14));
|
||||
return /** @type{?proto.Method.Success} */ (
|
||||
jspb.Message.getWrapperField(this, node_pb.Method.Success, 14));
|
||||
};
|
||||
|
||||
|
||||
/** @param {?proto.SuccessMessage|undefined} value */
|
||||
/** @param {?proto.Method.Success|undefined} value */
|
||||
proto.ServerMessage.prototype.setSuccess = function(value) {
|
||||
jspb.Message.setOneofWrapperField(this, 14, proto.ServerMessage.oneofGroups_[0], value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
*/
|
||||
proto.ServerMessage.prototype.clearSuccess = function() {
|
||||
this.setSuccess(undefined);
|
||||
};
|
||||
@@ -543,7 +586,7 @@ proto.ServerMessage.prototype.clearSuccess = function() {
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {!boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.ServerMessage.prototype.hasSuccess = function() {
|
||||
return jspb.Message.getField(this, 14) != null;
|
||||
@@ -551,21 +594,24 @@ proto.ServerMessage.prototype.hasSuccess = function() {
|
||||
|
||||
|
||||
/**
|
||||
* optional EventMessage event = 19;
|
||||
* @return {?proto.EventMessage}
|
||||
* optional Event event = 19;
|
||||
* @return {?proto.Event}
|
||||
*/
|
||||
proto.ServerMessage.prototype.getEvent = function() {
|
||||
return /** @type{?proto.EventMessage} */ (
|
||||
jspb.Message.getWrapperField(this, node_pb.EventMessage, 19));
|
||||
return /** @type{?proto.Event} */ (
|
||||
jspb.Message.getWrapperField(this, node_pb.Event, 19));
|
||||
};
|
||||
|
||||
|
||||
/** @param {?proto.EventMessage|undefined} value */
|
||||
/** @param {?proto.Event|undefined} value */
|
||||
proto.ServerMessage.prototype.setEvent = function(value) {
|
||||
jspb.Message.setOneofWrapperField(this, 19, proto.ServerMessage.oneofGroups_[0], value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
*/
|
||||
proto.ServerMessage.prototype.clearEvent = function() {
|
||||
this.setEvent(undefined);
|
||||
};
|
||||
@@ -573,7 +619,7 @@ proto.ServerMessage.prototype.clearEvent = function() {
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {!boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.ServerMessage.prototype.hasEvent = function() {
|
||||
return jspb.Message.getField(this, 19) != null;
|
||||
@@ -581,21 +627,24 @@ proto.ServerMessage.prototype.hasEvent = function() {
|
||||
|
||||
|
||||
/**
|
||||
* optional CallbackMessage callback = 22;
|
||||
* @return {?proto.CallbackMessage}
|
||||
* optional Callback callback = 22;
|
||||
* @return {?proto.Callback}
|
||||
*/
|
||||
proto.ServerMessage.prototype.getCallback = function() {
|
||||
return /** @type{?proto.CallbackMessage} */ (
|
||||
jspb.Message.getWrapperField(this, node_pb.CallbackMessage, 22));
|
||||
return /** @type{?proto.Callback} */ (
|
||||
jspb.Message.getWrapperField(this, node_pb.Callback, 22));
|
||||
};
|
||||
|
||||
|
||||
/** @param {?proto.CallbackMessage|undefined} value */
|
||||
/** @param {?proto.Callback|undefined} value */
|
||||
proto.ServerMessage.prototype.setCallback = function(value) {
|
||||
jspb.Message.setOneofWrapperField(this, 22, proto.ServerMessage.oneofGroups_[0], value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
*/
|
||||
proto.ServerMessage.prototype.clearCallback = function() {
|
||||
this.setCallback(undefined);
|
||||
};
|
||||
@@ -603,7 +652,7 @@ proto.ServerMessage.prototype.clearCallback = function() {
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {!boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.ServerMessage.prototype.hasCallback = function() {
|
||||
return jspb.Message.getField(this, 22) != null;
|
||||
@@ -626,6 +675,9 @@ proto.ServerMessage.prototype.setPong = function(value) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
*/
|
||||
proto.ServerMessage.prototype.clearPong = function() {
|
||||
this.setPong(undefined);
|
||||
};
|
||||
@@ -633,7 +685,7 @@ proto.ServerMessage.prototype.clearPong = function() {
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {!boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.ServerMessage.prototype.hasPong = function() {
|
||||
return jspb.Message.getField(this, 18) != null;
|
||||
@@ -641,21 +693,24 @@ proto.ServerMessage.prototype.hasPong = function() {
|
||||
|
||||
|
||||
/**
|
||||
* optional WorkingInitMessage init = 16;
|
||||
* @return {?proto.WorkingInitMessage}
|
||||
* optional WorkingInit init = 16;
|
||||
* @return {?proto.WorkingInit}
|
||||
*/
|
||||
proto.ServerMessage.prototype.getInit = function() {
|
||||
return /** @type{?proto.WorkingInitMessage} */ (
|
||||
jspb.Message.getWrapperField(this, proto.WorkingInitMessage, 16));
|
||||
return /** @type{?proto.WorkingInit} */ (
|
||||
jspb.Message.getWrapperField(this, proto.WorkingInit, 16));
|
||||
};
|
||||
|
||||
|
||||
/** @param {?proto.WorkingInitMessage|undefined} value */
|
||||
/** @param {?proto.WorkingInit|undefined} value */
|
||||
proto.ServerMessage.prototype.setInit = function(value) {
|
||||
jspb.Message.setOneofWrapperField(this, 16, proto.ServerMessage.oneofGroups_[0], value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
*/
|
||||
proto.ServerMessage.prototype.clearInit = function() {
|
||||
this.setInit(undefined);
|
||||
};
|
||||
@@ -663,7 +718,7 @@ proto.ServerMessage.prototype.clearInit = function() {
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {!boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.ServerMessage.prototype.hasInit = function() {
|
||||
return jspb.Message.getField(this, 16) != null;
|
||||
@@ -671,21 +726,24 @@ proto.ServerMessage.prototype.hasInit = function() {
|
||||
|
||||
|
||||
/**
|
||||
* optional SharedProcessActiveMessage shared_process_active = 17;
|
||||
* @return {?proto.SharedProcessActiveMessage}
|
||||
* optional SharedProcessActive shared_process_active = 17;
|
||||
* @return {?proto.SharedProcessActive}
|
||||
*/
|
||||
proto.ServerMessage.prototype.getSharedProcessActive = function() {
|
||||
return /** @type{?proto.SharedProcessActiveMessage} */ (
|
||||
jspb.Message.getWrapperField(this, vscode_pb.SharedProcessActiveMessage, 17));
|
||||
return /** @type{?proto.SharedProcessActive} */ (
|
||||
jspb.Message.getWrapperField(this, vscode_pb.SharedProcessActive, 17));
|
||||
};
|
||||
|
||||
|
||||
/** @param {?proto.SharedProcessActiveMessage|undefined} value */
|
||||
/** @param {?proto.SharedProcessActive|undefined} value */
|
||||
proto.ServerMessage.prototype.setSharedProcessActive = function(value) {
|
||||
jspb.Message.setOneofWrapperField(this, 17, proto.ServerMessage.oneofGroups_[0], value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
*/
|
||||
proto.ServerMessage.prototype.clearSharedProcessActive = function() {
|
||||
this.setSharedProcessActive(undefined);
|
||||
};
|
||||
@@ -693,7 +751,7 @@ proto.ServerMessage.prototype.clearSharedProcessActive = function() {
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {!boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.ServerMessage.prototype.hasSharedProcessActive = function() {
|
||||
return jspb.Message.getField(this, 17) != null;
|
||||
@@ -701,23 +759,6 @@ proto.ServerMessage.prototype.hasSharedProcessActive = function() {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.WorkingInitMessage = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.WorkingInitMessage, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
proto.WorkingInitMessage.displayName = 'proto.WorkingInitMessage';
|
||||
}
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
@@ -731,8 +772,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
* for transitional soy proto support: http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.WorkingInitMessage.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.WorkingInitMessage.toObject(opt_includeInstance, this);
|
||||
proto.WorkingInit.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.WorkingInit.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
@@ -741,19 +782,20 @@ proto.WorkingInitMessage.prototype.toObject = function(opt_includeInstance) {
|
||||
* @param {boolean|undefined} includeInstance Whether to include the JSPB
|
||||
* instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.WorkingInitMessage} msg The msg instance to transform.
|
||||
* @param {!proto.WorkingInit} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.WorkingInitMessage.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
proto.WorkingInit.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
homeDirectory: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
tmpDirectory: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
dataDirectory: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||
workingDirectory: jspb.Message.getFieldWithDefault(msg, 4, ""),
|
||||
operatingSystem: jspb.Message.getFieldWithDefault(msg, 5, 0),
|
||||
shell: jspb.Message.getFieldWithDefault(msg, 6, ""),
|
||||
builtinExtensionsDir: jspb.Message.getFieldWithDefault(msg, 7, "")
|
||||
builtinExtensionsDir: jspb.Message.getFieldWithDefault(msg, 7, ""),
|
||||
extensionsDirectory: jspb.Message.getFieldWithDefault(msg, 8, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -767,23 +809,23 @@ proto.WorkingInitMessage.toObject = function(includeInstance, msg) {
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.WorkingInitMessage}
|
||||
* @return {!proto.WorkingInit}
|
||||
*/
|
||||
proto.WorkingInitMessage.deserializeBinary = function(bytes) {
|
||||
proto.WorkingInit.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.WorkingInitMessage;
|
||||
return proto.WorkingInitMessage.deserializeBinaryFromReader(msg, reader);
|
||||
var msg = new proto.WorkingInit;
|
||||
return proto.WorkingInit.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.WorkingInitMessage} msg The message object to deserialize into.
|
||||
* @param {!proto.WorkingInit} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.WorkingInitMessage}
|
||||
* @return {!proto.WorkingInit}
|
||||
*/
|
||||
proto.WorkingInitMessage.deserializeBinaryFromReader = function(msg, reader) {
|
||||
proto.WorkingInit.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
@@ -807,7 +849,7 @@ proto.WorkingInitMessage.deserializeBinaryFromReader = function(msg, reader) {
|
||||
msg.setWorkingDirectory(value);
|
||||
break;
|
||||
case 5:
|
||||
var value = /** @type {!proto.WorkingInitMessage.OperatingSystem} */ (reader.readEnum());
|
||||
var value = /** @type {!proto.WorkingInit.OperatingSystem} */ (reader.readEnum());
|
||||
msg.setOperatingSystem(value);
|
||||
break;
|
||||
case 6:
|
||||
@@ -818,6 +860,10 @@ proto.WorkingInitMessage.deserializeBinaryFromReader = function(msg, reader) {
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setBuiltinExtensionsDir(value);
|
||||
break;
|
||||
case 8:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setExtensionsDirectory(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@@ -831,9 +877,9 @@ proto.WorkingInitMessage.deserializeBinaryFromReader = function(msg, reader) {
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.WorkingInitMessage.prototype.serializeBinary = function() {
|
||||
proto.WorkingInit.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.WorkingInitMessage.serializeBinaryToWriter(this, writer);
|
||||
proto.WorkingInit.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
@@ -841,11 +887,11 @@ proto.WorkingInitMessage.prototype.serializeBinary = function() {
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.WorkingInitMessage} message
|
||||
* @param {!proto.WorkingInit} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.WorkingInitMessage.serializeBinaryToWriter = function(message, writer) {
|
||||
proto.WorkingInit.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getHomeDirectory();
|
||||
if (f.length > 0) {
|
||||
@@ -896,13 +942,20 @@ proto.WorkingInitMessage.serializeBinaryToWriter = function(message, writer) {
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getExtensionsDirectory();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
8,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
proto.WorkingInitMessage.OperatingSystem = {
|
||||
proto.WorkingInit.OperatingSystem = {
|
||||
WINDOWS: 0,
|
||||
LINUX: 1,
|
||||
MAC: 2
|
||||
@@ -912,13 +965,13 @@ proto.WorkingInitMessage.OperatingSystem = {
|
||||
* optional string home_directory = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.WorkingInitMessage.prototype.getHomeDirectory = function() {
|
||||
proto.WorkingInit.prototype.getHomeDirectory = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/** @param {string} value */
|
||||
proto.WorkingInitMessage.prototype.setHomeDirectory = function(value) {
|
||||
proto.WorkingInit.prototype.setHomeDirectory = function(value) {
|
||||
jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
@@ -927,13 +980,13 @@ proto.WorkingInitMessage.prototype.setHomeDirectory = function(value) {
|
||||
* optional string tmp_directory = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.WorkingInitMessage.prototype.getTmpDirectory = function() {
|
||||
proto.WorkingInit.prototype.getTmpDirectory = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/** @param {string} value */
|
||||
proto.WorkingInitMessage.prototype.setTmpDirectory = function(value) {
|
||||
proto.WorkingInit.prototype.setTmpDirectory = function(value) {
|
||||
jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
@@ -942,13 +995,13 @@ proto.WorkingInitMessage.prototype.setTmpDirectory = function(value) {
|
||||
* optional string data_directory = 3;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.WorkingInitMessage.prototype.getDataDirectory = function() {
|
||||
proto.WorkingInit.prototype.getDataDirectory = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
|
||||
};
|
||||
|
||||
|
||||
/** @param {string} value */
|
||||
proto.WorkingInitMessage.prototype.setDataDirectory = function(value) {
|
||||
proto.WorkingInit.prototype.setDataDirectory = function(value) {
|
||||
jspb.Message.setProto3StringField(this, 3, value);
|
||||
};
|
||||
|
||||
@@ -957,28 +1010,28 @@ proto.WorkingInitMessage.prototype.setDataDirectory = function(value) {
|
||||
* optional string working_directory = 4;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.WorkingInitMessage.prototype.getWorkingDirectory = function() {
|
||||
proto.WorkingInit.prototype.getWorkingDirectory = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
|
||||
};
|
||||
|
||||
|
||||
/** @param {string} value */
|
||||
proto.WorkingInitMessage.prototype.setWorkingDirectory = function(value) {
|
||||
proto.WorkingInit.prototype.setWorkingDirectory = function(value) {
|
||||
jspb.Message.setProto3StringField(this, 4, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional OperatingSystem operating_system = 5;
|
||||
* @return {!proto.WorkingInitMessage.OperatingSystem}
|
||||
* @return {!proto.WorkingInit.OperatingSystem}
|
||||
*/
|
||||
proto.WorkingInitMessage.prototype.getOperatingSystem = function() {
|
||||
return /** @type {!proto.WorkingInitMessage.OperatingSystem} */ (jspb.Message.getFieldWithDefault(this, 5, 0));
|
||||
proto.WorkingInit.prototype.getOperatingSystem = function() {
|
||||
return /** @type {!proto.WorkingInit.OperatingSystem} */ (jspb.Message.getFieldWithDefault(this, 5, 0));
|
||||
};
|
||||
|
||||
|
||||
/** @param {!proto.WorkingInitMessage.OperatingSystem} value */
|
||||
proto.WorkingInitMessage.prototype.setOperatingSystem = function(value) {
|
||||
/** @param {!proto.WorkingInit.OperatingSystem} value */
|
||||
proto.WorkingInit.prototype.setOperatingSystem = function(value) {
|
||||
jspb.Message.setProto3EnumField(this, 5, value);
|
||||
};
|
||||
|
||||
@@ -987,13 +1040,13 @@ proto.WorkingInitMessage.prototype.setOperatingSystem = function(value) {
|
||||
* optional string shell = 6;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.WorkingInitMessage.prototype.getShell = function() {
|
||||
proto.WorkingInit.prototype.getShell = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 6, ""));
|
||||
};
|
||||
|
||||
|
||||
/** @param {string} value */
|
||||
proto.WorkingInitMessage.prototype.setShell = function(value) {
|
||||
proto.WorkingInit.prototype.setShell = function(value) {
|
||||
jspb.Message.setProto3StringField(this, 6, value);
|
||||
};
|
||||
|
||||
@@ -1002,15 +1055,30 @@ proto.WorkingInitMessage.prototype.setShell = function(value) {
|
||||
* optional string builtin_extensions_dir = 7;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.WorkingInitMessage.prototype.getBuiltinExtensionsDir = function() {
|
||||
proto.WorkingInit.prototype.getBuiltinExtensionsDir = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 7, ""));
|
||||
};
|
||||
|
||||
|
||||
/** @param {string} value */
|
||||
proto.WorkingInitMessage.prototype.setBuiltinExtensionsDir = function(value) {
|
||||
proto.WorkingInit.prototype.setBuiltinExtensionsDir = function(value) {
|
||||
jspb.Message.setProto3StringField(this, 7, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string extensions_directory = 8;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.WorkingInit.prototype.getExtensionsDirectory = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 8, ""));
|
||||
};
|
||||
|
||||
|
||||
/** @param {string} value */
|
||||
proto.WorkingInit.prototype.setExtensionsDirectory = function(value) {
|
||||
jspb.Message.setProto3StringField(this, 8, value);
|
||||
};
|
||||
|
||||
|
||||
goog.object.extend(exports, proto);
|
||||
|
||||
@@ -9,84 +9,133 @@ enum Module {
|
||||
Trash = 5;
|
||||
}
|
||||
|
||||
// A proxy identified by a unique name like "fs".
|
||||
message NamedProxyMessage {
|
||||
uint64 id = 1;
|
||||
Module module = 2;
|
||||
string method = 3;
|
||||
repeated string args = 4;
|
||||
}
|
||||
message Argument {
|
||||
message ErrorValue {
|
||||
string message = 1;
|
||||
string stack = 2;
|
||||
string code = 3;
|
||||
}
|
||||
|
||||
// A general proxy identified by an ID like WriteStream.
|
||||
message NumberedProxyMessage {
|
||||
uint64 id = 1;
|
||||
uint64 proxy_id = 2;
|
||||
string method = 3;
|
||||
repeated string args = 4;
|
||||
message BufferValue {
|
||||
bytes data = 1;
|
||||
}
|
||||
|
||||
message ObjectValue {
|
||||
map<string, Argument> data = 1;
|
||||
}
|
||||
|
||||
message ArrayValue {
|
||||
repeated Argument data = 1;
|
||||
}
|
||||
|
||||
message ProxyValue {
|
||||
uint64 id = 1;
|
||||
}
|
||||
|
||||
message FunctionValue {
|
||||
uint64 id = 1;
|
||||
}
|
||||
|
||||
message NullValue {}
|
||||
|
||||
message UndefinedValue {}
|
||||
|
||||
message DateValue {
|
||||
string date = 1;
|
||||
}
|
||||
|
||||
oneof msg {
|
||||
ErrorValue error = 1;
|
||||
BufferValue buffer = 2;
|
||||
ObjectValue object = 3;
|
||||
ArrayValue array = 4;
|
||||
ProxyValue proxy = 5;
|
||||
FunctionValue function = 6;
|
||||
NullValue null = 7;
|
||||
UndefinedValue undefined = 8;
|
||||
double number = 9;
|
||||
string string = 10;
|
||||
bool boolean = 11;
|
||||
DateValue date = 12;
|
||||
}
|
||||
}
|
||||
|
||||
// Call a remote method.
|
||||
message MethodMessage {
|
||||
message Method {
|
||||
// A proxy identified by a unique name like "fs".
|
||||
message Named {
|
||||
uint64 id = 1;
|
||||
Module module = 2;
|
||||
string method = 3;
|
||||
repeated Argument args = 4;
|
||||
}
|
||||
|
||||
// A general proxy identified by an ID like WriteStream.
|
||||
message Numbered {
|
||||
uint64 id = 1;
|
||||
uint64 proxy_id = 2;
|
||||
string method = 3;
|
||||
repeated Argument args = 4;
|
||||
}
|
||||
|
||||
// Remote method failed.
|
||||
message Fail {
|
||||
uint64 id = 1;
|
||||
Argument response = 2;
|
||||
}
|
||||
|
||||
// Remote method succeeded.
|
||||
message Success {
|
||||
uint64 id = 1;
|
||||
Argument response = 2;
|
||||
}
|
||||
|
||||
oneof msg {
|
||||
NamedProxyMessage named_proxy = 1;
|
||||
NumberedProxyMessage numbered_proxy = 2;
|
||||
Method.Named named_proxy = 1;
|
||||
Method.Numbered numbered_proxy = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Call a remote callback.
|
||||
message CallbackMessage {
|
||||
message Callback {
|
||||
// A remote callback for uniquely named proxy.
|
||||
message Named {
|
||||
Module module = 1;
|
||||
uint64 callback_id = 2;
|
||||
repeated Argument args = 3;
|
||||
}
|
||||
|
||||
// A remote callback for a numbered proxy.
|
||||
message Numbered {
|
||||
uint64 proxy_id = 1;
|
||||
uint64 callback_id = 2;
|
||||
repeated Argument args = 3;
|
||||
}
|
||||
|
||||
oneof msg {
|
||||
NamedCallbackMessage named_callback = 1;
|
||||
NumberedCallbackMessage numbered_callback = 2;
|
||||
Callback.Named named_callback = 1;
|
||||
Callback.Numbered numbered_callback = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// A remote callback for uniquely named proxy.
|
||||
message NamedCallbackMessage {
|
||||
Module module = 1;
|
||||
uint64 callback_id = 2;
|
||||
repeated string args = 3;
|
||||
}
|
||||
|
||||
// A remote callback for a numbered proxy.
|
||||
message NumberedCallbackMessage {
|
||||
uint64 proxy_id = 1;
|
||||
uint64 callback_id = 2;
|
||||
repeated string args = 3;
|
||||
}
|
||||
|
||||
// Emit an event.
|
||||
message EventMessage {
|
||||
oneof msg {
|
||||
NamedEventMessage named_event = 1;
|
||||
NumberedEventMessage numbered_event = 2;
|
||||
message Event {
|
||||
// Emit an event on a uniquely named proxy.
|
||||
message Named {
|
||||
Module module = 1;
|
||||
string event = 2;
|
||||
repeated Argument args = 3;
|
||||
}
|
||||
}
|
||||
|
||||
// Emit an event on a uniquely named proxy.
|
||||
message NamedEventMessage {
|
||||
Module module = 1;
|
||||
string event = 2;
|
||||
repeated string args = 3;
|
||||
}
|
||||
// Emit an event on a numbered proxy.
|
||||
message Numbered {
|
||||
uint64 proxy_id = 1;
|
||||
string event = 2;
|
||||
repeated Argument args = 3;
|
||||
}
|
||||
|
||||
// Emit an event on a numbered proxy.
|
||||
message NumberedEventMessage {
|
||||
uint64 proxy_id = 1;
|
||||
string event = 2;
|
||||
repeated string args = 3;
|
||||
}
|
||||
|
||||
// Remote method failed.
|
||||
message FailMessage {
|
||||
uint64 id = 1;
|
||||
string response = 2;
|
||||
}
|
||||
|
||||
// Remote method succeeded.
|
||||
message SuccessMessage {
|
||||
uint64 id = 1;
|
||||
string response = 2;
|
||||
oneof msg {
|
||||
Event.Named named_event = 1;
|
||||
Event.Numbered numbered_event = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message Ping {}
|
||||
|
||||
822
packages/protocol/src/proto/node_pb.d.ts
vendored
822
packages/protocol/src/proto/node_pb.d.ts
vendored
@@ -3,100 +3,440 @@
|
||||
|
||||
import * as jspb from "google-protobuf";
|
||||
|
||||
export class NamedProxyMessage extends jspb.Message {
|
||||
getId(): number;
|
||||
setId(value: number): void;
|
||||
export class Argument extends jspb.Message {
|
||||
hasError(): boolean;
|
||||
clearError(): void;
|
||||
getError(): Argument.ErrorValue | undefined;
|
||||
setError(value?: Argument.ErrorValue): void;
|
||||
|
||||
getModule(): Module;
|
||||
setModule(value: Module): void;
|
||||
hasBuffer(): boolean;
|
||||
clearBuffer(): void;
|
||||
getBuffer(): Argument.BufferValue | undefined;
|
||||
setBuffer(value?: Argument.BufferValue): void;
|
||||
|
||||
getMethod(): string;
|
||||
setMethod(value: string): void;
|
||||
hasObject(): boolean;
|
||||
clearObject(): void;
|
||||
getObject(): Argument.ObjectValue | undefined;
|
||||
setObject(value?: Argument.ObjectValue): void;
|
||||
|
||||
clearArgsList(): void;
|
||||
getArgsList(): Array<string>;
|
||||
setArgsList(value: Array<string>): void;
|
||||
addArgs(value: string, index?: number): string;
|
||||
hasArray(): boolean;
|
||||
clearArray(): void;
|
||||
getArray(): Argument.ArrayValue | undefined;
|
||||
setArray(value?: Argument.ArrayValue): void;
|
||||
|
||||
hasProxy(): boolean;
|
||||
clearProxy(): void;
|
||||
getProxy(): Argument.ProxyValue | undefined;
|
||||
setProxy(value?: Argument.ProxyValue): void;
|
||||
|
||||
hasFunction(): boolean;
|
||||
clearFunction(): void;
|
||||
getFunction(): Argument.FunctionValue | undefined;
|
||||
setFunction(value?: Argument.FunctionValue): void;
|
||||
|
||||
hasNull(): boolean;
|
||||
clearNull(): void;
|
||||
getNull(): Argument.NullValue | undefined;
|
||||
setNull(value?: Argument.NullValue): void;
|
||||
|
||||
hasUndefined(): boolean;
|
||||
clearUndefined(): void;
|
||||
getUndefined(): Argument.UndefinedValue | undefined;
|
||||
setUndefined(value?: Argument.UndefinedValue): void;
|
||||
|
||||
hasNumber(): boolean;
|
||||
clearNumber(): void;
|
||||
getNumber(): number;
|
||||
setNumber(value: number): void;
|
||||
|
||||
hasString(): boolean;
|
||||
clearString(): void;
|
||||
getString(): string;
|
||||
setString(value: string): void;
|
||||
|
||||
hasBoolean(): boolean;
|
||||
clearBoolean(): void;
|
||||
getBoolean(): boolean;
|
||||
setBoolean(value: boolean): void;
|
||||
|
||||
hasDate(): boolean;
|
||||
clearDate(): void;
|
||||
getDate(): Argument.DateValue | undefined;
|
||||
setDate(value?: Argument.DateValue): void;
|
||||
|
||||
getMsgCase(): Argument.MsgCase;
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): NamedProxyMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: NamedProxyMessage): NamedProxyMessage.AsObject;
|
||||
toObject(includeInstance?: boolean): Argument.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Argument): Argument.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: NamedProxyMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): NamedProxyMessage;
|
||||
static deserializeBinaryFromReader(message: NamedProxyMessage, reader: jspb.BinaryReader): NamedProxyMessage;
|
||||
static serializeBinaryToWriter(message: Argument, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Argument;
|
||||
static deserializeBinaryFromReader(message: Argument, reader: jspb.BinaryReader): Argument;
|
||||
}
|
||||
|
||||
export namespace NamedProxyMessage {
|
||||
export namespace Argument {
|
||||
export type AsObject = {
|
||||
id: number,
|
||||
module: Module,
|
||||
method: string,
|
||||
argsList: Array<string>,
|
||||
error?: Argument.ErrorValue.AsObject,
|
||||
buffer?: Argument.BufferValue.AsObject,
|
||||
object?: Argument.ObjectValue.AsObject,
|
||||
array?: Argument.ArrayValue.AsObject,
|
||||
proxy?: Argument.ProxyValue.AsObject,
|
||||
pb_function?: Argument.FunctionValue.AsObject,
|
||||
pb_null?: Argument.NullValue.AsObject,
|
||||
undefined?: Argument.UndefinedValue.AsObject,
|
||||
number: number,
|
||||
string: string,
|
||||
pb_boolean: boolean,
|
||||
date?: Argument.DateValue.AsObject,
|
||||
}
|
||||
|
||||
export class ErrorValue extends jspb.Message {
|
||||
getMessage(): string;
|
||||
setMessage(value: string): void;
|
||||
|
||||
getStack(): string;
|
||||
setStack(value: string): void;
|
||||
|
||||
getCode(): string;
|
||||
setCode(value: string): void;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): ErrorValue.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: ErrorValue): ErrorValue.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: ErrorValue, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): ErrorValue;
|
||||
static deserializeBinaryFromReader(message: ErrorValue, reader: jspb.BinaryReader): ErrorValue;
|
||||
}
|
||||
|
||||
export namespace ErrorValue {
|
||||
export type AsObject = {
|
||||
message: string,
|
||||
stack: string,
|
||||
code: string,
|
||||
}
|
||||
}
|
||||
|
||||
export class BufferValue extends jspb.Message {
|
||||
getData(): Uint8Array | string;
|
||||
getData_asU8(): Uint8Array;
|
||||
getData_asB64(): string;
|
||||
setData(value: Uint8Array | string): void;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): BufferValue.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: BufferValue): BufferValue.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: BufferValue, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): BufferValue;
|
||||
static deserializeBinaryFromReader(message: BufferValue, reader: jspb.BinaryReader): BufferValue;
|
||||
}
|
||||
|
||||
export namespace BufferValue {
|
||||
export type AsObject = {
|
||||
data: Uint8Array | string,
|
||||
}
|
||||
}
|
||||
|
||||
export class ObjectValue extends jspb.Message {
|
||||
getDataMap(): jspb.Map<string, Argument>;
|
||||
clearDataMap(): void;
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): ObjectValue.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: ObjectValue): ObjectValue.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: ObjectValue, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): ObjectValue;
|
||||
static deserializeBinaryFromReader(message: ObjectValue, reader: jspb.BinaryReader): ObjectValue;
|
||||
}
|
||||
|
||||
export namespace ObjectValue {
|
||||
export type AsObject = {
|
||||
dataMap: Array<[string, Argument.AsObject]>,
|
||||
}
|
||||
}
|
||||
|
||||
export class ArrayValue extends jspb.Message {
|
||||
clearDataList(): void;
|
||||
getDataList(): Array<Argument>;
|
||||
setDataList(value: Array<Argument>): void;
|
||||
addData(value?: Argument, index?: number): Argument;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): ArrayValue.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: ArrayValue): ArrayValue.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: ArrayValue, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): ArrayValue;
|
||||
static deserializeBinaryFromReader(message: ArrayValue, reader: jspb.BinaryReader): ArrayValue;
|
||||
}
|
||||
|
||||
export namespace ArrayValue {
|
||||
export type AsObject = {
|
||||
dataList: Array<Argument.AsObject>,
|
||||
}
|
||||
}
|
||||
|
||||
export class ProxyValue extends jspb.Message {
|
||||
getId(): number;
|
||||
setId(value: number): void;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): ProxyValue.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: ProxyValue): ProxyValue.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: ProxyValue, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): ProxyValue;
|
||||
static deserializeBinaryFromReader(message: ProxyValue, reader: jspb.BinaryReader): ProxyValue;
|
||||
}
|
||||
|
||||
export namespace ProxyValue {
|
||||
export type AsObject = {
|
||||
id: number,
|
||||
}
|
||||
}
|
||||
|
||||
export class FunctionValue extends jspb.Message {
|
||||
getId(): number;
|
||||
setId(value: number): void;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): FunctionValue.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: FunctionValue): FunctionValue.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: FunctionValue, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): FunctionValue;
|
||||
static deserializeBinaryFromReader(message: FunctionValue, reader: jspb.BinaryReader): FunctionValue;
|
||||
}
|
||||
|
||||
export namespace FunctionValue {
|
||||
export type AsObject = {
|
||||
id: number,
|
||||
}
|
||||
}
|
||||
|
||||
export class NullValue extends jspb.Message {
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): NullValue.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: NullValue): NullValue.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: NullValue, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): NullValue;
|
||||
static deserializeBinaryFromReader(message: NullValue, reader: jspb.BinaryReader): NullValue;
|
||||
}
|
||||
|
||||
export namespace NullValue {
|
||||
export type AsObject = {
|
||||
}
|
||||
}
|
||||
|
||||
export class UndefinedValue extends jspb.Message {
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): UndefinedValue.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: UndefinedValue): UndefinedValue.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: UndefinedValue, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): UndefinedValue;
|
||||
static deserializeBinaryFromReader(message: UndefinedValue, reader: jspb.BinaryReader): UndefinedValue;
|
||||
}
|
||||
|
||||
export namespace UndefinedValue {
|
||||
export type AsObject = {
|
||||
}
|
||||
}
|
||||
|
||||
export class DateValue extends jspb.Message {
|
||||
getDate(): string;
|
||||
setDate(value: string): void;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): DateValue.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: DateValue): DateValue.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: DateValue, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): DateValue;
|
||||
static deserializeBinaryFromReader(message: DateValue, reader: jspb.BinaryReader): DateValue;
|
||||
}
|
||||
|
||||
export namespace DateValue {
|
||||
export type AsObject = {
|
||||
date: string,
|
||||
}
|
||||
}
|
||||
|
||||
export enum MsgCase {
|
||||
MSG_NOT_SET = 0,
|
||||
ERROR = 1,
|
||||
BUFFER = 2,
|
||||
OBJECT = 3,
|
||||
ARRAY = 4,
|
||||
PROXY = 5,
|
||||
FUNCTION = 6,
|
||||
NULL = 7,
|
||||
UNDEFINED = 8,
|
||||
NUMBER = 9,
|
||||
STRING = 10,
|
||||
BOOLEAN = 11,
|
||||
DATE = 12,
|
||||
}
|
||||
}
|
||||
|
||||
export class NumberedProxyMessage extends jspb.Message {
|
||||
getId(): number;
|
||||
setId(value: number): void;
|
||||
|
||||
getProxyId(): number;
|
||||
setProxyId(value: number): void;
|
||||
|
||||
getMethod(): string;
|
||||
setMethod(value: string): void;
|
||||
|
||||
clearArgsList(): void;
|
||||
getArgsList(): Array<string>;
|
||||
setArgsList(value: Array<string>): void;
|
||||
addArgs(value: string, index?: number): string;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): NumberedProxyMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: NumberedProxyMessage): NumberedProxyMessage.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: NumberedProxyMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): NumberedProxyMessage;
|
||||
static deserializeBinaryFromReader(message: NumberedProxyMessage, reader: jspb.BinaryReader): NumberedProxyMessage;
|
||||
}
|
||||
|
||||
export namespace NumberedProxyMessage {
|
||||
export type AsObject = {
|
||||
id: number,
|
||||
proxyId: number,
|
||||
method: string,
|
||||
argsList: Array<string>,
|
||||
}
|
||||
}
|
||||
|
||||
export class MethodMessage extends jspb.Message {
|
||||
export class Method extends jspb.Message {
|
||||
hasNamedProxy(): boolean;
|
||||
clearNamedProxy(): void;
|
||||
getNamedProxy(): NamedProxyMessage | undefined;
|
||||
setNamedProxy(value?: NamedProxyMessage): void;
|
||||
getNamedProxy(): Method.Named | undefined;
|
||||
setNamedProxy(value?: Method.Named): void;
|
||||
|
||||
hasNumberedProxy(): boolean;
|
||||
clearNumberedProxy(): void;
|
||||
getNumberedProxy(): NumberedProxyMessage | undefined;
|
||||
setNumberedProxy(value?: NumberedProxyMessage): void;
|
||||
getNumberedProxy(): Method.Numbered | undefined;
|
||||
setNumberedProxy(value?: Method.Numbered): void;
|
||||
|
||||
getMsgCase(): MethodMessage.MsgCase;
|
||||
getMsgCase(): Method.MsgCase;
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): MethodMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: MethodMessage): MethodMessage.AsObject;
|
||||
toObject(includeInstance?: boolean): Method.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Method): Method.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: MethodMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): MethodMessage;
|
||||
static deserializeBinaryFromReader(message: MethodMessage, reader: jspb.BinaryReader): MethodMessage;
|
||||
static serializeBinaryToWriter(message: Method, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Method;
|
||||
static deserializeBinaryFromReader(message: Method, reader: jspb.BinaryReader): Method;
|
||||
}
|
||||
|
||||
export namespace MethodMessage {
|
||||
export namespace Method {
|
||||
export type AsObject = {
|
||||
namedProxy?: NamedProxyMessage.AsObject,
|
||||
numberedProxy?: NumberedProxyMessage.AsObject,
|
||||
namedProxy?: Method.Named.AsObject,
|
||||
numberedProxy?: Method.Numbered.AsObject,
|
||||
}
|
||||
|
||||
export class Named extends jspb.Message {
|
||||
getId(): number;
|
||||
setId(value: number): void;
|
||||
|
||||
getModule(): Module;
|
||||
setModule(value: Module): void;
|
||||
|
||||
getMethod(): string;
|
||||
setMethod(value: string): void;
|
||||
|
||||
clearArgsList(): void;
|
||||
getArgsList(): Array<Argument>;
|
||||
setArgsList(value: Array<Argument>): void;
|
||||
addArgs(value?: Argument, index?: number): Argument;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Named.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Named): Named.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: Named, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Named;
|
||||
static deserializeBinaryFromReader(message: Named, reader: jspb.BinaryReader): Named;
|
||||
}
|
||||
|
||||
export namespace Named {
|
||||
export type AsObject = {
|
||||
id: number,
|
||||
module: Module,
|
||||
method: string,
|
||||
argsList: Array<Argument.AsObject>,
|
||||
}
|
||||
}
|
||||
|
||||
export class Numbered extends jspb.Message {
|
||||
getId(): number;
|
||||
setId(value: number): void;
|
||||
|
||||
getProxyId(): number;
|
||||
setProxyId(value: number): void;
|
||||
|
||||
getMethod(): string;
|
||||
setMethod(value: string): void;
|
||||
|
||||
clearArgsList(): void;
|
||||
getArgsList(): Array<Argument>;
|
||||
setArgsList(value: Array<Argument>): void;
|
||||
addArgs(value?: Argument, index?: number): Argument;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Numbered.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Numbered): Numbered.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: Numbered, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Numbered;
|
||||
static deserializeBinaryFromReader(message: Numbered, reader: jspb.BinaryReader): Numbered;
|
||||
}
|
||||
|
||||
export namespace Numbered {
|
||||
export type AsObject = {
|
||||
id: number,
|
||||
proxyId: number,
|
||||
method: string,
|
||||
argsList: Array<Argument.AsObject>,
|
||||
}
|
||||
}
|
||||
|
||||
export class Fail extends jspb.Message {
|
||||
getId(): number;
|
||||
setId(value: number): void;
|
||||
|
||||
hasResponse(): boolean;
|
||||
clearResponse(): void;
|
||||
getResponse(): Argument | undefined;
|
||||
setResponse(value?: Argument): void;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Fail.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Fail): Fail.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: Fail, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Fail;
|
||||
static deserializeBinaryFromReader(message: Fail, reader: jspb.BinaryReader): Fail;
|
||||
}
|
||||
|
||||
export namespace Fail {
|
||||
export type AsObject = {
|
||||
id: number,
|
||||
response?: Argument.AsObject,
|
||||
}
|
||||
}
|
||||
|
||||
export class Success extends jspb.Message {
|
||||
getId(): number;
|
||||
setId(value: number): void;
|
||||
|
||||
hasResponse(): boolean;
|
||||
clearResponse(): void;
|
||||
getResponse(): Argument | undefined;
|
||||
setResponse(value?: Argument): void;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Success.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Success): Success.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: Success, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Success;
|
||||
static deserializeBinaryFromReader(message: Success, reader: jspb.BinaryReader): Success;
|
||||
}
|
||||
|
||||
export namespace Success {
|
||||
export type AsObject = {
|
||||
id: number,
|
||||
response?: Argument.AsObject,
|
||||
}
|
||||
}
|
||||
|
||||
export enum MsgCase {
|
||||
@@ -106,32 +446,92 @@ export namespace MethodMessage {
|
||||
}
|
||||
}
|
||||
|
||||
export class CallbackMessage extends jspb.Message {
|
||||
export class Callback extends jspb.Message {
|
||||
hasNamedCallback(): boolean;
|
||||
clearNamedCallback(): void;
|
||||
getNamedCallback(): NamedCallbackMessage | undefined;
|
||||
setNamedCallback(value?: NamedCallbackMessage): void;
|
||||
getNamedCallback(): Callback.Named | undefined;
|
||||
setNamedCallback(value?: Callback.Named): void;
|
||||
|
||||
hasNumberedCallback(): boolean;
|
||||
clearNumberedCallback(): void;
|
||||
getNumberedCallback(): NumberedCallbackMessage | undefined;
|
||||
setNumberedCallback(value?: NumberedCallbackMessage): void;
|
||||
getNumberedCallback(): Callback.Numbered | undefined;
|
||||
setNumberedCallback(value?: Callback.Numbered): void;
|
||||
|
||||
getMsgCase(): CallbackMessage.MsgCase;
|
||||
getMsgCase(): Callback.MsgCase;
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): CallbackMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: CallbackMessage): CallbackMessage.AsObject;
|
||||
toObject(includeInstance?: boolean): Callback.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Callback): Callback.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: CallbackMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): CallbackMessage;
|
||||
static deserializeBinaryFromReader(message: CallbackMessage, reader: jspb.BinaryReader): CallbackMessage;
|
||||
static serializeBinaryToWriter(message: Callback, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Callback;
|
||||
static deserializeBinaryFromReader(message: Callback, reader: jspb.BinaryReader): Callback;
|
||||
}
|
||||
|
||||
export namespace CallbackMessage {
|
||||
export namespace Callback {
|
||||
export type AsObject = {
|
||||
namedCallback?: NamedCallbackMessage.AsObject,
|
||||
numberedCallback?: NumberedCallbackMessage.AsObject,
|
||||
namedCallback?: Callback.Named.AsObject,
|
||||
numberedCallback?: Callback.Numbered.AsObject,
|
||||
}
|
||||
|
||||
export class Named extends jspb.Message {
|
||||
getModule(): Module;
|
||||
setModule(value: Module): void;
|
||||
|
||||
getCallbackId(): number;
|
||||
setCallbackId(value: number): void;
|
||||
|
||||
clearArgsList(): void;
|
||||
getArgsList(): Array<Argument>;
|
||||
setArgsList(value: Array<Argument>): void;
|
||||
addArgs(value?: Argument, index?: number): Argument;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Named.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Named): Named.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: Named, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Named;
|
||||
static deserializeBinaryFromReader(message: Named, reader: jspb.BinaryReader): Named;
|
||||
}
|
||||
|
||||
export namespace Named {
|
||||
export type AsObject = {
|
||||
module: Module,
|
||||
callbackId: number,
|
||||
argsList: Array<Argument.AsObject>,
|
||||
}
|
||||
}
|
||||
|
||||
export class Numbered extends jspb.Message {
|
||||
getProxyId(): number;
|
||||
setProxyId(value: number): void;
|
||||
|
||||
getCallbackId(): number;
|
||||
setCallbackId(value: number): void;
|
||||
|
||||
clearArgsList(): void;
|
||||
getArgsList(): Array<Argument>;
|
||||
setArgsList(value: Array<Argument>): void;
|
||||
addArgs(value?: Argument, index?: number): Argument;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Numbered.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Numbered): Numbered.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: Numbered, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Numbered;
|
||||
static deserializeBinaryFromReader(message: Numbered, reader: jspb.BinaryReader): Numbered;
|
||||
}
|
||||
|
||||
export namespace Numbered {
|
||||
export type AsObject = {
|
||||
proxyId: number,
|
||||
callbackId: number,
|
||||
argsList: Array<Argument.AsObject>,
|
||||
}
|
||||
}
|
||||
|
||||
export enum MsgCase {
|
||||
@@ -141,92 +541,92 @@ export namespace CallbackMessage {
|
||||
}
|
||||
}
|
||||
|
||||
export class NamedCallbackMessage extends jspb.Message {
|
||||
getModule(): Module;
|
||||
setModule(value: Module): void;
|
||||
|
||||
getCallbackId(): number;
|
||||
setCallbackId(value: number): void;
|
||||
|
||||
clearArgsList(): void;
|
||||
getArgsList(): Array<string>;
|
||||
setArgsList(value: Array<string>): void;
|
||||
addArgs(value: string, index?: number): string;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): NamedCallbackMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: NamedCallbackMessage): NamedCallbackMessage.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: NamedCallbackMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): NamedCallbackMessage;
|
||||
static deserializeBinaryFromReader(message: NamedCallbackMessage, reader: jspb.BinaryReader): NamedCallbackMessage;
|
||||
}
|
||||
|
||||
export namespace NamedCallbackMessage {
|
||||
export type AsObject = {
|
||||
module: Module,
|
||||
callbackId: number,
|
||||
argsList: Array<string>,
|
||||
}
|
||||
}
|
||||
|
||||
export class NumberedCallbackMessage extends jspb.Message {
|
||||
getProxyId(): number;
|
||||
setProxyId(value: number): void;
|
||||
|
||||
getCallbackId(): number;
|
||||
setCallbackId(value: number): void;
|
||||
|
||||
clearArgsList(): void;
|
||||
getArgsList(): Array<string>;
|
||||
setArgsList(value: Array<string>): void;
|
||||
addArgs(value: string, index?: number): string;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): NumberedCallbackMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: NumberedCallbackMessage): NumberedCallbackMessage.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: NumberedCallbackMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): NumberedCallbackMessage;
|
||||
static deserializeBinaryFromReader(message: NumberedCallbackMessage, reader: jspb.BinaryReader): NumberedCallbackMessage;
|
||||
}
|
||||
|
||||
export namespace NumberedCallbackMessage {
|
||||
export type AsObject = {
|
||||
proxyId: number,
|
||||
callbackId: number,
|
||||
argsList: Array<string>,
|
||||
}
|
||||
}
|
||||
|
||||
export class EventMessage extends jspb.Message {
|
||||
export class Event extends jspb.Message {
|
||||
hasNamedEvent(): boolean;
|
||||
clearNamedEvent(): void;
|
||||
getNamedEvent(): NamedEventMessage | undefined;
|
||||
setNamedEvent(value?: NamedEventMessage): void;
|
||||
getNamedEvent(): Event.Named | undefined;
|
||||
setNamedEvent(value?: Event.Named): void;
|
||||
|
||||
hasNumberedEvent(): boolean;
|
||||
clearNumberedEvent(): void;
|
||||
getNumberedEvent(): NumberedEventMessage | undefined;
|
||||
setNumberedEvent(value?: NumberedEventMessage): void;
|
||||
getNumberedEvent(): Event.Numbered | undefined;
|
||||
setNumberedEvent(value?: Event.Numbered): void;
|
||||
|
||||
getMsgCase(): EventMessage.MsgCase;
|
||||
getMsgCase(): Event.MsgCase;
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): EventMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: EventMessage): EventMessage.AsObject;
|
||||
toObject(includeInstance?: boolean): Event.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Event): Event.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: EventMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): EventMessage;
|
||||
static deserializeBinaryFromReader(message: EventMessage, reader: jspb.BinaryReader): EventMessage;
|
||||
static serializeBinaryToWriter(message: Event, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Event;
|
||||
static deserializeBinaryFromReader(message: Event, reader: jspb.BinaryReader): Event;
|
||||
}
|
||||
|
||||
export namespace EventMessage {
|
||||
export namespace Event {
|
||||
export type AsObject = {
|
||||
namedEvent?: NamedEventMessage.AsObject,
|
||||
numberedEvent?: NumberedEventMessage.AsObject,
|
||||
namedEvent?: Event.Named.AsObject,
|
||||
numberedEvent?: Event.Numbered.AsObject,
|
||||
}
|
||||
|
||||
export class Named extends jspb.Message {
|
||||
getModule(): Module;
|
||||
setModule(value: Module): void;
|
||||
|
||||
getEvent(): string;
|
||||
setEvent(value: string): void;
|
||||
|
||||
clearArgsList(): void;
|
||||
getArgsList(): Array<Argument>;
|
||||
setArgsList(value: Array<Argument>): void;
|
||||
addArgs(value?: Argument, index?: number): Argument;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Named.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Named): Named.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: Named, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Named;
|
||||
static deserializeBinaryFromReader(message: Named, reader: jspb.BinaryReader): Named;
|
||||
}
|
||||
|
||||
export namespace Named {
|
||||
export type AsObject = {
|
||||
module: Module,
|
||||
event: string,
|
||||
argsList: Array<Argument.AsObject>,
|
||||
}
|
||||
}
|
||||
|
||||
export class Numbered extends jspb.Message {
|
||||
getProxyId(): number;
|
||||
setProxyId(value: number): void;
|
||||
|
||||
getEvent(): string;
|
||||
setEvent(value: string): void;
|
||||
|
||||
clearArgsList(): void;
|
||||
getArgsList(): Array<Argument>;
|
||||
setArgsList(value: Array<Argument>): void;
|
||||
addArgs(value?: Argument, index?: number): Argument;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Numbered.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Numbered): Numbered.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: Numbered, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Numbered;
|
||||
static deserializeBinaryFromReader(message: Numbered, reader: jspb.BinaryReader): Numbered;
|
||||
}
|
||||
|
||||
export namespace Numbered {
|
||||
export type AsObject = {
|
||||
proxyId: number,
|
||||
event: string,
|
||||
argsList: Array<Argument.AsObject>,
|
||||
}
|
||||
}
|
||||
|
||||
export enum MsgCase {
|
||||
@@ -236,114 +636,6 @@ export namespace EventMessage {
|
||||
}
|
||||
}
|
||||
|
||||
export class NamedEventMessage extends jspb.Message {
|
||||
getModule(): Module;
|
||||
setModule(value: Module): void;
|
||||
|
||||
getEvent(): string;
|
||||
setEvent(value: string): void;
|
||||
|
||||
clearArgsList(): void;
|
||||
getArgsList(): Array<string>;
|
||||
setArgsList(value: Array<string>): void;
|
||||
addArgs(value: string, index?: number): string;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): NamedEventMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: NamedEventMessage): NamedEventMessage.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: NamedEventMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): NamedEventMessage;
|
||||
static deserializeBinaryFromReader(message: NamedEventMessage, reader: jspb.BinaryReader): NamedEventMessage;
|
||||
}
|
||||
|
||||
export namespace NamedEventMessage {
|
||||
export type AsObject = {
|
||||
module: Module,
|
||||
event: string,
|
||||
argsList: Array<string>,
|
||||
}
|
||||
}
|
||||
|
||||
export class NumberedEventMessage extends jspb.Message {
|
||||
getProxyId(): number;
|
||||
setProxyId(value: number): void;
|
||||
|
||||
getEvent(): string;
|
||||
setEvent(value: string): void;
|
||||
|
||||
clearArgsList(): void;
|
||||
getArgsList(): Array<string>;
|
||||
setArgsList(value: Array<string>): void;
|
||||
addArgs(value: string, index?: number): string;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): NumberedEventMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: NumberedEventMessage): NumberedEventMessage.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: NumberedEventMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): NumberedEventMessage;
|
||||
static deserializeBinaryFromReader(message: NumberedEventMessage, reader: jspb.BinaryReader): NumberedEventMessage;
|
||||
}
|
||||
|
||||
export namespace NumberedEventMessage {
|
||||
export type AsObject = {
|
||||
proxyId: number,
|
||||
event: string,
|
||||
argsList: Array<string>,
|
||||
}
|
||||
}
|
||||
|
||||
export class FailMessage extends jspb.Message {
|
||||
getId(): number;
|
||||
setId(value: number): void;
|
||||
|
||||
getResponse(): string;
|
||||
setResponse(value: string): void;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): FailMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: FailMessage): FailMessage.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: FailMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): FailMessage;
|
||||
static deserializeBinaryFromReader(message: FailMessage, reader: jspb.BinaryReader): FailMessage;
|
||||
}
|
||||
|
||||
export namespace FailMessage {
|
||||
export type AsObject = {
|
||||
id: number,
|
||||
response: string,
|
||||
}
|
||||
}
|
||||
|
||||
export class SuccessMessage extends jspb.Message {
|
||||
getId(): number;
|
||||
setId(value: number): void;
|
||||
|
||||
getResponse(): string;
|
||||
setResponse(value: string): void;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): SuccessMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: SuccessMessage): SuccessMessage.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: SuccessMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): SuccessMessage;
|
||||
static deserializeBinaryFromReader(message: SuccessMessage, reader: jspb.BinaryReader): SuccessMessage;
|
||||
}
|
||||
|
||||
export namespace SuccessMessage {
|
||||
export type AsObject = {
|
||||
id: number,
|
||||
response: string,
|
||||
}
|
||||
}
|
||||
|
||||
export class Ping extends jspb.Message {
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Ping.AsObject;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
syntax = "proto3";
|
||||
|
||||
// Sent when a shared process becomes active
|
||||
message SharedProcessActiveMessage {
|
||||
message SharedProcessActive {
|
||||
string socket_path = 1;
|
||||
string log_path = 2;
|
||||
}
|
||||
}
|
||||
|
||||
14
packages/protocol/src/proto/vscode_pb.d.ts
vendored
14
packages/protocol/src/proto/vscode_pb.d.ts
vendored
@@ -3,7 +3,7 @@
|
||||
|
||||
import * as jspb from "google-protobuf";
|
||||
|
||||
export class SharedProcessActiveMessage extends jspb.Message {
|
||||
export class SharedProcessActive extends jspb.Message {
|
||||
getSocketPath(): string;
|
||||
setSocketPath(value: string): void;
|
||||
|
||||
@@ -11,16 +11,16 @@ export class SharedProcessActiveMessage extends jspb.Message {
|
||||
setLogPath(value: string): void;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): SharedProcessActiveMessage.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: SharedProcessActiveMessage): SharedProcessActiveMessage.AsObject;
|
||||
toObject(includeInstance?: boolean): SharedProcessActive.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: SharedProcessActive): SharedProcessActive.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: SharedProcessActiveMessage, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): SharedProcessActiveMessage;
|
||||
static deserializeBinaryFromReader(message: SharedProcessActiveMessage, reader: jspb.BinaryReader): SharedProcessActiveMessage;
|
||||
static serializeBinaryToWriter(message: SharedProcessActive, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): SharedProcessActive;
|
||||
static deserializeBinaryFromReader(message: SharedProcessActive, reader: jspb.BinaryReader): SharedProcessActive;
|
||||
}
|
||||
|
||||
export namespace SharedProcessActiveMessage {
|
||||
export namespace SharedProcessActive {
|
||||
export type AsObject = {
|
||||
socketPath: string,
|
||||
logPath: string,
|
||||
|
||||
@@ -11,8 +11,7 @@ var jspb = require('google-protobuf');
|
||||
var goog = jspb;
|
||||
var global = Function('return this')();
|
||||
|
||||
goog.exportSymbol('proto.SharedProcessActiveMessage', null, global);
|
||||
|
||||
goog.exportSymbol('proto.SharedProcessActive', null, global);
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
@@ -23,15 +22,20 @@ goog.exportSymbol('proto.SharedProcessActiveMessage', null, global);
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.SharedProcessActiveMessage = function(opt_data) {
|
||||
proto.SharedProcessActive = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.SharedProcessActiveMessage, jspb.Message);
|
||||
goog.inherits(proto.SharedProcessActive, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
proto.SharedProcessActiveMessage.displayName = 'proto.SharedProcessActiveMessage';
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.SharedProcessActive.displayName = 'proto.SharedProcessActive';
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto suitable for use in Soy templates.
|
||||
@@ -43,8 +47,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
* for transitional soy proto support: http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.SharedProcessActiveMessage.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.SharedProcessActiveMessage.toObject(opt_includeInstance, this);
|
||||
proto.SharedProcessActive.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.SharedProcessActive.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
@@ -53,12 +57,12 @@ proto.SharedProcessActiveMessage.prototype.toObject = function(opt_includeInstan
|
||||
* @param {boolean|undefined} includeInstance Whether to include the JSPB
|
||||
* instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.SharedProcessActiveMessage} msg The msg instance to transform.
|
||||
* @param {!proto.SharedProcessActive} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.SharedProcessActiveMessage.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
proto.SharedProcessActive.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
socketPath: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
logPath: jspb.Message.getFieldWithDefault(msg, 2, "")
|
||||
};
|
||||
@@ -74,23 +78,23 @@ proto.SharedProcessActiveMessage.toObject = function(includeInstance, msg) {
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.SharedProcessActiveMessage}
|
||||
* @return {!proto.SharedProcessActive}
|
||||
*/
|
||||
proto.SharedProcessActiveMessage.deserializeBinary = function(bytes) {
|
||||
proto.SharedProcessActive.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.SharedProcessActiveMessage;
|
||||
return proto.SharedProcessActiveMessage.deserializeBinaryFromReader(msg, reader);
|
||||
var msg = new proto.SharedProcessActive;
|
||||
return proto.SharedProcessActive.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.SharedProcessActiveMessage} msg The message object to deserialize into.
|
||||
* @param {!proto.SharedProcessActive} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.SharedProcessActiveMessage}
|
||||
* @return {!proto.SharedProcessActive}
|
||||
*/
|
||||
proto.SharedProcessActiveMessage.deserializeBinaryFromReader = function(msg, reader) {
|
||||
proto.SharedProcessActive.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
@@ -118,9 +122,9 @@ proto.SharedProcessActiveMessage.deserializeBinaryFromReader = function(msg, rea
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.SharedProcessActiveMessage.prototype.serializeBinary = function() {
|
||||
proto.SharedProcessActive.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.SharedProcessActiveMessage.serializeBinaryToWriter(this, writer);
|
||||
proto.SharedProcessActive.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
@@ -128,11 +132,11 @@ proto.SharedProcessActiveMessage.prototype.serializeBinary = function() {
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.SharedProcessActiveMessage} message
|
||||
* @param {!proto.SharedProcessActive} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.SharedProcessActiveMessage.serializeBinaryToWriter = function(message, writer) {
|
||||
proto.SharedProcessActive.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getSocketPath();
|
||||
if (f.length > 0) {
|
||||
@@ -155,13 +159,13 @@ proto.SharedProcessActiveMessage.serializeBinaryToWriter = function(message, wri
|
||||
* optional string socket_path = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.SharedProcessActiveMessage.prototype.getSocketPath = function() {
|
||||
proto.SharedProcessActive.prototype.getSocketPath = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/** @param {string} value */
|
||||
proto.SharedProcessActiveMessage.prototype.setSocketPath = function(value) {
|
||||
proto.SharedProcessActive.prototype.setSocketPath = function(value) {
|
||||
jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
@@ -170,13 +174,13 @@ proto.SharedProcessActiveMessage.prototype.setSocketPath = function(value) {
|
||||
* optional string log_path = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.SharedProcessActiveMessage.prototype.getLogPath = function() {
|
||||
proto.SharedProcessActive.prototype.getLogPath = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/** @param {string} value */
|
||||
proto.SharedProcessActiveMessage.prototype.setLogPath = function(value) {
|
||||
proto.SharedProcessActive.prototype.setLogPath = function(value) {
|
||||
jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ describe("child_process", () => {
|
||||
const cp = client.modules[Module.ChildProcess];
|
||||
|
||||
const getStdout = async (proc: ChildProcess): Promise<string> => {
|
||||
return new Promise((r): Readable => proc.stdout.on("data", r))
|
||||
return new Promise((r): Readable => proc.stdout!.on("data", r))
|
||||
.then((s) => s.toString());
|
||||
};
|
||||
|
||||
@@ -36,10 +36,10 @@ describe("child_process", () => {
|
||||
it("should cat", async () => {
|
||||
const proc = cp.spawn("cat", []);
|
||||
expect(proc.pid).toBe(-1);
|
||||
proc.stdin.write("banana");
|
||||
proc.stdin!.write("banana");
|
||||
await expect(getStdout(proc)).resolves.toBe("banana");
|
||||
|
||||
proc.stdin.end();
|
||||
proc.stdin!.end();
|
||||
proc.kill();
|
||||
|
||||
expect(proc.pid).toBeGreaterThan(-1);
|
||||
@@ -53,6 +53,11 @@ describe("child_process", () => {
|
||||
|
||||
await expect(getStdout(proc)).resolves.toContain("hi=donkey\n");
|
||||
});
|
||||
|
||||
it("should eval", async () => {
|
||||
const proc = cp.spawn("node", ["-e", "console.log('foo')"]);
|
||||
await expect(getStdout(proc)).resolves.toContain("foo");
|
||||
});
|
||||
});
|
||||
|
||||
describe("fork", () => {
|
||||
|
||||
@@ -4,6 +4,8 @@ import * as util from "util";
|
||||
import { Module } from "../src/common/proxy";
|
||||
import { createClient, Helper } from "./helpers";
|
||||
|
||||
// tslint:disable deprecation to use fs.exists
|
||||
|
||||
describe("fs", () => {
|
||||
const client = createClient();
|
||||
// tslint:disable-next-line no-any
|
||||
@@ -242,6 +244,14 @@ describe("fs", () => {
|
||||
await util.promisify(nativeFs.close)(fd);
|
||||
});
|
||||
|
||||
it("should futimes existing file with date", async () => {
|
||||
const file = await helper.createTmpFile();
|
||||
const fd = await util.promisify(nativeFs.open)(file, "w");
|
||||
await expect(util.promisify(fs.futimes)(fd, new Date(), new Date()))
|
||||
.resolves.toBeUndefined();
|
||||
await util.promisify(nativeFs.close)(fd);
|
||||
});
|
||||
|
||||
it("should fail to futimes nonexistent file", async () => {
|
||||
await expect(util.promisify(fs.futimes)(99999, 9999, 9999))
|
||||
.rejects.toThrow("EBADF");
|
||||
@@ -346,7 +356,7 @@ describe("fs", () => {
|
||||
it("should read existing file", async () => {
|
||||
const fd = await util.promisify(nativeFs.open)(__filename, "r");
|
||||
const stat = await util.promisify(nativeFs.fstat)(fd);
|
||||
const buffer = new Buffer(stat.size);
|
||||
const buffer = Buffer.alloc(stat.size);
|
||||
let bytesRead = 0;
|
||||
let chunkSize = 2048;
|
||||
while (bytesRead < stat.size) {
|
||||
@@ -364,7 +374,7 @@ describe("fs", () => {
|
||||
});
|
||||
|
||||
it("should fail to read nonexistent file", async () => {
|
||||
await expect(util.promisify(fs.read)(99999, new Buffer(10), 9999, 999, 999))
|
||||
await expect(util.promisify(fs.read)(99999, Buffer.alloc(10), 9999, 999, 999))
|
||||
.rejects.toThrow("EBADF");
|
||||
});
|
||||
});
|
||||
@@ -466,6 +476,7 @@ describe("fs", () => {
|
||||
expect(stat).toMatchObject({
|
||||
size: nativeStat.size,
|
||||
});
|
||||
expect(typeof stat.mtime.getTime()).toBe("number");
|
||||
expect(stat.isFile()).toBe(true);
|
||||
});
|
||||
|
||||
@@ -493,7 +504,7 @@ describe("fs", () => {
|
||||
const destination = helper.tmpFile();
|
||||
await expect(util.promisify(fs.symlink)(source, destination))
|
||||
.resolves.toBeUndefined();
|
||||
expect(util.promisify(nativeFs.exists)(source))
|
||||
await expect(util.promisify(nativeFs.exists)(source))
|
||||
.resolves.toBe(true);
|
||||
});
|
||||
|
||||
@@ -525,7 +536,7 @@ describe("fs", () => {
|
||||
const file = await helper.createTmpFile();
|
||||
await expect(util.promisify(fs.unlink)(file))
|
||||
.resolves.toBeUndefined();
|
||||
expect(util.promisify(nativeFs.exists)(file))
|
||||
await expect(util.promisify(nativeFs.exists)(file))
|
||||
.resolves.toBe(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -38,6 +38,23 @@ describe("net", () => {
|
||||
expect(fn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should remove event listener", async () => {
|
||||
const socket = new net.Socket();
|
||||
|
||||
const fn1 = jest.fn();
|
||||
const fn2 = jest.fn();
|
||||
|
||||
socket.on("error", fn1);
|
||||
socket.on("error", fn2);
|
||||
socket.off("error", fn1);
|
||||
|
||||
socket.connect("/tmp/t/e/s/t/d/o/e/s/n/o/t/e/x/i/s/t");
|
||||
|
||||
await new Promise((r): nativeNet.Socket => socket.on("close", r));
|
||||
expect(fn1).toHaveBeenCalledTimes(0);
|
||||
expect(fn2).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should connect", async () => {
|
||||
await new Promise((resolve): void => {
|
||||
const socket = net.createConnection(socketPath, () => {
|
||||
|
||||
@@ -12,12 +12,10 @@ describe("Server", () => {
|
||||
workingDirectory,
|
||||
});
|
||||
|
||||
it("should get init msg", (done) => {
|
||||
client.initData.then((data) => {
|
||||
expect(data.dataDirectory).toEqual(dataDirectory);
|
||||
expect(data.workingDirectory).toEqual(workingDirectory);
|
||||
expect(data.builtInExtensionsDirectory).toEqual(builtInExtensionsDirectory);
|
||||
done();
|
||||
});
|
||||
it("should get init msg", async () => {
|
||||
const data = await client.initData;
|
||||
expect(data.dataDirectory).toEqual(dataDirectory);
|
||||
expect(data.workingDirectory).toEqual(workingDirectory);
|
||||
expect(data.builtInExtensionsDirectory).toEqual(builtInExtensionsDirectory);
|
||||
});
|
||||
});
|
||||
|
||||
101
packages/protocol/test/util.test.ts
Normal file
101
packages/protocol/test/util.test.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import * as fs from "fs";
|
||||
import * as util from "util";
|
||||
import { argumentToProto, protoToArgument } from "../src/common/util";
|
||||
|
||||
describe("Convert", () => {
|
||||
it("should convert nothing", () => {
|
||||
expect(protoToArgument()).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should convert null", () => {
|
||||
expect(protoToArgument(argumentToProto(null))).toBeNull();
|
||||
});
|
||||
|
||||
it("should convert undefined", () => {
|
||||
expect(protoToArgument(argumentToProto(undefined))).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should convert string", () => {
|
||||
expect(protoToArgument(argumentToProto("test"))).toBe("test");
|
||||
});
|
||||
|
||||
it("should convert number", () => {
|
||||
expect(protoToArgument(argumentToProto(10))).toBe(10);
|
||||
});
|
||||
|
||||
it("should convert boolean", () => {
|
||||
expect(protoToArgument(argumentToProto(true))).toBe(true);
|
||||
expect(protoToArgument(argumentToProto(false))).toBe(false);
|
||||
});
|
||||
|
||||
it("should convert error", () => {
|
||||
const error = new Error("message");
|
||||
const convertedError = protoToArgument(argumentToProto(error));
|
||||
|
||||
expect(convertedError instanceof Error).toBeTruthy();
|
||||
expect(convertedError.message).toBe("message");
|
||||
});
|
||||
|
||||
it("should convert buffer", async () => {
|
||||
const buffer = await util.promisify(fs.readFile)(__filename);
|
||||
expect(buffer instanceof Buffer).toBeTruthy();
|
||||
|
||||
const convertedBuffer = protoToArgument(argumentToProto(buffer));
|
||||
expect(convertedBuffer instanceof Buffer).toBeTruthy();
|
||||
expect(convertedBuffer.toString()).toBe(buffer.toString());
|
||||
});
|
||||
|
||||
it("should convert proxy", () => {
|
||||
let i = 0;
|
||||
const proto = argumentToProto(
|
||||
{ onEvent: (): void => undefined },
|
||||
undefined,
|
||||
() => i++,
|
||||
);
|
||||
|
||||
const proxy = protoToArgument(proto, undefined, (id) => {
|
||||
return {
|
||||
id: `created: ${id}`,
|
||||
dispose: (): Promise<void> => Promise.resolve(),
|
||||
onDone: (): Promise<void> => Promise.resolve(),
|
||||
onEvent: (): Promise<void> => Promise.resolve(),
|
||||
};
|
||||
});
|
||||
|
||||
expect(proxy.id).toBe("created: 0");
|
||||
});
|
||||
|
||||
it("should convert function", () => {
|
||||
const fn = jest.fn();
|
||||
// tslint:disable-next-line no-any
|
||||
const map = new Map<number, (...args: any[]) => void>();
|
||||
let i = 0;
|
||||
const proto = argumentToProto(
|
||||
fn,
|
||||
(f) => {
|
||||
map.set(i++, f);
|
||||
|
||||
return i - 1;
|
||||
},
|
||||
);
|
||||
|
||||
const remoteFn = protoToArgument(proto, (id, args) => {
|
||||
map.get(id)!(...args);
|
||||
});
|
||||
|
||||
remoteFn("a", "b", 1);
|
||||
|
||||
expect(fn).toHaveBeenCalledWith("a", "b", 1);
|
||||
});
|
||||
|
||||
it("should convert array", () => {
|
||||
const array = ["a", "b", 1, [1, "a"], null, undefined];
|
||||
expect(protoToArgument(argumentToProto(array))).toEqual(array);
|
||||
});
|
||||
|
||||
it("should convert object", () => {
|
||||
const obj = { a: "test" };
|
||||
// const obj = { "a": 1, "b": [1, "a"], test: null, test2: undefined };
|
||||
expect(protoToArgument(argumentToProto(obj))).toEqual(obj);
|
||||
});
|
||||
});
|
||||
@@ -64,29 +64,6 @@ accepts@~1.3.5:
|
||||
mime-types "~2.1.18"
|
||||
negotiator "0.6.1"
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||
integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
|
||||
|
||||
ansi-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||
|
||||
aproba@^1.0.3:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
|
||||
integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
|
||||
|
||||
are-we-there-yet@~1.1.2:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
|
||||
integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
|
||||
dependencies:
|
||||
delegates "^1.0.0"
|
||||
readable-stream "^2.0.6"
|
||||
|
||||
array-flatten@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
||||
@@ -114,21 +91,6 @@ balanced-match@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
bindings@^1.3.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
|
||||
integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
|
||||
dependencies:
|
||||
file-uri-to-path "1.0.0"
|
||||
|
||||
bl@^1.0.0:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
|
||||
integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==
|
||||
dependencies:
|
||||
readable-stream "^2.3.5"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
body-parser@1.18.3:
|
||||
version "1.18.3"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
|
||||
@@ -153,49 +115,16 @@ brace-expansion@^1.1.7:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
buffer-alloc-unsafe@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
|
||||
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
|
||||
|
||||
buffer-alloc@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
|
||||
integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
|
||||
dependencies:
|
||||
buffer-alloc-unsafe "^1.1.0"
|
||||
buffer-fill "^1.0.0"
|
||||
|
||||
buffer-fill@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
|
||||
integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
|
||||
|
||||
bytes@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||
integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
|
||||
|
||||
chownr@^1.0.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
|
||||
integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
|
||||
|
||||
code-point-at@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
console-control-strings@^1.0.0, console-control-strings@~1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
|
||||
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
|
||||
|
||||
content-disposition@0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
|
||||
@@ -216,11 +145,6 @@ cookie@0.3.1:
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
||||
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
cross-spawn-async@^2.1.1:
|
||||
version "2.2.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc"
|
||||
@@ -247,23 +171,6 @@ debug@2.6.9:
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
decompress-response@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
|
||||
integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
|
||||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
deep-extend@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
||||
|
||||
delegates@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
||||
|
||||
depd@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||
@@ -274,11 +181,6 @@ destroy@~1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
||||
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
|
||||
|
||||
detect-libc@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
|
||||
|
||||
dir-glob@^2.0.0:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4"
|
||||
@@ -296,13 +198,6 @@ encodeurl@~1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
|
||||
|
||||
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
|
||||
integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
escape-html@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
@@ -342,11 +237,6 @@ execa@^0.2.2:
|
||||
path-key "^1.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
expand-template@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
|
||||
integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
|
||||
|
||||
express@^4.16.4:
|
||||
version "4.16.4"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
|
||||
@@ -383,11 +273,6 @@ express@^4.16.4:
|
||||
utils-merge "1.0.1"
|
||||
vary "~1.1.2"
|
||||
|
||||
file-uri-to-path@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
||||
integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
|
||||
|
||||
finalhandler@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
|
||||
@@ -411,11 +296,6 @@ fresh@0.5.2:
|
||||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
||||
|
||||
fs-constants@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
|
||||
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
|
||||
|
||||
fs-extra@^0.30.0:
|
||||
version "0.30.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0"
|
||||
@@ -432,30 +312,11 @@ fs.realpath@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
gauge@~2.7.3:
|
||||
version "2.7.4"
|
||||
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
|
||||
integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
|
||||
dependencies:
|
||||
aproba "^1.0.3"
|
||||
console-control-strings "^1.0.0"
|
||||
has-unicode "^2.0.0"
|
||||
object-assign "^4.1.0"
|
||||
signal-exit "^3.0.0"
|
||||
string-width "^1.0.1"
|
||||
strip-ansi "^3.0.1"
|
||||
wide-align "^1.1.0"
|
||||
|
||||
get-stream@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
||||
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
|
||||
|
||||
github-from-package@0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
|
||||
integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=
|
||||
|
||||
glob@^7.1.2, glob@^7.1.3:
|
||||
version "7.1.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
|
||||
@@ -490,11 +351,6 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
|
||||
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
|
||||
|
||||
has-unicode@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
|
||||
integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
|
||||
|
||||
http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
|
||||
version "1.6.3"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
|
||||
@@ -525,43 +381,21 @@ inflight@^1.0.4:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@2.0.3, inherits@~2.0.3:
|
||||
inherits@2, inherits@2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
ini@~1.3.0:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
||||
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
|
||||
|
||||
ipaddr.js@1.8.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e"
|
||||
integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4=
|
||||
|
||||
is-fullwidth-code-point@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
|
||||
integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
|
||||
dependencies:
|
||||
number-is-nan "^1.0.0"
|
||||
|
||||
is-fullwidth-code-point@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
|
||||
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
|
||||
|
||||
is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
|
||||
|
||||
isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
@@ -621,11 +455,6 @@ mime@1.4.1:
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
|
||||
integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
|
||||
|
||||
mimic-response@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
|
||||
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
|
||||
|
||||
minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
@@ -633,23 +462,6 @@ minimatch@^3.0.4:
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimist@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
|
||||
|
||||
minimist@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
||||
|
||||
mkdirp@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
mount-point@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/mount-point/-/mount-point-3.0.0.tgz#665cb9edebe80d110e658db56c31d0aef51a8f97"
|
||||
@@ -664,21 +476,6 @@ ms@2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
|
||||
nan@2.10.0:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
|
||||
integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==
|
||||
|
||||
nan@^2.8.0:
|
||||
version "2.12.1"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552"
|
||||
integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==
|
||||
|
||||
napi-build-utils@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508"
|
||||
integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==
|
||||
|
||||
negotiator@0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
|
||||
@@ -689,26 +486,6 @@ nice-try@^1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
|
||||
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
|
||||
|
||||
node-abi@^2.7.0:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.7.1.tgz#a8997ae91176a5fbaa455b194976e32683cda643"
|
||||
integrity sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw==
|
||||
dependencies:
|
||||
semver "^5.4.1"
|
||||
|
||||
node-pty-prebuilt@^0.7.6:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/node-pty-prebuilt/-/node-pty-prebuilt-0.7.6.tgz#c04c41e40a527ed894bf0ee801f40e5fd6f5faf6"
|
||||
integrity sha512-aD/77N6WmohtWMhdHaBMunOihpZzDcp5Ig1cHsmtYNxl5NU8+3r9aGkfbKWUDYrPQaFgbJEAWfGeb3NFYd1+0g==
|
||||
dependencies:
|
||||
nan "2.10.0"
|
||||
prebuild-install "^5.0.0"
|
||||
|
||||
noop-logger@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2"
|
||||
integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=
|
||||
|
||||
npm-run-path@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-1.0.0.tgz#f5c32bf595fe81ae927daec52e82f8b000ac3c8f"
|
||||
@@ -723,22 +500,7 @@ npm-run-path@^2.0.0:
|
||||
dependencies:
|
||||
path-key "^2.0.0"
|
||||
|
||||
npmlog@^4.0.1:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
|
||||
integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
|
||||
dependencies:
|
||||
are-we-there-yet "~1.1.2"
|
||||
console-control-strings "~1.1.0"
|
||||
gauge "~2.7.3"
|
||||
set-blocking "~2.0.0"
|
||||
|
||||
number-is-nan@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
|
||||
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
|
||||
|
||||
object-assign@^4.0.1, object-assign@^4.1.0:
|
||||
object-assign@^4.0.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
@@ -750,14 +512,14 @@ on-finished@~2.3.0:
|
||||
dependencies:
|
||||
ee-first "1.1.1"
|
||||
|
||||
once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
os-homedir@^1.0.0, os-homedir@^1.0.1:
|
||||
os-homedir@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
|
||||
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
|
||||
@@ -831,33 +593,6 @@ pinkie@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
|
||||
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
|
||||
|
||||
prebuild-install@^5.0.0:
|
||||
version "5.2.5"
|
||||
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.2.5.tgz#c7485911fe98950b7f7cd15bb9daee11b875cc44"
|
||||
integrity sha512-6uZgMVg7yDfqlP5CPurVhtq3hUKBFNufiar4J5hZrlHTo59DDBEtyxw01xCdFss9j0Zb9+qzFVf/s4niayba3w==
|
||||
dependencies:
|
||||
detect-libc "^1.0.3"
|
||||
expand-template "^2.0.3"
|
||||
github-from-package "0.0.0"
|
||||
minimist "^1.2.0"
|
||||
mkdirp "^0.5.1"
|
||||
napi-build-utils "^1.0.1"
|
||||
node-abi "^2.7.0"
|
||||
noop-logger "^0.1.1"
|
||||
npmlog "^4.0.1"
|
||||
os-homedir "^1.0.1"
|
||||
pump "^2.0.1"
|
||||
rc "^1.2.7"
|
||||
simple-get "^2.7.0"
|
||||
tar-fs "^1.13.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
which-pm-runs "^1.0.0"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
|
||||
integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
|
||||
|
||||
proxy-addr@~2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93"
|
||||
@@ -871,22 +606,6 @@ pseudomap@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
|
||||
|
||||
pump@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954"
|
||||
integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==
|
||||
dependencies:
|
||||
end-of-stream "^1.1.0"
|
||||
once "^1.3.1"
|
||||
|
||||
pump@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
|
||||
integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
|
||||
dependencies:
|
||||
end-of-stream "^1.1.0"
|
||||
once "^1.3.1"
|
||||
|
||||
qs@6.5.2:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
@@ -907,29 +626,6 @@ raw-body@2.3.3:
|
||||
iconv-lite "0.4.23"
|
||||
unpipe "1.0.0"
|
||||
|
||||
rc@^1.2.7:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
|
||||
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
|
||||
dependencies:
|
||||
deep-extend "^0.6.0"
|
||||
ini "~1.3.0"
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
|
||||
integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.3"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~2.0.0"
|
||||
safe-buffer "~5.1.1"
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
rimraf@^2.2.8, rimraf@^2.6.3:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
|
||||
@@ -944,7 +640,7 @@ run-applescript@^3.0.0:
|
||||
dependencies:
|
||||
execa "^0.10.0"
|
||||
|
||||
safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
safe-buffer@5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
@@ -954,7 +650,7 @@ safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, s
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
semver@^5.4.1, semver@^5.5.0:
|
||||
semver@^5.5.0:
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
|
||||
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
|
||||
@@ -988,11 +684,6 @@ serve-static@1.13.2:
|
||||
parseurl "~1.3.2"
|
||||
send "0.16.2"
|
||||
|
||||
set-blocking@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||
|
||||
setprototypeof@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
|
||||
@@ -1015,34 +706,11 @@ signal-exit@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
|
||||
|
||||
simple-concat@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6"
|
||||
integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=
|
||||
|
||||
simple-get@^2.7.0:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d"
|
||||
integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==
|
||||
dependencies:
|
||||
decompress-response "^3.3.0"
|
||||
once "^1.3.1"
|
||||
simple-concat "^1.0.0"
|
||||
|
||||
slash@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
|
||||
integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=
|
||||
|
||||
spdlog@^0.7.2:
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.7.2.tgz#9298753d7694b9ee9bbfd7e01ea1e4c6ace1e64d"
|
||||
integrity sha512-rHfWCaWMD4NindDnql6rc6kn7Bs8JR92jhiUpCl3D6v+jYcQ6GozMLig0RliOOR8st5mU+IHLZnr15fBys5x/Q==
|
||||
dependencies:
|
||||
bindings "^1.3.0"
|
||||
mkdirp "^0.5.1"
|
||||
nan "^2.8.0"
|
||||
|
||||
"statuses@>= 1.4.0 < 2":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
|
||||
@@ -1053,87 +721,16 @@ statuses@~1.4.0:
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
|
||||
integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
|
||||
|
||||
string-width@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
|
||||
integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
|
||||
dependencies:
|
||||
code-point-at "^1.0.0"
|
||||
is-fullwidth-code-point "^1.0.0"
|
||||
strip-ansi "^3.0.0"
|
||||
|
||||
"string-width@^1.0.2 || 2":
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
|
||||
integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
|
||||
dependencies:
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
string_decoder@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
|
||||
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
|
||||
integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
|
||||
dependencies:
|
||||
ansi-regex "^2.0.0"
|
||||
|
||||
strip-ansi@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
|
||||
integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
|
||||
dependencies:
|
||||
ansi-regex "^3.0.0"
|
||||
|
||||
strip-eof@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
|
||||
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
|
||||
|
||||
strip-json-comments@~2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
|
||||
|
||||
tar-fs@^1.13.0:
|
||||
version "1.16.3"
|
||||
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509"
|
||||
integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==
|
||||
dependencies:
|
||||
chownr "^1.0.1"
|
||||
mkdirp "^0.5.1"
|
||||
pump "^1.0.0"
|
||||
tar-stream "^1.1.2"
|
||||
|
||||
tar-stream@^1.1.2:
|
||||
version "1.6.2"
|
||||
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
|
||||
integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
|
||||
dependencies:
|
||||
bl "^1.0.0"
|
||||
buffer-alloc "^1.2.0"
|
||||
end-of-stream "^1.0.0"
|
||||
fs-constants "^1.0.0"
|
||||
readable-stream "^2.3.0"
|
||||
to-buffer "^1.1.1"
|
||||
xtend "^4.0.0"
|
||||
|
||||
text-encoding@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.7.0.tgz#f895e836e45990624086601798ea98e8f36ee643"
|
||||
integrity sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==
|
||||
|
||||
to-buffer@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
|
||||
integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
|
||||
|
||||
trash@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/trash/-/trash-4.3.0.tgz#6ebeecdea4d666b06e389b47d135ea88e1de5075"
|
||||
@@ -1156,13 +753,6 @@ ts-protoc-gen@^0.8.0:
|
||||
dependencies:
|
||||
google-protobuf "^3.6.1"
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||
integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
type-is@~1.6.16:
|
||||
version "1.6.16"
|
||||
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194"
|
||||
@@ -1183,11 +773,6 @@ user-home@^2.0.0:
|
||||
dependencies:
|
||||
os-homedir "^1.0.0"
|
||||
|
||||
util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
utils-merge@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||
@@ -1203,11 +788,6 @@ vary@~1.1.2:
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
||||
|
||||
which-pm-runs@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
|
||||
integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=
|
||||
|
||||
which@^1.2.8, which@^1.2.9:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
||||
@@ -1215,13 +795,6 @@ which@^1.2.8, which@^1.2.9:
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
wide-align@^1.1.0:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
|
||||
integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
|
||||
dependencies:
|
||||
string-width "^1.0.2 || 2"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
@@ -1252,11 +825,6 @@ xdg-trashdir@^2.1.1:
|
||||
user-home "^2.0.0"
|
||||
xdg-basedir "^2.0.0"
|
||||
|
||||
xtend@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
|
||||
|
||||
yallist@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"build:binary": "ts-node scripts/nbin.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coder/nbin": "^1.0.4",
|
||||
"@coder/nbin": "^1.1.2",
|
||||
"commander": "^2.19.0",
|
||||
"express": "^4.16.4",
|
||||
"express-static-gzip": "^1.1.3",
|
||||
|
||||
@@ -10,6 +10,16 @@ const bin = new Binary({
|
||||
});
|
||||
bin.writeFiles(path.join(rootDir, "build", "**"));
|
||||
bin.writeFiles(path.join(rootDir, "out", "**"));
|
||||
[
|
||||
// Native modules. These are marked as externals in the webpack config.
|
||||
"spdlog",
|
||||
"node-pty",
|
||||
|
||||
// These are spdlog's dependencies.
|
||||
"mkdirp", "bindings",
|
||||
].forEach((name) => {
|
||||
bin.writeModule(path.join(__dirname, "../../../node_modules", name));
|
||||
});
|
||||
bin.build().then((binaryData) => {
|
||||
const outputPath = path.join(__dirname, "..", `cli-${target}`);
|
||||
fs.writeFileSync(outputPath, binaryData);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { field, logger } from "@coder/logger";
|
||||
import { ServerMessage, SharedProcessActiveMessage } from "@coder/protocol/src/proto";
|
||||
import { ChildProcess, fork, ForkOptions, spawn } from "child_process";
|
||||
import { ServerMessage, SharedProcessActive } from "@coder/protocol/src/proto";
|
||||
import { ChildProcess, fork, ForkOptions } from "child_process";
|
||||
import { randomFillSync } from "crypto";
|
||||
import * as fs from "fs";
|
||||
import * as fse from "fs-extra";
|
||||
@@ -8,9 +8,8 @@ import * as os from "os";
|
||||
import * as path from "path";
|
||||
import * as WebSocket from "ws";
|
||||
import { buildDir, cacheHome, dataHome, isCli, serveStatic } from "./constants";
|
||||
import { setup as setupNativeModules } from "./modules";
|
||||
import { createApp } from "./server";
|
||||
import { forkModule, requireFork, requireModule } from "./vscode/bootstrapFork";
|
||||
import { forkModule, requireModule } from "./vscode/bootstrapFork";
|
||||
import { SharedProcess, SharedProcessState } from "./vscode/sharedProcess";
|
||||
import opn = require("opn");
|
||||
|
||||
@@ -19,17 +18,21 @@ import * as commander from "commander";
|
||||
commander.version(process.env.VERSION || "development")
|
||||
.name("code-server")
|
||||
.description("Run VS Code on a remote server.")
|
||||
.option("--cert")
|
||||
.option("--cert-key")
|
||||
.option("-d, --data-dir <value>", "Customize where user-data is stored.")
|
||||
.option("--cert <value>")
|
||||
.option("--cert-key <value>")
|
||||
.option("-e, --extensions-dir <dir>", "Set the root path for extensions.")
|
||||
.option("-d --user-data-dir <dir>", " Specifies the directory that user data is kept in, useful when running as root.")
|
||||
.option("--data-dir <value>", "DEPRECATED: Use '--user-data-dir' instead. Customize where user-data is stored.")
|
||||
.option("-h, --host <value>", "Customize the hostname.", "0.0.0.0")
|
||||
.option("-o, --open", "Open in the browser on startup.", false)
|
||||
.option("-p, --port <number>", "Port to bind on.", 8443)
|
||||
.option("-p, --port <number>", "Port to bind on.", parseInt(process.env.PORT!, 10) || 8443)
|
||||
.option("-N, --no-auth", "Start without requiring authentication.", undefined)
|
||||
.option("-H, --allow-http", "Allow http connections.", false)
|
||||
.option("-P, --password <value>", "Specify a password for authentication.")
|
||||
.option("-P, --password <value>", "DEPRECATED: Use the PASSWORD environment variable instead. Specify a password for authentication.")
|
||||
.option("--disable-telemetry", "Disables ALL telemetry.", false)
|
||||
.option("--socket <value>", "Listen on a UNIX socket. Host and port will be ignored when set.")
|
||||
.option("--install-extension <value>", "Install an extension by its ID.")
|
||||
.option("--bootstrap-fork <name>", "Used for development. Never set.")
|
||||
.option("--fork <name>", "Used for development. Never set.")
|
||||
.option("--extra-args <args>", "Used for development. Never set.")
|
||||
.arguments("Specify working directory.")
|
||||
.parse(process.argv);
|
||||
@@ -37,7 +40,12 @@ commander.version(process.env.VERSION || "development")
|
||||
Error.stackTraceLimit = Infinity;
|
||||
if (isCli) {
|
||||
require("nbin").shimNativeFs(buildDir);
|
||||
require("nbin").shimNativeFs("/node_modules");
|
||||
}
|
||||
// Makes strings or numbers bold in stdout
|
||||
const bold = (text: string | number): string | number => {
|
||||
return `\u001B[1m${text}\u001B[0m`;
|
||||
};
|
||||
|
||||
(async (): Promise<void> => {
|
||||
const args = commander.args;
|
||||
@@ -46,25 +54,37 @@ if (isCli) {
|
||||
readonly allowHttp: boolean;
|
||||
readonly host: string;
|
||||
readonly port: number;
|
||||
readonly disableTelemetry: boolean;
|
||||
|
||||
readonly userDataDir?: string;
|
||||
readonly extensionsDir?: string;
|
||||
|
||||
readonly dataDir?: string;
|
||||
readonly password?: string;
|
||||
readonly open?: boolean;
|
||||
readonly cert?: string;
|
||||
readonly certKey?: string;
|
||||
readonly socket?: string;
|
||||
|
||||
readonly installExtension?: string;
|
||||
|
||||
readonly bootstrapFork?: string;
|
||||
readonly fork?: string;
|
||||
readonly extraArgs?: string;
|
||||
};
|
||||
|
||||
if (options.disableTelemetry) {
|
||||
process.env.DISABLE_TELEMETRY = "true";
|
||||
}
|
||||
|
||||
// Commander has an exception for `--no` prefixes. Here we'll adjust that.
|
||||
// tslint:disable-next-line:no-any
|
||||
const noAuthValue = (commander as any).auth;
|
||||
options.noAuth = !noAuthValue;
|
||||
|
||||
const dataDir = path.resolve(options.dataDir || path.join(dataHome, "code-server"));
|
||||
const dataDir = path.resolve(options.userDataDir || options.dataDir || path.join(dataHome, "code-server"));
|
||||
const extensionsDir = options.extensionsDir ? path.resolve(options.extensionsDir) : path.resolve(dataDir, "extensions");
|
||||
const workingDir = path.resolve(args[0] || process.cwd());
|
||||
const dependenciesDir = path.join(os.tmpdir(), "code-server/dependencies");
|
||||
|
||||
if (!fs.existsSync(dataDir)) {
|
||||
const oldDataDir = path.resolve(path.join(os.homedir(), ".code-server"));
|
||||
@@ -77,10 +97,24 @@ if (isCli) {
|
||||
await Promise.all([
|
||||
fse.mkdirp(cacheHome),
|
||||
fse.mkdirp(dataDir),
|
||||
fse.mkdirp(extensionsDir),
|
||||
fse.mkdirp(workingDir),
|
||||
fse.mkdirp(dependenciesDir),
|
||||
]);
|
||||
|
||||
setupNativeModules(dataDir);
|
||||
const unpackExecutable = (binaryName: string): void => {
|
||||
const memFile = path.join(isCli ? buildDir! : path.join(__dirname, ".."), "build/dependencies", binaryName);
|
||||
const diskFile = path.join(dependenciesDir, binaryName);
|
||||
if (!fse.existsSync(diskFile)) {
|
||||
fse.writeFileSync(diskFile, fse.readFileSync(memFile));
|
||||
}
|
||||
fse.chmodSync(diskFile, "755");
|
||||
};
|
||||
|
||||
unpackExecutable("rg");
|
||||
// tslint:disable-next-line no-any
|
||||
(<any>global).RIPGREP_LOCATION = path.join(dependenciesDir, "rg");
|
||||
|
||||
const builtInExtensionsDir = path.resolve(buildDir || path.join(__dirname, ".."), "build/extensions");
|
||||
if (options.bootstrapFork) {
|
||||
const modulePath = options.bootstrapFork;
|
||||
@@ -89,19 +123,13 @@ if (isCli) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
((options.extraArgs ? JSON.parse(options.extraArgs) : []) as string[]).forEach((arg, i) => {
|
||||
// [0] contains the binary running the script (`node` for example) and
|
||||
// [1] contains the script name, so the arguments come after that.
|
||||
process.argv[i + 2] = arg;
|
||||
});
|
||||
process.argv = [
|
||||
process.argv[0],
|
||||
process.argv[1],
|
||||
...(options.extraArgs ? JSON.parse(options.extraArgs) : []),
|
||||
];
|
||||
|
||||
return requireModule(modulePath, dataDir, builtInExtensionsDir);
|
||||
}
|
||||
|
||||
if (options.fork) {
|
||||
const modulePath = options.fork;
|
||||
|
||||
return requireFork(modulePath, JSON.parse(options.extraArgs!), builtInExtensionsDir);
|
||||
return requireModule(modulePath, builtInExtensionsDir);
|
||||
}
|
||||
|
||||
const logDir = path.join(cacheHome, "code-server/logs", new Date().toISOString().replace(/[-:.TZ]/g, ""));
|
||||
@@ -140,12 +168,37 @@ if (isCli) {
|
||||
}
|
||||
|
||||
logger.info(`\u001B[1mcode-server ${process.env.VERSION ? `v${process.env.VERSION}` : "development"}`);
|
||||
|
||||
if (options.dataDir) {
|
||||
logger.warn('"--data-dir" is deprecated. Use "--user-data-dir" instead.');
|
||||
}
|
||||
|
||||
if (options.installExtension) {
|
||||
const fork = forkModule("vs/code/node/cli", [
|
||||
"--user-data-dir", dataDir,
|
||||
"--builtin-extensions-dir", builtInExtensionsDir,
|
||||
"--extensions-dir", extensionsDir,
|
||||
"--install-extension", options.installExtension,
|
||||
], {
|
||||
env: {
|
||||
VSCODE_ALLOW_IO: "true",
|
||||
VSCODE_LOGS: process.env.VSCODE_LOGS,
|
||||
},
|
||||
}, dataDir);
|
||||
|
||||
fork.stdout.on("data", (d: Buffer) => d.toString().split("\n").forEach((l) => logger.info(l)));
|
||||
fork.stderr.on("data", (d: Buffer) => d.toString().split("\n").forEach((l) => logger.error(l)));
|
||||
fork.on("exit", () => process.exit());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: fill in appropriate doc url
|
||||
logger.info("Additional documentation: http://github.com/codercom/code-server");
|
||||
logger.info("Initializing", field("data-dir", dataDir), field("working-dir", workingDir), field("log-dir", logDir));
|
||||
const sharedProcess = new SharedProcess(dataDir, builtInExtensionsDir);
|
||||
logger.info("Initializing", field("data-dir", dataDir), field("extensions-dir", extensionsDir), field("working-dir", workingDir), field("log-dir", logDir));
|
||||
const sharedProcess = new SharedProcess(dataDir, extensionsDir, builtInExtensionsDir);
|
||||
const sendSharedProcessReady = (socket: WebSocket): void => {
|
||||
const active = new SharedProcessActiveMessage();
|
||||
const active = new SharedProcessActive();
|
||||
active.setSocketPath(sharedProcess.socketPath);
|
||||
active.setLogPath(logDir);
|
||||
const serverMessage = new ServerMessage();
|
||||
@@ -158,7 +211,11 @@ if (isCli) {
|
||||
}
|
||||
});
|
||||
|
||||
let password = options.password;
|
||||
if (options.password) {
|
||||
logger.warn('"--password" is deprecated. Use the PASSWORD environment variable instead.');
|
||||
}
|
||||
|
||||
let password = options.password || process.env.PASSWORD;
|
||||
if (!password) {
|
||||
// Generate a random password with a length of 24.
|
||||
const buffer = Buffer.alloc(12);
|
||||
@@ -171,20 +228,19 @@ if (isCli) {
|
||||
allowHttp: options.allowHttp,
|
||||
bypassAuth: options.noAuth,
|
||||
registerMiddleware: (app): void => {
|
||||
app.use((req, res, next) => {
|
||||
res.on("finish", () => {
|
||||
logger.trace(`\u001B[1m${req.method} ${res.statusCode} \u001B[0m${req.url}`, field("host", req.hostname), field("ip", req.ip));
|
||||
});
|
||||
|
||||
next();
|
||||
});
|
||||
// If we're not running from the binary and we aren't serving the static
|
||||
// pre-built version, use webpack to serve the web files.
|
||||
if (!isCli && !serveStatic) {
|
||||
const webpackConfig = require(path.resolve(__dirname, "..", "..", "web", "webpack.config.js"));
|
||||
const compiler = require("webpack")(webpackConfig);
|
||||
app.use(require("webpack-dev-middleware")(compiler, {
|
||||
logger,
|
||||
logger: {
|
||||
trace: (m: string): void => logger.trace("webpack", field("message", m)),
|
||||
debug: (m: string): void => logger.debug("webpack", field("message", m)),
|
||||
info: (m: string): void => logger.info("webpack", field("message", m)),
|
||||
warn: (m: string): void => logger.warn("webpack", field("message", m)),
|
||||
error: (m: string): void => logger.error("webpack", field("message", m)),
|
||||
},
|
||||
publicPath: webpackConfig.output.publicPath,
|
||||
stats: webpackConfig.stats,
|
||||
}));
|
||||
@@ -192,6 +248,7 @@ if (isCli) {
|
||||
}
|
||||
},
|
||||
serverOptions: {
|
||||
extensionsDirectory: extensionsDir,
|
||||
builtInExtensionsDirectory: builtInExtensionsDir,
|
||||
dataDirectory: dataDir,
|
||||
workingDirectory: workingDir,
|
||||
@@ -201,14 +258,7 @@ if (isCli) {
|
||||
return forkModule(options.env.AMD_ENTRYPOINT, args, options, dataDir);
|
||||
}
|
||||
|
||||
if (isCli) {
|
||||
return spawn(process.execPath, [path.join(buildDir, "out", "cli.js"), "--fork", modulePath, "--extra-args", JSON.stringify(args), "--data-dir", dataDir], {
|
||||
...options,
|
||||
stdio: [null, null, null, "ipc"],
|
||||
});
|
||||
} else {
|
||||
return fork(modulePath, args, options);
|
||||
}
|
||||
return fork(modulePath, args, options);
|
||||
},
|
||||
},
|
||||
password,
|
||||
@@ -219,7 +269,11 @@ if (isCli) {
|
||||
});
|
||||
|
||||
logger.info("Starting webserver...", field("host", options.host), field("port", options.port));
|
||||
app.server.listen(options.port, options.host);
|
||||
if (options.socket) {
|
||||
app.server.listen(options.socket);
|
||||
} else {
|
||||
app.server.listen(options.port, options.host);
|
||||
}
|
||||
let clientId = 1;
|
||||
app.wss.on("connection", (ws, req) => {
|
||||
const id = clientId++;
|
||||
@@ -234,11 +288,20 @@ if (isCli) {
|
||||
logger.info(`WebSocket closed \u001B[0m${req.url}`, field("client", id), field("code", code));
|
||||
});
|
||||
});
|
||||
|
||||
app.wss.on("error", (err: NodeJS.ErrnoException) => {
|
||||
if (err.code === "EADDRINUSE") {
|
||||
if (options.socket) {
|
||||
logger.error(`Socket ${bold(options.socket)} is in use. Please specify a different socket.`);
|
||||
} else {
|
||||
logger.error(`Port ${bold(options.port)} is in use. Please free up port ${options.port} or specify a different port with the -p flag`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
if (!options.certKey && !options.cert) {
|
||||
logger.warn("No certificate specified. \u001B[1mThis could be insecure.");
|
||||
// TODO: fill in appropriate doc url
|
||||
logger.warn("Documentation on securing your setup: https://coder.com/docs");
|
||||
logger.warn("Documentation on securing your setup: https://github.com/codercom/code-server/blob/master/doc/security/ssl.md");
|
||||
}
|
||||
|
||||
if (!options.noAuth) {
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as os from "os";
|
||||
import { isCli, buildDir } from "./constants";
|
||||
|
||||
/**
|
||||
* Handling of native modules within the CLI
|
||||
*/
|
||||
export const setup = (dataDirectory: string): void => {
|
||||
path.resolve(dataDirectory, "dependencies").split(path.sep).reduce((parentDir, childDir) => {
|
||||
const currentDir = path.join(parentDir, childDir);
|
||||
try {
|
||||
fs.mkdirSync(currentDir);
|
||||
} catch (ex) {
|
||||
if (ex.code !== "EEXIST" && ex.code !== "EISDIR" && ex.code !== "ENOENT") {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
return currentDir;
|
||||
}, os.platform() === "win32" ? undefined! : path.sep); // Might need path.sep here for linux. Having it for windows causes an error because \C:\Users ...
|
||||
|
||||
const unpackModule = (moduleName: string, markExecutable: boolean = false): void => {
|
||||
const memFile = path.join(isCli ? buildDir! : path.join(__dirname, ".."), "build/dependencies", moduleName);
|
||||
const diskFile = path.join(dataDirectory, "dependencies", moduleName);
|
||||
if (!fs.existsSync(diskFile)) {
|
||||
fs.writeFileSync(diskFile, fs.readFileSync(memFile));
|
||||
}
|
||||
if (markExecutable) {
|
||||
fs.chmodSync(diskFile, "755");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* We need to unpack node-pty and patch its `loadNative` function to require our unpacked pty.node
|
||||
* If pty.node isn't unpacked a SIGSEGV is thrown and the application exits. The exact reasoning
|
||||
* for this is unknown ATM, but this patch works around it.
|
||||
*/
|
||||
unpackModule("pty.node");
|
||||
unpackModule("spdlog.node");
|
||||
unpackModule("rg", true);
|
||||
// const nodePtyUtils = require("../../protocol/node_modules/node-pty-prebuilt/lib/utils") as typeof import("../../protocol/node_modules/node-pty-prebuilt/src/utils");
|
||||
// tslint:disable-next-line:no-any
|
||||
// nodePtyUtils.loadNative = (modName: string): any => {
|
||||
// return (typeof __non_webpack_require__ !== "undefined" ? __non_webpack_require__ : require)(path.join(dataDirectory, "dependencies", modName + ".node"));
|
||||
// };
|
||||
(<any>global).RIPGREP_LOCATION = path.join(dataDirectory, "dependencies", "rg");
|
||||
(<any>global).NODEPTY_LOCATION = path.join(dataDirectory, "dependencies", "pty.node");
|
||||
// tslint:disable-next-line:no-any
|
||||
(<any>global).SPDLOG_LOCATION = path.join(dataDirectory, "dependencies", "spdlog.node");
|
||||
// tslint:disable-next-line:no-unused-expression
|
||||
require("../../protocol/node_modules/node-pty-prebuilt/lib/index") as typeof import("../../protocol/node_modules/node-pty-prebuilt/src/index");
|
||||
};
|
||||
@@ -17,7 +17,7 @@ export interface PortScanner {
|
||||
* Will scan local ports and emit events when ports are added or removed.
|
||||
* Currently only scans TCP ports.
|
||||
*/
|
||||
export const createPortScanner = (scanInterval: number = 250): PortScanner => {
|
||||
export const createPortScanner = (scanInterval: number = 5000): PortScanner => {
|
||||
const ports = new Map<number, number>();
|
||||
|
||||
const addEmitter = new Emitter<number[]>();
|
||||
@@ -76,9 +76,14 @@ export const createPortScanner = (scanInterval: number = 250): PortScanner => {
|
||||
let disposed: boolean = false;
|
||||
|
||||
const doInterval = (): void => {
|
||||
logger.trace("scanning ports");
|
||||
scan((error) => {
|
||||
if (error) {
|
||||
logger.error(`Port scanning will not be available: ${error.message}.`);
|
||||
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
||||
logger.warn("Port scanning will not be available because netstat is not installed");
|
||||
} else {
|
||||
logger.warn(`Port scanning will not be available: ${error.message}`);
|
||||
}
|
||||
disposed = true;
|
||||
} else if (!disposed) {
|
||||
lastTimeout = setTimeout(doInterval, scanInterval);
|
||||
|
||||
@@ -18,6 +18,7 @@ import * as os from "os";
|
||||
import * as path from "path";
|
||||
import * as pem from "pem";
|
||||
import * as util from "util";
|
||||
import * as url from "url";
|
||||
import * as ws from "ws";
|
||||
import { buildDir } from "./constants";
|
||||
import { createPortScanner } from "./portScanner";
|
||||
@@ -140,13 +141,13 @@ export const createApp = async (options: CreateAppOptions): Promise<{
|
||||
};
|
||||
|
||||
const portScanner = createPortScanner();
|
||||
wss.on("connection", (ws, req) => {
|
||||
wss.on("connection", async (ws, req) => {
|
||||
if (req.url && req.url.startsWith("/tunnel")) {
|
||||
try {
|
||||
const rawPort = req.url.split("/").pop();
|
||||
const port = Number.parseInt(rawPort!, 10);
|
||||
|
||||
handleTunnel(ws, port);
|
||||
await handleTunnel(ws, port);
|
||||
} catch (ex) {
|
||||
ws.close(TunnelCloseCode.Error, ex.toString());
|
||||
}
|
||||
@@ -189,31 +190,70 @@ export const createApp = async (options: CreateAppOptions): Promise<{
|
||||
new Server(connection, options.serverOptions);
|
||||
});
|
||||
|
||||
const redirect = (
|
||||
req: express.Request, res: express.Response,
|
||||
to: string = "", from: string = "",
|
||||
code: number = 302, protocol: string = req.protocol,
|
||||
): void => {
|
||||
const currentUrl = `${protocol}://${req.headers.host}${req.originalUrl}`;
|
||||
const newUrl = url.parse(currentUrl);
|
||||
if (from && newUrl.pathname) {
|
||||
newUrl.pathname = newUrl.pathname.replace(new RegExp(`\/${from}\/?$`), "/");
|
||||
}
|
||||
if (to) {
|
||||
newUrl.pathname = (newUrl.pathname || "").replace(/\/$/, "") + `/${to}`;
|
||||
}
|
||||
newUrl.path = undefined; // Path is not necessary for format().
|
||||
const newUrlString = url.format(newUrl);
|
||||
logger.trace(`Redirecting from ${currentUrl} to ${newUrlString}`);
|
||||
|
||||
return res.redirect(code, newUrlString);
|
||||
};
|
||||
|
||||
const baseDir = buildDir || path.join(__dirname, "..");
|
||||
const authStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/auth"));
|
||||
const unauthStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/unauth"));
|
||||
const staticGzip = expressStaticGzip(path.join(baseDir, "build/web"));
|
||||
|
||||
app.use((req, res, next) => {
|
||||
logger.trace(`\u001B[1m${req.method} ${res.statusCode} \u001B[0m${req.originalUrl}`, field("host", req.hostname), field("ip", req.ip));
|
||||
|
||||
// Force HTTPS unless allowing HTTP.
|
||||
if (!isEncrypted(req.socket) && !options.allowHttp) {
|
||||
return res.redirect(301, `https://${req.headers.host!}${req.path}`);
|
||||
return redirect(req, res, "", "", 301, "https");
|
||||
}
|
||||
|
||||
if (isAuthed(req)) {
|
||||
// We can serve the actual VSCode bin
|
||||
authStaticFunc(req, res, next);
|
||||
} else {
|
||||
// Serve only the unauthed version
|
||||
unauthStaticFunc(req, res, next);
|
||||
}
|
||||
});
|
||||
// @ts-ignore
|
||||
app.use((err, req, res, next) => {
|
||||
next();
|
||||
});
|
||||
app.get("/ping", (req, res) => {
|
||||
|
||||
// @ts-ignore
|
||||
app.use((err, _req, _res, next) => {
|
||||
logger.error(err.message);
|
||||
next();
|
||||
});
|
||||
|
||||
// If not authenticated, redirect to the login page.
|
||||
app.get("/", (req, res, next) => {
|
||||
if (!isAuthed(req)) {
|
||||
return redirect(req, res, "login");
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
// If already authenticated, redirect back to the root.
|
||||
app.get("/login", (req, res, next) => {
|
||||
if (isAuthed(req)) {
|
||||
return redirect(req, res, "", "login");
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
// For getting general server data.
|
||||
app.get("/ping", (_req, res) => {
|
||||
res.json({
|
||||
hostname: os.hostname(),
|
||||
});
|
||||
});
|
||||
|
||||
// For getting a resource on disk.
|
||||
app.get("/resource/:url(*)", async (req, res) => {
|
||||
if (!ensureAuthed(req, res)) {
|
||||
return;
|
||||
@@ -254,6 +294,8 @@ export const createApp = async (options: CreateAppOptions): Promise<{
|
||||
res.end();
|
||||
}
|
||||
});
|
||||
|
||||
// For writing a resource to disk.
|
||||
app.post("/resource/:url(*)", async (req, res) => {
|
||||
if (!ensureAuthed(req, res)) {
|
||||
return;
|
||||
@@ -271,7 +313,7 @@ export const createApp = async (options: CreateAppOptions): Promise<{
|
||||
const body = data.join("");
|
||||
await mkdirp(path.dirname(fullPath));
|
||||
fs.writeFileSync(fullPath, body);
|
||||
logger.debug("Wrote resource", field("path", fullPath), field("content-length", body.length));
|
||||
logger.info("Wrote resource", field("path", fullPath), field("content-length", body.length));
|
||||
res.status(200);
|
||||
res.end();
|
||||
});
|
||||
@@ -282,6 +324,9 @@ export const createApp = async (options: CreateAppOptions): Promise<{
|
||||
}
|
||||
});
|
||||
|
||||
// Everything else just pulls from the static build directory.
|
||||
app.use(staticGzip);
|
||||
|
||||
return {
|
||||
express: app,
|
||||
server,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import * as cp from "child_process";
|
||||
import * as fs from "fs";
|
||||
import * as os from "os";
|
||||
import * as path from "path";
|
||||
import * as vm from "vm";
|
||||
import { logger } from "@coder/logger";
|
||||
import { buildDir, isCli } from "../constants";
|
||||
|
||||
let ipcMsgBuffer: Buffer[] | undefined = [];
|
||||
@@ -40,54 +42,13 @@ const requireFilesystemModule = (id: string, builtInExtensionsDir: string): any
|
||||
return customMod.require(id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Called from forking a module
|
||||
*/
|
||||
export const requireFork = (modulePath: string, args: string[], builtInExtensionsDir: string): void => {
|
||||
const Module = require("module") as typeof import("module");
|
||||
const oldRequire = Module.prototype.require;
|
||||
// tslint:disable-next-line:no-any
|
||||
const oldLoad = (Module as any)._findPath;
|
||||
// @ts-ignore
|
||||
(Module as any)._findPath = function (request, parent, isMain): any {
|
||||
const lookupPaths = oldLoad.call(this, request, parent, isMain);
|
||||
|
||||
return lookupPaths;
|
||||
};
|
||||
// tslint:disable-next-line:no-any
|
||||
Module.prototype.require = function (id: string): any {
|
||||
if (id === "typescript") {
|
||||
return require("typescript");
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
return oldRequire.call(this, id as any);
|
||||
};
|
||||
|
||||
if (!process.send) {
|
||||
throw new Error("No IPC messaging initialized");
|
||||
}
|
||||
|
||||
process.argv = ["", "", ...args];
|
||||
requireFilesystemModule(modulePath, builtInExtensionsDir);
|
||||
|
||||
if (ipcMsgBuffer && ipcMsgListener) {
|
||||
process.removeListener("message", ipcMsgListener);
|
||||
// tslint:disable-next-line:no-any
|
||||
ipcMsgBuffer.forEach((i) => process.emit("message" as any, i as any));
|
||||
ipcMsgBuffer = undefined;
|
||||
ipcMsgListener = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export const requireModule = (modulePath: string, dataDir: string, builtInExtensionsDir: string): void => {
|
||||
export const requireModule = (modulePath: string, builtInExtensionsDir: string): void => {
|
||||
process.env.AMD_ENTRYPOINT = modulePath;
|
||||
const xml = require("xhr2");
|
||||
xml.XMLHttpRequest.prototype._restrictedHeaders["user-agent"] = false;
|
||||
// tslint:disable-next-line no-any this makes installing extensions work.
|
||||
(global as any).XMLHttpRequest = xml.XMLHttpRequest;
|
||||
|
||||
const mod = require("module") as typeof import("module");
|
||||
const promiseFinally = require("promise.prototype.finally") as { shim: () => void };
|
||||
promiseFinally.shim();
|
||||
/**
|
||||
@@ -100,16 +61,7 @@ export const requireModule = (modulePath: string, dataDir: string, builtInExtens
|
||||
};
|
||||
|
||||
if (isCli) {
|
||||
/**
|
||||
* Needed for properly forking external modules within the CLI
|
||||
*/
|
||||
// tslint:disable-next-line:no-any
|
||||
(<any>cp).fork = (modulePath: string, args: ReadonlyArray<string> = [], options?: cp.ForkOptions): cp.ChildProcess => {
|
||||
return cp.spawn(process.execPath, [path.join(buildDir, "out", "cli.js"), "--fork", modulePath, "--extra-args", JSON.stringify(args), "--data-dir", dataDir], {
|
||||
...options,
|
||||
stdio: [null, null, null, "ipc"],
|
||||
});
|
||||
};
|
||||
process.env.NBIN_BYPASS = "true";
|
||||
}
|
||||
|
||||
const baseDir = path.join(buildDir, "build");
|
||||
@@ -130,7 +82,6 @@ export const requireModule = (modulePath: string, dataDir: string, builtInExtens
|
||||
* @param modulePath Path of the VS Code module to load.
|
||||
*/
|
||||
export const forkModule = (modulePath: string, args?: string[], options?: cp.ForkOptions, dataDir?: string): cp.ChildProcess => {
|
||||
let proc: cp.ChildProcess;
|
||||
const forkOptions: cp.ForkOptions = {
|
||||
stdio: [null, null, null, "ipc"],
|
||||
};
|
||||
@@ -139,17 +90,33 @@ export const forkModule = (modulePath: string, args?: string[], options?: cp.For
|
||||
delete options.env.ELECTRON_RUN_AS_NODE;
|
||||
forkOptions.env = options.env;
|
||||
}
|
||||
|
||||
const forkArgs = ["--bootstrap-fork", modulePath];
|
||||
if (args) {
|
||||
forkArgs.push("--extra-args", JSON.stringify(args));
|
||||
}
|
||||
if (dataDir) {
|
||||
forkArgs.push("--data-dir", dataDir);
|
||||
forkArgs.push("--user-data-dir", dataDir);
|
||||
}
|
||||
|
||||
const nodeArgs = [];
|
||||
if (isCli) {
|
||||
proc = cp.spawn(process.execPath, [path.join(buildDir, "out", "cli.js"), ...forkArgs], forkOptions);
|
||||
nodeArgs.push(path.join(buildDir, "out", "cli.js"));
|
||||
} else {
|
||||
proc = cp.spawn(process.execPath, ["--require", "ts-node/register", "--require", "tsconfig-paths/register", process.argv[1], ...forkArgs], forkOptions);
|
||||
nodeArgs.push(
|
||||
"--require", "ts-node/register",
|
||||
"--require", "tsconfig-paths/register",
|
||||
process.argv[1],
|
||||
);
|
||||
}
|
||||
|
||||
const proc = cp.spawn(process.execPath, [...nodeArgs, ...forkArgs], forkOptions);
|
||||
if (args && args[0] === "--type=watcherService" && os.platform() === "linux") {
|
||||
cp.exec(`renice -n 19 -p ${proc.pid}`, (error) => {
|
||||
if (error) {
|
||||
logger.warn(error.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return proc;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ChildProcess } from "child_process";
|
||||
import * as fs from "fs";
|
||||
import * as os from "os";
|
||||
import * as path from "path";
|
||||
import { forkModule } from "./bootstrapFork";
|
||||
@@ -23,123 +22,139 @@ export type SharedProcessEvent = {
|
||||
};
|
||||
|
||||
export class SharedProcess {
|
||||
public readonly socketPath: string = os.platform() === "win32" ? path.join("\\\\?\\pipe", os.tmpdir(), `.code-server${Math.random().toString()}`) : path.join(os.tmpdir(), `.code-server${Math.random().toString()}`);
|
||||
public readonly socketPath: string = os.platform() === "win32"
|
||||
? path.join("\\\\?\\pipe", os.tmpdir(), `.code-server${Math.random().toString()}`)
|
||||
: path.join(os.tmpdir(), `.code-server${Math.random().toString()}`);
|
||||
private _state: SharedProcessState = SharedProcessState.Stopped;
|
||||
private activeProcess: ChildProcess | undefined;
|
||||
private ipcHandler: StdioIpcHandler | undefined;
|
||||
private readonly onStateEmitter = new Emitter<SharedProcessEvent>();
|
||||
public readonly onState = this.onStateEmitter.event;
|
||||
private readonly retryName = "Shared process";
|
||||
private readonly logger = logger.named("shared");
|
||||
private readonly retry = retry.register("Shared process", () => this.connect());
|
||||
private disposed: boolean = false;
|
||||
|
||||
public constructor(
|
||||
private readonly userDataDir: string,
|
||||
private readonly extensionsDir: string,
|
||||
private readonly builtInExtensionsDir: string,
|
||||
) {
|
||||
retry.register(this.retryName, () => this.restart());
|
||||
retry.run(this.retryName);
|
||||
this.retry.run();
|
||||
}
|
||||
|
||||
public get state(): SharedProcessState {
|
||||
return this._state;
|
||||
}
|
||||
|
||||
public restart(): void {
|
||||
if (this.activeProcess && !this.activeProcess.killed) {
|
||||
this.activeProcess.kill();
|
||||
}
|
||||
|
||||
const extensionsDir = path.join(this.userDataDir, "extensions");
|
||||
const mkdir = (dir: string): void => {
|
||||
try {
|
||||
fs.mkdirSync(dir);
|
||||
} catch (ex) {
|
||||
if (ex.code !== "EEXIST" && ex.code !== "EISDIR") {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
};
|
||||
mkdir(this.userDataDir);
|
||||
mkdir(extensionsDir);
|
||||
|
||||
this.setState({
|
||||
state: SharedProcessState.Starting,
|
||||
});
|
||||
let resolved: boolean = false;
|
||||
const maybeStop = (error: string): void => {
|
||||
if (resolved) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
error,
|
||||
state: SharedProcessState.Stopped,
|
||||
});
|
||||
if (!this.activeProcess) {
|
||||
return;
|
||||
}
|
||||
this.activeProcess.kill();
|
||||
};
|
||||
this.activeProcess = forkModule("vs/code/electron-browser/sharedProcess/sharedProcessMain", [], {
|
||||
env: {
|
||||
VSCODE_ALLOW_IO: "true",
|
||||
VSCODE_LOGS: process.env.VSCODE_LOGS,
|
||||
},
|
||||
}, this.userDataDir);
|
||||
if (this.logger.level <= Level.Trace) {
|
||||
this.activeProcess.stdout.on("data", (data) => {
|
||||
this.logger.trace(() => ["stdout", field("data", data.toString())]);
|
||||
});
|
||||
}
|
||||
this.activeProcess.on("error", (error) => {
|
||||
this.logger.error("error", field("error", error));
|
||||
maybeStop(error.message);
|
||||
});
|
||||
this.activeProcess.on("exit", (err) => {
|
||||
if (this._state !== SharedProcessState.Stopped) {
|
||||
this.setState({
|
||||
error: `Exited with ${err}`,
|
||||
state: SharedProcessState.Stopped,
|
||||
});
|
||||
}
|
||||
retry.run(this.retryName, new Error(`Exited with ${err}`));
|
||||
});
|
||||
this.ipcHandler = new StdioIpcHandler(this.activeProcess);
|
||||
this.ipcHandler.once("handshake:hello", () => {
|
||||
const data: {
|
||||
sharedIPCHandle: string;
|
||||
args: Partial<ParsedArgs>;
|
||||
logLevel: Level;
|
||||
} = {
|
||||
args: {
|
||||
"builtin-extensions-dir": this.builtInExtensionsDir,
|
||||
"user-data-dir": this.userDataDir,
|
||||
"extensions-dir": extensionsDir,
|
||||
},
|
||||
logLevel: this.logger.level,
|
||||
sharedIPCHandle: this.socketPath,
|
||||
};
|
||||
this.ipcHandler!.send("handshake:hey there", "", data);
|
||||
});
|
||||
this.ipcHandler.once("handshake:im ready", () => {
|
||||
resolved = true;
|
||||
retry.recover(this.retryName);
|
||||
this.setState({
|
||||
state: SharedProcessState.Ready,
|
||||
});
|
||||
});
|
||||
this.activeProcess.stderr.on("data", (data) => {
|
||||
this.logger.error("stderr", field("data", data.toString()));
|
||||
maybeStop(data.toString());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal the shared process to terminate.
|
||||
*/
|
||||
public dispose(): void {
|
||||
this.disposed = true;
|
||||
if (this.ipcHandler) {
|
||||
this.ipcHandler.send("handshake:goodbye");
|
||||
}
|
||||
this.ipcHandler = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start and connect to the shared process.
|
||||
*/
|
||||
private async connect(): Promise<void> {
|
||||
this.setState({ state: SharedProcessState.Starting });
|
||||
const activeProcess = await this.restart();
|
||||
|
||||
activeProcess.on("exit", (exitCode) => {
|
||||
const error = new Error(`Exited with ${exitCode}`);
|
||||
this.setState({
|
||||
error: error.message,
|
||||
state: SharedProcessState.Stopped,
|
||||
});
|
||||
if (!this.disposed) {
|
||||
this.retry.run(error);
|
||||
}
|
||||
});
|
||||
|
||||
this.setState({ state: SharedProcessState.Ready });
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart the shared process. Kill existing process if running. Resolve when
|
||||
* the shared process is ready and reject when it errors or dies before being
|
||||
* ready.
|
||||
*/
|
||||
private async restart(): Promise<ChildProcess> {
|
||||
if (this.activeProcess && !this.activeProcess.killed) {
|
||||
this.activeProcess.kill();
|
||||
}
|
||||
|
||||
const activeProcess = forkModule("vs/code/electron-browser/sharedProcess/sharedProcessMain", [], {
|
||||
env: {
|
||||
VSCODE_ALLOW_IO: "true",
|
||||
VSCODE_LOGS: process.env.VSCODE_LOGS,
|
||||
DISABLE_TELEMETRY: process.env.DISABLE_TELEMETRY,
|
||||
},
|
||||
}, this.userDataDir);
|
||||
this.activeProcess = activeProcess;
|
||||
|
||||
await new Promise((resolve, reject): void => {
|
||||
const doReject = (error: Error | number | null): void => {
|
||||
if (error === null) {
|
||||
error = new Error("Exited unexpectedly");
|
||||
} else if (typeof error === "number") {
|
||||
error = new Error(`Exited with ${error}`);
|
||||
}
|
||||
activeProcess.removeAllListeners();
|
||||
this.setState({
|
||||
error: error.message,
|
||||
state: SharedProcessState.Stopped,
|
||||
});
|
||||
reject(error);
|
||||
};
|
||||
|
||||
activeProcess.on("error", doReject);
|
||||
activeProcess.on("exit", doReject);
|
||||
|
||||
activeProcess.stdout.on("data", (data) => {
|
||||
logger.trace("stdout", field("data", data.toString()));
|
||||
});
|
||||
|
||||
activeProcess.stderr.on("data", (data) => {
|
||||
// Warn instead of error to prevent panic. It's unlikely stderr here is
|
||||
// about anything critical to the functioning of the editor.
|
||||
logger.warn("stderr", field("data", data.toString()));
|
||||
});
|
||||
|
||||
this.ipcHandler = new StdioIpcHandler(activeProcess);
|
||||
this.ipcHandler.once("handshake:hello", () => {
|
||||
const data: {
|
||||
sharedIPCHandle: string;
|
||||
args: Partial<ParsedArgs>;
|
||||
logLevel: Level;
|
||||
} = {
|
||||
args: {
|
||||
"builtin-extensions-dir": this.builtInExtensionsDir,
|
||||
"user-data-dir": this.userDataDir,
|
||||
"extensions-dir": this.extensionsDir,
|
||||
},
|
||||
logLevel: this.logger.level,
|
||||
sharedIPCHandle: this.socketPath,
|
||||
};
|
||||
this.ipcHandler!.send("handshake:hey there", "", data);
|
||||
});
|
||||
this.ipcHandler.once("handshake:im ready", () => {
|
||||
activeProcess.removeListener("error", doReject);
|
||||
activeProcess.removeListener("exit", doReject);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
return activeProcess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the internal shared process state and emit the state event.
|
||||
*/
|
||||
private setState(event: SharedProcessEvent): void {
|
||||
this._state = event.state;
|
||||
this.onStateEmitter.emit(event);
|
||||
|
||||
@@ -6,14 +6,12 @@ const root = path.resolve(__dirname, "../..");
|
||||
|
||||
module.exports = merge(
|
||||
require(path.join(root, "scripts/webpack.node.config.js"))({
|
||||
// Config options.
|
||||
dirname: __dirname,
|
||||
}), {
|
||||
output: {
|
||||
filename: "cli.js",
|
||||
path: path.join(__dirname, "out"),
|
||||
libraryTarget: "commonjs",
|
||||
},
|
||||
mode: "production",
|
||||
node: {
|
||||
console: false,
|
||||
global: false,
|
||||
@@ -23,14 +21,8 @@ module.exports = merge(
|
||||
__dirname: false,
|
||||
setImmediate: false
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"node-pty": "node-pty-prebuilt",
|
||||
},
|
||||
},
|
||||
externals: {
|
||||
"nbin": "commonjs nbin",
|
||||
"fsevents": "fsevents",
|
||||
},
|
||||
entry: "./packages/server/src/cli.ts",
|
||||
plugins: [
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@coder/logger/-/logger-1.0.3.tgz#e0e1ae5496fde5a3c6ef3d748fdfb26a55add8b8"
|
||||
integrity sha512-1o5qDZX2VZUNnzgz5KfAdMnaqaX6FNeTs0dUdg73MRHfQW94tFTIryFC1xTTCuzxGDjVHOHkaUAI4uHA2bheOA==
|
||||
|
||||
"@coder/nbin@^1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@coder/nbin/-/nbin-1.0.4.tgz#13a3d110fe116ed5d5fdbd1384f0335745dfd859"
|
||||
integrity sha512-mtd5hzPHWBwKpTCYdJdLdiY4CFCEb8HUtv3NgH8SSLFiPDwY7H1UlpqeamIty27NZ+9NLnrBd/DfaE3aVo7rxQ==
|
||||
"@coder/nbin@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@coder/nbin/-/nbin-1.1.2.tgz#3af9e4368f37532da446c7c291d476bb52de995d"
|
||||
integrity sha512-MkwKpmu1SU9wkBwQ+bZVU2nPzENWUa3Isut9osVq3LG+udovsk+k5c5rjfJ1q8cf4km5snjOSYiulug3n9sdgw==
|
||||
dependencies:
|
||||
"@coder/logger" "^1.0.3"
|
||||
fs-extra "^7.0.1"
|
||||
|
||||
@@ -12,6 +12,7 @@ import { IFileService, FileOperation } from "vs/platform/files/common/files";
|
||||
import { ITextFileService } from "vs/workbench/services/textfile/common/textfiles";
|
||||
import { IModelService } from "vs/editor/common/services/modelService";
|
||||
import { ITerminalService } from "vs/workbench/contrib/terminal/common/terminal";
|
||||
import { IStorageService } from "vs/platform/storage/common/storage";
|
||||
// NOTE: shouldn't import anything from VS Code here or anything that will
|
||||
// depend on a synchronous fill like `os`.
|
||||
|
||||
@@ -38,6 +39,14 @@ class VSClient extends IdeClient {
|
||||
// tslint:disable-next-line:no-any
|
||||
statusbarService: getService<IStatusbarService>(IStatusbarService) as any,
|
||||
notificationService: getService<INotificationService>(INotificationService),
|
||||
storageService: {
|
||||
save: (): Promise<void> => {
|
||||
// tslint:disable-next-line:no-any
|
||||
const storageService = getService<IStorageService>(IStorageService) as any;
|
||||
|
||||
return storageService.close();
|
||||
},
|
||||
},
|
||||
|
||||
onFileCreate: (cb): void => {
|
||||
getService<IFileService>(IFileService).onAfterOperation((e) => {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
--primary: #2A2E37;
|
||||
--border: black;
|
||||
--faded: #a0a1a5;
|
||||
--disabled: #888;
|
||||
--header-background: #161616;
|
||||
--header-foreground: white;
|
||||
--list-active-selection-background: rgb(0, 120, 160);
|
||||
@@ -101,6 +102,12 @@
|
||||
background-color: var(--list-active-selection-background);
|
||||
color: var(--list-active-selection-foreground);
|
||||
}
|
||||
|
||||
&.disabled, &.disabled:hover {
|
||||
background-color: var(--primary);
|
||||
color: var(--disabled);
|
||||
cursor: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +141,11 @@
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
button[disabled], button[disabled]:hover {
|
||||
color: var(--disabled);
|
||||
cursor: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ import { IThemeService } from "vs/platform/theme/common/themeService";
|
||||
import { workbench } from "./workbench";
|
||||
import "./dialog.scss";
|
||||
|
||||
/**
|
||||
* Describes the type of dialog to show.
|
||||
*/
|
||||
export enum DialogType {
|
||||
NewFolder,
|
||||
Save,
|
||||
@@ -68,8 +71,12 @@ interface DialogEntry {
|
||||
readonly isDirectory: boolean;
|
||||
readonly size: number;
|
||||
readonly lastModified: string;
|
||||
readonly isDisabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open and save dialogs.
|
||||
*/
|
||||
class Dialog {
|
||||
private _path: string | undefined;
|
||||
|
||||
@@ -108,7 +115,7 @@ class Dialog {
|
||||
this.root.style.width = "850px";
|
||||
this.root.style.height = "600px";
|
||||
this.background.appendChild(this.root);
|
||||
(document.getElementById("workbench.main.container") || document.body).appendChild(this.background);
|
||||
(document.querySelector(".monaco-workbench") || document.body).appendChild(this.background);
|
||||
this.root.classList.add("dialog");
|
||||
|
||||
const setProperty = (vari: string, id: string): void => {
|
||||
@@ -263,10 +270,12 @@ class Dialog {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's a directory, we want to navigate to it. If it's a file, then we
|
||||
// only want to open it if opening files is supported.
|
||||
if (element.isDirectory) {
|
||||
this.path = element.fullPath;
|
||||
} else {
|
||||
// Open
|
||||
} else if ((this.options as OpenDialogOptions).properties.openFile) {
|
||||
this.selectEmitter.emit(element.fullPath);
|
||||
}
|
||||
});
|
||||
@@ -282,12 +291,20 @@ class Dialog {
|
||||
});
|
||||
buttonsNode.appendChild(cancelBtn);
|
||||
const confirmBtn = document.createElement("button");
|
||||
confirmBtn.innerText = "Confirm";
|
||||
const openDirectory = (this.options as OpenDialogOptions).properties.openDirectory;
|
||||
confirmBtn.innerText = this.options.buttonLabel || "Confirm";
|
||||
confirmBtn.addEventListener("click", () => {
|
||||
if (this._path) {
|
||||
if (this._path && openDirectory) {
|
||||
this.selectEmitter.emit(this._path);
|
||||
}
|
||||
});
|
||||
// Disable if we can't open directories, otherwise you can open a directory
|
||||
// as a file which won't work. This is because our button currently just
|
||||
// always opens whatever directory is opened and will not open selected
|
||||
// files. (A single click on a file is used to open it instead.)
|
||||
if (!openDirectory) {
|
||||
confirmBtn.disabled = true;
|
||||
}
|
||||
buttonsNode.appendChild(confirmBtn);
|
||||
this.root.appendChild(buttonsNode);
|
||||
this.entryList.layout();
|
||||
@@ -303,6 +320,9 @@ class Dialog {
|
||||
return this.errorEmitter.event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the dialog.
|
||||
*/
|
||||
public dispose(): void {
|
||||
this.selectEmitter.dispose();
|
||||
this.errorEmitter.dispose();
|
||||
@@ -310,6 +330,9 @@ class Dialog {
|
||||
this.background.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and insert the path shown at the top of the dialog.
|
||||
*/
|
||||
private buildPath(): void {
|
||||
while (this.pathNode.lastChild) {
|
||||
this.pathNode.removeChild(this.pathNode.lastChild);
|
||||
@@ -376,6 +399,9 @@ class Dialog {
|
||||
return (<any>this.entryList).typeFilterController.filter._pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the files and return dialog entries.
|
||||
*/
|
||||
private async list(directory: string): Promise<ReadonlyArray<DialogEntry>> {
|
||||
const paths = (await util.promisify(fs.readdir)(directory)).sort();
|
||||
const stats = await Promise.all(paths.map(p => util.promisify(fs.stat)(path.join(directory, p))));
|
||||
@@ -386,6 +412,9 @@ class Dialog {
|
||||
isDirectory: stat.isDirectory(),
|
||||
lastModified: stat.mtime.toDateString(),
|
||||
size: stat.size,
|
||||
// If we can't open files, show them as disabled.
|
||||
isDisabled: !stat.isDirectory()
|
||||
&& !(this.options as OpenDialogOptions).properties.openFile,
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -397,11 +426,17 @@ interface DialogEntryData {
|
||||
label: HighlightedLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendering for the different parts of a dialog entry.
|
||||
*/
|
||||
class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEntryData> {
|
||||
public get templateId(): string {
|
||||
return "dialog-entry";
|
||||
}
|
||||
|
||||
/**
|
||||
* Append and return containers for each part of the dialog entry.
|
||||
*/
|
||||
public renderTemplate(container: HTMLElement): DialogEntryData {
|
||||
addClass(container, "dialog-entry");
|
||||
addClass(container, "dialog-grid");
|
||||
@@ -422,6 +457,9 @@ class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEn
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a dialog entry.
|
||||
*/
|
||||
public renderElement(node: ITreeNode<DialogEntry, string>, _index: number, templateData: DialogEntryData): void {
|
||||
templateData.icon.className = "dialog-entry-icon monaco-icon-label";
|
||||
const classes = getIconClasses(
|
||||
@@ -444,8 +482,19 @@ class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEn
|
||||
}] : []);
|
||||
templateData.size.innerText = node.element.size.toString();
|
||||
templateData.lastModified.innerText = node.element.lastModified;
|
||||
|
||||
// We know this exists because we created the template.
|
||||
const entryContainer = templateData.label.element.parentElement!.parentElement!.parentElement!;
|
||||
if (node.element.isDisabled) {
|
||||
entryContainer.classList.add("disabled");
|
||||
} else {
|
||||
entryContainer.classList.remove("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing (not implemented).
|
||||
*/
|
||||
public disposeTemplate(_templateData: DialogEntryData): void {
|
||||
// throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
170
packages/vscode/src/fill/applicationInsights.ts
Normal file
170
packages/vscode/src/fill/applicationInsights.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* Used by node
|
||||
*/
|
||||
import * as https from "https";
|
||||
import * as os from "os";
|
||||
|
||||
export const defaultClient = "filler";
|
||||
|
||||
export class TelemetryClient {
|
||||
public channel = {
|
||||
setUseDiskRetryCaching: (): void => undefined,
|
||||
};
|
||||
|
||||
public constructor() {
|
||||
//
|
||||
}
|
||||
|
||||
public trackEvent(options: {
|
||||
name: string;
|
||||
properties: object;
|
||||
measurements: object;
|
||||
}): void {
|
||||
if (!options.properties) {
|
||||
options.properties = {};
|
||||
}
|
||||
if (!options.measurements) {
|
||||
options.measurements = {};
|
||||
}
|
||||
|
||||
try {
|
||||
const cpus = os.cpus();
|
||||
// tslint:disable-next-line:no-any
|
||||
(options.measurements as any).cpu = {
|
||||
model: cpus[0].model,
|
||||
cores: cpus.length,
|
||||
};
|
||||
} catch (ex) {
|
||||
// Nothin
|
||||
}
|
||||
|
||||
try {
|
||||
// tslint:disable-next-line:no-any
|
||||
(options.measurements as any).memory = {
|
||||
virtual_free: os.freemem(),
|
||||
virtual_used: os.totalmem(),
|
||||
};
|
||||
} catch (ex) {
|
||||
//
|
||||
}
|
||||
|
||||
try {
|
||||
// tslint:disable:no-any
|
||||
(options.properties as any)["common.shell"] = os.userInfo().shell;
|
||||
(options.properties as any)["common.release"] = os.release();
|
||||
(options.properties as any)["common.arch"] = os.arch();
|
||||
// tslint:enable:no-any
|
||||
} catch (ex) {
|
||||
//
|
||||
}
|
||||
|
||||
try {
|
||||
// tslint:disable-next-line:no-any
|
||||
(options.properties as any)["common.machineId"] = machineIdSync();
|
||||
} catch (ex) {
|
||||
//
|
||||
}
|
||||
|
||||
try {
|
||||
const request = https.request({
|
||||
host: "v1.telemetry.coder.com",
|
||||
port: 443,
|
||||
path: "/track",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
request.on("error", () => {
|
||||
// Do nothing, we don"t really care
|
||||
});
|
||||
request.write(JSON.stringify(options));
|
||||
request.end();
|
||||
} catch (ex) {
|
||||
// Suppress all errs
|
||||
}
|
||||
}
|
||||
|
||||
public flush(options: {
|
||||
readonly callback: () => void;
|
||||
}): void {
|
||||
options.callback();
|
||||
}
|
||||
}
|
||||
|
||||
// Taken from https://github.com/automation-stack/node-machine-id
|
||||
import { exec, execSync } from "child_process";
|
||||
import { createHash } from "crypto";
|
||||
|
||||
const isWindowsProcessMixedOrNativeArchitecture = (): "" | "mixed" | "native" => {
|
||||
// detect if the node binary is the same arch as the Windows OS.
|
||||
// or if this is 32 bit node on 64 bit windows.
|
||||
if (process.platform !== "win32") {
|
||||
return "";
|
||||
}
|
||||
if (process.arch === "ia32" && process.env.hasOwnProperty("PROCESSOR_ARCHITEW6432")) {
|
||||
return "mixed";
|
||||
}
|
||||
|
||||
return "native";
|
||||
};
|
||||
|
||||
let { platform } = process,
|
||||
win32RegBinPath = {
|
||||
native: "%windir%\\System32",
|
||||
mixed: "%windir%\\sysnative\\cmd.exe /c %windir%\\System32",
|
||||
"": "",
|
||||
},
|
||||
guid = {
|
||||
darwin: "ioreg -rd1 -c IOPlatformExpertDevice",
|
||||
win32: `${win32RegBinPath[isWindowsProcessMixedOrNativeArchitecture()]}\\REG ` +
|
||||
"QUERY HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography " +
|
||||
"/v MachineGuid",
|
||||
linux: "( cat /var/lib/dbus/machine-id /etc/machine-id 2> /dev/null || hostname ) | head -n 1 || :",
|
||||
freebsd: "kenv -q smbios.system.uuid || sysctl -n kern.hostuuid",
|
||||
// tslint:disable-next-line:no-any
|
||||
} as any;
|
||||
|
||||
const hash = (guid: string): string => {
|
||||
return createHash("sha256").update(guid).digest("hex");
|
||||
};
|
||||
|
||||
const expose = (result: string): string => {
|
||||
switch (platform) {
|
||||
case "darwin":
|
||||
return result
|
||||
.split("IOPlatformUUID")[1]
|
||||
.split("\n")[0].replace(/\=|\s+|\"/ig, "")
|
||||
.toLowerCase();
|
||||
case "win32":
|
||||
return result
|
||||
.toString()
|
||||
.split("REG_SZ")[1]
|
||||
.replace(/\r+|\n+|\s+/ig, "")
|
||||
.toLowerCase();
|
||||
case "linux":
|
||||
return result
|
||||
.toString()
|
||||
.replace(/\r+|\n+|\s+/ig, "")
|
||||
.toLowerCase();
|
||||
case "freebsd":
|
||||
return result
|
||||
.toString()
|
||||
.replace(/\r+|\n+|\s+/ig, "")
|
||||
.toLowerCase();
|
||||
default:
|
||||
throw new Error(`Unsupported platform: ${process.platform}`);
|
||||
}
|
||||
};
|
||||
|
||||
let cachedMachineId: string | undefined;
|
||||
|
||||
const machineIdSync = (): string => {
|
||||
if (cachedMachineId) {
|
||||
return cachedMachineId;
|
||||
}
|
||||
let id: string = expose(execSync(guid[platform]).toString());
|
||||
cachedMachineId = hash(id);
|
||||
|
||||
return cachedMachineId;
|
||||
};
|
||||
@@ -1,14 +1,16 @@
|
||||
import * as path from "path";
|
||||
import * as paths from "./paths";
|
||||
import * as environment from "vs/platform/environment/node/environmentService";
|
||||
|
||||
/**
|
||||
* Customize paths using data received from the initialization message.
|
||||
*/
|
||||
export class EnvironmentService extends environment.EnvironmentService {
|
||||
public get sharedIPCHandle(): string {
|
||||
return paths.getSocketPath() || super.sharedIPCHandle;
|
||||
}
|
||||
|
||||
public get extensionsPath(): string {
|
||||
return path.join(paths.getAppDataPath(), "extensions");
|
||||
return paths.getExtensionsDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,36 @@
|
||||
import { logger } from "@coder/logger";
|
||||
import { IDisposable } from "vs/base/common/lifecycle";
|
||||
import * as actions from "vs/platform/actions/common/actions";
|
||||
import { CloseWorkspaceAction } from "vs/workbench/browser/actions/workspaceActions";
|
||||
import { OpenProcessExplorer } from "vs/workbench/contrib/issue/electron-browser/issueActions";
|
||||
import { ToggleDevToolsAction } from "vs/workbench/electron-browser/actions/developerActions";
|
||||
import { OpenPrivacyStatementUrlAction, OpenRequestFeatureUrlAction, OpenTwitterUrlAction } from "vs/workbench/electron-browser/actions/helpActions";
|
||||
import { CloseCurrentWindowAction, NewWindowAction, ShowAboutDialogAction } from "vs/workbench/electron-browser/actions/windowActions";
|
||||
|
||||
const toSkip = [
|
||||
ToggleDevToolsAction.ID,
|
||||
OpenTwitterUrlAction.ID,
|
||||
OpenPrivacyStatementUrlAction.ID,
|
||||
ShowAboutDialogAction.ID,
|
||||
OpenProcessExplorer.ID,
|
||||
OpenRequestFeatureUrlAction.ID,
|
||||
NewWindowAction.ID,
|
||||
CloseCurrentWindowAction.ID,
|
||||
CloseWorkspaceAction.ID,
|
||||
|
||||
// Unfortunately referenced as a string
|
||||
"update.showCurrentReleaseNotes",
|
||||
"workbench.action.openIssueReporter",
|
||||
];
|
||||
|
||||
// Intercept appending menu items so we can skip items that won't work.
|
||||
const originalAppend = actions.MenuRegistry.appendMenuItem.bind(actions.MenuRegistry);
|
||||
actions.MenuRegistry.appendMenuItem = (id: actions.MenuId, item: actions.IMenuItem | actions.ISubmenuItem): IDisposable => {
|
||||
if (actions.isIMenuItem(item)) {
|
||||
switch (item.command.id) {
|
||||
case ToggleDevToolsAction.ID: // There appears to be no way to toggle this programmatically.
|
||||
logger.debug(`Skipping unsupported menu item ${item.command.id}`);
|
||||
|
||||
return {
|
||||
dispose: (): void => undefined,
|
||||
};
|
||||
if (toSkip.indexOf(item.command.id) !== -1) {
|
||||
// Skip instantiation
|
||||
return {
|
||||
dispose: (): void => undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import * as nls from "vs/nls";
|
||||
import { Action } from "vs/base/common/actions";
|
||||
import { TERMINAL_COMMAND_ID } from "vs/workbench/contrib/terminal/common/terminalCommands";
|
||||
import { ITerminalService } from "vs/workbench/contrib/terminal/common/terminal";
|
||||
import * as actions from "vs/workbench/contrib/terminal/electron-browser/terminalActions";
|
||||
import * as instance from "vs/workbench/contrib/terminal/electron-browser/terminalInstance";
|
||||
import * as actions from "vs/workbench/contrib/terminal/browser/terminalActions";
|
||||
import * as instance from "vs/workbench/contrib/terminal/browser/terminalInstance";
|
||||
import { client } from "../client";
|
||||
|
||||
const getLabel = (key: string, enabled: boolean): string => {
|
||||
|
||||
@@ -4,6 +4,7 @@ class Paths {
|
||||
private _appData: string | undefined;
|
||||
private _defaultUserData: string | undefined;
|
||||
private _socketPath: string | undefined;
|
||||
private _extensionsDirectory: string | undefined;
|
||||
private _builtInExtensionsDirectory: string | undefined;
|
||||
private _workingDirectory: string | undefined;
|
||||
|
||||
@@ -31,6 +32,14 @@ class Paths {
|
||||
return this._socketPath;
|
||||
}
|
||||
|
||||
public get extensionsDirectory(): string {
|
||||
if (!this._extensionsDirectory) {
|
||||
throw new Error("trying to access extensions directory before it has been set");
|
||||
}
|
||||
|
||||
return this._extensionsDirectory;
|
||||
}
|
||||
|
||||
public get builtInExtensionsDirectory(): string {
|
||||
if (!this._builtInExtensionsDirectory) {
|
||||
throw new Error("trying to access builtin extensions directory before it has been set");
|
||||
@@ -52,6 +61,7 @@ class Paths {
|
||||
this._appData = data.dataDirectory;
|
||||
this._defaultUserData = data.dataDirectory;
|
||||
this._socketPath = sharedData.socketPath;
|
||||
this._extensionsDirectory = data.extensionsDirectory;
|
||||
this._builtInExtensionsDirectory = data.builtInExtensionsDirectory;
|
||||
this._workingDirectory = data.workingDirectory;
|
||||
}
|
||||
@@ -61,5 +71,6 @@ export const _paths = new Paths();
|
||||
export const getAppDataPath = (): string => _paths.appData;
|
||||
export const getDefaultUserDataPath = (): string => _paths.defaultUserData;
|
||||
export const getWorkingDirectory = (): string => _paths.workingDirectory;
|
||||
export const getExtensionsDirectory = (): string => _paths.extensionsDirectory;
|
||||
export const getBuiltInExtensionsDirectory = (): string => _paths.builtInExtensionsDirectory;
|
||||
export const getSocketPath = (): string => _paths.socketPath;
|
||||
|
||||
@@ -4,6 +4,20 @@ import { IProductConfiguration } from "vs/platform/product/node/product";
|
||||
class Product implements IProductConfiguration {
|
||||
public nameShort = "code-server";
|
||||
public nameLong = "code-server";
|
||||
public documentationUrl = "https://code.visualstudio.com/docs";
|
||||
public keyboardShortcutsUrlMac = "https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf";
|
||||
public keyboardShortcutsUrlLinux = "https://code.visualstudio.com/shortcuts/keyboard-shortcuts-linux.pdf";
|
||||
public keyboardShortcutsUrlWin = "https://code.visualstudio.com/shortcuts/keyboard-shortcuts-windows.pdf";
|
||||
public introductoryVideosUrl = "https://code.visualstudio.com/docs/getstarted/introvideos";
|
||||
public tipsAndTricksUrl = "https://code.visualstudio.com/docs/getstarted/tips-and-tricks";
|
||||
public twitterUrl = "https://twitter.com/code";
|
||||
public licenseUrl = "https://github.com/codercom/code-server/blob/master/LICENSE";
|
||||
public aiConfig = process.env.DISABLE_TELEMETRY ? undefined! : {
|
||||
// Only needed so vscode can see that content exists for this value.
|
||||
// We override the application insights module.
|
||||
asimovKey: "content",
|
||||
};
|
||||
public enableTelemetry = process.env.DISABLE_TELEMETRY ? false : true;
|
||||
|
||||
private _dataFolderName: string | undefined;
|
||||
public get dataFolderName(): string {
|
||||
@@ -18,7 +32,8 @@ class Product implements IProductConfiguration {
|
||||
serviceUrl: global && global.process && global.process.env.SERVICE_URL
|
||||
|| process.env.SERVICE_URL
|
||||
|| "https://v1.extapi.coder.com",
|
||||
};
|
||||
// tslint:disable-next-line:no-any
|
||||
} as any;
|
||||
|
||||
public extensionExecutionEnvironments = {
|
||||
"wayou.vscode-todo-highlight": "worker",
|
||||
|
||||
@@ -11,6 +11,8 @@ import { IStorageService, WillSaveStateReason } from "vs/platform/storage/common
|
||||
import * as paths from "./paths";
|
||||
import { workbench } from "../workbench";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
class StorageDatabase implements workspaceStorage.IStorageDatabase {
|
||||
public readonly onDidChangeItemsExternal = Event.None;
|
||||
private readonly items = new Map<string, string>();
|
||||
@@ -26,7 +28,8 @@ class StorageDatabase implements workspaceStorage.IStorageDatabase {
|
||||
}
|
||||
|
||||
this.triggerFlush(WillSaveStateReason.SHUTDOWN);
|
||||
navigator.sendBeacon(`/resource${this.path}`, this.content);
|
||||
const resourceBaseUrl = location.pathname.replace(/\/$/, "") + "/resource";
|
||||
navigator.sendBeacon(`${resourceBaseUrl}/${this.path}`, this.content);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,17 @@ import * as vscodeTextmate from "../../../../lib/vscode/node_modules/vscode-text
|
||||
|
||||
const target = vscodeTextmate as typeof vscodeTextmate;
|
||||
|
||||
const ctx = (require as any).context("../../../../lib/extensions", true, /.*\.tmLanguage.json$/);
|
||||
// Maps grammar scope to loaded grammar
|
||||
const scopeToGrammar = {} as any;
|
||||
|
||||
ctx.keys().forEach((key: string) => {
|
||||
const value = ctx(key);
|
||||
if (value.scopeName) {
|
||||
scopeToGrammar[value.scopeName] = value;
|
||||
}
|
||||
});
|
||||
|
||||
target.Registry = class Registry extends vscodeTextmate.Registry {
|
||||
public constructor(opts: vscodeTextmate.RegistryOptions) {
|
||||
super({
|
||||
@@ -21,6 +32,13 @@ target.Registry = class Registry extends vscodeTextmate.Registry {
|
||||
}).catch(reason => rej(reason));
|
||||
});
|
||||
},
|
||||
loadGrammar: async (scopeName: string) => {
|
||||
if (scopeToGrammar[scopeName]) {
|
||||
return scopeToGrammar[scopeName];
|
||||
}
|
||||
|
||||
return opts.loadGrammar(scopeName);
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,21 +1,32 @@
|
||||
import * as electron from "electron";
|
||||
import { Emitter } from "@coder/events";
|
||||
import * as windowsIpc from "vs/platform/windows/node/windowsIpc";
|
||||
import { IWindowsService, INativeOpenDialogOptions, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, IMessageBoxResult, IDevToolsOptions, IEnterWorkspaceResult, CrashReporterStartOptions, INewWindowOptions, IOpenFileRequest, IAddFoldersRequest } from "vs/platform/windows/common/windows";
|
||||
import { logger } from "@coder/logger";
|
||||
import { IWindowsService, INativeOpenDialogOptions, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, IMessageBoxResult, IDevToolsOptions, IEnterWorkspaceResult, CrashReporterStartOptions, INewWindowOptions, IOpenFileRequest, IAddFoldersRequest, IURIToOpen, IOpenSettings } from "vs/platform/windows/common/windows";
|
||||
import { ParsedArgs } from "vs/platform/environment/common/environment";
|
||||
import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier } from "vs/platform/workspaces/common/workspaces";
|
||||
import { URI } from "vs/base/common/uri";
|
||||
import { IRecentlyOpened } from "vs/platform/history/common/history";
|
||||
import { IRecentlyOpened, IRecent } from "vs/platform/history/common/history";
|
||||
import { ISerializableCommandAction } from "vs/platform/actions/common/actions";
|
||||
import { client } from "../client";
|
||||
import { showOpenDialog } from "../dialog";
|
||||
import { workbench } from "../workbench";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
// VS Code overrides window.open to call openExternal, but we then call
|
||||
// window.open which results in an infinite loop. Store the function but also
|
||||
// make it unable to be set (doesn't work otherwise).
|
||||
const windowOpen = window.open;
|
||||
Object.defineProperty(window, "open", {
|
||||
set: (): void => { /* Not allowed. */ },
|
||||
get: (): Function => windowOpen,
|
||||
});
|
||||
|
||||
/**
|
||||
* Instead of going to the shared process, we'll directly run these methods on
|
||||
* the client. This setup means we can only control the current window.
|
||||
*/
|
||||
class WindowsService implements IWindowsService {
|
||||
export class WindowsService implements IWindowsService {
|
||||
// tslint:disable-next-line no-any
|
||||
public _serviceBrand: any;
|
||||
|
||||
@@ -36,9 +47,9 @@ class WindowsService implements IWindowsService {
|
||||
private readonly window = new electron.BrowserWindow();
|
||||
|
||||
// Dialogs
|
||||
public async pickFileFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
public async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||
showOpenDialog({
|
||||
...(_options.dialogOptions || {}),
|
||||
...(options.dialogOptions || {}),
|
||||
properties: {
|
||||
openFile: true,
|
||||
openDirectory: true,
|
||||
@@ -51,13 +62,13 @@ class WindowsService implements IWindowsService {
|
||||
}],
|
||||
} as IOpenFileRequest);
|
||||
}).catch((ex) => {
|
||||
//
|
||||
logger.error(ex.message);
|
||||
});
|
||||
}
|
||||
|
||||
public async pickFileAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
public async pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||
showOpenDialog({
|
||||
...(_options.dialogOptions || {}),
|
||||
...(options.dialogOptions || {}),
|
||||
properties: {
|
||||
openFile: true,
|
||||
},
|
||||
@@ -69,26 +80,32 @@ class WindowsService implements IWindowsService {
|
||||
}],
|
||||
} as IOpenFileRequest);
|
||||
}).catch((ex) => {
|
||||
//
|
||||
logger.error(ex.message);
|
||||
});
|
||||
}
|
||||
|
||||
public async pickFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
public async pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||
if (!options.dialogOptions) {
|
||||
options.dialogOptions = {};
|
||||
}
|
||||
if (!options.dialogOptions.title) {
|
||||
options.dialogOptions.title = "Open Folder";
|
||||
}
|
||||
showOpenDialog({
|
||||
...(_options.dialogOptions || {}),
|
||||
...(options.dialogOptions || {}),
|
||||
properties: {
|
||||
openDirectory: true,
|
||||
},
|
||||
}).then((path) => {
|
||||
workbench.workspace = URI.file(path);
|
||||
}).catch((ex) => {
|
||||
//
|
||||
logger.error(ex.message);
|
||||
});
|
||||
}
|
||||
|
||||
public async pickWorkspaceAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
public async pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||
showOpenDialog({
|
||||
...(_options.dialogOptions || {}),
|
||||
...(options.dialogOptions || {}),
|
||||
properties: {
|
||||
openDirectory: true,
|
||||
},
|
||||
@@ -98,7 +115,7 @@ class WindowsService implements IWindowsService {
|
||||
foldersToAdd: [URI.file(path)],
|
||||
} as IAddFoldersRequest);
|
||||
}).catch((ex) => {
|
||||
//
|
||||
logger.error(ex.message);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -121,16 +138,14 @@ class WindowsService implements IWindowsService {
|
||||
});
|
||||
}
|
||||
|
||||
public showOpenDialog(windowId: number, options: OpenDialogOptions): Promise<string[]> {
|
||||
return showOpenDialog({
|
||||
public async showOpenDialog(_windowId: number, options: OpenDialogOptions): Promise<string[]> {
|
||||
return [await showOpenDialog({
|
||||
...(options || {}),
|
||||
properties: {
|
||||
openDirectory: true,
|
||||
openFile: true,
|
||||
openDirectory: options && options.properties && options.properties.includes("openDirectory") || false,
|
||||
openFile: options && options.properties && options.properties.includes("openFile") || false,
|
||||
},
|
||||
}).then((path) => {
|
||||
return [path];
|
||||
});
|
||||
})];
|
||||
}
|
||||
|
||||
public reloadWindow(windowId: number, _args?: ParsedArgs): Promise<void> {
|
||||
@@ -149,14 +164,14 @@ class WindowsService implements IWindowsService {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public enterWorkspace(_windowId: number, _path: URI): Promise<IEnterWorkspaceResult> {
|
||||
if (_path.path.endsWith(".json")) {
|
||||
public enterWorkspace(_windowId: number, uri: URI): Promise<IEnterWorkspaceResult> {
|
||||
if (uri.path.endsWith(".json")) {
|
||||
workbench.workspace = {
|
||||
id: "Untitled",
|
||||
configPath: _path.path,
|
||||
configPath: uri,
|
||||
};
|
||||
} else {
|
||||
workbench.workspace = _path;
|
||||
workbench.workspace = uri;
|
||||
}
|
||||
|
||||
return undefined!;
|
||||
@@ -180,7 +195,7 @@ class WindowsService implements IWindowsService {
|
||||
return Promise.resolve(this.getWindowById(windowId).setRepresentedFilename(fileName));
|
||||
}
|
||||
|
||||
public addRecentlyOpened(_files: URI[]): Promise<void> {
|
||||
public addRecentlyOpened(_files: IRecent[]): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
@@ -284,7 +299,7 @@ class WindowsService implements IWindowsService {
|
||||
}
|
||||
|
||||
// Global methods
|
||||
public openWindow(_windowId: number, _paths: URI[], _options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean, forceOpenWorkspaceAsFile?: boolean, args?: ParsedArgs }): Promise<void> {
|
||||
public openWindow(_windowId: number, _uris: IURIToOpen[], _options?: IOpenSettings): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
@@ -308,8 +323,8 @@ class WindowsService implements IWindowsService {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public async showItemInFolder(_path: string): Promise<void> {
|
||||
workbench.workspace = URI.file(_path);
|
||||
public async showItemInFolder(uri: URI): Promise<void> {
|
||||
workbench.workspace = uri;
|
||||
}
|
||||
|
||||
public getActiveWindowId(): Promise<number | undefined> {
|
||||
@@ -343,7 +358,3 @@ class WindowsService implements IWindowsService {
|
||||
return this.window;
|
||||
}
|
||||
}
|
||||
|
||||
const target = windowsIpc as typeof windowsIpc;
|
||||
// @ts-ignore TODO: don't ignore it.
|
||||
target.WindowsChannelClient = WindowsService;
|
||||
|
||||
@@ -5,7 +5,7 @@ import { IWorkbenchActionRegistry, Extensions } from "vs/workbench/common/action
|
||||
import { SyncActionDescriptor } from "vs/platform/actions/common/actions";
|
||||
import { ContextKeyExpr } from "vs/platform/contextkey/common/contextkey";
|
||||
import { ToggleDevToolsAction } from "vs/workbench/electron-browser/actions/developerActions";
|
||||
import { TerminalPasteAction } from "vs/workbench/contrib/terminal/electron-browser/terminalActions";
|
||||
import { TerminalPasteAction } from "vs/workbench/contrib/terminal/browser/terminalActions";
|
||||
import { KEYBINDING_CONTEXT_TERMINAL_FOCUS } from "vs/workbench/contrib/terminal/common/terminal";
|
||||
import { KeyCode, KeyMod } from "vs/base/common/keyCodes";
|
||||
import { workbench } from "../workbench";
|
||||
|
||||
@@ -53,3 +53,7 @@
|
||||
width: 56px !important;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.window-controls-container {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as os from "os";
|
||||
import { IProgress, INotificationHandle } from "@coder/ide";
|
||||
import { logger } from "@coder/logger";
|
||||
import { client } from "./client";
|
||||
|
||||
import "./fill/platform";
|
||||
@@ -29,11 +30,20 @@ import { RawContextKey, IContextKeyService } from "vs/platform/contextkey/common
|
||||
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
|
||||
import { URI } from "vs/base/common/uri";
|
||||
|
||||
/**
|
||||
* Initializes VS Code and provides a way to call into general client
|
||||
* functionality.
|
||||
*/
|
||||
export class Workbench {
|
||||
public readonly retry = client.retry;
|
||||
|
||||
private readonly windowId = parseInt(new Date().toISOString().replace(/[-:.TZ]/g, ""), 10);
|
||||
private _serviceCollection: ServiceCollection | undefined;
|
||||
private _clipboardContextKey: RawContextKey<boolean> | undefined;
|
||||
|
||||
/**
|
||||
* Handle a drop event on the file explorer.
|
||||
*/
|
||||
public async handleExternalDrop(target: ExplorerItem | ExplorerModel, originalEvent: DragEvent): Promise<void> {
|
||||
await client.upload.uploadDropped(
|
||||
originalEvent,
|
||||
@@ -41,11 +51,14 @@ export class Workbench {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a drop event on the editor.
|
||||
*/
|
||||
public handleDrop(event: DragEvent, resolveTargetGroup: () => IEditorGroup, afterDrop: (targetGroup: IEditorGroup) => void, targetIndex?: number): void {
|
||||
client.upload.uploadDropped(event, URI.file(paths.getWorkingDirectory())).then((paths) => {
|
||||
client.upload.uploadDropped(event, URI.file(paths.getWorkingDirectory())).then(async (paths) => {
|
||||
const uris = paths.map((p) => URI.file(p));
|
||||
if (uris.length) {
|
||||
(this.serviceCollection.get(IWindowsService) as IWindowsService).addRecentlyOpened(uris);
|
||||
await (this.serviceCollection.get(IWindowsService) as IWindowsService).addRecentlyOpened(uris);
|
||||
}
|
||||
|
||||
const editors: IResourceEditor[] = uris.map(uri => ({
|
||||
@@ -57,10 +70,10 @@ export class Workbench {
|
||||
}));
|
||||
|
||||
const targetGroup = resolveTargetGroup();
|
||||
|
||||
(this.serviceCollection.get(IEditorService) as IEditorService).openEditors(editors, targetGroup).then(() => {
|
||||
afterDrop(targetGroup);
|
||||
});
|
||||
await (this.serviceCollection.get(IEditorService) as IEditorService).openEditors(editors, targetGroup);
|
||||
afterDrop(targetGroup);
|
||||
}).catch((error) => {
|
||||
logger.error(error.message);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -115,6 +128,14 @@ export class Workbench {
|
||||
|
||||
public set serviceCollection(collection: ServiceCollection) {
|
||||
this._serviceCollection = collection;
|
||||
|
||||
const contextKeys = this.serviceCollection.get(IContextKeyService) as IContextKeyService;
|
||||
const bounded = this.clipboardContextKey.bindTo(contextKeys);
|
||||
client.clipboard.onPermissionChange((enabled) => {
|
||||
bounded.set(enabled);
|
||||
});
|
||||
client.clipboard.initialize();
|
||||
|
||||
client.progressService = {
|
||||
start: <T>(title: string, task: (progress: IProgress) => Promise<T>, onCancel: () => void): Promise<T> => {
|
||||
let lastProgress = 0;
|
||||
@@ -164,6 +185,9 @@ export class Workbench {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Start VS Code.
|
||||
*/
|
||||
public async initialize(): Promise<void> {
|
||||
this._clipboardContextKey = new RawContextKey("nativeClipboard", client.clipboard.isEnabled);
|
||||
|
||||
@@ -210,12 +234,6 @@ export class Workbench {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const contextKeys = this.serviceCollection.get(IContextKeyService) as IContextKeyService;
|
||||
const bounded = this.clipboardContextKey.bindTo(contextKeys);
|
||||
client.clipboard.onPermissionChange((enabled) => {
|
||||
bounded.set(enabled);
|
||||
});
|
||||
client.clipboard.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ const vsFills = path.join(root, "packages/vscode/src/fill");
|
||||
|
||||
module.exports = merge(
|
||||
require(path.join(root, "scripts/webpack.node.config.js"))({
|
||||
dirname: __dirname,
|
||||
typescriptCompilerOptions: {
|
||||
target: "es6",
|
||||
},
|
||||
@@ -15,7 +16,6 @@ module.exports = merge(
|
||||
mode: "development",
|
||||
output: {
|
||||
chunkFilename: "[name].bundle.js",
|
||||
path: path.resolve(__dirname, "out"),
|
||||
publicPath: "/",
|
||||
filename: "bootstrap-fork.js",
|
||||
libraryTarget: "commonjs",
|
||||
@@ -36,7 +36,8 @@ module.exports = merge(
|
||||
loader: "ignore-loader",
|
||||
}],
|
||||
}, {
|
||||
test: /((\\|\/)vs(\\|\/)code(\\|\/)electron-main(\\|\/))|((\\|\/)test(\\|\/))|(OSSREADME\.json$)|\/browser\//,
|
||||
// The only thing we need in electron-browser is the shared process (including contrib).
|
||||
test: /((\\|\/)vs(\\|\/)code(\\|\/)electron-main(\\|\/))|((\\|\/)test(\\|\/))|(OSSREADME\.json$)|\/browser\/|\/electron-browser\/(?!sharedProcess\/).+\//,
|
||||
use: [{
|
||||
loader: "ignore-loader",
|
||||
}],
|
||||
@@ -50,15 +51,17 @@ module.exports = merge(
|
||||
"windows-mutex": path.resolve(fills, "empty.ts"),
|
||||
"windows-process-tree": path.resolve(fills, "empty.ts"),
|
||||
"vscode-windows-registry": path.resolve(fills, "empty.ts"),
|
||||
"vscode-windows-ca-certs": path.resolve(fills, "empty.ts"),
|
||||
"vscode-sqlite3": path.resolve(fills, "empty.ts"),
|
||||
"vs/base/browser/browser": path.resolve(fills, "empty.ts"),
|
||||
|
||||
"applicationinsights": path.join(vsFills, "applicationInsights.ts"),
|
||||
"electron": path.join(vsFills, "stdioElectron.ts"),
|
||||
"vscode-ripgrep": path.join(vsFills, "ripgrep.ts"),
|
||||
"native-keymap": path.join(vsFills, "native-keymap.ts"),
|
||||
"native-watchdog": path.join(vsFills, "native-watchdog.ts"),
|
||||
"vs/base/common/amd": path.resolve(vsFills, "amd.ts"),
|
||||
"vs/base/node/paths": path.resolve(vsFills, "paths.ts"),
|
||||
"vs/base/node/paths": path.join(vsFills, "paths.ts"),
|
||||
"vs/platform/product/node/package": path.resolve(vsFills, "package.ts"),
|
||||
"vs/platform/product/node/product": path.resolve(vsFills, "product.ts"),
|
||||
"vs/base/node/zip": path.resolve(vsFills, "zip.ts"),
|
||||
|
||||
BIN
packages/web/assets/logo.png
Normal file
BIN
packages/web/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coder/web",
|
||||
"scripts": {
|
||||
"build": "../../node_modules/.bin/cross-env UV_THREADPOOL_SIZE=100 node --max-old-space-size=32384 ../../node_modules/webpack/bin/webpack.js --config ./webpack.config.js"
|
||||
}
|
||||
"name": "@coder/web",
|
||||
"scripts": {
|
||||
"build": "../../node_modules/.bin/cross-env UV_THREADPOOL_SIZE=100 node --max-old-space-size=32384 ../../node_modules/webpack/bin/webpack.js --config ./webpack.config.js"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,14 @@
|
||||
}
|
||||
document.body.style.background = bg;
|
||||
})();
|
||||
|
||||
// Check that service workers are registered
|
||||
if ("serviceWorker" in navigator) {
|
||||
// Use the window load event to keep the page load performant
|
||||
window.addEventListener("load", () => {
|
||||
navigator.serviceWorker.register("/service-worker.js");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -7,7 +7,9 @@ const vsFills = path.join(root, "packages/vscode/src/fill");
|
||||
|
||||
module.exports = merge(
|
||||
require(path.join(root, "scripts/webpack.client.config.js"))({
|
||||
dirname: __dirname,
|
||||
entry: path.join(root, "packages/web/src/index.ts"),
|
||||
name: "ide",
|
||||
template: path.join(root, "packages/web/src/index.html"),
|
||||
typescriptCompilerOptions: {
|
||||
"target": "es5",
|
||||
@@ -15,11 +17,6 @@ module.exports = merge(
|
||||
},
|
||||
},
|
||||
), {
|
||||
output: {
|
||||
chunkFilename: "[name]-[hash:6].bundle.js",
|
||||
path: path.join(__dirname, "out"),
|
||||
filename: "[hash:6].bundle.js",
|
||||
},
|
||||
node: {
|
||||
module: "empty",
|
||||
crypto: "empty",
|
||||
@@ -70,6 +67,7 @@ module.exports = merge(
|
||||
// This seems to be in the wrong place?
|
||||
"vs/workbench/contrib/codeEditor/electron-browser/media/WordWrap_16x.svg": "vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/WordWrap_16x.svg",
|
||||
|
||||
"vs/platform/windows/electron-browser/windowsService": path.join(vsFills, "windowsService.ts"),
|
||||
"vs/base/node/paths": path.join(vsFills, "paths.ts"),
|
||||
"vs/base/common/amd": path.join(vsFills, "amd.ts"),
|
||||
"vs/platform/product/node/package": path.resolve(vsFills, "package.ts"),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
24
scripts/vstar.sh
Executable file
24
scripts/vstar.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
|
||||
# Builds a tarfile containing vscode sourcefiles neccessary for CI.
|
||||
# Done outside the CI and uploaded to object storage to reduce CI time.
|
||||
|
||||
branch=1.33.1
|
||||
dir=/tmp/vstar
|
||||
outfile=/tmp/vstar-$branch.tar.gz
|
||||
rm -rf $dir
|
||||
mkdir -p $dir
|
||||
|
||||
cd $dir
|
||||
git clone https://github.com/microsoft/vscode --branch $branch --single-branch --depth=1
|
||||
cd vscode
|
||||
|
||||
yarn
|
||||
|
||||
npx gulp vscode-linux-x64 --max-old-space-size=32384
|
||||
rm -rf extensions build out* test
|
||||
cd ..
|
||||
mv *-x64/resources/app/extensions ./extensions
|
||||
rm -rf *-x64
|
||||
tar -czvf $outfile .
|
||||
@@ -4,10 +4,12 @@ const merge = require("webpack-merge");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const PreloadWebpackPlugin = require("preload-webpack-plugin");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
// const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
|
||||
const WebpackPwaManifest = require("webpack-pwa-manifest");
|
||||
const { GenerateSW } = require("workbox-webpack-plugin");
|
||||
|
||||
const root = path.join(__dirname, "..");
|
||||
const prod = process.env.NODE_ENV === "production" || process.env.CI === "true";
|
||||
const cachePattern = /\.(?:png|jpg|jpeg|svg|css|js|ttf|woff|eot|woff2|wasm)$/;
|
||||
|
||||
module.exports = (options = {}) => merge(
|
||||
require("./webpack.general.config")(options), {
|
||||
@@ -30,29 +32,57 @@ module.exports = (options = {}) => merge(
|
||||
loader: "sass-loader",
|
||||
}],
|
||||
}, {
|
||||
test: /\.(svg|png|ttf|woff|eot|woff2)$/,
|
||||
test: /\.(png|ttf|woff|eot|woff2)$/,
|
||||
use: [{
|
||||
loader: "file-loader",
|
||||
options: {
|
||||
name: "[path][name].[ext]",
|
||||
},
|
||||
}],
|
||||
}, {
|
||||
test: /\.svg$/,
|
||||
loader: 'url-loader'
|
||||
}],
|
||||
},
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "[name].css",
|
||||
chunkFilename: "[id].css",
|
||||
chunkFilename: `${options.name || "client"}.[name].[hash:6].css`,
|
||||
filename: `${options.name || "client"}.[name].[hash:6].css`
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: options.template,
|
||||
template: options.template
|
||||
}),
|
||||
new PreloadWebpackPlugin({
|
||||
rel: "preload",
|
||||
as: "script",
|
||||
as: "script"
|
||||
}),
|
||||
].concat(prod ? [] : [
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
]),
|
||||
target: "web",
|
||||
new WebpackPwaManifest({
|
||||
name: "Coder",
|
||||
short_name: "Coder",
|
||||
description: "Run VS Code on a remote server",
|
||||
background_color: "#e5e5e5",
|
||||
icons: [{
|
||||
src: path.join(root, "packages/web/assets/logo.png"),
|
||||
sizes: [96, 128, 192, 256, 384],
|
||||
}],
|
||||
})
|
||||
].concat(prod ? [
|
||||
new GenerateSW({
|
||||
include: [cachePattern],
|
||||
runtimeCaching: [{
|
||||
urlPattern: cachePattern,
|
||||
handler: "StaleWhileRevalidate",
|
||||
options: {
|
||||
cacheName: "code-server",
|
||||
expiration: {
|
||||
maxAgeSeconds: 86400,
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200],
|
||||
},
|
||||
},
|
||||
},
|
||||
]}),
|
||||
] : [new webpack.HotModuleReplacementPlugin()]),
|
||||
target: "web"
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user