feat: 机器列表新增运行状态 & refactor: 登录账号信息存储与context

This commit is contained in:
meilin.huang
2023-11-07 21:05:21 +08:00
parent d9adf0fd25
commit eddda41291
74 changed files with 915 additions and 652 deletions

View File

@@ -15,7 +15,7 @@
"countup.js": "^2.7.0",
"cropperjs": "^1.5.11",
"echarts": "^5.4.3",
"element-plus": "^2.4.1",
"element-plus": "^2.4.2",
"jsencrypt": "^3.3.1",
"lodash": "^4.17.21",
"mitt": "^3.0.1",
@@ -29,7 +29,7 @@
"sortablejs": "^1.15.0",
"sql-formatter": "^12.1.2",
"uuid": "^9.0.1",
"vue": "^3.3.7",
"vue": "^3.3.8",
"vue-clipboard3": "^1.0.1",
"vue-router": "^4.2.5",
"xterm": "^5.3.0",

View File

@@ -118,10 +118,10 @@ const props = defineProps({
required: true,
},
// sql脚本名若有则去加载该sql内容
sqlName: {
type: String,
default: '',
},
// sqlName: {
// type: String,
// default: '',
// },
editorHeight: {
type: String,
default: '600',
@@ -153,7 +153,7 @@ const state = reactive({
hasUpdatedFileds: false,
});
const { tableDataHeight, ti, execRes, table, loading, hasUpdatedFileds } = toRefs(state);
const { tableDataHeight, ti, execRes, table, sqlName, loading, hasUpdatedFileds } = toRefs(state);
watch(
() => props.editorHeight,

View File

@@ -37,6 +37,36 @@
</el-link>
</template>
<template #stat="{ data }">
<span v-if="!data.stat">-</span>
<div v-else>
<el-row>
<el-text size="small" style="font-size: 10px">
内存(可用/):
<span :class="getStatsFontClass(data.stat.memAvailable, data.stat.memTotal)"
>{{ formatByteSize(data.stat.memAvailable, 1) }}/{{ formatByteSize(data.stat.memTotal, 1) }}
</span>
</el-text>
</el-row>
<el-row>
<el-text style="font-size: 10px" size="small">
CPU(空闲): <span :class="getStatsFontClass(data.stat.cpuIdle, 100)">{{ data.stat.cpuIdle.toFixed(0) }}%</span>
</el-text>
</el-row>
</div>
</template>
<template #fs="{ data }">
<span v-if="!data.stat?.fsInfos">-</span>
<div v-else>
<el-row v-for="i in data.stat.fsInfos.slice(0, 2)" :key="i.mountPoint">
<el-text style="font-size: 10px" size="small" :class="getStatsFontClass(i.free, i.used + i.free)">
{{ i.mountPoint }} => {{ formatByteSize(i.free, 0) }}/{{ formatByteSize(i.used + i.free, 0) }}
</el-text>
</el-row>
</div>
</template>
<template #status="{ data }">
<el-switch
v-auth:disabled="'machine:update'"
@@ -168,6 +198,7 @@ import TagInfo from '../component/TagInfo.vue';
import PageTable from '@/components/pagetable/PageTable.vue';
import { TableColumn, TableQuery } from '@/components/pagetable';
import { hasPerms } from '@/components/auth/auth';
import { formatByteSize } from '@/common/utils/format';
// 组件
const TerminalDialog = defineAsyncComponent(() => import('@/components/terminal/TerminalDialog.vue'));
@@ -196,6 +227,8 @@ const columns = ref([
TableColumn.new('tagPath', '标签路径').isSlot().setAddWidth(20),
TableColumn.new('name', '名称'),
TableColumn.new('ipPort', 'ip:port').isSlot().setAddWidth(50),
TableColumn.new('stat', '运行状态').isSlot().setAddWidth(50),
TableColumn.new('fs', '磁盘(挂载点=>可用/总)').isSlot().setAddWidth(20),
TableColumn.new('username', '用户名'),
TableColumn.new('status', '状态').isSlot().setMinWidth(85),
TableColumn.new('remark', '备注'),
@@ -408,6 +441,18 @@ const search = async () => {
}
};
const getStatsFontClass = (availavle: number, total: number) => {
const p = availavle / total;
if (p < 0.1) {
return 'color-danger';
}
if (p < 0.2) {
return 'color-warning';
}
return 'color-success';
};
const showInfo = (info: any) => {
state.infoDialog.data = info;
state.infoDialog.visible = true;

View File

@@ -8,18 +8,18 @@
<el-link @click="onRefresh" icon="refresh" :underline="false" type="success"></el-link>
</template>
<el-descriptions-item label="主机名">
{{ stats.Hostname }}
{{ stats.hostname }}
</el-descriptions-item>
<el-descriptions-item label="运行时间">
{{ stats.Uptime }}
{{ stats.uptime }}
</el-descriptions-item>
<el-descriptions-item label="总任务">
{{ stats.TotalProcs }}
{{ stats.totalProcs }}
</el-descriptions-item>
<el-descriptions-item label="运行中任务">
{{ stats.RunningProcs }}
{{ stats.runningProcs }}
</el-descriptions-item>
<el-descriptions-item label="负载"> {{ stats.Load1 }} {{ stats.Load5 }} {{ stats.Load10 }} </el-descriptions-item>
<el-descriptions-item label="负载"> {{ stats.load1 }} {{ stats.load5 }} {{ stats.load10 }} </el-descriptions-item>
</el-descriptions>
</el-col>
@@ -35,16 +35,16 @@
<el-row :gutter="20">
<el-col :lg="8" :md="8">
<span style="font-size: 16px; font-weight: 700">磁盘</span>
<el-table :data="stats.FSInfos" stripe max-height="250" style="width: 100%" border>
<el-table-column prop="MountPoint" label="挂载点" min-width="100" show-overflow-tooltip> </el-table-column>
<el-table-column prop="Used" label="可使用" min-width="70" show-overflow-tooltip>
<el-table :data="stats.fSInfos" stripe max-height="250" style="width: 100%" border>
<el-table-column prop="mountPoint" label="挂载点" min-width="100" show-overflow-tooltip> </el-table-column>
<el-table-column prop="used" label="可使用" min-width="70" show-overflow-tooltip>
<template #default="scope">
{{ formatByteSize(scope.row.Free) }}
{{ formatByteSize(scope.row.free) }}
</template>
</el-table-column>
<el-table-column prop="Used" label="已使用" min-width="70" show-overflow-tooltip>
<template #default="scope">
{{ formatByteSize(scope.row.Used) }}
{{ formatByteSize(scope.row.used) }}
</template>
</el-table-column>
</el-table>
@@ -54,16 +54,16 @@
<span style="font-size: 16px; font-weight: 700">网卡</span>
<el-table :data="netInter" stripe max-height="250" style="width: 100%" border>
<el-table-column prop="name" label="网卡" min-width="120" show-overflow-tooltip></el-table-column>
<el-table-column prop="IPv4" label="IPv4" min-width="130" show-overflow-tooltip> </el-table-column>
<el-table-column prop="IPv6" label="IPv6" min-width="130" show-overflow-tooltip> </el-table-column>
<el-table-column prop="Rx" label="接收(rx)" min-width="110" show-overflow-tooltip>
<el-table-column prop="ipv4" label="IPv4" min-width="130" show-overflow-tooltip> </el-table-column>
<el-table-column prop="ipv6" label="IPv6" min-width="130" show-overflow-tooltip> </el-table-column>
<el-table-column prop="rx" label="接收(rx)" min-width="110" show-overflow-tooltip>
<template #default="scope">
{{ formatByteSize(scope.row.Rx) }}
{{ formatByteSize(scope.row.rx) }}
</template>
</el-table-column>
<el-table-column prop="Tx" label="发送(tx)" min-width="110" show-overflow-tooltip>
<el-table-column prop="tx" label="发送(tx)" min-width="110" show-overflow-tooltip>
<template #default="scope">
{{ formatByteSize(scope.row.Tx) }}
{{ formatByteSize(scope.row.tx) }}
</template>
</el-table-column>
</el-table>
@@ -84,9 +84,6 @@ const props = defineProps({
visible: {
type: Boolean,
},
stats: {
type: Object,
},
machineId: {
type: Number,
},
@@ -134,11 +131,12 @@ const onRefresh = async () => {
};
const initMemStats = () => {
const mem = state.stats.memInfo;
const data = [
{ name: '可用内存', value: state.stats.MemAvailable },
{ name: '可用内存', value: mem.available },
{
name: '已用内存',
value: state.stats.MemTotal - state.stats.MemAvailable,
value: mem.total - mem.available,
},
];
const option = {
@@ -192,20 +190,20 @@ const initMemStats = () => {
};
const initCpuStats = () => {
const cpu = state.stats.CPU;
const cpu = state.stats.cpu;
const data = [
{ name: 'Idle', value: cpu.Idle },
{ name: 'Idle', value: cpu.idle },
{
name: 'Iowait',
value: cpu.Iowait,
value: cpu.iowait,
},
{
name: 'System',
value: cpu.System,
value: cpu.system,
},
{
name: 'User',
value: cpu.User,
value: cpu.user,
},
];
const option = {
@@ -283,7 +281,7 @@ const initEchartsResize = () => {
const parseNetInter = () => {
state.netInter = [];
const netInter = state.stats.NetIntf;
const netInter = state.stats.netIntf;
const keys = Object.keys(netInter);
const values = Object.values(netInter);
for (let i = 0; i < values.length; i++) {

View File

@@ -390,13 +390,13 @@
estree-walker "^2.0.2"
source-map-js "^1.0.2"
"@vue/compiler-core@3.3.7":
version "3.3.7"
resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.3.7.tgz#865a5734c971686d9737d85a0c5a08de045b6162"
integrity sha512-pACdY6YnTNVLXsB86YD8OF9ihwpolzhhtdLVHhBL6do/ykr6kKXNYABRtNMGrsQXpEXXyAdwvWWkuTbs4MFtPQ==
"@vue/compiler-core@3.3.8":
version "3.3.8"
resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.3.8.tgz#301bb60d0245265a88ed5b30e200fbf223acb313"
integrity sha512-hN/NNBUECw8SusQvDSqqcVv6gWq8L6iAktUR0UF3vGu2OhzRqcOiAno0FmBJWwxhYEXRlQJT5XnoKsVq1WZx4g==
dependencies:
"@babel/parser" "^7.23.0"
"@vue/shared" "3.3.7"
"@vue/shared" "3.3.8"
estree-walker "^2.0.2"
source-map-js "^1.0.2"
@@ -408,25 +408,25 @@
"@vue/compiler-core" "3.3.4"
"@vue/shared" "3.3.4"
"@vue/compiler-dom@3.3.7":
version "3.3.7"
resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.3.7.tgz#a245aa03f9bfcdb537a239bf02842072de0644c9"
integrity sha512-0LwkyJjnUPssXv/d1vNJ0PKfBlDoQs7n81CbO6Q0zdL7H1EzqYRrTVXDqdBVqro0aJjo/FOa1qBAPVI4PGSHBw==
"@vue/compiler-dom@3.3.8":
version "3.3.8"
resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.3.8.tgz#09d832514b9b8d9415a3816b065d69dbefcc7e9b"
integrity sha512-+PPtv+p/nWDd0AvJu3w8HS0RIm/C6VGBIRe24b9hSyNWOAPEUosFZ5diwawwP8ip5sJ8n0Pe87TNNNHnvjs0FQ==
dependencies:
"@vue/compiler-core" "3.3.7"
"@vue/shared" "3.3.7"
"@vue/compiler-core" "3.3.8"
"@vue/shared" "3.3.8"
"@vue/compiler-sfc@3.3.7":
version "3.3.7"
resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.3.7.tgz#219d04b3013c7b15fbc536e2279e07810b731cc2"
integrity sha512-7pfldWy/J75U/ZyYIXRVqvLRw3vmfxDo2YLMwVtWVNew8Sm8d6wodM+OYFq4ll/UxfqVr0XKiVwti32PCrruAw==
"@vue/compiler-sfc@3.3.8":
version "3.3.8"
resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.3.8.tgz#40b18e48aa00260950964d1d72157668521be0e1"
integrity sha512-WMzbUrlTjfYF8joyT84HfwwXo+8WPALuPxhy+BZ6R4Aafls+jDBnSz8PDz60uFhuqFbl3HxRfxvDzrUf3THwpA==
dependencies:
"@babel/parser" "^7.23.0"
"@vue/compiler-core" "3.3.7"
"@vue/compiler-dom" "3.3.7"
"@vue/compiler-ssr" "3.3.7"
"@vue/reactivity-transform" "3.3.7"
"@vue/shared" "3.3.7"
"@vue/compiler-core" "3.3.8"
"@vue/compiler-dom" "3.3.8"
"@vue/compiler-ssr" "3.3.8"
"@vue/reactivity-transform" "3.3.8"
"@vue/shared" "3.3.8"
estree-walker "^2.0.2"
magic-string "^0.30.5"
postcss "^8.4.31"
@@ -456,13 +456,13 @@
"@vue/compiler-dom" "3.3.4"
"@vue/shared" "3.3.4"
"@vue/compiler-ssr@3.3.7":
version "3.3.7"
resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.3.7.tgz#eff4a70f7ceb800d60e68d208b96a030c0f1b636"
integrity sha512-TxOfNVVeH3zgBc82kcUv+emNHo+vKnlRrkv8YvQU5+Y5LJGJwSNzcmLUoxD/dNzv0bhQ/F0s+InlgV0NrApJZg==
"@vue/compiler-ssr@3.3.8":
version "3.3.8"
resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.3.8.tgz#136eed54411e4694815d961048a237191063fbce"
integrity sha512-hXCqQL/15kMVDBuoBYpUnSYT8doDNwsjvm3jTefnXr+ytn294ySnT8NlsFHmTgKNjwpuFy7XVV8yTeLtNl/P6w==
dependencies:
"@vue/compiler-dom" "3.3.7"
"@vue/shared" "3.3.7"
"@vue/compiler-dom" "3.3.8"
"@vue/shared" "3.3.8"
"@vue/devtools-api@^6.5.0":
version "6.5.0"
@@ -480,58 +480,58 @@
estree-walker "^2.0.2"
magic-string "^0.30.0"
"@vue/reactivity-transform@3.3.7":
version "3.3.7"
resolved "https://registry.npmmirror.com/@vue/reactivity-transform/-/reactivity-transform-3.3.7.tgz#eb9f5110af5085079b851d162205394bc790d539"
integrity sha512-APhRmLVbgE1VPGtoLQoWBJEaQk4V8JUsqrQihImVqKT+8U6Qi3t5ATcg4Y9wGAPb3kIhetpufyZ1RhwbZCIdDA==
"@vue/reactivity-transform@3.3.8":
version "3.3.8"
resolved "https://registry.npmmirror.com/@vue/reactivity-transform/-/reactivity-transform-3.3.8.tgz#6d07649013b0be5c670f0ab6cc7ddd3150ad03f2"
integrity sha512-49CvBzmZNtcHua0XJ7GdGifM8GOXoUMOX4dD40Y5DxI3R8OUhMlvf2nvgUAcPxaXiV5MQQ1Nwy09ADpnLQUqRw==
dependencies:
"@babel/parser" "^7.23.0"
"@vue/compiler-core" "3.3.7"
"@vue/shared" "3.3.7"
"@vue/compiler-core" "3.3.8"
"@vue/shared" "3.3.8"
estree-walker "^2.0.2"
magic-string "^0.30.5"
"@vue/reactivity@3.3.7":
version "3.3.7"
resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.3.7.tgz#48b6671a45ba33039da2c0eb25ae702f924486a9"
integrity sha512-cZNVjWiw00708WqT0zRpyAgduG79dScKEPYJXq2xj/aMtk3SKvL3FBt2QKUlh6EHBJ1m8RhBY+ikBUzwc7/khg==
"@vue/reactivity@3.3.8":
version "3.3.8"
resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.3.8.tgz#cce8a03a3fd3539c3eeda53e277ba365d160dd4d"
integrity sha512-ctLWitmFBu6mtddPyOKpHg8+5ahouoTCRtmAHZAXmolDtuZXfjL2T3OJ6DL6ezBPQB1SmMnpzjiWjCiMYmpIuw==
dependencies:
"@vue/shared" "3.3.7"
"@vue/shared" "3.3.8"
"@vue/runtime-core@3.3.7":
version "3.3.7"
resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.3.7.tgz#c1eece1c98f936dc69dd0667d11b464579b128fd"
integrity sha512-LHq9du3ubLZFdK/BP0Ysy3zhHqRfBn80Uc+T5Hz3maFJBGhci1MafccnL3rpd5/3wVfRHAe6c+PnlO2PAavPTQ==
"@vue/runtime-core@3.3.8":
version "3.3.8"
resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.3.8.tgz#fba5a632cbf2b5d29e171489570149cb6975dcdb"
integrity sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==
dependencies:
"@vue/reactivity" "3.3.7"
"@vue/shared" "3.3.7"
"@vue/reactivity" "3.3.8"
"@vue/shared" "3.3.8"
"@vue/runtime-dom@3.3.7":
version "3.3.7"
resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.3.7.tgz#e7cf88cc01591fdf6e3164825554fdadc3137ffc"
integrity sha512-PFQU1oeJxikdDmrfoNQay5nD4tcPNYixUBruZzVX/l0eyZvFKElZUjW4KctCcs52nnpMGO6UDK+jF5oV4GT5Lw==
"@vue/runtime-dom@3.3.8":
version "3.3.8"
resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.3.8.tgz#e2d7aa795cf50914dda9a951887765a594b38af4"
integrity sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==
dependencies:
"@vue/runtime-core" "3.3.7"
"@vue/shared" "3.3.7"
"@vue/runtime-core" "3.3.8"
"@vue/shared" "3.3.8"
csstype "^3.1.2"
"@vue/server-renderer@3.3.7":
version "3.3.7"
resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.3.7.tgz#0cc3dc6ad39a54693e6e8f853caa3c7bb43b0364"
integrity sha512-UlpKDInd1hIZiNuVVVvLgxpfnSouxKQOSE2bOfQpBuGwxRV/JqqTCyyjXUWiwtVMyeRaZhOYYqntxElk8FhBhw==
"@vue/server-renderer@3.3.8":
version "3.3.8"
resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.3.8.tgz#9b1779010e75783edeed8fcfb97d9c95fc3ac5d2"
integrity sha512-zVCUw7RFskvPuNlPn/8xISbrf0zTWsTSdYTsUTN1ERGGZGVnRxM2QZ3x1OR32+vwkkCm0IW6HmJ49IsPm7ilLg==
dependencies:
"@vue/compiler-ssr" "3.3.7"
"@vue/shared" "3.3.7"
"@vue/compiler-ssr" "3.3.8"
"@vue/shared" "3.3.8"
"@vue/shared@3.3.4":
version "3.3.4"
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.3.4.tgz#06e83c5027f464eef861c329be81454bc8b70780"
integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==
"@vue/shared@3.3.7":
version "3.3.7"
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.3.7.tgz#0091852fe5cc4237c8440fe32f3ab6bc920ae6d9"
integrity sha512-N/tbkINRUDExgcPTBvxNkvHGu504k8lzlNQRITVnm6YjOjwa4r0nnbd4Jb01sNpur5hAllyRJzSK5PvB9PPwRg==
"@vue/shared@3.3.8":
version "3.3.8"
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.3.8.tgz#f044942142e1d3a395f24132e6203a784838542d"
integrity sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==
"@vueuse/core@^9.1.0":
version "9.2.0"
@@ -841,10 +841,10 @@ echarts@^5.4.3:
tslib "2.3.0"
zrender "5.4.4"
element-plus@^2.4.1:
version "2.4.1"
resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.4.1.tgz#8a5faa69e856d82494b94d77fb485d9e727c8bc1"
integrity sha512-t7nl+vQlkBKVk1Ag6AufSDyFV8YIXxTFsaya4Nz/0tiRlcz65WPN4WMFeNURuFJleu1HLNtP4YyQKMuS7El8uA==
element-plus@^2.4.2:
version "2.4.2"
resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.4.2.tgz#2a24632e0904ccd7bbbd64c269704f6b9969833c"
integrity sha512-E/HwXX7JF1LPvQSjs0fZ8WblIoc0quoXsRXQZiL7QDq7xJdNGSUaXtdk7xiEv7axPmLfEFtxE5du9fFspDrmJw==
dependencies:
"@ctrl/tinycolor" "^3.4.1"
"@element-plus/icons-vue" "^2.0.6"
@@ -1912,16 +1912,16 @@ vue-router@^4.2.5:
dependencies:
"@vue/devtools-api" "^6.5.0"
vue@^3.3.7:
version "3.3.7"
resolved "https://registry.npmmirror.com/vue/-/vue-3.3.7.tgz#972a218682443a3819d121261b2bff914417f4f0"
integrity sha512-YEMDia1ZTv1TeBbnu6VybatmSteGOS3A3YgfINOfraCbf85wdKHzscD6HSS/vB4GAtI7sa1XPX7HcQaJ1l24zA==
vue@^3.3.8:
version "3.3.8"
resolved "https://registry.npmmirror.com/vue/-/vue-3.3.8.tgz#532ff071af24f6a69e5ecc53a66858a9ee874ffc"
integrity sha512-5VSX/3DabBikOXMsxzlW8JyfeLKlG9mzqnWgLQLty88vdZL7ZJgrdgBOmrArwxiLtmS+lNNpPcBYqrhE6TQW5w==
dependencies:
"@vue/compiler-dom" "3.3.7"
"@vue/compiler-sfc" "3.3.7"
"@vue/runtime-dom" "3.3.7"
"@vue/server-renderer" "3.3.7"
"@vue/shared" "3.3.7"
"@vue/compiler-dom" "3.3.8"
"@vue/compiler-sfc" "3.3.8"
"@vue/runtime-dom" "3.3.8"
"@vue/server-renderer" "3.3.8"
"@vue/shared" "3.3.8"
which@^2.0.1:
version "2.0.2"

View File

@@ -1,6 +1,7 @@
package api
import (
"context"
"encoding/json"
"fmt"
"mayfly-go/internal/auth/api/form"
@@ -107,7 +108,7 @@ func (a *AccountLogin) OtpVerify(rc *req.Ctx) {
update := &sysentity.Account{OtpSecret: otpSecret}
update.Id = accountId
update.OtpSecretEncrypt()
biz.ErrIsNil(a.AccountApp.Update(update))
biz.ErrIsNil(a.AccountApp.Update(context.Background(), update))
}
la := &sysentity.Account{Username: otpInfo.Username}
@@ -119,6 +120,7 @@ func (a *AccountLogin) OtpVerify(rc *req.Ctx) {
}
func (a *AccountLogin) Logout(rc *req.Ctx) {
req.GetPermissionCodeRegistery().Remove(rc.LoginAccount.Id)
ws.CloseClient(ws.UserId(rc.LoginAccount.Id))
la := rc.GetLoginAccount()
req.GetPermissionCodeRegistery().Remove(la.Id)
ws.CloseClient(ws.UserId(la.Id))
}

View File

@@ -1,6 +1,7 @@
package api
import (
"context"
"fmt"
"mayfly-go/internal/auth/config"
msgapp "mayfly-go/internal/msg/application"
@@ -108,7 +109,7 @@ func saveLogin(account *sysentity.Account, ip string) {
updateAccount.Id = account.Id
updateAccount.LastLoginIp = ip
// 偷懒为了方便直接获取accountApp
biz.ErrIsNil(sysapp.GetAccountApp().Update(updateAccount))
biz.ErrIsNil(sysapp.GetAccountApp().Update(context.TODO(), updateAccount))
// 创建登录消息
loginMsg := &msgentity.Msg{
@@ -119,5 +120,5 @@ func saveLogin(account *sysentity.Account, ip string) {
loginMsg.CreateTime = &now
loginMsg.Creator = account.Username
loginMsg.CreatorId = account.Id
msgapp.GetMsgApp().Create(loginMsg)
msgapp.GetMsgApp().Create(context.TODO(), loginMsg)
}

View File

@@ -1,6 +1,7 @@
package api
import (
"context"
"crypto/tls"
"fmt"
"mayfly-go/internal/auth/api/form"
@@ -88,10 +89,10 @@ func (a *LdapLogin) createUser(userName, displayName string) {
account := &sysentity.Account{Username: userName}
account.SetBaseInfo(nil)
account.Name = displayName
biz.ErrIsNil(a.AccountApp.Create(account))
biz.ErrIsNil(a.AccountApp.Create(context.TODO(), account))
// 将 LADP 用户本地密码设置为空,不允许本地登录
account.Password = cryptox.PwdHash("")
biz.ErrIsNil(a.AccountApp.Update(account))
biz.ErrIsNil(a.AccountApp.Update(context.TODO(), account))
}
func (a *LdapLogin) getOrCreateUserWithLdap(userName string, password string, cols ...string) (*sysentity.Account, error) {

View File

@@ -1,6 +1,7 @@
package api
import (
"context"
"fmt"
"io"
"mayfly-go/internal/auth/api/vo"
@@ -42,7 +43,7 @@ func (a *Oauth2Login) OAuth2Login(rc *req.Ctx) {
func (a *Oauth2Login) OAuth2Bind(rc *req.Ctx) {
client, _ := a.getOAuthClient()
state := stringx.Rand(32)
cache.SetStr("oauth2:state:"+state, "bind:"+strconv.FormatUint(rc.LoginAccount.Id, 10),
cache.SetStr("oauth2:state:"+state, "bind:"+strconv.FormatUint(rc.GetLoginAccount().Id, 10),
5*time.Minute)
rc.GinCtx.Redirect(http.StatusFound, client.AuthCodeURL(state))
}
@@ -152,7 +153,7 @@ func (a *Oauth2Login) doLoginAction(rc *req.Ctx, userId string, oauth *config.Oa
Name: userId,
Username: userId,
}
biz.ErrIsNil(a.AccountApp.Create(account))
biz.ErrIsNil(a.AccountApp.Create(context.TODO(), account))
// 绑定
err := a.Oauth2App.BindOAuthAccount(&entity.Oauth2Account{
AccountId: account.Id,
@@ -207,7 +208,7 @@ func (a *Oauth2Login) Oauth2Status(ctx *req.Ctx) {
res.Enable = oauth2LoginConfig.Enable
if res.Enable {
err := a.Oauth2App.GetOAuthAccount(&entity.Oauth2Account{
AccountId: ctx.LoginAccount.Id,
AccountId: ctx.GetLoginAccount().Id,
}, "account_id", "identity")
res.Bind = err == nil
}
@@ -216,7 +217,7 @@ func (a *Oauth2Login) Oauth2Status(ctx *req.Ctx) {
}
func (a *Oauth2Login) Oauth2Unbind(rc *req.Ctx) {
a.Oauth2App.Unbind(rc.LoginAccount.Id)
a.Oauth2App.Unbind(rc.GetLoginAccount().Id)
}
// 获取oauth2登录配置信息因为有些字段是敏感字段故单独使用接口获取

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"mayfly-go/internal/auth/domain/entity"
"mayfly-go/internal/auth/domain/repository"
)
@@ -29,11 +30,11 @@ func (a *oauth2AppImpl) GetOAuthAccount(condition *entity.Oauth2Account, cols ..
func (a *oauth2AppImpl) BindOAuthAccount(e *entity.Oauth2Account) error {
if e.Id == 0 {
return a.oauthAccountRepo.Insert(e)
return a.oauthAccountRepo.Insert(context.Background(), e)
}
return a.oauthAccountRepo.UpdateById(e)
return a.oauthAccountRepo.UpdateById(context.Background(), e)
}
func (a *oauth2AppImpl) Unbind(accountId uint64) {
a.oauthAccountRepo.DeleteByCond(&entity.Oauth2Account{AccountId: accountId})
a.oauthAccountRepo.DeleteByCond(context.Background(), &entity.Oauth2Account{AccountId: accountId})
}

View File

@@ -23,7 +23,7 @@ type Index struct {
}
func (i *Index) Count(rc *req.Ctx) {
accountId := rc.LoginAccount.Id
accountId := rc.GetLoginAccount().Id
tagIds := i.TagApp.ListTagIdByAccountId(accountId)
var mongoNum int64

View File

@@ -13,7 +13,6 @@ import (
tagapp "mayfly-go/internal/tag/application"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/ginx"
"mayfly-go/pkg/gormx"
"mayfly-go/pkg/logx"
"mayfly-go/pkg/model"
"mayfly-go/pkg/req"
@@ -42,7 +41,7 @@ func (d *Db) Dbs(rc *req.Ctx) {
queryCond, page := ginx.BindQueryAndPage[*entity.DbQuery](rc.GinCtx, new(entity.DbQuery))
// 不存在可访问标签id即没有可操作数据
tagIds := d.TagApp.ListTagIdByAccountId(rc.LoginAccount.Id)
tagIds := d.TagApp.ListTagIdByAccountId(rc.GetLoginAccount().Id)
if len(tagIds) == 0 {
rc.ResData = model.EmptyPageResult[any]()
return
@@ -55,7 +54,7 @@ func (d *Db) Dbs(rc *req.Ctx) {
}
func (d *Db) DbTags(rc *req.Ctx) {
rc.ResData = d.TagApp.ListTagByAccountIdAndResource(rc.LoginAccount.Id, new(entity.Db))
rc.ResData = d.TagApp.ListTagByAccountIdAndResource(rc.GetLoginAccount().Id, new(entity.Db))
}
func (d *Db) Save(rc *req.Ctx) {
@@ -64,8 +63,7 @@ func (d *Db) Save(rc *req.Ctx) {
rc.ReqParam = form
db.SetBaseInfo(rc.LoginAccount)
biz.ErrIsNil(d.DbApp.Save(db))
biz.ErrIsNil(d.DbApp.Save(rc.MetaCtx, db))
}
func (d *Db) DeleteDb(rc *req.Ctx) {
@@ -73,13 +71,14 @@ func (d *Db) DeleteDb(rc *req.Ctx) {
rc.ReqParam = idsStr
ids := strings.Split(idsStr, ",")
ctx := rc.MetaCtx
for _, v := range ids {
value, err := strconv.Atoi(v)
biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
dbId := uint64(value)
d.DbApp.Delete(dbId)
d.DbApp.Delete(ctx, dbId)
// 删除该库的sql执行记录
d.DbSqlExecApp.DeleteBy(&entity.DbSqlExec{DbId: dbId})
d.DbSqlExecApp.DeleteBy(ctx, &entity.DbSqlExec{DbId: dbId})
}
}
@@ -91,7 +90,7 @@ func (d *Db) ExecSql(rc *req.Ctx) {
dbId := getDbId(g)
dbConn, err := d.DbApp.GetDbConn(dbId, form.Db)
biz.ErrIsNil(err)
biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.LoginAccount.Id, dbConn.Info.TagPath), "%s")
biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.GetLoginAccount().Id, dbConn.Info.TagPath), "%s")
rc.ReqParam = fmt.Sprintf("%s\n-> %s", dbConn.Info.GetLogDesc(), form.Sql)
biz.NotEmpty(form.Sql, "sql不能为空")
@@ -104,7 +103,7 @@ func (d *Db) ExecSql(rc *req.Ctx) {
Db: form.Db,
Remark: form.Remark,
DbConn: dbConn,
LoginAccount: rc.LoginAccount,
LoginAccount: rc.GetLoginAccount(),
}
sqls, err := sqlparser.SplitStatementToPieces(sql, sqlparser.WithDialect(dbConn.Info.Type.Dialect()))
@@ -163,7 +162,7 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
dbConn, err := d.DbApp.GetDbConn(dbId, dbName)
biz.ErrIsNil(err)
biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.LoginAccount.Id, dbConn.Info.TagPath), "%s")
biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.GetLoginAccount().Id, dbConn.Info.TagPath), "%s")
rc.ReqParam = fmt.Sprintf("filename: %s -> %s", filename, dbConn.Info.GetLogDesc())
defer func() {
@@ -172,7 +171,7 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
if len(errInfo) > 300 {
errInfo = errInfo[:300] + "..."
}
d.MsgApp.CreateAndSend(rc.LoginAccount, msgdto.ErrSysMsg("sql脚本执行失败", fmt.Sprintf("[%s][%s]执行失败: [%s]", filename, dbConn.Info.GetLogDesc(), errInfo)).WithClientId(clientId))
d.MsgApp.CreateAndSend(rc.GetLoginAccount(), msgdto.ErrSysMsg("sql脚本执行失败", fmt.Sprintf("[%s][%s]执行失败: [%s]", filename, dbConn.Info.GetLogDesc(), errInfo)).WithClientId(clientId))
}
}()
@@ -181,7 +180,7 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
Db: dbName,
Remark: filename,
DbConn: dbConn,
LoginAccount: rc.LoginAccount,
LoginAccount: rc.GetLoginAccount(),
}
var sql string
@@ -191,7 +190,8 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
executedStatements := 0
progressId := stringx.Rand(32)
defer ws.SendJsonMsg(ws.UserId(rc.LoginAccount.Id), clientId, msgdto.InfoSysMsg("sql脚本执行进度", &progressMsg{
laId := rc.GetLoginAccount().Id
defer ws.SendJsonMsg(ws.UserId(laId), clientId, msgdto.InfoSysMsg("sql脚本执行进度", &progressMsg{
Id: progressId,
Title: filename,
ExecutedStatements: executedStatements,
@@ -202,7 +202,7 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
for {
select {
case <-ticker.C:
ws.SendJsonMsg(ws.UserId(rc.LoginAccount.Id), clientId, msgdto.InfoSysMsg("sql脚本执行进度", &progressMsg{
ws.SendJsonMsg(ws.UserId(laId), clientId, msgdto.InfoSysMsg("sql脚本执行进度", &progressMsg{
Id: progressId,
Title: filename,
ExecutedStatements: executedStatements,
@@ -231,7 +231,7 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
}
dbConn, err = d.DbApp.GetDbConn(dbId, stmtUse.DBName.String())
biz.ErrIsNil(err)
biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.LoginAccount.Id, dbConn.Info.TagPath), "%s")
biz.ErrIsNilAppendErr(d.TagApp.CanAccess(laId, dbConn.Info.TagPath), "%s")
execReq.DbConn = dbConn
}
// 需要记录执行记录
@@ -245,7 +245,7 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
biz.ErrIsNilAppendErr(err, "%s")
}
d.MsgApp.CreateAndSend(rc.LoginAccount, msgdto.SuccessSysMsg("sql脚本执行成功", fmt.Sprintf("sql脚本执行完成%s", rc.ReqParam)).WithClientId(clientId))
d.MsgApp.CreateAndSend(rc.GetLoginAccount(), msgdto.SuccessSysMsg("sql脚本执行成功", fmt.Sprintf("sql脚本执行完成%s", rc.ReqParam)).WithClientId(clientId))
}
// 数据库dump
@@ -268,9 +268,10 @@ func (d *Db) DumpSql(rc *req.Ctx) {
// 是否需要导出数据
needData := dumpType == "2" || dumpType == "3"
la := rc.GetLoginAccount()
db, err := d.DbApp.GetById(new(entity.Db), dbId)
biz.ErrIsNil(err, "该数据库不存在")
biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.LoginAccount.Id, db.TagPath), "%s")
biz.ErrIsNilAppendErr(d.TagApp.CanAccess(la.Id, db.TagPath), "%s")
now := time.Now()
filename := fmt.Sprintf("%s.%s.sql%s", db.Name, now.Format("20060102150405"), extName)
@@ -294,7 +295,7 @@ func (d *Db) DumpSql(rc *req.Ctx) {
if len(msg) > 0 {
msg = "数据库导出失败: " + msg
writer.WriteString(msg)
d.MsgApp.CreateAndSend(rc.LoginAccount, msgdto.ErrSysMsg("数据库导出失败", msg))
d.MsgApp.CreateAndSend(la, msgdto.ErrSysMsg("数据库导出失败", msg))
}
writer.Close()
}()
@@ -444,73 +445,6 @@ func (d *Db) GetCreateTableDdl(rc *req.Ctx) {
rc.ResData = res
}
// @router /api/db/:dbId/sql [post]
func (d *Db) SaveSql(rc *req.Ctx) {
g := rc.GinCtx
account := rc.LoginAccount
dbSqlForm := &form.DbSqlSaveForm{}
ginx.BindJsonAndValid(g, dbSqlForm)
rc.ReqParam = dbSqlForm
dbId := getDbId(g)
// 判断dbId是否存在
err := gormx.GetById(new(entity.Db), dbId)
biz.ErrIsNil(err, "该数据库信息不存在")
// 获取用于是否有该dbsql的保存记录有则更改否则新增
dbSql := &entity.DbSql{Type: dbSqlForm.Type, DbId: dbId, Name: dbSqlForm.Name, Db: dbSqlForm.Db}
dbSql.CreatorId = account.Id
e := gormx.GetBy(dbSql)
dbSql.SetBaseInfo(account)
// 更新sql信息
dbSql.Sql = dbSqlForm.Sql
if e == nil {
gormx.UpdateById(dbSql)
} else {
gormx.Insert(dbSql)
}
}
// 获取所有保存的sql names
func (d *Db) GetSqlNames(rc *req.Ctx) {
dbId := getDbId(rc.GinCtx)
dbName := getDbName(rc.GinCtx)
// 获取用于是否有该dbsql的保存记录有则更改否则新增
dbSql := &entity.DbSql{Type: 1, DbId: dbId, Db: dbName}
dbSql.CreatorId = rc.LoginAccount.Id
var sqls []entity.DbSql
gormx.ListBy(dbSql, &sqls, "id", "name")
rc.ResData = sqls
}
// 删除保存的sql
func (d *Db) DeleteSql(rc *req.Ctx) {
dbSql := &entity.DbSql{Type: 1, DbId: getDbId(rc.GinCtx)}
dbSql.CreatorId = rc.LoginAccount.Id
dbSql.Name = rc.GinCtx.Query("name")
dbSql.Db = rc.GinCtx.Query("db")
biz.ErrIsNil(gormx.DeleteBy(dbSql))
}
// @router /api/db/:dbId/sql [get]
func (d *Db) GetSql(rc *req.Ctx) {
dbId := getDbId(rc.GinCtx)
dbName := getDbName(rc.GinCtx)
// 根据创建者id 数据库id以及sql模板名称查询保存的sql信息
dbSql := &entity.DbSql{Type: 1, DbId: dbId, Db: dbName}
dbSql.CreatorId = rc.LoginAccount.Id
dbSql.Name = rc.GinCtx.Query("name")
e := gormx.GetBy(dbSql)
if e != nil {
return
}
rc.ResData = dbSql
}
func getDbId(g *gin.Context) uint64 {
dbId, _ := strconv.Atoi(g.Param("dbId"))
biz.IsTrue(dbId > 0, "dbId错误")

View File

@@ -0,0 +1,77 @@
package api
import (
"mayfly-go/internal/db/api/form"
"mayfly-go/internal/db/application"
"mayfly-go/internal/db/domain/entity"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/ginx"
"mayfly-go/pkg/req"
)
type DbSql struct {
DbSqlApp application.DbSql
}
// @router /api/db/:dbId/sql [post]
func (d *DbSql) SaveSql(rc *req.Ctx) {
g := rc.GinCtx
dbSqlForm := &form.DbSqlSaveForm{}
ginx.BindJsonAndValid(g, dbSqlForm)
rc.ReqParam = dbSqlForm
dbId := getDbId(g)
account := rc.GetLoginAccount()
// 获取用于是否有该dbsql的保存记录有则更改否则新增
dbSql := &entity.DbSql{Type: dbSqlForm.Type, DbId: dbId, Name: dbSqlForm.Name, Db: dbSqlForm.Db}
dbSql.CreatorId = account.Id
e := d.DbSqlApp.GetBy(dbSql)
// 更新sql信息
dbSql.Sql = dbSqlForm.Sql
if e == nil {
d.DbSqlApp.UpdateById(rc.MetaCtx, dbSql)
} else {
d.DbSqlApp.Insert(rc.MetaCtx, dbSql)
}
}
// 获取所有保存的sql names
func (d *DbSql) GetSqlNames(rc *req.Ctx) {
dbId := getDbId(rc.GinCtx)
dbName := getDbName(rc.GinCtx)
// 获取用于是否有该dbsql的保存记录有则更改否则新增
dbSql := &entity.DbSql{Type: 1, DbId: dbId, Db: dbName}
dbSql.CreatorId = rc.GetLoginAccount().Id
var sqls []entity.DbSql
d.DbSqlApp.ListByCond(dbSql, &sqls, "id", "name")
rc.ResData = sqls
}
// 删除保存的sql
func (d *DbSql) DeleteSql(rc *req.Ctx) {
dbSql := &entity.DbSql{Type: 1, DbId: getDbId(rc.GinCtx)}
dbSql.CreatorId = rc.GetLoginAccount().Id
dbSql.Name = rc.GinCtx.Query("name")
dbSql.Db = rc.GinCtx.Query("db")
biz.ErrIsNil(d.DbSqlApp.DeleteByCond(rc.MetaCtx, dbSql))
}
// @router /api/db/:dbId/sql [get]
func (d *DbSql) GetSql(rc *req.Ctx) {
dbId := getDbId(rc.GinCtx)
dbName := getDbName(rc.GinCtx)
// 根据创建者id 数据库id以及sql模板名称查询保存的sql信息
dbSql := &entity.DbSql{Type: 1, DbId: dbId, Db: dbName}
dbSql.CreatorId = rc.GetLoginAccount().Id
dbSql.Name = rc.GinCtx.Query("name")
e := d.DbSqlApp.GetBy(dbSql)
if e != nil {
return
}
rc.ResData = dbSql
}

View File

@@ -14,7 +14,7 @@ type DbSqlExec struct {
func (d *DbSqlExec) DbSqlExecs(rc *req.Ctx) {
queryCond, page := ginx.BindQueryAndPage(rc.GinCtx, new(entity.DbSqlExecQuery))
queryCond.CreatorId = rc.LoginAccount.Id
queryCond.CreatorId = rc.GetLoginAccount().Id
res, err := d.DbSqlExecApp.GetPageList(queryCond, page, new([]entity.DbSqlExec))
biz.ErrIsNil(err)
rc.ResData = res

View File

@@ -43,9 +43,7 @@ func (d *Instance) SaveInstance(rc *req.Ctx) {
// 密码脱敏记录日志
form.Password = "****"
rc.ReqParam = form
instance.SetBaseInfo(rc.LoginAccount)
biz.ErrIsNil(d.InstanceApp.Save(instance))
biz.ErrIsNil(d.InstanceApp.Save(rc.MetaCtx, instance))
}
// GetInstance 获取数据库实例密码,由于数据库是加密存储,故提供该接口展示原文密码
@@ -84,7 +82,7 @@ func (d *Instance) DeleteInstance(rc *req.Ctx) {
biz.ErrIsNil(err, "获取数据库实例错误数据库实例ID为: %d", instance.Id)
biz.IsTrue(false, "不能删除数据库实例【%s】请先删除其关联的数据库资源。", instance.Name)
}
d.InstanceApp.Delete(instanceId)
d.InstanceApp.Delete(rc.MetaCtx, instanceId)
}
}

View File

@@ -8,6 +8,7 @@ var (
instanceApp Instance = newInstanceApp(persistence.GetInstanceRepo())
dbApp Db = newDbApp(persistence.GetDbRepo(), persistence.GetDbSqlRepo(), instanceApp)
dbSqlExecApp DbSqlExec = newDbSqlExecApp(persistence.GetDbSqlExecRepo())
dbSqlApp DbSql = newDbSqlApp(persistence.GetDbSqlRepo())
)
func GetInstanceApp() Instance {
@@ -18,6 +19,10 @@ func GetDbApp() Db {
return dbApp
}
func GetDbSqlApp() DbSql {
return dbSqlApp
}
func GetDbSqlExecApp() DbSqlExec {
return dbSqlExecApp
}

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"mayfly-go/internal/db/dbm"
"mayfly-go/internal/db/domain/entity"
"mayfly-go/internal/db/domain/repository"
@@ -20,10 +21,10 @@ type Db interface {
Count(condition *entity.DbQuery) int64
Save(entity *entity.Db) error
Save(ctx context.Context, entity *entity.Db) error
// 删除数据库信息
Delete(id uint64) error
Delete(ctx context.Context, id uint64) error
// 获取数据库连接实例
// @param id 数据库id
@@ -56,7 +57,7 @@ func (d *dbAppImpl) Count(condition *entity.DbQuery) int64 {
return d.GetRepo().Count(condition)
}
func (d *dbAppImpl) Save(dbEntity *entity.Db) error {
func (d *dbAppImpl) Save(ctx context.Context, dbEntity *entity.Db) error {
// 查找是否存在
oldDb := &entity.Db{Name: dbEntity.Name, InstanceId: dbEntity.InstanceId}
err := d.GetBy(oldDb)
@@ -65,7 +66,7 @@ func (d *dbAppImpl) Save(dbEntity *entity.Db) error {
if err == nil {
return errorx.NewBiz("该实例下数据库名已存在")
}
return d.Insert(dbEntity)
return d.Insert(ctx, dbEntity)
}
// 如果存在该库,则校验修改的库是否为该库
@@ -90,13 +91,13 @@ func (d *dbAppImpl) Save(dbEntity *entity.Db) error {
// 关闭数据库连接
dbm.CloseDb(dbEntity.Id, v)
// 删除该库关联的所有sql记录
d.dbSqlRepo.DeleteByCond(&entity.DbSql{DbId: dbId, Db: v})
d.dbSqlRepo.DeleteByCond(ctx, &entity.DbSql{DbId: dbId, Db: v})
}
return d.UpdateById(dbEntity)
return d.UpdateById(ctx, dbEntity)
}
func (d *dbAppImpl) Delete(id uint64) error {
func (d *dbAppImpl) Delete(ctx context.Context, id uint64) error {
db, err := d.GetById(new(entity.Db), id)
if err != nil {
return errorx.NewBiz("该数据库不存在")
@@ -107,8 +108,8 @@ func (d *dbAppImpl) Delete(id uint64) error {
dbm.CloseDb(id, v)
}
// 删除该库下用户保存的所有sql信息
d.dbSqlRepo.DeleteByCond(&entity.DbSql{DbId: id})
return d.DeleteById(id)
d.dbSqlRepo.DeleteByCond(ctx, &entity.DbSql{DbId: id})
return d.DeleteById(ctx, id)
}
func (d *dbAppImpl) GetDbConn(dbId uint64, dbName string) (*dbm.DbConn, error) {

View File

@@ -0,0 +1,21 @@
package application
import (
"mayfly-go/internal/db/domain/entity"
"mayfly-go/internal/db/domain/repository"
"mayfly-go/pkg/base"
)
type DbSql interface {
base.App[*entity.DbSql]
}
type dbSqlAppImpl struct {
base.AppImpl[*entity.DbSql, repository.DbSql]
}
func newDbSqlApp(dbSqlRepo repository.DbSql) DbSql {
app := new(dbSqlAppImpl)
app.Repo = dbSqlRepo
return app
}

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"encoding/json"
"fmt"
"mayfly-go/internal/db/config"
@@ -49,7 +50,7 @@ type DbSqlExec interface {
Exec(execSqlReq *DbSqlExecReq) (*DbSqlExecRes, error)
// 根据条件删除sql执行记录
DeleteBy(condition *entity.DbSqlExec)
DeleteBy(ctx context.Context, condition *entity.DbSqlExec)
// 分页获取
GetPageList(condition *entity.DbSqlExecQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
@@ -139,19 +140,19 @@ func (d *dbSqlExecAppImpl) Exec(execSqlReq *DbSqlExecReq) (*DbSqlExecRes, error)
// 保存sql执行记录如果是查询类则根据系统配置判断是否保存
func (d *dbSqlExecAppImpl) saveSqlExecLog(isQuery bool, dbSqlExecRecord *entity.DbSqlExec) {
if !isQuery {
d.dbSqlExecRepo.Insert(dbSqlExecRecord)
d.dbSqlExecRepo.Insert(context.TODO(), dbSqlExecRecord)
return
}
if config.GetDbSaveQuerySql() {
dbSqlExecRecord.Table = "-"
dbSqlExecRecord.OldValue = "-"
dbSqlExecRecord.Type = entity.DbSqlExecTypeQuery
d.dbSqlExecRepo.Insert(dbSqlExecRecord)
d.dbSqlExecRepo.Insert(context.TODO(), dbSqlExecRecord)
}
}
func (d *dbSqlExecAppImpl) DeleteBy(condition *entity.DbSqlExec) {
d.dbSqlExecRepo.DeleteByCond(condition)
func (d *dbSqlExecAppImpl) DeleteBy(ctx context.Context, condition *entity.DbSqlExec) {
d.dbSqlExecRepo.DeleteByCond(ctx, condition)
}
func (d *dbSqlExecAppImpl) GetPageList(condition *entity.DbSqlExecQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"mayfly-go/internal/db/domain/entity"
"mayfly-go/internal/db/domain/repository"
"mayfly-go/pkg/base"
@@ -16,10 +17,10 @@ type Instance interface {
Count(condition *entity.InstanceQuery) int64
Save(instanceEntity *entity.DbInstance) error
Save(ctx context.Context, instanceEntity *entity.DbInstance) error
// Delete 删除数据库信息
Delete(id uint64) error
Delete(ctx context.Context, id uint64) error
// GetDatabases 获取数据库实例的所有数据库列表
GetDatabases(entity *entity.DbInstance) ([]string, error)
@@ -44,7 +45,7 @@ func (app *instanceAppImpl) Count(condition *entity.InstanceQuery) int64 {
return app.CountByCond(condition)
}
func (app *instanceAppImpl) Save(instanceEntity *entity.DbInstance) error {
func (app *instanceAppImpl) Save(ctx context.Context, instanceEntity *entity.DbInstance) error {
// 默认tcp连接
instanceEntity.Network = instanceEntity.GetNetwork()
@@ -72,7 +73,7 @@ func (app *instanceAppImpl) Save(instanceEntity *entity.DbInstance) error {
return errorx.NewBiz("该数据库实例已存在")
}
instanceEntity.PwdEncrypt()
return app.Insert(instanceEntity)
return app.Insert(ctx, instanceEntity)
}
// 如果存在该库,则校验修改的库是否为该库
@@ -80,11 +81,11 @@ func (app *instanceAppImpl) Save(instanceEntity *entity.DbInstance) error {
return errorx.NewBiz("该数据库实例已存在")
}
instanceEntity.PwdEncrypt()
return app.UpdateById(instanceEntity)
return app.UpdateById(ctx, instanceEntity)
}
func (app *instanceAppImpl) Delete(id uint64) error {
return app.DeleteById(id)
func (app *instanceAppImpl) Delete(ctx context.Context, id uint64) error {
return app.DeleteById(ctx, id)
}
func (app *instanceAppImpl) GetDatabases(ed *entity.DbInstance) ([]string, error) {

View File

@@ -46,15 +46,6 @@ func InitDbRouter(router *gin.RouterGroup) {
req.NewGet(":dbId/c-metadata", d.ColumnMA),
req.NewGet(":dbId/hint-tables", d.HintTables),
// 用户sql相关
req.NewPost(":dbId/sql", d.SaveSql),
req.NewGet(":dbId/sql", d.GetSql),
req.NewDelete(":dbId/sql", d.DeleteSql),
req.NewGet(":dbId/sql-names", d.GetSqlNames),
}
req.BatchSetGroup(db, reqs[:])

View File

@@ -0,0 +1,32 @@
package router
import (
"mayfly-go/internal/db/api"
"mayfly-go/internal/db/application"
"mayfly-go/pkg/req"
"github.com/gin-gonic/gin"
)
func InitDbSqlRouter(router *gin.RouterGroup) {
db := router.Group("dbs")
dbSql := &api.DbSql{
DbSqlApp: application.GetDbSqlApp(),
}
reqs := [...]*req.Conf{
// 用户sql相关
req.NewPost(":dbId/sql", dbSql.SaveSql),
req.NewGet(":dbId/sql", dbSql.GetSql),
req.NewDelete(":dbId/sql", dbSql.DeleteSql),
req.NewGet(":dbId/sql-names", dbSql.GetSqlNames),
}
req.BatchSetGroup(db, reqs[:])
}

View File

@@ -5,5 +5,6 @@ import "github.com/gin-gonic/gin"
func Init(router *gin.RouterGroup) {
InitInstanceRouter(router)
InitDbRouter(router)
InitDbSqlRouter(router)
InitDbSqlExecRouter(router)
}

View File

@@ -44,8 +44,7 @@ func (c *AuthCert) SaveAuthCert(rc *req.Ctx) {
acForm.Password = "***"
rc.ReqParam = acForm
ac.SetBaseInfo(rc.LoginAccount)
biz.ErrIsNil(c.AuthCertApp.Save(ac))
biz.ErrIsNil(c.AuthCertApp.Save(rc.MetaCtx, ac))
}
func (c *AuthCert) Delete(rc *req.Ctx) {
@@ -56,6 +55,6 @@ func (c *AuthCert) Delete(rc *req.Ctx) {
for _, v := range ids {
value, err := strconv.Atoi(v)
biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
c.AuthCertApp.DeleteById(uint64(value))
c.AuthCertApp.DeleteById(rc.MetaCtx, uint64(value))
}
}

View File

@@ -39,7 +39,7 @@ func (m *Machine) Machines(rc *req.Ctx) {
condition, pageParam := ginx.BindQueryAndPage(rc.GinCtx, new(entity.MachineQuery))
// 不存在可访问标签id即没有可操作数据
tagIds := m.TagApp.ListTagIdByAccountId(rc.LoginAccount.Id)
tagIds := m.TagApp.ListTagIdByAccountId(rc.GetLoginAccount().Id)
if len(tagIds) == 0 {
rc.ResData = model.EmptyPageResult[any]()
return
@@ -55,12 +55,20 @@ func (m *Machine) Machines(rc *req.Ctx) {
for _, mv := range *res.List {
mv.HasCli = mcm.HasCli(mv.Id)
if machineStats, err := m.MachineApp.GetMachineStats(mv.Id); err == nil {
mv.Stat = collx.M{
"cpuIdle": machineStats.CPU.Idle,
"memAvailable": machineStats.MemInfo.Available,
"memTotal": machineStats.MemInfo.Total,
"fsInfos": machineStats.FSInfos,
}
}
}
rc.ResData = res
}
func (m *Machine) MachineTags(rc *req.Ctx) {
rc.ResData = m.TagApp.ListTagByAccountIdAndResource(rc.LoginAccount.Id, new(entity.Machine))
rc.ResData = m.TagApp.ListTagByAccountIdAndResource(rc.GetLoginAccount().Id, new(entity.Machine))
}
func (m *Machine) MachineStats(rc *req.Ctx) {
@@ -77,8 +85,7 @@ func (m *Machine) SaveMachine(rc *req.Ctx) {
machineForm.Password = "******"
rc.ReqParam = machineForm
me.SetBaseInfo(rc.LoginAccount)
biz.ErrIsNil(m.MachineApp.Save(me))
biz.ErrIsNil(m.MachineApp.Save(rc.MetaCtx, me))
}
func (m *Machine) TestConn(rc *req.Ctx) {
@@ -92,7 +99,7 @@ func (m *Machine) ChangeStatus(rc *req.Ctx) {
id := uint64(ginx.PathParamInt(g, "machineId"))
status := int8(ginx.PathParamInt(g, "status"))
rc.ReqParam = collx.Kvs("id", id, "status", status)
biz.ErrIsNil(m.MachineApp.ChangeStatus(id, status))
biz.ErrIsNil(m.MachineApp.ChangeStatus(rc.MetaCtx, id, status))
}
func (m *Machine) DeleteMachine(rc *req.Ctx) {
@@ -103,7 +110,7 @@ func (m *Machine) DeleteMachine(rc *req.Ctx) {
for _, v := range ids {
value, err := strconv.Atoi(v)
biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
m.MachineApp.Delete(uint64(value))
m.MachineApp.Delete(rc.MetaCtx, uint64(value))
}
}
@@ -133,7 +140,7 @@ func (m *Machine) GetProcess(rc *req.Ctx) {
cli, err := m.MachineApp.GetCli(GetMachineId(rc.GinCtx))
biz.ErrIsNilAppendErr(err, "获取客户端连接失败: %s")
biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.LoginAccount.Id, cli.Info.TagPath), "%s")
biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.GetLoginAccount().Id, cli.Info.TagPath), "%s")
res, err := cli.Run(cmd)
biz.ErrIsNilAppendErr(err, "获取进程信息失败: %s")
@@ -147,7 +154,7 @@ func (m *Machine) KillProcess(rc *req.Ctx) {
cli, err := m.MachineApp.GetCli(GetMachineId(rc.GinCtx))
biz.ErrIsNilAppendErr(err, "获取客户端连接失败: %s")
biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.LoginAccount.Id, cli.Info.TagPath), "%s")
biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.GetLoginAccount().Id, cli.Info.TagPath), "%s")
res, err := cli.Run("sudo kill -9 " + pid)
biz.ErrIsNil(err, "终止进程失败: %s", res)
@@ -173,7 +180,7 @@ func (m *Machine) WsSSH(g *gin.Context) {
cli, err := m.MachineApp.GetCli(GetMachineId(g))
biz.ErrIsNilAppendErr(err, "获取客户端连接失败: %s")
biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.LoginAccount.Id, cli.Info.TagPath), "%s")
biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.GetLoginAccount().Id, cli.Info.TagPath), "%s")
cols := ginx.QueryInt(g, "cols", 80)
rows := ginx.QueryInt(g, "rows", 40)
@@ -182,7 +189,7 @@ func (m *Machine) WsSSH(g *gin.Context) {
if cli.Info.EnableRecorder == 1 {
now := time.Now()
// 回放文件路径为: 基础配置路径/机器id/操作日期/操作者账号/操作时间.cast
recPath := fmt.Sprintf("%s/%d/%s/%s", config.Conf.Server.GetMachineRecPath(), cli.Info.Id, now.Format("20060102"), rc.LoginAccount.Username)
recPath := fmt.Sprintf("%s/%d/%s/%s", config.Conf.Server.GetMachineRecPath(), cli.Info.Id, now.Format("20060102"), rc.GetLoginAccount().Username)
os.MkdirAll(recPath, 0766)
fileName := path.Join(recPath, fmt.Sprintf("%s.cast", now.Format("20060102_150405")))
f, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0766)

View File

@@ -35,12 +35,12 @@ func (m *MachineCronJob) Save(rc *req.Ctx) {
jobForm := new(form.MachineCronJobForm)
mcj := ginx.BindJsonAndCopyTo[*entity.MachineCronJob](rc.GinCtx, jobForm, new(entity.MachineCronJob))
rc.ReqParam = jobForm
mcj.SetBaseInfo(rc.LoginAccount)
cronJobId, err := m.MachineCronJobApp.Save(mcj)
cronJobId, err := m.MachineCronJobApp.Save(rc.MetaCtx, mcj)
biz.ErrIsNil(err)
// 关联机器
m.MachineCronJobApp.CronJobRelateMachines(cronJobId, jobForm.MachineIds, rc.LoginAccount)
m.MachineCronJobApp.CronJobRelateMachines(rc.MetaCtx, cronJobId, jobForm.MachineIds)
}
func (m *MachineCronJob) Delete(rc *req.Ctx) {
@@ -51,7 +51,7 @@ func (m *MachineCronJob) Delete(rc *req.Ctx) {
for _, v := range ids {
value, err := strconv.Atoi(v)
biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
m.MachineCronJobApp.Delete(uint64(value))
m.MachineCronJobApp.Delete(rc.MetaCtx, uint64(value))
}
}

View File

@@ -52,14 +52,13 @@ func (m *MachineFile) MachineFiles(rc *req.Ctx) {
func (m *MachineFile) SaveMachineFiles(rc *req.Ctx) {
fileForm := new(form.MachineFileForm)
entity := ginx.BindJsonAndCopyTo[*entity.MachineFile](rc.GinCtx, fileForm, new(entity.MachineFile))
entity.SetBaseInfo(rc.LoginAccount)
rc.ReqParam = fileForm
biz.ErrIsNil(m.MachineFileApp.Save(entity))
biz.ErrIsNil(m.MachineFileApp.Save(rc.MetaCtx, entity))
}
func (m *MachineFile) DeleteFile(rc *req.Ctx) {
biz.ErrIsNil(m.MachineFileApp.Delete(GetMachineFileId(rc.GinCtx)))
biz.ErrIsNil(m.MachineFileApp.Delete(rc.MetaCtx, GetMachineFileId(rc.GinCtx)))
}
/*** sftp相关操作 */
@@ -190,7 +189,7 @@ func (m *MachineFile) UploadFile(rc *req.Ctx) {
file, _ := fileheader.Open()
defer file.Close()
la := rc.LoginAccount
la := rc.GetLoginAccount()
defer func() {
if anyx.ToString(recover()) != "" {
logx.Errorf("文件上传失败: %s", err)
@@ -262,7 +261,7 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
wg.Add(len(chunks))
isSuccess := true
la := rc.LoginAccount
la := rc.GetLoginAccount()
for _, chunk := range chunks {
go func(files []FolderFile, wg *sync.WaitGroup) {
defer func() {
@@ -298,7 +297,7 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
wg.Wait()
if isSuccess {
// 保存消息并发送文件上传成功通知
m.MsgApp.CreateAndSend(rc.LoginAccount, msgdto.SuccessSysMsg("文件上传成功", fmt.Sprintf("[%s]文件夹已成功上传至 %s[%s:%s]", folderName, mi.Name, mi.Ip, basePath)))
m.MsgApp.CreateAndSend(la, msgdto.SuccessSysMsg("文件上传成功", fmt.Sprintf("[%s]文件夹已成功上传至 %s[%s:%s]", folderName, mi.Name, mi.Ip, basePath)))
}
}

View File

@@ -37,9 +37,7 @@ func (m *MachineScript) SaveMachineScript(rc *req.Ctx) {
machineScript := ginx.BindJsonAndCopyTo(rc.GinCtx, form, new(entity.MachineScript))
rc.ReqParam = form
machineScript.SetBaseInfo(rc.LoginAccount)
biz.ErrIsNil(m.MachineScriptApp.Save(machineScript))
biz.ErrIsNil(m.MachineScriptApp.Save(rc.MetaCtx, machineScript))
}
func (m *MachineScript) DeleteMachineScript(rc *req.Ctx) {
@@ -50,7 +48,7 @@ func (m *MachineScript) DeleteMachineScript(rc *req.Ctx) {
for _, v := range ids {
value, err := strconv.Atoi(v)
biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
m.MachineScriptApp.Delete(uint64(value))
m.MachineScriptApp.Delete(rc.MetaCtx, uint64(value))
}
}
@@ -71,7 +69,7 @@ func (m *MachineScript) RunMachineScript(rc *req.Ctx) {
}
cli, err := m.MachineApp.GetCli(machineId)
biz.ErrIsNilAppendErr(err, "获取客户端连接失败: %s")
biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.LoginAccount.Id, cli.Info.TagPath), "%s")
biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.GetLoginAccount().Id, cli.Info.TagPath), "%s")
res, err := cli.Run(script)
// 记录请求参数

View File

@@ -26,11 +26,13 @@ type MachineVO struct {
UpdateTime *time.Time `json:"updateTime"`
Modifier *string `json:"modifier"`
ModifierId *int64 `json:"modifierId"`
HasCli bool `json:"hasCli" gorm:"-"`
Remark *string `json:"remark"`
EnableRecorder int8 `json:"enableRecorder"`
TagId uint64 `json:"tagId"`
TagPath string `json:"tagPath"`
HasCli bool `json:"hasCli" gorm:"-"`
Stat map[string]any `json:"stat" gorm:"-"`
}
type MachineScriptVO struct {

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"mayfly-go/internal/machine/domain/entity"
"mayfly-go/internal/machine/domain/repository"
"mayfly-go/pkg/base"
@@ -13,7 +14,7 @@ type AuthCert interface {
GetPageList(condition *entity.AuthCertQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
Save(ac *entity.AuthCert) error
Save(ctx context.Context, ac *entity.AuthCert) error
GetByIds(ids ...uint64) []*entity.AuthCert
}
@@ -32,7 +33,7 @@ func (a *authCertAppImpl) GetPageList(condition *entity.AuthCertQuery, pageParam
return a.GetRepo().GetPageList(condition, pageParam, toEntity)
}
func (a *authCertAppImpl) Save(ac *entity.AuthCert) error {
func (a *authCertAppImpl) Save(ctx context.Context, ac *entity.AuthCert) error {
oldAc := &entity.AuthCert{Name: ac.Name}
err := a.GetBy(oldAc, "Id", "Name")
@@ -41,14 +42,14 @@ func (a *authCertAppImpl) Save(ac *entity.AuthCert) error {
if err == nil {
return errorx.NewBiz("该凭证名已存在")
}
return a.Insert(ac)
return a.Insert(ctx, ac)
}
// 如果存在该库,则校验修改的库是否为该库
if err == nil && oldAc.Id != ac.Id {
return errorx.NewBiz("该凭证名已存在")
}
return a.UpdateById(ac)
return a.UpdateById(ctx, ac)
}
func (a *authCertAppImpl) GetByIds(ids ...uint64) []*entity.AuthCert {

View File

@@ -1,14 +1,20 @@
package application
import (
"context"
"fmt"
"mayfly-go/internal/machine/api/vo"
"mayfly-go/internal/machine/domain/entity"
"mayfly-go/internal/machine/domain/repository"
"mayfly-go/internal/machine/infrastructure/cache"
"mayfly-go/internal/machine/mcm"
"mayfly-go/pkg/base"
"mayfly-go/pkg/errorx"
"mayfly-go/pkg/gormx"
"mayfly-go/pkg/logx"
"mayfly-go/pkg/model"
"mayfly-go/pkg/scheduler"
"time"
"gorm.io/gorm"
)
@@ -16,17 +22,17 @@ import (
type Machine interface {
base.App[*entity.Machine]
Save(*entity.Machine) error
Save(ctx context.Context, m *entity.Machine) error
// 测试机器连接
TestConn(me *entity.Machine) error
// 调整机器状态
ChangeStatus(id uint64, status int8) error
ChangeStatus(ctx context.Context, id uint64, status int8) error
Count(condition *entity.MachineQuery) int64
Delete(id uint64) error
Delete(ctx context.Context, id uint64) error
// 分页获取机器信息列表
GetMachineList(condition *entity.MachineQuery, pageParam *model.PageParam, toEntity *[]*vo.MachineVO, orderBy ...string) (*model.PageResult[*[]*vo.MachineVO], error)
@@ -36,6 +42,12 @@ type Machine interface {
// 获取ssh隧道机器连接
GetSshTunnelMachine(id int) (*mcm.SshTunnelMachine, error)
// 定时更新机器状态信息
TimerUpdateStats()
// 获取机器运行时状态信息
GetMachineStats(machineId uint64) (*mcm.Stats, error)
}
func newMachineApp(machineRepo repository.Machine, authCertApp AuthCert) Machine {
@@ -61,7 +73,7 @@ func (m *machineAppImpl) Count(condition *entity.MachineQuery) int64 {
return m.GetRepo().Count(condition)
}
func (m *machineAppImpl) Save(me *entity.Machine) error {
func (m *machineAppImpl) Save(ctx context.Context, me *entity.Machine) error {
oldMachine := &entity.Machine{Ip: me.Ip, Port: me.Port, Username: me.Username}
if me.SshTunnelMachineId > 0 {
oldMachine.SshTunnelMachineId = me.SshTunnelMachineId
@@ -75,7 +87,7 @@ func (m *machineAppImpl) Save(me *entity.Machine) error {
}
// 新增机器,默认启用状态
me.Status = entity.MachineStatusEnable
return m.Insert(me)
return m.Insert(ctx, me)
}
// 如果存在该库,则校验修改的库是否为该库
@@ -85,7 +97,7 @@ func (m *machineAppImpl) Save(me *entity.Machine) error {
// 关闭连接
mcm.DeleteCli(me.Id)
return m.UpdateById(me)
return m.UpdateById(ctx, me)
}
func (m *machineAppImpl) TestConn(me *entity.Machine) error {
@@ -102,7 +114,7 @@ func (m *machineAppImpl) TestConn(me *entity.Machine) error {
return nil
}
func (m *machineAppImpl) ChangeStatus(id uint64, status int8) error {
func (m *machineAppImpl) ChangeStatus(ctx context.Context, id uint64, status int8) error {
if status == entity.MachineStatusDisable {
// 关闭连接
mcm.DeleteCli(id)
@@ -110,11 +122,11 @@ func (m *machineAppImpl) ChangeStatus(id uint64, status int8) error {
machine := new(entity.Machine)
machine.Id = id
machine.Status = status
return m.UpdateById(machine)
return m.UpdateById(ctx, machine)
}
// 根据条件获取机器信息
func (m *machineAppImpl) Delete(id uint64) error {
func (m *machineAppImpl) Delete(ctx context.Context, id uint64) error {
// 关闭连接
mcm.DeleteCli(id)
return gormx.Tx(
@@ -145,6 +157,39 @@ func (m *machineAppImpl) GetSshTunnelMachine(machineId int) (*mcm.SshTunnelMachi
})
}
func (m *machineAppImpl) TimerUpdateStats() {
logx.Debug("开始定时收集并缓存服务器状态信息...")
scheduler.AddFun("@every 2m", func() {
machineIds := new([]entity.Machine)
m.GetRepo().ListByCond(&entity.Machine{Status: entity.MachineStatusEnable}, machineIds, "id")
for _, ma := range *machineIds {
go func(mid uint64) {
defer func() {
if err := recover(); err != nil {
logx.ErrorTrace(fmt.Sprintf("定时获取机器[id=%d]状态信息失败", mid), err.(error))
}
}()
logx.Debugf("定时获取机器[id=%d]状态信息开始", mid)
cli, err := m.GetCli(mid)
// ssh获取客户端失败则更新机器状态为禁用
if err != nil {
updateMachine := &entity.Machine{Status: entity.MachineStatusDisable}
updateMachine.Id = mid
now := time.Now()
updateMachine.UpdateTime = &now
m.UpdateById(context.TODO(), updateMachine)
}
cache.SaveMachineStats(mid, cli.GetAllStats())
logx.Debugf("定时获取机器[id=%d]状态信息结束", mid)
}(ma.Id)
}
})
}
func (m *machineAppImpl) GetMachineStats(machineId uint64) (*mcm.Stats, error) {
return cache.GetMachineStats(machineId)
}
// 生成机器信息根据授权凭证id填充用户密码等
func (m *machineAppImpl) toMachineInfoById(machineId uint64) (*mcm.MachineInfo, error) {
me, err := m.GetById(new(entity.Machine), machineId)

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"mayfly-go/internal/machine/domain/entity"
"mayfly-go/internal/machine/domain/repository"
"mayfly-go/pkg/base"
@@ -25,9 +26,9 @@ type MachineCronJob interface {
// 获取分页执行结果列表
GetExecPageList(condition *entity.MachineCronJobExec, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
Save(entity *entity.MachineCronJob) (uint64, error)
Save(ctx context.Context, entity *entity.MachineCronJob) (uint64, error)
Delete(id uint64)
Delete(ctx context.Context, id uint64)
// 获取计划任务关联的机器列表id
GetRelateMachineIds(cronJobId uint64) []uint64
@@ -36,10 +37,10 @@ type MachineCronJob interface {
GetRelateCronJobIds(machineId uint64) []uint64
// 计划任务关联机器
CronJobRelateMachines(cronJobId uint64, machineIds []uint64, la *model.LoginAccount)
CronJobRelateMachines(ctx context.Context, cronJobId uint64, machineIds []uint64)
// 机器关联计划任务
MachineRelateCronJobs(machineId uint64, cronJobs []uint64, la *model.LoginAccount)
MachineRelateCronJobs(ctx context.Context, machineId uint64, cronJobs []uint64)
// 初始化计划任务
InitCronJob()
@@ -79,10 +80,10 @@ func (m *machineCropJobAppImpl) GetExecPageList(condition *entity.MachineCronJob
}
// 保存机器任务信息
func (m *machineCropJobAppImpl) Save(mcj *entity.MachineCronJob) (uint64, error) {
func (m *machineCropJobAppImpl) Save(ctx context.Context, mcj *entity.MachineCronJob) (uint64, error) {
// 更新操作
if mcj.Id != 0 {
m.UpdateById(mcj)
m.UpdateById(ctx, mcj)
cj, err := m.GetById(new(entity.MachineCronJob), mcj.Id)
if err != nil {
return 0, errorx.NewBiz("该任务不存在")
@@ -93,16 +94,16 @@ func (m *machineCropJobAppImpl) Save(mcj *entity.MachineCronJob) (uint64, error)
}
m.addCronJob(mcj)
if err := m.Insert(mcj); err != nil {
if err := m.Insert(ctx, mcj); err != nil {
return 0, err
}
return mcj.Id, nil
}
func (m *machineCropJobAppImpl) Delete(id uint64) {
m.DeleteById(id)
m.machineCropJobExecRepo.DeleteByCond(&entity.MachineCronJobExec{CronJobId: id})
m.machineCropJobRelateRepo.DeleteByCond(&entity.MachineCronJobRelate{CronJobId: id})
func (m *machineCropJobAppImpl) Delete(ctx context.Context, id uint64) {
m.DeleteById(ctx, id)
m.machineCropJobExecRepo.DeleteByCond(ctx, &entity.MachineCronJobExec{CronJobId: id})
m.machineCropJobRelateRepo.DeleteByCond(ctx, &entity.MachineCronJobRelate{CronJobId: id})
}
func (m *machineCropJobAppImpl) GetRelateMachineIds(cronJobId uint64) []uint64 {
@@ -113,47 +114,39 @@ func (m *machineCropJobAppImpl) GetRelateCronJobIds(machineId uint64) []uint64 {
return m.machineCropJobRelateRepo.GetCronJobIds(machineId)
}
func (m *machineCropJobAppImpl) CronJobRelateMachines(cronJobId uint64, machineIds []uint64, la *model.LoginAccount) {
func (m *machineCropJobAppImpl) CronJobRelateMachines(ctx context.Context, cronJobId uint64, machineIds []uint64) {
oldMachineIds := m.machineCropJobRelateRepo.GetMachineIds(cronJobId)
addIds, delIds, _ := collx.ArrayCompare[uint64](machineIds, oldMachineIds, func(u1, u2 uint64) bool { return u1 == u2 })
addVals := make([]*entity.MachineCronJobRelate, 0)
now := time.Now()
for _, addId := range addIds {
addVals = append(addVals, &entity.MachineCronJobRelate{
MachineId: addId,
CronJobId: cronJobId,
Creator: la.Username,
CreatorId: la.Id,
CreateTime: &now,
MachineId: addId,
CronJobId: cronJobId,
})
}
m.machineCropJobRelateRepo.BatchInsert(addVals)
m.machineCropJobRelateRepo.BatchInsert(ctx, addVals)
for _, delId := range delIds {
m.machineCropJobRelateRepo.DeleteByCond(&entity.MachineCronJobRelate{CronJobId: cronJobId, MachineId: delId})
m.machineCropJobRelateRepo.DeleteByCond(ctx, &entity.MachineCronJobRelate{CronJobId: cronJobId, MachineId: delId})
}
}
func (m *machineCropJobAppImpl) MachineRelateCronJobs(machineId uint64, cronJobs []uint64, la *model.LoginAccount) {
func (m *machineCropJobAppImpl) MachineRelateCronJobs(ctx context.Context, machineId uint64, cronJobs []uint64) {
oldCronIds := m.machineCropJobRelateRepo.GetCronJobIds(machineId)
addIds, delIds, _ := collx.ArrayCompare[uint64](cronJobs, oldCronIds, func(u1, u2 uint64) bool { return u1 == u2 })
addVals := make([]*entity.MachineCronJobRelate, 0)
now := time.Now()
for _, addId := range addIds {
addVals = append(addVals, &entity.MachineCronJobRelate{
MachineId: machineId,
CronJobId: addId,
Creator: la.Username,
CreatorId: la.Id,
CreateTime: &now,
MachineId: machineId,
CronJobId: addId,
})
}
m.machineCropJobRelateRepo.BatchInsert(addVals)
m.machineCropJobRelateRepo.BatchInsert(ctx, addVals)
for _, delId := range delIds {
m.machineCropJobRelateRepo.DeleteByCond(&entity.MachineCronJobRelate{CronJobId: delId, MachineId: machineId})
m.machineCropJobRelateRepo.DeleteByCond(ctx, &entity.MachineCronJobRelate{CronJobId: delId, MachineId: machineId})
}
}
@@ -240,7 +233,7 @@ func (m *machineCropJobAppImpl) runCronJob0(mid uint64, cronJob *entity.MachineC
defer func() {
if err := recover(); err != nil {
res := anyx.ToString(err)
m.machineCropJobExecRepo.Insert(&entity.MachineCronJobExec{
m.machineCropJobExecRepo.Insert(context.TODO(), &entity.MachineCronJobExec{
MachineId: mid,
CronJobId: cronJob.Id,
ExecTime: time.Now(),
@@ -280,5 +273,5 @@ func (m *machineCropJobAppImpl) runCronJob0(mid uint64, cronJob *entity.MachineC
execRes.Status = entity.MachineCronJobExecStatusError
}
// 保存执行记录
m.machineCropJobExecRepo.Insert(execRes)
m.machineCropJobExecRepo.Insert(context.TODO(), execRes)
}

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"errors"
"fmt"
"io"
@@ -27,9 +28,9 @@ type MachineFile interface {
// 根据id获取
GetById(id uint64, cols ...string) *entity.MachineFile
Save(entity *entity.MachineFile) error
Save(ctx context.Context, entity *entity.MachineFile) error
Delete(id uint64) error
Delete(ctx context.Context, id uint64) error
// 获取文件关联的机器信息,主要用于记录日志使用
// GetMachine(fileId uint64) *mcm.Info
@@ -91,31 +92,34 @@ func (m *machineFileAppImpl) GetPageList(condition *entity.MachineFile, pagePara
// 根据条件获取
func (m *machineFileAppImpl) GetMachineFile(condition *entity.MachineFile, cols ...string) error {
return m.machineFileRepo.GetMachineFile(condition, cols...)
return m.machineFileRepo.GetBy(condition, cols...)
}
// 根据id获取
func (m *machineFileAppImpl) GetById(id uint64, cols ...string) *entity.MachineFile {
return m.machineFileRepo.GetById(id, cols...)
mf := new(entity.MachineFile)
if err := m.machineFileRepo.GetById(mf, id, cols...); err == nil {
return mf
}
return nil
}
// 保存机器文件配置
func (m *machineFileAppImpl) Save(mf *entity.MachineFile) error {
func (m *machineFileAppImpl) Save(ctx context.Context, mf *entity.MachineFile) error {
_, err := m.machineApp.GetById(new(entity.Machine), mf.MachineId, "Name")
if err != nil {
return errorx.NewBiz("该机器不存在")
}
if mf.Id != 0 {
return m.machineFileRepo.UpdateById(mf)
return m.machineFileRepo.UpdateById(ctx, mf)
}
return m.machineFileRepo.Create(mf)
return m.machineFileRepo.Insert(ctx, mf)
}
// 根据id删除
func (m *machineFileAppImpl) Delete(id uint64) error {
return m.machineFileRepo.Delete(id)
func (m *machineFileAppImpl) Delete(ctx context.Context, id uint64) error {
return m.machineFileRepo.DeleteById(ctx, id)
}
func (m *machineFileAppImpl) ReadDir(fid uint64, path string) ([]fs.FileInfo, error) {

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"mayfly-go/internal/machine/domain/entity"
"mayfly-go/internal/machine/domain/repository"
"mayfly-go/pkg/base"
@@ -14,9 +15,9 @@ type MachineScript interface {
// 分页获取机器脚本信息列表
GetPageList(condition *entity.MachineScript, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
Save(entity *entity.MachineScript) error
Save(ctx context.Context, entity *entity.MachineScript) error
Delete(id uint64)
Delete(ctx context.Context, id uint64)
}
func newMachineScriptApp(machineScriptRepo repository.MachineScript, machineApp Machine) MachineScript {
@@ -39,7 +40,7 @@ func (m *machineScriptAppImpl) GetPageList(condition *entity.MachineScript, page
}
// 保存机器脚本
func (m *machineScriptAppImpl) Save(ms *entity.MachineScript) error {
func (m *machineScriptAppImpl) Save(ctx context.Context, ms *entity.MachineScript) error {
// 如果机器id不为公共脚本id则校验机器是否存在
if machineId := ms.MachineId; machineId != Common_Script_Machine_Id {
_, err := m.machineApp.GetById(new(entity.Machine), machineId, "Name")
@@ -49,12 +50,12 @@ func (m *machineScriptAppImpl) Save(ms *entity.MachineScript) error {
}
if ms.Id != 0 {
return m.UpdateById(ms)
return m.UpdateById(ctx, ms)
}
return m.Insert(ms)
return m.Insert(ctx, ms)
}
// 根据id删除
func (m *machineScriptAppImpl) Delete(id uint64) {
m.DeleteById(id)
func (m *machineScriptAppImpl) Delete(ctx context.Context, id uint64) {
m.DeleteById(ctx, id)
}

View File

@@ -30,6 +30,13 @@ type MachineCronJobRelate struct {
CreateTime *time.Time
}
func (m *MachineCronJobRelate) SetBaseInfo(la *model.LoginAccount) {
now := time.Now()
m.CreateTime = &now
m.Creator = la.Username
m.CreatorId = la.Id
}
// 机器任务执行记录
type MachineCronJobExec struct {
model.DeletedModel

View File

@@ -3,6 +3,7 @@ package entity
type MachineQuery struct {
Ids string `json:"ids" form:"ids"`
Name string `json:"name" form:"name"`
Status int8 `json:"status" form:"status"`
Ip string `json:"ip" form:"ip"` // IP地址
TagPath string `json:"tagPath" form:"tagPath"`
TagIds []uint64

View File

@@ -2,22 +2,13 @@ package repository
import (
"mayfly-go/internal/machine/domain/entity"
"mayfly-go/pkg/base"
"mayfly-go/pkg/model"
)
type MachineFile interface {
base.Repo[*entity.MachineFile]
// 分页获取机器脚本信息列表
GetPageList(condition *entity.MachineFile, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
// 根据条件获取
GetMachineFile(condition *entity.MachineFile, cols ...string) error
// 根据id获取
GetById(id uint64, cols ...string) *entity.MachineFile
Delete(id uint64) error
Create(entity *entity.MachineFile) error
UpdateById(entity *entity.MachineFile) error
}

View File

@@ -0,0 +1,24 @@
package cache
import (
"errors"
"fmt"
"mayfly-go/internal/machine/mcm"
global_cache "mayfly-go/pkg/cache"
"mayfly-go/pkg/utils/jsonx"
"time"
)
const MachineStatCackeKey = "mayfly:machine:%d:stat"
func SaveMachineStats(machineId uint64, stat *mcm.Stats) error {
return global_cache.SetStr(fmt.Sprintf(MachineStatCackeKey, machineId), jsonx.ToStr(stat), 10*time.Minute)
}
func GetMachineStats(machineId uint64) (*mcm.Stats, error) {
cacheStr := global_cache.GetStr(fmt.Sprintf(MachineStatCackeKey, machineId))
if cacheStr == "" {
return nil, errors.New("不存在该值")
}
return jsonx.To(cacheStr, new(mcm.Stats))
}

View File

@@ -23,6 +23,7 @@ func newMachineRepo() repository.Machine {
// 分页获取机器信息列表
func (m *machineRepoImpl) GetMachineList(condition *entity.MachineQuery, pageParam *model.PageParam, toEntity *[]*vo.MachineVO, orderBy ...string) (*model.PageResult[*[]*vo.MachineVO], error) {
qd := gormx.NewQuery(new(entity.Machine)).
Eq("status", condition.Status).
Like("ip", condition.Ip).
Like("name", condition.Name).
In("tag_id", condition.TagIds).

View File

@@ -3,14 +3,17 @@ package persistence
import (
"mayfly-go/internal/machine/domain/entity"
"mayfly-go/internal/machine/domain/repository"
"mayfly-go/pkg/base"
"mayfly-go/pkg/gormx"
"mayfly-go/pkg/model"
)
type machineFileRepoImpl struct{}
type machineFileRepoImpl struct {
base.RepoImpl[*entity.MachineFile]
}
func newMachineFileRepo() repository.MachineFile {
return new(machineFileRepoImpl)
return &machineFileRepoImpl{base.RepoImpl[*entity.MachineFile]{M: new(entity.MachineFile)}}
}
// 分页获取机器文件信息列表
@@ -18,30 +21,3 @@ func (m *machineFileRepoImpl) GetPageList(condition *entity.MachineFile, pagePar
qd := gormx.NewQuery(condition).WithCondModel(condition).WithOrderBy(orderBy...)
return gormx.PageQuery(qd, pageParam, toEntity)
}
// 根据条件获取账号信息
func (m *machineFileRepoImpl) GetMachineFile(condition *entity.MachineFile, cols ...string) error {
return gormx.GetBy(condition, cols...)
}
// 根据id获取
func (m *machineFileRepoImpl) GetById(id uint64, cols ...string) *entity.MachineFile {
ms := new(entity.MachineFile)
if err := gormx.GetById(ms, id, cols...); err != nil {
return nil
}
return ms
}
// 根据id获取
func (m *machineFileRepoImpl) Delete(id uint64) error {
return gormx.DeleteById(new(entity.MachineFile), id)
}
func (m *machineFileRepoImpl) Create(entity *entity.MachineFile) error {
return gormx.Insert(entity)
}
func (m *machineFileRepoImpl) UpdateById(entity *entity.MachineFile) error {
return gormx.UpdateById(entity)
}

View File

@@ -4,4 +4,5 @@ import "mayfly-go/internal/machine/application"
func Init() {
application.GetMachineCronJobApp().InitCronJob()
application.GetMachineApp().TimerUpdateStats()
}

View File

@@ -42,7 +42,13 @@ func (c *Cli) GetSession() (*ssh.Session, error) {
if c.sshClient == nil {
return nil, errorx.NewBiz("请先进行机器客户端连接")
}
return c.sshClient.NewSession()
session, err := c.sshClient.NewSession()
if err != nil {
// 获取session失败则关闭cli重试
DeleteCli(c.Info.Id)
return nil, errorx.NewBiz("请重试...")
}
return session, nil
}
// 执行shell
@@ -51,7 +57,6 @@ func (c *Cli) GetSession() (*ssh.Session, error) {
func (c *Cli) Run(shell string) (string, error) {
session, err := c.GetSession()
if err != nil {
c.Close()
return "", err
}
defer session.Close()
@@ -67,6 +72,10 @@ func (c *Cli) GetAllStats() *Stats {
res, _ := c.Run(StatsShell)
infos := strings.Split(res, "-----")
stats := new(Stats)
if len(infos) < 8 {
logx.Warnf("获取机器[id=%d, name=%s]的状态信息失败", c.Info.Id, c.Info.Name)
return stats
}
getUptime(infos[0], stats)
getHostname(infos[1], stats)
getLoad(infos[2], stats)

View File

@@ -9,48 +9,52 @@ import (
)
type FSInfo struct {
MountPoint string
Used uint64
Free uint64
MountPoint string `json:"mountPoint"`
Used uint64 `json:"used"`
Free uint64 `json:"free"`
}
type NetIntfInfo struct {
IPv4 string
IPv6 string
Rx uint64
Tx uint64
IPv4 string `json:"ipv4"`
IPv6 string `json:"ipv6"`
Rx uint64 `json:"rx"`
Tx uint64 `json:"tx"`
}
type MemInfo struct {
Total uint64 `json:"total"`
Free uint64 `json:"free"`
Buffers uint64 `json:"buffers"`
Available uint64 `json:"available"`
Cached uint64 `json:"cached"`
SwapTotal uint64 `json:"swapTotal"`
SwapFree uint64 `json:"swapFree"`
}
type CPUInfo struct {
User float32
Nice float32
System float32
Idle float32
Iowait float32
Irq float32
SoftIrq float32
Steal float32
Guest float32
User float32 `json:"user"`
Nice float32 `json:"nice"`
System float32 `json:"system"`
Idle float32 `json:"idle"`
Iowait float32 `json:"iowait"`
Irq float32 `json:"irq"`
SoftIrq float32 `json:"softIrq"`
Steal float32 `json:"steal"`
Guest float32 `json:"guest"`
}
type Stats struct {
Uptime string
Hostname string
Load1 string
Load5 string
Load10 string
RunningProcs string
TotalProcs string
MemTotal uint64
MemFree uint64
MemBuffers uint64
MemAvailable uint64
MemCached uint64
SwapTotal uint64
SwapFree uint64
FSInfos []FSInfo
NetIntf map[string]NetIntfInfo
CPU CPUInfo // or []CPUInfo to get all the cpu-core's stats?
Uptime string `json:"uptime"`
Hostname string `json:"hostname"`
Load1 string `json:"load1"`
Load5 string `json:"load5"`
Load10 string `json:"load10"`
RunningProcs string `json:"runningProcs"`
TotalProcs string `json:"totalProcs"`
MemInfo MemInfo `json:"memInfo"`
FSInfos []FSInfo `json:"fSInfos"`
NetIntf map[string]NetIntfInfo `json:"netIntf"`
CPU CPUInfo `json:"cpu"` // or []CPUInfo to get all the cpu-core's stats?
}
const StatsShell = `
@@ -141,19 +145,19 @@ func getMemInfo(memInfo string, stats *Stats) (err error) {
val *= 1024
switch parts[0] {
case "MemTotal:":
stats.MemTotal = val
stats.MemInfo.Total = val
case "MemFree:":
stats.MemFree = val
stats.MemInfo.Free = val
case "Buffers:":
stats.MemBuffers = val
stats.MemInfo.Buffers = val
case "Cached:":
stats.MemCached = val
stats.MemInfo.Cached = val
case "SwapTotal:":
stats.SwapTotal = val
stats.MemInfo.SwapTotal = val
case "SwapFree:":
stats.SwapFree = val
stats.MemInfo.SwapFree = val
case "MemAvailable:":
stats.MemAvailable = val
stats.MemInfo.Available = val
}
}
}

View File

@@ -30,7 +30,7 @@ func (m *Mongo) Mongos(rc *req.Ctx) {
queryCond, page := ginx.BindQueryAndPage[*entity.MongoQuery](rc.GinCtx, new(entity.MongoQuery))
// 不存在可访问标签id即没有可操作数据
tagIds := m.TagApp.ListTagIdByAccountId(rc.LoginAccount.Id)
tagIds := m.TagApp.ListTagIdByAccountId(rc.GetLoginAccount().Id)
if len(tagIds) == 0 {
rc.ResData = model.EmptyPageResult[any]()
return
@@ -43,7 +43,7 @@ func (m *Mongo) Mongos(rc *req.Ctx) {
}
func (m *Mongo) MongoTags(rc *req.Ctx) {
rc.ResData = m.TagApp.ListTagByAccountIdAndResource(rc.LoginAccount.Id, new(entity.Mongo))
rc.ResData = m.TagApp.ListTagByAccountIdAndResource(rc.GetLoginAccount().Id, new(entity.Mongo))
}
func (m *Mongo) Save(rc *req.Ctx) {
@@ -57,8 +57,7 @@ func (m *Mongo) Save(rc *req.Ctx) {
}(form.Uri)
rc.ReqParam = form
mongo.SetBaseInfo(rc.LoginAccount)
biz.ErrIsNil(m.MongoApp.Save(mongo))
biz.ErrIsNil(m.MongoApp.Save(rc.MetaCtx, mongo))
}
func (m *Mongo) DeleteMongo(rc *req.Ctx) {
@@ -69,7 +68,7 @@ func (m *Mongo) DeleteMongo(rc *req.Ctx) {
for _, v := range ids {
value, err := strconv.Atoi(v)
biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
m.MongoApp.Delete(uint64(value))
m.MongoApp.Delete(rc.MetaCtx, uint64(value))
}
}

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"mayfly-go/internal/mongo/domain/entity"
"mayfly-go/internal/mongo/domain/repository"
"mayfly-go/internal/mongo/mgm"
@@ -17,10 +18,10 @@ type Mongo interface {
Count(condition *entity.MongoQuery) int64
Save(entity *entity.Mongo) error
Save(ctx context.Context, entity *entity.Mongo) error
// 删除数据库信息
Delete(id uint64) error
Delete(ctx context.Context, id uint64) error
// 获取mongo连接实例
// @param id mongo id
@@ -46,19 +47,19 @@ func (d *mongoAppImpl) Count(condition *entity.MongoQuery) int64 {
return d.GetRepo().Count(condition)
}
func (d *mongoAppImpl) Delete(id uint64) error {
func (d *mongoAppImpl) Delete(ctx context.Context, id uint64) error {
mgm.CloseConn(id)
return d.GetRepo().DeleteById(id)
return d.GetRepo().DeleteById(ctx, id)
}
func (d *mongoAppImpl) Save(m *entity.Mongo) error {
func (d *mongoAppImpl) Save(ctx context.Context, m *entity.Mongo) error {
if m.Id == 0 {
return d.GetRepo().Insert(m)
return d.GetRepo().Insert(ctx, m)
}
// 先关闭连接
mgm.CloseConn(m.Id)
return d.GetRepo().UpdateById(m)
return d.GetRepo().UpdateById(ctx, m)
}
func (d *mongoAppImpl) GetMongoConn(id uint64) (*mgm.MongoConn, error) {

View File

@@ -15,7 +15,7 @@ type Msg struct {
// 获取账号接收的消息列表
func (m *Msg) GetMsgs(rc *req.Ctx) {
condition := &entity.Msg{
RecipientId: int64(rc.LoginAccount.Id),
RecipientId: int64(rc.GetLoginAccount().Id),
}
res, err := m.MsgApp.GetPageList(condition, ginx.GetPageParam(rc.GinCtx), new([]entity.Msg))
biz.ErrIsNil(err)

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"mayfly-go/internal/msg/application/dto"
"mayfly-go/internal/msg/domain/entity"
"mayfly-go/internal/msg/domain/repository"
@@ -12,7 +13,7 @@ import (
type Msg interface {
GetPageList(condition *entity.Msg, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
Create(msg *entity.Msg)
Create(ctx context.Context, msg *entity.Msg)
// 创建消息并通过ws发送
CreateAndSend(la *model.LoginAccount, msg *dto.SysMsg)
@@ -32,13 +33,13 @@ func (a *msgAppImpl) GetPageList(condition *entity.Msg, pageParam *model.PagePar
return a.msgRepo.GetPageList(condition, pageParam, toEntity)
}
func (a *msgAppImpl) Create(msg *entity.Msg) {
a.msgRepo.Insert(msg)
func (a *msgAppImpl) Create(ctx context.Context, msg *entity.Msg) {
a.msgRepo.Insert(ctx, msg)
}
func (a *msgAppImpl) CreateAndSend(la *model.LoginAccount, wmsg *dto.SysMsg) {
now := time.Now()
msg := &entity.Msg{Type: 2, Msg: wmsg.Msg, RecipientId: int64(la.Id), CreateTime: &now, CreatorId: la.Id, Creator: la.Username}
a.msgRepo.Insert(msg)
a.msgRepo.Insert(context.TODO(), msg)
ws.SendJsonMsg(ws.UserId(la.Id), wmsg.ClientId, wmsg)
}

View File

@@ -31,7 +31,7 @@ func (r *Redis) RedisList(rc *req.Ctx) {
queryCond, page := ginx.BindQueryAndPage[*entity.RedisQuery](rc.GinCtx, new(entity.RedisQuery))
// 不存在可访问标签id即没有可操作数据
tagIds := r.TagApp.ListTagIdByAccountId(rc.LoginAccount.Id)
tagIds := r.TagApp.ListTagIdByAccountId(rc.GetLoginAccount().Id)
if len(tagIds) == 0 {
rc.ResData = model.EmptyPageResult[any]()
return
@@ -44,7 +44,7 @@ func (r *Redis) RedisList(rc *req.Ctx) {
}
func (r *Redis) RedisTags(rc *req.Ctx) {
rc.ResData = r.TagApp.ListTagByAccountIdAndResource(rc.LoginAccount.Id, new(entity.Redis))
rc.ResData = r.TagApp.ListTagByAccountIdAndResource(rc.GetLoginAccount().Id, new(entity.Redis))
}
func (r *Redis) Save(rc *req.Ctx) {
@@ -60,8 +60,7 @@ func (r *Redis) Save(rc *req.Ctx) {
form.Password = "****"
rc.ReqParam = form
redis.SetBaseInfo(rc.LoginAccount)
biz.ErrIsNil(r.RedisApp.Save(redis))
biz.ErrIsNil(r.RedisApp.Save(rc.MetaCtx, redis))
}
// 获取redis实例密码由于数据库是加密存储故提供该接口展示原文密码
@@ -81,7 +80,7 @@ func (r *Redis) DeleteRedis(rc *req.Ctx) {
for _, v := range ids {
value, err := strconv.Atoi(v)
biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
r.RedisApp.Delete(uint64(value))
r.RedisApp.Delete(rc.MetaCtx, uint64(value))
}
}
@@ -218,7 +217,7 @@ func (r *Redis) checkKeyAndGetRedisConn(rc *req.Ctx) (*rdm.RedisConn, string) {
func (r *Redis) getRedisConn(rc *req.Ctx) *rdm.RedisConn {
ri, err := r.RedisApp.GetRedisConn(getIdAndDbNum(rc.GinCtx))
biz.ErrIsNil(err)
biz.ErrIsNilAppendErr(r.TagApp.CanAccess(rc.LoginAccount.Id, ri.Info.TagPath), "%s")
biz.ErrIsNilAppendErr(r.TagApp.CanAccess(rc.GetLoginAccount().Id, ri.Info.TagPath), "%s")
return ri
}

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"mayfly-go/internal/redis/domain/entity"
"mayfly-go/internal/redis/domain/repository"
"mayfly-go/internal/redis/rdm"
@@ -19,10 +20,10 @@ type Redis interface {
Count(condition *entity.RedisQuery) int64
Save(re *entity.Redis) error
Save(ctx context.Context, re *entity.Redis) error
// 删除数据库信息
Delete(id uint64) error
Delete(ctx context.Context, id uint64) error
// 获取数据库连接实例
// id: 数据库实例id
@@ -52,7 +53,7 @@ func (r *redisAppImpl) Count(condition *entity.RedisQuery) int64 {
return r.GetRepo().Count(condition)
}
func (r *redisAppImpl) Save(re *entity.Redis) error {
func (r *redisAppImpl) Save(ctx context.Context, re *entity.Redis) error {
// ’修改信息且密码不为空‘ or ‘新增’需要测试是否可连接
if (re.Id != 0 && re.Password != "") || re.Id == 0 {
if err := r.TestConn(re); err != nil {
@@ -72,7 +73,7 @@ func (r *redisAppImpl) Save(re *entity.Redis) error {
return errorx.NewBiz("该实例已存在")
}
re.PwdEncrypt()
return r.Insert(re)
return r.Insert(ctx, re)
}
// 如果存在该库,则校验修改的库是否为该库
@@ -87,11 +88,11 @@ func (r *redisAppImpl) Save(re *entity.Redis) error {
}
}
re.PwdEncrypt()
return r.UpdateById(re)
return r.UpdateById(ctx, re)
}
// 删除Redis信息
func (r *redisAppImpl) Delete(id uint64) error {
func (r *redisAppImpl) Delete(ctx context.Context, id uint64) error {
re, err := r.GetById(new(entity.Redis), id)
if err != nil {
return errorx.NewBiz("该redis信息不存在")
@@ -101,7 +102,7 @@ func (r *redisAppImpl) Delete(id uint64) error {
db, _ := strconv.Atoi(dbStr)
rdm.CloseConn(re.Id, db)
}
return r.DeleteById(id)
return r.DeleteById(ctx, id)
}
// 获取数据库连接实例

View File

@@ -35,7 +35,7 @@ type Account struct {
// 获取当前登录用户的菜单与权限码
func (a *Account) GetPermissions(rc *req.Ctx) {
account := rc.LoginAccount
account := rc.GetLoginAccount()
var resources vo.AccountResourceVOList
// 获取账号菜单资源
@@ -78,15 +78,13 @@ func (a *Account) ChangePassword(rc *req.Ctx) {
updateAccount := new(entity.Account)
updateAccount.Id = account.Id
updateAccount.Password = cryptox.PwdHash(originNewPwd)
biz.ErrIsNil(a.AccountApp.Update(updateAccount), "更新账号密码失败")
biz.ErrIsNil(a.AccountApp.Update(rc.MetaCtx, updateAccount), "更新账号密码失败")
// 赋值loginAccount 主要用于记录操作日志,因为操作日志保存请求上下文没有该信息不保存日志
if rc.LoginAccount == nil {
rc.LoginAccount = &model.LoginAccount{
Id: account.Id,
Username: account.Username,
}
}
contextx.WithLoginAccount(rc.MetaCtx, &model.LoginAccount{
Id: account.Id,
Username: account.Username,
})
}
// 获取个人账号信息
@@ -94,7 +92,7 @@ func (a *Account) AccountInfo(rc *req.Ctx) {
ap := new(vo.AccountPersonVO)
// 角色信息
roles := new([]vo.AccountRoleVO)
a.RoleApp.GetAccountRoles(rc.LoginAccount.Id, roles)
a.RoleApp.GetAccountRoles(rc.GetLoginAccount().Id, roles)
ap.Roles = *roles
rc.ResData = ap
@@ -104,7 +102,7 @@ func (a *Account) AccountInfo(rc *req.Ctx) {
func (a *Account) UpdateAccount(rc *req.Ctx) {
updateAccount := ginx.BindJsonAndCopyTo[*entity.Account](rc.GinCtx, new(form.AccountUpdateForm), new(entity.Account))
// 账号id为登录者账号
updateAccount.Id = rc.LoginAccount.Id
updateAccount.Id = rc.GetLoginAccount().Id
if updateAccount.Password != "" {
biz.IsTrue(utils.CheckAccountPasswordLever(updateAccount.Password), "密码强度必须8位以上且包含字⺟⼤⼩写+数字+特殊符号")
@@ -118,7 +116,7 @@ func (a *Account) UpdateAccount(rc *req.Ctx) {
// 禁止更新用户名,防止误传被更新
updateAccount.Username = ""
}
biz.ErrIsNil(a.AccountApp.Update(updateAccount))
biz.ErrIsNil(a.AccountApp.Update(rc.MetaCtx, updateAccount))
}
/** 后台账号操作 **/
@@ -139,10 +137,9 @@ func (a *Account) SaveAccount(rc *req.Ctx) {
form.Password = "*****"
rc.ReqParam = form
account.SetBaseInfo(rc.LoginAccount)
if account.Id == 0 {
biz.ErrIsNil(a.AccountApp.Create(account))
biz.ErrIsNil(a.AccountApp.Create(rc.MetaCtx, account))
} else {
if account.Password != "" {
biz.IsTrue(utils.CheckAccountPasswordLever(account.Password), "密码强度必须8位以上且包含字⺟⼤⼩写+数字+特殊符号")
@@ -150,7 +147,7 @@ func (a *Account) SaveAccount(rc *req.Ctx) {
}
// 更新操作不允许修改用户名、防止误传更新
account.Username = ""
biz.ErrIsNil(a.AccountApp.Update(account))
biz.ErrIsNil(a.AccountApp.Update(rc.MetaCtx, account))
}
}
@@ -161,7 +158,7 @@ func (a *Account) ChangeStatus(rc *req.Ctx) {
account.Id = uint64(ginx.PathParamInt(g, "id"))
account.Status = int8(ginx.PathParamInt(g, "status"))
rc.ReqParam = collx.Kvs("accountId", account.Id, "status", account.Status)
biz.ErrIsNil(a.AccountApp.Update(account))
biz.ErrIsNil(a.AccountApp.Update(rc.MetaCtx, account))
}
func (a *Account) DeleteAccount(rc *req.Ctx) {
@@ -172,7 +169,7 @@ func (a *Account) DeleteAccount(rc *req.Ctx) {
for _, v := range ids {
value, err := strconv.Atoi(v)
biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
biz.ErrIsNilAppendErr(a.AccountApp.Delete(uint64(value)), "删除失败:%s")
biz.ErrIsNilAppendErr(a.AccountApp.Delete(rc.MetaCtx, uint64(value)), "删除失败:%s")
}
}
@@ -207,7 +204,7 @@ func (a *Account) SaveRoles(rc *req.Ctx) {
return uint64(id)
})
a.RoleApp.SaveAccountRole(contextx.NewLoginAccount(rc.LoginAccount), form.Id, newIds)
a.RoleApp.SaveAccountRole(rc.MetaCtx, form.Id, newIds)
}
// 重置otp秘钥
@@ -216,5 +213,5 @@ func (a *Account) ResetOtpSecret(rc *req.Ctx) {
accountId := uint64(ginx.PathParamInt(rc.GinCtx, "id"))
account.Id = accountId
rc.ReqParam = collx.Kvs("accountId", accountId)
biz.ErrIsNil(a.AccountApp.Update(account))
biz.ErrIsNil(a.AccountApp.Update(rc.MetaCtx, account))
}

View File

@@ -16,7 +16,7 @@ type Config struct {
func (c *Config) Configs(rc *req.Ctx) {
g := rc.GinCtx
condition := &entity.Config{Key: g.Query("key")}
condition.Permission = rc.LoginAccount.Username
condition.Permission = rc.GetLoginAccount().Username
res, err := c.ConfigApp.GetPageList(condition, ginx.GetPageParam(g), new([]entity.Config))
biz.ErrIsNil(err)
rc.ResData = res
@@ -40,6 +40,5 @@ func (c *Config) SaveConfig(rc *req.Ctx) {
form := &form.ConfigForm{}
config := ginx.BindJsonAndCopyTo(rc.GinCtx, form, new(entity.Config))
rc.ReqParam = form
config.SetBaseInfo(rc.LoginAccount)
biz.ErrIsNil(c.ConfigApp.Save(config))
biz.ErrIsNil(c.ConfigApp.Save(rc.MetaCtx, config))
}

View File

@@ -39,19 +39,18 @@ func (r *Resource) SaveResource(rc *req.Ctx) {
bytes, _ := json.Marshal(form.Meta)
entity.Meta = string(bytes)
entity.SetBaseInfo(rc.LoginAccount)
biz.ErrIsNil(r.ResourceApp.Save(entity))
biz.ErrIsNil(r.ResourceApp.Save(rc.MetaCtx, entity))
}
func (r *Resource) DelResource(rc *req.Ctx) {
biz.ErrIsNil(r.ResourceApp.Delete(uint64(ginx.PathParamInt(rc.GinCtx, "id"))))
biz.ErrIsNil(r.ResourceApp.Delete(rc.MetaCtx, uint64(ginx.PathParamInt(rc.GinCtx, "id"))))
}
func (r *Resource) ChangeStatus(rc *req.Ctx) {
rid := uint64(ginx.PathParamInt(rc.GinCtx, "id"))
status := int8(ginx.PathParamInt(rc.GinCtx, "status"))
rc.ReqParam = collx.Kvs("id", rid, "status", status)
biz.ErrIsNil(r.ResourceApp.ChangeStatus(rid, status))
biz.ErrIsNil(r.ResourceApp.ChangeStatus(rc.MetaCtx, rid, status))
}
func (r *Resource) Sort(rc *req.Ctx) {
@@ -62,6 +61,6 @@ func (r *Resource) Sort(rc *req.Ctx) {
for _, v := range rs {
sortE := &entity.Resource{Pid: v.Pid, Weight: v.Weight}
sortE.Id = uint64(v.Id)
r.ResourceApp.Sort(sortE)
r.ResourceApp.Sort(rc.MetaCtx, sortE)
}
}

View File

@@ -6,7 +6,6 @@ import (
"mayfly-go/internal/sys/application"
"mayfly-go/internal/sys/domain/entity"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/contextx"
"mayfly-go/pkg/ginx"
"mayfly-go/pkg/req"
"mayfly-go/pkg/utils/collx"
@@ -32,9 +31,8 @@ func (r *Role) SaveRole(rc *req.Ctx) {
form := &form.RoleForm{}
role := ginx.BindJsonAndCopyTo(rc.GinCtx, form, new(entity.Role))
rc.ReqParam = form
role.SetBaseInfo(rc.LoginAccount)
r.RoleApp.SaveRole(role)
r.RoleApp.SaveRole(rc.MetaCtx, role)
}
// 删除角色及其资源关联关系
@@ -46,7 +44,7 @@ func (r *Role) DelRole(rc *req.Ctx) {
for _, v := range ids {
value, err := strconv.Atoi(v)
biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
r.RoleApp.DeleteRole(uint64(value))
r.RoleApp.DeleteRole(rc.MetaCtx, uint64(value))
}
}
@@ -77,5 +75,5 @@ func (r *Role) SaveResource(rc *req.Ctx) {
return uint64(id)
})
r.RoleApp.SaveRoleResource(contextx.NewLoginAccount(rc.LoginAccount), form.Id, newIds)
r.RoleApp.SaveRoleResource(rc.MetaCtx, form.Id, newIds)
}

View File

@@ -38,8 +38,6 @@ func (s *System) ConnectWs(g *gin.Context) {
biz.ErrIsNil(err, "sys websocket没有权限连接")
// 登录账号信息
la := rc.LoginAccount
if la != nil {
ws.AddClient(ws.UserId(la.Id), clientId, wsConn)
}
la := rc.GetLoginAccount()
ws.AddClient(ws.UserId(la.Id), clientId, wsConn)
}

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"mayfly-go/internal/sys/domain/entity"
"mayfly-go/internal/sys/domain/repository"
"mayfly-go/pkg/base"
@@ -17,11 +18,11 @@ type Account interface {
GetPageList(condition *entity.Account, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
Create(account *entity.Account) error
Create(ctx context.Context, account *entity.Account) error
Update(account *entity.Account) error
Update(ctx context.Context, account *entity.Account) error
Delete(id uint64) error
Delete(ctx context.Context, id uint64) error
}
func newAccountApp(accountRepo repository.Account) Account {
@@ -36,17 +37,17 @@ func (a *accountAppImpl) GetPageList(condition *entity.Account, pageParam *model
return a.GetRepo().GetPageList(condition, pageParam, toEntity)
}
func (a *accountAppImpl) Create(account *entity.Account) error {
func (a *accountAppImpl) Create(ctx context.Context, account *entity.Account) error {
if a.GetBy(&entity.Account{Username: account.Username}) == nil {
return errorx.NewBiz("该账号用户名已存在")
}
// 默认密码为账号用户名
account.Password = cryptox.PwdHash(account.Username)
account.Status = entity.AccountEnableStatus
return a.Insert(account)
return a.Insert(ctx, account)
}
func (a *accountAppImpl) Update(account *entity.Account) error {
func (a *accountAppImpl) Update(ctx context.Context, account *entity.Account) error {
if account.Username != "" {
unAcc := &entity.Account{Username: account.Username}
err := a.GetBy(unAcc)
@@ -55,14 +56,14 @@ func (a *accountAppImpl) Update(account *entity.Account) error {
}
}
return a.UpdateById(account)
return a.UpdateById(ctx, account)
}
func (a *accountAppImpl) Delete(id uint64) error {
func (a *accountAppImpl) Delete(ctx context.Context, id uint64) error {
return gormx.Tx(
func(db *gorm.DB) error {
// 删除account信息
return a.DeleteByIdWithDb(db, id)
return a.DeleteByIdWithDb(ctx, db, id)
},
func(db *gorm.DB) error {
// 删除账号关联的角色信息

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"encoding/json"
"mayfly-go/internal/sys/domain/entity"
"mayfly-go/internal/sys/domain/repository"
@@ -20,7 +21,7 @@ type Config interface {
GetPageList(condition *entity.Config, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
Save(config *entity.Config) error
Save(ctx context.Context, config *entity.Config) error
// GetConfig 获取指定key的配置信息, 不会返回nil, 若不存在则值都默认值即空字符串
GetConfig(key string) *entity.Config
@@ -41,9 +42,9 @@ func (a *configAppImpl) GetPageList(condition *entity.Config, pageParam *model.P
return a.GetRepo().GetPageList(condition, pageParam, toEntity)
}
func (a *configAppImpl) Save(config *entity.Config) error {
func (a *configAppImpl) Save(ctx context.Context, config *entity.Config) error {
if config.Id == 0 {
if err := a.Insert(config); err != nil {
if err := a.Insert(ctx, config); err != nil {
return err
}
} else {
@@ -52,7 +53,7 @@ func (a *configAppImpl) Save(config *entity.Config) error {
return errorx.NewBiz("您无权修改该配置")
}
if err := a.UpdateById(config); err != nil {
if err := a.UpdateById(ctx, config); err != nil {
return err
}
}

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"mayfly-go/internal/common/consts"
"mayfly-go/internal/sys/domain/entity"
"mayfly-go/internal/sys/domain/repository"
@@ -15,13 +16,13 @@ import (
type Resource interface {
base.App[*entity.Resource]
Save(entity *entity.Resource) error
Save(ctx context.Context, entity *entity.Resource) error
Delete(id uint64) error
Delete(ctx context.Context, id uint64) error
ChangeStatus(resourceId uint64, status int8) error
ChangeStatus(ctx context.Context, resourceId uint64, status int8) error
Sort(re *entity.Resource) error
Sort(ctx context.Context, re *entity.Resource) error
GetAccountResources(accountId uint64, toEntity any) error
}
@@ -36,7 +37,7 @@ type resourceAppImpl struct {
base.AppImpl[*entity.Resource, repository.Resource]
}
func (r *resourceAppImpl) Save(resource *entity.Resource) error {
func (r *resourceAppImpl) Save(ctx context.Context, resource *entity.Resource) error {
// 更新操作
if resource.Id != 0 {
if resource.Code != "" {
@@ -51,7 +52,7 @@ func (r *resourceAppImpl) Save(resource *entity.Resource) error {
}
}
}
return gormx.UpdateById(resource)
return r.UpdateById(ctx, resource)
}
// 生成随机八位唯一标识符
@@ -73,10 +74,10 @@ func (r *resourceAppImpl) Save(resource *entity.Resource) error {
return err
}
resource.Weight = int(time.Now().Unix())
return gormx.Insert(resource)
return r.Insert(ctx, resource)
}
func (r *resourceAppImpl) ChangeStatus(resourceId uint64, status int8) error {
func (r *resourceAppImpl) ChangeStatus(ctx context.Context, resourceId uint64, status int8) error {
resource, err := r.GetById(new(entity.Resource), resourceId)
if err != nil {
return errorx.NewBiz("资源不存在")
@@ -85,7 +86,7 @@ func (r *resourceAppImpl) ChangeStatus(resourceId uint64, status int8) error {
return r.GetRepo().UpdateByUiPathLike(resource)
}
func (r *resourceAppImpl) Sort(sortResource *entity.Resource) error {
func (r *resourceAppImpl) Sort(ctx context.Context, sortResource *entity.Resource) error {
resource, err := r.GetById(new(entity.Resource), sortResource.Id)
if err != nil {
return errorx.NewBiz("资源不存在")
@@ -95,7 +96,7 @@ func (r *resourceAppImpl) Sort(sortResource *entity.Resource) error {
if sortResource.Pid == resource.Pid {
saveE := &entity.Resource{Weight: sortResource.Weight}
saveE.Id = sortResource.Id
return r.Save(saveE)
return r.Save(ctx, saveE)
}
// 若资源原本唯一标识路径为xxxx/yyyy/zzzz/,则获取其父节点路径标识 xxxx/yyyy/ 与自身节点标识 zzzz/
@@ -131,7 +132,7 @@ func (r *resourceAppImpl) Sort(sortResource *entity.Resource) error {
} else {
updateUiPath.UiPath = strings.ReplaceAll(v.UiPath, parentResourceUiPath, newParentResourceUiPath)
}
r.Save(updateUiPath)
r.Save(ctx, updateUiPath)
}
// 更新零值使用map因为pid=0表示根节点
@@ -155,7 +156,7 @@ func (r *resourceAppImpl) checkCode(code string) error {
return nil
}
func (r *resourceAppImpl) Delete(id uint64) error {
func (r *resourceAppImpl) Delete(ctx context.Context, id uint64) error {
resource, err := r.GetById(new(entity.Resource), id)
if err != nil {
return errorx.NewBiz("资源不存在")
@@ -164,7 +165,7 @@ func (r *resourceAppImpl) Delete(id uint64) error {
// 删除当前节点及其所有子节点
children := r.GetRepo().GetChildren(resource.UiPath)
for _, v := range children {
r.GetRepo().DeleteById(v.Id)
r.GetRepo().DeleteById(ctx, v.Id)
// 删除角色关联的资源信息
gormx.DeleteBy(&entity.RoleResource{ResourceId: v.Id})
}

View File

@@ -17,9 +17,9 @@ import (
type Role interface {
GetPageList(condition *entity.Role, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
SaveRole(role *entity.Role) error
SaveRole(ctx context.Context, role *entity.Role) error
DeleteRole(id uint64) error
DeleteRole(ctx context.Context, id uint64) error
GetRoleResourceIds(roleId uint64) []uint64
@@ -29,7 +29,7 @@ type Role interface {
SaveRoleResource(ctx context.Context, roleId uint64, resourceIds []uint64)
// 删除角色资源关联记录
DeleteRoleResource(roleId uint64, resourceId uint64)
DeleteRoleResource(ctx context.Context, roleId uint64, resourceId uint64)
// 获取账号角色id列表
GetAccountRoleIds(accountId uint64) []uint64
@@ -37,7 +37,7 @@ type Role interface {
// 保存账号角色关联信息
SaveAccountRole(ctx context.Context, accountId uint64, roleIds []uint64)
DeleteAccountRole(accountId, roleId uint64)
DeleteAccountRole(ctx context.Context, accountId, roleId uint64)
GetAccountRoles(accountId uint64, toEntity any)
}
@@ -56,7 +56,7 @@ func (m *roleAppImpl) GetPageList(condition *entity.Role, pageParam *model.PageP
return m.roleRepo.GetPageList(condition, pageParam, toEntity, orderBy...)
}
func (m *roleAppImpl) SaveRole(role *entity.Role) error {
func (m *roleAppImpl) SaveRole(ctx context.Context, role *entity.Role) error {
role.Code = strings.ToUpper(role.Code)
if role.Id != 0 {
// code不可更改防止误传
@@ -68,11 +68,11 @@ func (m *roleAppImpl) SaveRole(role *entity.Role) error {
return gormx.Insert(role)
}
func (m *roleAppImpl) DeleteRole(id uint64) error {
func (m *roleAppImpl) DeleteRole(ctx context.Context, id uint64) error {
// 删除角色与资源的关联关系
return gormx.Tx(
func(db *gorm.DB) error {
return m.roleRepo.DeleteByIdWithDb(db, id)
return m.roleRepo.DeleteByIdWithDb(ctx, db, id)
},
func(db *gorm.DB) error {
return gormx.DeleteByWithDb(db, &entity.RoleResource{RoleId: id})
@@ -110,11 +110,11 @@ func (m *roleAppImpl) SaveRoleResource(ctx context.Context, roleId uint64, resou
m.roleRepo.SaveRoleResource(addVals)
for _, v := range delIds {
m.DeleteRoleResource(roleId, v)
m.DeleteRoleResource(ctx, roleId, v)
}
}
func (m *roleAppImpl) DeleteRoleResource(roleId uint64, resourceId uint64) {
func (m *roleAppImpl) DeleteRoleResource(ctx context.Context, roleId uint64, resourceId uint64) {
m.roleRepo.DeleteRoleResource(roleId, resourceId)
}
@@ -140,11 +140,11 @@ func (m *roleAppImpl) SaveAccountRole(ctx context.Context, accountId uint64, rol
m.roleRepo.SaveAccountRole(rr)
}
for _, v := range delIds {
m.DeleteAccountRole(accountId, v)
m.DeleteAccountRole(ctx, accountId, v)
}
}
func (m *roleAppImpl) DeleteAccountRole(accountId, roleId uint64) {
func (m *roleAppImpl) DeleteAccountRole(ctx context.Context, accountId, roleId uint64) {
m.roleRepo.DeleteAccountRole(accountId, roleId)
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"mayfly-go/internal/sys/domain/entity"
"mayfly-go/internal/sys/domain/repository"
"mayfly-go/pkg/contextx"
"mayfly-go/pkg/errorx"
"mayfly-go/pkg/model"
"mayfly-go/pkg/req"
@@ -34,7 +35,7 @@ func (m *syslogAppImpl) GetPageList(condition *entity.SysLogQuery, pageParam *mo
}
func (m *syslogAppImpl) SaveFromReq(req *req.Ctx) {
lg := req.LoginAccount
lg := contextx.GetLoginAccount(req.MetaCtx)
if lg == nil {
lg = &model.LoginAccount{Id: 0, Username: "-"}
}
@@ -74,5 +75,5 @@ func (m *syslogAppImpl) SaveFromReq(req *req.Ctx) {
syslog.Type = entity.SyslogTypeNorman
}
m.syslogRepo.Insert(syslog)
m.syslogRepo.Insert(req.MetaCtx, syslog)
}

View File

@@ -16,7 +16,7 @@ type TagTree struct {
}
func (p *TagTree) GetAccountTags(rc *req.Ctx) {
tagPaths := p.TagTreeApp.ListTagByAccountId(rc.LoginAccount.Id)
tagPaths := p.TagTreeApp.ListTagByAccountId(rc.GetLoginAccount().Id)
allTagPath := make([]string, 0)
if len(tagPaths) > 0 {
tags := p.TagTreeApp.ListTagByPath(tagPaths...)
@@ -46,13 +46,11 @@ func (p *TagTree) SaveTagTree(rc *req.Ctx) {
tagTree := &entity.TagTree{}
ginx.BindJsonAndValid(rc.GinCtx, tagTree)
loginAccount := rc.LoginAccount
tagTree.SetBaseInfo(loginAccount)
rc.ReqParam = fmt.Sprintf("tagTreeId: %d, tagName: %s, codePath: %s", tagTree.Id, tagTree.Name, tagTree.CodePath)
biz.ErrIsNil(p.TagTreeApp.Save(tagTree))
biz.ErrIsNil(p.TagTreeApp.Save(rc.MetaCtx, tagTree))
}
func (p *TagTree) DelTagTree(rc *req.Ctx) {
biz.ErrIsNil(p.TagTreeApp.Delete(uint64(ginx.PathParamInt(rc.GinCtx, "id"))))
biz.ErrIsNil(p.TagTreeApp.Delete(rc.MetaCtx, uint64(ginx.PathParamInt(rc.GinCtx, "id"))))
}

View File

@@ -35,9 +35,8 @@ func (p *Team) SaveTeam(rc *req.Ctx) {
rc.ReqParam = team
isAdd := team.Id == 0
loginAccount := rc.LoginAccount
team.SetBaseInfo(loginAccount)
p.TeamApp.Save(team)
loginAccount := rc.GetLoginAccount()
p.TeamApp.Save(rc.MetaCtx, team)
// 如果是新增团队则默认将自己加入该团队
if isAdd {
@@ -46,8 +45,7 @@ func (p *Team) SaveTeam(rc *req.Ctx) {
teamMem.Username = loginAccount.Username
teamMem.TeamId = team.Id
teamMem.SetBaseInfo(rc.LoginAccount)
p.TeamApp.SaveMember(teamMem)
p.TeamApp.SaveMember(rc.MetaCtx, teamMem)
}
}
@@ -59,7 +57,7 @@ func (p *Team) DelTeam(rc *req.Ctx) {
for _, v := range ids {
value, err := strconv.Atoi(v)
biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
p.TeamApp.Delete(uint64(value))
p.TeamApp.Delete(rc.MetaCtx, uint64(value))
}
}
@@ -94,8 +92,7 @@ func (p *Team) SaveTeamMember(rc *req.Ctx) {
teamMember.TeamId = teamId
teamMember.AccountId = accountId
teamMember.Username = account.Username
teamMember.SetBaseInfo(rc.LoginAccount)
p.TeamApp.SaveMember(teamMember)
p.TeamApp.SaveMember(rc.MetaCtx, teamMember)
}
rc.ReqParam = teamMems
@@ -108,7 +105,7 @@ func (p *Team) DelTeamMember(rc *req.Ctx) {
aid := ginx.PathParamInt(g, "accountId")
rc.ReqParam = fmt.Sprintf("teamId: %d, accountId: %d", tid, aid)
p.TeamApp.DeleteMember(uint64(tid), uint64(aid))
p.TeamApp.DeleteMember(rc.MetaCtx, uint64(tid), uint64(aid))
}
// 获取团队关联的标签id
@@ -133,18 +130,16 @@ func (p *Team) SaveTags(rc *req.Ctx) {
return i1 == i2
})
loginAccount := rc.LoginAccount
for _, v := range addIds {
tagId := v
tag, err := p.TagApp.GetById(new(entity.TagTree), tagId)
biz.ErrIsNil(err, "存在非法标签id")
ptt := &entity.TagTreeTeam{TeamId: teamId, TagId: tagId, TagPath: tag.CodePath}
ptt.SetBaseInfo(loginAccount)
p.TeamApp.SaveTag(ptt)
p.TeamApp.SaveTag(rc.MetaCtx, ptt)
}
for _, v := range delIds {
p.TeamApp.DeleteTag(teamId, v)
p.TeamApp.DeleteTag(rc.MetaCtx, teamId, v)
}
rc.ReqParam = form

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
dbapp "mayfly-go/internal/db/application"
dbentity "mayfly-go/internal/db/domain/entity"
machineapp "mayfly-go/internal/machine/application"
@@ -23,9 +24,9 @@ type TagTree interface {
ListByQuery(condition *entity.TagTreeQuery, toEntity any)
Save(tt *entity.TagTree) error
Save(ctx context.Context, tt *entity.TagTree) error
Delete(id uint64) error
Delete(ctx context.Context, id uint64) error
// 获取账号id拥有的可访问的标签id
ListTagIdByAccountId(accountId uint64) []uint64
@@ -74,7 +75,7 @@ type tagTreeAppImpl struct {
dbApp dbapp.Db
}
func (p *tagTreeAppImpl) Save(tag *entity.TagTree) error {
func (p *tagTreeAppImpl) Save(ctx context.Context, tag *entity.TagTree) error {
// 新建项目树节点信息
if tag.Id == 0 {
if strings.Contains(tag.Code, entity.CodePathSeparator) {
@@ -96,13 +97,13 @@ func (p *tagTreeAppImpl) Save(tag *entity.TagTree) error {
return errorx.NewBiz("已存在该标签路径开头的标签, 请修改该标识code")
}
return p.GetRepo().Insert(tag)
return p.Insert(ctx, tag)
}
// 防止误传导致被更新
tag.Code = ""
tag.CodePath = ""
return p.GetRepo().UpdateById(tag)
return p.UpdateById(ctx, tag)
}
func (p *tagTreeAppImpl) ListByQuery(condition *entity.TagTreeQuery, toEntity any) {
@@ -161,7 +162,7 @@ func (p *tagTreeAppImpl) CanAccess(accountId uint64, tagPath string) error {
return errorx.NewBiz("您无权操作该资源")
}
func (p *tagTreeAppImpl) Delete(id uint64) error {
func (p *tagTreeAppImpl) Delete(ctx context.Context, id uint64) error {
tagIds := [1]uint64{id}
if p.machineApp.Count(&machineentity.MachineQuery{TagIds: tagIds[:]}) > 0 {
return errorx.NewBiz("请先删除该标签关联的机器信息")
@@ -176,7 +177,7 @@ func (p *tagTreeAppImpl) Delete(id uint64) error {
return errorx.NewBiz("请先删除该标签关联的Mongo信息")
}
p.DeleteById(id)
p.DeleteById(ctx, id)
// 删除该标签关联的团队信息
return p.tagTreeTeamRepo.DeleteByCond(&entity.TagTreeTeam{TagId: id})
return p.tagTreeTeamRepo.DeleteByCond(ctx, &entity.TagTreeTeam{TagId: id})
}

View File

@@ -1,6 +1,7 @@
package application
import (
"context"
"mayfly-go/internal/tag/domain/entity"
"mayfly-go/internal/tag/domain/repository"
"mayfly-go/pkg/biz"
@@ -14,17 +15,17 @@ type Team interface {
// 分页获取项目团队信息列表
GetPageList(condition *entity.Team, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
Save(team *entity.Team) error
Save(ctx context.Context, team *entity.Team) error
Delete(id uint64) error
Delete(ctx context.Context, id uint64) error
//--------------- 团队成员相关接口 ---------------
GetMemberPage(condition *entity.TeamMember, pageParam *model.PageParam, toEntity any) (*model.PageResult[any], error)
SaveMember(tagTeamMember *entity.TeamMember)
SaveMember(ctx context.Context, tagTeamMember *entity.TeamMember)
DeleteMember(teamId, accountId uint64)
DeleteMember(tx context.Context, teamId, accountId uint64)
IsExistMember(teamId, accounId uint64) bool
@@ -32,9 +33,9 @@ type Team interface {
ListTagIds(teamId uint64) []uint64
SaveTag(tagTeam *entity.TagTreeTeam) error
SaveTag(ctx context.Context, tagTeam *entity.TagTreeTeam) error
DeleteTag(teamId, tagId uint64) error
DeleteTag(tx context.Context, teamId, tagId uint64) error
}
func newTeamApp(teamRepo repository.Team,
@@ -58,23 +59,23 @@ func (p *teamAppImpl) GetPageList(condition *entity.Team, pageParam *model.PageP
return p.teamRepo.GetPageList(condition, pageParam, toEntity, orderBy...)
}
func (p *teamAppImpl) Save(team *entity.Team) error {
func (p *teamAppImpl) Save(ctx context.Context, team *entity.Team) error {
if team.Id == 0 {
return p.teamRepo.Insert(team)
return p.teamRepo.Insert(ctx, team)
}
return p.teamRepo.UpdateById(team)
return p.teamRepo.UpdateById(ctx, team)
}
func (p *teamAppImpl) Delete(id uint64) error {
func (p *teamAppImpl) Delete(ctx context.Context, id uint64) error {
return gormx.Tx(
func(db *gorm.DB) error {
return p.teamRepo.DeleteByIdWithDb(db, id)
return p.teamRepo.DeleteByIdWithDb(ctx, db, id)
},
func(db *gorm.DB) error {
return p.teamMemberRepo.DeleteByCondWithDb(db, &entity.TeamMember{TeamId: id})
return p.teamMemberRepo.DeleteByCondWithDb(ctx, db, &entity.TeamMember{TeamId: id})
},
func(db *gorm.DB) error {
return p.tagTreeTeamRepo.DeleteByCondWithDb(db, &entity.TagTreeTeam{TeamId: id})
return p.tagTreeTeamRepo.DeleteByCondWithDb(ctx, db, &entity.TagTreeTeam{TeamId: id})
},
)
}
@@ -86,15 +87,15 @@ func (p *teamAppImpl) GetMemberPage(condition *entity.TeamMember, pageParam *mod
}
// 保存团队成员信息
func (p *teamAppImpl) SaveMember(teamMember *entity.TeamMember) {
func (p *teamAppImpl) SaveMember(ctx context.Context, teamMember *entity.TeamMember) {
teamMember.Id = 0
biz.IsTrue(!p.teamMemberRepo.IsExist(teamMember.TeamId, teamMember.AccountId), "该成员已存在")
p.teamMemberRepo.Insert(teamMember)
p.teamMemberRepo.Insert(ctx, teamMember)
}
// 删除团队成员信息
func (p *teamAppImpl) DeleteMember(teamId, accountId uint64) {
p.teamMemberRepo.DeleteByCond(&entity.TeamMember{TeamId: teamId, AccountId: accountId})
func (p *teamAppImpl) DeleteMember(ctx context.Context, teamId, accountId uint64) {
p.teamMemberRepo.DeleteByCond(ctx, &entity.TeamMember{TeamId: teamId, AccountId: accountId})
}
func (p *teamAppImpl) IsExistMember(teamId, accounId uint64) bool {
@@ -114,12 +115,12 @@ func (p *teamAppImpl) ListTagIds(teamId uint64) []uint64 {
}
// 保存关联项目信息
func (p *teamAppImpl) SaveTag(tagTreeTeam *entity.TagTreeTeam) error {
func (p *teamAppImpl) SaveTag(ctx context.Context, tagTreeTeam *entity.TagTreeTeam) error {
tagTreeTeam.Id = 0
return p.tagTreeTeamRepo.Insert(tagTreeTeam)
return p.tagTreeTeamRepo.Insert(ctx, tagTreeTeam)
}
// 删除关联项目信息
func (p *teamAppImpl) DeleteTag(teamId, tagId uint64) error {
return p.tagTreeTeamRepo.DeleteByCond(&entity.TagTreeTeam{TeamId: teamId, TagId: tagId})
func (p *teamAppImpl) DeleteTag(ctx context.Context, teamId, tagId uint64) error {
return p.tagTreeTeamRepo.DeleteByCond(ctx, &entity.TagTreeTeam{TeamId: teamId, TagId: tagId})
}

View File

@@ -1,44 +1,47 @@
package base
import (
"context"
"mayfly-go/pkg/model"
"gorm.io/gorm"
)
// 基础application接口
type App[T any] interface {
type App[T model.ModelI] interface {
// 新增一个实体
Insert(e T) error
Insert(ctx context.Context, e T) error
// 使用指定gorm db执行主要用于事务执行
InsertWithDb(db *gorm.DB, e T) error
InsertWithDb(ctx context.Context, db *gorm.DB, e T) error
// 批量新增实体
BatchInsert(models []T) error
BatchInsert(ctx context.Context, models []T) error
// 使用指定gorm db执行主要用于事务执行
BatchInsertWithDb(db *gorm.DB, es []T) error
BatchInsertWithDb(ctx context.Context, db *gorm.DB, es []T) error
// 根据实体id更新实体信息
UpdateById(e T) error
UpdateById(ctx context.Context, e T) error
// 使用指定gorm db执行主要用于事务执行
UpdateByIdWithDb(db *gorm.DB, e T) error
UpdateByIdWithDb(ctx context.Context, db *gorm.DB, e T) error
// 根据实体主键删除实体
DeleteById(id uint64) error
DeleteById(ctx context.Context, id uint64) error
// 使用指定gorm db执行主要用于事务执行
DeleteByIdWithDb(db *gorm.DB, id uint64) error
DeleteByIdWithDb(ctx context.Context, db *gorm.DB, id uint64) error
// 根据实体条件更新参数udpateFields指定字段
Updates(cond any, udpateFields map[string]any) error
Updates(ctx context.Context, cond any, udpateFields map[string]any) error
// 根据实体条件删除实体
DeleteByCond(cond any) error
DeleteByCond(ctx context.Context, cond any) error
// 使用指定gorm db执行主要用于事务执行
DeleteByCondWithDb(db *gorm.DB, cond any) error
DeleteByCondWithDb(ctx context.Context, db *gorm.DB, cond any) error
// 根据实体id查询
GetById(e T, id uint64, cols ...string) (T, error)
@@ -62,7 +65,7 @@ type App[T any] interface {
}
// 基础application接口实现
type AppImpl[T any, R Repo[T]] struct {
type AppImpl[T model.ModelI, R Repo[T]] struct {
Repo R // repo接口
}
@@ -72,57 +75,57 @@ func (ai *AppImpl[T, R]) GetRepo() R {
}
// 新增一个实体 (单纯新增,不做其他业务逻辑处理)
func (ai *AppImpl[T, R]) Insert(e T) error {
return ai.GetRepo().Insert(e)
func (ai *AppImpl[T, R]) Insert(ctx context.Context, e T) error {
return ai.GetRepo().Insert(ctx, e)
}
// 使用指定gorm db执行主要用于事务执行
func (ai *AppImpl[T, R]) InsertWithDb(db *gorm.DB, e T) error {
return ai.GetRepo().InsertWithDb(db, e)
func (ai *AppImpl[T, R]) InsertWithDb(ctx context.Context, db *gorm.DB, e T) error {
return ai.GetRepo().InsertWithDb(ctx, db, e)
}
// 批量新增实体 (单纯新增,不做其他业务逻辑处理)
func (ai *AppImpl[T, R]) BatchInsert(es []T) error {
return ai.GetRepo().BatchInsert(es)
func (ai *AppImpl[T, R]) BatchInsert(ctx context.Context, es []T) error {
return ai.GetRepo().BatchInsert(ctx, es)
}
// 使用指定gorm db执行主要用于事务执行
func (ai *AppImpl[T, R]) BatchInsertWithDb(db *gorm.DB, es []T) error {
return ai.GetRepo().BatchInsertWithDb(db, es)
func (ai *AppImpl[T, R]) BatchInsertWithDb(ctx context.Context, db *gorm.DB, es []T) error {
return ai.GetRepo().BatchInsertWithDb(ctx, db, es)
}
// 根据实体id更新实体信息 (单纯更新,不做其他业务逻辑处理)
func (ai *AppImpl[T, R]) UpdateById(e T) error {
return ai.GetRepo().UpdateById(e)
func (ai *AppImpl[T, R]) UpdateById(ctx context.Context, e T) error {
return ai.GetRepo().UpdateById(ctx, e)
}
// 使用指定gorm db执行主要用于事务执行
func (ai *AppImpl[T, R]) UpdateByIdWithDb(db *gorm.DB, e T) error {
return ai.GetRepo().UpdateByIdWithDb(db, e)
func (ai *AppImpl[T, R]) UpdateByIdWithDb(ctx context.Context, db *gorm.DB, e T) error {
return ai.GetRepo().UpdateByIdWithDb(ctx, db, e)
}
// 根据实体条件更新参数udpateFields指定字段 (单纯更新,不做其他业务逻辑处理)
func (ai *AppImpl[T, R]) Updates(cond any, udpateFields map[string]any) error {
func (ai *AppImpl[T, R]) Updates(ctx context.Context, cond any, udpateFields map[string]any) error {
return ai.GetRepo().Updates(cond, udpateFields)
}
// 根据实体主键删除实体 (单纯删除实体,不做其他业务逻辑处理)
func (ai *AppImpl[T, R]) DeleteById(id uint64) error {
return ai.GetRepo().DeleteById(id)
func (ai *AppImpl[T, R]) DeleteById(ctx context.Context, id uint64) error {
return ai.GetRepo().DeleteById(ctx, id)
}
func (ai *AppImpl[T, R]) DeleteByIdWithDb(db *gorm.DB, id uint64) error {
return ai.GetRepo().DeleteByCondWithDb(db, id)
func (ai *AppImpl[T, R]) DeleteByIdWithDb(ctx context.Context, db *gorm.DB, id uint64) error {
return ai.GetRepo().DeleteByCondWithDb(ctx, db, id)
}
// 根据指定条件删除实体 (单纯删除实体,不做其他业务逻辑处理)
func (ai *AppImpl[T, R]) DeleteByCond(cond any) error {
return ai.GetRepo().DeleteByCond(cond)
func (ai *AppImpl[T, R]) DeleteByCond(ctx context.Context, cond any) error {
return ai.GetRepo().DeleteByCond(ctx, cond)
}
// 使用指定gorm db执行主要用于事务执行
func (ai *AppImpl[T, R]) DeleteByCondWithDb(db *gorm.DB, cond any) error {
return ai.GetRepo().DeleteByCondWithDb(db, cond)
func (ai *AppImpl[T, R]) DeleteByCondWithDb(ctx context.Context, db *gorm.DB, cond any) error {
return ai.GetRepo().DeleteByCondWithDb(ctx, db, cond)
}
// 根据实体id查询

View File

@@ -1,47 +1,50 @@
package base
import (
"context"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/contextx"
"mayfly-go/pkg/gormx"
"mayfly-go/pkg/model"
"gorm.io/gorm"
)
// 基础repo接口
type Repo[T any] interface {
type Repo[T model.ModelI] interface {
// 新增一个实体
Insert(e T) error
Insert(ctx context.Context, e T) error
// 使用指定gorm db执行主要用于事务执行
InsertWithDb(db *gorm.DB, e T) error
InsertWithDb(ctx context.Context, db *gorm.DB, e T) error
// 批量新增实体
BatchInsert(models []T) error
BatchInsert(ctx context.Context, models []T) error
// 使用指定gorm db执行主要用于事务执行
BatchInsertWithDb(db *gorm.DB, es []T) error
BatchInsertWithDb(ctx context.Context, db *gorm.DB, es []T) error
// 根据实体id更新实体信息
UpdateById(e T) error
UpdateById(ctx context.Context, e T) error
// 使用指定gorm db执行主要用于事务执行
UpdateByIdWithDb(db *gorm.DB, e T) error
UpdateByIdWithDb(ctx context.Context, db *gorm.DB, e T) error
// 根据实体主键删除实体
DeleteById(id uint64) error
DeleteById(ctx context.Context, id uint64) error
// 使用指定gorm db执行主要用于事务执行
DeleteByIdWithDb(db *gorm.DB, id uint64) error
DeleteByIdWithDb(ctx context.Context, db *gorm.DB, id uint64) error
// 根据实体条件更新参数udpateFields指定字段
Updates(cond any, udpateFields map[string]any) error
// 根据实体条件删除实体
DeleteByCond(cond any) error
DeleteByCond(ctx context.Context, cond any) error
// 使用指定gorm db执行主要用于事务执行
DeleteByCondWithDb(db *gorm.DB, cond any) error
DeleteByCondWithDb(ctx context.Context, db *gorm.DB, cond any) error
// 根据实体id查询
GetById(e T, id uint64, cols ...string) error
@@ -66,52 +69,58 @@ type Repo[T any] interface {
}
// 基础repo接口
type RepoImpl[T any] struct {
type RepoImpl[T model.ModelI] struct {
M any // 模型实例
}
func (br *RepoImpl[T]) Insert(e T) error {
return gormx.Insert(e)
func (br *RepoImpl[T]) Insert(ctx context.Context, e T) error {
return gormx.Insert(br.setBaseInfo(ctx, e))
}
func (br *RepoImpl[T]) InsertWithDb(db *gorm.DB, e T) error {
return gormx.InsertWithDb(db, e)
func (br *RepoImpl[T]) InsertWithDb(ctx context.Context, db *gorm.DB, e T) error {
return gormx.InsertWithDb(db, br.setBaseInfo(ctx, e))
}
func (br *RepoImpl[T]) BatchInsert(es []T) error {
func (br *RepoImpl[T]) BatchInsert(ctx context.Context, es []T) error {
for _, e := range es {
br.setBaseInfo(ctx, e)
}
return gormx.BatchInsert(es)
}
// 使用指定gorm db执行主要用于事务执行
func (br *RepoImpl[T]) BatchInsertWithDb(db *gorm.DB, es []T) error {
func (br *RepoImpl[T]) BatchInsertWithDb(ctx context.Context, db *gorm.DB, es []T) error {
for _, e := range es {
br.setBaseInfo(ctx, e)
}
return gormx.BatchInsertWithDb(db, es)
}
func (br *RepoImpl[T]) UpdateById(e T) error {
return gormx.UpdateById(e)
func (br *RepoImpl[T]) UpdateById(ctx context.Context, e T) error {
return gormx.UpdateById(br.setBaseInfo(ctx, e))
}
func (br *RepoImpl[T]) UpdateByIdWithDb(db *gorm.DB, e T) error {
return gormx.UpdateByIdWithDb(db, e)
func (br *RepoImpl[T]) UpdateByIdWithDb(ctx context.Context, db *gorm.DB, e T) error {
return gormx.UpdateByIdWithDb(db, br.setBaseInfo(ctx, e))
}
func (br *RepoImpl[T]) Updates(cond any, udpateFields map[string]any) error {
return gormx.Updates(cond, udpateFields)
}
func (br *RepoImpl[T]) DeleteById(id uint64) error {
func (br *RepoImpl[T]) DeleteById(ctx context.Context, id uint64) error {
return gormx.DeleteById(br.getModel(), id)
}
func (br *RepoImpl[T]) DeleteByIdWithDb(db *gorm.DB, id uint64) error {
func (br *RepoImpl[T]) DeleteByIdWithDb(ctx context.Context, db *gorm.DB, id uint64) error {
return gormx.DeleteByCondWithDb(db, br.getModel(), id)
}
func (br *RepoImpl[T]) DeleteByCond(cond any) error {
func (br *RepoImpl[T]) DeleteByCond(ctx context.Context, cond any) error {
return gormx.DeleteByCond(br.getModel(), cond)
}
func (br *RepoImpl[T]) DeleteByCondWithDb(db *gorm.DB, cond any) error {
func (br *RepoImpl[T]) DeleteByCondWithDb(ctx context.Context, db *gorm.DB, cond any) error {
return gormx.DeleteByCondWithDb(db, br.getModel(), cond)
}
@@ -147,3 +156,11 @@ func (br *RepoImpl[T]) getModel() any {
biz.IsTrue(br.M != nil, "base.RepoImpl的M字段不能为空")
return br.M
}
// 从上下文获取登录账号信息,并赋值至实体
func (br *RepoImpl[T]) setBaseInfo(ctx context.Context, e T) T {
if la := contextx.GetLoginAccount(ctx); la != nil {
e.SetBaseInfo(la)
}
return e
}

View File

@@ -21,9 +21,12 @@ func WithLoginAccount(ctx context.Context, la *model.LoginAccount) context.Conte
return context.WithValue(ctx, LoginAccountKey, la)
}
// 从context中获取登录账号信息
// 从context中获取登录账号信息不存在返回nil
func GetLoginAccount(ctx context.Context) *model.LoginAccount {
return ctx.Value(LoginAccountKey).(*model.LoginAccount)
if la, ok := ctx.Value(LoginAccountKey).(*model.LoginAccount); ok {
return la
}
return nil
}
func NewTraceId() context.Context {
@@ -31,10 +34,13 @@ func NewTraceId() context.Context {
}
func WithTraceId(ctx context.Context) context.Context {
return context.WithValue(ctx, TraceIdKey, stringx.Rand(16))
return context.WithValue(ctx, TraceIdKey, stringx.RandByChars(16, stringx.Nums+stringx.LowerChars))
}
// 从context中获取traceId
func GetTraceId(ctx context.Context) string {
return ctx.Value(TraceIdKey).(string)
if val, ok := ctx.Value(TraceIdKey).(string); ok {
return val
}
return ""
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"log/slog"
"mayfly-go/pkg/contextx"
"mayfly-go/pkg/utils/runtimex"
"path/filepath"
"runtime"
@@ -47,7 +48,7 @@ func Debugf(format string, args ...any) {
Log(context.Background(), slog.LevelDebug, fmt.Sprintf(format, args...))
}
func DebugWithFields(msg string, mapFields map[string]any) {
func DebugWithFields(ctx context.Context, msg string, mapFields map[string]any) {
Log(context.Background(), slog.LevelDebug, msg, map2Attrs(mapFields)...)
}
@@ -68,8 +69,8 @@ func Infof(format string, args ...any) {
Log(context.Background(), slog.LevelInfo, fmt.Sprintf(format, args...))
}
func InfoWithFields(msg string, mapFields map[string]any) {
Log(context.Background(), slog.LevelInfo, msg, map2Attrs(mapFields)...)
func InfoWithFields(ctx context.Context, msg string, mapFields map[string]any) {
Log(ctx, slog.LevelInfo, msg, map2Attrs(mapFields)...)
}
func Warn(msg string, args ...any) {
@@ -97,8 +98,8 @@ func ErrorTrace(msg string, err error) {
Log(context.Background(), slog.LevelError, fmt.Sprintf(msg+" %s\n%s", err.Error(), runtimex.StatckStr(2, 10)))
}
func ErrorWithFields(msg string, mapFields map[string]any) {
Log(context.Background(), slog.LevelError, msg, map2Attrs(mapFields)...)
func ErrorWithFields(ctx context.Context, msg string, mapFields map[string]any) {
Log(ctx, slog.LevelError, msg, map2Attrs(mapFields)...)
}
func Panic(msg string, args ...any) {
@@ -120,6 +121,10 @@ func Log(ctx context.Context, level slog.Level, msg string, args ...any) {
func getCommonAttr(ctx context.Context, level slog.Level) []any {
commonAttrs := make([]any, 0)
// 尝试从上下文获取traceId若存在则记录
if traceId := contextx.GetTraceId(ctx); traceId != "" {
commonAttrs = append(commonAttrs, "tid", traceId)
}
// 如果系统配置添加方法信息或者为错误级别时则 记录方法信息及行号
if GetConfig().AddSource || level == slog.LevelError {
// skip [runtime.Callers, getCommonAttr, appendCommonAttr, logx.Log, logx.Info|Debug|Warn|Error..]

View File

@@ -12,6 +12,15 @@ const (
ModelUndeleted int8 = 0
)
// 实体接口
type ModelI interface {
// 使用当前登录账号信息设置实体结构体的基础信息
//
// 如创建时间,修改时间,创建者,修改者信息
SetBaseInfo(account *LoginAccount)
}
// 含有删除字段模型
type DeletedModel struct {
Id uint64 `json:"id"`
@@ -19,6 +28,13 @@ type DeletedModel struct {
DeleteTime *time.Time `json:"-"`
}
func (m *DeletedModel) SetBaseInfo(account *LoginAccount) {
isCreate := m.Id == 0
if isCreate {
m.IsDeleted = ModelUndeleted
}
}
// 基础实体模型,数据表最基础字段,每张表必备字段
type Model struct {
DeletedModel

View File

@@ -2,6 +2,7 @@ package req
import (
"fmt"
"mayfly-go/pkg/contextx"
"mayfly-go/pkg/errorx"
"mayfly-go/pkg/logx"
"mayfly-go/pkg/utils/anyx"
@@ -54,7 +55,7 @@ func LogHandler(rc *Ctx) error {
req := rc.GinCtx.Request
attrMap[req.Method] = req.URL.Path
if la := rc.LoginAccount; la != nil {
if la := contextx.GetLoginAccount(rc.MetaCtx); la != nil {
attrMap["uid"] = la.Id
attrMap["uname"] = la.Username
}
@@ -93,10 +94,10 @@ func LogHandler(rc *Ctx) error {
}
if err := rc.Err; err != nil {
logx.ErrorWithFields(logMsg, attrMap)
logx.ErrorWithFields(rc.MetaCtx, logMsg, attrMap)
return nil
}
logx.InfoWithFields(logMsg, attrMap)
logx.InfoWithFields(rc.MetaCtx, logMsg, attrMap)
return nil
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"mayfly-go/pkg/cache"
"mayfly-go/pkg/config"
"mayfly-go/pkg/contextx"
"mayfly-go/pkg/errorx"
"mayfly-go/pkg/model"
"mayfly-go/pkg/rediscli"
@@ -60,12 +61,10 @@ func PermissionHandler(rc *Ctx) error {
return errorx.PermissionErr
}
}
if rc.LoginAccount == nil {
rc.LoginAccount = &model.LoginAccount{
Id: userId,
Username: userName,
}
}
rc.MetaCtx = contextx.WithLoginAccount(rc.MetaCtx, &model.LoginAccount{
Id: userId,
Username: userName,
})
return nil
}

View File

@@ -1,7 +1,10 @@
package req
import (
"context"
"io"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/contextx"
"mayfly-go/pkg/ginx"
"mayfly-go/pkg/model"
"mayfly-go/pkg/utils/assert"
@@ -16,12 +19,13 @@ type HandlerFunc func(*Ctx)
type Ctx struct {
Conf *Conf // 请求配置
GinCtx *gin.Context // gin context
LoginAccount *model.LoginAccount // 登录账号信息只有校验token后才会有值
ReqParam any // 请求参数,主要用于记录日志
ResData any // 响应结果
Err any // 请求错误
timed int64 // 执行时间
GinCtx *gin.Context // gin context
ReqParam any // 请求参数,主要用于记录日志
ResData any // 响应结果
Err any // 请求错误
timed int64 // 执行时间
MetaCtx context.Context // 元数据上下文信息,如登录账号(只有校验token后才会有值)traceId等
}
func (rc *Ctx) Handle(handler HandlerFunc) {
@@ -59,6 +63,15 @@ func (rc *Ctx) Download(reader io.Reader, filename string) {
ginx.Download(rc.GinCtx, reader, filename)
}
// 获取当前登录账号信息,不存在则会报错。
//
// 若不需要报错则使用contextx.GetLoginAccount方法
func (rc *Ctx) GetLoginAccount() *model.LoginAccount {
la := contextx.GetLoginAccount(rc.MetaCtx)
biz.IsTrue(la != nil, "获取登录账号信息失败, 请确认该接口是否通过鉴权")
return la
}
func (rc *Ctx) WithConf(conf *Conf) *Ctx {
rc.Conf = conf
return rc
@@ -87,7 +100,7 @@ func (rc *Ctx) GetLogInfo() *LogInfo {
}
func NewCtxWithGin(g *gin.Context) *Ctx {
return &Ctx{GinCtx: g}
return &Ctx{GinCtx: g, MetaCtx: contextx.NewTraceId()}
}
// 处理器拦截器函数

View File

@@ -13,6 +13,11 @@ func ToMap(jsonStr string) map[string]any {
return ToMapByBytes([]byte(jsonStr))
}
// json字符串转结构体
func To[T any](jsonStr string, res T) (T, error) {
return res, json.Unmarshal([]byte(jsonStr), &res)
}
// json字节数组转map
func ToMapByBytes(bytes []byte) map[string]any {
var res map[string]any

View File

@@ -5,11 +5,18 @@ import (
"time"
)
const randChar = "0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const Nums = "0123456789"
const LowerChars = "abcdefghigklmnopqrstuvwxyz"
const UpperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
// 生成随机字符串
func Rand(l int) string {
strList := []byte(randChar)
return RandByChars(l, Nums+LowerChars+UpperChars)
}
// 根据传入的chars随机生成指定位数的字符串
func RandByChars(l int, chars string) string {
strList := []byte(chars)
result := []byte{}
i := 0

View File

@@ -0,0 +1,26 @@
package stringx
import (
"fmt"
"mayfly-go/pkg/utils/collx"
"strings"
"testing"
)
func TestTemplateParse(t *testing.T) {
tmpl := `
{{if gt .cpu 10*5}}
当前服务器[{{.asset.host}}]cpu使用率为{{.cpu}}
{{end}}
`
vars := collx.M{
"cpu": 60,
"asset": collx.M{
"host": "localhost:121",
},
}
res, _ := TemplateParse(tmpl, vars)
res2 := strings.TrimSpace(res)
fmt.Println(res2)
}