Merge pull request #159 from jamebal/dev

perf: 优化SSE连接
This commit is contained in:
jmal 2024-06-05 21:42:11 +08:00 committed by GitHub
commit e8e5420cea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 90 additions and 75 deletions

View File

@ -132,7 +132,7 @@ export default {
// speedSmoothingFactor: 0.1,
// progressCallbacksInterval: 500,
maxChunkRetries: 3, // 最大重试次数
simultaneousUploads: 5, // 并发上传数
simultaneousUploads: 2, // 并发上传数
testChunks: true, // 是否开启服务器分片校验
// 服务器分片校验函数,秒传及断点续传基础
checkChunkUploadedByResponse: function (chunk, message) {
@ -204,7 +204,7 @@ export default {
message(msg) {
switch (msg.event) {
case 'uploaderChunkSize':
this.onStorageTypeChange(msg.data)
this.onStorageTypeChange(msg.data.body)
break
case 'fileListScrollTop':
this.fileListScrollTop = msg.data

View File

@ -43,7 +43,6 @@ export default {
},
watch: {
data(val) {
console.log('data', val)
this.dataList = val
},
message(msg) {

View File

@ -21,7 +21,7 @@ import ResizeMixin from './mixin/ResizeHandler'
import { getToken } from '@/utils/auth'
import AudioPreview from "@/components/preview/AudioPreview";
import globalUploader from '@/components/SimpleUploader/globalUploader.vue'
import { connectToSSE } from '@/sse/SSEClient'
import { initiateSSE } from '@/sse/SSEClient'
export default {
name: 'Layout',
@ -62,7 +62,7 @@ export default {
if(getToken()){
this.isShow = window.pc;
// 与服务器建立sse连接
connectToSSE(this.$store.state.user.name)
initiateSSE(this.$store.state.user.name)
if(this.$route.path.startsWith('/setting')){
this.isShow = true
}

View File

@ -1,92 +1,108 @@
import Bus from "@/assets/js/bus";
import _ from "lodash";
import store from "@/store";
import {generateUUID} from "ant-design-vue/lib/vc-select/util";
import { generateUUID } from "ant-design-vue/lib/vc-select/util";
let eventSource = null;
let timer = null;
let lastHeartbeat = new Date().getTime();
const uuid = generateUUID();
const throttledConnectSSE = _.throttle(username => {
if (typeof (EventSource) !== 'undefined') {
const url = `/api/events?username=${username}&uuid=${uuid}`;
eventSource = new EventSource(url);
eventSource.addEventListener('message', function (event) {
if (event.data === 'h') {
// 心跳包, 超过5s没有收到心跳包, 则关闭连接
lastHeartbeat = new Date().getTime()
} else {
const msg = JSON.parse( event.data);
onMessage(msg)
}
});
eventSource.addEventListener('error', function (event) {
eventSource.close()
connectToSSE(username);
});
// 清除定时器
if (timer) {
clearInterval(timer);
}
// 3s检测一次连接状态
timer = setInterval(() => {
if (eventSource.readyState === 1) {
// 心跳包, 超过5s没有收到心跳包, 则关闭连接
if (new Date().getTime() - lastHeartbeat > 5000) {
eventSource.close()
}
}
if (eventSource.readyState === 2) {
connectToSSE(username);
}
}, 3000);
const throttledConnectSSE = _.throttle((username) => {
if (typeof EventSource !== 'undefined') {
connectToSSE(username);
} else {
console.error('EventSource is not supported by the browser');
}
}, 3000);
export function connectToSSE(username) {
function connectToSSE(username) {
const url = `/api/events?username=${username}&uuid=${uuid}`;
eventSource = new EventSource(url);
eventSource.addEventListener('message', handleMessage);
eventSource.addEventListener('error', handleError.bind(null, username));
startHeartbeatCheck(username);
}
function handleMessage(event) {
if (event.data === 'h') {
lastHeartbeat = new Date().getTime();
} else {
const msg = JSON.parse(event.data);
onMessage(msg);
}
}
function handleError(username) {
eventSource.close();
throttledConnectSSE(username);
}
function clearExistingTimer() {
if (timer) {
clearInterval(timer);
}
}
function startHeartbeatCheck(username) {
clearExistingTimer();
timer = setInterval(() => {
if (eventSource.readyState === 1 && new Date().getTime() - lastHeartbeat > 5000) {
eventSource.close();
}
if (eventSource.readyState === 2) {
throttledConnectSSE(username);
}
}, 3000);
}
function onMessage(msg) {
const url = msg.url
if (url === 'synced') {
store.dispatch('updateMessage', {event: 'msg/synced', data: msg})
} else if (url === 'taskProgress') {
store.dispatch('updateMessage', {event: 'msg/taskProgress', data: msg})
} else if (url === 'uploaderChunkSize') {
store.dispatch('updateMessage', {event: 'uploaderChunkSize', data: msg.body})
const { url, body } = msg;
const eventMapping = {
synced: 'msg/synced',
taskProgress: 'msg/taskProgress',
uploaderChunkSize: 'uploaderChunkSize',
};
if (eventMapping[url]) {
store.dispatch('updateMessage', { event: eventMapping[url], data: msg });
} else {
store.dispatch('updateMessage', {event: 'msg/file/change', data: msg})
if ('operationFile' === url) {
let doc = msg.body
if (doc.code === 0) {
Bus.notify({
title: `${doc.operation}成功`,
dangerouslyUseHTMLString: true,
message: `
<div>
<p>form:</p>
<pre style="word-break: break-all;white-space: pre-wrap;font-size: 12px;">${doc.from}</pre>
</div>
<div>
<p>to:</p>
<pre style="word-break: break-all;white-space: pre-wrap;font-size: 12px;">${doc.to}</pre>
</div>`,
type: 'success',
});
} else {
store.dispatch('updateMessage', {event: 'msg/file/operation/fault', data: msg});
Bus.notify({
title: `${doc.operation}失败`,
dangerouslyUseHTMLString: true,
message: `<span style="font-size: 12px;">${doc.msg}</span>`,
type: 'error'
});
}
handleFileChangeMessage(msg, url, body);
}
}
function handleFileChangeMessage(msg, url, body) {
store.dispatch('updateMessage', { event: 'msg/file/change', data: msg });
if (url === 'operationFile') {
const { operation, from, to, code, msg: message } = body;
const notificationOptions = {
title: `${operation} ${code === 0 ? '成功' : '失败'}`,
dangerouslyUseHTMLString: true,
message: code === 0
? `
<div>
<p>from:</p>
<pre style="word-break: break-all;white-space: pre-wrap;font-size: 12px;">${from}</pre>
</div>
<div>
<p>to:</p>
<pre style="word-break: break-all;white-space: pre-wrap;font-size: 12px;">${to}</pre>
</div>`
: `<span style="font-size: 12px;">${message}</span>`,
type: code === 0 ? 'success' : 'error',
};
Bus.notify(notificationOptions);
if (code !== 0) {
store.dispatch('updateMessage', { event: 'msg/file/operation/fault', data: msg });
}
}
}
export function initiateSSE(username) {
throttledConnectSSE(username);
}