diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 06109895..bc7d2b35 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -9,10 +9,12 @@ import { AuthGuard } from './auth.guard';
import { StepComponent } from './scenario/step.component';
import { PrintableComponent } from './printable/printable.component';
import { GuacTerminalComponent } from './scenario/guacTerminal.component';
+import { WebsocketTestComponent } from './websocket-test/websockettest.component';
const routes: Routes = [
{ path: '', redirectTo: '/app/home', pathMatch: 'full' },
{ path: 'login', component: LoginComponent },
+ { path: 'test/:url', component: WebsocketTestComponent },
{
path: 'add/:accesscode',
component: AppComponent,
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 1d10825e..4ac9b527 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -48,6 +48,7 @@ import { VerificationService } from './services/verification.service';
import { TaskProgressComponent } from './scenario/task-progress/task-progress.component';
import { TaskModalComponent } from './scenario/task-modal/task-modal.component';
import { SingleTaskVerificationMarkdownComponent } from './hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component';
+import { WebsocketTestComponent } from './websocket-test/websockettest.component';
import '@cds/core/icon/register.js';
import {
ClarityIcons,
@@ -171,6 +172,7 @@ export function jwtOptionsFactory() {
TaskProgressComponent,
TaskModalComponent,
SingleTaskVerificationMarkdownComponent,
+ WebsocketTestComponent,
],
imports: [
BrowserModule,
diff --git a/src/app/websocket-test/websockettest.component.css b/src/app/websocket-test/websockettest.component.css
new file mode 100644
index 00000000..a7835876
--- /dev/null
+++ b/src/app/websocket-test/websockettest.component.css
@@ -0,0 +1,8 @@
+as-split-area {
+ margin-left: 10px;
+}
+
+.success {
+ color: green;
+ font-weight: bold;
+}
diff --git a/src/app/websocket-test/websockettest.component.html b/src/app/websocket-test/websockettest.component.html
new file mode 100644
index 00000000..d7f3361a
--- /dev/null
+++ b/src/app/websocket-test/websockettest.component.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+ Websocket Tester
+ This page is dedicated to test if the websocket for the shell proxy is
+ reachable. If it is reachable you should be able to see
+
+ - /healthz endpoint responding with 200
+ - Websocket being opened
+ - Client sending a ping
+ - Websocket responding with pong
+
+ Troubleshooting
+ If the /healthz endopoint is not responding you should check if the shell
+ proxy is up and running. Also verify that {{ endpoint }} is the correct
+ URL to the proxy. If the endpoint responds with 200 but the websocket is
+ not being opened, you should verify that no firewall is in place that
+ disallows the usage of websockets for {{ endpoint }}
+
+
+
+ Testing {{ target }}:
+
+
+
+ Check successfully completed and websocket reachable.
+
+
+
+
+
diff --git a/src/app/websocket-test/websockettest.component.ts b/src/app/websocket-test/websockettest.component.ts
new file mode 100644
index 00000000..5ed04870
--- /dev/null
+++ b/src/app/websocket-test/websockettest.component.ts
@@ -0,0 +1,78 @@
+import { HttpClient } from '@angular/common/http';
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { HfMarkdownRenderContext } from '../hf-markdown/hf-markdown.component';
+import { AppConfigService } from '../app-config.service';
+
+@Component({
+ selector: 'app-websockettest',
+ templateUrl: './websockettest.component.html',
+ styleUrls: ['./websockettest.component.css'],
+})
+export class WebsocketTestComponent implements OnInit {
+ target: string;
+ wsEndpoint: string;
+ endpoint: string;
+
+ completed: boolean;
+
+ mermaidString = 'sequenceDiagram';
+ markdownString = '';
+ mdContext: HfMarkdownRenderContext = { vmInfo: {}, session: '' };
+
+ private Config = this.config.getConfig();
+ public title = this.Config.title || "Rancher's Hobby Farm";
+
+ constructor(
+ private config: AppConfigService,
+ private route: ActivatedRoute,
+ private http: HttpClient,
+ ) {}
+ ngOnInit(): void {
+ this.target = this.route.snapshot.params['url'];
+ this.endpoint = 'https://' + this.target + '/shell/healthz';
+ this.wsEndpoint = 'wss://' + this.target + '/shell/websocketTest';
+ this.testConnection();
+ }
+
+ testConnection() {
+ this.addMermaidString('you', this.target, '/shell/healthz');
+ this.http.get(this.endpoint).subscribe({
+ next: () => {
+ this.addMermaidString(this.target, 'you', '200, OK');
+ this.testWSConnection();
+ },
+ error: (msg) => {
+ console.log(msg);
+ this.addMermaidString(this.target, 'you', msg.code);
+ },
+ });
+ }
+
+ testWSConnection() {
+ this.addMermaidString('you', this.target, 'open websocket', '+');
+ const socket = new WebSocket(this.wsEndpoint);
+ socket.onmessage = (event) => {
+ if (event.data == 'pong') {
+ this.addMermaidString(this.target, 'you', 'pong', '-');
+ this.completed = true;
+ }
+ };
+
+ socket.onopen = () => {
+ this.addMermaidString(this.target, 'you', 'websocket opened');
+ socket.send('ping');
+ this.addMermaidString('you', this.target, 'ping');
+ };
+ }
+
+ addMermaidString(
+ from: string,
+ to: string,
+ content: string,
+ opChar: string = '',
+ ) {
+ this.mermaidString += '\n ' + from + '->>' + opChar + to + ': ' + content;
+ this.markdownString = '```mermaid\n' + this.mermaidString + '\n```';
+ }
+}