refactor: replace fetch SSE with original EventSource

This commit is contained in:
Tristan Yang
2022-10-24 22:20:15 +08:00
parent 18813a9ebb
commit 1b29f84cfa
3 changed files with 179 additions and 227 deletions
+1 -2
View File
@@ -1,12 +1,11 @@
{
"name": "vocechat-web",
"version": "0.3.11",
"version": "0.3.12",
"private": true,
"homepage": "https://voce.chat",
"dependencies": {
"@emoji-mart/data": "^1.0.6",
"@metamask/onboarding": "^1.0.1",
"@microsoft/fetch-event-source": "^2.0.1",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.8",
"@react-oauth/google": "^0.2.8",
"@reduxjs/toolkit": "^1.8.6",
+24 -66
View File
@@ -1,5 +1,4 @@
import { useEffect, useState } from "react";
import { fetchEventSource, EventStreamContentType } from "@microsoft/fetch-event-source";
import toast from "react-hot-toast";
import BASE_URL from "../../../app/config";
import { setReady } from "../../../app/slices/ui";
@@ -22,10 +21,6 @@ import chatMessageHandler from "./chat.handler";
import store, { useAppDispatch, useAppSelector } from "../../../app/store";
import { ServerEvent, UsersStateEvent } from "../../../types/sse";
class RetryError extends Error { }
class FatalError extends Error { }
const getQueryString = (params: { [key: string]: string }) => {
const sp = new URLSearchParams();
Object.entries(params).forEach(([key, val]) => {
@@ -36,7 +31,7 @@ const getQueryString = (params: { [key: string]: string }) => {
return sp.toString();
};
let inter: number | null = null;
let SSE: EventSource | null = null;
export default function useStreaming() {
const [readyPullData, setReadyPullData] = useState(false);
const {
@@ -48,9 +43,8 @@ export default function useStreaming() {
const loginUid = authData.user?.uid || 0;
let initialized = false;
let initializing = false;
let controller = new AbortController();
const startStreaming = async () => {
const startStreaming = () => {
console.info("sse start streaming", initialized, initializing);
if (initialized || initializing) return;
// 如果token快要过期,先renew
@@ -80,35 +74,30 @@ export default function useStreaming() {
if (usersVersion !== 0) {
params.users_version = `${usersVersion}`;
}
await fetchEventSource(`${BASE_URL}/user/events?${getQueryString(params)}`, {
openWhenHidden: true,
signal: controller.signal,
async onopen(response) {
// 开始初始化推送
SSE = new EventSource(`${BASE_URL}/user/events?${getQueryString(params)}`);
SSE.onopen = () => {
initializing = false;
if (response.ok && response.headers.get("content-type") === EventStreamContentType) {
console.info("sse everything ok");
initialized = true;
return; // everything's good
} else if (response.status >= 400 && response.status < 500 && response.status !== 429) {
// 重新登录
// client-side errors are usually non-retriable:
console.info("sse debug: open fatal");
throw new FatalError();
} else {
// server error
console.info("sse debug: open retry");
throw new RetryError();
};
SSE.onerror = (err) => {
console.error("sse error", err);
initializing = false;
stopStreaming();
if (inter) {
clearTimeout(inter);
}
},
onmessage(evt) {
// 重连
inter = window.setTimeout(() => {
initialized = false;
startStreaming();
}, 2000);
};
SSE.onmessage = (evt) => {
initializing = false;
console.info("sse message", evt.data);
// if the server emits an error message, throw an exception
// so it gets handled by the onerror callback below:
if (evt.event === "FatalError") {
console.info("sse debug: error message fatal");
throw new FatalError(evt.data);
}
const data: ServerEvent = JSON.parse(evt.data);
const { type } = data;
switch (type) {
@@ -274,44 +263,13 @@ export default function useStreaming() {
console.info("sse event data", data);
break;
}
},
onclose() {
// if the server closes the connection unexpectedly, retry:
console.info("sse debug: closed");
initializing = false;
throw new RetryError();
},
onerror(err) {
initializing = false;
if (err instanceof FatalError || err.toString().indexOf("network error") > -1) {
console.info("sse debug: error fatal", err);
throw err; // rethrow to stop the operation
} else {
console.info("sse debug: error other", err);
stopStreaming();
if (inter) {
clearTimeout(inter);
}
// 重连
inter = window.setTimeout(() => {
initialized = false;
startStreaming();
}, 2000);
throw err; // rethrow to stop the operation
// do nothing to automatically retry. You can also
// return a specific retry interval here.
}
}
});
initializing = false;
// for controlling
return controller;
};
};
const stopStreaming = () => {
console.info("sse stop streaming");
if (controller && controller.abort) {
controller.abort();
if (SSE) {
SSE.close();
}
};
-5
View File
@@ -2296,11 +2296,6 @@
dependencies:
bowser "^2.9.0"
"@microsoft/fetch-event-source@^2.0.1":
version "2.0.1"
resolved "https://mirrors.cloud.tencent.com/npm/@microsoft%2ffetch-event-source/-/fetch-event-source-2.0.1.tgz#9ceecc94b49fbaa15666e38ae8587f64acce007d"
integrity sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==
"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1":
version "5.1.1-v1"
resolved "https://mirrors.cloud.tencent.com/npm/@nicolo-ribaudo%2feslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129"