Path: blob/main/components/supervisor/frontend/src/ide/ide-web-socket.ts
2501 views
/**1* Copyright (c) 2020 Gitpod GmbH. All rights reserved.2* Licensed under the GNU Affero General Public License (AGPL).3* See License.AGPL.txt in the project root for license information.4*/56import { serverUrl } from "../shared/urls";7import { metricsReporter } from "./ide-metrics-service-client";8import ReconnectingWebSocket from "reconnecting-websocket";9import { Disposable } from "@gitpod/gitpod-protocol/lib/util/disposable";1011let connected = false;12const workspaceSockets = new Set<IDEWebSocket>();1314const workspaceOrigin = new URL(window.location.href).origin;15const gitpodOrigin = new URL(serverUrl.toString()).origin;16const WebSocket = window.WebSocket;17function isWorkspaceOrigin(url: string): boolean {18const originUrl = new URL(url);19originUrl.protocol = window.location.protocol;20return originUrl.origin === workspaceOrigin;21}22function isLocalhostOrigin(url: string): boolean {23const originUrl = new URL(url);24originUrl.protocol = window.location.protocol;25return originUrl.hostname === "localhost";26}27function isGitpodOrigin(url: string): boolean {28const originUrl = new URL(url);29originUrl.protocol = window.location.protocol;30return originUrl.origin === gitpodOrigin;31}32/**33* IDEWebSocket is a proxy to standard WebSocket34* which allows to control when web sockets to the workspace35* should be opened or closed.36* It should not deviate from standard WebSocket in any other way.37*/38class IDEWebSocket extends ReconnectingWebSocket {39constructor(url: string, protocol?: string | string[]) {40super(url, protocol, {41WebSocket,42startClosed: isWorkspaceOrigin(url) && !connected,43maxRetries: 0,44connectionTimeout: 2147483647, // disable connection timeout, clients should handle it45});46let origin = "unknown";47if (isWorkspaceOrigin(url)) {48origin = "workspace";49workspaceSockets.add(this);50this.addEventListener("close", () => {51workspaceSockets.delete(this);52});53} else if (isLocalhostOrigin(url)) {54origin = "localhost";55} else if (isGitpodOrigin(url)) {56origin = "gitpod";57}58metricsReporter.instrumentWebSocket(this as any, origin);59}60static disconnectWorkspace(): void {61for (const socket of workspaceSockets) {62socket.close();63}64}65}6667export function install(): void {68window.WebSocket = IDEWebSocket as any;69}7071export function connectWorkspace(): Disposable {72if (connected) {73return Disposable.NULL;74}75connected = true;76for (const socket of workspaceSockets) {77socket.reconnect();78}79return Disposable.create(() => disconnectWorkspace());80}8182export function disconnectWorkspace(): void {83if (!connected) {84return;85}86connected = false;87for (const socket of workspaceSockets) {88socket.close();89}90}919293