forked from authgear/authgear-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwebsocket.ts
More file actions
118 lines (101 loc) · 3.08 KB
/
websocket.ts
File metadata and controls
118 lines (101 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { Controller } from "@hotwired/stimulus";
import { visit } from "@hotwired/turbo";
import { RetryEventTarget } from "./retry";
function refreshPage() {
let url = window.location.pathname;
if (window.location.search !== "") {
url += window.location.search;
}
if (window.location.hash !== "") {
url += window.location.hash;
}
visit(url, { action: "replace" });
}
export class WebSocketController extends Controller {
ws: WebSocket | null = null;
abortController: AbortController | null = null;
retryEventTarget: RetryEventTarget | null = null;
dispose = () => {
if (this.ws != null) {
this.ws.onclose = () => {};
this.ws.close();
}
this.ws = null;
};
refreshIfNeeded = () => {
const ele = document.querySelector('[data-is-refresh-link="true"]');
if (ele) {
// if there is refresh link in the page, don't refresh automatically
return;
}
const btn = document.querySelector('[data-submit-when-refresh="true"]');
if (btn instanceof HTMLElement) {
btn.click();
return;
}
refreshPage();
};
connectWebSocket = (isReconnect: boolean) => {
const scheme = window.location.protocol === "https:" ? "wss:" : "ws:";
const host = window.location.host;
var meta: HTMLMetaElement | null = document.querySelector(
'meta[name="x-authgear-page-loaded-at"]'
);
let sessionUpdatedAfter = "";
if (meta != null) {
sessionUpdatedAfter = meta.content || "";
}
// We only pass session_updated_after in case of reconnection.
// If we also pass session_updated_after in first connection,
// we will receive a refresh message which will refresh the page immediately.
// This will cause the page to load twice.
const url =
`${scheme}//${host}/_internals/ws` +
(isReconnect && sessionUpdatedAfter != ""
? `?session_updated_after=${sessionUpdatedAfter}`
: "");
this.ws = new WebSocket(url);
this.ws.onopen = (e) => {
console.log("ws onopen", e);
this.retryEventTarget?.markSuccess();
};
this.ws.onclose = (e) => {
console.log("ws onclose", e);
// Close code 1000 means we do not need to reconnect.
if (e.code === 1000) {
return;
}
this.retryEventTarget?.scheduleRetry();
};
this.ws.onerror = (e) => {
console.error("ws onerror", e);
};
this.ws.onmessage = (e) => {
console.log("ws onmessage", e);
const message = JSON.parse(e.data);
switch (message.kind) {
case "refresh":
this.refreshIfNeeded();
}
};
};
connect() {
this.abortController = new AbortController();
this.retryEventTarget = new RetryEventTarget({
abortController: this.abortController,
});
this.retryEventTarget.addEventListener("retry", () => {
this.dispose();
this.connectWebSocket(true);
});
this.connectWebSocket(false);
}
disconnect() {
this.dispose();
if (this.abortController != null) {
this.abortController.abort();
}
this.abortController = null;
this.retryEventTarget = null;
}
}