Skip to content

Commit fd92017

Browse files
akosyakovMatthewFagan
authored and
MatthewFagan
committed
fix gitpod-io#3847: reconnect ws to server in iframe
1 parent b40e222 commit fd92017

File tree

5 files changed

+45
-44
lines changed

5 files changed

+45
-44
lines changed

components/dashboard/src/Login.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import { AuthProviderInfo } from "@gitpod/gitpod-protocol";
88
import { useContext, useEffect, useState } from "react";
99
import { UserContext } from "./user-context";
10-
import { getGitpodService, gitpodHostUrl, reconnectGitpodService } from "./service/service";
10+
import { getGitpodService, gitpodHostUrl } from "./service/service";
1111
import { iconForAuthProvider, simplifyProviderName } from "./provider-utils";
1212
import gitpod from './images/gitpod.svg';
1313
import gitpodIcon from './icons/gitpod.svg';
@@ -58,7 +58,7 @@ export function Login() {
5858
// todo: not here, but add a button to the /login-success page to close, if this should not work as expected
5959
}
6060
(async () => {
61-
reconnectGitpodService();
61+
await getGitpodService().reconnect();
6262
setUser(await getGitpodService().server.getLoggedInUser());
6363
markLoggedIn();
6464
})();

components/dashboard/src/service/service.tsx

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ function createGitpodService<C extends GitpodClient, S extends GitpodServer>() {
1919
const factory = new JsonRpcProxyFactory<S>();
2020
const proxy = factory.createProxy();
2121
factory.listen(connection);
22-
return new GitpodServiceImpl<C, S>(proxy);
22+
return new GitpodServiceImpl<C, S>(proxy, {
23+
onReconnect: async () => {
24+
await connection.sendRequest('$reconnectServer');
25+
}
26+
});
2327
}
2428
let host = gitpodHostUrl
2529
.asWebsocket()
@@ -28,25 +32,20 @@ function createGitpodService<C extends GitpodClient, S extends GitpodServer>() {
2832

2933
const connectionProvider = new WebSocketConnectionProvider();
3034
let numberOfErrors = 0;
31-
const { proxy, webSocket } = connectionProvider.createProxy2<S>(host.toString(), undefined, {
35+
let onReconnect = () => { };
36+
const proxy = connectionProvider.createProxy<S>(host.toString(), undefined, {
3237
onerror: (event: any) => {
3338
log.error(event);
3439
if (numberOfErrors++ === 5) {
3540
alert('We are having trouble connecting to the server.\nEither you are offline or websocket connections are blocked.');
3641
}
42+
},
43+
onListening: socket => {
44+
onReconnect = () => socket.reconnect()
3745
}
3846
});
3947

40-
const service = new GitpodServiceImpl<C, S>(proxy);
41-
(service as any).reconnect = () => {
42-
const ws = (webSocket as any);
43-
if (typeof ws.reconnect === "function") {
44-
ws.reconnect();
45-
} else {
46-
console.log("WebSocket reconnect not possible.");
47-
}
48-
};
49-
return service;
48+
return new GitpodServiceImpl<C, S>(proxy, { onReconnect });
5049
}
5150

5251
function getGitpodService(): GitpodService {
@@ -56,13 +55,4 @@ function getGitpodService(): GitpodService {
5655
return service;
5756
}
5857

59-
function reconnectGitpodService() {
60-
const service = getGitpodService() as any;
61-
if (service.reconnect) {
62-
service.reconnect();
63-
} else {
64-
console.error("WebSocket reconnect not possible.")
65-
}
66-
}
67-
68-
export { getGitpodService, reconnectGitpodService }
58+
export { getGitpodService }

components/gitpod-protocol/src/gitpod-service.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
User, WorkspaceInfo, WorkspaceCreationResult, UserMessage, WorkspaceInstanceUser,
99
WhitelistedRepository, WorkspaceImageBuild, AuthProviderInfo, Branding, CreateWorkspaceMode,
1010
Token, UserEnvVarValue, ResolvePluginsParams, PreparePluginUploadParams, Terms,
11-
ResolvedPlugins, Configuration, InstallPluginsParams, UninstallPluginParams, UserInfo, GitpodTokenType,
11+
ResolvedPlugins, Configuration, InstallPluginsParams, UninstallPluginParams, UserInfo, GitpodTokenType,
1212
GitpodToken, AuthProviderEntry, GuessGitTokenScopesParams, GuessedGitTokenScopes
1313
} from './protocol';
1414
import { JsonRpcProxy, JsonRpcServer } from './messaging/proxy-factory';
@@ -189,7 +189,7 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
189189
tsGetSlots(): Promise<TeamSubscriptionSlotResolved[]>;
190190
tsGetUnassignedSlot(teamSubscriptionId: string): Promise<TeamSubscriptionSlot | undefined>
191191
tsAddSlots(teamSubscriptionId: string, quantity: number): Promise<void>;
192-
tsAssignSlot(teamSubscriptionId: string, teamSubscriptionSlotId: string, identityStr: string|undefined): Promise<void>
192+
tsAssignSlot(teamSubscriptionId: string, teamSubscriptionSlotId: string, identityStr: string | undefined): Promise<void>
193193
tsReassignSlot(teamSubscriptionId: string, teamSubscriptionSlotId: string, newIdentityStr: string): Promise<void>;
194194
tsDeactivateSlot(teamSubscriptionId: string, teamSubscriptionSlotId: string): Promise<void>;
195195
tsReactivateSlot(teamSubscriptionId: string, teamSubscriptionSlotId: string): Promise<void>;
@@ -402,7 +402,7 @@ export class WorkspaceInstanceUpdateListener {
402402
private readonly onDidChangeEmitter = new Emitter<void>();
403403
readonly onDidChange = this.onDidChangeEmitter.event;
404404

405-
private source: 'sync' | 'update' = 'sync';
405+
private source: 'sync' | 'update' = 'sync';
406406

407407
get info(): WorkspaceInfo {
408408
return this._info;
@@ -494,11 +494,15 @@ export class WorkspaceInstanceUpdateListener {
494494

495495
}
496496

497+
export interface GitpodServiceOptions {
498+
onReconnect?: () => (void | Promise<void>)
499+
}
500+
497501
export class GitpodServiceImpl<Client extends GitpodClient, Server extends GitpodServer> {
498502

499503
private readonly compositeClient = new GitpodCompositeClient<Client>();
500504

501-
constructor(public readonly server: JsonRpcProxy<Server>) {
505+
constructor(public readonly server: JsonRpcProxy<Server>, private options?: GitpodServiceOptions) {
502506
server.setClient(this.compositeClient);
503507
server.onDidOpenConnection(() => this.compositeClient.notifyDidOpenConnection());
504508
server.onDidCloseConnection(() => this.compositeClient.notifyDidCloseConnection());
@@ -518,6 +522,12 @@ export class GitpodServiceImpl<Client extends GitpodClient, Server extends Gitpo
518522
this.instanceListeners.set(workspaceId, listener);
519523
return listener;
520524
}
525+
526+
async reconnect(): Promise<void> {
527+
if (this.options?.onReconnect) {
528+
await this.options.onReconnect();
529+
}
530+
}
521531
}
522532

523533
export function createGitpodService<C extends GitpodClient, S extends GitpodServer>(serverUrl: string | Promise<string>) {
@@ -535,6 +545,11 @@ export function createGitpodService<C extends GitpodClient, S extends GitpodServ
535545
}
536546

537547
const connectionProvider = new WebSocketConnectionProvider();
538-
const gitpodServer = connectionProvider.createProxy<S>(url);
539-
return new GitpodServiceImpl<C, S>(gitpodServer);
548+
let onReconnect = () => { };
549+
const gitpodServer = connectionProvider.createProxy<S>(url, undefined, {
550+
onListening: socket => {
551+
onReconnect = () => socket.reconnect();
552+
}
553+
});
554+
return new GitpodServiceImpl<C, S>(gitpodServer, { onReconnect });
540555
}

components/gitpod-protocol/src/messaging/browser/connection.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import ReconnectingWebSocket from 'reconnecting-websocket';
1212

1313
export interface WebSocketOptions {
1414
onerror?: (event: Event) => void;
15+
onListening?: (socket: ReconnectingWebSocket) => void;
1516
}
1617

1718
export class WebSocketConnectionProvider {
@@ -26,30 +27,24 @@ export class WebSocketConnectionProvider {
2627
createProxy<T extends object>(path: string | Promise<string>, target?: object, options?: WebSocketOptions): JsonRpcProxy<T> {
2728
const factory = new JsonRpcProxyFactory<T>(target);
2829
const startListening = (path: string) => {
29-
this.listen({
30-
path,
31-
onConnection: c => factory.listen(c)
32-
},
30+
const socket = this.listen({
31+
path,
32+
onConnection: c => factory.listen(c)
33+
},
3334
options
3435
);
36+
if (options?.onListening) {
37+
options.onListening(socket as any as ReconnectingWebSocket)
38+
}
3539
};
36-
40+
3741
if (typeof path === "string") {
3842
startListening(path);
3943
} else {
4044
path.then(path => startListening(path));
4145
}
4246
return factory.createProxy();
4347
}
44-
createProxy2<T extends object>(path: string, target?: object, options?: WebSocketOptions): { proxy: JsonRpcProxy<T>, webSocket: WebSocket } {
45-
const factory = new JsonRpcProxyFactory<T>(target);
46-
const webSocket = this.listen({
47-
path,
48-
onConnection: c => factory.listen(c)
49-
}, options);
50-
const proxy = factory.createProxy();
51-
return { proxy, webSocket };
52-
}
5348

5449
/**
5550
* Install a connection handler for the given path.

components/supervisor/frontend/src/shared/loading-frame.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export function load({ gitpodService }: {
4040
const frameWindow = frame.contentWindow!;
4141
const writer = new WindowMessageWriter('gitpodServer', frameWindow, serverOrigin);
4242
const connection = createMessageConnection(reader, writer, new ConsoleLogger())
43+
connection.onRequest('$reconnectServer', () => gitpodService.reconnect());
4344
factory.listen(connection);
4445
const setState = (state: object) => {
4546
frameWindow.postMessage({ type: 'setState', state }, serverOrigin);

0 commit comments

Comments
 (0)