From 2b91bbe185cb668bea69830284003225a640b4af Mon Sep 17 00:00:00 2001
From: "meilin.huang" <954537473@qq.com>
Date: Thu, 19 Oct 2023 19:00:23 +0800
Subject: [PATCH] =?UTF-8?q?refactor:=20websocket=E6=94=AF=E6=8C=81?=
=?UTF-8?q?=E5=8D=95=E7=94=A8=E6=88=B7=E5=A4=9A=E8=BF=9E=E6=8E=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 14 +-
mayfly_go_web/package.json | 2 +-
mayfly_go_web/src/common/request.ts | 9 +-
mayfly_go_web/src/common/sockets.ts | 76 ----------
mayfly_go_web/src/common/syssocket.ts | 99 +++++++++++++
mayfly_go_web/src/common/utils/storage.ts | 19 +--
mayfly_go_web/src/common/utils/string.ts | 10 ++
mayfly_go_web/src/router/index.ts | 13 +-
mayfly_go_web/src/views/ops/db/DbEdit.vue | 2 +
mayfly_go_web/src/views/ops/db/DbList.vue | 6 +-
mayfly_go_web/src/views/ops/db/SqlExec.vue | 3 +
.../src/views/ops/db/component/tab/Query.vue | 49 ++++++-
mayfly_go_web/src/views/ops/db/db.ts | 2 -
.../src/views/ops/db/table/DbTableList.vue | 11 +-
mayfly_go_web/src/views/ops/machine/api.ts | 2 +-
.../views/ops/machine/file/MachineFile.vue | 3 +-
mayfly_go_web/src/views/personal/index.vue | 2 +-
mayfly_go_web/yarn.lock | 8 +-
server/internal/auth/api/account_login.go | 2 +-
server/internal/db/api/db.go | 61 +++-----
.../internal/msg/application/dto/sys_msg.go | 7 +
server/internal/msg/application/msg.go | 2 +-
server/internal/sys/api/system.go | 11 +-
server/pkg/model/login_account.go | 3 -
server/pkg/req/permission_handler.go | 10 +-
server/pkg/utils/collx/array.go | 11 ++
server/pkg/utils/uniqueid/uniqueid.go | 9 --
server/pkg/ws/client.go | 27 ++--
server/pkg/ws/client_manager.go | 133 ++++++++++++------
server/pkg/ws/msg.go | 8 +-
server/pkg/ws/ws.go | 14 +-
31 files changed, 365 insertions(+), 263 deletions(-)
delete mode 100644 mayfly_go_web/src/common/sockets.ts
create mode 100644 mayfly_go_web/src/common/syssocket.ts
delete mode 100644 server/pkg/utils/uniqueid/uniqueid.go
diff --git a/README.md b/README.md
index 957733f7..753ec6c1 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
# 🌈mayfly-go
-
-
-
+
+
+
-
-
-
+
+
+
@@ -100,4 +100,4 @@ http://go.mayfly.run
#### 💌 支持作者
-如果觉得项目不错,或者已经在使用了,希望你可以去 Github 或者 Gitee 帮我点个 ⭐ Star,这将是对我极大的鼓励与支持。
+如果觉得项目不错,或者已经在使用了,希望你可以去 Github 或者 Gitee 帮我点个 ⭐ Star,这将是对我极大的鼓励与支持。
diff --git a/mayfly_go_web/package.json b/mayfly_go_web/package.json
index d6a5df74..d1e74208 100644
--- a/mayfly_go_web/package.json
+++ b/mayfly_go_web/package.json
@@ -15,7 +15,7 @@
"countup.js": "^2.7.0",
"cropperjs": "^1.5.11",
"echarts": "^5.4.0",
- "element-plus": "^2.4.0",
+ "element-plus": "^2.4.1",
"jsencrypt": "^3.3.1",
"lodash": "^4.17.21",
"mitt": "^3.0.1",
diff --git a/mayfly_go_web/src/common/request.ts b/mayfly_go_web/src/common/request.ts
index f026f932..370ab98c 100755
--- a/mayfly_go_web/src/common/request.ts
+++ b/mayfly_go_web/src/common/request.ts
@@ -1,7 +1,7 @@
import router from '../router';
import Axios from 'axios';
import config from './config';
-import { getClientUuid, getToken, joinClientParams } from './utils/storage';
+import { getClientId, getToken } from './utils/storage';
import { templateResolve } from './utils/string';
import { ElMessage } from 'element-plus';
@@ -54,7 +54,7 @@ service.interceptors.request.use(
if (token) {
// 设置token
config.headers['Authorization'] = token;
- config.headers['Client-Uuid'] = getClientUuid();
+ config.headers['ClientId'] = getClientId();
}
return config;
},
@@ -180,6 +180,11 @@ function getApiUrl(url: string) {
return baseUrl + url + '?' + joinClientParams();
}
+// 组装客户端参数,包括 token 和 clientId
+export function joinClientParams(): string {
+ return `token=${getToken()}&clientId=${getClientId()}`;
+}
+
export default {
request,
get,
diff --git a/mayfly_go_web/src/common/sockets.ts b/mayfly_go_web/src/common/sockets.ts
deleted file mode 100644
index 4ccda632..00000000
--- a/mayfly_go_web/src/common/sockets.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import Config from './config';
-import { ElNotification, NotificationHandle } from 'element-plus';
-import SocketBuilder from './SocketBuilder';
-import { getToken, joinClientParams } from '@/common/utils/storage';
-import { createVNode, reactive } from 'vue';
-import { buildProgressProps } from '@/components/progress-notify/progress-notify';
-import ProgressNotify from '/src/components/progress-notify/progress-notify.vue';
-
-export default {
- /**
- * 全局系统消息websocket
- */
- sysMsgSocket() {
- const token = getToken();
- if (!token) {
- return null;
- }
- const messageTypes = {
- 0: 'error',
- 1: 'success',
- 2: 'info',
- };
- const notifyMap: Map = new Map();
- const sysMsgUrl = `${Config.baseWsUrl}/sysmsg?${joinClientParams()}`;
-
- return SocketBuilder.builder(sysMsgUrl)
- .message((event: { data: string }) => {
- const message = JSON.parse(event.data);
- const type = messageTypes[message.type];
- switch (message.category) {
- case 'execSqlFileProgress':
- const content = JSON.parse(message.msg);
- const id = content.id;
- let progress = notifyMap.get(id);
- if (content.terminated) {
- if (progress != undefined) {
- progress.notification?.close();
- notifyMap.delete(id);
- progress = undefined;
- }
- return;
- }
- if (progress == undefined) {
- progress = {
- props: reactive(buildProgressProps()),
- notification: undefined,
- };
- }
- progress.props.progress.title = content.title;
- progress.props.progress.executedStatements = content.executedStatements;
- if (!notifyMap.has(id)) {
- const vNodeMessage = createVNode(ProgressNotify, progress.props, null);
- progress.notification = ElNotification({
- duration: 0,
- title: message.title,
- message: vNodeMessage,
- type: type,
- showClose: false,
- });
- notifyMap.set(id, progress);
- }
- break;
- default:
- ElNotification({
- duration: 0,
- title: message.title,
- message: message.msg,
- type: type,
- });
- break;
- }
- })
- .open((event: any) => console.log(event))
- .build();
- },
-};
diff --git a/mayfly_go_web/src/common/syssocket.ts b/mayfly_go_web/src/common/syssocket.ts
new file mode 100644
index 00000000..504b2762
--- /dev/null
+++ b/mayfly_go_web/src/common/syssocket.ts
@@ -0,0 +1,99 @@
+import Config from './config';
+import { ElNotification } from 'element-plus';
+import SocketBuilder from './SocketBuilder';
+import { getToken } from '@/common/utils/storage';
+
+import { joinClientParams } from './request';
+
+class SysSocket {
+ /**
+ * socket连接
+ */
+ socket: any;
+
+ /**
+ * key -> 消息类别,value -> 消息对应的处理器函数
+ */
+ categoryHandlers: Map = new Map();
+
+ /**
+ * 消息类型
+ */
+ messageTypes = {
+ 0: 'error',
+ 1: 'success',
+ 2: 'info',
+ };
+
+ /**
+ * 初始化全局系统消息websocket
+ */
+ init() {
+ // 存在则不需要重新建立连接
+ if (this.socket) {
+ return;
+ }
+ const token = getToken();
+ if (!token) {
+ return null;
+ }
+
+ const sysMsgUrl = `${Config.baseWsUrl}/sysmsg?${joinClientParams()}`;
+ this.socket = SocketBuilder.builder(sysMsgUrl)
+ .message((event: { data: string }) => {
+ const message = JSON.parse(event.data);
+ // 存在消息类别对应的处理器,则进行处理,否则进行默认通知处理
+ const handler = this.categoryHandlers.get(message.category);
+ if (handler) {
+ handler(message);
+ return;
+ }
+
+ const type = this.getMsgType(message.type);
+ ElNotification({
+ duration: 0,
+ title: message.title,
+ message: message.msg,
+ type: type,
+ });
+ })
+ .open((event: any) => console.log(event))
+ .close(() => {
+ console.log('close sys socket');
+ this.socket = null;
+ })
+ .build();
+ }
+
+ destory() {
+ this.socket.close();
+ this.socket = null;
+ this.categoryHandlers.clear();
+ }
+
+ /**
+ * 注册消息处理函数
+ *
+ * @param category 消息类别
+ * @param handlerFunc 消息处理函数
+ */
+ registerMsgHandler(category: any, handlerFunc: any) {
+ if (this.categoryHandlers.has(category)) {
+ console.log(`${category}该类别消息处理器已存在...`);
+ return;
+ }
+ if (typeof handlerFunc != 'function') {
+ throw new Error('message handler需为函数');
+ }
+ this.categoryHandlers.set(category, handlerFunc);
+ }
+
+ getMsgType(msgType: any) {
+ return this.messageTypes[msgType];
+ }
+}
+
+// 全局系统消息websocket;
+const sysSocket = new SysSocket();
+
+export default sysSocket;
diff --git a/mayfly_go_web/src/common/utils/storage.ts b/mayfly_go_web/src/common/utils/storage.ts
index 6e8739fc..ff9275dd 100644
--- a/mayfly_go_web/src/common/utils/storage.ts
+++ b/mayfly_go_web/src/common/utils/storage.ts
@@ -1,9 +1,9 @@
-import { v1 as uuidv1 } from 'uuid';
+import { randomUuid } from './string';
const TokenKey = 'token';
const UserKey = 'user';
const TagViewsKey = 'tagViews';
-const ClientUuid = 'clientUuid'
+const ClientIdKey = 'clientId';
// 获取请求token
export function getToken(): string {
@@ -52,18 +52,13 @@ export function removeTagViews() {
}
// 获取客户端UUID
-export function getClientUuid(): string {
- let uuid = getSession(ClientUuid)
+export function getClientId(): string {
+ let uuid = getSession(ClientIdKey);
if (uuid == null) {
- uuid = uuidv1()
- setSession(ClientUuid, uuid)
+ uuid = randomUuid();
+ setSession(ClientIdKey, uuid);
}
- return uuid
-}
-
-// 组装客户端参数,包括 token 和 clientUuid
-export function joinClientParams(): string {
- return `token=${getToken()}&clientUuid=${getClientUuid()}`
+ return uuid;
}
// 1. localStorage
diff --git a/mayfly_go_web/src/common/utils/string.ts b/mayfly_go_web/src/common/utils/string.ts
index b0405b25..49e97af4 100644
--- a/mayfly_go_web/src/common/utils/string.ts
+++ b/mayfly_go_web/src/common/utils/string.ts
@@ -1,3 +1,5 @@
+import { v1 as uuidv1 } from 'uuid';
+
/**
* 模板字符串解析,如:template = 'hahaha{name}_{id}' ,param = {name: 'hh', id: 1}
* 解析后为 hahahahh_1
@@ -129,3 +131,11 @@ export function getContentWidth(content: any): number {
// }
return flexWidth;
}
+
+/**
+ *
+ * @returns uuid
+ */
+export function randomUuid() {
+ return uuidv1();
+}
diff --git a/mayfly_go_web/src/router/index.ts b/mayfly_go_web/src/router/index.ts
index 74f70f50..f216f6b7 100644
--- a/mayfly_go_web/src/router/index.ts
+++ b/mayfly_go_web/src/router/index.ts
@@ -6,7 +6,7 @@ import { templateResolve } from '@/common/utils/string';
import { NextLoading } from '@/common/utils/loading';
import { dynamicRoutes, staticRoutes, pathMatch } from './route';
import openApi from '@/common/openApi';
-import sockets from '@/common/sockets';
+import syssocket from '@/common/syssocket';
import pinia from '@/store/index';
import { useThemeConfig } from '@/store/themeConfig';
import { useUserInfo } from '@/store/userInfo';
@@ -179,7 +179,6 @@ export async function initRouter() {
}
}
-let SysWs: any;
let loadRouter = false;
// 路由加载前
@@ -204,10 +203,7 @@ router.beforeEach(async (to, from, next) => {
resetRoute();
NProgress.done();
- if (SysWs) {
- SysWs.close();
- SysWs = undefined;
- }
+ syssocket.destory();
return;
}
if (token && to.path === '/login') {
@@ -217,9 +213,10 @@ router.beforeEach(async (to, from, next) => {
}
// 终端不需要连接系统websocket消息
- if (!SysWs && to.path != '/machine/terminal') {
- SysWs = sockets.sysMsgSocket();
+ if (to.path != '/machine/terminal') {
+ syssocket.init();
}
+
// 不存在路由(避免刷新页面找不到路由)并且未加载过(避免token过期,导致获取权限接口报权限不足,无限获取),则重新初始化路由
if (useRoutesList().routesList.length == 0 && !loadRouter) {
await initRouter();
diff --git a/mayfly_go_web/src/views/ops/db/DbEdit.vue b/mayfly_go_web/src/views/ops/db/DbEdit.vue
index cbb3a725..dbc6404e 100644
--- a/mayfly_go_web/src/views/ops/db/DbEdit.vue
+++ b/mayfly_go_web/src/views/ops/db/DbEdit.vue
@@ -171,6 +171,8 @@ const changeDatabase = () => {
};
const getAllDatabase = async () => {
+ // 清空数据库列表,可能已经有选择库了
+ state.databaseList = [];
if (state.form.instanceId > 0) {
state.allDatabases = await dbApi.getAllDatabase.request({ instanceId: state.form.instanceId });
}
diff --git a/mayfly_go_web/src/views/ops/db/DbList.vue b/mayfly_go_web/src/views/ops/db/DbList.vue
index dfbc1389..47c0b95c 100644
--- a/mayfly_go_web/src/views/ops/db/DbList.vue
+++ b/mayfly_go_web/src/views/ops/db/DbList.vue
@@ -172,7 +172,7 @@ import { ref, toRefs, reactive, onMounted, defineAsyncComponent } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { dbApi } from './api';
import config from '@/common/config';
-import { joinClientParams } from '@/common/utils/storage';
+import { joinClientParams } from '@/common/request';
import { isTrue } from '@/common/assert';
import { Search as SearchIcon } from '@element-plus/icons-vue';
import { dateFormat } from '@/common/utils/date';
@@ -355,7 +355,9 @@ const deleteDb = async () => {
await dbApi.deleteDb.request({ id: state.selectionData.map((x: any) => x.id).join(',') });
ElMessage.success('删除成功');
search();
- } catch (err) {}
+ } catch (err) {
+ //
+ }
};
const onShowSqlExec = async (row: any) => {
diff --git a/mayfly_go_web/src/views/ops/db/SqlExec.vue b/mayfly_go_web/src/views/ops/db/SqlExec.vue
index 4f773f8f..1f010deb 100644
--- a/mayfly_go_web/src/views/ops/db/SqlExec.vue
+++ b/mayfly_go_web/src/views/ops/db/SqlExec.vue
@@ -387,6 +387,9 @@ const addQueryTab = async (inst: any, db: string, sqlName: string = '') => {
dbs: inst.dbs,
};
state.tabs.set(label, tab);
+
+ // 注册当前sql编辑框提示词
+ registerDbCompletionItemProvider('sql', tab.dbId, tab.db, tab.params.dbs);
};
const onRemoveTab = (targetName: string) => {
diff --git a/mayfly_go_web/src/views/ops/db/component/tab/Query.vue b/mayfly_go_web/src/views/ops/db/component/tab/Query.vue
index 998d71cb..9be9e50b 100644
--- a/mayfly_go_web/src/views/ops/db/component/tab/Query.vue
+++ b/mayfly_go_web/src/views/ops/db/component/tab/Query.vue
@@ -88,7 +88,7 @@