mirror of
https://github.com/coder/code-server.git
synced 2026-04-14 15:19:07 -05:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bde62fbd6 | ||
|
|
6fbbb1047f | ||
|
|
e07a591745 | ||
|
|
676c7bf915 | ||
|
|
9ad7d0b7a3 | ||
|
|
07e7c38ea2 | ||
|
|
0b9af6ef67 | ||
|
|
c63dc3a1ea | ||
|
|
860c99e3b8 | ||
|
|
7e1e9d1249 |
46
README.md
46
README.md
@@ -6,72 +6,58 @@ Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and a
|
||||
|
||||
## Highlights
|
||||
|
||||
- **Code everywhere**
|
||||
- Code on your Chromebook, tablet, and laptop with a consistent development environment.
|
||||
- Develop on a Linux machine and pick up from any device with a web browser.
|
||||
- **Server-powered**
|
||||
- Take advantage of large cloud servers to speed up tests, compilations, downloads, and more.
|
||||
- Preserve battery life when you're on the go as all intensive tasks run on your server.
|
||||
- Make use of a spare computer you have lying around and turn it into a full development environment.
|
||||
- Code on any device with a consistent development environment
|
||||
- Use cloud servers to speed up tests, compilations, downloads, and more
|
||||
- Preserve battery life when you're on the go; all intensive tasks run on your server
|
||||
|
||||
## Getting Started
|
||||
|
||||
For a full setup and walkthrough, please see [./doc/guide.md](./doc/guide.md).
|
||||
There are two ways to get started:
|
||||
|
||||
### Quick Install
|
||||
1. Using the [install script](./install.sh), which automates most of the process. The script uses the system package manager (if possible)
|
||||
2. Manually installing code-server; see [Installation](./doc/install.md) for instructions applicable to most use cases
|
||||
|
||||
We have a [script](./install.sh) to install code-server for Linux, macOS and FreeBSD.
|
||||
|
||||
It tries to use the system package manager if possible.
|
||||
|
||||
First run to print out the install process:
|
||||
If you choose to use the install script, you can preview what occurs during the install process:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
|
||||
```
|
||||
|
||||
Now to actually install:
|
||||
To install, run:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://code-server.dev/install.sh | sh
|
||||
```
|
||||
|
||||
The install script will print out how to run and start using code-server.
|
||||
When done, the install script prints out instructions for running and starting code-server.
|
||||
|
||||
### Manual Install
|
||||
|
||||
Docs on the install script, manual installation and docker image are at [./doc/install.md](./doc/install.md).
|
||||
We also have an in-depth [setup and configuration](./doc/guide.md) guide.
|
||||
|
||||
### Alpha Program 🐣
|
||||
|
||||
We're working on a cloud platform to make deploying and managing code-server easier. If you don't want to worry about
|
||||
We're working on a cloud platform that makes deploying and managing code-server easier. Consider [joining our alpha program](https://codercom.typeform.com/to/U4IKyv0W) if you don't want to worry about
|
||||
|
||||
- TLS
|
||||
- Authentication
|
||||
- Port Forwarding
|
||||
|
||||
consider [joining our alpha program](https://codercom.typeform.com/to/U4IKyv0W).
|
||||
|
||||
## FAQ
|
||||
|
||||
See [./doc/FAQ.md](./doc/FAQ.md).
|
||||
|
||||
## Contributing
|
||||
## Want to help?
|
||||
|
||||
See [./doc/CONTRIBUTING.md](./doc/CONTRIBUTING.md).
|
||||
See [CONTRIBUTING](./doc/CONTRIBUTING.md) for details.
|
||||
|
||||
## Hiring
|
||||
|
||||
We ([@cdr](https://github.com/cdr)) are looking for engineers to help maintain
|
||||
code-server, innovate on open source and streamline dev workflows.
|
||||
We ([@cdr](https://github.com/cdr)) are looking for engineers to help [maintain
|
||||
code-server](https://jobs.lever.co/coder/e40becde-2cbd-4885-9029-e5c7b0a734b8), innovate on open source, and streamline dev workflows.
|
||||
|
||||
Our main office is in Austin, Texas. Remote is ok as long as
|
||||
you're in North America or Europe.
|
||||
|
||||
Please get in [touch](mailto:jobs@coder.com) with your resume/github if interested.
|
||||
|
||||
We're also hiring someone specifically to help maintain code-server.
|
||||
See the listing [here](https://jobs.lever.co/coder/e40becde-2cbd-4885-9029-e5c7b0a734b8).
|
||||
Please get in [touch](mailto:jobs@coder.com) with your resume/GitHub if interested.
|
||||
|
||||
## For Organizations
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ EOF
|
||||
bundle_vscode() {
|
||||
mkdir -p "$VSCODE_OUT_PATH"
|
||||
rsync "$VSCODE_SRC_PATH/yarn.lock" "$VSCODE_OUT_PATH"
|
||||
rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY+-min}/" "$VSCODE_OUT_PATH/out"
|
||||
rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY:+-min}/" "$VSCODE_OUT_PATH/out"
|
||||
|
||||
rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions"
|
||||
if [ "$KEEP_MODULES" = 0 ]; then
|
||||
|
||||
@@ -25,8 +25,11 @@ main() {
|
||||
esac
|
||||
|
||||
OS="$(uname | tr '[:upper:]' '[:lower:]')"
|
||||
curl -fsSL "https://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -o ./lib/coder-cloud-agent
|
||||
chmod +x ./lib/coder-cloud-agent
|
||||
if curl -fsSL "https://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -o ./lib/coder-cloud-agent; then
|
||||
chmod +x ./lib/coder-cloud-agent
|
||||
else
|
||||
echo "Failed to download cloud agent; --link will not work"
|
||||
fi
|
||||
|
||||
if ! vscode_yarn; then
|
||||
echo "You may not have the required dependencies to build the native modules."
|
||||
|
||||
@@ -1225,10 +1225,10 @@ index 0000000000000000000000000000000000000000..4ea6d95d36aaac07dbd4d0e16ab3c1bb
|
||||
+}
|
||||
diff --git a/src/vs/server/entry.ts b/src/vs/server/entry.ts
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ab020fbb4e4ab3748cc807765ff9c362389faafa
|
||||
index 0000000000000000000000000000000000000000..8482c48bae007ed6b39183001ae2cc6d140fcd50
|
||||
--- /dev/null
|
||||
+++ b/src/vs/server/entry.ts
|
||||
@@ -0,0 +1,78 @@
|
||||
@@ -0,0 +1,79 @@
|
||||
+import { field } from '@coder/logger';
|
||||
+import { setUnexpectedErrorHandler } from 'vs/base/common/errors';
|
||||
+import { CodeServerMessage, VscodeMessage } from 'vs/server/ipc';
|
||||
@@ -1273,7 +1273,8 @@ index 0000000000000000000000000000000000000000..ab020fbb4e4ab3748cc807765ff9c362
|
||||
+// Wait for the init message then start up VS Code. Subsequent messages will
|
||||
+// return new workbench options without starting a new instance.
|
||||
+process.on('message', async (message: CodeServerMessage, socket) => {
|
||||
+ logger.debug('got message from code-server', field('message', message));
|
||||
+ logger.debug('got message from code-server', field('type', message.type));
|
||||
+ logger.trace('code-server message content', field('message', message));
|
||||
+ switch (message.type) {
|
||||
+ case 'init':
|
||||
+ try {
|
||||
@@ -1821,10 +1822,11 @@ index 0000000000000000000000000000000000000000..609c4d1cb43f52f92906b901c14c790f
|
||||
+}
|
||||
diff --git a/src/vs/server/node/connection.ts b/src/vs/server/node/connection.ts
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..eec198c948d48b1539ff46510016f759f396be18
|
||||
index 0000000000000000000000000000000000000000..93062cadc627c61e0829c27a72894b81e6a0e039
|
||||
--- /dev/null
|
||||
+++ b/src/vs/server/node/connection.ts
|
||||
@@ -0,0 +1,157 @@
|
||||
@@ -0,0 +1,171 @@
|
||||
+import { field, Logger, logger } from '@coder/logger';
|
||||
+import * as cp from 'child_process';
|
||||
+import { VSBuffer } from 'vs/base/common/buffer';
|
||||
+import { Emitter } from 'vs/base/common/event';
|
||||
@@ -1832,10 +1834,8 @@ index 0000000000000000000000000000000000000000..eec198c948d48b1539ff46510016f759
|
||||
+import { ISocket } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
+import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
+import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
+import { ILogService } from 'vs/platform/log/common/log';
|
||||
+import { getNlsConfiguration } from 'vs/server/node/nls';
|
||||
+import { Protocol } from 'vs/server/node/protocol';
|
||||
+import { IExtHostReadyMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
+
|
||||
+export abstract class Connection {
|
||||
+ private readonly _onClose = new Emitter<void>();
|
||||
@@ -1899,13 +1899,14 @@ index 0000000000000000000000000000000000000000..eec198c948d48b1539ff46510016f759
|
||||
+
|
||||
+export class ExtensionHostConnection extends Connection {
|
||||
+ private process?: cp.ChildProcess;
|
||||
+ private readonly logger: Logger;
|
||||
+
|
||||
+ public constructor(
|
||||
+ locale:string, protocol: Protocol, buffer: VSBuffer, token: string,
|
||||
+ private readonly log: ILogService,
|
||||
+ private readonly environment: INativeEnvironmentService,
|
||||
+ ) {
|
||||
+ super(protocol, token);
|
||||
+ this.logger = logger.named("exthost", field("token", token));
|
||||
+ this.protocol.dispose();
|
||||
+ this.spawn(locale, buffer).then((p) => this.process = p);
|
||||
+ this.protocol.getUnderlyingSocket().pause();
|
||||
@@ -1928,6 +1929,7 @@ index 0000000000000000000000000000000000000000..eec198c948d48b1539ff46510016f759
|
||||
+ private sendInitMessage(buffer: VSBuffer): void {
|
||||
+ const socket = this.protocol.getUnderlyingSocket();
|
||||
+ socket.pause();
|
||||
+ this.logger.trace('Sending socket');
|
||||
+ this.process!.send({ // Process must be set at this point.
|
||||
+ type: 'VSCODE_EXTHOST_IPC_SOCKET',
|
||||
+ initialDataChunk: (buffer.buffer as Buffer).toString('base64'),
|
||||
@@ -1936,7 +1938,9 @@ index 0000000000000000000000000000000000000000..eec198c948d48b1539ff46510016f759
|
||||
+ }
|
||||
+
|
||||
+ private async spawn(locale: string, buffer: VSBuffer): Promise<cp.ChildProcess> {
|
||||
+ this.logger.trace('Getting NLS configuration...');
|
||||
+ const config = await getNlsConfiguration(locale, this.environment.userDataPath);
|
||||
+ this.logger.trace('Spawning extension host...');
|
||||
+ const proc = cp.fork(
|
||||
+ FileAccess.asFileUri('bootstrap-fork', require).fsPath,
|
||||
+ [ '--type=extensionHost' ],
|
||||
@@ -1956,30 +1960,41 @@ index 0000000000000000000000000000000000000000..eec198c948d48b1539ff46510016f759
|
||||
+ },
|
||||
+ );
|
||||
+
|
||||
+ proc.on('error', () => this.dispose());
|
||||
+ proc.on('exit', () => this.dispose());
|
||||
+ proc.on('error', (error) => {
|
||||
+ this.logger.error('Exited unexpectedly', field('error', error));
|
||||
+ this.dispose();
|
||||
+ });
|
||||
+ proc.on('exit', (code) => {
|
||||
+ this.logger.trace('Exited', field('code', code));
|
||||
+ this.dispose();
|
||||
+ });
|
||||
+ if (proc.stdout && proc.stderr) {
|
||||
+ proc.stdout.setEncoding('utf8').on('data', (d) => this.log.info('Extension host stdout', d));
|
||||
+ proc.stderr.setEncoding('utf8').on('data', (d) => this.log.error('Extension host stderr', d));
|
||||
+ proc.stdout.setEncoding('utf8').on('data', (d) => this.logger.info(d));
|
||||
+ proc.stderr.setEncoding('utf8').on('data', (d) => this.logger.error(d));
|
||||
+ }
|
||||
+
|
||||
+ proc.on('message', (event) => {
|
||||
+ if (event && event.type === '__$console') {
|
||||
+ const severity = (<any>this.log)[event.severity] ? event.severity : 'info';
|
||||
+ (<any>this.log)[severity]('Extension host', event.arguments);
|
||||
+ }
|
||||
+ if (event && event.type === 'VSCODE_EXTHOST_DISCONNECTED') {
|
||||
+ this.setOffline();
|
||||
+ switch (event && event.type) {
|
||||
+ case '__$console':
|
||||
+ const severity = (<any>this.logger)[event.severity] || 'info';
|
||||
+ (<any>this.logger)[severity]('console', field('arguments', event.arguments));
|
||||
+ break;
|
||||
+ case 'VSCODE_EXTHOST_DISCONNECTED':
|
||||
+ this.logger.trace('Going offline');
|
||||
+ this.setOffline();
|
||||
+ break;
|
||||
+ case 'VSCODE_EXTHOST_IPC_READY':
|
||||
+ this.logger.trace('Got ready message');
|
||||
+ this.sendInitMessage(buffer);
|
||||
+ break;
|
||||
+ default:
|
||||
+ this.logger.error('Unexpected message', field("event", event));
|
||||
+ break;
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ const listen = (message: IExtHostReadyMessage) => {
|
||||
+ if (message.type === 'VSCODE_EXTHOST_IPC_READY') {
|
||||
+ proc.removeListener('message', listen);
|
||||
+ this.sendInitMessage(buffer);
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ return proc.on('message', listen);
|
||||
+ this.logger.trace('Waiting for handshake...');
|
||||
+ return proc;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/vs/server/node/insights.ts b/src/vs/server/node/insights.ts
|
||||
@@ -2463,15 +2478,17 @@ index 0000000000000000000000000000000000000000..3d428a57d31f29c40f9c3ce45f715b44
|
||||
+};
|
||||
diff --git a/src/vs/server/node/protocol.ts b/src/vs/server/node/protocol.ts
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..3c74512192aec6220216bc8563b3127b9cfd5fbf
|
||||
index 0000000000000000000000000000000000000000..0d9310038c0ca378579652d89bc8ac84924213db
|
||||
--- /dev/null
|
||||
+++ b/src/vs/server/node/protocol.ts
|
||||
@@ -0,0 +1,73 @@
|
||||
@@ -0,0 +1,91 @@
|
||||
+import { field } from '@coder/logger';
|
||||
+import * as net from 'net';
|
||||
+import { VSBuffer } from 'vs/base/common/buffer';
|
||||
+import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
+import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
+import { AuthRequest, ConnectionTypeRequest, HandshakeMessage } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
+import { logger } from 'vs/server/node/logger';
|
||||
+
|
||||
+export interface SocketOptions {
|
||||
+ readonly reconnectionToken: string;
|
||||
@@ -2499,29 +2516,45 @@ index 0000000000000000000000000000000000000000..3c74512192aec6220216bc8563b3127b
|
||||
+ * Perform a handshake to get a connection request.
|
||||
+ */
|
||||
+ public handshake(): Promise<ConnectionTypeRequest> {
|
||||
+ logger.trace('Protocol handshake', field('token', this.options.reconnectionToken));
|
||||
+ return new Promise((resolve, reject) => {
|
||||
+ const timeout = setTimeout(() => {
|
||||
+ logger.error('Handshake timed out', field('token', this.options.reconnectionToken));
|
||||
+ reject(new Error("timed out"));
|
||||
+ }, 10000); // Matches the client timeout.
|
||||
+
|
||||
+ const handler = this.onControlMessage((rawMessage) => {
|
||||
+ try {
|
||||
+ const message = JSON.parse(rawMessage.toString());
|
||||
+ const raw = rawMessage.toString();
|
||||
+ logger.trace('Protocol message', field('token', this.options.reconnectionToken), field('message', raw));
|
||||
+ const message = JSON.parse(raw);
|
||||
+ switch (message.type) {
|
||||
+ case 'auth': return this.authenticate(message);
|
||||
+ case 'auth':
|
||||
+ return this.authenticate(message);
|
||||
+ case 'connectionType':
|
||||
+ handler.dispose();
|
||||
+ clearTimeout(timeout);
|
||||
+ return resolve(message);
|
||||
+ default: throw new Error('Unrecognized message type');
|
||||
+ default:
|
||||
+ throw new Error('Unrecognized message type');
|
||||
+ }
|
||||
+ } catch (error) {
|
||||
+ handler.dispose();
|
||||
+ clearTimeout(timeout);
|
||||
+ reject(error);
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ // Kick off the handshake in case we missed the client's opening shot.
|
||||
+ // TODO: Investigate why that message seems to get lost.
|
||||
+ this.authenticate();
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * TODO: This ignores the authentication process entirely for now.
|
||||
+ */
|
||||
+ private authenticate(_message: AuthRequest): void {
|
||||
+ private authenticate(_?: AuthRequest): void {
|
||||
+ this.sendMessage({ type: 'sign', data: '' });
|
||||
+ }
|
||||
+
|
||||
@@ -2542,10 +2575,11 @@ index 0000000000000000000000000000000000000000..3c74512192aec6220216bc8563b3127b
|
||||
+}
|
||||
diff --git a/src/vs/server/node/server.ts b/src/vs/server/node/server.ts
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..a1289865858f405f93d3d396f41c6a0aadffd5e5
|
||||
index 0000000000000000000000000000000000000000..45a7bf62a6c07d8771b0257e7c98fae095109eb1
|
||||
--- /dev/null
|
||||
+++ b/src/vs/server/node/server.ts
|
||||
@@ -0,0 +1,286 @@
|
||||
@@ -0,0 +1,291 @@
|
||||
+import { field } from '@coder/logger';
|
||||
+import * as fs from 'fs';
|
||||
+import * as net from 'net';
|
||||
+import * as path from 'path';
|
||||
@@ -2709,6 +2743,7 @@ index 0000000000000000000000000000000000000000..a1289865858f405f93d3d396f41c6a0a
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ logger.debug('New connection', field('token', token));
|
||||
+ protocol.sendMessage(await ok());
|
||||
+
|
||||
+ let connection: Connection;
|
||||
@@ -2727,12 +2762,14 @@ index 0000000000000000000000000000000000000000..a1289865858f405f93d3d396f41c6a0a
|
||||
+ connection = new ExtensionHostConnection(
|
||||
+ message.args ? message.args.language : 'en',
|
||||
+ protocol, buffer, token,
|
||||
+ this.services.get(ILogService) as ILogService,
|
||||
+ this.services.get(IEnvironmentService) as INativeEnvironmentService,
|
||||
+ );
|
||||
+ }
|
||||
+ connections.set(token, connection);
|
||||
+ connection.onClose(() => connections.delete(token));
|
||||
+ connection.onClose(() => {
|
||||
+ logger.debug('Connection closed', field('token', token));
|
||||
+ connections.delete(token);
|
||||
+ });
|
||||
+ this.disposeOldOfflineConnections(connections);
|
||||
+ break;
|
||||
+ case ConnectionType.Tunnel: return protocol.tunnel();
|
||||
@@ -2744,6 +2781,7 @@ index 0000000000000000000000000000000000000000..a1289865858f405f93d3d396f41c6a0a
|
||||
+ const offline = Array.from(connections.values())
|
||||
+ .filter((connection) => typeof connection.offline !== 'undefined');
|
||||
+ for (let i = 0, max = offline.length - this.maxExtraOfflineConnections; i < max; ++i) {
|
||||
+ logger.debug('Disposing offline connection', field("token", offline[i].token));
|
||||
+ offline[i].dispose();
|
||||
+ }
|
||||
+ }
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
- [Build](#build)
|
||||
- [Structure](#structure)
|
||||
- [VS Code Patch](#vs-code-patch)
|
||||
- [Currently Known Issues](#currently-known-issues)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
@@ -15,24 +16,26 @@
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Please link to the issue each PR solves.
|
||||
If there is no existing issue, please first create one unless the fix is minor.
|
||||
Please create a [GitHub Issue](https://github.com/cdr/code-server/issues) for each issue
|
||||
you'd like to address unless the proposed fix is minor.
|
||||
|
||||
Please make sure the base of your PR is the master branch. We keep the GitHub
|
||||
default branch the latest release branch to avoid confusion as the
|
||||
documentation is on GitHub and we don't want users to see docs on unreleased
|
||||
features.
|
||||
In your Pull Requests (PR), link to the issue that the PR solves.
|
||||
|
||||
Please ensure that the base of your PR is the **master** branch. (Note: The default
|
||||
GitHub branch is the latest release branch, though you should point all of your changes to be merged into
|
||||
master).
|
||||
|
||||
## Requirements
|
||||
|
||||
Please refer to [VS Code's prerequisites](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites).
|
||||
The prerequisites for contributing to code-server are almost the same as those for
|
||||
[VS Code](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites).
|
||||
There are several differences, however. You must:
|
||||
|
||||
Differences:
|
||||
- Use Node.js version 12.x (or greater)
|
||||
- Have [nfpm](https://github.com/goreleaser/nfpm) (which is used to build `.deb` and `.rpm` packages and [jq](https://stedolan.github.io/jq/) (used to build code-server releases) installed
|
||||
|
||||
- We require a minimum of node v12 but later versions should work.
|
||||
- We use [nfpm](https://github.com/goreleaser/nfpm) to build `.deb` and `.rpm` packages.
|
||||
- We use [jq](https://stedolan.github.io/jq/) to build code-server releases.
|
||||
- The [CI container](../ci/images/debian10/Dockerfile) is a useful reference for all our dependencies.
|
||||
The [CI container](../ci/images/debian8/Dockerfile) is a useful reference for all
|
||||
of the dependencies code-server uses.
|
||||
|
||||
## Development Workflow
|
||||
|
||||
@@ -40,10 +43,10 @@ Differences:
|
||||
yarn
|
||||
yarn vscode
|
||||
yarn watch
|
||||
# Visit http://localhost:8080 once the build completed.
|
||||
# Visit http://localhost:8080 once the build is completed.
|
||||
```
|
||||
|
||||
To develop inside of an isolated docker container:
|
||||
To develop inside an isolated Docker container:
|
||||
|
||||
```shell
|
||||
./ci/dev/image/run.sh yarn
|
||||
@@ -53,12 +56,12 @@ To develop inside of an isolated docker container:
|
||||
|
||||
`yarn watch` will live reload changes to the source.
|
||||
|
||||
If changes are made to the patch and you've built previously you must manually
|
||||
reset VS Code then run `yarn vscode:patch`.
|
||||
If you introduce changes to the patch and you've previously built, you
|
||||
must (1) manually reset VS Code and (2) run `yarn vscode:patch`.
|
||||
|
||||
## Build
|
||||
|
||||
You can build with:
|
||||
You can build using:
|
||||
|
||||
```shell
|
||||
./ci/dev/image/run.sh ./ci/steps/release.sh
|
||||
@@ -66,22 +69,22 @@ You can build with:
|
||||
|
||||
Run your build with:
|
||||
|
||||
```
|
||||
```shell
|
||||
cd release
|
||||
yarn --production
|
||||
# Runs the built JavaScript with Node.
|
||||
node .
|
||||
```
|
||||
|
||||
Build release packages (make sure you run `./ci/steps/release.sh` first):
|
||||
Build the release packages (make sure that you run `./ci/steps/release.sh` first):
|
||||
|
||||
```
|
||||
```shell
|
||||
IMAGE=centos7 ./ci/dev/image/run.sh ./ci/steps/release-packages.sh
|
||||
# The standalone release is in ./release-standalone
|
||||
# .deb, .rpm and the standalone archive are in ./release-packages
|
||||
```
|
||||
|
||||
The `release.sh` script is the equivalent of:
|
||||
The `release.sh` script is equal to running:
|
||||
|
||||
```shell
|
||||
yarn
|
||||
@@ -91,73 +94,69 @@ yarn build:vscode
|
||||
yarn release
|
||||
```
|
||||
|
||||
And `release-packages.sh` is:
|
||||
And `release-packages.sh` is equal to:
|
||||
|
||||
```
|
||||
```shell
|
||||
yarn release:standalone
|
||||
yarn test:standalone-release
|
||||
yarn package
|
||||
```
|
||||
|
||||
For a faster release build you can also run:
|
||||
For a faster release build, you can run instead:
|
||||
|
||||
```
|
||||
```shell
|
||||
KEEP_MODULES=1 ./ci/steps/release.sh
|
||||
node ./release
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
The `code-server` script serves an HTTP API to login and start a remote VS Code process.
|
||||
The `code-server` script serves an HTTP API for login and starting a remote VS Code process.
|
||||
|
||||
The CLI code is in [./src/node](./src/node) and the HTTP routes are implemented in
|
||||
[./src/node/app](./src/node/app).
|
||||
|
||||
Most of the meaty parts are in our VS Code patch which is described next.
|
||||
Most of the meaty parts are in the VS Code patch, which we described next.
|
||||
|
||||
### VS Code Patch
|
||||
|
||||
Back in v1 of code-server, we had an extensive patch of VS Code that split the codebase
|
||||
into a frontend and server. The frontend consisted of all UI code and the server ran
|
||||
the extensions and exposed an API to the frontend for file access and everything else
|
||||
that the UI needed.
|
||||
In v1 of code-server, we had a patch of VS Code that split the codebase into a front-end
|
||||
and a server. The front-end consisted of all UI code, while the server ran the extensions
|
||||
and exposed an API to the front-end for file access and all UI needs.
|
||||
|
||||
This worked but eventually Microsoft added support to VS Code to run it in the web.
|
||||
They have open sourced the frontend but have kept the server closed source.
|
||||
|
||||
So in interest of piggy backing off their work, v2 and beyond use the VS Code
|
||||
web frontend and fill in the server. This is contained in our
|
||||
Over time, Microsoft added support to VS Code to run it on the web. They have made
|
||||
the front-end open source, but not the server. As such, code-server v2 (and later) uses
|
||||
the VS Code front-end and implements the server. You can find this in
|
||||
[./ci/dev/vscode.patch](../ci/dev/vscode.patch) under the path `src/vs/server`.
|
||||
|
||||
Other notable changes in our patch include:
|
||||
|
||||
- Add our own build file which includes our code and VS Code's web code.
|
||||
- Allow multiple extension directories (both user and built-in).
|
||||
- Modify the loader, websocket, webview, service worker, and asset requests to
|
||||
use the URL of the page as a base (and TLS if necessary for the websocket).
|
||||
- Send client-side telemetry through the server.
|
||||
- Allow modification of the display language.
|
||||
- Make it possible for us to load code on the client.
|
||||
- Make extensions work in the browser.
|
||||
- Make it possible to install extensions of any kind.
|
||||
- Fix getting permanently disconnected when you sleep or hibernate for a while.
|
||||
- Add connection type to web socket query parameters.
|
||||
- Adding our build file, which includes our code and VS Code's web code
|
||||
- Allowing multiple extension directories (both user and built-in)
|
||||
- Modifying the loader, websocket, webview, service worker, and asset requests to
|
||||
use the URL of the page as a base (and TLS, if necessary for the websocket)
|
||||
- Sending client-side telemetry through the server
|
||||
- Allowing modification of the display language
|
||||
- Making it possible for us to load code on the client
|
||||
- Making extensions work in the browser
|
||||
- Making it possible to install extensions of any kind
|
||||
- Fixing issue with getting disconnected when your machine sleeps or hibernates
|
||||
- Adding connection type to web socket query parameters
|
||||
|
||||
Some known issues presently:
|
||||
|
||||
- Creating custom VS Code extensions and debugging them doesn't work.
|
||||
- Extension profiling and tips are currently disabled.
|
||||
|
||||
As the web portion of VS Code matures, we'll be able to shrink and maybe even entirely
|
||||
eliminate our patch. In the meantime, however, upgrading the VS Code version requires
|
||||
ensuring that the patch still applies and has the intended effects.
|
||||
|
||||
To generate a new patch run `yarn vscode:diff`.
|
||||
|
||||
**note**: We have extension docs on the CI and build system at [./ci/README.md](../ci/README.md)
|
||||
|
||||
If functionality doesn't depend on code from VS Code then it should be moved
|
||||
into code-server otherwise it should be in the patch.
|
||||
|
||||
In the future we'd like to run VS Code unit tests against our builds to ensure features
|
||||
As the web portion of VS Code matures, we'll be able to shrink and possibly
|
||||
eliminate our patch. In the meantime, upgrading the VS Code version requires
|
||||
us to ensure that the patch is applied and works as intended. In the future,
|
||||
we'd like to run VS Code unit tests against our builds to ensure that features
|
||||
work as expected.
|
||||
|
||||
To generate a new patch, run `yarn vscode:diff`
|
||||
|
||||
**Note**: We have [extension docs](../ci/README.md) on the CI and build system.
|
||||
|
||||
If the functionality you're working on does NOT depend on code from VS Code, please
|
||||
move it out and into code-server.
|
||||
|
||||
### Currently Known Issues
|
||||
|
||||
- Creating custom VS Code extensions and debugging them doesn't work
|
||||
- Extension profiling and tips are currently disabled
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "code-server",
|
||||
"license": "MIT",
|
||||
"version": "3.6.1",
|
||||
"version": "3.6.2",
|
||||
"description": "Run VS Code on a remote server.",
|
||||
"homepage": "https://github.com/cdr/code-server",
|
||||
"bugs": {
|
||||
|
||||
@@ -50,12 +50,15 @@ export class VscodeHttpProvider extends HttpProvider {
|
||||
|
||||
logger.debug("setting up vs code...")
|
||||
return new Promise<WorkbenchOptions>((resolve, reject) => {
|
||||
vscode.once("message", (message: VscodeMessage) => {
|
||||
logger.debug("got message from vs code", field("message", message))
|
||||
return message.type === "options" && message.id === id
|
||||
? resolve(message.options)
|
||||
: reject(new Error("Unexpected response during initialization"))
|
||||
})
|
||||
const onMessage = (message: VscodeMessage) => {
|
||||
// There can be parallel initializations so wait for the right ID.
|
||||
if (message.type === "options" && message.id === id) {
|
||||
logger.trace("got message from vs code", field("message", message))
|
||||
vscode.off("message", onMessage)
|
||||
resolve(message.options)
|
||||
}
|
||||
}
|
||||
vscode.on("message", onMessage)
|
||||
vscode.once("error", reject)
|
||||
vscode.once("exit", (code) => reject(new Error(`VS Code exited unexpectedly with code ${code}`)))
|
||||
this.send({ type: "init", id, options }, vscode)
|
||||
@@ -77,7 +80,7 @@ export class VscodeHttpProvider extends HttpProvider {
|
||||
|
||||
this._vscode = new Promise((resolve, reject) => {
|
||||
vscode.once("message", (message: VscodeMessage) => {
|
||||
logger.debug("got message from vs code", field("message", message))
|
||||
logger.trace("got message from vs code", field("message", message))
|
||||
return message.type === "ready"
|
||||
? resolve(vscode)
|
||||
: reject(new Error("Unexpected response waiting for ready response"))
|
||||
|
||||
@@ -738,6 +738,8 @@ export class HttpServer {
|
||||
}
|
||||
|
||||
private onUpgrade = async (request: http.IncomingMessage, socket: net.Socket, head: Buffer): Promise<void> => {
|
||||
socket.pause()
|
||||
|
||||
try {
|
||||
this.heart.beat()
|
||||
socket.on("error", () => socket.destroy())
|
||||
|
||||
Reference in New Issue
Block a user