Commit 75221ace authored by 王曜嵚 Wang Yaoqin's avatar 王曜嵚 Wang Yaoqin

dev: 调试接口

parent 24900cd7
...@@ -10,7 +10,10 @@ ...@@ -10,7 +10,10 @@
<span title="分支" class="secondary branch">分支:{{ info?.branch }}</span> <span title="分支" class="secondary branch">分支:{{ info?.branch }}</span>
<span title="目录" class="secondary">目录:/var/logwire-platform</span> <span title="目录" class="secondary">目录:/var/logwire-platform</span>
</div> </div>
<div class="row" style="margin-top: 50px;"> <div v-if="tip" class="row" style="color: #ffa15b;word-break: break-all;">
<span>Tip: {{ tip }}</span>
</div>
<div class="row" style="position: absolute;bottom: 0px;">
<div class="extra-operation" @click="navigateTo('/git')"> <div class="extra-operation" @click="navigateTo('/git')">
<svg t="1714466723924" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13200" width="200" height="200"><path d="M738.986667 868.693333c0 47.786667 37.546667 85.333333 85.333333 85.333334s85.333333-37.546667 85.333333-85.333334-37.546667-85.333333-85.333333-85.333333-85.333333 39.253333-85.333333 85.333333z" p-id="13201"></path><path d="M824.32 979.626667c-61.44 0-110.933333-49.493333-110.933333-110.933334s49.493333-110.933333 110.933333-110.933333 110.933333 49.493333 110.933333 110.933333-49.493333 110.933333-110.933333 110.933334z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733333 59.733333s27.306667 59.733333 59.733333 59.733334 59.733333-27.306667 59.733333-59.733334-27.306667-59.733333-59.733333-59.733333z" p-id="13202"></path><path d="M269.653333 868.693333c0 47.786667 37.546667 85.333333 85.333334 85.333334s85.333333-37.546667 85.333333-85.333334-37.546667-85.333333-85.333333-85.333333-85.333333 39.253333-85.333334 85.333333z" p-id="13203"></path><path d="M354.986667 979.626667c-61.44 0-110.933333-49.493333-110.933334-110.933334s49.493333-110.933333 110.933334-110.933333 110.933333 49.493333 110.933333 110.933333-49.493333 110.933333-110.933333 110.933334z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733334 59.733333s27.306667 59.733333 59.733334 59.733334 59.733333-27.306667 59.733333-59.733334-27.306667-59.733333-59.733333-59.733333z" p-id="13204"></path><path d="M269.653333 186.026667c0 47.786667 37.546667 85.333333 85.333334 85.333333s85.333333-37.546667 85.333333-85.333333-37.546667-85.333333-85.333333-85.333334-85.333333 39.253333-85.333334 85.333334z" p-id="13205"></path><path d="M354.986667 296.96c-61.44 0-110.933333-49.493333-110.933334-110.933333s49.493333-110.933333 110.933334-110.933334 110.933333 49.493333 110.933333 110.933334-49.493333 110.933333-110.933333 110.933333z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733334 59.733334s27.306667 59.733333 59.733334 59.733333 59.733333-27.306667 59.733333-59.733333-27.306667-59.733333-59.733333-59.733334z" p-id="13206"></path><path d="M824.32 808.96c-13.653333 0-25.6-11.946667-25.6-25.6v-85.333333c0-68.266667-110.933333-114.346667-218.453333-157.013334-75.093333-30.72-150.186667-61.44-199.68-104.106666V785.066667c0 13.653333-11.946667 25.6-25.6 25.6s-25.6-11.946667-25.6-25.6V273.066667c0-13.653333 11.946667-25.6 25.6-25.6s25.6 11.946667 25.6 25.6v63.146666c0 68.266667 110.933333 114.346667 218.453333 157.013334 122.88 51.2 250.88 102.4 250.88 204.8v85.333333c0 13.653333-11.946667 25.6-25.6 25.6z" p-id="13207"></path></svg> <svg t="1714466723924" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13200" width="200" height="200"><path d="M738.986667 868.693333c0 47.786667 37.546667 85.333333 85.333333 85.333334s85.333333-37.546667 85.333333-85.333334-37.546667-85.333333-85.333333-85.333333-85.333333 39.253333-85.333333 85.333333z" p-id="13201"></path><path d="M824.32 979.626667c-61.44 0-110.933333-49.493333-110.933333-110.933334s49.493333-110.933333 110.933333-110.933333 110.933333 49.493333 110.933333 110.933333-49.493333 110.933333-110.933333 110.933334z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733333 59.733333s27.306667 59.733333 59.733333 59.733334 59.733333-27.306667 59.733333-59.733334-27.306667-59.733333-59.733333-59.733333z" p-id="13202"></path><path d="M269.653333 868.693333c0 47.786667 37.546667 85.333333 85.333334 85.333334s85.333333-37.546667 85.333333-85.333334-37.546667-85.333333-85.333333-85.333333-85.333333 39.253333-85.333334 85.333333z" p-id="13203"></path><path d="M354.986667 979.626667c-61.44 0-110.933333-49.493333-110.933334-110.933334s49.493333-110.933333 110.933334-110.933333 110.933333 49.493333 110.933333 110.933333-49.493333 110.933333-110.933333 110.933334z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733334 59.733333s27.306667 59.733333 59.733334 59.733334 59.733333-27.306667 59.733333-59.733334-27.306667-59.733333-59.733333-59.733333z" p-id="13204"></path><path d="M269.653333 186.026667c0 47.786667 37.546667 85.333333 85.333334 85.333333s85.333333-37.546667 85.333333-85.333333-37.546667-85.333333-85.333333-85.333334-85.333333 39.253333-85.333334 85.333334z" p-id="13205"></path><path d="M354.986667 296.96c-61.44 0-110.933333-49.493333-110.933334-110.933333s49.493333-110.933333 110.933334-110.933334 110.933333 49.493333 110.933333 110.933334-49.493333 110.933333-110.933333 110.933333z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733334 59.733334s27.306667 59.733333 59.733334 59.733333 59.733333-27.306667 59.733333-59.733333-27.306667-59.733333-59.733333-59.733334z" p-id="13206"></path><path d="M824.32 808.96c-13.653333 0-25.6-11.946667-25.6-25.6v-85.333333c0-68.266667-110.933333-114.346667-218.453333-157.013334-75.093333-30.72-150.186667-61.44-199.68-104.106666V785.066667c0 13.653333-11.946667 25.6-25.6 25.6s-25.6-11.946667-25.6-25.6V273.066667c0-13.653333 11.946667-25.6 25.6-25.6s25.6 11.946667 25.6 25.6v63.146666c0 68.266667 110.933333 114.346667 218.453333 157.013334 122.88 51.2 250.88 102.4 250.88 204.8v85.333333c0 13.653333-11.946667 25.6-25.6 25.6z" p-id="13207"></path></svg>
切换分支 切换分支
...@@ -52,21 +55,31 @@ ...@@ -52,21 +55,31 @@
import { Socket, io } from 'socket.io-client'; import { Socket, io } from 'socket.io-client';
import { useUserStore } from '~/store/user'; import { useUserStore } from '~/store/user';
let { pending, data: info } = useLazyFetch('/api/devops/v1/getProjectInfo') let tip = ref('')
let { pending, data: info, execute } = useLazyFetch('/api/devops/v1/getProjectInfo')
watch(info, (info) => { watch(info, (info) => {
useUserStore().setBranchV1({ branchV1: info?.branch || '' }) useUserStore().setBranchV1({ branchV1: info?.branch || '' })
if (info && info.status) {
tip.value = getTip(info.status) || ''
}
}) })
let socket: Socket = getWebSocket() let socket: Socket = getWebSocket()
onMounted(() => { onMounted(() => {
socket.on('ChangeV1Status', (e: any) => { socket.on('v1', (e: string) => {
if (info.value) info.value.status = e const data = JSON.parse(e) as { type: string , message: string }
if (data.type === 'Tip') {
tip.value = data.message
} else if (data.type === 'Status') {
info.value!.status = data.message as any
tip.value = getTip(data.message) || ''
}
}) })
}) })
onUnmounted(() => { onUnmounted(() => {
socket.removeListener('ChangeV1Status') socket.removeListener('v1')
}) })
function handleOpenVscode() { function handleOpenVscode() {
...@@ -80,7 +93,6 @@ function getStatusLabel(status?: string) { ...@@ -80,7 +93,6 @@ function getStatusLabel(status?: string) {
['created', "已创建"], ['created', "已创建"],
['running', '运行中'], ['running', '运行中'],
['launched', '正在运行'], ['launched', '正在运行'],
['stopped', '已停止'],
['compiling', '编译中'], ['compiling', '编译中'],
['compiled', '已编译'] ['compiled', '已编译']
]) ])
...@@ -97,9 +109,16 @@ async function handleCompile() { ...@@ -97,9 +109,16 @@ async function handleCompile() {
} }
async function handleInstall() { async function handleInstall() {
await $fetch('/api/devops/v1/install', { method: 'post' }) await $fetch('/api/devops/v1/install', { method: 'post' })
if (info.value) { execute()
info.value.branch = 'master' }
} function getTip (status: string) {
const HOST = process.env.NODE_ENV === 'production' ? '192.168.0.4' : (process.env.DEVHOST || '192.168.0.190')
const port = useUserStore().port
const map = new Map([
['null', '请点击右侧按钮完成项目初始化'],
['launched', `请代理后端请求到 ${HOST}:${port}`]
])
return map.get(status)
} }
</script> </script>
...@@ -117,6 +136,7 @@ async function handleInstall() { ...@@ -117,6 +136,7 @@ async function handleInstall() {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
padding: 20px; padding: 20px;
position: relative;
} }
.project-card__settings{ .project-card__settings{
width: 60px; width: 60px;
......
...@@ -10,7 +10,11 @@ ...@@ -10,7 +10,11 @@
<span title="分支" class="secondary branch">分支:{{ info?.branch }}</span> <span title="分支" class="secondary branch">分支:{{ info?.branch }}</span>
<span title="目录" class="secondary">目录:/var/logwire-backend</span> <span title="目录" class="secondary">目录:/var/logwire-backend</span>
</div> </div>
<div class="row" style="margin-top: 50px;"> <div v-if="tip" class="row" style="color: #ffa15b;word-break: break-all;">
<span>TIP: </span>
<span v-html="tip"></span>
</div>
<div class="row" style="position: absolute;bottom: 0px;">
<div class="extra-operation" @click="navigateTo('/git')"> <div class="extra-operation" @click="navigateTo('/git')">
<svg t="1714466723924" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13200" width="200" height="200"><path d="M738.986667 868.693333c0 47.786667 37.546667 85.333333 85.333333 85.333334s85.333333-37.546667 85.333333-85.333334-37.546667-85.333333-85.333333-85.333333-85.333333 39.253333-85.333333 85.333333z" p-id="13201"></path><path d="M824.32 979.626667c-61.44 0-110.933333-49.493333-110.933333-110.933334s49.493333-110.933333 110.933333-110.933333 110.933333 49.493333 110.933333 110.933333-49.493333 110.933333-110.933333 110.933334z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733333 59.733333s27.306667 59.733333 59.733333 59.733334 59.733333-27.306667 59.733333-59.733334-27.306667-59.733333-59.733333-59.733333z" p-id="13202"></path><path d="M269.653333 868.693333c0 47.786667 37.546667 85.333333 85.333334 85.333334s85.333333-37.546667 85.333333-85.333334-37.546667-85.333333-85.333333-85.333333-85.333333 39.253333-85.333334 85.333333z" p-id="13203"></path><path d="M354.986667 979.626667c-61.44 0-110.933333-49.493333-110.933334-110.933334s49.493333-110.933333 110.933334-110.933333 110.933333 49.493333 110.933333 110.933333-49.493333 110.933333-110.933333 110.933334z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733334 59.733333s27.306667 59.733333 59.733334 59.733334 59.733333-27.306667 59.733333-59.733334-27.306667-59.733333-59.733333-59.733333z" p-id="13204"></path><path d="M269.653333 186.026667c0 47.786667 37.546667 85.333333 85.333334 85.333333s85.333333-37.546667 85.333333-85.333333-37.546667-85.333333-85.333333-85.333334-85.333333 39.253333-85.333334 85.333334z" p-id="13205"></path><path d="M354.986667 296.96c-61.44 0-110.933333-49.493333-110.933334-110.933333s49.493333-110.933333 110.933334-110.933334 110.933333 49.493333 110.933333 110.933334-49.493333 110.933333-110.933333 110.933333z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733334 59.733334s27.306667 59.733333 59.733334 59.733333 59.733333-27.306667 59.733333-59.733333-27.306667-59.733333-59.733333-59.733334z" p-id="13206"></path><path d="M824.32 808.96c-13.653333 0-25.6-11.946667-25.6-25.6v-85.333333c0-68.266667-110.933333-114.346667-218.453333-157.013334-75.093333-30.72-150.186667-61.44-199.68-104.106666V785.066667c0 13.653333-11.946667 25.6-25.6 25.6s-25.6-11.946667-25.6-25.6V273.066667c0-13.653333 11.946667-25.6 25.6-25.6s25.6 11.946667 25.6 25.6v63.146666c0 68.266667 110.933333 114.346667 218.453333 157.013334 122.88 51.2 250.88 102.4 250.88 204.8v85.333333c0 13.653333-11.946667 25.6-25.6 25.6z" p-id="13207"></path></svg> <svg t="1714466723924" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13200" width="200" height="200"><path d="M738.986667 868.693333c0 47.786667 37.546667 85.333333 85.333333 85.333334s85.333333-37.546667 85.333333-85.333334-37.546667-85.333333-85.333333-85.333333-85.333333 39.253333-85.333333 85.333333z" p-id="13201"></path><path d="M824.32 979.626667c-61.44 0-110.933333-49.493333-110.933333-110.933334s49.493333-110.933333 110.933333-110.933333 110.933333 49.493333 110.933333 110.933333-49.493333 110.933333-110.933333 110.933334z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733333 59.733333s27.306667 59.733333 59.733333 59.733334 59.733333-27.306667 59.733333-59.733334-27.306667-59.733333-59.733333-59.733333z" p-id="13202"></path><path d="M269.653333 868.693333c0 47.786667 37.546667 85.333333 85.333334 85.333334s85.333333-37.546667 85.333333-85.333334-37.546667-85.333333-85.333333-85.333333-85.333333 39.253333-85.333334 85.333333z" p-id="13203"></path><path d="M354.986667 979.626667c-61.44 0-110.933333-49.493333-110.933334-110.933334s49.493333-110.933333 110.933334-110.933333 110.933333 49.493333 110.933333 110.933333-49.493333 110.933333-110.933333 110.933334z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733334 59.733333s27.306667 59.733333 59.733334 59.733334 59.733333-27.306667 59.733333-59.733334-27.306667-59.733333-59.733333-59.733333z" p-id="13204"></path><path d="M269.653333 186.026667c0 47.786667 37.546667 85.333333 85.333334 85.333333s85.333333-37.546667 85.333333-85.333333-37.546667-85.333333-85.333333-85.333334-85.333333 39.253333-85.333334 85.333334z" p-id="13205"></path><path d="M354.986667 296.96c-61.44 0-110.933333-49.493333-110.933334-110.933333s49.493333-110.933333 110.933334-110.933334 110.933333 49.493333 110.933333 110.933334-49.493333 110.933333-110.933333 110.933333z m0-170.666667c-32.426667 0-59.733333 27.306667-59.733334 59.733334s27.306667 59.733333 59.733334 59.733333 59.733333-27.306667 59.733333-59.733333-27.306667-59.733333-59.733333-59.733334z" p-id="13206"></path><path d="M824.32 808.96c-13.653333 0-25.6-11.946667-25.6-25.6v-85.333333c0-68.266667-110.933333-114.346667-218.453333-157.013334-75.093333-30.72-150.186667-61.44-199.68-104.106666V785.066667c0 13.653333-11.946667 25.6-25.6 25.6s-25.6-11.946667-25.6-25.6V273.066667c0-13.653333 11.946667-25.6 25.6-25.6s25.6 11.946667 25.6 25.6v63.146666c0 68.266667 110.933333 114.346667 218.453333 157.013334 122.88 51.2 250.88 102.4 250.88 204.8v85.333333c0 13.653333-11.946667 25.6-25.6 25.6z" p-id="13207"></path></svg>
切换分支 切换分支
...@@ -44,7 +48,7 @@ ...@@ -44,7 +48,7 @@
<div class="setting-item" v-if="info?.status === 'compiled'" title="运行" @click="handleExecute"> <div class="setting-item" v-if="info?.status === 'compiled'" title="运行" @click="handleExecute">
<svg t="1714466279198" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1111" width="200" height="200"><path d="M512 193.536c175.616 0 318.464 142.848 318.464 318.464s-142.848 318.464-318.464 318.464S193.536 687.616 193.536 512 336.384 193.536 512 193.536M512 102.4c-226.304 0-409.6 183.296-409.6 409.6s183.296 409.6 409.6 409.6 409.6-183.296 409.6-409.6-183.296-409.6-409.6-409.6z" p-id="1112"></path><path d="M670.208 483.328L456.192 360.96a26.0096 26.0096 0 0 0-38.912 22.528v244.736c0 19.968 21.504 32.256 38.912 22.528l214.016-122.368c17.408-10.24 17.408-35.328 0-45.056z" p-id="1113"></path></svg> <svg t="1714466279198" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1111" width="200" height="200"><path d="M512 193.536c175.616 0 318.464 142.848 318.464 318.464s-142.848 318.464-318.464 318.464S193.536 687.616 193.536 512 336.384 193.536 512 193.536M512 102.4c-226.304 0-409.6 183.296-409.6 409.6s183.296 409.6 409.6 409.6 409.6-183.296 409.6-409.6-183.296-409.6-409.6-409.6z" p-id="1112"></path><path d="M670.208 483.328L456.192 360.96a26.0096 26.0096 0 0 0-38.912 22.528v244.736c0 19.968 21.504 32.256 38.912 22.528l214.016-122.368c17.408-10.24 17.408-35.328 0-45.056z" p-id="1113"></path></svg>
</div> </div>
<div class="setting-item" v-if="info?.status === 'launched'" title="停止" @click="handleStop"> <div class="setting-item" v-if="info?.status === 'launched' || info?.status === 'debug-launched'" title="停止" @click="handleStop">
<svg t="1714466309184" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1264" width="200" height="200"><path d="M611.328 638.464H412.672c-14.848 0-27.136-12.288-27.136-27.136V412.672c0-14.848 12.288-27.136 27.136-27.136h198.144c14.848 0 27.136 12.288 27.136 27.136v198.144c0.512 15.36-11.776 27.648-26.624 27.648z" p-id="1265"></path><path d="M512 193.536c175.616 0 318.464 142.848 318.464 318.464s-142.848 318.464-318.464 318.464S193.536 687.616 193.536 512 336.384 193.536 512 193.536M512 102.4c-226.304 0-409.6 183.296-409.6 409.6s183.296 409.6 409.6 409.6 409.6-183.296 409.6-409.6-183.296-409.6-409.6-409.6z" p-id="1266"></path></svg> <svg t="1714466309184" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1264" width="200" height="200"><path d="M611.328 638.464H412.672c-14.848 0-27.136-12.288-27.136-27.136V412.672c0-14.848 12.288-27.136 27.136-27.136h198.144c14.848 0 27.136 12.288 27.136 27.136v198.144c0.512 15.36-11.776 27.648-26.624 27.648z" p-id="1265"></path><path d="M512 193.536c175.616 0 318.464 142.848 318.464 318.464s-142.848 318.464-318.464 318.464S193.536 687.616 193.536 512 336.384 193.536 512 193.536M512 102.4c-226.304 0-409.6 183.296-409.6 409.6s183.296 409.6 409.6 409.6 409.6-183.296 409.6-409.6-183.296-409.6-409.6-409.6z" p-id="1266"></path></svg>
</div> </div>
<div v-if="info?.status?.endsWith('ing')" class="setting-item"> <div v-if="info?.status?.endsWith('ing')" class="setting-item">
...@@ -73,21 +77,31 @@ ...@@ -73,21 +77,31 @@
import { Socket, io } from 'socket.io-client'; import { Socket, io } from 'socket.io-client';
import { useUserStore } from '~/store/user'; import { useUserStore } from '~/store/user';
let { pending, data: info } = useLazyFetch('/api/devops/v2/getProjectInfo') let tip = ref('')
let { pending, data: info, execute } = useLazyFetch('/api/devops/v2/getProjectInfo')
watch(info, (info) => { watch(info, (info) => {
useUserStore().setBranchV2({ branchV2: info?.branch || '' }) useUserStore().setBranchV2({ branchV2: info?.branch || '' })
if (info && info.status) {
tip.value = getTip(info.status) || ''
}
}) })
let socket: Socket = getWebSocket() let socket: Socket = getWebSocket()
onMounted(() => { onMounted(() => {
socket.on('ChangeV2Status', (e: any) => { socket.on('v2', (e: string) => {
console.log('info', info, e) const data = JSON.parse(e) as { type: string , message: string }
if (info.value) info.value.status = e if (data.type === 'Tip') {
tip.value = data.message
} else if (data.type === 'Status') {
info.value!.status = data.message as any
tip.value = getTip(data.message) || ''
}
}) })
}) })
onUnmounted(() => { onUnmounted(() => {
socket.removeListener('changeV2Status') socket.removeListener('v2')
}) })
function handleOpenVscode() { function handleOpenVscode() {
window.open(window.location.protocol + '//' + window.location.hostname + ':' + useUserStore().port + '/vscode?folder=/var/logwire-backend', '_blank') window.open(window.location.protocol + '//' + window.location.hostname + ':' + useUserStore().port + '/vscode?folder=/var/logwire-backend', '_blank')
...@@ -100,7 +114,7 @@ function getStatusLabel(status?: string) { ...@@ -100,7 +114,7 @@ function getStatusLabel(status?: string) {
['created', "已创建"], ['created', "已创建"],
['running', '运行中'], ['running', '运行中'],
['launched', '正在运行'], ['launched', '正在运行'],
['stopped', '已停止'], ['debugLaunched', '正在调试'],
['compiling', '编译中'], ['compiling', '编译中'],
['compiled', '已编译'] ['compiled', '已编译']
]) ])
...@@ -123,9 +137,17 @@ async function handleCompile() { ...@@ -123,9 +137,17 @@ async function handleCompile() {
} }
async function handleInstall() { async function handleInstall() {
await $fetch('/api/devops/v2/install', { method: 'post' }) await $fetch('/api/devops/v2/install', { method: 'post' })
if (info.value) { execute()
info.value.branch = 'master' }
}
function getTip (status: string) {
const HOST = process.env.NODE_ENV === 'production' ? '192.168.0.4' : (process.env.DEVHOST || '192.168.0.190')
const port = useUserStore().port
const map = new Map([
['null', '请点击右侧按钮完成项目初始化'],
['launched', `请代理后端请求到 ${HOST}:${port}, 开发环境域名和端口号为 ${(info.value?.tenants as any)?.host}`]
])
return map.get(status)
} }
</script> </script>
...@@ -144,6 +166,7 @@ async function handleInstall() { ...@@ -144,6 +166,7 @@ async function handleInstall() {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
padding: 20px; padding: 20px;
position: relative;
} }
.project-card__settings{ .project-card__settings{
width: 60px; width: 60px;
......
...@@ -7,7 +7,11 @@ export default defineEventHandler(async (event) => { ...@@ -7,7 +7,11 @@ export default defineEventHandler(async (event) => {
let docker = createDockerFactory(username) let docker = createDockerFactory(username)
LogUtil.clear(username) LogUtil.clear(username)
await changeProjectStatus( 'v1', username, 'status', 'compiling') await changeProjectStatus('v1', username, 'status', 'compiling')
const rowV2 = await getPgTableData('v2', username)
if (rowV2?.status === 'launched') {
await changeProjectStatus('v2', username, 'status', 'compiled')
}
// 每次编译前把已有的 tenants_config 文件夹拷贝到一个地方,编译完成后,再拷贝回来 // 每次编译前把已有的 tenants_config 文件夹拷贝到一个地方,编译完成后,再拷贝回来
let container = await docker.checkContainer( username + '.node') let container = await docker.checkContainer( username + '.node')
......
...@@ -11,6 +11,10 @@ export default defineEventHandler(async (event) => { ...@@ -11,6 +11,10 @@ export default defineEventHandler(async (event) => {
LogUtil.printInfo(username, '程序启动中') LogUtil.printInfo(username, '程序启动中')
await changeProjectStatus( 'v1', username, 'status', 'running') await changeProjectStatus( 'v1', username, 'status', 'running')
const rowV2 = await getPgTableData('v2', username)
if (rowV2?.status === 'launched') {
await changeProjectStatus('v2', username, 'status', 'compiled')
}
if (!container) { if (!container) {
throw new Error('没有创建容器,请先初始化容器') throw new Error('没有创建容器,请先初始化容器')
} }
......
import Dockerode from "dockerode" import Dockerode from "dockerode"
import LogUtil from "~/server/utils/log" import LogUtil, { sendSocketMessage } from "~/server/utils/log"
import path from 'path' import path from 'path'
export default defineEventHandler(async (event) => { export default defineEventHandler(async (event) => {
let username = event.context.username let username = event.context.username
let pgClient = await createPgClientFactory(username) let isClonedSuccess = true
let sshKey = ''
try { try {
LogUtil.clear(username) LogUtil.clear(username)
let docker = createDockerFactory(username) let docker = createDockerFactory(username)
const rowV2 = await getPgTableData( 'v2', username)
if (!rowV2 || rowV2?.status === 'null' || !rowV2?.status) {
throw new Error('请先初始化 V2')
}
let rowV1 = await getPgTableData('v1', username) let rowV1 = await getPgTableData('v1', username)
if (!rowV1) await insertPgTableData('v1', username) if (!rowV1) await insertPgTableData('v1', username)
await changeProjectStatus( 'v1', username, 'status', 'creating') await changeProjectStatus( 'v1', username, 'status', 'creating')
...@@ -22,20 +18,48 @@ export default defineEventHandler(async (event) => { ...@@ -22,20 +18,48 @@ export default defineEventHandler(async (event) => {
} }
// 创建 postgres 不一定要在本机,即使是 dev 环境也可以联远程的容器 // 创建 postgres 不一定要在本机,即使是 dev 环境也可以联远程的容器
await LogUtil.run(username, 'v1-创建 postgres 容器', async () => { await LogUtil.run(username, 'v1-创建 postgres 容器', async () => {
if (process.env.NODE_ENV?.trim() !== 'production') {
let postgresInfo = await docker.checkContainer('postgres_12')
if (!postgresInfo) {
let postgres = await docker.checkAndCreateContainer({ name: 'postgres_12', img: 'postgres:12', env: ["POSTGRES_PASSWORD=postgres"], portBindings: { '5432/tcp': [{ HostPort: PgPort.toString() }] } })
await docker.startContainer({ container: postgres })
await sleep(3000)
}
const database = username + '_v1' const database = username + '_v1'
let result = await executePgQuery({ client: pgClient, query: "SELECT u.datname FROM pg_catalog.pg_database u where u.datname='" + database + "';" }) let client = await createPgClientFactory()
let result = await executePgQuery({ client, query: "SELECT u.datname FROM pg_catalog.pg_database u where u.datname='" + database + "';" })
if (result.rows.length === 0) { if (result.rows.length === 0) {
await executePgQuery({ client: pgClient, query: 'CREATE DATABASE ' + database }) await executePgQuery({ client, query: 'CREATE DATABASE ' + database })
const client = await createPgClient({ host: HOST, port: PgPort, database: database }) await client.end()
client = await createPgClient({ host: HOST, port: PgPort, database: database })
await executePgQuery({ client, query: 'CREATE SCHEMA library' }) await executePgQuery({ client, query: 'CREATE SCHEMA library' })
await client.end() await client.end()
} }
}
})
await LogUtil.run(username, 'v1-创建 redis 容器', async () => {
if (process.env.NODE_ENV?.trim() !== 'production') {
let redisInfo = await docker.checkContainer('redis')
if (!redisInfo) {
let redis = await docker.checkAndCreateContainer({ name: 'redis', img: 'redis', portBindings: { '6379/tcp': [{ HostPort: '6379' }] } })
await docker.startContainer({ container: redis })
}
}
})
await LogUtil.run(username, '检查 SSH Key', async () => {
sshKey = await checkSshExists(username)
LogUtil.printWarning(username, `${username}@greaconsulting.com 用户 SSH key 为 <strong>${sshKey.replace(/\n/g, '')}</strong>, 若克隆仓库失败, 请检查是否放入 Gitlab SSH 设置中并重试\n`)
}) })
await LogUtil.run(username, 'v1-克隆仓库', async () => { await LogUtil.run(username, 'v1-克隆仓库', async () => {
isClonedSuccess = false
await docker.execContainerCommand({ container, cmd: ['git', 'config' ,'--global', 'core.sshCommand', 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'] }) await docker.execContainerCommand({ container, cmd: ['git', 'config' ,'--global', 'core.sshCommand', 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'] })
await docker.execContainerCommand({ container, cmd: 'rm -rf /var/logwire-platform' }) await docker.execContainerCommand({ container, cmd: 'rm -rf /var/logwire-platform' })
await docker.execContainerCommand({ container, cmd: 'git clone ssh://git@gitlab.logwire.cn:13389/logwire/logwire-platform.git', dir: '/var' }) await docker.execContainerCommand({ container, cmd: 'git clone ssh://git@gitlab.logwire.cn:13389/logwire/logwire-platform.git', dir: '/var' })
isClonedSuccess = true
}) })
await LogUtil.run(username, 'v1-安装 openjdk ', async () => { await LogUtil.run(username, 'v1-安装 openjdk ', async () => {
...@@ -64,11 +88,15 @@ export default defineEventHandler(async (event) => { ...@@ -64,11 +88,15 @@ export default defineEventHandler(async (event) => {
}) })
await changeProjectStatus( 'v1', username, 'status', 'created') await changeProjectStatus( 'v1', username, 'status', 'created')
await stopPgClient(pgClient)
LogUtil.printSuccess(username, 'installed') LogUtil.printSuccess(username, 'installed')
} catch (err: any) { } catch (err: any) {
await changeProjectStatus( 'v1', username, 'status', 'null') await changeProjectStatus( 'v1', username, 'status', 'null')
await stopPgClient(pgClient) if (!isClonedSuccess) {
const message = `初始化中克隆仓库失败,请将 <strong>${sshKey.replace(/\n/g, '')}</strong> 放入 Gitlab SSH 设置中并重试`
const type = 'Tip'
const eventData = { type, message }
sendSocketMessage(username, 'v1', JSON.stringify(eventData))
}
LogUtil.printError(username, (err instanceof Error ? err.message : JSON.stringify(err))) LogUtil.printError(username, (err instanceof Error ? err.message : JSON.stringify(err)))
setResponseStatus(event, 500) setResponseStatus(event, 500)
return err return err
......
...@@ -9,6 +9,7 @@ export default defineEventHandler(async (event) => { ...@@ -9,6 +9,7 @@ export default defineEventHandler(async (event) => {
throw new Error('没有创建容器,请先初始化容器') throw new Error('没有创建容器,请先初始化容器')
} }
LogUtil.printInfo(username, `程序停止中......`) LogUtil.printInfo(username, `程序停止中......`)
await changeProjectStatus( 'v1', username, 'status', 'stopping')
await docker.execContainerCommand({ container, cmd: 'pm2 delete platform', quiet: true }) await docker.execContainerCommand({ container, cmd: 'pm2 delete platform', quiet: true })
LogUtil.printInfo(username, `程序已停止`) LogUtil.printInfo(username, `程序已停止`)
await changeProjectStatus( 'v1', username, 'status', 'compiled') await changeProjectStatus( 'v1', username, 'status', 'compiled')
......
...@@ -9,6 +9,11 @@ export default defineEventHandler(async (event) => { ...@@ -9,6 +9,11 @@ export default defineEventHandler(async (event) => {
let docker = createDockerFactory(username) let docker = createDockerFactory(username)
await changeProjectStatus( 'v2', username, 'status', 'compiling') await changeProjectStatus( 'v2', username, 'status', 'compiling')
const rowV1 = await getPgTableData('v1', username)
if (rowV1?.status === 'launched') {
await changeProjectStatus('v2', username, 'status', 'compiled')
}
// TODO: 在后端发送 websocket 通知前端状态变更 // TODO: 在后端发送 websocket 通知前端状态变更
// 每次编译前把已有的 tenants_config 文件夹拷贝到一个地方,编译完成后,再拷贝回来 // 每次编译前把已有的 tenants_config 文件夹拷贝到一个地方,编译完成后,再拷贝回来
......
...@@ -15,6 +15,11 @@ export default defineEventHandler(async (event) => { ...@@ -15,6 +15,11 @@ export default defineEventHandler(async (event) => {
const port = rowUser!.port const port = rowUser!.port
const debug = rowV2!.debug const debug = rowV2!.debug
if (rowV2?.status !== 'compiled') {
throw new Error('调试只可以在已创建状态下进行')
}
await changeProjectStatus( 'v2', username, 'status', 'running')
// 有可能本身就关闭了 // 有可能本身就关闭了
try { try {
LogUtil.print(username, `[progress] [[1;34mLoading[m] 关闭已存在的 Nginx 服务 ...... \n`) LogUtil.print(username, `[progress] [[1;34mLoading[m] 关闭已存在的 Nginx 服务 ...... \n`)
...@@ -63,5 +68,5 @@ export default defineEventHandler(async (event) => { ...@@ -63,5 +68,5 @@ export default defineEventHandler(async (event) => {
LogUtil.print(username, `[progress] [[1;34mInfo[m] 请设置开发环境域名和端口号 <strong>${tenants?.host}</strong> 上\n`) LogUtil.print(username, `[progress] [[1;34mInfo[m] 请设置开发环境域名和端口号 <strong>${tenants?.host}</strong> 上\n`)
LogUtil.print(username, `[progress] [[1;34mInfo[m] 调试程序已启动,请IP地址为 <strong>${debug?.host}</strong> 后端访问 <strong>${HOST}:${port}</strong> 进行调试\n`) LogUtil.print(username, `[progress] [[1;34mInfo[m] 调试程序已启动,请IP地址为 <strong>${debug?.host}</strong> 后端访问 <strong>${HOST}:${port}</strong> 进行调试\n`)
await changeProjectStatus( 'v2', username, 'status', 'running') await changeProjectStatus( 'v2', username, 'status', 'debug-launched')
}) })
\ No newline at end of file
...@@ -14,6 +14,10 @@ export default defineEventHandler(async (event) => { ...@@ -14,6 +14,10 @@ export default defineEventHandler(async (event) => {
LogUtil.printInfo(username, `程序初始化中......`) LogUtil.printInfo(username, `程序初始化中......`)
await changeProjectStatus( 'v2', username, 'status', 'running') await changeProjectStatus( 'v2', username, 'status', 'running')
const rowV1 = await getPgTableData('v1', username)
if (rowV1?.status === 'launched') {
await changeProjectStatus('v2', username, 'status', 'compiled')
}
if (!container) { if (!container) {
throw new Error('没有创建容器,请先初始化容器') throw new Error('没有创建容器,请先初始化容器')
} }
......
import Dockerode from "dockerode" import Dockerode from "dockerode"
import LogUtil, { sendProjectStatus } from "~/server/utils/log" import LogUtil, { sendProjectStatus, sendSocketMessage } from "~/server/utils/log"
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
import { changeProjectStatus } from "~/server/utils/postgres" import { changeProjectStatus } from "~/server/utils/postgres"
export default defineEventHandler(async (event) => { export default defineEventHandler(async (event) => {
let username = event.context.username let username = event.context.username
let pgClient = await createPgClientFactory('backend_helper') let isClonedSuccess = true
let sshKey = ''
try { try {
LogUtil.clear(username) LogUtil.clear(username)
let docker = createDockerFactory(username) let docker = createDockerFactory(username)
let host = docker.host
let container: Dockerode.Container = {} as Dockerode.Container let container: Dockerode.Container = {} as Dockerode.Container
const port = (await getPgTableData( 'user', username))?.port const port = (await getPgTableData( 'user', username))?.port
const row = await getPgTableData('v2', username) const row = await getPgTableData('v2', username)
...@@ -28,7 +28,7 @@ export default defineEventHandler(async (event) => { ...@@ -28,7 +28,7 @@ export default defineEventHandler(async (event) => {
await docker.startContainer({ container }) await docker.startContainer({ container })
}) })
await LogUtil.run(username, '检查 SSH Key', async () => { await LogUtil.run(username, '检查 SSH Key', async () => {
let sshKey = await checkSshExists(username) sshKey = await checkSshExists(username)
LogUtil.printWarning(username, `${username}@greaconsulting.com 用户 SSH key 为 <strong>${sshKey.replace(/\n/g, '')}</strong>, 若克隆仓库失败, 请检查是否放入 Gitlab SSH 设置中并重试\n`) LogUtil.printWarning(username, `${username}@greaconsulting.com 用户 SSH key 为 <strong>${sshKey.replace(/\n/g, '')}</strong>, 若克隆仓库失败, 请检查是否放入 Gitlab SSH 设置中并重试\n`)
}) })
// 创建 postgres 不一定要在本机,即使是 dev 环境也可以联远程的容器 // 创建 postgres 不一定要在本机,即使是 dev 环境也可以联远程的容器
...@@ -52,9 +52,12 @@ export default defineEventHandler(async (event) => { ...@@ -52,9 +52,12 @@ export default defineEventHandler(async (event) => {
}) })
await LogUtil.run(username, '创建 redis 容器', async () => { await LogUtil.run(username, '创建 redis 容器', async () => {
if (process.env.NODE_ENV?.trim() !== 'production') { if (process.env.NODE_ENV?.trim() !== 'production') {
let redisInfo = await docker.checkContainer('redis')
if (!redisInfo) {
let redis = await docker.checkAndCreateContainer({ name: 'redis', img: 'redis', portBindings: { '6379/tcp': [{ HostPort: '6379' }] } }) let redis = await docker.checkAndCreateContainer({ name: 'redis', img: 'redis', portBindings: { '6379/tcp': [{ HostPort: '6379' }] } })
await docker.startContainer({ container: redis }) await docker.startContainer({ container: redis })
} }
}
}) })
await LogUtil.run(username, '创建 zookeeper 容器', async () => { await LogUtil.run(username, '创建 zookeeper 容器', async () => {
if (process.env.NODE_ENV?.trim() !== 'production') { if (process.env.NODE_ENV?.trim() !== 'production') {
...@@ -88,9 +91,11 @@ export default defineEventHandler(async (event) => { ...@@ -88,9 +91,11 @@ export default defineEventHandler(async (event) => {
}) })
await LogUtil.run(username, '克隆仓库', async () => { await LogUtil.run(username, '克隆仓库', async () => {
isClonedSuccess = false
await docker.execContainerCommand({ container, cmd: ['git', 'config' ,'--global', 'core.sshCommand', 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'] }) await docker.execContainerCommand({ container, cmd: ['git', 'config' ,'--global', 'core.sshCommand', 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'] })
await docker.execContainerCommand({ container, cmd: 'rm -rf /var/logwire-backend' }) await docker.execContainerCommand({ container, cmd: 'rm -rf /var/logwire-backend' })
await docker.execContainerCommand({ container, cmd: 'git clone ssh://git@gitlab.logwire.cn:13389/logwire2/logwire-backend.git', dir: '/var' }) await docker.execContainerCommand({ container, cmd: 'git clone ssh://git@gitlab.logwire.cn:13389/logwire2/logwire-backend.git', dir: '/var' })
isClonedSuccess = true
}) })
// await LogUtil.run(username, '添加源', async () => { // await LogUtil.run(username, '添加源', async () => {
// let txt = await docker.getFile({ container, path: '/etc/apt/sources.list' }) // let txt = await docker.getFile({ container, path: '/etc/apt/sources.list' })
...@@ -189,11 +194,15 @@ export default defineEventHandler(async (event) => { ...@@ -189,11 +194,15 @@ export default defineEventHandler(async (event) => {
await setPgTableData('v2', username, 'debug', JSON.stringify(debug)) await setPgTableData('v2', username, 'debug', JSON.stringify(debug))
}) })
await changeProjectStatus( 'v2', username, 'status', 'created') await changeProjectStatus( 'v2', username, 'status', 'created')
await stopPgClient(pgClient)
LogUtil.printSuccess(username, '安装成功') LogUtil.printSuccess(username, '安装成功')
} catch (err: any) { } catch (err: any) {
await changeProjectStatus( 'v2', username, 'status', 'null') await changeProjectStatus( 'v2', username, 'status', 'null')
await stopPgClient(pgClient) if (!isClonedSuccess) {
const message = `初始化中克隆仓库失败,请将 <strong>${sshKey.replace(/\n/g, '')}</strong> 放入 Gitlab SSH 设置中并重试`
const type = 'Tip'
const eventData = { type, message }
sendSocketMessage(username, 'v2', JSON.stringify(eventData))
}
LogUtil.printError(username, (err instanceof Error ? err.message : JSON.stringify(err))) LogUtil.printError(username, (err instanceof Error ? err.message : JSON.stringify(err)))
setResponseStatus(event, 500) setResponseStatus(event, 500)
return err return err
......
...@@ -9,6 +9,7 @@ export default defineEventHandler(async (event) => { ...@@ -9,6 +9,7 @@ export default defineEventHandler(async (event) => {
throw new Error('没有创建容器,请先初始化容器') throw new Error('没有创建容器,请先初始化容器')
} }
LogUtil.printInfo(username, `程序停止中......`) LogUtil.printInfo(username, `程序停止中......`)
await changeProjectStatus( 'v2', username, 'status', 'stopping')
await docker.execContainerCommand({ container, cmd: 'pm2 delete backend', quiet: true }) await docker.execContainerCommand({ container, cmd: 'pm2 delete backend', quiet: true })
await docker.execContainerCommand({ container, cmd: 'pm2 delete gateway', quiet: true }) await docker.execContainerCommand({ container, cmd: 'pm2 delete gateway', quiet: true })
LogUtil.print(username, `程序已停止`) LogUtil.print(username, `程序已停止`)
......
...@@ -14,9 +14,17 @@ export function getWebsocketIo (username: string) { ...@@ -14,9 +14,17 @@ export function getWebsocketIo (username: string) {
} }
export function sendProjectStatus (platform: 'v1' | 'v2', username: string, status: string) { export function sendProjectStatus (platform: 'v1' | 'v2', username: string, status: string) {
const eventName = platform === 'v1' ? 'ChangeV1Status' : 'ChangeV2Status'
const socket = getWebsocketIo(username) const socket = getWebsocketIo(username)
socket.emit(eventName, status) const eventData = {
type: 'Status',
message: status
}
socket.emit(platform, JSON.stringify(eventData))
}
export function sendSocketMessage (username: string, eventName: string, message: string) {
const socket = getWebsocketIo(username)
socket.emit(eventName, message)
} }
export default class LogUtil { export default class LogUtil {
...@@ -50,4 +58,8 @@ export default class LogUtil { ...@@ -50,4 +58,8 @@ export default class LogUtil {
let socket = getWebsocketIo(username) let socket = getWebsocketIo(username)
socket.emit('ClearLog') socket.emit('ClearLog')
} }
static printNotification (username: string, notification: string) {
let socket = getWebsocketIo(username)
socket.emit('Notification', removeUnreadCharacter(notification))
}
} }
...@@ -42,7 +42,7 @@ export type TableUser = { username: string, port: number } ...@@ -42,7 +42,7 @@ export type TableUser = { username: string, port: number }
export type TableV2 = { export type TableV2 = {
username: string username: string
status: 'null' | 'created' | 'stopped' | 'running' | 'launched' | 'creating' | 'compiling' | 'compiled' status: 'null' | 'created' | 'running' | 'launched' | 'debug-launched' | 'creating' | 'compiling' | 'compiled'
tenants: Record<string, any> tenants: Record<string, any>
debug: Record<string, any> debug: Record<string, any>
has_debugged: boolean has_debugged: boolean
...@@ -51,7 +51,7 @@ export type TableV2 = { ...@@ -51,7 +51,7 @@ export type TableV2 = {
export type TableV1 = { export type TableV1 = {
username: string username: string
status: 'null' | 'created' | 'stopped' | 'running' | 'launched' | 'creating' | 'compiling' | 'compiled' status: 'null' | 'created' | 'running' | 'launched' | 'creating' | 'compiling' | 'compiled'
serverProperties: { id: any, key: string, value: string }[] serverProperties: { id: any, key: string, value: string }[]
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment