Skip to content

Commit

Permalink
Initial simple cloud-shell frontend (#64)
Browse files Browse the repository at this point in the history
* Initial simple cloud-shell frontend

Signed-off-by: Oleksandr Andriienko <oandriie@redhat.com>

* Address changes

Signed-off-by: Oleksandr Andriienko <oandriie@redhat.com>
  • Loading branch information
AndrienkoAleksandr authored Jan 2, 2020
1 parent c17780c commit 78d10e9
Show file tree
Hide file tree
Showing 13 changed files with 4,123 additions and 1 deletion.
14 changes: 13 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,22 @@ RUN adduser -D -g '' unprivilegeduser && \
cp -rf /etc/ssl/certs/ca-certificates.crt /rootfs/etc/ssl/certs && \
cp -rf /go/src/github.com/eclipse/che-machine-exec/che-machine-exec /rootfs/go/bin

FROM node:10.16-alpine as frontend-builder

ARG SRC=/cloud-shell-src
ARG DIST=/cloud-shell

COPY cloud-shell ${SRC}
WORKDIR ${SRC}
RUN yarn && yarn run build && \
mkdir ${DIST} && \
cp -rf index.html dist node_modules ${DIST}

FROM scratch

COPY --from=builder /rootfs /
COPY --from=frontend-builder ${DIST} ${DIST}

USER unprivilegeduser

ENTRYPOINT ["/go/bin/che-machine-exec"]
ENTRYPOINT ["/go/bin/che-machine-exec", "--static", "/cloud-shell"]
2 changes: 2 additions & 0 deletions cloud-shell/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist
node_modules
4 changes: 4 additions & 0 deletions cloud-shell/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

### Cloud Shell

Cloud shell application provides simple terminal widget for development purpose.
20 changes: 20 additions & 0 deletions cloud-shell/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!--
Copyright (c) 2019 Red Hat, Inc.
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
which is available at https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
Contributors:
Red Hat, Inc. - initial API and implementation
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Cloud Shell</title>
</head>
<body>
<div id='terminal-container'></div>
<script src="./dist/bundle.js"></script>
</body>
</html>
28 changes: 28 additions & 0 deletions cloud-shell/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "cloud.shell",
"version": "0.1.0",
"description": "Che Cloud Shell Workspace",
"private": true,
"scripts": {
"build": "webpack --mode production",
"dev-build": "webpack --mode development"
},
"publisher": "Eclipse Che",
"author": "Oleksandr Andriienko",
"license": "EPL-2.0",
"devDependencies": {
"css-loader": "^0.28.9",
"style-loader": "^0.20.1",
"ts-loader": "^5.3.3",
"typescript": "3.4.5",
"webpack": "^4.0.0",
"webpack-cli": "^3.2.1"
},
"dependencies": {
"reconnecting-websocket": "^4.2.0",
"vscode-uri": "^2.1.1",
"vscode-ws-jsonrpc": "^0.1.1",
"xterm": "^4.3.0",
"xterm-addon-fit": "^0.3.0"
}
}
72 changes: 72 additions & 0 deletions cloud-shell/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2019 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/

import { CloudShellTerminal, TerminalHandler } from "./terminal";
import { JsonRpcConnection } from "./json-rpc-connection";
import { GenericNotificationHandler } from "vscode-jsonrpc";
import { MachineExec } from "./terminal-protocol";

const terminalElem = document.getElementById('terminal-container');

const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
const port = window.location.port ? `:${window.location.port}` : '';
const hostUrl = `${protocol}://${window.location.host}${port}`;
const connectUrl = hostUrl + '/connect';
const attachUrl = hostUrl + '/attach';

const terminal: CloudShellTerminal = new CloudShellTerminal();

terminal.open(terminalElem);
terminal.sendText('Welcome to the Cloud Shell.\n');

console.log(connectUrl);
const rpcConnecton = new JsonRpcConnection(connectUrl);
rpcConnecton.create().then(connection => {
connection.onNotification('connected', (handler: GenericNotificationHandler) => {
const exec: MachineExec = {
tty: true,
cols: terminal.cols,
rows: terminal.rows,
};

connection.sendRequest<{}>('create', exec).then((value: {}) => {
const id = value as number;
const attachConnection = rpcConnecton.createReconnectionWebsocket(`${attachUrl}/${id}`);

attachConnection.onopen = (event: Event) => {
// resize terminal first time on open
connection.sendRequest('resize', {cols: terminal.cols, rows: terminal.rows, id});

attachConnection.onmessage = (event: MessageEvent) => {
terminal.sendText(event.data);
}

const terminalHandler: TerminalHandler = {
onData(data: string):void {
attachConnection.send(data);
},
onResize(cols: number, rows: number) {
connection.sendRequest('resize', {cols, rows, id});
}
}

terminal.addHandler(terminalHandler);
};
attachConnection.onerror = (errEvn: ErrorEvent) => {
console.log('Attach connection error: ', errEvn.error);
}
attachConnection.onclose = (event: CloseEvent) => {
console.log('Attach connection closed: ', event.code);
}
});
});
}).catch(err => {
console.log('Fatal. Unable to connect to container.', err);
})
62 changes: 62 additions & 0 deletions cloud-shell/src/json-rpc-connection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2019 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/

import ReconnectingWebSocket from "reconnecting-websocket";
import { IWebSocket, ConsoleLogger, createWebSocketConnection, Logger, MessageConnection } from 'vscode-ws-jsonrpc';

export class JsonRpcConnection {

private logger: Logger;

constructor(readonly url: string) {
this.logger = new ConsoleLogger();
}

create(): Promise<MessageConnection> {
return new Promise<MessageConnection>((resolve, reject) => {
const websocket = this.createReconnectionWebsocket(this.url);

websocket.onopen = () => {
const iWebSocket = this.toIWebSocket(websocket);
const rpcConnection = createWebSocketConnection(iWebSocket, this.logger);

rpcConnection.listen();
resolve(rpcConnection);
}

websocket.onerror = (err: ErrorEvent) => {
reject(`Websocket connection closed with an error: ${err}`);
}
});
}

private toIWebSocket(webSocket: ReconnectingWebSocket): IWebSocket {
return {
send: content => webSocket.send(content),
onMessage: callback => webSocket.onmessage = (msgEvent: MessageEvent) => callback(msgEvent.data),
onError: callback => webSocket.onerror = error => callback(error.message),
onClose: callback => webSocket.onclose = (event: CloseEvent) => callback(event.code, event.reason),
dispose: () => webSocket.close()
};
}

public createReconnectionWebsocket(url: string): ReconnectingWebSocket {
return new ReconnectingWebSocket(
url,
undefined, {
maxReconnectionDelay: 10000,
minReconnectionDelay: 1000,
reconnectionDelayGrowFactor: 1.3,
connectionTimeout: 10000,
maxRetries: Infinity,
debug: false
});
}
}
32 changes: 32 additions & 0 deletions cloud-shell/src/terminal-protocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2019 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/

export interface MachineIdentifier {
machineName: string,
workspaceId: string
}

export interface MachineExec {
identifier?: MachineIdentifier,
cmd?: string[],
tty: boolean,
cols: number,
rows: number,
id?: number
}

export interface IdParam {
id: number
}

export interface ResizeParam extends IdParam {
rows: number,
cols: number
}
72 changes: 72 additions & 0 deletions cloud-shell/src/terminal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2019 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/

import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit';
import '../styles.css';
import 'xterm/css/xterm.css';

export interface TerminalHandler {
onData(data: string): void;
onResize(cols: number, rows: number): void;
}

export class CloudShellTerminal {

private xterm: Terminal;

private fitAddon: FitAddon;
private resizeTimeout: any;

constructor() {
this.xterm = new Terminal();

// todo remove after debug;
(window as any).xterm = this.xterm;

// load xterm addons.
this.fitAddon = new FitAddon();
this.xterm.loadAddon(this.fitAddon);

window.addEventListener("resize", () => {
this.fitAddon.fit();
}, false);
}

addHandler(terminalHandler: TerminalHandler) {
this.xterm.onData((data) => {
terminalHandler.onData(data);
});
this.xterm.onResize((resizeEvent) => {
terminalHandler.onResize(resizeEvent.cols, resizeEvent.rows);
});
}

get cols(): number {
return this.xterm.cols;
}

get rows(): number {
return this.xterm.rows;
}

open(parent: HTMLElement) {
this.xterm.open(parent);
this.fitAddon.fit();
}

sendText(text: string) {
this.xterm.write(text);
}

dispose() {
this.xterm.dispose();
}
}
13 changes: 13 additions & 0 deletions cloud-shell/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
body {
position: absolute;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}

#terminal-container {
position: relative;
width: 100%;
height: 100%;
}
10 changes: 10 additions & 0 deletions cloud-shell/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es6",
"allowJs": true
}
}
34 changes: 34 additions & 0 deletions cloud-shell/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const path = require('path');

module.exports = {
entry: ['./src/index.ts'],
devtool: 'inline-source-map',
node: {
net: 'empty',
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}]
}
],
},
resolve: {
modules: ['./node_modules'],
extensions: [ '.tsx', '.ts', '.js', '.css', '.scss'],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
Loading

0 comments on commit 78d10e9

Please sign in to comment.