Compare commits

..

84 Commits

Author SHA1 Message Date
Kyle Carberry
2bc6e1a457 Fix clipboard pasting 2019-04-22 20:20:48 -04:00
Kyle Carberry
e61ea796c6 Bundle grammars (#563) 2019-04-22 12:51:05 -05:00
Kyle Carberry
d073622629 Add --socket flag (#564)
* Add --socket flag

* Add msg for already bound socket
2019-04-22 12:47:27 -05:00
Kyle Carberry
5f40ebb845 Update wording for sshcode 2019-04-19 21:22:00 -04:00
Kyle Carberry
c56e2797cc Add sshcode to the readme 2019-04-19 21:20:31 -04:00
Kyle Carberry
166efcb17e Hide titlebar controls and fix menubar toggle (#550) 2019-04-19 19:54:50 -05:00
Kyle Carberry
206e107a9a Merge branch 'master' of github.com:codercom/code-server 2019-04-19 20:03:54 -04:00
Kyle Carberry
12c8b5d337 Closes #466 2019-04-19 20:03:52 -04:00
Asher
4aa20fd864 Fix require.toUrl on the Node side
- Fixes #542
2019-04-19 13:32:10 -05:00
Illia Poplawski
0cd4e46055 Fix self hosted flags (#523)
* Remove -h flag for help information

* Add tab after removing -h option

* Remove spaces after --user-data-dir option to line up with other menu items
2019-04-18 13:02:29 -05:00
Asher
f51823b51f Fix open dialog
- Fixes #508
2019-04-18 12:08:44 -05:00
Asher
55bfeab208 Deprecate password flag in favor of an environment variable 2019-04-18 11:10:55 -05:00
Asher
309d15cefd Use file/folder open commands for all operating systems
Mac was using its own thing.

- Fixes #535
- Fixes #501
2019-04-18 10:50:23 -05:00
Kyle Carberry
95006a435a Merge branch 'master' of github.com:codercom/code-server 2019-04-17 21:01:25 -04:00
Kyle Carberry
4d576ab4d4 Trigger configuration update when loaded 2019-04-17 21:01:23 -04:00
Asher
d5b03ef60e Remove version from Docker command 2019-04-17 17:38:22 -05:00
Kyle Carberry
c3a38e3fea Add telemetry and option to disable (#519)
* Add telemetry and option to disable

* Update readme and getting-started guide

* Update lockfile

* Update getting started guide
2019-04-17 17:18:35 -05:00
Asher
cc8c7e2cee Make assets unique (#518)
* Make all assets unique

All CSS and JavaScript files have unique names now. I also moved the
login to the /login path in order to ensure the HTML for each page is
also unique.

* Explicitly include assets to cache
2019-04-17 17:18:20 -05:00
Kyle Carberry
e0f1787ce6 Update logger 2019-04-17 17:47:02 -04:00
John McCambridge
50e6108012 Add confirmation for closing window (#463)
* Add confirmation for closing window

* Make function an event listener for consistency

* Change let to const

* Refactor for compatability
2019-04-17 16:42:36 -05:00
Asher
630ccfcacc Add flag to install an extension from the command line (#504) 2019-04-17 16:30:50 -05:00
Patrick Smith
c4c26058ef Use port from PORT env variable if available (#502) 2019-04-17 16:30:39 -05:00
Kyle Carberry
8a4da542ae Add GCP logging extender (#503)
* Add GCP logging extender

* Minor version bump for new API

* Update packages/logger/src/logger.ts

Co-Authored-By: kylecarbs <kyle@kwc.io>
2019-04-17 13:41:10 -05:00
Luca Casonato
e907dbe7e6 fixe password signin with service-worker (#511) 2019-04-17 10:27:24 -05:00
Luca Casonato
22b485acd9 Added serviceworker and web-manifest (#154)
* Added serviceworker and manifest.json

* added deps in package.json

* fixed image link

* actually fixed images i think

* added assets to individual module folders

* added caching

* Serviceworker now properly loads

* Changed single to double quotes

* Update lock

* moved the service worker back into prod only

* removed sw from general

* changed background color of splash screen

* added logo to server

* centralized logo into single assets folder
2019-04-16 15:44:57 -05:00
Asher
b8f222acf2 Ensure all environment paths are created
This normally happens in electron-main/main.ts but we don't run anything
from there.

Fixes #499.
2019-04-16 10:58:13 -05:00
Asher
aabb2ecda7 Update node to 10.15.1 (#472)
* Update Node to 10.15.1

* Remove string replace that was used for oclif

* Update nbin

* Package node-pty and spdlog with nbin

* Label stderr/stdout from shared process

* Remove fork override

* Prevent "already disposed" errors when trying to kill disposed proxies

* Include spdlog dependencies

* Shim /node_modules

* Add node_modules to Docker ignore

It keeps using my already-built .node files which results in a
mismatching GLIBC version error.

* Update nbin
2019-04-15 19:48:12 -05:00
Kibo Hikari
dfabc070b9 fix(dockerfile): explicitly create a volume and set permission for project dir (#471)
Signed-off-by: Kibo Hikari <enra@sayonika.moe>
2019-04-13 23:34:25 -05:00
Kyle Carberry
da420cdda9 Merge branch 'master' of github.com:codercom/code-server 2019-04-14 00:32:06 -04:00
Kyle Carberry
c6a46e4753 Fix reading text from clipboard via electron fill 2019-04-14 00:32:03 -04:00
Asher
742dd6f597 Upgrade VS Code to 1.33.1 2019-04-12 16:10:45 -05:00
Yen-Chi Chen
6c3ff1d6f0 Fix typo: doc/self-hosted/index.md (#477) 2019-04-12 10:35:54 -05:00
John McCambridge
db57aa229f Allow use of the enter key for password input for code-server (#479)
* Allow use of the enter key for password input for code-server

* Remove function, make html form

* Remove function and create html form

* Handle form submit action

* Remove button listener

* Check if form exists
2019-04-12 10:35:30 -05:00
David Pinezich
f7342ede69 Update digitalocean.md (#486)
Seems that   sudo ./code-server-linux -p 80 is outdated. The "linux" is not anymore given.
2019-04-11 16:18:13 -05:00
Anmol Sethi
b781ccde9c Add common utilities to Dockerfile (#488) 2019-04-11 15:30:21 -05:00
Asher
8f62b2bff2 Decrease max retry time to three seconds 2019-04-11 14:58:29 -05:00
Asher
7047be859c Fix some open file/folder issues
- "Open folder" now says "open folder" instead of "open file"
- "Open folder" won't allow you to open files
- "Open file" won't allow you to open directories

Fixes #249.
2019-04-11 14:55:06 -05:00
Kyle Carberry
2785e2219a Remove hosted from the readme 2019-04-11 02:11:51 +00:00
majik
4b217fba00 Feature/relative url (#307)
* resrouce relative url

* add url pathname for require.toUrl (fix webview url)

* rest resrouce relative url

* fix resource url

* ignore .vscode
2019-04-10 20:07:53 -05:00
Kyle Carberry
3fae68bbab Add storage save to ide-api 2019-04-09 12:24:53 -04:00
Asher
a2f20aa25c Update window service fill 2019-04-08 18:04:41 -05:00
Asher
94b8b9a5cf Fix window.open infinite loop 2019-04-08 17:44:10 -05:00
Asher
bbd8b27fc7 Explicitly mention if netstat isn't installed; downgrade to warning 2019-04-08 11:15:25 -05:00
Asher
6361635b55 Move backup service init to the shared process
Since this is where it attempts to read it, this should solve the JSON
errors for good.
2019-04-08 11:03:33 -05:00
Kyle Carberry
d2da4cfc43 Fix errors appearing 2019-04-07 17:04:49 -04:00
Asher
a1136b3a02 Update VS Code to 1.33.0 (#445)
* Update VS Code to 1.33.0

* Fix slow file tree

* Fix WindowsService fill

* Provide `off` on event listeners

* Fix webview

* Fix double title bar and missing preferences on Mac

* Bump VS Code version in Travis config

* Fix black dialog text (again)

* Fix shared process not starting
2019-04-05 18:49:29 -05:00
Anmol Sethi
4dd74b31b9 Merge pull request #435 from codercom/docker-fixes
Reduce layers in Dockerfile
2019-04-05 10:18:50 -05:00
Anmol Sethi
bc0f6eb65d Reduce layers in Dockerfile 2019-04-04 20:00:42 -05:00
Anmol Sethi
6737d3da18 Merge pull request #433 from codercom/docker-fixes
Significantly improve the Dockerfile
2019-04-04 18:42:14 -05:00
Anmol Sethi
eb0f773146 Update README.md 2019-04-04 18:41:45 -05:00
Anmol Sethi
ebac84899e Significantly improve the Dockerfile
- Adds dumb-init so closes #403, closes #361, closes #383
- User mode docker so closes #192, closes #65
- Uses latest docker ubuntu instead of 18.10 which is the rolling tag so closes #404

Thanks to @RichardMcSorley and @sr229
2019-04-04 18:41:45 -05:00
Richard McSorley
0b7a090a73 Use an init system 2019-04-04 18:41:45 -05:00
Hikari Kibo
a95019f38d fix: slap adduser into another RUN
im abusing the word slap today please help me
2019-04-04 18:41:45 -05:00
Hikari
15948c1af6 feat: user-mode docker
Signed-off-by: Hikari <enra@sayonika.moe>
2019-04-04 18:41:45 -05:00
Asher
e73eb74208 Fix sending dates through the protocol
Fixes #253.
2019-04-04 18:24:53 -05:00
Kyle Carberry
278c59b920 Remove non-working menu items 2019-04-04 18:04:34 -04:00
Kyle Carberry
5a1eb858a9 Merge branch 'master' of github.com:codercom/code-server 2019-04-04 17:13:58 -04:00
Kyle Carberry
3c1dfb1170 Update @coder/nbin. Fixes UI state saves 2019-04-04 17:13:54 -04:00
Asher
09a02eb9e9 Build for production in Docker 2019-04-04 13:33:49 -05:00
Kyle Carberry
2bd7281fa0 Update @coder/nbin 2019-04-04 09:59:50 -04:00
Asher
e12fcd3a0d Fix error when shared process exits with null 2019-04-03 17:32:20 -05:00
Kyle Carberry
4af84fcaf6 Add flags for customizing user data dir and extensions dir (#420)
* Add flags for customizing extensions directory

* Update @coder/nbin
2019-04-03 17:07:47 -05:00
Asher
c607015a26 Initialize backup service (#419)
- Fixes #399
- Fixes #332
2019-04-03 16:08:15 -05:00
John McCambridge
217515344e Add port in use message (#418)
* Add clear error message if port is in use

* Add bold function for text/numbers

* remove unused dependency:

* remove unused line break

* Change logger message

* Use NodeJS.ErrnoException type

* Add back check for error code
2019-04-03 15:50:52 -05:00
Kyle Carberry
dcf409aecb Improve CI caching (#416)
* Adjust linux distro to ubuntu 14.04

* Cache lib directory for speedy builds

* Fix path linking for default extensions

* Update reset

* Reset to head

* Improve caching

* Still run yarn in CI

* Update yarn before install

* Increase cache timeout

* Install vscode from vstar

* Undo data-dir changes to CLI, add back clean, remove unused CI func

* Remove additional flags added

* Remove unused dependency

* Reset vscode install dir so patching always works
2019-04-03 14:24:00 -05:00
Kyle Carberry
2683b7c734 Update notes title 2019-04-03 11:23:32 -04:00
Asher
3a672d725a Convert fully to protobuf (was partially JSON) (#402)
* Convert fully to protobuf (was partially JSON)

* Handle all floating promises

* Remove stringified proto from trace logging

It wasn't proving to be very useful.
2019-04-02 17:44:28 -05:00
Kyle Carberry
f484781693 Minor update in notes 2019-04-02 11:41:44 -04:00
Anmol Sethi
97f5b07003 Fix icons on safari when using cookie authentication (#398)
Cookie's are not sent with url's in -webkit-mask so we
embed the svg's directly in the css.
2019-04-01 15:20:39 -05:00
MOZGIII
7481395353 Changed "lib" to "/lib" at .gitignore (#395) 2019-04-01 14:15:43 -05:00
Asher
033ef151ca Improve retry
Registering returns an instance that lets you retry and recover without
needing to keep passing the name everywhere.

Also refactored the shared process a little to make better use of the
retry and downgraded stderr messages to warnings because they aren't
critical.
2019-04-01 13:31:34 -05:00
Jeff Delaney
3fec7f432c doc: fixed name of binary to match latest release (#386) 2019-03-31 13:15:33 -05:00
Asher
4887078423 Fix typescript tslint plugin
tslint-language-service is the deprecated version which we don't
actually even have listed in the package.json. typescript-tslint-plugin
is the new version.
2019-03-29 18:44:04 -05:00
Asher
91deaece47 Reduce frequency of port scanning 2019-03-29 16:14:28 -05:00
Asher
03ad2a17b2 Handle disconnects (#363)
* Make proxies decide how to handle disconnects

* Connect to a new terminal instance on disconnect

* Use our retry for the watcher

* Specify method when proxy doesn't exist

* Don't error when closing/killing disconnected proxy

* Specify proxy ID when a method doesn't exist

* Use our retry for the searcher

Also dispose some things for the watcher because it doesn't seem that
was done properly.

The searcher also now starts immediately so there won't be lag when you
perform your first search.

* Use our retry for the extension host

* Emit error in parent proxy class

Reduces duplicate code. Not all items are "supposed" to have an error
event according to the original implementation we are filling, but there
is no reason why we can't emit our own events (and are already doing so
for the "disconnected" event anyway).

* Reconnect spdlog

* Add error message when shared process disconnects

* Pass method resolve to parse

* Don't pass method to getProxy

It doesn't tell you anything that trace logging wouldn't and has
no relation to what the function actually does.

* Fix infinite recursion when disposing protocol client in tests
2019-03-28 17:59:49 -05:00
John McCambridge
a4cca6b759 Add information about release notifications/gif (#355)
* Add information about release notifications/gif

* Remove unecessary space

* Add smaller gif

* Add even smaller gif

* Trim time in new gif

* Cropped a tad more

* Fix weird aligning
2019-03-27 17:05:44 -05:00
NGTmeaty
6105bba0a4 Add higher quality Discord badge and add a link to the license badge. (#364)
* Add higher quality Discord badge and add link 

to license.

* Use @grant's much better version :)
2019-03-27 17:05:23 -05:00
Asher
259095eae2 Watcher and initial load performance improvements (#357)
* Set low CPU priority on watcher

Fixes #247.

* Batch stat and readdir calls

* Fix fs.exists

callbackify seems to always adds an error as the first argument. Opted
to just use the promise for this one.

* Batch lstat

* Add maximum time for flushing batches
2019-03-27 17:04:19 -05:00
Carlos Azaustre
38a0706b18 Add example with letsencrypt certificates
* updated the download link

* added example with letsencrypt certificates
2019-03-27 10:36:03 -05:00
Ryo Ochiai
c7ae12c2ed Add .node-version file (#272) 2019-03-27 10:35:00 -05:00
James Peters
3331f9b28d Update Dockerfile (#327) 2019-03-27 10:34:34 -05:00
Reda Aissaoui
def4104c53 Changed executable name (#353)
code-server-luni should be only code-server
2019-03-27 10:23:23 -05:00
Kyle Carberry
4eb5331ddc Fixes #121 2019-03-27 10:36:32 -04:00
Kyle Carberry
3bb5c0bbe5 Fixes #351 2019-03-27 09:56:05 -04:00
104 changed files with 10139 additions and 4726 deletions

View File

@@ -7,3 +7,4 @@ doc/
.travis.yml .travis.yml
LICENSE LICENSE
README.md README.md
node_modules

4
.gitignore vendored
View File

@@ -1,6 +1,8 @@
lib /lib
node_modules node_modules
dist dist
out out
.DS_Store .DS_Store
release release
.vscode
.cache

1
.node-version Normal file
View File

@@ -0,0 +1 @@
10.15.1

View File

@@ -1,16 +1,17 @@
language: node_js language: node_js
node_js: node_js:
- 8.15.0 - 10.15.1
env: 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: matrix:
include: include:
- os: linux - os: linux
dist: ubuntu dist: trusty
- os: osx - os: osx
before_install: before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libxkbfile-dev - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libxkbfile-dev
libsecret-1-dev; fi libsecret-1-dev; fi
- npm install -g yarn@1.12.3
script: script:
- scripts/build.sh - scripts/build.sh
before_deploy: before_deploy:
@@ -35,4 +36,8 @@ deploy:
on: on:
repo: codercom/code-server repo: codercom/code-server
branch: master branch: master
cache: yarn cache:
yarn: true
timeout: 1000
directories:
- .cache

View File

@@ -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. # Install VS Code's deps. These are the only two it seems we need.
RUN apt-get update && apt-get install -y \ 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 # 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. # 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. # We deploy with ubuntu so that devs have a familiar environment.
FROM ubuntu:18.10 FROM ubuntu:18.04
WORKDIR /root/project
COPY --from=0 /src/packages/server/cli-linux-x64 /usr/local/bin/code-server
EXPOSE 8443
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
openssl \ openssl \
net-tools \ net-tools \
git \ git \
locales locales \
sudo \
dumb-init \
vim \
curl \
wget
RUN locale-gen en_US.UTF-8 RUN locale-gen en_US.UTF-8
# We unfortunately cannot use update-locale because docker will not use the env variables # 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. # configured in /etc/default/locale so we need to set it manually.
ENV LANG=en_US.UTF-8 ENV LC_ALL=en_US.UTF-8
ENTRYPOINT ["code-server"]
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"]

View File

@@ -2,14 +2,14 @@
[!["Open Issues"](https://img.shields.io/github/issues-raw/codercom/code-server.svg)](https://github.com/codercom/code-server/issues) [!["Open Issues"](https://img.shields.io/github/issues-raw/codercom/code-server.svg)](https://github.com/codercom/code-server/issues)
[!["Latest Release"](https://img.shields.io/github/release/codercom/code-server.svg)](https://github.com/codercom/code-server/releases/latest) [!["Latest Release"](https://img.shields.io/github/release/codercom/code-server.svg)](https://github.com/codercom/code-server/releases/latest)
[![MIT license](https://img.shields.io/badge/license-MIT-green.svg)](#) [![MIT license](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/codercom/code-server/blob/master/LICENSE)
[![Discord](https://discordapp.com/api/guilds/463752820026376202/widget.png)](https://discord.gg/zxSwN8Z) [![Discord](https://img.shields.io/discord/463752820026376202.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/zxSwN8Z)
`code-server` is [VS Code](https://github.com/Microsoft/vscode) running on a remote server, accessible through the browser. `code-server` is [VS Code](https://github.com/Microsoft/vscode) running on a remote server, accessible through the browser.
Try it out: Try it out:
```bash ```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. - 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 ## 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 ### 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. - Creating custom VS Code extensions and debugging them doesn't work.
### Future ### Future
- **Stay up to date!** Get notified about new releases of code-server.
![Screenshot](/doc/assets/release.gif)
- Windows support. - Windows support.
- Electron and Chrome OS applications to bridge the gap between local<->remote. - 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. - 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 ## Contributing

View File

@@ -4,21 +4,22 @@ import * as fse from "fs-extra";
import * as os from "os"; import * as os from "os";
import * as path from "path"; import * as path from "path";
import * as zlib from "zlib"; import * as zlib from "zlib";
import * as https from "https";
import * as tar from "tar";
const isWin = os.platform() === "win32"; const isWin = os.platform() === "win32";
const libPath = path.join(__dirname, "../lib"); const libPath = path.join(__dirname, "../lib");
const vscodePath = path.join(libPath, "vscode"); const vscodePath = path.join(libPath, "vscode");
const defaultExtensionsPath = path.join(libPath, "extensions");
const pkgsPath = path.join(__dirname, "../packages"); const pkgsPath = path.join(__dirname, "../packages");
const defaultExtensionsPath = path.join(libPath, "VSCode-linux-x64/resources/app/extensions"); const vscodeVersion = process.env.VSCODE_VERSION || "1.33.1";
const vscodeVersion = process.env.VSCODE_VERSION || "1.32.0"; const vsSourceUrl = `https://codesrv-ci.cdr.sh/vstar-${vscodeVersion}.tar.gz`;
const buildServerBinary = register("build:server:binary", async (runner) => { const buildServerBinary = register("build:server:binary", async (runner) => {
await ensureInstalled(); await ensureInstalled();
await copyForDefaultExtensions();
await Promise.all([ await Promise.all([
buildBootstrapFork(), buildBootstrapFork(),
buildWeb(), buildWeb(),
buildDefaultExtensions(),
buildServerBundle(), buildServerBundle(),
buildAppBrowser(), 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 bootstrapForkPath = path.join(pkgsPath, "vscode", "out", "bootstrap-fork.js");
const webOutputPath = path.join(pkgsPath, "web", "out"); const webOutputPath = path.join(pkgsPath, "web", "out");
const browserAppOutputPath = path.join(pkgsPath, "app", "browser", "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"); let ripgrepPath = path.join(pkgsPath, "..", "lib", "vscode", "node_modules", "vscode-ripgrep", "bin", "rg");
if (isWin) { if (isWin) {
ripgrepPath += ".exe"; 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)) { if (!fs.existsSync(webOutputPath)) {
throw new Error("Web bundle must be built"); 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")); fse.copySync(defaultExtensionsPath, path.join(cliBuildPath, "extensions"));
fs.writeFileSync(path.join(cliBuildPath, "bootstrap-fork.js.gz"), zlib.gzipSync(fs.readFileSync(bootstrapForkPath))); 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); const stat = fs.statSync(dir);
if (stat.isDirectory()) { if (stat.isDirectory()) {
const paths = fs.readdirSync(dir); 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()) { } 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)); fse.mkdirpSync(path.dirname(newPath));
fs.writeFileSync(newPath + ".gz", zlib.gzipSync(fs.readFileSync(dir))); fs.writeFileSync(newPath + ".gz", zlib.gzipSync(fs.readFileSync(dir)));
} else { } else {
// Nothing // Nothing
} }
}; };
cpDir(webOutputPath, "auth", webOutputPath); cpDir(webOutputPath, webOutputPath);
cpDir(browserAppOutputPath, "unauth", browserAppOutputPath); cpDir(browserAppOutputPath, browserAppOutputPath, "login");
fse.mkdirpSync(path.join(cliBuildPath, "dependencies")); 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")); 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"]); 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) => { const ensureInstalled = register("vscode:install", async (runner) => {
await ensureCloned(); runner.cwd = libPath;
runner.cwd = vscodePath; if (fs.existsSync(vscodePath) && fs.existsSync(defaultExtensionsPath)) {
const install = await runner.execute(isWin ? "yarn.cmd" : "yarn", []); const pkgVersion = JSON.parse(fs.readFileSync(path.join(vscodePath, "package.json")).toString("utf8")).version;
if (install.exitCode !== 0) { if (pkgVersion === vscodeVersion) {
throw new Error(`Failed to install vscode dependencies: ${install.stderr}`); runner.cwd = vscodePath;
}
});
const ensureCloned = register("vscode:clone", async (runner) => { const reset = await runner.execute("git", ["reset", "--hard"]);
if (fs.existsSync(vscodePath)) { if (reset.exitCode !== 0) {
await ensureClean(); throw new Error(`Failed to clean git repository: ${reset.stderr}`);
} else { }
fse.mkdirpSync(libPath);
runner.cwd = libPath; return;
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}`);
} }
} }
runner.cwd = vscodePath; fse.removeSync(libPath);
const checkout = await runner.execute("git", ["checkout", vscodeVersion]); fse.mkdirpSync(libPath);
if (checkout.exitCode !== 0) {
throw new Error(`Failed to checkout: ${checkout.stderr}`);
}
});
const ensureClean = register("vscode:clean", async (runner) => { await new Promise<void>((resolve, reject): void => {
runner.cwd = vscodePath; https.get(vsSourceUrl, (res) => {
if (res.statusCode !== 200) {
return reject(res.statusMessage);
}
const status = await runner.execute("git", ["status", "--porcelain"]); res.pipe(tar.x({
if (status.stdout.trim() !== "") { C: libPath,
const clean = await runner.execute("git", ["clean", "-f", "-d", "-X"]); }).on("finish", () => {
if (clean.exitCode !== 0) { resolve();
throw new Error(`Failed to clean git repository: ${clean.stderr}`); }).on("error", (err: Error) => {
} reject(err);
const removeUnstaged = await runner.execute("git", ["checkout", "--", "."]); }));
if (removeUnstaged.exitCode !== 0) { }).on("error", (err) => {
throw new Error(`Failed to remove unstaged files: ${removeUnstaged.stderr}`); reject(err);
} });
} });
const fetch = await runner.execute("git", ["fetch", "--prune"]);
if (fetch.exitCode !== 0) {
throw new Error(`Failed to fetch latest changes: ${fetch.stderr}`);
}
}); });
const ensurePatched = register("vscode:patch", async (runner) => { const ensurePatched = register("vscode:patch", async (runner) => {
if (!fs.existsSync(vscodePath)) { if (!fs.existsSync(vscodePath)) {
throw new Error("vscode must be cloned to patch"); throw new Error("vscode must be cloned to patch");
} }
await ensureClean(); await ensureInstalled();
runner.cwd = vscodePath; runner.cwd = vscodePath;
const patchPath = path.join(__dirname, "../scripts/vscode.patch"); const patchPath = path.join(__dirname, "../scripts/vscode.patch");
@@ -250,9 +194,9 @@ register("package", async (runner, releaseTag) => {
}); });
runner.cwd = releasePath; runner.cwd = releasePath;
await os.platform() === "linux" await (os.platform() === "linux"
? runner.execute("tar", ["-cvzf", `${archiveName}.tar.gz`, `${archiveName}`]) ? runner.execute("tar", ["-cvzf", `${archiveName}.tar.gz`, `${archiveName}`])
: runner.execute("zip", ["-r", `${archiveName}.zip`, `${archiveName}`]); : runner.execute("zip", ["-r", `${archiveName}.zip`, `${archiveName}`]));
}); });
run(); run();

View File

@@ -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) > To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../../security/ssl.md)
- Finally, run - 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"> - 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"> - Then click **"proceed anyway"**<img src="../../assets/chrome_confirm.png">

View File

@@ -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) > 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 - 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 > 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"> - 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">

View File

@@ -54,7 +54,7 @@ chmod +x code-server
- Start the 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 > 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -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). > 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. 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. code-server can be ran with a number of arguments to customize your working directory, host, port, and SSL certificate.
``` ```
USAGE Usage: code-server [options]
$ code-server [WORKDIR]
ARGUMENTS Run VS Code on a remote server.
WORKDIR [default: (directory to binary)] Specify working dir
OPTIONS Options:
-d, --data-dir=data-dir -V, --version output the version number
-h, --host=host [default: 0.0.0.0] --cert <value>
-o, --open Open in browser on startup --cert-key <value>
-p, --port=port [default: 8443] Port to bind on -e, --extensions-dir <dir> Set the root path for extensions.
-v, --version show CLI version -d --user-data-dir <dir> Specifies the directory that user data is kept in, useful when running as root.
--allow-http --data-dir <value> DEPRECATED: Use '--user-data-dir' instead. Customize where user-data is stored.
--cert=cert -h, --host <value> Customize the hostname. (default: "0.0.0.0")
--cert-key=cert-key -o, --open Open in the browser on startup.
--help show CLI help -p, --port <number> Port to bind on. (default: 8443)
--no-auth -N, --no-auth Start without requiring authentication.
--password=password -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 ### 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 ### 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` > Example: `code-server -h 127.0.0.1`
### Open ### 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 ### 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. 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` > Example: `code-server -p 9000`
### Telemetry
Disable all telemetry with `code-server --disable-telemetry`.
### Cert and Cert Key ### 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. 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 (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) > 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 *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 ### 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.

View File

@@ -15,7 +15,9 @@
"devDependencies": { "devDependencies": {
"@types/fs-extra": "^5.0.4", "@types/fs-extra": "^5.0.4",
"@types/node": "^10.12.18", "@types/node": "^10.12.18",
"@types/tar": "^4.0.0",
"@types/trash": "^4.3.1", "@types/trash": "^4.3.1",
"cache-loader": "^2.0.1",
"cross-env": "^5.2.0", "cross-env": "^5.2.0",
"crypto-browserify": "^3.12.0", "crypto-browserify": "^3.12.0",
"css-loader": "^2.1.0", "css-loader": "^2.1.0",
@@ -34,6 +36,8 @@
"sass-loader": "^7.1.0", "sass-loader": "^7.1.0",
"string-replace-loader": "^2.1.1", "string-replace-loader": "^2.1.1",
"style-loader": "^0.23.1", "style-loader": "^0.23.1",
"tar": "^4.4.8",
"terser-webpack-plugin": "^1.2.3",
"ts-loader": "^5.3.3", "ts-loader": "^5.3.3",
"ts-node": "^7.0.1", "ts-node": "^7.0.1",
"tsconfig-paths": "^3.8.0", "tsconfig-paths": "^3.8.0",
@@ -42,6 +46,7 @@
"typescript": "^3.2.2", "typescript": "^3.2.2",
"typescript-tslint-plugin": "^0.2.1", "typescript-tslint-plugin": "^0.2.1",
"uglifyjs-webpack-plugin": "^2.1.1", "uglifyjs-webpack-plugin": "^2.1.1",
"url-loader": "^1.1.2",
"util": "^0.11.1", "util": "^0.11.1",
"webpack": "^4.28.4", "webpack": "^4.28.4",
"webpack-bundle-analyzer": "^3.0.3", "webpack-bundle-analyzer": "^3.0.3",
@@ -49,10 +54,17 @@
"webpack-dev-middleware": "^3.5.0", "webpack-dev-middleware": "^3.5.0",
"webpack-dev-server": "^3.1.14", "webpack-dev-server": "^3.1.14",
"webpack-hot-middleware": "^2.24.3", "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" "write-file-webpack-plugin": "^4.5.0"
}, },
"resolutions": {
"bindings": "1.3.0"
},
"dependencies": { "dependencies": {
"node-loader": "^0.6.0", "node-loader": "^0.6.0",
"node-pty": "0.8.1",
"spdlog": "0.8.1",
"webpack-merge": "^4.2.1" "webpack-merge": "^4.2.1"
} }
} }

View File

@@ -7,22 +7,24 @@
</head> </head>
<body> <body>
<div class="login"> <form id="login-form">
<div class="back"> <- Back </div> <div class="login">
<h4 class="title">code-server</h4> <div class="back">
<h2 class="subtitle"> <- Back </div> <h4 class="title">code-server</h4>
Enter server password <h2 class="subtitle">
</h2> Enter server password
<div class="mdc-text-field"> </h2>
<input type="password" id="password" class="mdc-text-field__input" required> <div class="mdc-text-field">
<label class="mdc-floating-label" for="password">Password</label> <input type="password" id="password" class="mdc-text-field__input" required>
<div class="mdc-line-ripple"></div> <label class="mdc-floating-label" for="password">Password</label>
</div> <div class="mdc-line-ripple"></div>
<button id="submit" class="mdc-button mdc-button--unelevated"> </div>
<span class="mdc-button__label">Enter IDE</span> <button id="submit" class="mdc-button mdc-button--unelevated">
</button> <span class="mdc-button__label">Enter IDE</span>
<div id="error-display"></div> </button>
</div> <div id="error-display"></div>
</div>
</form>
</body> </body>
</html> </html>

View File

@@ -20,12 +20,17 @@ window.addEventListener("message", (event) => {
}); });
const password = document.getElementById("password") as HTMLInputElement; const password = document.getElementById("password") as HTMLInputElement;
const submit = document.getElementById("submit") as HTMLButtonElement; const form = document.getElementById("login-form") as HTMLFormElement;
if (!submit) {
throw new Error("No submit button found"); 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(); location.reload();
}); });
@@ -38,4 +43,4 @@ const errorDisplay = document.getElementById("error-display") as HTMLDivElement;
if (document.referrer === document.location.href && matches) { if (document.referrer === document.location.href && matches) {
errorDisplay.innerText = "Password is incorrect!"; errorDisplay.innerText = "Password is incorrect!";
} }

View File

@@ -7,11 +7,10 @@ const root = path.resolve(__dirname, "../../..");
module.exports = merge( module.exports = merge(
require(path.join(root, "scripts/webpack.client.config.js"))({ require(path.join(root, "scripts/webpack.client.config.js"))({
entry: path.join(root, "packages/app/browser/src/app.ts"), dirname: __dirname,
template: path.join(root, "packages/app/browser/src/app.html"), entry: path.join(__dirname, "src/app.ts"),
name: "login",
template: path.join(__dirname, "src/app.html"),
}), { }), {
output: {
path: path.join(__dirname, "out"),
},
}, },
); );

View File

@@ -5,15 +5,12 @@ const root = path.resolve(__dirname, "../..");
module.exports = merge( module.exports = merge(
require(path.join(root, "scripts/webpack.node.config.js"))({ require(path.join(root, "scripts/webpack.node.config.js"))({
// Options. dirname: __dirname,
name: "dns",
}), { }), {
externals: { externals: {
"node-named": "commonjs node-named", "node-named": "commonjs node-named",
}, },
output: {
path: path.join(__dirname, "out"),
filename: "main.js",
},
entry: [ entry: [
"./packages/dns/src/dns.ts" "./packages/dns/src/dns.ts"
], ],

View File

@@ -136,12 +136,17 @@ interface ICommandRegistry {
registerCommand(command: ICommand): IDisposable; registerCommand(command: ICommand): IDisposable;
} }
interface IStorageService {
save(): Promise<void>;
}
declare namespace ide { declare namespace ide {
export const client: {}; export const client: {};
export const workbench: { export const workbench: {
readonly statusbarService: IStatusbarService; readonly statusbarService: IStatusbarService;
readonly notificationService: INotificationService; readonly notificationService: INotificationService;
readonly storageService: IStorageService;
readonly menuRegistry: IMenuRegistry; readonly menuRegistry: IMenuRegistry;
readonly commandRegistry: ICommandRegistry; readonly commandRegistry: ICommandRegistry;

View File

@@ -1,6 +1,6 @@
{ {
"name": "@coder/ide-api", "name": "@coder/ide-api",
"version": "1.0.3", "version": "1.0.4",
"typings": "api.d.ts", "typings": "api.d.ts",
"author": "Coder", "author": "Coder",
"license": "MIT", "license": "MIT",

View File

@@ -34,6 +34,12 @@ export abstract class IdeClient {
this.loadTime = time(2500); this.loadTime = time(2500);
let appWindow: Window | undefined; let appWindow: Window | undefined;
window.addEventListener("beforeunload", (e) => {
e.preventDefault(); // FireFox
e.returnValue = ""; // Chrome
});
window.addEventListener("message", (event) => { window.addEventListener("message", (event) => {
if (event.data === "app") { if (event.data === "app") {
appWindow = event.source as Window; appWindow = event.source as Window;
@@ -41,7 +47,16 @@ export abstract class IdeClient {
}); });
this.sharedProcessData = new Promise((resolve): void => { 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) => { 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>(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, V>(description: string, duration: number, task: (v: V) => Promise<T>, t: Promise<V>): Promise<T>;
public async task<T, V1, V2>(description: string, duration: number, task: (v1: V1, v2: V2) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>): Promise<T>; public async task<T, V1, V2>(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>(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>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4, v5: V5) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>, t5: Promise<V5>): Promise<T>;
public async task<T, V1, V2, V3, V4, V5, V6>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4, v5: V5, v6: V6) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>, t5: Promise<V5>, t6: Promise<V6>): Promise<T>; public async task<T, 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>( public async task<T>(
description: string, duration: number = 100, task: (...args: any[]) => Promise<T>, ...after: Array<Promise<any>> // tslint:disable-line no-any description: string, duration: number = 100, task: (...args: any[]) => Promise<T>, ...after: Array<Promise<any>> // tslint:disable-line no-any
): Promise<T> { ): Promise<T> {

View File

@@ -11,7 +11,7 @@ class WebsocketConnection implements ReadWriteConnection {
private activeSocket: WebSocket | undefined; private activeSocket: WebSocket | undefined;
private readonly messageBuffer = <Uint8Array[]>[]; private readonly messageBuffer = <Uint8Array[]>[];
private readonly socketTimeoutDelay = 60 * 1000; private readonly socketTimeoutDelay = 60 * 1000;
private readonly retryName = "Socket"; private readonly retry = retry.register("Socket", () => this.connect());
private isUp: boolean = false; private isUp: boolean = false;
private closed: boolean = false; private closed: boolean = false;
@@ -26,11 +26,14 @@ class WebsocketConnection implements ReadWriteConnection {
public readonly onMessage = this.messageEmitter.event; public readonly onMessage = this.messageEmitter.event;
public constructor() { public constructor() {
retry.register(this.retryName, () => this.connect()); this.retry.block();
retry.block(this.retryName); this.retry.run();
retry.run(this.retryName);
} }
/**
* Send data across the socket. If closed, will error. If connecting, will
* queue.
*/
public send(data: Buffer | Uint8Array): void { public send(data: Buffer | Uint8Array): void {
if (this.closed) { if (this.closed) {
throw new Error("web socket is closed"); throw new Error("web socket is closed");
@@ -42,6 +45,9 @@ class WebsocketConnection implements ReadWriteConnection {
} }
} }
/**
* Close socket connection.
*/
public close(): void { public close(): void {
this.closed = true; this.closed = true;
this.dispose(); this.dispose();
@@ -75,8 +81,8 @@ class WebsocketConnection implements ReadWriteConnection {
field("wasClean", event.wasClean), field("wasClean", event.wasClean),
); );
if (!this.closed) { if (!this.closed) {
retry.block(this.retryName); this.retry.block();
retry.run(this.retryName); this.retry.run();
} }
}); });
@@ -108,15 +114,19 @@ class WebsocketConnection implements ReadWriteConnection {
}, this.socketTimeoutDelay); }, this.socketTimeoutDelay);
await new Promise((resolve, reject): void => { await new Promise((resolve, reject): void => {
const onClose = (): void => { const doReject = (): void => {
clearTimeout(socketWaitTimeout); clearTimeout(socketWaitTimeout);
socket.removeEventListener("close", onClose); socket.removeEventListener("error", doReject);
socket.removeEventListener("close", doReject);
reject(); reject();
}; };
socket.addEventListener("close", onClose); socket.addEventListener("error", doReject);
socket.addEventListener("close", doReject);
socket.addEventListener("open", async () => { socket.addEventListener("open", () => {
clearTimeout(socketWaitTimeout); clearTimeout(socketWaitTimeout);
socket.removeEventListener("error", doReject);
socket.removeEventListener("close", doReject);
resolve(); resolve();
}); });
}); });

View File

@@ -132,7 +132,7 @@ export class Dialog {
public show(): void { public show(): void {
if (!this.cachedActiveElement) { if (!this.cachedActiveElement) {
this.cachedActiveElement = document.activeElement as HTMLElement; 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); document.addEventListener("keydown", this.onKeydown);
if (this.input) { if (this.input) {
this.input.focus(); this.input.focus();

View File

@@ -45,7 +45,8 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
}, },
set: (value: string): void => { set: (value: string): void => {
if (value) { 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); oldSrc!.set!.call(img, value);
}, },
@@ -66,7 +67,8 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
}, },
set: (value: string): void => { set: (value: string): void => {
if (value) { 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); oldInnerHtml!.set!.call(style, value);
}, },
@@ -80,7 +82,8 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
if (sheet && !overridden) { if (sheet && !overridden) {
const oldInsertRule = sheet.insertRule; const oldInsertRule = sheet.insertRule;
sheet.insertRule = (rule: string, index?: number): void => { 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); oldInsertRule.call(sheet, rule, index);
}; };
overridden = true; 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).getWebContents = (): void => undefined; // tslint:disable-line no-any
(view as any).send = (channel: string, ...args: any[]): void => { // 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) { if (args[0] && typeof args[0] === "object" && args[0].contents) {
// TODO // TODO
args[0].contents = (args[0].contents as string).replace(/"(file:\/\/[^"]*)"/g, (m1) => `"/resource${m1}"`); const resourceBaseUrl = location.pathname.replace(/\/$/, "") + "/resource";
args[0].contents = (args[0].contents as string).replace(/"vscode-resource:([^"]*)"/g, (m, m1) => `"/resource${m1}"`); 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'"); args[0].contents = (args[0].contents as string).replace(/style-src vscode-core-resource:/g, "style-src 'self'");
} }
if (view.contentWindow) { if (view.contentWindow) {
@@ -178,6 +186,10 @@ class Clipboard {
public writeText(value: string): Promise<void> { public writeText(value: string): Promise<void> {
return clipboard.writeText(value); return clipboard.writeText(value);
} }
public readText(): Promise<string> {
return clipboard.readText();
}
} }
class Shell { class Shell {

View 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>

View File

@@ -1,14 +1,64 @@
import { logger, field } from "@coder/logger"; import { logger, field } from "@coder/logger";
import { NotificationService, INotificationHandle, INotificationService, Severity } from "./fill/notification"; import { NotificationService, INotificationHandle, INotificationService, Severity } from "./fill/notification";
// tslint:disable no-any can have different return values
interface IRetryItem { interface IRetryItem {
/**
* How many times this item has been retried.
*/
count?: number; 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; timeout?: number | NodeJS.Timer;
/**
* Whether the item is retrying or waiting to retry.
*/
running?: boolean; 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. * to the user explaining what is happening with an option to immediately retry.
*/ */
export class Retry { export class Retry {
private items = new Map<string, IRetryItem>(); private readonly items = new Map<string, IRetryItem>();
// Times are in seconds. // Times are in seconds.
private readonly retryMinDelay = 1; private readonly retryMinDelay = 1;
private readonly retryMaxDelay = 10; private readonly retryMaxDelay = 3;
private readonly maxImmediateRetries = 5; private readonly maxImmediateRetries = 5;
private readonly retryExponent = 1.5; private readonly retryExponent = 1.5;
private blocked: string | boolean | undefined; 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 * Register a function to retry that starts/connects to a service.
* back up). If a name is passed, that service will still be allowed to retry *
* 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). * (unless we have already blocked).
* *
* Blocking without a name will override a block with a name. * 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. * Unblock retries and run any that are pending.
*/ */
public unblock(): void { private unblock(): void {
this.blocked = false; this.blocked = false;
this.items.forEach((item, name) => { this.items.forEach((item, name) => {
if (item.running) { 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. * Retry a service.
*/ */
public run(name: string, error?: Error): void { private run(name: string, error?: Error): void {
if (!this.items.has(name)) { if (!this.items.has(name)) {
throw new Error(`"${name}" is not registered`); throw new Error(`"${name}" is not registered`);
} }
@@ -149,7 +215,7 @@ export class Retry {
/** /**
* Reset a service after a successfully recovering. * Reset a service after a successfully recovering.
*/ */
public recover(name: string): void { private recover(name: string): void {
if (!this.items.has(name)) { if (!this.items.has(name)) {
throw new Error(`"${name}" is not registered`); throw new Error(`"${name}" is not registered`);
} }
@@ -191,9 +257,9 @@ export class Retry {
if (this.blocked === name) { if (this.blocked === name) {
this.unblock(); this.unblock();
} }
}).catch(() => { }).catch((error) => {
endItem(); endItem();
this.run(name); this.run(name, error);
}); });
} else { } else {
endItem(); endItem();
@@ -214,8 +280,7 @@ export class Retry {
const now = Date.now(); const now = Date.now();
const items = Array.from(this.items.entries()).filter(([_, item]) => { const items = Array.from(this.items.entries()).filter(([_, item]) => {
return item.showInNotification return typeof item.end !== "undefined"
&& typeof item.end !== "undefined"
&& item.end > now && item.end > now
&& item.delay && item.delay >= this.notificationThreshold; && item.delay && item.delay >= this.notificationThreshold;
}).sort((a, b) => { }).sort((a, b) => {

View File

@@ -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", "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" "postinstall": "if [ ! -d out ];then npm run build; fi"
}, },
"version": "1.0.3", "version": "1.1.3",
"main": "out/main.js", "main": "out/main.js",
"types": "out/index.d.ts", "types": "out/index.d.ts",
"author": "Coder", "author": "Coder",
"license": "MIT" "license": "MIT",
"dependencies": {
"@google-cloud/logging": "^4.5.2"
}
} }

View 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" }));
});
});

View 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));
});
};
};

View File

@@ -59,6 +59,14 @@ export const field = <T>(name: string, value: T): Field<T> => {
return new Field(name, value); 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. * This formats & builds text for logging.
* It should only be used to build one log item at a time since it stores the * 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 _formatter: Formatter,
private readonly name?: string, private readonly name?: string,
private readonly defaultFields?: FieldArray, private readonly defaultFields?: FieldArray,
private readonly extenders: Extender[] = [],
) { ) {
if (name) { if (name) {
this.nameColor = this.hashStringToColor(name); this.nameColor = this.hashStringToColor(name);
@@ -248,6 +257,10 @@ export class Logger {
this.muted = true; this.muted = true;
} }
public extend(extender: Extender): void {
this.extenders.push(extender);
}
/** /**
* Outputs information. * Outputs information.
*/ */
@@ -328,7 +341,7 @@ export class Logger {
* Each name is deterministically generated a color. * Each name is deterministically generated a color.
*/ */
public named(name: string, ...fields: FieldArray): Logger { 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) { if (this.muted) {
l.mute(); l.mute();
} }
@@ -393,6 +406,16 @@ export class Logger {
console.log(...this._formatter.flush()); console.log(...this._formatter.flush());
} }
// tslint:enable no-console // 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,
});
});
} }
/** /**

View File

@@ -1,16 +1,34 @@
const path = require("path"); const path = require("path");
const merge = require("webpack-merge"); const merge = require("webpack-merge");
module.exports = merge(require(path.join(__dirname, "../../scripts", "webpack.general.config.js"))(), { module.exports = [
devtool: "none", merge(require(path.join(__dirname, "../../scripts", "webpack.general.config.js"))(), {
mode: "production", devtool: "none",
target: "node", mode: "production",
output: { target: "node",
path: path.join(__dirname, "out"), output: {
filename: "main.js", path: path.join(__dirname, "out"),
libraryTarget: "commonjs", filename: "main.js",
}, libraryTarget: "commonjs",
entry: [ },
"./packages/logger/src/index.ts" 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

View File

@@ -33,8 +33,7 @@
"@coder/(.*)/test": "<rootDir>/$1/test", "@coder/(.*)/test": "<rootDir>/$1/test",
"@coder/(.*)": "<rootDir>/$1/src", "@coder/(.*)": "<rootDir>/$1/src",
"vs/(.*)": "<rootDir>/../lib/vscode/src/vs/$1", "vs/(.*)": "<rootDir>/../lib/vscode/src/vs/$1",
"vszip": "<rootDir>/../lib/vscode/src/vs/base/node/zip.ts", "vszip": "<rootDir>/../lib/vscode/src/vs/base/node/zip.ts"
"^node-pty": "node-pty-prebuilt"
}, },
"transform": { "transform": {
"^.+\\.tsx?$": "ts-jest" "^.+\\.tsx?$": "ts-jest"

View File

@@ -4,8 +4,6 @@
"dependencies": { "dependencies": {
"express": "^4.16.4", "express": "^4.16.4",
"google-protobuf": "^3.6.1", "google-protobuf": "^3.6.1",
"node-pty-prebuilt": "^0.7.6",
"spdlog": "^0.7.2",
"trash": "^4.3.0", "trash": "^4.3.0",
"ws": "^6.1.2" "ws": "^6.1.2"
}, },

View File

@@ -5,8 +5,8 @@ import { Emitter } from "@coder/events";
import { logger, field } from "@coder/logger"; import { logger, field } from "@coder/logger";
import { ReadWriteConnection, InitData, SharedProcessData } from "../common/connection"; import { ReadWriteConnection, InitData, SharedProcessData } from "../common/connection";
import { Module, ServerProxy } from "../common/proxy"; import { Module, ServerProxy } from "../common/proxy";
import { stringify, parse, moduleToProto, protoToModule, protoToOperatingSystem } from "../common/util"; import { argumentToProto, protoToArgument, moduleToProto, protoToModule, protoToOperatingSystem } from "../common/util";
import { Ping, ServerMessage, ClientMessage, MethodMessage, NamedProxyMessage, NumberedProxyMessage, SuccessMessage, FailMessage, EventMessage, CallbackMessage } from "../proto"; import { Argument, Ping, ServerMessage, ClientMessage, Method, Event, Callback } from "../proto";
import { FsModule, ChildProcessModule, NetModule, NodePtyModule, SpdlogModule, TrashModule } from "./modules"; import { FsModule, ChildProcessModule, NetModule, NodePtyModule, SpdlogModule, TrashModule } from "./modules";
// tslint:disable no-any // tslint:disable no-any
@@ -24,8 +24,8 @@ export class Client {
private messageId = 0; private messageId = 0;
private callbackId = 0; private callbackId = 0;
private readonly proxies = new Map<number | Module, ProxyData>(); private readonly proxies = new Map<number | Module, ProxyData>();
private readonly successEmitter = new Emitter<SuccessMessage>(); private readonly successEmitter = new Emitter<Method.Success>();
private readonly failEmitter = new Emitter<FailMessage>(); private readonly failEmitter = new Emitter<Method.Fail>();
private readonly eventEmitter = new Emitter<{ event: string; args: any[]; }>(); private readonly eventEmitter = new Emitter<{ event: string; args: any[]; }>();
private _initData: InitData | undefined; private _initData: InitData | undefined;
@@ -129,19 +129,13 @@ export class Client {
field("event listeners", this.eventEmitter.counts), field("event listeners", this.eventEmitter.counts),
]); ]);
const message = new FailMessage(); const message = new Method.Fail();
const error = new Error("disconnected"); const error = new Error("disconnected");
message.setResponse(stringify(error)); message.setResponse(argumentToProto(error));
this.failEmitter.emit(message); this.failEmitter.emit(message);
this.eventEmitter.emit({ event: "exit", args: [1] }); this.eventEmitter.emit({ event: "disconnected", args: [error] });
this.eventEmitter.emit({ event: "close", args: [] }); this.eventEmitter.emit({ event: "done", 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] });
}; };
connection.onDown(() => handleDisconnect()); connection.onDown(() => handleDisconnect());
@@ -149,6 +143,12 @@ export class Client {
clearTimeout(this.pingTimeout as any); clearTimeout(this.pingTimeout as any);
this.pingTimeout = undefined; this.pingTimeout = undefined;
handleDisconnect(); handleDisconnect();
this.proxies.clear();
this.successEmitter.dispose();
this.failEmitter.dispose();
this.eventEmitter.dispose();
this.initDataEmitter.dispose();
this.sharedProcessActiveEmitter.dispose();
}); });
connection.onUp(() => this.disconnected = false); connection.onUp(() => this.disconnected = false);
@@ -174,19 +174,30 @@ export class Client {
* Make a remote call for a proxy's method using proto. * Make a remote call for a proxy's method using proto.
*/ */
private remoteCall(proxyId: number | Module, method: string, args: any[]): Promise<any> { private remoteCall(proxyId: number | Module, method: string, args: any[]): Promise<any> {
if (this.disconnected) { if (typeof proxyId === "number" && (this.disconnected || !this.proxies.has(proxyId))) {
return Promise.reject(new Error("disconnected")); // 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++; const id = this.messageId++;
let proxyMessage: NamedProxyMessage | NumberedProxyMessage; let proxyMessage: Method.Named | Method.Numbered;
if (typeof proxyId === "string") { if (typeof proxyId === "string") {
proxyMessage = new NamedProxyMessage(); proxyMessage = new Method.Named();
proxyMessage.setModule(moduleToProto(proxyId)); proxyMessage.setModule(moduleToProto(proxyId));
message.setNamedProxy(proxyMessage); message.setNamedProxy(proxyMessage);
} else { } else {
proxyMessage = new NumberedProxyMessage(); proxyMessage = new Method.Numbered();
proxyMessage.setProxyId(proxyId); proxyMessage.setProxyId(proxyId);
message.setNumberedProxy(proxyMessage); message.setNumberedProxy(proxyMessage);
} }
@@ -206,16 +217,14 @@ export class Client {
return callbackId; return callbackId;
}; };
const stringifiedArgs = args.map((a) => stringify(a, storeCallback));
logger.trace(() => [ logger.trace(() => [
"sending", "sending",
field("id", id), field("id", id),
field("proxyId", proxyId), field("proxyId", proxyId),
field("method", method), field("method", method),
field("args", stringifiedArgs),
]); ]);
proxyMessage.setArgsList(stringifiedArgs); proxyMessage.setArgsList(args.map((a) => argumentToProto(a, storeCallback)));
const clientMessage = new ClientMessage(); const clientMessage = new ClientMessage();
clientMessage.setMethod(message); clientMessage.setMethod(message);
@@ -223,7 +232,7 @@ export class Client {
// The server will send back a fail or success message when the method // 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. // 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 => { const dispose = (): void => {
d1.dispose(); d1.dispose();
d2.dispose(); d2.dispose();
@@ -237,12 +246,12 @@ export class Client {
const d1 = this.successEmitter.event(id, (message) => { const d1 = this.successEmitter.event(id, (message) => {
dispose(); dispose();
resolve(this.parse(message.getResponse())); resolve(this.protoToArgument(message.getResponse(), promise));
}); });
const d2 = this.failEmitter.event(id, (message) => { const d2 = this.failEmitter.event(id, (message) => {
dispose(); dispose();
reject(parse(message.getResponse())); reject(protoToArgument(message.getResponse()));
}); });
}); });
@@ -253,42 +262,54 @@ export class Client {
* Handle all messages from the server. * Handle all messages from the server.
*/ */
private async handleMessage(message: ServerMessage): Promise<void> { private async handleMessage(message: ServerMessage): Promise<void> {
if (message.hasInit()) { switch (message.getMsgCase()) {
const init = message.getInit()!; case ServerMessage.MsgCase.INIT:
this._initData = { const init = message.getInit()!;
dataDirectory: init.getDataDirectory(), this._initData = {
homeDirectory: init.getHomeDirectory(), dataDirectory: init.getDataDirectory(),
tmpDirectory: init.getTmpDirectory(), homeDirectory: init.getHomeDirectory(),
workingDirectory: init.getWorkingDirectory(), tmpDirectory: init.getTmpDirectory(),
os: protoToOperatingSystem(init.getOperatingSystem()), workingDirectory: init.getWorkingDirectory(),
shell: init.getShell(), os: protoToOperatingSystem(init.getOperatingSystem()),
builtInExtensionsDirectory: init.getBuiltinExtensionsDir(), shell: init.getShell(),
}; extensionsDirectory: init.getExtensionsDirectory(),
this.initDataEmitter.emit(this._initData); builtInExtensionsDirectory: init.getBuiltinExtensionsDir(),
} else if (message.hasSuccess()) { };
this.emitSuccess(message.getSuccess()!); this.initDataEmitter.emit(this._initData);
} else if (message.hasFail()) { break;
this.emitFail(message.getFail()!); case ServerMessage.MsgCase.SUCCESS:
} else if (message.hasEvent()) { this.emitSuccess(message.getSuccess()!);
await this.emitEvent(message.getEvent()!); break;
} else if (message.hasCallback()) { case ServerMessage.MsgCase.FAIL:
await this.runCallback(message.getCallback()!); this.emitFail(message.getFail()!);
} else if (message.hasSharedProcessActive()) { break;
const sharedProcessActiveMessage = message.getSharedProcessActive()!; case ServerMessage.MsgCase.EVENT:
this.sharedProcessActiveEmitter.emit({ await this.emitEvent(message.getEvent()!);
socketPath: sharedProcessActiveMessage.getSocketPath(), break;
logPath: sharedProcessActiveMessage.getLogPath(), case ServerMessage.MsgCase.CALLBACK:
}); await this.runCallback(message.getCallback()!);
} else if (message.hasPong()) { break;
// Nothing to do since pings are on a timer rather than waiting for the case ServerMessage.MsgCase.SHARED_PROCESS_ACTIVE:
// next pong in case a message from either the client or server is dropped const sharedProcessActiveMessage = message.getSharedProcessActive()!;
// which would break the ping cycle. this.sharedProcessActiveEmitter.emit({
} else { socketPath: sharedProcessActiveMessage.getSocketPath(),
throw new Error("unknown message type"); 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(() => [ logger.trace(() => [
"received resolve", "received resolve",
field("id", message.getId()), field("id", message.getId()),
@@ -297,7 +318,10 @@ export class Client {
this.successEmitter.emit(message.getId(), message); 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(() => [ logger.trace(() => [
"received reject", "received reject",
field("id", message.getId()), field("id", message.getId()),
@@ -313,7 +337,7 @@ export class Client {
* request before it emits. Instead, emit all events from the server so all * request before it emits. Instead, emit all events from the server so all
* events are always caught on the client. * 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 eventMessage = message.getNamedEvent()! || message.getNumberedEvent()!;
const proxyId = message.getNamedEvent() const proxyId = message.getNamedEvent()
? protoToModule(message.getNamedEvent()!.getModule()) ? protoToModule(message.getNamedEvent()!.getModule())
@@ -324,10 +348,9 @@ export class Client {
"received event", "received event",
field("proxyId", proxyId), field("proxyId", proxyId),
field("event", event), 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 }); 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 * also only be used when passed together with the method. If they are sent
* afterward, they may never be called due to timing issues. * 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 callbackMessage = message.getNamedCallback()! || message.getNumberedCallback()!;
const proxyId = message.getNamedCallback() const proxyId = message.getNamedCallback()
? protoToModule(message.getNamedCallback()!.getModule()) ? protoToModule(message.getNamedCallback()!.getModule())
@@ -350,16 +373,15 @@ export class Client {
"running callback", "running callback",
field("proxyId", proxyId), field("proxyId", proxyId),
field("callbackId", callbackId), 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); this.getProxy(proxyId).callbacks.get(callbackId)!(...args);
} }
/** /**
* Start the ping loop. Does nothing if already pinging. * Start the ping loop. Does nothing if already pinging.
*/ */
private startPinging = (): void => { private readonly startPinging = (): void => {
if (typeof this.pingTimeout !== "undefined") { if (typeof this.pingTimeout !== "undefined") {
return; return;
} }
@@ -450,12 +472,12 @@ export class Client {
callbacks: new Map(), callbacks: new Map(),
}); });
instance.onDone((disconnected: boolean) => { instance.onDone(() => {
const log = (): void => { const log = (): void => {
logger.trace(() => [ logger.trace(() => [
typeof proxyId === "number" ? "disposed proxy" : "disposed proxy callbacks", typeof proxyId === "number" ? "disposed proxy" : "disposed proxy callbacks",
field("proxyId", proxyId), 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("callbacks", Array.from(this.proxies.values()).reduce((count, proxy) => count + proxy.callbacks.size, 0)),
field("success listeners", this.successEmitter.counts), field("success listeners", this.successEmitter.counts),
field("fail listeners", this.failEmitter.counts), field("fail listeners", this.failEmitter.counts),
@@ -471,7 +493,7 @@ export class Client {
this.eventEmitter.dispose(proxyId); this.eventEmitter.dispose(proxyId);
log(); log();
}; };
if (!disconnected) { if (!this.disconnected) {
instance.dispose().then(dispose).catch(dispose); instance.dispose().then(dispose).catch(dispose);
} else { } else {
dispose(); dispose();
@@ -496,10 +518,16 @@ export class Client {
await this.getProxy(proxyId).promise; 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 { private getProxy(proxyId: number | Module): ProxyData {
if (!this.proxies.has(proxyId)) { if (!this.proxies.has(proxyId)) {
throw new Error(`proxy ${proxyId} disposed too early`); throw new Error(`proxy ${proxyId} disposed too early`);

View File

@@ -6,6 +6,8 @@ import { ClientProxy } from "../../common/proxy";
import { ChildProcessModuleProxy, ChildProcessProxy, ChildProcessProxies } from "../../node/modules/child_process"; import { ChildProcessModuleProxy, ChildProcessProxy, ChildProcessProxies } from "../../node/modules/child_process";
import { Readable, Writable } from "./stream"; import { Readable, Writable } from "./stream";
// tslint:disable completed-docs
export class ChildProcess extends ClientProxy<ChildProcessProxy> implements cp.ChildProcess { export class ChildProcess extends ClientProxy<ChildProcessProxy> implements cp.ChildProcess {
public readonly stdin: stream.Writable; public readonly stdin: stream.Writable;
public readonly stdout: stream.Readable; 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.stderr = new Readable(proxyPromises.then((p) => p.stderr!));
this.stdio = [this.stdin, this.stdout, this.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._pid = pid;
this._connected = true; this._connected = true;
}); }));
this.on("disconnect", () => this._connected = false); this.on("disconnect", () => this._connected = false);
this.on("exit", () => { this.on("exit", () => {
this._connected = false; this._connected = false;
@@ -48,19 +50,19 @@ export class ChildProcess extends ClientProxy<ChildProcessProxy> implements cp.C
public kill(): void { public kill(): void {
this._killed = true; this._killed = true;
this.proxy.kill(); this.catch(this.proxy.kill());
} }
public disconnect(): void { public disconnect(): void {
this.proxy.disconnect(); this.catch(this.proxy.disconnect());
} }
public ref(): void { public ref(): void {
this.proxy.ref(); this.catch(this.proxy.ref());
} }
public unref(): void { public unref(): void {
this.proxy.unref(); this.catch(this.proxy.unref());
} }
public send( 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. 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 { export class ChildProcessModule {

View File

@@ -1,15 +1,50 @@
import * as fs from "fs"; import * as fs from "fs";
import { callbackify } from "util"; import { callbackify } from "util";
import { ClientProxy } from "../../common/proxy"; import { ClientProxy, Batch } from "../../common/proxy";
import { IEncodingOptions, IEncodingOptionsCallback } from "../../common/util"; import { IEncodingOptions, IEncodingOptionsCallback } from "../../common/util";
import { FsModuleProxy, Stats as IStats, WatcherProxy, WriteStreamProxy } from "../../node/modules/fs"; import { FsModuleProxy, Stats as IStats, WatcherProxy, WriteStreamProxy } from "../../node/modules/fs";
import { Writable } from "./stream"; import { Writable } from "./stream";
// tslint:disable no-any // 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 { class Watcher extends ClientProxy<WatcherProxy> implements fs.FSWatcher {
public close(): void { 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 { public close(): void {
this.proxy.close(); this.catch(this.proxy.close());
} }
} }
export class FsModule { 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 => { public access = (path: fs.PathLike, mode: number | undefined | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => {
if (typeof mode === "function") { if (typeof mode === "function") {
@@ -72,9 +115,7 @@ export class FsModule {
} }
public exists = (path: fs.PathLike, callback: (exists: boolean) => void): void => { public exists = (path: fs.PathLike, callback: (exists: boolean) => void): void => {
callbackify(this.proxy.exists)(path, (exists) => { this.proxy.exists(path).then((exists) => callback(exists)).catch(() => callback(false));
callback!(exists as any);
});
} }
public fchmod = (fd: number, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => { 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 => { 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)); callback(error, stats && new Stats(stats));
}); });
} }
@@ -175,7 +216,7 @@ export class FsModule {
callback = options; callback = options;
options = undefined; 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 => { 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 => { 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)); callback(error, stats && new Stats(stats));
}); });
} }
@@ -276,17 +317,7 @@ export class FsModule {
} }
class Stats implements fs.Stats { class Stats implements fs.Stats {
public readonly atime: Date; public constructor(private readonly stats: IStats) {}
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 get dev(): number { return this.stats.dev; } public get dev(): number { return this.stats.dev; }
public get ino(): number { return this.stats.ino; } 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 size(): number { return this.stats.size; }
public get blksize(): number { return this.stats.blksize; } public get blksize(): number { return this.stats.blksize; }
public get blocks(): number { return this.stats.blocks; } 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 atimeMs(): number { return this.stats.atimeMs; }
public get mtimeMs(): number { return this.stats.mtimeMs; } public get mtimeMs(): number { return this.stats.mtimeMs; }
public get ctimeMs(): number { return this.stats.ctimeMs; } public get ctimeMs(): number { return this.stats.ctimeMs; }

View File

@@ -4,6 +4,8 @@ import { ClientProxy } from "../../common/proxy";
import { NetModuleProxy, NetServerProxy, NetSocketProxy } from "../../node/modules/net"; import { NetModuleProxy, NetServerProxy, NetSocketProxy } from "../../node/modules/net";
import { Duplex } from "./stream"; import { Duplex } from "./stream";
// tslint:disable completed-docs
export class Socket extends Duplex<NetSocketProxy> implements net.Socket { export class Socket extends Duplex<NetSocketProxy> implements net.Socket {
private _connecting: boolean = false; private _connecting: boolean = false;
private _destroyed: boolean = false; private _destroyed: boolean = false;
@@ -29,9 +31,8 @@ export class Socket extends Duplex<NetSocketProxy> implements net.Socket {
if (callback) { if (callback) {
this.on("connect", callback as () => void); 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 // tslint:disable-next-line no-any
@@ -117,24 +118,30 @@ export class Socket extends Duplex<NetSocketProxy> implements net.Socket {
} }
public unref(): void { public unref(): void {
this.proxy.unref(); this.catch(this.proxy.unref());
} }
public ref(): void { public ref(): void {
this.proxy.ref(); this.catch(this.proxy.ref());
} }
} }
export class Server extends ClientProxy<NetServerProxy> implements net.Server { export class Server extends ClientProxy<NetServerProxy> implements net.Server {
private socketId = 0;
private readonly sockets = new Map<number, net.Socket>(); private readonly sockets = new Map<number, net.Socket>();
private _listening: boolean = false; private _listening: boolean = false;
public constructor(proxyPromise: Promise<NetServerProxy> | NetServerProxy) { public constructor(proxyPromise: Promise<NetServerProxy> | NetServerProxy) {
super(proxyPromise); super(proxyPromise);
this.proxy.onConnection((socketProxy) => { this.catch(this.proxy.onConnection((socketProxy) => {
this.emit("connection", new Socket(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("listening", () => this._listening = true);
this.on("error", () => this._listening = false); 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.on("listening", callback as () => void);
} }
this.proxy.listen(handle, hostname, backlog); return this.catch(this.proxy.listen(handle, hostname, backlog));
return this;
} }
public get connections(): number { public get connections(): number {
@@ -180,26 +185,25 @@ export class Server extends ClientProxy<NetServerProxy> implements net.Server {
if (callback) { if (callback) {
this.on("close", callback); this.on("close", callback);
} }
this.proxy.close();
return this; return this.catch(this.proxy.close());
} }
public ref(): this { public ref(): this {
this.proxy.ref(); return this.catch(this.proxy.ref());
return this;
} }
public unref(): this { public unref(): this {
this.proxy.unref(); return this.catch(this.proxy.unref());
return this;
} }
public getConnections(cb: (error: Error | null, count: number) => void): void { public getConnections(cb: (error: Error | null, count: number) => void): void {
cb(null, this.sockets.size); cb(null, this.sockets.size);
} }
protected handleDisconnect(): void {
this.emit("close");
}
} }
type NodeNet = typeof net; type NodeNet = typeof net;

View File

@@ -2,17 +2,28 @@ import * as pty from "node-pty";
import { ClientProxy } from "../../common/proxy"; import { ClientProxy } from "../../common/proxy";
import { NodePtyModuleProxy, NodePtyProcessProxy } from "../../node/modules/node-pty"; import { NodePtyModuleProxy, NodePtyProcessProxy } from "../../node/modules/node-pty";
// tslint:disable completed-docs
export class NodePtyProcess extends ClientProxy<NodePtyProcessProxy> implements pty.IPty { export class NodePtyProcess extends ClientProxy<NodePtyProcessProxy> implements pty.IPty {
private _pid = -1; private _pid = -1;
private _process = ""; private _process = "";
public constructor(proxyPromise: Promise<NodePtyProcessProxy>) { public constructor(
super(proxyPromise); private readonly moduleProxy: NodePtyModuleProxy,
this.proxy.getPid().then((pid) => this._pid = pid); private readonly file: string,
this.proxy.getProcess().then((process) => this._process = process); private readonly args: string[] | string,
private readonly options: pty.IPtyForkOptions,
) {
super(moduleProxy.spawn(file, args, options));
this.on("process", (process) => this._process = process); 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 { public get pid(): number {
return this._pid; return this._pid;
} }
@@ -22,15 +33,21 @@ export class NodePtyProcess extends ClientProxy<NodePtyProcessProxy> implements
} }
public resize(columns: number, rows: number): void { public resize(columns: number, rows: number): void {
this.proxy.resize(columns, rows); this.catch(this.proxy.resize(columns, rows));
} }
public write(data: string): void { public write(data: string): void {
this.proxy.write(data); this.catch(this.proxy.write(data));
} }
public kill(signal?: string): void { 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 constructor(private readonly proxy: NodePtyModuleProxy) {}
public spawn = (file: string, args: string[] | string, options: pty.IPtyForkOptions): pty.IPty => { 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);
} }
} }

View File

@@ -2,17 +2,33 @@ import * as spdlog from "spdlog";
import { ClientProxy } from "../../common/proxy"; import { ClientProxy } from "../../common/proxy";
import { RotatingLoggerProxy, SpdlogModuleProxy } from "../../node/modules/spdlog"; import { RotatingLoggerProxy, SpdlogModuleProxy } from "../../node/modules/spdlog";
// tslint:disable completed-docs
class RotatingLogger extends ClientProxy<RotatingLoggerProxy> implements spdlog.RotatingLogger { class RotatingLogger extends ClientProxy<RotatingLoggerProxy> implements spdlog.RotatingLogger {
public async trace (message: string): Promise<void> { this.proxy.trace(message); } public constructor(
public async debug (message: string): Promise<void> { this.proxy.debug(message); } private readonly moduleProxy: SpdlogModuleProxy,
public async info (message: string): Promise<void> { this.proxy.info(message); } private readonly name: string,
public async warn (message: string): Promise<void> { this.proxy.warn(message); } private readonly filename: string,
public async error (message: string): Promise<void> { this.proxy.error(message); } private readonly filesize: number,
public async critical (message: string): Promise<void> { this.proxy.critical(message); } private readonly filecount: number,
public async setLevel (level: number): Promise<void> { this.proxy.setLevel(level); } ) {
public async clearFormatters (): Promise<void> { this.proxy.clearFormatters(); } super(moduleProxy.createLogger(name, filename, filesize, filecount));
public async flush (): Promise<void> { this.proxy.flush(); } }
public async drop (): Promise<void> { this.proxy.drop(); }
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 { export class SpdlogModule {
@@ -21,12 +37,20 @@ export class SpdlogModule {
public constructor(private readonly proxy: SpdlogModuleProxy) { public constructor(private readonly proxy: SpdlogModuleProxy) {
this.RotatingLogger = class extends RotatingLogger { this.RotatingLogger = class extends RotatingLogger {
public constructor(name: string, filename: string, filesize: number, filecount: number) { 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 => { public setAsyncMode = (bufferSize: number, flushInterval: number): Promise<void> => {
this.proxy.setAsyncMode(bufferSize, flushInterval); 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));
} }
} }

View File

@@ -3,6 +3,8 @@ import { callbackify } from "util";
import { ClientProxy } from "../../common/proxy"; import { ClientProxy } from "../../common/proxy";
import { DuplexProxy, IReadableProxy, WritableProxy } from "../../node/modules/stream"; 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 { export class Writable<T extends WritableProxy = WritableProxy> extends ClientProxy<T> implements stream.Writable {
public get writable(): boolean { public get writable(): boolean {
throw new Error("not implemented"); throw new Error("not implemented");
@@ -41,13 +43,11 @@ export class Writable<T extends WritableProxy = WritableProxy> extends ClientPro
} }
public destroy(): void { public destroy(): void {
this.proxy.destroy(); this.catch(this.proxy.destroy());
} }
public setDefaultEncoding(encoding: string): this { public setDefaultEncoding(encoding: string): this {
this.proxy.setDefaultEncoding(encoding); return this.catch(this.proxy.setDefaultEncoding(encoding));
return this;
} }
// tslint:disable-next-line no-any // 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 { 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 { public destroy(): void {
this.proxy.destroy(); this.catch(this.proxy.destroy());
} }
public setEncoding(encoding: string): this { 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 { 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");
} }
} }

View File

@@ -1,6 +1,8 @@
import * as trash from "trash"; import * as trash from "trash";
import { TrashModuleProxy } from "../../node/modules/trash"; import { TrashModuleProxy } from "../../node/modules/trash";
// tslint:disable completed-docs
export class TrashModule { export class TrashModule {
public constructor(private readonly proxy: TrashModuleProxy) {} public constructor(private readonly proxy: TrashModuleProxy) {}

View File

@@ -23,6 +23,7 @@ export interface InitData {
readonly homeDirectory: string; readonly homeDirectory: string;
readonly tmpDirectory: string; readonly tmpDirectory: string;
readonly shell: string; readonly shell: string;
readonly extensionsDirectory: string;
readonly builtInExtensionsDirectory: string; readonly builtInExtensionsDirectory: string;
} }

View File

@@ -29,21 +29,77 @@ const unpromisify = <T extends ServerProxy>(proxyPromise: Promise<T>): T => {
* need a bunch of `then` calls everywhere. * need a bunch of `then` calls everywhere.
*/ */
export abstract class ClientProxy<T extends ServerProxy> extends EventEmitter { 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 * You can specify not to bind events in order to avoid emitting twice for
* duplex streams. * duplex streams.
*/ */
public constructor(proxyPromise: Promise<T> | T, bindEvents: boolean = true) { public constructor(
proxyPromise: Promise<T> | T,
private readonly bindEvents: boolean = true,
) {
super(); super();
this.proxy = isPromise(proxyPromise) ? unpromisify(proxyPromise) : proxyPromise; this.initialize(proxyPromise);
if (bindEvents) { if (this.bindEvents) {
this.proxy.onEvent((event, ...args): void => { this.on("disconnected", (error) => {
this.emit(event, ...args); 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. * from those child proxies and fail to dispose them properly.
*/ */
export interface ServerProxy { export interface ServerProxy {
/**
* Dispose the proxy.
*/
dispose(): Promise<void>; dispose(): Promise<void>;
/** /**
@@ -73,6 +132,9 @@ export interface ServerProxy {
onEvent(cb: (event: string, ...args: any[]) => void): Promise<void>; onEvent(cb: (event: string, ...args: any[]) => void): Promise<void>;
} }
/**
* Supported top-level module proxies.
*/
export enum Module { export enum Module {
Fs = "fs", Fs = "fs",
ChildProcess = "child_process", ChildProcess = "child_process",
@@ -81,3 +143,82 @@ export enum Module {
NodePty = "node-pty", NodePty = "node-pty",
Trash = "trash", 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)));
}
}

View File

@@ -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 { OperatingSystem } from "../common/connection";
import { Module, ServerProxy } from "./proxy"; import { Module, ServerProxy } from "./proxy";
@@ -29,227 +29,151 @@ export type IEncodingOptions = {
export type IEncodingOptionsCallback = IEncodingOptions | ((err: NodeJS.ErrnoException, ...args: any[]) => void); 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 function is possible, provide `storeFunction`.
* If sending a proxy is possible, provide `storeProxy`. * If sending a proxy is possible, provide `storeProxy`.
*/ */
export const stringify = ( export const argumentToProto = (
value: any, value: any,
storeFunction?: (fn: () => void) => number, storeFunction?: (fn: () => void) => number,
storeProxy?: (proxy: ServerProxy) => number, storeProxy?: (proxy: ServerProxy) => number,
): string => { ): Argument => {
const convert = (currentValue: any): StringifiedValue => { const convert = (currentValue: any): Argument => {
// Errors don't stringify at all. They just become "{}". const message = new Argument();
// For some reason when running in Jest errors aren't instances of Error,
// so also check against the values.
if (currentValue instanceof Error if (currentValue instanceof Error
|| (currentValue && typeof currentValue.message !== "undefined" || (currentValue && typeof currentValue.message !== "undefined"
&& typeof currentValue.stack !== "undefined")) { && typeof currentValue.stack !== "undefined")) {
return { const arg = new Argument.ErrorValue();
type: "error", arg.setMessage(currentValue.message);
data: { arg.setStack(currentValue.stack);
message: currentValue.message, arg.setCode(currentValue.code);
stack: currentValue.stack, message.setError(arg);
code: (currentValue as NodeJS.ErrnoException).code, } else if (currentValue instanceof Uint8Array || currentValue instanceof Buffer) {
}, const arg = new Argument.BufferValue();
}; arg.setData(currentValue);
} message.setBuffer(arg);
} else if (Array.isArray(currentValue)) {
// With stringify, Uint8Array gets turned into objects with each index const arg = new Argument.ArrayValue();
// becoming a key for some reason. Then trying to do something like write arg.setDataList(currentValue.map(convert));
// that data results in [object Object] being written. Stringify them like message.setArray(arg);
// a Buffer instead. Also handle Buffer so it doesn't get caught by the } else if (isProxy(currentValue)) {
// 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)) {
if (!storeProxy) { if (!storeProxy) {
throw new Error("no way to serialize proxy"); throw new Error("no way to serialize proxy");
} }
const arg = new Argument.ProxyValue();
return { arg.setId(storeProxy(currentValue));
type: "proxy", message.setProxy(arg);
data: { } else if (currentValue instanceof Date
id: storeProxy(currentValue), || (currentValue && typeof currentValue.getTime === "function")) {
}, const arg = new Argument.DateValue();
}; arg.setDate(currentValue.toString());
} message.setDate(arg);
} else if (currentValue !== null && typeof currentValue === "object") {
if (currentValue !== null && typeof currentValue === "object") { const arg = new Argument.ObjectValue();
const converted: { [key: string]: StringifiedValue } = {}; const map = arg.getDataMap();
Object.keys(currentValue).forEach((key) => { Object.keys(currentValue).forEach((key) => {
converted[key] = convert(currentValue[key]); map.set(key, convert(currentValue[key]));
}); });
message.setObject(arg);
return { } else if (currentValue === null) {
type: "object", message.setNull(new Argument.NullValue());
data: converted, } else {
}; switch (typeof currentValue) {
} case "undefined":
message.setUndefined(new Argument.UndefinedValue());
// `undefined` can't be stringified. break;
if (typeof currentValue === "undefined") { case "function":
return { if (!storeFunction) {
type: "undefined", throw new Error("no way to serialize function");
}; }
} const arg = new Argument.FunctionValue();
arg.setId(storeFunction(currentValue));
if (typeof currentValue === "function") { message.setFunction(arg);
if (!storeFunction) { break;
throw new Error("no way to serialize function"); 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)) { return message;
throw new Error(`cannot stringify ${typeof currentValue}`);
}
return currentValue;
}; };
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 running a remote callback is supported, provide `runCallback`.
* If using a remote proxy is supported, provide `createProxy`. * If using a remote proxy is supported, provide `createProxy`.
*/ */
export const parse = ( export const protoToArgument = (
value?: string, message?: Argument,
runCallback?: (id: number, args: any[]) => void, runCallback?: (id: number, args: any[]) => void,
createProxy?: (id: number) => ServerProxy, createProxy?: (id: number) => ServerProxy,
): any => { ): any => {
const convert = (currentValue: StringifiedValue): any => { const convert = (currentMessage: Argument): any => {
if (currentValue && !isPrimitive(currentValue)) { switch (currentMessage.getMsgCase()) {
// Would prefer a switch but the types don't seem to work. case Argument.MsgCase.ERROR:
if (currentValue.type === "buffer") { const errorMessage = currentMessage.getError()!;
return Buffer.from(currentValue.data); const error = new Error(errorMessage.getMessage());
} (error as NodeJS.ErrnoException).code = errorMessage.getCode();
(error as any).originalStack = errorMessage.getStack();
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;
return error; 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") { return createProxy(currentMessage.getProxy()!.getId());
const converted: { [key: string]: any } = {}; case Argument.MsgCase.DATE:
Object.keys(currentValue.data).forEach((key) => { return new Date(currentMessage.getDate()!.getDate());
converted[key] = convert(currentValue.data[key]); case Argument.MsgCase.OBJECT:
const obj: { [Key: string]: any } = {};
currentMessage.getObject()!.getDataMap().forEach((argument, key) => {
obj[key] = convert(argument);
}); });
return converted; return obj;
} case Argument.MsgCase.UNDEFINED:
if (currentValue.type === "array") {
return currentValue.data.map(convert);
}
if (currentValue.type === "undefined") {
return undefined; return undefined;
} case Argument.MsgCase.NULL:
return null;
if (currentValue.type === "function") { case Argument.MsgCase.FUNCTION:
if (!runCallback) { if (!runCallback) {
throw new Error("no way to run remote callback"); throw new Error("no way to run remote callback");
} }
return (...args: any[]): void => { return (...args: any[]): void => {
return runCallback(currentValue.data.id, args); return runCallback(currentMessage.getFunction()!.getId(), args);
}; };
} case Argument.MsgCase.NUMBER:
return currentMessage.getNumber();
if (currentValue.type === "proxy") { case Argument.MsgCase.STRING:
if (!createProxy) { return currentMessage.getString();
throw new Error("no way to create proxy"); case Argument.MsgCase.BOOLEAN:
} return currentMessage.getBoolean();
default:
return createProxy(currentValue.data.id); 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 => { 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) { switch (protoOp) {
case WorkingInitMessage.OperatingSystem.WINDOWS: return OperatingSystem.Windows; case WorkingInit.OperatingSystem.WINDOWS: return OperatingSystem.Windows;
case WorkingInitMessage.OperatingSystem.LINUX: return OperatingSystem.Linux; case WorkingInit.OperatingSystem.LINUX: return OperatingSystem.Linux;
case WorkingInitMessage.OperatingSystem.MAC: return OperatingSystem.Mac; case WorkingInit.OperatingSystem.MAC: return OperatingSystem.Mac;
default: throw new Error(`unsupported operating system ${protoOp}`); 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) { switch (platform) {
case "win32": return WorkingInitMessage.OperatingSystem.WINDOWS; case "win32": return WorkingInit.OperatingSystem.WINDOWS;
case "linux": return WorkingInitMessage.OperatingSystem.LINUX; case "linux": return WorkingInit.OperatingSystem.LINUX;
case "darwin": return WorkingInitMessage.OperatingSystem.MAC; case "darwin": return WorkingInit.OperatingSystem.MAC;
default: throw new Error(`unrecognized platform "${platform}"`); default: throw new Error(`unrecognized platform "${platform}"`);
} }
}; };

View File

@@ -3,6 +3,8 @@ import { ServerProxy } from "../../common/proxy";
import { preserveEnv } from "../../common/util"; import { preserveEnv } from "../../common/util";
import { WritableProxy, ReadableProxy } from "./stream"; import { WritableProxy, ReadableProxy } from "./stream";
// tslint:disable completed-docs
export type ForkProvider = (modulePath: string, args?: string[], options?: cp.ForkOptions) => cp.ChildProcess; export type ForkProvider = (modulePath: string, args?: string[], options?: cp.ForkOptions) => cp.ChildProcess;
export class ChildProcessProxy implements ServerProxy { export class ChildProcessProxy implements ServerProxy {
@@ -26,7 +28,7 @@ export class ChildProcessProxy implements ServerProxy {
// tslint:disable-next-line no-any // tslint:disable-next-line no-any
public async send(message: any): Promise<void> { public async send(message: any): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject): void => {
this.process.send(message, (error) => { this.process.send(message, (error) => {
if (error) { if (error) {
reject(error); reject(error);
@@ -46,8 +48,8 @@ export class ChildProcessProxy implements ServerProxy {
} }
public async dispose(): Promise<void> { public async dispose(): Promise<void> {
this.kill(); this.process.kill();
setTimeout(() => this.kill("SIGKILL"), 5000); // Double tap. setTimeout(() => this.process.kill("SIGKILL"), 5000); // Double tap.
} }
// tslint:disable-next-line no-any // tslint:disable-next-line no-any
@@ -62,9 +64,9 @@ export class ChildProcessProxy implements ServerProxy {
export interface ChildProcessProxies { export interface ChildProcessProxies {
childProcess: ChildProcessProxy; childProcess: ChildProcessProxy;
stdin?: WritableProxy; stdin?: WritableProxy | null;
stdout?: ReadableProxy; stdout?: ReadableProxy | null;
stderr?: ReadableProxy; stderr?: ReadableProxy | null;
} }
export class ChildProcessModuleProxy { export class ChildProcessModuleProxy {

View File

@@ -4,6 +4,8 @@ import { ServerProxy } from "../../common/proxy";
import { IEncodingOptions } from "../../common/util"; import { IEncodingOptions } from "../../common/util";
import { WritableProxy } from "./stream"; import { WritableProxy } from "./stream";
// tslint:disable completed-docs
/** /**
* A serializable version of fs.Stats. * A serializable version of fs.Stats.
*/ */
@@ -22,10 +24,10 @@ export interface Stats {
mtimeMs: number; mtimeMs: number;
ctimeMs: number; ctimeMs: number;
birthtimeMs: number; birthtimeMs: number;
atime: Date | string; atime: Date;
mtime: Date | string; mtime: Date;
ctime: Date | string; ctime: Date;
birthtime: Date | string; birthtime: Date;
_isFile: boolean; _isFile: boolean;
_isDirectory: boolean; _isDirectory: boolean;
_isBlockDevice: boolean; _isBlockDevice: boolean;
@@ -41,13 +43,13 @@ export class WriteStreamProxy extends WritableProxy<fs.WriteStream> {
} }
public async dispose(): Promise<void> { public async dispose(): Promise<void> {
super.dispose(); await super.dispose();
this.stream.close(); this.stream.close();
} }
// tslint:disable-next-line no-any // tslint:disable-next-line no-any
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> { 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)); this.stream.on("open", (fd) => cb("open", fd));
} }
} }
@@ -109,7 +111,7 @@ export class FsModuleProxy {
} }
public exists(path: fs.PathLike): Promise<boolean> { 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> { public fchmod(fd: number, mode: string | number): Promise<void> {
@@ -156,6 +158,10 @@ export class FsModuleProxy {
return this.makeStatsSerializable(await promisify(fs.lstat)(path)); 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> { public mkdir(path: fs.PathLike, mode: number | string | fs.MakeDirectoryOptions | undefined | null): Promise<void> {
return promisify(fs.mkdir)(path, mode); 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 }> { 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); return promisify(fs.read)(fd, buffer, 0, length, position);
} }
@@ -182,6 +188,10 @@ export class FsModuleProxy {
return promisify(fs.readdir)(path, options); 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> { public readlink(path: fs.PathLike, options: IEncodingOptions): Promise<string | Buffer> {
return promisify(fs.readlink)(path, options); return promisify(fs.readlink)(path, options);
} }
@@ -202,6 +212,10 @@ export class FsModuleProxy {
return this.makeStatsSerializable(await promisify(fs.stat)(path)); 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> { public symlink(target: fs.PathLike, path: fs.PathLike, type?: fs.symlink.Type | null): Promise<void> {
return promisify(fs.symlink)(target, path, type); return promisify(fs.symlink)(target, path, type);
} }

View File

@@ -2,6 +2,8 @@ import * as net from "net";
import { ServerProxy } from "../../common/proxy"; import { ServerProxy } from "../../common/proxy";
import { DuplexProxy } from "./stream"; import { DuplexProxy } from "./stream";
// tslint:disable completed-docs
export class NetSocketProxy extends DuplexProxy<net.Socket> { export class NetSocketProxy extends DuplexProxy<net.Socket> {
public async connect(options: number | string | net.SocketConnectOpts, host?: string): Promise<void> { 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 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 // tslint:disable-next-line no-any
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> { 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("connect", () => cb("connect"));
this.stream.on("lookup", (error, address, family, host) => cb("lookup", error, address, family, host)); this.stream.on("lookup", (error, address, family, host) => cb("lookup", error, address, family, host));
this.stream.on("timeout", () => cb("timeout")); this.stream.on("timeout", () => cb("timeout"));

View File

@@ -4,6 +4,8 @@ import * as pty from "node-pty";
import { ServerProxy } from "../../common/proxy"; import { ServerProxy } from "../../common/proxy";
import { preserveEnv } from "../../common/util"; import { preserveEnv } from "../../common/util";
// tslint:disable completed-docs
/** /**
* Server-side IPty proxy. * Server-side IPty proxy.
*/ */
@@ -22,7 +24,7 @@ export class NodePtyProcessProxy implements ServerProxy {
} }
}, 200); }, 200);
this.onDone(() => clearInterval(timer)); this.process.on("exit", () => clearInterval(timer));
} }
public async getPid(): Promise<number> { public async getPid(): Promise<number> {
@@ -50,8 +52,8 @@ export class NodePtyProcessProxy implements ServerProxy {
} }
public async dispose(): Promise<void> { public async dispose(): Promise<void> {
this.kill(); this.process.kill();
setTimeout(() => this.kill("SIGKILL"), 5000); // Double tap. setTimeout(() => this.process.kill("SIGKILL"), 5000); // Double tap.
this.emitter.removeAllListeners(); this.emitter.removeAllListeners();
} }

View File

@@ -3,6 +3,8 @@ import { EventEmitter } from "events";
import * as spdlog from "spdlog"; import * as spdlog from "spdlog";
import { ServerProxy } from "../../common/proxy"; import { ServerProxy } from "../../common/proxy";
// tslint:disable completed-docs
export class RotatingLoggerProxy implements ServerProxy { export class RotatingLoggerProxy implements ServerProxy {
private readonly emitter = new EventEmitter(); private readonly emitter = new EventEmitter();
@@ -24,7 +26,7 @@ export class RotatingLoggerProxy implements ServerProxy {
} }
public async dispose(): Promise<void> { public async dispose(): Promise<void> {
this.flush(); await this.flush();
this.emitter.emit("dispose"); this.emitter.emit("dispose");
this.emitter.removeAllListeners(); this.emitter.removeAllListeners();
} }

View File

@@ -1,6 +1,8 @@
import * as stream from "stream"; import * as stream from "stream";
import { ServerProxy } from "../../common/proxy"; import { ServerProxy } from "../../common/proxy";
// tslint:disable completed-docs
export class WritableProxy<T extends stream.Writable = stream.Writable> implements ServerProxy { export class WritableProxy<T extends stream.Writable = stream.Writable> implements ServerProxy {
public constructor(protected readonly stream: T) {} 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 // tslint:disable-next-line no-any
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> { 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("data", (chunk) => cb("data", chunk));
this.stream.on("end", () => cb("end")); this.stream.on("end", () => cb("end"));
} }

View File

@@ -1,5 +1,7 @@
import * as trash from "trash"; import * as trash from "trash";
// tslint:disable completed-docs
export class TrashModuleProxy { export class TrashModuleProxy {
public async trash(path: string, options?: trash.Options): Promise<void> { public async trash(path: string, options?: trash.Options): Promise<void> {
return trash(path, options); return trash(path, options);

View File

@@ -3,8 +3,8 @@ import * as os from "os";
import { field, logger} from "@coder/logger"; import { field, logger} from "@coder/logger";
import { ReadWriteConnection } from "../common/connection"; import { ReadWriteConnection } from "../common/connection";
import { Module, ServerProxy } from "../common/proxy"; import { Module, ServerProxy } from "../common/proxy";
import { isPromise, isProxy, moduleToProto, parse, platformToProto, protoToModule, stringify } from "../common/util"; import { isPromise, isProxy, moduleToProto, protoToArgument, platformToProto, protoToModule, argumentToProto } from "../common/util";
import { CallbackMessage, ClientMessage, EventMessage, FailMessage, MethodMessage, NamedCallbackMessage, NamedEventMessage, NumberedCallbackMessage, NumberedEventMessage, Pong, ServerMessage, SuccessMessage, WorkingInitMessage } from "../proto"; import { Argument, Callback, ClientMessage, Event, Method, Pong, ServerMessage, WorkingInit } from "../proto";
import { ChildProcessModuleProxy, ForkProvider, FsModuleProxy, NetModuleProxy, NodePtyModuleProxy, SpdlogModuleProxy, TrashModuleProxy } from "./modules"; import { ChildProcessModuleProxy, ForkProvider, FsModuleProxy, NetModuleProxy, NodePtyModuleProxy, SpdlogModuleProxy, TrashModuleProxy } from "./modules";
// tslint:disable no-any // tslint:disable no-any
@@ -14,6 +14,7 @@ export interface ServerOptions {
readonly dataDirectory: string; readonly dataDirectory: string;
readonly cacheDirectory: string; readonly cacheDirectory: string;
readonly builtInExtensionsDirectory: string; readonly builtInExtensionsDirectory: string;
readonly extensionsDirectory: string;
readonly fork?: ForkProvider; readonly fork?: ForkProvider;
} }
@@ -22,11 +23,14 @@ interface ProxyData {
instance: any; instance: any;
} }
/**
* Handle messages from the client.
*/
export class Server { export class Server {
private proxyId = 0; private proxyId = 0;
private readonly proxies = new Map<number | Module, ProxyData>(); private readonly proxies = new Map<number | Module, ProxyData>();
private disconnected: boolean = false; private disconnected: boolean = false;
private responseTimeout = 10000; private readonly responseTimeout = 10000;
public constructor( public constructor(
private readonly connection: ReadWriteConnection, private readonly connection: ReadWriteConnection,
@@ -57,7 +61,9 @@ export class Server {
this.proxies.forEach((proxy, proxyId) => { this.proxies.forEach((proxy, proxyId) => {
if (isProxy(proxy.instance)) { if (isProxy(proxy.instance)) {
proxy.instance.dispose(); proxy.instance.dispose().catch((error) => {
logger.error(error.message);
});
} }
this.removeProxy(proxyId); this.removeProxy(proxyId);
}); });
@@ -84,14 +90,15 @@ export class Server {
logger.error(error.message, field("error", error)); logger.error(error.message, field("error", error));
}); });
const initMsg = new WorkingInitMessage(); const initMsg = new WorkingInit();
initMsg.setDataDirectory(this.options.dataDirectory); initMsg.setDataDirectory(this.options.dataDirectory);
initMsg.setWorkingDirectory(this.options.workingDirectory); initMsg.setWorkingDirectory(this.options.workingDirectory);
initMsg.setBuiltinExtensionsDir(this.options.builtInExtensionsDirectory); initMsg.setBuiltinExtensionsDir(this.options.builtInExtensionsDirectory);
initMsg.setExtensionsDirectory(this.options.extensionsDirectory);
initMsg.setHomeDirectory(os.homedir()); initMsg.setHomeDirectory(os.homedir());
initMsg.setTmpDirectory(os.tmpdir()); initMsg.setTmpDirectory(os.tmpdir());
initMsg.setOperatingSystem(platformToProto(os.platform())); 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(); const srvMsg = new ServerMessage();
srvMsg.setInit(initMsg); srvMsg.setInit(initMsg);
connection.send(srvMsg.serializeBinary()); connection.send(srvMsg.serializeBinary());
@@ -101,29 +108,32 @@ export class Server {
* Handle all messages from the client. * Handle all messages from the client.
*/ */
private async handleMessage(message: ClientMessage): Promise<void> { private async handleMessage(message: ClientMessage): Promise<void> {
if (message.hasMethod()) { switch (message.getMsgCase()) {
await this.runMethod(message.getMethod()!); case ClientMessage.MsgCase.METHOD:
} else if (message.hasPing()) { await this.runMethod(message.getMethod()!);
logger.trace("ping"); break;
const srvMsg = new ServerMessage(); case ClientMessage.MsgCase.PING:
srvMsg.setPong(new Pong()); logger.trace("ping");
this.connection.send(srvMsg.serializeBinary()); const srvMsg = new ServerMessage();
} else { srvMsg.setPong(new Pong());
throw new Error("unknown message type"); this.connection.send(srvMsg.serializeBinary());
break;
default:
throw new Error("unknown message type");
} }
} }
/** /**
* Run a method on a proxy. * 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 proxyMessage = message.getNamedProxy()! || message.getNumberedProxy()!;
const id = proxyMessage.getId(); const id = proxyMessage.getId();
const proxyId = message.hasNamedProxy() const proxyId = message.hasNamedProxy()
? protoToModule(message.getNamedProxy()!.getModule()) ? protoToModule(message.getNamedProxy()!.getModule())
: message.getNumberedProxy()!.getProxyId(); : message.getNumberedProxy()!.getProxyId();
const method = proxyMessage.getMethod(); const method = proxyMessage.getMethod();
const args = proxyMessage.getArgsList().map((a) => parse( const args = proxyMessage.getArgsList().map((a) => protoToArgument(
a, a,
(id, args) => this.sendCallback(proxyId, id, args), (id, args) => this.sendCallback(proxyId, id, args),
)); ));
@@ -133,14 +143,13 @@ export class Server {
field("id", id), field("id", id),
field("proxyId", proxyId), field("proxyId", proxyId),
field("method", method), field("method", method),
field("args", proxyMessage.getArgsList()),
]); ]);
let response: any; let response: any;
try { try {
const proxy = this.getProxy(proxyId); const proxy = this.getProxy(proxyId);
if (typeof proxy.instance[method] !== "function") { 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); response = proxy.instance[method](...args);
@@ -153,7 +162,7 @@ export class Server {
// Proxies must always return promises. // Proxies must always return promises.
if (!isPromise(response)) { if (!isPromise(response)) {
throw new Error('"${method}" must return a promise'); throw new Error(`"${method}" must return a promise`);
} }
} catch (error) { } catch (error) {
logger.error( logger.error(
@@ -175,27 +184,25 @@ export class Server {
* Send a callback to the client. * Send a callback to the client.
*/ */
private sendCallback(proxyId: number | Module, callbackId: number, args: any[]): void { private sendCallback(proxyId: number | Module, callbackId: number, args: any[]): void {
const stringifiedArgs = args.map((a) => this.stringify(a));
logger.trace(() => [ logger.trace(() => [
"sending callback", "sending callback",
field("proxyId", proxyId), field("proxyId", proxyId),
field("callbackId", callbackId), field("callbackId", callbackId),
field("args", stringifiedArgs),
]); ]);
const message = new CallbackMessage(); const message = new Callback();
let callbackMessage: NamedCallbackMessage | NumberedCallbackMessage; let callbackMessage: Callback.Named | Callback.Numbered;
if (typeof proxyId === "string") { if (typeof proxyId === "string") {
callbackMessage = new NamedCallbackMessage(); callbackMessage = new Callback.Named();
callbackMessage.setModule(moduleToProto(proxyId)); callbackMessage.setModule(moduleToProto(proxyId));
message.setNamedCallback(callbackMessage); message.setNamedCallback(callbackMessage);
} else { } else {
callbackMessage = new NumberedCallbackMessage(); callbackMessage = new Callback.Numbered();
callbackMessage.setProxyId(proxyId); callbackMessage.setProxyId(proxyId);
message.setNumberedCallback(callbackMessage); message.setNumberedCallback(callbackMessage);
} }
callbackMessage.setCallbackId(callbackId); callbackMessage.setCallbackId(callbackId);
callbackMessage.setArgsList(stringifiedArgs); callbackMessage.setArgsList(args.map((a) => this.argumentToProto(a)));
const serverMessage = new ServerMessage(); const serverMessage = new ServerMessage();
serverMessage.setCallback(message); 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; 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; 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 { private storeProxy(instance: ServerProxy | any, moduleProxyId?: Module): number | Module {
// In case we disposed while waiting for a function to return. // In case we disposed while waiting for a function to return.
if (this.disconnected) { if (this.disconnected) {
if (isProxy(instance)) { if (isProxy(instance)) {
instance.dispose(); instance.dispose().catch((error) => {
logger.error(error.message);
});
} }
throw new Error("disposed"); throw new Error("disposed");
@@ -226,16 +241,22 @@ export class Server {
this.proxies.set(proxyId, { instance }); this.proxies.set(proxyId, { instance });
if (isProxy(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(() => { instance.onDone(() => {
// It might have finished because we disposed it due to a disconnect. // It might have finished because we disposed it due to a disconnect.
if (!this.disconnected) { if (!this.disconnected) {
this.sendEvent(proxyId, "done"); this.sendEvent(proxyId, "done");
this.getProxy(proxyId).disposeTimeout = setTimeout(() => { this.getProxy(proxyId).disposeTimeout = setTimeout(() => {
instance.dispose(); instance.dispose().catch((error) => {
logger.error(error.message);
});
this.removeProxy(proxyId); this.removeProxy(proxyId);
}, this.responseTimeout); }, this.responseTimeout);
} }
}).catch((error) => {
logger.error(error.message);
}); });
} }
@@ -246,27 +267,25 @@ export class Server {
* Send an event to the client. * Send an event to the client.
*/ */
private sendEvent(proxyId: number | Module, event: string, ...args: any[]): void { private sendEvent(proxyId: number | Module, event: string, ...args: any[]): void {
const stringifiedArgs = args.map((a) => this.stringify(a));
logger.trace(() => [ logger.trace(() => [
"sending event", "sending event",
field("proxyId", proxyId), field("proxyId", proxyId),
field("event", event), field("event", event),
field("args", stringifiedArgs),
]); ]);
const message = new EventMessage(); const message = new Event();
let eventMessage: NamedEventMessage | NumberedEventMessage; let eventMessage: Event.Named | Event.Numbered;
if (typeof proxyId === "string") { if (typeof proxyId === "string") {
eventMessage = new NamedEventMessage(); eventMessage = new Event.Named();
eventMessage.setModule(moduleToProto(proxyId)); eventMessage.setModule(moduleToProto(proxyId));
message.setNamedEvent(eventMessage); message.setNamedEvent(eventMessage);
} else { } else {
eventMessage = new NumberedEventMessage(); eventMessage = new Event.Numbered();
eventMessage.setProxyId(proxyId); eventMessage.setProxyId(proxyId);
message.setNumberedEvent(eventMessage); message.setNumberedEvent(eventMessage);
} }
eventMessage.setEvent(event); eventMessage.setEvent(event);
eventMessage.setArgsList(stringifiedArgs); eventMessage.setArgsList(args.map((a) => this.argumentToProto(a)));
const serverMessage = new ServerMessage(); const serverMessage = new ServerMessage();
serverMessage.setEvent(message); serverMessage.setEvent(message);
@@ -277,16 +296,14 @@ export class Server {
* Send a response back to the client. * Send a response back to the client.
*/ */
private sendResponse(id: number, response: any): void { private sendResponse(id: number, response: any): void {
const stringifiedResponse = this.stringify(response);
logger.trace(() => [ logger.trace(() => [
"sending resolve", "sending resolve",
field("id", id), field("id", id),
field("response", stringifiedResponse),
]); ]);
const successMessage = new SuccessMessage(); const successMessage = new Method.Success();
successMessage.setId(id); successMessage.setId(id);
successMessage.setResponse(stringifiedResponse); successMessage.setResponse(this.argumentToProto(response));
const serverMessage = new ServerMessage(); const serverMessage = new ServerMessage();
serverMessage.setSuccess(successMessage); serverMessage.setSuccess(successMessage);
@@ -297,16 +314,15 @@ export class Server {
* Send an exception back to the client. * Send an exception back to the client.
*/ */
private sendException(id: number, error: Error): void { private sendException(id: number, error: Error): void {
const stringifiedError = stringify(error);
logger.trace(() => [ logger.trace(() => [
"sending reject", "sending reject",
field("id", id) , field("id", id) ,
field("response", stringifiedError), field("message", error.message),
]); ]);
const failedMessage = new FailMessage(); const failedMessage = new Method.Fail();
failedMessage.setId(id); failedMessage.setId(id);
failedMessage.setResponse(stringifiedError); failedMessage.setResponse(argumentToProto(error));
const serverMessage = new ServerMessage(); const serverMessage = new ServerMessage();
serverMessage.setFail(failedMessage); 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 { private getProxy(proxyId: number | Module): ProxyData {
if (!this.proxies.has(proxyId)) { if (!this.proxies.has(proxyId)) {
throw new Error(`proxy ${proxyId} disposed too early`); throw new Error(`proxy ${proxyId} disposed too early`);

View File

@@ -6,7 +6,7 @@ import "vscode.proto";
message ClientMessage { message ClientMessage {
oneof msg { oneof msg {
// node.proto // node.proto
MethodMessage method = 20; Method method = 20;
Ping ping = 21; Ping ping = 21;
} }
} }
@@ -15,20 +15,20 @@ message ClientMessage {
message ServerMessage { message ServerMessage {
oneof msg { oneof msg {
// node.proto // node.proto
FailMessage fail = 13; Method.Fail fail = 13;
SuccessMessage success = 14; Method.Success success = 14;
EventMessage event = 19; Event event = 19;
CallbackMessage callback = 22; Callback callback = 22;
Pong pong = 18; Pong pong = 18;
WorkingInitMessage init = 16; WorkingInit init = 16;
// vscode.proto // vscode.proto
SharedProcessActiveMessage shared_process_active = 17; SharedProcessActive shared_process_active = 17;
} }
} }
message WorkingInitMessage { message WorkingInit {
string home_directory = 1; string home_directory = 1;
string tmp_directory = 2; string tmp_directory = 2;
string data_directory = 3; string data_directory = 3;
@@ -41,4 +41,5 @@ message WorkingInitMessage {
OperatingSystem operating_system = 5; OperatingSystem operating_system = 5;
string shell = 6; string shell = 6;
string builtin_extensions_dir = 7; string builtin_extensions_dir = 7;
string extensions_directory = 8;
} }

View File

@@ -8,8 +8,8 @@ import * as vscode_pb from "./vscode_pb";
export class ClientMessage extends jspb.Message { export class ClientMessage extends jspb.Message {
hasMethod(): boolean; hasMethod(): boolean;
clearMethod(): void; clearMethod(): void;
getMethod(): node_pb.MethodMessage | undefined; getMethod(): node_pb.Method | undefined;
setMethod(value?: node_pb.MethodMessage): void; setMethod(value?: node_pb.Method): void;
hasPing(): boolean; hasPing(): boolean;
clearPing(): void; clearPing(): void;
@@ -29,7 +29,7 @@ export class ClientMessage extends jspb.Message {
export namespace ClientMessage { export namespace ClientMessage {
export type AsObject = { export type AsObject = {
method?: node_pb.MethodMessage.AsObject, method?: node_pb.Method.AsObject,
ping?: node_pb.Ping.AsObject, ping?: node_pb.Ping.AsObject,
} }
@@ -43,23 +43,23 @@ export namespace ClientMessage {
export class ServerMessage extends jspb.Message { export class ServerMessage extends jspb.Message {
hasFail(): boolean; hasFail(): boolean;
clearFail(): void; clearFail(): void;
getFail(): node_pb.FailMessage | undefined; getFail(): node_pb.Method.Fail | undefined;
setFail(value?: node_pb.FailMessage): void; setFail(value?: node_pb.Method.Fail): void;
hasSuccess(): boolean; hasSuccess(): boolean;
clearSuccess(): void; clearSuccess(): void;
getSuccess(): node_pb.SuccessMessage | undefined; getSuccess(): node_pb.Method.Success | undefined;
setSuccess(value?: node_pb.SuccessMessage): void; setSuccess(value?: node_pb.Method.Success): void;
hasEvent(): boolean; hasEvent(): boolean;
clearEvent(): void; clearEvent(): void;
getEvent(): node_pb.EventMessage | undefined; getEvent(): node_pb.Event | undefined;
setEvent(value?: node_pb.EventMessage): void; setEvent(value?: node_pb.Event): void;
hasCallback(): boolean; hasCallback(): boolean;
clearCallback(): void; clearCallback(): void;
getCallback(): node_pb.CallbackMessage | undefined; getCallback(): node_pb.Callback | undefined;
setCallback(value?: node_pb.CallbackMessage): void; setCallback(value?: node_pb.Callback): void;
hasPong(): boolean; hasPong(): boolean;
clearPong(): void; clearPong(): void;
@@ -68,13 +68,13 @@ export class ServerMessage extends jspb.Message {
hasInit(): boolean; hasInit(): boolean;
clearInit(): void; clearInit(): void;
getInit(): WorkingInitMessage | undefined; getInit(): WorkingInit | undefined;
setInit(value?: WorkingInitMessage): void; setInit(value?: WorkingInit): void;
hasSharedProcessActive(): boolean; hasSharedProcessActive(): boolean;
clearSharedProcessActive(): void; clearSharedProcessActive(): void;
getSharedProcessActive(): vscode_pb.SharedProcessActiveMessage | undefined; getSharedProcessActive(): vscode_pb.SharedProcessActive | undefined;
setSharedProcessActive(value?: vscode_pb.SharedProcessActiveMessage): void; setSharedProcessActive(value?: vscode_pb.SharedProcessActive): void;
getMsgCase(): ServerMessage.MsgCase; getMsgCase(): ServerMessage.MsgCase;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
@@ -89,13 +89,13 @@ export class ServerMessage extends jspb.Message {
export namespace ServerMessage { export namespace ServerMessage {
export type AsObject = { export type AsObject = {
fail?: node_pb.FailMessage.AsObject, fail?: node_pb.Method.Fail.AsObject,
success?: node_pb.SuccessMessage.AsObject, success?: node_pb.Method.Success.AsObject,
event?: node_pb.EventMessage.AsObject, event?: node_pb.Event.AsObject,
callback?: node_pb.CallbackMessage.AsObject, callback?: node_pb.Callback.AsObject,
pong?: node_pb.Pong.AsObject, pong?: node_pb.Pong.AsObject,
init?: WorkingInitMessage.AsObject, init?: WorkingInit.AsObject,
sharedProcessActive?: vscode_pb.SharedProcessActiveMessage.AsObject, sharedProcessActive?: vscode_pb.SharedProcessActive.AsObject,
} }
export enum MsgCase { export enum MsgCase {
@@ -110,7 +110,7 @@ export namespace ServerMessage {
} }
} }
export class WorkingInitMessage extends jspb.Message { export class WorkingInit extends jspb.Message {
getHomeDirectory(): string; getHomeDirectory(): string;
setHomeDirectory(value: string): void; setHomeDirectory(value: string): void;
@@ -123,8 +123,8 @@ export class WorkingInitMessage extends jspb.Message {
getWorkingDirectory(): string; getWorkingDirectory(): string;
setWorkingDirectory(value: string): void; setWorkingDirectory(value: string): void;
getOperatingSystem(): WorkingInitMessage.OperatingSystem; getOperatingSystem(): WorkingInit.OperatingSystem;
setOperatingSystem(value: WorkingInitMessage.OperatingSystem): void; setOperatingSystem(value: WorkingInit.OperatingSystem): void;
getShell(): string; getShell(): string;
setShell(value: string): void; setShell(value: string): void;
@@ -132,25 +132,29 @@ export class WorkingInitMessage extends jspb.Message {
getBuiltinExtensionsDir(): string; getBuiltinExtensionsDir(): string;
setBuiltinExtensionsDir(value: string): void; setBuiltinExtensionsDir(value: string): void;
getExtensionsDirectory(): string;
setExtensionsDirectory(value: string): void;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): WorkingInitMessage.AsObject; toObject(includeInstance?: boolean): WorkingInit.AsObject;
static toObject(includeInstance: boolean, msg: WorkingInitMessage): WorkingInitMessage.AsObject; static toObject(includeInstance: boolean, msg: WorkingInit): WorkingInit.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: WorkingInitMessage, writer: jspb.BinaryWriter): void; static serializeBinaryToWriter(message: WorkingInit, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): WorkingInitMessage; static deserializeBinary(bytes: Uint8Array): WorkingInit;
static deserializeBinaryFromReader(message: WorkingInitMessage, reader: jspb.BinaryReader): WorkingInitMessage; static deserializeBinaryFromReader(message: WorkingInit, reader: jspb.BinaryReader): WorkingInit;
} }
export namespace WorkingInitMessage { export namespace WorkingInit {
export type AsObject = { export type AsObject = {
homeDirectory: string, homeDirectory: string,
tmpDirectory: string, tmpDirectory: string,
dataDirectory: string, dataDirectory: string,
workingDirectory: string, workingDirectory: string,
operatingSystem: WorkingInitMessage.OperatingSystem, operatingSystem: WorkingInit.OperatingSystem,
shell: string, shell: string,
builtinExtensionsDir: string, builtinExtensionsDir: string,
extensionsDirectory: string,
} }
export enum OperatingSystem { export enum OperatingSystem {

View File

@@ -12,12 +12,13 @@ var goog = jspb;
var global = Function('return this')(); var global = Function('return this')();
var node_pb = require('./node_pb.js'); var node_pb = require('./node_pb.js');
goog.object.extend(proto, node_pb);
var vscode_pb = require('./vscode_pb.js'); var vscode_pb = require('./vscode_pb.js');
goog.object.extend(proto, vscode_pb);
goog.exportSymbol('proto.ClientMessage', null, global); goog.exportSymbol('proto.ClientMessage', null, global);
goog.exportSymbol('proto.ServerMessage', null, global); goog.exportSymbol('proto.ServerMessage', null, global);
goog.exportSymbol('proto.WorkingInitMessage', null, global); goog.exportSymbol('proto.WorkingInit', null, global);
goog.exportSymbol('proto.WorkingInitMessage.OperatingSystem', null, global); goog.exportSymbol('proto.WorkingInit.OperatingSystem', null, global);
/** /**
* Generated by JsPbCodeGenerator. * Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a * @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); goog.inherits(proto.ClientMessage, jspb.Message);
if (goog.DEBUG && !COMPILED) { if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.ClientMessage.displayName = 'proto.ClientMessage'; 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 * Oneof group definitions for this message. Each group defines the field
* numbers belonging to that group. When of these fields' value is set, all * 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 * @suppress {unusedLocalVariables} f is only used for nested messages
*/ */
proto.ClientMessage.toObject = function(includeInstance, msg) { proto.ClientMessage.toObject = function(includeInstance, msg) {
var f, obj = { var obj = {
method: (f = msg.getMethod()) && node_pb.MethodMessage.toObject(includeInstance, f), method: (f = msg.getMethod()) && node_pb.Method.toObject(includeInstance, f),
ping: (f = msg.getPing()) && node_pb.Ping.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(); var field = reader.getFieldNumber();
switch (field) { switch (field) {
case 20: case 20:
var value = new node_pb.MethodMessage; var value = new node_pb.Method;
reader.readMessage(value,node_pb.MethodMessage.deserializeBinaryFromReader); reader.readMessage(value,node_pb.Method.deserializeBinaryFromReader);
msg.setMethod(value); msg.setMethod(value);
break; break;
case 21: case 21:
@@ -172,7 +220,7 @@ proto.ClientMessage.serializeBinaryToWriter = function(message, writer) {
writer.writeMessage( writer.writeMessage(
20, 20,
f, f,
node_pb.MethodMessage.serializeBinaryToWriter node_pb.Method.serializeBinaryToWriter
); );
} }
f = message.getPing(); f = message.getPing();
@@ -187,21 +235,24 @@ proto.ClientMessage.serializeBinaryToWriter = function(message, writer) {
/** /**
* optional MethodMessage method = 20; * optional Method method = 20;
* @return {?proto.MethodMessage} * @return {?proto.Method}
*/ */
proto.ClientMessage.prototype.getMethod = function() { proto.ClientMessage.prototype.getMethod = function() {
return /** @type{?proto.MethodMessage} */ ( return /** @type{?proto.Method} */ (
jspb.Message.getWrapperField(this, node_pb.MethodMessage, 20)); jspb.Message.getWrapperField(this, node_pb.Method, 20));
}; };
/** @param {?proto.MethodMessage|undefined} value */ /** @param {?proto.Method|undefined} value */
proto.ClientMessage.prototype.setMethod = function(value) { proto.ClientMessage.prototype.setMethod = function(value) {
jspb.Message.setOneofWrapperField(this, 20, proto.ClientMessage.oneofGroups_[0], value); jspb.Message.setOneofWrapperField(this, 20, proto.ClientMessage.oneofGroups_[0], value);
}; };
/**
* Clears the message field making it undefined.
*/
proto.ClientMessage.prototype.clearMethod = function() { proto.ClientMessage.prototype.clearMethod = function() {
this.setMethod(undefined); this.setMethod(undefined);
}; };
@@ -209,7 +260,7 @@ proto.ClientMessage.prototype.clearMethod = function() {
/** /**
* Returns whether this field is set. * Returns whether this field is set.
* @return {!boolean} * @return {boolean}
*/ */
proto.ClientMessage.prototype.hasMethod = function() { proto.ClientMessage.prototype.hasMethod = function() {
return jspb.Message.getField(this, 20) != null; 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() { proto.ClientMessage.prototype.clearPing = function() {
this.setPing(undefined); this.setPing(undefined);
}; };
@@ -239,7 +293,7 @@ proto.ClientMessage.prototype.clearPing = function() {
/** /**
* Returns whether this field is set. * Returns whether this field is set.
* @return {!boolean} * @return {boolean}
*/ */
proto.ClientMessage.prototype.hasPing = function() { proto.ClientMessage.prototype.hasPing = function() {
return jspb.Message.getField(this, 21) != null; 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 * Oneof group definitions for this message. Each group defines the field
* numbers belonging to that group. When of these fields' value is set, all * 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 * @suppress {unusedLocalVariables} f is only used for nested messages
*/ */
proto.ServerMessage.toObject = function(includeInstance, msg) { proto.ServerMessage.toObject = function(includeInstance, msg) {
var f, obj = { var obj = {
fail: (f = msg.getFail()) && node_pb.FailMessage.toObject(includeInstance, f), fail: (f = msg.getFail()) && node_pb.Method.Fail.toObject(includeInstance, f),
success: (f = msg.getSuccess()) && node_pb.SuccessMessage.toObject(includeInstance, f), success: (f = msg.getSuccess()) && node_pb.Method.Success.toObject(includeInstance, f),
event: (f = msg.getEvent()) && node_pb.EventMessage.toObject(includeInstance, f), event: (f = msg.getEvent()) && node_pb.Event.toObject(includeInstance, f),
callback: (f = msg.getCallback()) && node_pb.CallbackMessage.toObject(includeInstance, f), callback: (f = msg.getCallback()) && node_pb.Callback.toObject(includeInstance, f),
pong: (f = msg.getPong()) && node_pb.Pong.toObject(includeInstance, f), pong: (f = msg.getPong()) && node_pb.Pong.toObject(includeInstance, f),
init: (f = msg.getInit()) && proto.WorkingInitMessage.toObject(includeInstance, f), init: (f = msg.getInit()) && proto.WorkingInit.toObject(includeInstance, f),
sharedProcessActive: (f = msg.getSharedProcessActive()) && vscode_pb.SharedProcessActiveMessage.toObject(includeInstance, f) sharedProcessActive: (f = msg.getSharedProcessActive()) && vscode_pb.SharedProcessActive.toObject(includeInstance, f)
}; };
if (includeInstance) { if (includeInstance) {
@@ -368,23 +405,23 @@ proto.ServerMessage.deserializeBinaryFromReader = function(msg, reader) {
var field = reader.getFieldNumber(); var field = reader.getFieldNumber();
switch (field) { switch (field) {
case 13: case 13:
var value = new node_pb.FailMessage; var value = new node_pb.Method.Fail;
reader.readMessage(value,node_pb.FailMessage.deserializeBinaryFromReader); reader.readMessage(value,node_pb.Method.Fail.deserializeBinaryFromReader);
msg.setFail(value); msg.setFail(value);
break; break;
case 14: case 14:
var value = new node_pb.SuccessMessage; var value = new node_pb.Method.Success;
reader.readMessage(value,node_pb.SuccessMessage.deserializeBinaryFromReader); reader.readMessage(value,node_pb.Method.Success.deserializeBinaryFromReader);
msg.setSuccess(value); msg.setSuccess(value);
break; break;
case 19: case 19:
var value = new node_pb.EventMessage; var value = new node_pb.Event;
reader.readMessage(value,node_pb.EventMessage.deserializeBinaryFromReader); reader.readMessage(value,node_pb.Event.deserializeBinaryFromReader);
msg.setEvent(value); msg.setEvent(value);
break; break;
case 22: case 22:
var value = new node_pb.CallbackMessage; var value = new node_pb.Callback;
reader.readMessage(value,node_pb.CallbackMessage.deserializeBinaryFromReader); reader.readMessage(value,node_pb.Callback.deserializeBinaryFromReader);
msg.setCallback(value); msg.setCallback(value);
break; break;
case 18: case 18:
@@ -393,13 +430,13 @@ proto.ServerMessage.deserializeBinaryFromReader = function(msg, reader) {
msg.setPong(value); msg.setPong(value);
break; break;
case 16: case 16:
var value = new proto.WorkingInitMessage; var value = new proto.WorkingInit;
reader.readMessage(value,proto.WorkingInitMessage.deserializeBinaryFromReader); reader.readMessage(value,proto.WorkingInit.deserializeBinaryFromReader);
msg.setInit(value); msg.setInit(value);
break; break;
case 17: case 17:
var value = new vscode_pb.SharedProcessActiveMessage; var value = new vscode_pb.SharedProcessActive;
reader.readMessage(value,vscode_pb.SharedProcessActiveMessage.deserializeBinaryFromReader); reader.readMessage(value,vscode_pb.SharedProcessActive.deserializeBinaryFromReader);
msg.setSharedProcessActive(value); msg.setSharedProcessActive(value);
break; break;
default: default:
@@ -436,7 +473,7 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
writer.writeMessage( writer.writeMessage(
13, 13,
f, f,
node_pb.FailMessage.serializeBinaryToWriter node_pb.Method.Fail.serializeBinaryToWriter
); );
} }
f = message.getSuccess(); f = message.getSuccess();
@@ -444,7 +481,7 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
writer.writeMessage( writer.writeMessage(
14, 14,
f, f,
node_pb.SuccessMessage.serializeBinaryToWriter node_pb.Method.Success.serializeBinaryToWriter
); );
} }
f = message.getEvent(); f = message.getEvent();
@@ -452,7 +489,7 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
writer.writeMessage( writer.writeMessage(
19, 19,
f, f,
node_pb.EventMessage.serializeBinaryToWriter node_pb.Event.serializeBinaryToWriter
); );
} }
f = message.getCallback(); f = message.getCallback();
@@ -460,7 +497,7 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
writer.writeMessage( writer.writeMessage(
22, 22,
f, f,
node_pb.CallbackMessage.serializeBinaryToWriter node_pb.Callback.serializeBinaryToWriter
); );
} }
f = message.getPong(); f = message.getPong();
@@ -476,7 +513,7 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
writer.writeMessage( writer.writeMessage(
16, 16,
f, f,
proto.WorkingInitMessage.serializeBinaryToWriter proto.WorkingInit.serializeBinaryToWriter
); );
} }
f = message.getSharedProcessActive(); f = message.getSharedProcessActive();
@@ -484,28 +521,31 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
writer.writeMessage( writer.writeMessage(
17, 17,
f, f,
vscode_pb.SharedProcessActiveMessage.serializeBinaryToWriter vscode_pb.SharedProcessActive.serializeBinaryToWriter
); );
} }
}; };
/** /**
* optional FailMessage fail = 13; * optional Method.Fail fail = 13;
* @return {?proto.FailMessage} * @return {?proto.Method.Fail}
*/ */
proto.ServerMessage.prototype.getFail = function() { proto.ServerMessage.prototype.getFail = function() {
return /** @type{?proto.FailMessage} */ ( return /** @type{?proto.Method.Fail} */ (
jspb.Message.getWrapperField(this, node_pb.FailMessage, 13)); 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) { proto.ServerMessage.prototype.setFail = function(value) {
jspb.Message.setOneofWrapperField(this, 13, proto.ServerMessage.oneofGroups_[0], value); jspb.Message.setOneofWrapperField(this, 13, proto.ServerMessage.oneofGroups_[0], value);
}; };
/**
* Clears the message field making it undefined.
*/
proto.ServerMessage.prototype.clearFail = function() { proto.ServerMessage.prototype.clearFail = function() {
this.setFail(undefined); this.setFail(undefined);
}; };
@@ -513,7 +553,7 @@ proto.ServerMessage.prototype.clearFail = function() {
/** /**
* Returns whether this field is set. * Returns whether this field is set.
* @return {!boolean} * @return {boolean}
*/ */
proto.ServerMessage.prototype.hasFail = function() { proto.ServerMessage.prototype.hasFail = function() {
return jspb.Message.getField(this, 13) != null; return jspb.Message.getField(this, 13) != null;
@@ -521,21 +561,24 @@ proto.ServerMessage.prototype.hasFail = function() {
/** /**
* optional SuccessMessage success = 14; * optional Method.Success success = 14;
* @return {?proto.SuccessMessage} * @return {?proto.Method.Success}
*/ */
proto.ServerMessage.prototype.getSuccess = function() { proto.ServerMessage.prototype.getSuccess = function() {
return /** @type{?proto.SuccessMessage} */ ( return /** @type{?proto.Method.Success} */ (
jspb.Message.getWrapperField(this, node_pb.SuccessMessage, 14)); 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) { proto.ServerMessage.prototype.setSuccess = function(value) {
jspb.Message.setOneofWrapperField(this, 14, proto.ServerMessage.oneofGroups_[0], value); jspb.Message.setOneofWrapperField(this, 14, proto.ServerMessage.oneofGroups_[0], value);
}; };
/**
* Clears the message field making it undefined.
*/
proto.ServerMessage.prototype.clearSuccess = function() { proto.ServerMessage.prototype.clearSuccess = function() {
this.setSuccess(undefined); this.setSuccess(undefined);
}; };
@@ -543,7 +586,7 @@ proto.ServerMessage.prototype.clearSuccess = function() {
/** /**
* Returns whether this field is set. * Returns whether this field is set.
* @return {!boolean} * @return {boolean}
*/ */
proto.ServerMessage.prototype.hasSuccess = function() { proto.ServerMessage.prototype.hasSuccess = function() {
return jspb.Message.getField(this, 14) != null; return jspb.Message.getField(this, 14) != null;
@@ -551,21 +594,24 @@ proto.ServerMessage.prototype.hasSuccess = function() {
/** /**
* optional EventMessage event = 19; * optional Event event = 19;
* @return {?proto.EventMessage} * @return {?proto.Event}
*/ */
proto.ServerMessage.prototype.getEvent = function() { proto.ServerMessage.prototype.getEvent = function() {
return /** @type{?proto.EventMessage} */ ( return /** @type{?proto.Event} */ (
jspb.Message.getWrapperField(this, node_pb.EventMessage, 19)); jspb.Message.getWrapperField(this, node_pb.Event, 19));
}; };
/** @param {?proto.EventMessage|undefined} value */ /** @param {?proto.Event|undefined} value */
proto.ServerMessage.prototype.setEvent = function(value) { proto.ServerMessage.prototype.setEvent = function(value) {
jspb.Message.setOneofWrapperField(this, 19, proto.ServerMessage.oneofGroups_[0], value); jspb.Message.setOneofWrapperField(this, 19, proto.ServerMessage.oneofGroups_[0], value);
}; };
/**
* Clears the message field making it undefined.
*/
proto.ServerMessage.prototype.clearEvent = function() { proto.ServerMessage.prototype.clearEvent = function() {
this.setEvent(undefined); this.setEvent(undefined);
}; };
@@ -573,7 +619,7 @@ proto.ServerMessage.prototype.clearEvent = function() {
/** /**
* Returns whether this field is set. * Returns whether this field is set.
* @return {!boolean} * @return {boolean}
*/ */
proto.ServerMessage.prototype.hasEvent = function() { proto.ServerMessage.prototype.hasEvent = function() {
return jspb.Message.getField(this, 19) != null; return jspb.Message.getField(this, 19) != null;
@@ -581,21 +627,24 @@ proto.ServerMessage.prototype.hasEvent = function() {
/** /**
* optional CallbackMessage callback = 22; * optional Callback callback = 22;
* @return {?proto.CallbackMessage} * @return {?proto.Callback}
*/ */
proto.ServerMessage.prototype.getCallback = function() { proto.ServerMessage.prototype.getCallback = function() {
return /** @type{?proto.CallbackMessage} */ ( return /** @type{?proto.Callback} */ (
jspb.Message.getWrapperField(this, node_pb.CallbackMessage, 22)); jspb.Message.getWrapperField(this, node_pb.Callback, 22));
}; };
/** @param {?proto.CallbackMessage|undefined} value */ /** @param {?proto.Callback|undefined} value */
proto.ServerMessage.prototype.setCallback = function(value) { proto.ServerMessage.prototype.setCallback = function(value) {
jspb.Message.setOneofWrapperField(this, 22, proto.ServerMessage.oneofGroups_[0], value); jspb.Message.setOneofWrapperField(this, 22, proto.ServerMessage.oneofGroups_[0], value);
}; };
/**
* Clears the message field making it undefined.
*/
proto.ServerMessage.prototype.clearCallback = function() { proto.ServerMessage.prototype.clearCallback = function() {
this.setCallback(undefined); this.setCallback(undefined);
}; };
@@ -603,7 +652,7 @@ proto.ServerMessage.prototype.clearCallback = function() {
/** /**
* Returns whether this field is set. * Returns whether this field is set.
* @return {!boolean} * @return {boolean}
*/ */
proto.ServerMessage.prototype.hasCallback = function() { proto.ServerMessage.prototype.hasCallback = function() {
return jspb.Message.getField(this, 22) != null; 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() { proto.ServerMessage.prototype.clearPong = function() {
this.setPong(undefined); this.setPong(undefined);
}; };
@@ -633,7 +685,7 @@ proto.ServerMessage.prototype.clearPong = function() {
/** /**
* Returns whether this field is set. * Returns whether this field is set.
* @return {!boolean} * @return {boolean}
*/ */
proto.ServerMessage.prototype.hasPong = function() { proto.ServerMessage.prototype.hasPong = function() {
return jspb.Message.getField(this, 18) != null; return jspb.Message.getField(this, 18) != null;
@@ -641,21 +693,24 @@ proto.ServerMessage.prototype.hasPong = function() {
/** /**
* optional WorkingInitMessage init = 16; * optional WorkingInit init = 16;
* @return {?proto.WorkingInitMessage} * @return {?proto.WorkingInit}
*/ */
proto.ServerMessage.prototype.getInit = function() { proto.ServerMessage.prototype.getInit = function() {
return /** @type{?proto.WorkingInitMessage} */ ( return /** @type{?proto.WorkingInit} */ (
jspb.Message.getWrapperField(this, proto.WorkingInitMessage, 16)); jspb.Message.getWrapperField(this, proto.WorkingInit, 16));
}; };
/** @param {?proto.WorkingInitMessage|undefined} value */ /** @param {?proto.WorkingInit|undefined} value */
proto.ServerMessage.prototype.setInit = function(value) { proto.ServerMessage.prototype.setInit = function(value) {
jspb.Message.setOneofWrapperField(this, 16, proto.ServerMessage.oneofGroups_[0], value); jspb.Message.setOneofWrapperField(this, 16, proto.ServerMessage.oneofGroups_[0], value);
}; };
/**
* Clears the message field making it undefined.
*/
proto.ServerMessage.prototype.clearInit = function() { proto.ServerMessage.prototype.clearInit = function() {
this.setInit(undefined); this.setInit(undefined);
}; };
@@ -663,7 +718,7 @@ proto.ServerMessage.prototype.clearInit = function() {
/** /**
* Returns whether this field is set. * Returns whether this field is set.
* @return {!boolean} * @return {boolean}
*/ */
proto.ServerMessage.prototype.hasInit = function() { proto.ServerMessage.prototype.hasInit = function() {
return jspb.Message.getField(this, 16) != null; return jspb.Message.getField(this, 16) != null;
@@ -671,21 +726,24 @@ proto.ServerMessage.prototype.hasInit = function() {
/** /**
* optional SharedProcessActiveMessage shared_process_active = 17; * optional SharedProcessActive shared_process_active = 17;
* @return {?proto.SharedProcessActiveMessage} * @return {?proto.SharedProcessActive}
*/ */
proto.ServerMessage.prototype.getSharedProcessActive = function() { proto.ServerMessage.prototype.getSharedProcessActive = function() {
return /** @type{?proto.SharedProcessActiveMessage} */ ( return /** @type{?proto.SharedProcessActive} */ (
jspb.Message.getWrapperField(this, vscode_pb.SharedProcessActiveMessage, 17)); jspb.Message.getWrapperField(this, vscode_pb.SharedProcessActive, 17));
}; };
/** @param {?proto.SharedProcessActiveMessage|undefined} value */ /** @param {?proto.SharedProcessActive|undefined} value */
proto.ServerMessage.prototype.setSharedProcessActive = function(value) { proto.ServerMessage.prototype.setSharedProcessActive = function(value) {
jspb.Message.setOneofWrapperField(this, 17, proto.ServerMessage.oneofGroups_[0], value); jspb.Message.setOneofWrapperField(this, 17, proto.ServerMessage.oneofGroups_[0], value);
}; };
/**
* Clears the message field making it undefined.
*/
proto.ServerMessage.prototype.clearSharedProcessActive = function() { proto.ServerMessage.prototype.clearSharedProcessActive = function() {
this.setSharedProcessActive(undefined); this.setSharedProcessActive(undefined);
}; };
@@ -693,7 +751,7 @@ proto.ServerMessage.prototype.clearSharedProcessActive = function() {
/** /**
* Returns whether this field is set. * Returns whether this field is set.
* @return {!boolean} * @return {boolean}
*/ */
proto.ServerMessage.prototype.hasSharedProcessActive = function() { proto.ServerMessage.prototype.hasSharedProcessActive = function() {
return jspb.Message.getField(this, 17) != null; 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) { 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 * for transitional soy proto support: http://goto/soy-param-migration
* @return {!Object} * @return {!Object}
*/ */
proto.WorkingInitMessage.prototype.toObject = function(opt_includeInstance) { proto.WorkingInit.prototype.toObject = function(opt_includeInstance) {
return proto.WorkingInitMessage.toObject(opt_includeInstance, this); 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 * @param {boolean|undefined} includeInstance Whether to include the JSPB
* instance for transitional soy proto support: * instance for transitional soy proto support:
* http://goto/soy-param-migration * 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} * @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages * @suppress {unusedLocalVariables} f is only used for nested messages
*/ */
proto.WorkingInitMessage.toObject = function(includeInstance, msg) { proto.WorkingInit.toObject = function(includeInstance, msg) {
var f, obj = { var obj = {
homeDirectory: jspb.Message.getFieldWithDefault(msg, 1, ""), homeDirectory: jspb.Message.getFieldWithDefault(msg, 1, ""),
tmpDirectory: jspb.Message.getFieldWithDefault(msg, 2, ""), tmpDirectory: jspb.Message.getFieldWithDefault(msg, 2, ""),
dataDirectory: jspb.Message.getFieldWithDefault(msg, 3, ""), dataDirectory: jspb.Message.getFieldWithDefault(msg, 3, ""),
workingDirectory: jspb.Message.getFieldWithDefault(msg, 4, ""), workingDirectory: jspb.Message.getFieldWithDefault(msg, 4, ""),
operatingSystem: jspb.Message.getFieldWithDefault(msg, 5, 0), operatingSystem: jspb.Message.getFieldWithDefault(msg, 5, 0),
shell: jspb.Message.getFieldWithDefault(msg, 6, ""), 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) { if (includeInstance) {
@@ -767,23 +809,23 @@ proto.WorkingInitMessage.toObject = function(includeInstance, msg) {
/** /**
* Deserializes binary data (in protobuf wire format). * Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize. * @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 reader = new jspb.BinaryReader(bytes);
var msg = new proto.WorkingInitMessage; var msg = new proto.WorkingInit;
return proto.WorkingInitMessage.deserializeBinaryFromReader(msg, reader); return proto.WorkingInit.deserializeBinaryFromReader(msg, reader);
}; };
/** /**
* Deserializes binary data (in protobuf wire format) from the * Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object. * 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. * @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()) { while (reader.nextField()) {
if (reader.isEndGroup()) { if (reader.isEndGroup()) {
break; break;
@@ -807,7 +849,7 @@ proto.WorkingInitMessage.deserializeBinaryFromReader = function(msg, reader) {
msg.setWorkingDirectory(value); msg.setWorkingDirectory(value);
break; break;
case 5: case 5:
var value = /** @type {!proto.WorkingInitMessage.OperatingSystem} */ (reader.readEnum()); var value = /** @type {!proto.WorkingInit.OperatingSystem} */ (reader.readEnum());
msg.setOperatingSystem(value); msg.setOperatingSystem(value);
break; break;
case 6: case 6:
@@ -818,6 +860,10 @@ proto.WorkingInitMessage.deserializeBinaryFromReader = function(msg, reader) {
var value = /** @type {string} */ (reader.readString()); var value = /** @type {string} */ (reader.readString());
msg.setBuiltinExtensionsDir(value); msg.setBuiltinExtensionsDir(value);
break; break;
case 8:
var value = /** @type {string} */ (reader.readString());
msg.setExtensionsDirectory(value);
break;
default: default:
reader.skipField(); reader.skipField();
break; break;
@@ -831,9 +877,9 @@ proto.WorkingInitMessage.deserializeBinaryFromReader = function(msg, reader) {
* Serializes the message to binary data (in protobuf wire format). * Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array} * @return {!Uint8Array}
*/ */
proto.WorkingInitMessage.prototype.serializeBinary = function() { proto.WorkingInit.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter(); var writer = new jspb.BinaryWriter();
proto.WorkingInitMessage.serializeBinaryToWriter(this, writer); proto.WorkingInit.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer(); return writer.getResultBuffer();
}; };
@@ -841,11 +887,11 @@ proto.WorkingInitMessage.prototype.serializeBinary = function() {
/** /**
* Serializes the given message to binary data (in protobuf wire * Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter. * format), writing to the given BinaryWriter.
* @param {!proto.WorkingInitMessage} message * @param {!proto.WorkingInit} message
* @param {!jspb.BinaryWriter} writer * @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages * @suppress {unusedLocalVariables} f is only used for nested messages
*/ */
proto.WorkingInitMessage.serializeBinaryToWriter = function(message, writer) { proto.WorkingInit.serializeBinaryToWriter = function(message, writer) {
var f = undefined; var f = undefined;
f = message.getHomeDirectory(); f = message.getHomeDirectory();
if (f.length > 0) { if (f.length > 0) {
@@ -896,13 +942,20 @@ proto.WorkingInitMessage.serializeBinaryToWriter = function(message, writer) {
f f
); );
} }
f = message.getExtensionsDirectory();
if (f.length > 0) {
writer.writeString(
8,
f
);
}
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
proto.WorkingInitMessage.OperatingSystem = { proto.WorkingInit.OperatingSystem = {
WINDOWS: 0, WINDOWS: 0,
LINUX: 1, LINUX: 1,
MAC: 2 MAC: 2
@@ -912,13 +965,13 @@ proto.WorkingInitMessage.OperatingSystem = {
* optional string home_directory = 1; * optional string home_directory = 1;
* @return {string} * @return {string}
*/ */
proto.WorkingInitMessage.prototype.getHomeDirectory = function() { proto.WorkingInit.prototype.getHomeDirectory = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
}; };
/** @param {string} value */ /** @param {string} value */
proto.WorkingInitMessage.prototype.setHomeDirectory = function(value) { proto.WorkingInit.prototype.setHomeDirectory = function(value) {
jspb.Message.setProto3StringField(this, 1, value); jspb.Message.setProto3StringField(this, 1, value);
}; };
@@ -927,13 +980,13 @@ proto.WorkingInitMessage.prototype.setHomeDirectory = function(value) {
* optional string tmp_directory = 2; * optional string tmp_directory = 2;
* @return {string} * @return {string}
*/ */
proto.WorkingInitMessage.prototype.getTmpDirectory = function() { proto.WorkingInit.prototype.getTmpDirectory = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
}; };
/** @param {string} value */ /** @param {string} value */
proto.WorkingInitMessage.prototype.setTmpDirectory = function(value) { proto.WorkingInit.prototype.setTmpDirectory = function(value) {
jspb.Message.setProto3StringField(this, 2, value); jspb.Message.setProto3StringField(this, 2, value);
}; };
@@ -942,13 +995,13 @@ proto.WorkingInitMessage.prototype.setTmpDirectory = function(value) {
* optional string data_directory = 3; * optional string data_directory = 3;
* @return {string} * @return {string}
*/ */
proto.WorkingInitMessage.prototype.getDataDirectory = function() { proto.WorkingInit.prototype.getDataDirectory = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
}; };
/** @param {string} value */ /** @param {string} value */
proto.WorkingInitMessage.prototype.setDataDirectory = function(value) { proto.WorkingInit.prototype.setDataDirectory = function(value) {
jspb.Message.setProto3StringField(this, 3, value); jspb.Message.setProto3StringField(this, 3, value);
}; };
@@ -957,28 +1010,28 @@ proto.WorkingInitMessage.prototype.setDataDirectory = function(value) {
* optional string working_directory = 4; * optional string working_directory = 4;
* @return {string} * @return {string}
*/ */
proto.WorkingInitMessage.prototype.getWorkingDirectory = function() { proto.WorkingInit.prototype.getWorkingDirectory = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, "")); return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
}; };
/** @param {string} value */ /** @param {string} value */
proto.WorkingInitMessage.prototype.setWorkingDirectory = function(value) { proto.WorkingInit.prototype.setWorkingDirectory = function(value) {
jspb.Message.setProto3StringField(this, 4, value); jspb.Message.setProto3StringField(this, 4, value);
}; };
/** /**
* optional OperatingSystem operating_system = 5; * optional OperatingSystem operating_system = 5;
* @return {!proto.WorkingInitMessage.OperatingSystem} * @return {!proto.WorkingInit.OperatingSystem}
*/ */
proto.WorkingInitMessage.prototype.getOperatingSystem = function() { proto.WorkingInit.prototype.getOperatingSystem = function() {
return /** @type {!proto.WorkingInitMessage.OperatingSystem} */ (jspb.Message.getFieldWithDefault(this, 5, 0)); return /** @type {!proto.WorkingInit.OperatingSystem} */ (jspb.Message.getFieldWithDefault(this, 5, 0));
}; };
/** @param {!proto.WorkingInitMessage.OperatingSystem} value */ /** @param {!proto.WorkingInit.OperatingSystem} value */
proto.WorkingInitMessage.prototype.setOperatingSystem = function(value) { proto.WorkingInit.prototype.setOperatingSystem = function(value) {
jspb.Message.setProto3EnumField(this, 5, value); jspb.Message.setProto3EnumField(this, 5, value);
}; };
@@ -987,13 +1040,13 @@ proto.WorkingInitMessage.prototype.setOperatingSystem = function(value) {
* optional string shell = 6; * optional string shell = 6;
* @return {string} * @return {string}
*/ */
proto.WorkingInitMessage.prototype.getShell = function() { proto.WorkingInit.prototype.getShell = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 6, "")); return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 6, ""));
}; };
/** @param {string} value */ /** @param {string} value */
proto.WorkingInitMessage.prototype.setShell = function(value) { proto.WorkingInit.prototype.setShell = function(value) {
jspb.Message.setProto3StringField(this, 6, value); jspb.Message.setProto3StringField(this, 6, value);
}; };
@@ -1002,15 +1055,30 @@ proto.WorkingInitMessage.prototype.setShell = function(value) {
* optional string builtin_extensions_dir = 7; * optional string builtin_extensions_dir = 7;
* @return {string} * @return {string}
*/ */
proto.WorkingInitMessage.prototype.getBuiltinExtensionsDir = function() { proto.WorkingInit.prototype.getBuiltinExtensionsDir = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 7, "")); return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 7, ""));
}; };
/** @param {string} value */ /** @param {string} value */
proto.WorkingInitMessage.prototype.setBuiltinExtensionsDir = function(value) { proto.WorkingInit.prototype.setBuiltinExtensionsDir = function(value) {
jspb.Message.setProto3StringField(this, 7, 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); goog.object.extend(exports, proto);

View File

@@ -9,84 +9,133 @@ enum Module {
Trash = 5; Trash = 5;
} }
// A proxy identified by a unique name like "fs". message Argument {
message NamedProxyMessage { message ErrorValue {
uint64 id = 1; string message = 1;
Module module = 2; string stack = 2;
string method = 3; string code = 3;
repeated string args = 4; }
}
// A general proxy identified by an ID like WriteStream. message BufferValue {
message NumberedProxyMessage { bytes data = 1;
uint64 id = 1; }
uint64 proxy_id = 2;
string method = 3; message ObjectValue {
repeated string args = 4; 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. // 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 { oneof msg {
NamedProxyMessage named_proxy = 1; Method.Named named_proxy = 1;
NumberedProxyMessage numbered_proxy = 2; Method.Numbered numbered_proxy = 2;
} }
} }
// Call a remote callback. message Callback {
message CallbackMessage { // 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 { oneof msg {
NamedCallbackMessage named_callback = 1; Callback.Named named_callback = 1;
NumberedCallbackMessage numbered_callback = 2; Callback.Numbered numbered_callback = 2;
} }
} }
// A remote callback for uniquely named proxy. message Event {
message NamedCallbackMessage { // Emit an event on a uniquely named proxy.
Module module = 1; message Named {
uint64 callback_id = 2; Module module = 1;
repeated string args = 3; string event = 2;
} repeated Argument 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;
} }
}
// Emit an event on a uniquely named proxy. // Emit an event on a numbered proxy.
message NamedEventMessage { message Numbered {
Module module = 1; uint64 proxy_id = 1;
string event = 2; string event = 2;
repeated string args = 3; repeated Argument args = 3;
} }
// Emit an event on a numbered proxy. oneof msg {
message NumberedEventMessage { Event.Named named_event = 1;
uint64 proxy_id = 1; Event.Numbered numbered_event = 2;
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;
} }
message Ping {} message Ping {}

View File

@@ -3,100 +3,440 @@
import * as jspb from "google-protobuf"; import * as jspb from "google-protobuf";
export class NamedProxyMessage extends jspb.Message { export class Argument extends jspb.Message {
getId(): number; hasError(): boolean;
setId(value: number): void; clearError(): void;
getError(): Argument.ErrorValue | undefined;
setError(value?: Argument.ErrorValue): void;
getModule(): Module; hasBuffer(): boolean;
setModule(value: Module): void; clearBuffer(): void;
getBuffer(): Argument.BufferValue | undefined;
setBuffer(value?: Argument.BufferValue): void;
getMethod(): string; hasObject(): boolean;
setMethod(value: string): void; clearObject(): void;
getObject(): Argument.ObjectValue | undefined;
setObject(value?: Argument.ObjectValue): void;
clearArgsList(): void; hasArray(): boolean;
getArgsList(): Array<string>; clearArray(): void;
setArgsList(value: Array<string>): void; getArray(): Argument.ArrayValue | undefined;
addArgs(value: string, index?: number): string; 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; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): NamedProxyMessage.AsObject; toObject(includeInstance?: boolean): Argument.AsObject;
static toObject(includeInstance: boolean, msg: NamedProxyMessage): NamedProxyMessage.AsObject; static toObject(includeInstance: boolean, msg: Argument): Argument.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: NamedProxyMessage, writer: jspb.BinaryWriter): void; static serializeBinaryToWriter(message: Argument, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): NamedProxyMessage; static deserializeBinary(bytes: Uint8Array): Argument;
static deserializeBinaryFromReader(message: NamedProxyMessage, reader: jspb.BinaryReader): NamedProxyMessage; static deserializeBinaryFromReader(message: Argument, reader: jspb.BinaryReader): Argument;
} }
export namespace NamedProxyMessage { export namespace Argument {
export type AsObject = { export type AsObject = {
id: number, error?: Argument.ErrorValue.AsObject,
module: Module, buffer?: Argument.BufferValue.AsObject,
method: string, object?: Argument.ObjectValue.AsObject,
argsList: Array<string>, 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 { export class Method 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 {
hasNamedProxy(): boolean; hasNamedProxy(): boolean;
clearNamedProxy(): void; clearNamedProxy(): void;
getNamedProxy(): NamedProxyMessage | undefined; getNamedProxy(): Method.Named | undefined;
setNamedProxy(value?: NamedProxyMessage): void; setNamedProxy(value?: Method.Named): void;
hasNumberedProxy(): boolean; hasNumberedProxy(): boolean;
clearNumberedProxy(): void; clearNumberedProxy(): void;
getNumberedProxy(): NumberedProxyMessage | undefined; getNumberedProxy(): Method.Numbered | undefined;
setNumberedProxy(value?: NumberedProxyMessage): void; setNumberedProxy(value?: Method.Numbered): void;
getMsgCase(): MethodMessage.MsgCase; getMsgCase(): Method.MsgCase;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): MethodMessage.AsObject; toObject(includeInstance?: boolean): Method.AsObject;
static toObject(includeInstance: boolean, msg: MethodMessage): MethodMessage.AsObject; static toObject(includeInstance: boolean, msg: Method): Method.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: MethodMessage, writer: jspb.BinaryWriter): void; static serializeBinaryToWriter(message: Method, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): MethodMessage; static deserializeBinary(bytes: Uint8Array): Method;
static deserializeBinaryFromReader(message: MethodMessage, reader: jspb.BinaryReader): MethodMessage; static deserializeBinaryFromReader(message: Method, reader: jspb.BinaryReader): Method;
} }
export namespace MethodMessage { export namespace Method {
export type AsObject = { export type AsObject = {
namedProxy?: NamedProxyMessage.AsObject, namedProxy?: Method.Named.AsObject,
numberedProxy?: NumberedProxyMessage.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 { export enum MsgCase {
@@ -106,32 +446,92 @@ export namespace MethodMessage {
} }
} }
export class CallbackMessage extends jspb.Message { export class Callback extends jspb.Message {
hasNamedCallback(): boolean; hasNamedCallback(): boolean;
clearNamedCallback(): void; clearNamedCallback(): void;
getNamedCallback(): NamedCallbackMessage | undefined; getNamedCallback(): Callback.Named | undefined;
setNamedCallback(value?: NamedCallbackMessage): void; setNamedCallback(value?: Callback.Named): void;
hasNumberedCallback(): boolean; hasNumberedCallback(): boolean;
clearNumberedCallback(): void; clearNumberedCallback(): void;
getNumberedCallback(): NumberedCallbackMessage | undefined; getNumberedCallback(): Callback.Numbered | undefined;
setNumberedCallback(value?: NumberedCallbackMessage): void; setNumberedCallback(value?: Callback.Numbered): void;
getMsgCase(): CallbackMessage.MsgCase; getMsgCase(): Callback.MsgCase;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): CallbackMessage.AsObject; toObject(includeInstance?: boolean): Callback.AsObject;
static toObject(includeInstance: boolean, msg: CallbackMessage): CallbackMessage.AsObject; static toObject(includeInstance: boolean, msg: Callback): Callback.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: CallbackMessage, writer: jspb.BinaryWriter): void; static serializeBinaryToWriter(message: Callback, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): CallbackMessage; static deserializeBinary(bytes: Uint8Array): Callback;
static deserializeBinaryFromReader(message: CallbackMessage, reader: jspb.BinaryReader): CallbackMessage; static deserializeBinaryFromReader(message: Callback, reader: jspb.BinaryReader): Callback;
} }
export namespace CallbackMessage { export namespace Callback {
export type AsObject = { export type AsObject = {
namedCallback?: NamedCallbackMessage.AsObject, namedCallback?: Callback.Named.AsObject,
numberedCallback?: NumberedCallbackMessage.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 { export enum MsgCase {
@@ -141,92 +541,92 @@ export namespace CallbackMessage {
} }
} }
export class NamedCallbackMessage extends jspb.Message { export class Event 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 {
hasNamedEvent(): boolean; hasNamedEvent(): boolean;
clearNamedEvent(): void; clearNamedEvent(): void;
getNamedEvent(): NamedEventMessage | undefined; getNamedEvent(): Event.Named | undefined;
setNamedEvent(value?: NamedEventMessage): void; setNamedEvent(value?: Event.Named): void;
hasNumberedEvent(): boolean; hasNumberedEvent(): boolean;
clearNumberedEvent(): void; clearNumberedEvent(): void;
getNumberedEvent(): NumberedEventMessage | undefined; getNumberedEvent(): Event.Numbered | undefined;
setNumberedEvent(value?: NumberedEventMessage): void; setNumberedEvent(value?: Event.Numbered): void;
getMsgCase(): EventMessage.MsgCase; getMsgCase(): Event.MsgCase;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): EventMessage.AsObject; toObject(includeInstance?: boolean): Event.AsObject;
static toObject(includeInstance: boolean, msg: EventMessage): EventMessage.AsObject; static toObject(includeInstance: boolean, msg: Event): Event.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: EventMessage, writer: jspb.BinaryWriter): void; static serializeBinaryToWriter(message: Event, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): EventMessage; static deserializeBinary(bytes: Uint8Array): Event;
static deserializeBinaryFromReader(message: EventMessage, reader: jspb.BinaryReader): EventMessage; static deserializeBinaryFromReader(message: Event, reader: jspb.BinaryReader): Event;
} }
export namespace EventMessage { export namespace Event {
export type AsObject = { export type AsObject = {
namedEvent?: NamedEventMessage.AsObject, namedEvent?: Event.Named.AsObject,
numberedEvent?: NumberedEventMessage.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 { 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 { export class Ping extends jspb.Message {
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): Ping.AsObject; toObject(includeInstance?: boolean): Ping.AsObject;

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
syntax = "proto3"; syntax = "proto3";
// Sent when a shared process becomes active // Sent when a shared process becomes active
message SharedProcessActiveMessage { message SharedProcessActive {
string socket_path = 1; string socket_path = 1;
string log_path = 2; string log_path = 2;
} }

View File

@@ -3,7 +3,7 @@
import * as jspb from "google-protobuf"; import * as jspb from "google-protobuf";
export class SharedProcessActiveMessage extends jspb.Message { export class SharedProcessActive extends jspb.Message {
getSocketPath(): string; getSocketPath(): string;
setSocketPath(value: string): void; setSocketPath(value: string): void;
@@ -11,16 +11,16 @@ export class SharedProcessActiveMessage extends jspb.Message {
setLogPath(value: string): void; setLogPath(value: string): void;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): SharedProcessActiveMessage.AsObject; toObject(includeInstance?: boolean): SharedProcessActive.AsObject;
static toObject(includeInstance: boolean, msg: SharedProcessActiveMessage): SharedProcessActiveMessage.AsObject; static toObject(includeInstance: boolean, msg: SharedProcessActive): SharedProcessActive.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: SharedProcessActiveMessage, writer: jspb.BinaryWriter): void; static serializeBinaryToWriter(message: SharedProcessActive, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): SharedProcessActiveMessage; static deserializeBinary(bytes: Uint8Array): SharedProcessActive;
static deserializeBinaryFromReader(message: SharedProcessActiveMessage, reader: jspb.BinaryReader): SharedProcessActiveMessage; static deserializeBinaryFromReader(message: SharedProcessActive, reader: jspb.BinaryReader): SharedProcessActive;
} }
export namespace SharedProcessActiveMessage { export namespace SharedProcessActive {
export type AsObject = { export type AsObject = {
socketPath: string, socketPath: string,
logPath: string, logPath: string,

View File

@@ -11,8 +11,7 @@ var jspb = require('google-protobuf');
var goog = jspb; var goog = jspb;
var global = Function('return this')(); var global = Function('return this')();
goog.exportSymbol('proto.SharedProcessActiveMessage', null, global); goog.exportSymbol('proto.SharedProcessActive', null, global);
/** /**
* Generated by JsPbCodeGenerator. * Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a * @param {Array=} opt_data Optional initial data array, typically from a
@@ -23,15 +22,20 @@ goog.exportSymbol('proto.SharedProcessActiveMessage', null, global);
* @extends {jspb.Message} * @extends {jspb.Message}
* @constructor * @constructor
*/ */
proto.SharedProcessActiveMessage = function(opt_data) { proto.SharedProcessActive = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null); 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) { if (goog.DEBUG && !COMPILED) {
proto.SharedProcessActiveMessage.displayName = 'proto.SharedProcessActiveMessage'; /**
* @public
* @override
*/
proto.SharedProcessActive.displayName = 'proto.SharedProcessActive';
} }
if (jspb.Message.GENERATE_TO_OBJECT) { if (jspb.Message.GENERATE_TO_OBJECT) {
/** /**
* Creates an object representation of this proto suitable for use in Soy templates. * 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 * for transitional soy proto support: http://goto/soy-param-migration
* @return {!Object} * @return {!Object}
*/ */
proto.SharedProcessActiveMessage.prototype.toObject = function(opt_includeInstance) { proto.SharedProcessActive.prototype.toObject = function(opt_includeInstance) {
return proto.SharedProcessActiveMessage.toObject(opt_includeInstance, this); 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 * @param {boolean|undefined} includeInstance Whether to include the JSPB
* instance for transitional soy proto support: * instance for transitional soy proto support:
* http://goto/soy-param-migration * 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} * @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages * @suppress {unusedLocalVariables} f is only used for nested messages
*/ */
proto.SharedProcessActiveMessage.toObject = function(includeInstance, msg) { proto.SharedProcessActive.toObject = function(includeInstance, msg) {
var f, obj = { var obj = {
socketPath: jspb.Message.getFieldWithDefault(msg, 1, ""), socketPath: jspb.Message.getFieldWithDefault(msg, 1, ""),
logPath: jspb.Message.getFieldWithDefault(msg, 2, "") logPath: jspb.Message.getFieldWithDefault(msg, 2, "")
}; };
@@ -74,23 +78,23 @@ proto.SharedProcessActiveMessage.toObject = function(includeInstance, msg) {
/** /**
* Deserializes binary data (in protobuf wire format). * Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize. * @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 reader = new jspb.BinaryReader(bytes);
var msg = new proto.SharedProcessActiveMessage; var msg = new proto.SharedProcessActive;
return proto.SharedProcessActiveMessage.deserializeBinaryFromReader(msg, reader); return proto.SharedProcessActive.deserializeBinaryFromReader(msg, reader);
}; };
/** /**
* Deserializes binary data (in protobuf wire format) from the * Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object. * 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. * @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()) { while (reader.nextField()) {
if (reader.isEndGroup()) { if (reader.isEndGroup()) {
break; break;
@@ -118,9 +122,9 @@ proto.SharedProcessActiveMessage.deserializeBinaryFromReader = function(msg, rea
* Serializes the message to binary data (in protobuf wire format). * Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array} * @return {!Uint8Array}
*/ */
proto.SharedProcessActiveMessage.prototype.serializeBinary = function() { proto.SharedProcessActive.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter(); var writer = new jspb.BinaryWriter();
proto.SharedProcessActiveMessage.serializeBinaryToWriter(this, writer); proto.SharedProcessActive.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer(); return writer.getResultBuffer();
}; };
@@ -128,11 +132,11 @@ proto.SharedProcessActiveMessage.prototype.serializeBinary = function() {
/** /**
* Serializes the given message to binary data (in protobuf wire * Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter. * format), writing to the given BinaryWriter.
* @param {!proto.SharedProcessActiveMessage} message * @param {!proto.SharedProcessActive} message
* @param {!jspb.BinaryWriter} writer * @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages * @suppress {unusedLocalVariables} f is only used for nested messages
*/ */
proto.SharedProcessActiveMessage.serializeBinaryToWriter = function(message, writer) { proto.SharedProcessActive.serializeBinaryToWriter = function(message, writer) {
var f = undefined; var f = undefined;
f = message.getSocketPath(); f = message.getSocketPath();
if (f.length > 0) { if (f.length > 0) {
@@ -155,13 +159,13 @@ proto.SharedProcessActiveMessage.serializeBinaryToWriter = function(message, wri
* optional string socket_path = 1; * optional string socket_path = 1;
* @return {string} * @return {string}
*/ */
proto.SharedProcessActiveMessage.prototype.getSocketPath = function() { proto.SharedProcessActive.prototype.getSocketPath = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
}; };
/** @param {string} value */ /** @param {string} value */
proto.SharedProcessActiveMessage.prototype.setSocketPath = function(value) { proto.SharedProcessActive.prototype.setSocketPath = function(value) {
jspb.Message.setProto3StringField(this, 1, value); jspb.Message.setProto3StringField(this, 1, value);
}; };
@@ -170,13 +174,13 @@ proto.SharedProcessActiveMessage.prototype.setSocketPath = function(value) {
* optional string log_path = 2; * optional string log_path = 2;
* @return {string} * @return {string}
*/ */
proto.SharedProcessActiveMessage.prototype.getLogPath = function() { proto.SharedProcessActive.prototype.getLogPath = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
}; };
/** @param {string} value */ /** @param {string} value */
proto.SharedProcessActiveMessage.prototype.setLogPath = function(value) { proto.SharedProcessActive.prototype.setLogPath = function(value) {
jspb.Message.setProto3StringField(this, 2, value); jspb.Message.setProto3StringField(this, 2, value);
}; };

View File

@@ -10,7 +10,7 @@ describe("child_process", () => {
const cp = client.modules[Module.ChildProcess]; const cp = client.modules[Module.ChildProcess];
const getStdout = async (proc: ChildProcess): Promise<string> => { 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()); .then((s) => s.toString());
}; };
@@ -36,10 +36,10 @@ describe("child_process", () => {
it("should cat", async () => { it("should cat", async () => {
const proc = cp.spawn("cat", []); const proc = cp.spawn("cat", []);
expect(proc.pid).toBe(-1); expect(proc.pid).toBe(-1);
proc.stdin.write("banana"); proc.stdin!.write("banana");
await expect(getStdout(proc)).resolves.toBe("banana"); await expect(getStdout(proc)).resolves.toBe("banana");
proc.stdin.end(); proc.stdin!.end();
proc.kill(); proc.kill();
expect(proc.pid).toBeGreaterThan(-1); expect(proc.pid).toBeGreaterThan(-1);
@@ -53,6 +53,11 @@ describe("child_process", () => {
await expect(getStdout(proc)).resolves.toContain("hi=donkey\n"); 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", () => { describe("fork", () => {

View File

@@ -4,6 +4,8 @@ import * as util from "util";
import { Module } from "../src/common/proxy"; import { Module } from "../src/common/proxy";
import { createClient, Helper } from "./helpers"; import { createClient, Helper } from "./helpers";
// tslint:disable deprecation to use fs.exists
describe("fs", () => { describe("fs", () => {
const client = createClient(); const client = createClient();
// tslint:disable-next-line no-any // tslint:disable-next-line no-any
@@ -242,6 +244,14 @@ describe("fs", () => {
await util.promisify(nativeFs.close)(fd); 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 () => { it("should fail to futimes nonexistent file", async () => {
await expect(util.promisify(fs.futimes)(99999, 9999, 9999)) await expect(util.promisify(fs.futimes)(99999, 9999, 9999))
.rejects.toThrow("EBADF"); .rejects.toThrow("EBADF");
@@ -346,7 +356,7 @@ describe("fs", () => {
it("should read existing file", async () => { it("should read existing file", async () => {
const fd = await util.promisify(nativeFs.open)(__filename, "r"); const fd = await util.promisify(nativeFs.open)(__filename, "r");
const stat = await util.promisify(nativeFs.fstat)(fd); const stat = await util.promisify(nativeFs.fstat)(fd);
const buffer = new Buffer(stat.size); const buffer = Buffer.alloc(stat.size);
let bytesRead = 0; let bytesRead = 0;
let chunkSize = 2048; let chunkSize = 2048;
while (bytesRead < stat.size) { while (bytesRead < stat.size) {
@@ -364,7 +374,7 @@ describe("fs", () => {
}); });
it("should fail to read nonexistent file", async () => { 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"); .rejects.toThrow("EBADF");
}); });
}); });
@@ -466,6 +476,7 @@ describe("fs", () => {
expect(stat).toMatchObject({ expect(stat).toMatchObject({
size: nativeStat.size, size: nativeStat.size,
}); });
expect(typeof stat.mtime.getTime()).toBe("number");
expect(stat.isFile()).toBe(true); expect(stat.isFile()).toBe(true);
}); });
@@ -493,7 +504,7 @@ describe("fs", () => {
const destination = helper.tmpFile(); const destination = helper.tmpFile();
await expect(util.promisify(fs.symlink)(source, destination)) await expect(util.promisify(fs.symlink)(source, destination))
.resolves.toBeUndefined(); .resolves.toBeUndefined();
expect(util.promisify(nativeFs.exists)(source)) await expect(util.promisify(nativeFs.exists)(source))
.resolves.toBe(true); .resolves.toBe(true);
}); });
@@ -525,7 +536,7 @@ describe("fs", () => {
const file = await helper.createTmpFile(); const file = await helper.createTmpFile();
await expect(util.promisify(fs.unlink)(file)) await expect(util.promisify(fs.unlink)(file))
.resolves.toBeUndefined(); .resolves.toBeUndefined();
expect(util.promisify(nativeFs.exists)(file)) await expect(util.promisify(nativeFs.exists)(file))
.resolves.toBe(false); .resolves.toBe(false);
}); });

View File

@@ -38,6 +38,23 @@ describe("net", () => {
expect(fn).toHaveBeenCalledTimes(1); 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 () => { it("should connect", async () => {
await new Promise((resolve): void => { await new Promise((resolve): void => {
const socket = net.createConnection(socketPath, () => { const socket = net.createConnection(socketPath, () => {

View File

@@ -12,12 +12,10 @@ describe("Server", () => {
workingDirectory, workingDirectory,
}); });
it("should get init msg", (done) => { it("should get init msg", async () => {
client.initData.then((data) => { const data = await client.initData;
expect(data.dataDirectory).toEqual(dataDirectory); expect(data.dataDirectory).toEqual(dataDirectory);
expect(data.workingDirectory).toEqual(workingDirectory); expect(data.workingDirectory).toEqual(workingDirectory);
expect(data.builtInExtensionsDirectory).toEqual(builtInExtensionsDirectory); expect(data.builtInExtensionsDirectory).toEqual(builtInExtensionsDirectory);
done();
});
}); });
}); });

View 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);
});
});

View File

@@ -64,29 +64,6 @@ accepts@~1.3.5:
mime-types "~2.1.18" mime-types "~2.1.18"
negotiator "0.6.1" 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: array-flatten@1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 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" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 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: body-parser@1.18.3:
version "1.18.3" version "1.18.3"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" 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" balanced-match "^1.0.0"
concat-map "0.0.1" 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: bytes@3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= 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: concat-map@0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 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: content-disposition@0.5.2:
version "0.5.2" version "0.5.2"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 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" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= 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: cross-spawn-async@^2.1.1:
version "2.2.5" version "2.2.5"
resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc" 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: dependencies:
ms "2.0.0" 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: depd@~1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 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" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 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: dir-glob@^2.0.0:
version "2.2.2" version "2.2.2"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" 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" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 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: escape-html@~1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 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" path-key "^1.0.0"
strip-eof "^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: express@^4.16.4:
version "4.16.4" version "4.16.4"
resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" 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" utils-merge "1.0.1"
vary "~1.1.2" 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: finalhandler@1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" 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" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 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: fs-extra@^0.30.0:
version "0.30.0" version "0.30.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" 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" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 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: get-stream@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= 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: glob@^7.1.2, glob@^7.1.3:
version "7.1.3" version "7.1.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" 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" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== 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: http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
version "1.6.3" version "1.6.3"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" 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" once "^1.3.0"
wrappy "1" wrappy "1"
inherits@2, inherits@2.0.3, inherits@~2.0.3: inherits@2, inherits@2.0.3:
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 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: ipaddr.js@1.8.0:
version "1.8.0" version "1.8.0"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e"
integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= 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: is-stream@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= 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: isexe@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 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" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== 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: minimatch@^3.0.4:
version "3.0.4" version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@@ -633,23 +462,6 @@ minimatch@^3.0.4:
dependencies: dependencies:
brace-expansion "^1.1.7" 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: mount-point@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/mount-point/-/mount-point-3.0.0.tgz#665cb9edebe80d110e658db56c31d0aef51a8f97" 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" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 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: negotiator@0.6.1:
version "0.6.1" version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" 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" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== 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: npm-run-path@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-1.0.0.tgz#f5c32bf595fe81ae927daec52e82f8b000ac3c8f" 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: dependencies:
path-key "^2.0.0" path-key "^2.0.0"
npmlog@^4.0.1: object-assign@^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:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
@@ -750,14 +512,14 @@ on-finished@~2.3.0:
dependencies: dependencies:
ee-first "1.1.1" 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" version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies: dependencies:
wrappy "1" wrappy "1"
os-homedir@^1.0.0, os-homedir@^1.0.1: os-homedir@^1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
@@ -831,33 +593,6 @@ pinkie@^2.0.0:
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= 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: proxy-addr@~2.0.4:
version "2.0.4" version "2.0.4"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" 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" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= 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: qs@6.5.2:
version "6.5.2" version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" 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" iconv-lite "0.4.23"
unpipe "1.0.0" 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: rimraf@^2.2.8, rimraf@^2.6.3:
version "2.6.3" version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
@@ -944,7 +640,7 @@ run-applescript@^3.0.0:
dependencies: dependencies:
execa "^0.10.0" 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" version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 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" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
semver@^5.4.1, semver@^5.5.0: semver@^5.5.0:
version "5.6.0" version "5.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
@@ -988,11 +684,6 @@ serve-static@1.13.2:
parseurl "~1.3.2" parseurl "~1.3.2"
send "0.16.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: setprototypeof@1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" 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" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= 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: slash@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= 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": "statuses@>= 1.4.0 < 2":
version "1.5.0" version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 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" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== 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: strip-eof@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= 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: text-encoding@^0.7.0:
version "0.7.0" version "0.7.0"
resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.7.0.tgz#f895e836e45990624086601798ea98e8f36ee643" resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.7.0.tgz#f895e836e45990624086601798ea98e8f36ee643"
integrity sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA== 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: trash@^4.3.0:
version "4.3.0" version "4.3.0"
resolved "https://registry.yarnpkg.com/trash/-/trash-4.3.0.tgz#6ebeecdea4d666b06e389b47d135ea88e1de5075" resolved "https://registry.yarnpkg.com/trash/-/trash-4.3.0.tgz#6ebeecdea4d666b06e389b47d135ea88e1de5075"
@@ -1156,13 +753,6 @@ ts-protoc-gen@^0.8.0:
dependencies: dependencies:
google-protobuf "^3.6.1" 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: type-is@~1.6.16:
version "1.6.16" version "1.6.16"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194"
@@ -1183,11 +773,6 @@ user-home@^2.0.0:
dependencies: dependencies:
os-homedir "^1.0.0" 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: utils-merge@1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 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" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 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: which@^1.2.8, which@^1.2.9:
version "1.3.1" version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 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: dependencies:
isexe "^2.0.0" 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: wrappy@1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 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" user-home "^2.0.0"
xdg-basedir "^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: yallist@^2.1.2:
version "2.1.2" version "2.1.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"

View File

@@ -9,7 +9,7 @@
"build:binary": "ts-node scripts/nbin.ts" "build:binary": "ts-node scripts/nbin.ts"
}, },
"dependencies": { "dependencies": {
"@coder/nbin": "^1.0.4", "@coder/nbin": "^1.1.2",
"commander": "^2.19.0", "commander": "^2.19.0",
"express": "^4.16.4", "express": "^4.16.4",
"express-static-gzip": "^1.1.3", "express-static-gzip": "^1.1.3",

View File

@@ -10,6 +10,16 @@ const bin = new Binary({
}); });
bin.writeFiles(path.join(rootDir, "build", "**")); bin.writeFiles(path.join(rootDir, "build", "**"));
bin.writeFiles(path.join(rootDir, "out", "**")); 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) => { bin.build().then((binaryData) => {
const outputPath = path.join(__dirname, "..", `cli-${target}`); const outputPath = path.join(__dirname, "..", `cli-${target}`);
fs.writeFileSync(outputPath, binaryData); fs.writeFileSync(outputPath, binaryData);

View File

@@ -1,6 +1,6 @@
import { field, logger } from "@coder/logger"; import { field, logger } from "@coder/logger";
import { ServerMessage, SharedProcessActiveMessage } from "@coder/protocol/src/proto"; import { ServerMessage, SharedProcessActive } from "@coder/protocol/src/proto";
import { ChildProcess, fork, ForkOptions, spawn } from "child_process"; import { ChildProcess, fork, ForkOptions } from "child_process";
import { randomFillSync } from "crypto"; import { randomFillSync } from "crypto";
import * as fs from "fs"; import * as fs from "fs";
import * as fse from "fs-extra"; import * as fse from "fs-extra";
@@ -8,9 +8,8 @@ import * as os from "os";
import * as path from "path"; import * as path from "path";
import * as WebSocket from "ws"; import * as WebSocket from "ws";
import { buildDir, cacheHome, dataHome, isCli, serveStatic } from "./constants"; import { buildDir, cacheHome, dataHome, isCli, serveStatic } from "./constants";
import { setup as setupNativeModules } from "./modules";
import { createApp } from "./server"; import { createApp } from "./server";
import { forkModule, requireFork, requireModule } from "./vscode/bootstrapFork"; import { forkModule, requireModule } from "./vscode/bootstrapFork";
import { SharedProcess, SharedProcessState } from "./vscode/sharedProcess"; import { SharedProcess, SharedProcessState } from "./vscode/sharedProcess";
import opn = require("opn"); import opn = require("opn");
@@ -19,17 +18,21 @@ import * as commander from "commander";
commander.version(process.env.VERSION || "development") commander.version(process.env.VERSION || "development")
.name("code-server") .name("code-server")
.description("Run VS Code on a remote server.") .description("Run VS Code on a remote server.")
.option("--cert") .option("--cert <value>")
.option("--cert-key") .option("--cert-key <value>")
.option("-d, --data-dir <value>", "Customize where user-data is stored.") .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("-h, --host <value>", "Customize the hostname.", "0.0.0.0")
.option("-o, --open", "Open in the browser on startup.", false) .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("-N, --no-auth", "Start without requiring authentication.", undefined)
.option("-H, --allow-http", "Allow http connections.", false) .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("--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.") .option("--extra-args <args>", "Used for development. Never set.")
.arguments("Specify working directory.") .arguments("Specify working directory.")
.parse(process.argv); .parse(process.argv);
@@ -37,7 +40,12 @@ commander.version(process.env.VERSION || "development")
Error.stackTraceLimit = Infinity; Error.stackTraceLimit = Infinity;
if (isCli) { if (isCli) {
require("nbin").shimNativeFs(buildDir); 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> => { (async (): Promise<void> => {
const args = commander.args; const args = commander.args;
@@ -46,25 +54,37 @@ if (isCli) {
readonly allowHttp: boolean; readonly allowHttp: boolean;
readonly host: string; readonly host: string;
readonly port: number; readonly port: number;
readonly disableTelemetry: boolean;
readonly userDataDir?: string;
readonly extensionsDir?: string;
readonly dataDir?: string; readonly dataDir?: string;
readonly password?: string; readonly password?: string;
readonly open?: boolean; readonly open?: boolean;
readonly cert?: string; readonly cert?: string;
readonly certKey?: string; readonly certKey?: string;
readonly socket?: string;
readonly installExtension?: string;
readonly bootstrapFork?: string; readonly bootstrapFork?: string;
readonly fork?: string;
readonly extraArgs?: string; readonly extraArgs?: string;
}; };
if (options.disableTelemetry) {
process.env.DISABLE_TELEMETRY = "true";
}
// Commander has an exception for `--no` prefixes. Here we'll adjust that. // Commander has an exception for `--no` prefixes. Here we'll adjust that.
// tslint:disable-next-line:no-any // tslint:disable-next-line:no-any
const noAuthValue = (commander as any).auth; const noAuthValue = (commander as any).auth;
options.noAuth = !noAuthValue; 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 workingDir = path.resolve(args[0] || process.cwd());
const dependenciesDir = path.join(os.tmpdir(), "code-server/dependencies");
if (!fs.existsSync(dataDir)) { if (!fs.existsSync(dataDir)) {
const oldDataDir = path.resolve(path.join(os.homedir(), ".code-server")); const oldDataDir = path.resolve(path.join(os.homedir(), ".code-server"));
@@ -77,10 +97,24 @@ if (isCli) {
await Promise.all([ await Promise.all([
fse.mkdirp(cacheHome), fse.mkdirp(cacheHome),
fse.mkdirp(dataDir), fse.mkdirp(dataDir),
fse.mkdirp(extensionsDir),
fse.mkdirp(workingDir), 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"); const builtInExtensionsDir = path.resolve(buildDir || path.join(__dirname, ".."), "build/extensions");
if (options.bootstrapFork) { if (options.bootstrapFork) {
const modulePath = options.bootstrapFork; const modulePath = options.bootstrapFork;
@@ -89,19 +123,13 @@ if (isCli) {
process.exit(1); process.exit(1);
} }
((options.extraArgs ? JSON.parse(options.extraArgs) : []) as string[]).forEach((arg, i) => { process.argv = [
// [0] contains the binary running the script (`node` for example) and process.argv[0],
// [1] contains the script name, so the arguments come after that. process.argv[1],
process.argv[i + 2] = arg; ...(options.extraArgs ? JSON.parse(options.extraArgs) : []),
}); ];
return requireModule(modulePath, dataDir, builtInExtensionsDir); return requireModule(modulePath, builtInExtensionsDir);
}
if (options.fork) {
const modulePath = options.fork;
return requireFork(modulePath, JSON.parse(options.extraArgs!), builtInExtensionsDir);
} }
const logDir = path.join(cacheHome, "code-server/logs", new Date().toISOString().replace(/[-:.TZ]/g, "")); 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"}`); 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 // TODO: fill in appropriate doc url
logger.info("Additional documentation: http://github.com/codercom/code-server"); 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)); logger.info("Initializing", field("data-dir", dataDir), field("extensions-dir", extensionsDir), field("working-dir", workingDir), field("log-dir", logDir));
const sharedProcess = new SharedProcess(dataDir, builtInExtensionsDir); const sharedProcess = new SharedProcess(dataDir, extensionsDir, builtInExtensionsDir);
const sendSharedProcessReady = (socket: WebSocket): void => { const sendSharedProcessReady = (socket: WebSocket): void => {
const active = new SharedProcessActiveMessage(); const active = new SharedProcessActive();
active.setSocketPath(sharedProcess.socketPath); active.setSocketPath(sharedProcess.socketPath);
active.setLogPath(logDir); active.setLogPath(logDir);
const serverMessage = new ServerMessage(); 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) { if (!password) {
// Generate a random password with a length of 24. // Generate a random password with a length of 24.
const buffer = Buffer.alloc(12); const buffer = Buffer.alloc(12);
@@ -171,20 +228,19 @@ if (isCli) {
allowHttp: options.allowHttp, allowHttp: options.allowHttp,
bypassAuth: options.noAuth, bypassAuth: options.noAuth,
registerMiddleware: (app): void => { 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 // 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. // pre-built version, use webpack to serve the web files.
if (!isCli && !serveStatic) { if (!isCli && !serveStatic) {
const webpackConfig = require(path.resolve(__dirname, "..", "..", "web", "webpack.config.js")); const webpackConfig = require(path.resolve(__dirname, "..", "..", "web", "webpack.config.js"));
const compiler = require("webpack")(webpackConfig); const compiler = require("webpack")(webpackConfig);
app.use(require("webpack-dev-middleware")(compiler, { 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, publicPath: webpackConfig.output.publicPath,
stats: webpackConfig.stats, stats: webpackConfig.stats,
})); }));
@@ -192,6 +248,7 @@ if (isCli) {
} }
}, },
serverOptions: { serverOptions: {
extensionsDirectory: extensionsDir,
builtInExtensionsDirectory: builtInExtensionsDir, builtInExtensionsDirectory: builtInExtensionsDir,
dataDirectory: dataDir, dataDirectory: dataDir,
workingDirectory: workingDir, workingDirectory: workingDir,
@@ -201,14 +258,7 @@ if (isCli) {
return forkModule(options.env.AMD_ENTRYPOINT, args, options, dataDir); return forkModule(options.env.AMD_ENTRYPOINT, args, options, dataDir);
} }
if (isCli) { return fork(modulePath, args, options);
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);
}
}, },
}, },
password, password,
@@ -219,7 +269,11 @@ if (isCli) {
}); });
logger.info("Starting webserver...", field("host", options.host), field("port", options.port)); 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; let clientId = 1;
app.wss.on("connection", (ws, req) => { app.wss.on("connection", (ws, req) => {
const id = clientId++; const id = clientId++;
@@ -234,11 +288,20 @@ if (isCli) {
logger.info(`WebSocket closed \u001B[0m${req.url}`, field("client", id), field("code", code)); 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) { if (!options.certKey && !options.cert) {
logger.warn("No certificate specified. \u001B[1mThis could be insecure."); logger.warn("No certificate specified. \u001B[1mThis could be insecure.");
// TODO: fill in appropriate doc url // 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) { if (!options.noAuth) {

View File

@@ -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");
};

View File

@@ -17,7 +17,7 @@ export interface PortScanner {
* Will scan local ports and emit events when ports are added or removed. * Will scan local ports and emit events when ports are added or removed.
* Currently only scans TCP ports. * 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 ports = new Map<number, number>();
const addEmitter = new Emitter<number[]>(); const addEmitter = new Emitter<number[]>();
@@ -76,9 +76,14 @@ export const createPortScanner = (scanInterval: number = 250): PortScanner => {
let disposed: boolean = false; let disposed: boolean = false;
const doInterval = (): void => { const doInterval = (): void => {
logger.trace("scanning ports");
scan((error) => { scan((error) => {
if (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; disposed = true;
} else if (!disposed) { } else if (!disposed) {
lastTimeout = setTimeout(doInterval, scanInterval); lastTimeout = setTimeout(doInterval, scanInterval);

View File

@@ -18,6 +18,7 @@ import * as os from "os";
import * as path from "path"; import * as path from "path";
import * as pem from "pem"; import * as pem from "pem";
import * as util from "util"; import * as util from "util";
import * as url from "url";
import * as ws from "ws"; import * as ws from "ws";
import { buildDir } from "./constants"; import { buildDir } from "./constants";
import { createPortScanner } from "./portScanner"; import { createPortScanner } from "./portScanner";
@@ -140,13 +141,13 @@ export const createApp = async (options: CreateAppOptions): Promise<{
}; };
const portScanner = createPortScanner(); const portScanner = createPortScanner();
wss.on("connection", (ws, req) => { wss.on("connection", async (ws, req) => {
if (req.url && req.url.startsWith("/tunnel")) { if (req.url && req.url.startsWith("/tunnel")) {
try { try {
const rawPort = req.url.split("/").pop(); const rawPort = req.url.split("/").pop();
const port = Number.parseInt(rawPort!, 10); const port = Number.parseInt(rawPort!, 10);
handleTunnel(ws, port); await handleTunnel(ws, port);
} catch (ex) { } catch (ex) {
ws.close(TunnelCloseCode.Error, ex.toString()); ws.close(TunnelCloseCode.Error, ex.toString());
} }
@@ -189,31 +190,70 @@ export const createApp = async (options: CreateAppOptions): Promise<{
new Server(connection, options.serverOptions); 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 baseDir = buildDir || path.join(__dirname, "..");
const authStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/auth")); const staticGzip = expressStaticGzip(path.join(baseDir, "build/web"));
const unauthStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/unauth"));
app.use((req, res, next) => { 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) { 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(); 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({ res.json({
hostname: os.hostname(), hostname: os.hostname(),
}); });
}); });
// For getting a resource on disk.
app.get("/resource/:url(*)", async (req, res) => { app.get("/resource/:url(*)", async (req, res) => {
if (!ensureAuthed(req, res)) { if (!ensureAuthed(req, res)) {
return; return;
@@ -254,6 +294,8 @@ export const createApp = async (options: CreateAppOptions): Promise<{
res.end(); res.end();
} }
}); });
// For writing a resource to disk.
app.post("/resource/:url(*)", async (req, res) => { app.post("/resource/:url(*)", async (req, res) => {
if (!ensureAuthed(req, res)) { if (!ensureAuthed(req, res)) {
return; return;
@@ -271,7 +313,7 @@ export const createApp = async (options: CreateAppOptions): Promise<{
const body = data.join(""); const body = data.join("");
await mkdirp(path.dirname(fullPath)); await mkdirp(path.dirname(fullPath));
fs.writeFileSync(fullPath, body); 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.status(200);
res.end(); 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 { return {
express: app, express: app,
server, server,

View File

@@ -1,7 +1,9 @@
import * as cp from "child_process"; import * as cp from "child_process";
import * as fs from "fs"; import * as fs from "fs";
import * as os from "os";
import * as path from "path"; import * as path from "path";
import * as vm from "vm"; import * as vm from "vm";
import { logger } from "@coder/logger";
import { buildDir, isCli } from "../constants"; import { buildDir, isCli } from "../constants";
let ipcMsgBuffer: Buffer[] | undefined = []; let ipcMsgBuffer: Buffer[] | undefined = [];
@@ -40,54 +42,13 @@ const requireFilesystemModule = (id: string, builtInExtensionsDir: string): any
return customMod.require(id); return customMod.require(id);
}; };
/** export const requireModule = (modulePath: string, builtInExtensionsDir: string): void => {
* 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 => {
process.env.AMD_ENTRYPOINT = modulePath; process.env.AMD_ENTRYPOINT = modulePath;
const xml = require("xhr2"); const xml = require("xhr2");
xml.XMLHttpRequest.prototype._restrictedHeaders["user-agent"] = false; xml.XMLHttpRequest.prototype._restrictedHeaders["user-agent"] = false;
// tslint:disable-next-line no-any this makes installing extensions work. // tslint:disable-next-line no-any this makes installing extensions work.
(global as any).XMLHttpRequest = xml.XMLHttpRequest; (global as any).XMLHttpRequest = xml.XMLHttpRequest;
const mod = require("module") as typeof import("module");
const promiseFinally = require("promise.prototype.finally") as { shim: () => void }; const promiseFinally = require("promise.prototype.finally") as { shim: () => void };
promiseFinally.shim(); promiseFinally.shim();
/** /**
@@ -100,16 +61,7 @@ export const requireModule = (modulePath: string, dataDir: string, builtInExtens
}; };
if (isCli) { if (isCli) {
/** process.env.NBIN_BYPASS = "true";
* 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"],
});
};
} }
const baseDir = path.join(buildDir, "build"); 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. * @param modulePath Path of the VS Code module to load.
*/ */
export const forkModule = (modulePath: string, args?: string[], options?: cp.ForkOptions, dataDir?: string): cp.ChildProcess => { export const forkModule = (modulePath: string, args?: string[], options?: cp.ForkOptions, dataDir?: string): cp.ChildProcess => {
let proc: cp.ChildProcess;
const forkOptions: cp.ForkOptions = { const forkOptions: cp.ForkOptions = {
stdio: [null, null, null, "ipc"], 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; delete options.env.ELECTRON_RUN_AS_NODE;
forkOptions.env = options.env; forkOptions.env = options.env;
} }
const forkArgs = ["--bootstrap-fork", modulePath]; const forkArgs = ["--bootstrap-fork", modulePath];
if (args) { if (args) {
forkArgs.push("--extra-args", JSON.stringify(args)); forkArgs.push("--extra-args", JSON.stringify(args));
} }
if (dataDir) { if (dataDir) {
forkArgs.push("--data-dir", dataDir); forkArgs.push("--user-data-dir", dataDir);
} }
const nodeArgs = [];
if (isCli) { if (isCli) {
proc = cp.spawn(process.execPath, [path.join(buildDir, "out", "cli.js"), ...forkArgs], forkOptions); nodeArgs.push(path.join(buildDir, "out", "cli.js"));
} else { } 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; return proc;

View File

@@ -1,5 +1,4 @@
import { ChildProcess } from "child_process"; import { ChildProcess } from "child_process";
import * as fs from "fs";
import * as os from "os"; import * as os from "os";
import * as path from "path"; import * as path from "path";
import { forkModule } from "./bootstrapFork"; import { forkModule } from "./bootstrapFork";
@@ -23,123 +22,139 @@ export type SharedProcessEvent = {
}; };
export class SharedProcess { 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 _state: SharedProcessState = SharedProcessState.Stopped;
private activeProcess: ChildProcess | undefined; private activeProcess: ChildProcess | undefined;
private ipcHandler: StdioIpcHandler | undefined; private ipcHandler: StdioIpcHandler | undefined;
private readonly onStateEmitter = new Emitter<SharedProcessEvent>(); private readonly onStateEmitter = new Emitter<SharedProcessEvent>();
public readonly onState = this.onStateEmitter.event; public readonly onState = this.onStateEmitter.event;
private readonly retryName = "Shared process";
private readonly logger = logger.named("shared"); private readonly logger = logger.named("shared");
private readonly retry = retry.register("Shared process", () => this.connect());
private disposed: boolean = false;
public constructor( public constructor(
private readonly userDataDir: string, private readonly userDataDir: string,
private readonly extensionsDir: string,
private readonly builtInExtensionsDir: string, private readonly builtInExtensionsDir: string,
) { ) {
retry.register(this.retryName, () => this.restart()); this.retry.run();
retry.run(this.retryName);
} }
public get state(): SharedProcessState { public get state(): SharedProcessState {
return this._state; return this._state;
} }
public restart(): void { /**
if (this.activeProcess && !this.activeProcess.killed) { * Signal the shared process to terminate.
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());
});
}
public dispose(): void { public dispose(): void {
this.disposed = true;
if (this.ipcHandler) { if (this.ipcHandler) {
this.ipcHandler.send("handshake:goodbye"); this.ipcHandler.send("handshake:goodbye");
} }
this.ipcHandler = undefined; 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 { private setState(event: SharedProcessEvent): void {
this._state = event.state; this._state = event.state;
this.onStateEmitter.emit(event); this.onStateEmitter.emit(event);

View File

@@ -6,14 +6,12 @@ const root = path.resolve(__dirname, "../..");
module.exports = merge( module.exports = merge(
require(path.join(root, "scripts/webpack.node.config.js"))({ require(path.join(root, "scripts/webpack.node.config.js"))({
// Config options. dirname: __dirname,
}), { }), {
output: { output: {
filename: "cli.js", filename: "cli.js",
path: path.join(__dirname, "out"),
libraryTarget: "commonjs", libraryTarget: "commonjs",
}, },
mode: "production",
node: { node: {
console: false, console: false,
global: false, global: false,
@@ -23,14 +21,8 @@ module.exports = merge(
__dirname: false, __dirname: false,
setImmediate: false setImmediate: false
}, },
resolve: {
alias: {
"node-pty": "node-pty-prebuilt",
},
},
externals: { externals: {
"nbin": "commonjs nbin", "nbin": "commonjs nbin",
"fsevents": "fsevents",
}, },
entry: "./packages/server/src/cli.ts", entry: "./packages/server/src/cli.ts",
plugins: [ plugins: [

View File

@@ -7,10 +7,10 @@
resolved "https://registry.yarnpkg.com/@coder/logger/-/logger-1.0.3.tgz#e0e1ae5496fde5a3c6ef3d748fdfb26a55add8b8" resolved "https://registry.yarnpkg.com/@coder/logger/-/logger-1.0.3.tgz#e0e1ae5496fde5a3c6ef3d748fdfb26a55add8b8"
integrity sha512-1o5qDZX2VZUNnzgz5KfAdMnaqaX6FNeTs0dUdg73MRHfQW94tFTIryFC1xTTCuzxGDjVHOHkaUAI4uHA2bheOA== integrity sha512-1o5qDZX2VZUNnzgz5KfAdMnaqaX6FNeTs0dUdg73MRHfQW94tFTIryFC1xTTCuzxGDjVHOHkaUAI4uHA2bheOA==
"@coder/nbin@^1.0.4": "@coder/nbin@^1.1.2":
version "1.0.4" version "1.1.2"
resolved "https://registry.yarnpkg.com/@coder/nbin/-/nbin-1.0.4.tgz#13a3d110fe116ed5d5fdbd1384f0335745dfd859" resolved "https://registry.yarnpkg.com/@coder/nbin/-/nbin-1.1.2.tgz#3af9e4368f37532da446c7c291d476bb52de995d"
integrity sha512-mtd5hzPHWBwKpTCYdJdLdiY4CFCEb8HUtv3NgH8SSLFiPDwY7H1UlpqeamIty27NZ+9NLnrBd/DfaE3aVo7rxQ== integrity sha512-MkwKpmu1SU9wkBwQ+bZVU2nPzENWUa3Isut9osVq3LG+udovsk+k5c5rjfJ1q8cf4km5snjOSYiulug3n9sdgw==
dependencies: dependencies:
"@coder/logger" "^1.0.3" "@coder/logger" "^1.0.3"
fs-extra "^7.0.1" fs-extra "^7.0.1"

View File

@@ -12,6 +12,7 @@ import { IFileService, FileOperation } from "vs/platform/files/common/files";
import { ITextFileService } from "vs/workbench/services/textfile/common/textfiles"; import { ITextFileService } from "vs/workbench/services/textfile/common/textfiles";
import { IModelService } from "vs/editor/common/services/modelService"; import { IModelService } from "vs/editor/common/services/modelService";
import { ITerminalService } from "vs/workbench/contrib/terminal/common/terminal"; 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 // NOTE: shouldn't import anything from VS Code here or anything that will
// depend on a synchronous fill like `os`. // depend on a synchronous fill like `os`.
@@ -38,6 +39,14 @@ class VSClient extends IdeClient {
// tslint:disable-next-line:no-any // tslint:disable-next-line:no-any
statusbarService: getService<IStatusbarService>(IStatusbarService) as any, statusbarService: getService<IStatusbarService>(IStatusbarService) as any,
notificationService: getService<INotificationService>(INotificationService), 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 => { onFileCreate: (cb): void => {
getService<IFileService>(IFileService).onAfterOperation((e) => { getService<IFileService>(IFileService).onAfterOperation((e) => {

View File

@@ -2,6 +2,7 @@
--primary: #2A2E37; --primary: #2A2E37;
--border: black; --border: black;
--faded: #a0a1a5; --faded: #a0a1a5;
--disabled: #888;
--header-background: #161616; --header-background: #161616;
--header-foreground: white; --header-foreground: white;
--list-active-selection-background: rgb(0, 120, 160); --list-active-selection-background: rgb(0, 120, 160);
@@ -101,6 +102,12 @@
background-color: var(--list-active-selection-background); background-color: var(--list-active-selection-background);
color: var(--list-active-selection-foreground); color: var(--list-active-selection-foreground);
} }
&.disabled, &.disabled:hover {
background-color: var(--primary);
color: var(--disabled);
cursor: initial;
}
} }
} }
@@ -134,6 +141,11 @@
color: white; color: white;
} }
} }
button[disabled], button[disabled]:hover {
color: var(--disabled);
cursor: initial;
}
} }
} }

View File

@@ -16,6 +16,9 @@ import { IThemeService } from "vs/platform/theme/common/themeService";
import { workbench } from "./workbench"; import { workbench } from "./workbench";
import "./dialog.scss"; import "./dialog.scss";
/**
* Describes the type of dialog to show.
*/
export enum DialogType { export enum DialogType {
NewFolder, NewFolder,
Save, Save,
@@ -68,8 +71,12 @@ interface DialogEntry {
readonly isDirectory: boolean; readonly isDirectory: boolean;
readonly size: number; readonly size: number;
readonly lastModified: string; readonly lastModified: string;
readonly isDisabled?: boolean;
} }
/**
* Open and save dialogs.
*/
class Dialog { class Dialog {
private _path: string | undefined; private _path: string | undefined;
@@ -108,7 +115,7 @@ class Dialog {
this.root.style.width = "850px"; this.root.style.width = "850px";
this.root.style.height = "600px"; this.root.style.height = "600px";
this.background.appendChild(this.root); 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"); this.root.classList.add("dialog");
const setProperty = (vari: string, id: string): void => { const setProperty = (vari: string, id: string): void => {
@@ -263,10 +270,12 @@ class Dialog {
return; 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) { if (element.isDirectory) {
this.path = element.fullPath; this.path = element.fullPath;
} else { } else if ((this.options as OpenDialogOptions).properties.openFile) {
// Open
this.selectEmitter.emit(element.fullPath); this.selectEmitter.emit(element.fullPath);
} }
}); });
@@ -282,12 +291,20 @@ class Dialog {
}); });
buttonsNode.appendChild(cancelBtn); buttonsNode.appendChild(cancelBtn);
const confirmBtn = document.createElement("button"); 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", () => { confirmBtn.addEventListener("click", () => {
if (this._path) { if (this._path && openDirectory) {
this.selectEmitter.emit(this._path); 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); buttonsNode.appendChild(confirmBtn);
this.root.appendChild(buttonsNode); this.root.appendChild(buttonsNode);
this.entryList.layout(); this.entryList.layout();
@@ -303,6 +320,9 @@ class Dialog {
return this.errorEmitter.event; return this.errorEmitter.event;
} }
/**
* Remove the dialog.
*/
public dispose(): void { public dispose(): void {
this.selectEmitter.dispose(); this.selectEmitter.dispose();
this.errorEmitter.dispose(); this.errorEmitter.dispose();
@@ -310,6 +330,9 @@ class Dialog {
this.background.remove(); this.background.remove();
} }
/**
* Build and insert the path shown at the top of the dialog.
*/
private buildPath(): void { private buildPath(): void {
while (this.pathNode.lastChild) { while (this.pathNode.lastChild) {
this.pathNode.removeChild(this.pathNode.lastChild); this.pathNode.removeChild(this.pathNode.lastChild);
@@ -376,6 +399,9 @@ class Dialog {
return (<any>this.entryList).typeFilterController.filter._pattern; return (<any>this.entryList).typeFilterController.filter._pattern;
} }
/**
* List the files and return dialog entries.
*/
private async list(directory: string): Promise<ReadonlyArray<DialogEntry>> { private async list(directory: string): Promise<ReadonlyArray<DialogEntry>> {
const paths = (await util.promisify(fs.readdir)(directory)).sort(); 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)))); 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(), isDirectory: stat.isDirectory(),
lastModified: stat.mtime.toDateString(), lastModified: stat.mtime.toDateString(),
size: stat.size, 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; label: HighlightedLabel;
} }
/**
* Rendering for the different parts of a dialog entry.
*/
class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEntryData> { class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEntryData> {
public get templateId(): string { public get templateId(): string {
return "dialog-entry"; return "dialog-entry";
} }
/**
* Append and return containers for each part of the dialog entry.
*/
public renderTemplate(container: HTMLElement): DialogEntryData { public renderTemplate(container: HTMLElement): DialogEntryData {
addClass(container, "dialog-entry"); addClass(container, "dialog-entry");
addClass(container, "dialog-grid"); 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 { public renderElement(node: ITreeNode<DialogEntry, string>, _index: number, templateData: DialogEntryData): void {
templateData.icon.className = "dialog-entry-icon monaco-icon-label"; templateData.icon.className = "dialog-entry-icon monaco-icon-label";
const classes = getIconClasses( const classes = getIconClasses(
@@ -444,8 +482,19 @@ class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEn
}] : []); }] : []);
templateData.size.innerText = node.element.size.toString(); templateData.size.innerText = node.element.size.toString();
templateData.lastModified.innerText = node.element.lastModified; 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 { public disposeTemplate(_templateData: DialogEntryData): void {
// throw new Error("Method not implemented."); // throw new Error("Method not implemented.");
} }

View 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;
};

View File

@@ -1,14 +1,16 @@
import * as path from "path";
import * as paths from "./paths"; import * as paths from "./paths";
import * as environment from "vs/platform/environment/node/environmentService"; import * as environment from "vs/platform/environment/node/environmentService";
/**
* Customize paths using data received from the initialization message.
*/
export class EnvironmentService extends environment.EnvironmentService { export class EnvironmentService extends environment.EnvironmentService {
public get sharedIPCHandle(): string { public get sharedIPCHandle(): string {
return paths.getSocketPath() || super.sharedIPCHandle; return paths.getSocketPath() || super.sharedIPCHandle;
} }
public get extensionsPath(): string { public get extensionsPath(): string {
return path.join(paths.getAppDataPath(), "extensions"); return paths.getExtensionsDirectory();
} }
} }

View File

@@ -1,19 +1,36 @@
import { logger } from "@coder/logger";
import { IDisposable } from "vs/base/common/lifecycle"; import { IDisposable } from "vs/base/common/lifecycle";
import * as actions from "vs/platform/actions/common/actions"; 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 { 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. // Intercept appending menu items so we can skip items that won't work.
const originalAppend = actions.MenuRegistry.appendMenuItem.bind(actions.MenuRegistry); const originalAppend = actions.MenuRegistry.appendMenuItem.bind(actions.MenuRegistry);
actions.MenuRegistry.appendMenuItem = (id: actions.MenuId, item: actions.IMenuItem | actions.ISubmenuItem): IDisposable => { actions.MenuRegistry.appendMenuItem = (id: actions.MenuId, item: actions.IMenuItem | actions.ISubmenuItem): IDisposable => {
if (actions.isIMenuItem(item)) { if (actions.isIMenuItem(item)) {
switch (item.command.id) { if (toSkip.indexOf(item.command.id) !== -1) {
case ToggleDevToolsAction.ID: // There appears to be no way to toggle this programmatically. // Skip instantiation
logger.debug(`Skipping unsupported menu item ${item.command.id}`); return {
dispose: (): void => undefined,
return { };
dispose: (): void => undefined,
};
} }
} }

View File

@@ -2,8 +2,8 @@ import * as nls from "vs/nls";
import { Action } from "vs/base/common/actions"; import { Action } from "vs/base/common/actions";
import { TERMINAL_COMMAND_ID } from "vs/workbench/contrib/terminal/common/terminalCommands"; import { TERMINAL_COMMAND_ID } from "vs/workbench/contrib/terminal/common/terminalCommands";
import { ITerminalService } from "vs/workbench/contrib/terminal/common/terminal"; import { ITerminalService } from "vs/workbench/contrib/terminal/common/terminal";
import * as actions from "vs/workbench/contrib/terminal/electron-browser/terminalActions"; import * as actions from "vs/workbench/contrib/terminal/browser/terminalActions";
import * as instance from "vs/workbench/contrib/terminal/electron-browser/terminalInstance"; import * as instance from "vs/workbench/contrib/terminal/browser/terminalInstance";
import { client } from "../client"; import { client } from "../client";
const getLabel = (key: string, enabled: boolean): string => { const getLabel = (key: string, enabled: boolean): string => {

View File

@@ -4,6 +4,7 @@ class Paths {
private _appData: string | undefined; private _appData: string | undefined;
private _defaultUserData: string | undefined; private _defaultUserData: string | undefined;
private _socketPath: string | undefined; private _socketPath: string | undefined;
private _extensionsDirectory: string | undefined;
private _builtInExtensionsDirectory: string | undefined; private _builtInExtensionsDirectory: string | undefined;
private _workingDirectory: string | undefined; private _workingDirectory: string | undefined;
@@ -31,6 +32,14 @@ class Paths {
return this._socketPath; 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 { public get builtInExtensionsDirectory(): string {
if (!this._builtInExtensionsDirectory) { if (!this._builtInExtensionsDirectory) {
throw new Error("trying to access builtin extensions directory before it has been set"); 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._appData = data.dataDirectory;
this._defaultUserData = data.dataDirectory; this._defaultUserData = data.dataDirectory;
this._socketPath = sharedData.socketPath; this._socketPath = sharedData.socketPath;
this._extensionsDirectory = data.extensionsDirectory;
this._builtInExtensionsDirectory = data.builtInExtensionsDirectory; this._builtInExtensionsDirectory = data.builtInExtensionsDirectory;
this._workingDirectory = data.workingDirectory; this._workingDirectory = data.workingDirectory;
} }
@@ -61,5 +71,6 @@ export const _paths = new Paths();
export const getAppDataPath = (): string => _paths.appData; export const getAppDataPath = (): string => _paths.appData;
export const getDefaultUserDataPath = (): string => _paths.defaultUserData; export const getDefaultUserDataPath = (): string => _paths.defaultUserData;
export const getWorkingDirectory = (): string => _paths.workingDirectory; export const getWorkingDirectory = (): string => _paths.workingDirectory;
export const getExtensionsDirectory = (): string => _paths.extensionsDirectory;
export const getBuiltInExtensionsDirectory = (): string => _paths.builtInExtensionsDirectory; export const getBuiltInExtensionsDirectory = (): string => _paths.builtInExtensionsDirectory;
export const getSocketPath = (): string => _paths.socketPath; export const getSocketPath = (): string => _paths.socketPath;

View File

@@ -4,6 +4,20 @@ import { IProductConfiguration } from "vs/platform/product/node/product";
class Product implements IProductConfiguration { class Product implements IProductConfiguration {
public nameShort = "code-server"; public nameShort = "code-server";
public nameLong = "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; private _dataFolderName: string | undefined;
public get dataFolderName(): string { public get dataFolderName(): string {
@@ -18,7 +32,8 @@ class Product implements IProductConfiguration {
serviceUrl: global && global.process && global.process.env.SERVICE_URL serviceUrl: global && global.process && global.process.env.SERVICE_URL
|| process.env.SERVICE_URL || process.env.SERVICE_URL
|| "https://v1.extapi.coder.com", || "https://v1.extapi.coder.com",
}; // tslint:disable-next-line:no-any
} as any;
public extensionExecutionEnvironments = { public extensionExecutionEnvironments = {
"wayou.vscode-todo-highlight": "worker", "wayou.vscode-todo-highlight": "worker",

View File

@@ -11,6 +11,8 @@ import { IStorageService, WillSaveStateReason } from "vs/platform/storage/common
import * as paths from "./paths"; import * as paths from "./paths";
import { workbench } from "../workbench"; import { workbench } from "../workbench";
// tslint:disable completed-docs
class StorageDatabase implements workspaceStorage.IStorageDatabase { class StorageDatabase implements workspaceStorage.IStorageDatabase {
public readonly onDidChangeItemsExternal = Event.None; public readonly onDidChangeItemsExternal = Event.None;
private readonly items = new Map<string, string>(); private readonly items = new Map<string, string>();
@@ -26,7 +28,8 @@ class StorageDatabase implements workspaceStorage.IStorageDatabase {
} }
this.triggerFlush(WillSaveStateReason.SHUTDOWN); this.triggerFlush(WillSaveStateReason.SHUTDOWN);
navigator.sendBeacon(`/resource${this.path}`, this.content); const resourceBaseUrl = location.pathname.replace(/\/$/, "") + "/resource";
navigator.sendBeacon(`${resourceBaseUrl}/${this.path}`, this.content);
}); });
} }

View File

@@ -2,6 +2,17 @@ import * as vscodeTextmate from "../../../../lib/vscode/node_modules/vscode-text
const target = vscodeTextmate as typeof vscodeTextmate; 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 { target.Registry = class Registry extends vscodeTextmate.Registry {
public constructor(opts: vscodeTextmate.RegistryOptions) { public constructor(opts: vscodeTextmate.RegistryOptions) {
super({ super({
@@ -21,6 +32,13 @@ target.Registry = class Registry extends vscodeTextmate.Registry {
}).catch(reason => rej(reason)); }).catch(reason => rej(reason));
}); });
}, },
loadGrammar: async (scopeName: string) => {
if (scopeToGrammar[scopeName]) {
return scopeToGrammar[scopeName];
}
return opts.loadGrammar(scopeName);
},
}); });
} }
}; };

View File

@@ -1,21 +1,32 @@
import * as electron from "electron"; import * as electron from "electron";
import { Emitter } from "@coder/events"; import { Emitter } from "@coder/events";
import * as windowsIpc from "vs/platform/windows/node/windowsIpc"; import { logger } from "@coder/logger";
import { IWindowsService, INativeOpenDialogOptions, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, IMessageBoxResult, IDevToolsOptions, IEnterWorkspaceResult, CrashReporterStartOptions, INewWindowOptions, IOpenFileRequest, IAddFoldersRequest } from "vs/platform/windows/common/windows"; 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 { ParsedArgs } from "vs/platform/environment/common/environment";
import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier } from "vs/platform/workspaces/common/workspaces"; import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier } from "vs/platform/workspaces/common/workspaces";
import { URI } from "vs/base/common/uri"; 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 { ISerializableCommandAction } from "vs/platform/actions/common/actions";
import { client } from "../client"; import { client } from "../client";
import { showOpenDialog } from "../dialog"; import { showOpenDialog } from "../dialog";
import { workbench } from "../workbench"; 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 * 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. * 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 // tslint:disable-next-line no-any
public _serviceBrand: any; public _serviceBrand: any;
@@ -36,9 +47,9 @@ class WindowsService implements IWindowsService {
private readonly window = new electron.BrowserWindow(); private readonly window = new electron.BrowserWindow();
// Dialogs // Dialogs
public async pickFileFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> { public async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
showOpenDialog({ showOpenDialog({
...(_options.dialogOptions || {}), ...(options.dialogOptions || {}),
properties: { properties: {
openFile: true, openFile: true,
openDirectory: true, openDirectory: true,
@@ -51,13 +62,13 @@ class WindowsService implements IWindowsService {
}], }],
} as IOpenFileRequest); } as IOpenFileRequest);
}).catch((ex) => { }).catch((ex) => {
// logger.error(ex.message);
}); });
} }
public async pickFileAndOpen(_options: INativeOpenDialogOptions): Promise<void> { public async pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void> {
showOpenDialog({ showOpenDialog({
...(_options.dialogOptions || {}), ...(options.dialogOptions || {}),
properties: { properties: {
openFile: true, openFile: true,
}, },
@@ -69,26 +80,32 @@ class WindowsService implements IWindowsService {
}], }],
} as IOpenFileRequest); } as IOpenFileRequest);
}).catch((ex) => { }).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({ showOpenDialog({
...(_options.dialogOptions || {}), ...(options.dialogOptions || {}),
properties: { properties: {
openDirectory: true, openDirectory: true,
}, },
}).then((path) => { }).then((path) => {
workbench.workspace = URI.file(path); workbench.workspace = URI.file(path);
}).catch((ex) => { }).catch((ex) => {
// logger.error(ex.message);
}); });
} }
public async pickWorkspaceAndOpen(_options: INativeOpenDialogOptions): Promise<void> { public async pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void> {
showOpenDialog({ showOpenDialog({
...(_options.dialogOptions || {}), ...(options.dialogOptions || {}),
properties: { properties: {
openDirectory: true, openDirectory: true,
}, },
@@ -98,7 +115,7 @@ class WindowsService implements IWindowsService {
foldersToAdd: [URI.file(path)], foldersToAdd: [URI.file(path)],
} as IAddFoldersRequest); } as IAddFoldersRequest);
}).catch((ex) => { }).catch((ex) => {
// logger.error(ex.message);
}); });
} }
@@ -121,16 +138,14 @@ class WindowsService implements IWindowsService {
}); });
} }
public showOpenDialog(windowId: number, options: OpenDialogOptions): Promise<string[]> { public async showOpenDialog(_windowId: number, options: OpenDialogOptions): Promise<string[]> {
return showOpenDialog({ return [await showOpenDialog({
...(options || {}), ...(options || {}),
properties: { properties: {
openDirectory: true, openDirectory: options && options.properties && options.properties.includes("openDirectory") || false,
openFile: true, openFile: options && options.properties && options.properties.includes("openFile") || false,
}, },
}).then((path) => { })];
return [path];
});
} }
public reloadWindow(windowId: number, _args?: ParsedArgs): Promise<void> { public reloadWindow(windowId: number, _args?: ParsedArgs): Promise<void> {
@@ -149,14 +164,14 @@ class WindowsService implements IWindowsService {
throw new Error("not implemented"); throw new Error("not implemented");
} }
public enterWorkspace(_windowId: number, _path: URI): Promise<IEnterWorkspaceResult> { public enterWorkspace(_windowId: number, uri: URI): Promise<IEnterWorkspaceResult> {
if (_path.path.endsWith(".json")) { if (uri.path.endsWith(".json")) {
workbench.workspace = { workbench.workspace = {
id: "Untitled", id: "Untitled",
configPath: _path.path, configPath: uri,
}; };
} else { } else {
workbench.workspace = _path; workbench.workspace = uri;
} }
return undefined!; return undefined!;
@@ -180,7 +195,7 @@ class WindowsService implements IWindowsService {
return Promise.resolve(this.getWindowById(windowId).setRepresentedFilename(fileName)); 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"); throw new Error("not implemented");
} }
@@ -284,7 +299,7 @@ class WindowsService implements IWindowsService {
} }
// Global methods // 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"); throw new Error("not implemented");
} }
@@ -308,8 +323,8 @@ class WindowsService implements IWindowsService {
throw new Error("not implemented"); throw new Error("not implemented");
} }
public async showItemInFolder(_path: string): Promise<void> { public async showItemInFolder(uri: URI): Promise<void> {
workbench.workspace = URI.file(_path); workbench.workspace = uri;
} }
public getActiveWindowId(): Promise<number | undefined> { public getActiveWindowId(): Promise<number | undefined> {
@@ -343,7 +358,3 @@ class WindowsService implements IWindowsService {
return this.window; return this.window;
} }
} }
const target = windowsIpc as typeof windowsIpc;
// @ts-ignore TODO: don't ignore it.
target.WindowsChannelClient = WindowsService;

View File

@@ -5,7 +5,7 @@ import { IWorkbenchActionRegistry, Extensions } from "vs/workbench/common/action
import { SyncActionDescriptor } from "vs/platform/actions/common/actions"; import { SyncActionDescriptor } from "vs/platform/actions/common/actions";
import { ContextKeyExpr } from "vs/platform/contextkey/common/contextkey"; import { ContextKeyExpr } from "vs/platform/contextkey/common/contextkey";
import { ToggleDevToolsAction } from "vs/workbench/electron-browser/actions/developerActions"; 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 { KEYBINDING_CONTEXT_TERMINAL_FOCUS } from "vs/workbench/contrib/terminal/common/terminal";
import { KeyCode, KeyMod } from "vs/base/common/keyCodes"; import { KeyCode, KeyMod } from "vs/base/common/keyCodes";
import { workbench } from "../workbench"; import { workbench } from "../workbench";

View File

@@ -53,3 +53,7 @@
width: 56px !important; width: 56px !important;
margin-right: 4px; margin-right: 4px;
} }
.window-controls-container {
display: none !important;
}

View File

@@ -1,5 +1,6 @@
import * as os from "os"; import * as os from "os";
import { IProgress, INotificationHandle } from "@coder/ide"; import { IProgress, INotificationHandle } from "@coder/ide";
import { logger } from "@coder/logger";
import { client } from "./client"; import { client } from "./client";
import "./fill/platform"; import "./fill/platform";
@@ -29,11 +30,20 @@ import { RawContextKey, IContextKeyService } from "vs/platform/contextkey/common
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection"; import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
import { URI } from "vs/base/common/uri"; import { URI } from "vs/base/common/uri";
/**
* Initializes VS Code and provides a way to call into general client
* functionality.
*/
export class Workbench { export class Workbench {
public readonly retry = client.retry;
private readonly windowId = parseInt(new Date().toISOString().replace(/[-:.TZ]/g, ""), 10); private readonly windowId = parseInt(new Date().toISOString().replace(/[-:.TZ]/g, ""), 10);
private _serviceCollection: ServiceCollection | undefined; private _serviceCollection: ServiceCollection | undefined;
private _clipboardContextKey: RawContextKey<boolean> | undefined; private _clipboardContextKey: RawContextKey<boolean> | undefined;
/**
* Handle a drop event on the file explorer.
*/
public async handleExternalDrop(target: ExplorerItem | ExplorerModel, originalEvent: DragEvent): Promise<void> { public async handleExternalDrop(target: ExplorerItem | ExplorerModel, originalEvent: DragEvent): Promise<void> {
await client.upload.uploadDropped( await client.upload.uploadDropped(
originalEvent, 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 { 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)); const uris = paths.map((p) => URI.file(p));
if (uris.length) { 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 => ({ const editors: IResourceEditor[] = uris.map(uri => ({
@@ -57,10 +70,10 @@ export class Workbench {
})); }));
const targetGroup = resolveTargetGroup(); const targetGroup = resolveTargetGroup();
await (this.serviceCollection.get(IEditorService) as IEditorService).openEditors(editors, targetGroup);
(this.serviceCollection.get(IEditorService) as IEditorService).openEditors(editors, targetGroup).then(() => { afterDrop(targetGroup);
afterDrop(targetGroup); }).catch((error) => {
}); logger.error(error.message);
}); });
} }
@@ -115,6 +128,14 @@ export class Workbench {
public set serviceCollection(collection: ServiceCollection) { public set serviceCollection(collection: ServiceCollection) {
this._serviceCollection = collection; 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 = { client.progressService = {
start: <T>(title: string, task: (progress: IProgress) => Promise<T>, onCancel: () => void): Promise<T> => { start: <T>(title: string, task: (progress: IProgress) => Promise<T>, onCancel: () => void): Promise<T> => {
let lastProgress = 0; let lastProgress = 0;
@@ -164,6 +185,9 @@ export class Workbench {
}; };
} }
/**
* Start VS Code.
*/
public async initialize(): Promise<void> { public async initialize(): Promise<void> {
this._clipboardContextKey = new RawContextKey("nativeClipboard", client.clipboard.isEnabled); this._clipboardContextKey = new RawContextKey("nativeClipboard", client.clipboard.isEnabled);
@@ -210,12 +234,6 @@ export class Workbench {
return; 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();
} }
} }

View File

@@ -7,6 +7,7 @@ const vsFills = path.join(root, "packages/vscode/src/fill");
module.exports = merge( module.exports = merge(
require(path.join(root, "scripts/webpack.node.config.js"))({ require(path.join(root, "scripts/webpack.node.config.js"))({
dirname: __dirname,
typescriptCompilerOptions: { typescriptCompilerOptions: {
target: "es6", target: "es6",
}, },
@@ -15,7 +16,6 @@ module.exports = merge(
mode: "development", mode: "development",
output: { output: {
chunkFilename: "[name].bundle.js", chunkFilename: "[name].bundle.js",
path: path.resolve(__dirname, "out"),
publicPath: "/", publicPath: "/",
filename: "bootstrap-fork.js", filename: "bootstrap-fork.js",
libraryTarget: "commonjs", libraryTarget: "commonjs",
@@ -36,7 +36,8 @@ module.exports = merge(
loader: "ignore-loader", 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: [{ use: [{
loader: "ignore-loader", loader: "ignore-loader",
}], }],
@@ -50,15 +51,17 @@ module.exports = merge(
"windows-mutex": path.resolve(fills, "empty.ts"), "windows-mutex": path.resolve(fills, "empty.ts"),
"windows-process-tree": path.resolve(fills, "empty.ts"), "windows-process-tree": path.resolve(fills, "empty.ts"),
"vscode-windows-registry": 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"), "vscode-sqlite3": path.resolve(fills, "empty.ts"),
"vs/base/browser/browser": 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"), "electron": path.join(vsFills, "stdioElectron.ts"),
"vscode-ripgrep": path.join(vsFills, "ripgrep.ts"), "vscode-ripgrep": path.join(vsFills, "ripgrep.ts"),
"native-keymap": path.join(vsFills, "native-keymap.ts"), "native-keymap": path.join(vsFills, "native-keymap.ts"),
"native-watchdog": path.join(vsFills, "native-watchdog.ts"), "native-watchdog": path.join(vsFills, "native-watchdog.ts"),
"vs/base/common/amd": path.resolve(vsFills, "amd.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/package": path.resolve(vsFills, "package.ts"),
"vs/platform/product/node/product": path.resolve(vsFills, "product.ts"), "vs/platform/product/node/product": path.resolve(vsFills, "product.ts"),
"vs/base/node/zip": path.resolve(vsFills, "zip.ts"), "vs/base/node/zip": path.resolve(vsFills, "zip.ts"),

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -1,6 +1,6 @@
{ {
"name": "@coder/web", "name": "@coder/web",
"scripts": { "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" "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"
} }
} }

View File

@@ -24,7 +24,14 @@
} }
document.body.style.background = bg; 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> </script>
</body> </body>
</html>
</html>

View File

@@ -7,7 +7,9 @@ const vsFills = path.join(root, "packages/vscode/src/fill");
module.exports = merge( module.exports = merge(
require(path.join(root, "scripts/webpack.client.config.js"))({ require(path.join(root, "scripts/webpack.client.config.js"))({
dirname: __dirname,
entry: path.join(root, "packages/web/src/index.ts"), entry: path.join(root, "packages/web/src/index.ts"),
name: "ide",
template: path.join(root, "packages/web/src/index.html"), template: path.join(root, "packages/web/src/index.html"),
typescriptCompilerOptions: { typescriptCompilerOptions: {
"target": "es5", "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: { node: {
module: "empty", module: "empty",
crypto: "empty", crypto: "empty",
@@ -70,6 +67,7 @@ module.exports = merge(
// This seems to be in the wrong place? // 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/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/node/paths": path.join(vsFills, "paths.ts"),
"vs/base/common/amd": path.join(vsFills, "amd.ts"), "vs/base/common/amd": path.join(vsFills, "amd.ts"),
"vs/platform/product/node/package": path.resolve(vsFills, "package.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
View 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 .

View File

@@ -4,10 +4,12 @@ const merge = require("webpack-merge");
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const PreloadWebpackPlugin = require("preload-webpack-plugin"); const PreloadWebpackPlugin = require("preload-webpack-plugin");
const HtmlWebpackPlugin = require("html-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 root = path.join(__dirname, "..");
const prod = process.env.NODE_ENV === "production" || process.env.CI === "true"; 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( module.exports = (options = {}) => merge(
require("./webpack.general.config")(options), { require("./webpack.general.config")(options), {
@@ -30,29 +32,57 @@ module.exports = (options = {}) => merge(
loader: "sass-loader", loader: "sass-loader",
}], }],
}, { }, {
test: /\.(svg|png|ttf|woff|eot|woff2)$/, test: /\.(png|ttf|woff|eot|woff2)$/,
use: [{ use: [{
loader: "file-loader", loader: "file-loader",
options: { options: {
name: "[path][name].[ext]", name: "[path][name].[ext]",
}, },
}], }],
}, {
test: /\.svg$/,
loader: 'url-loader'
}], }],
}, },
plugins: [ plugins: [
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: "[name].css", chunkFilename: `${options.name || "client"}.[name].[hash:6].css`,
chunkFilename: "[id].css", filename: `${options.name || "client"}.[name].[hash:6].css`
}), }),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
template: options.template, template: options.template
}), }),
new PreloadWebpackPlugin({ new PreloadWebpackPlugin({
rel: "preload", rel: "preload",
as: "script", as: "script"
}), }),
].concat(prod ? [] : [ new WebpackPwaManifest({
new webpack.HotModuleReplacementPlugin(), name: "Coder",
]), short_name: "Coder",
target: "web", 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