Commit 596c911c authored by 王曜嵚 Wang Yaoqin's avatar 王曜嵚 Wang Yaoqin

dev: websocket 后端传递

parent b2ffb25e
......@@ -3,7 +3,6 @@
padding: 0;
}
.content{
background-color: #EFEFEF;
overflow: hidden;
height: 100%;
padding: 24px;
......
<template>
<span>
<slot />
</span>
</template>
\ No newline at end of file
<template>
<div class="bottom-log" v-show="userStore.username">
<div class="log__icon">
<svg t="1713863250860" fill="gray" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5129" width="16" height="16"><path d="M96 652.8c-19.2 0-38.4-19.2-38.4-38.4V409.6c0-19.2 19.2-38.4 38.4-38.4s38.4 19.2 38.4 38.4v204.8c0 25.6-12.8 38.4-38.4 38.4z" p-id="5130"></path><path d="M1017.6 512c0-51.2-32-89.6-76.8-102.4V160c0-83.2-64-147.2-147.2-147.2H204.8C121.6 12.8 57.6 76.8 57.6 160v19.2c0 19.2 19.2 38.4 38.4 38.4s38.4-19.2 38.4-38.4v-19.2c0-38.4 32-70.4 70.4-70.4h595.2c38.4 0 70.4 32 70.4 70.4V409.6c-38.4 12.8-76.8 57.6-76.8 102.4 0 51.2 32 89.6 76.8 102.4v249.6c0 38.4-32 70.4-70.4 70.4H204.8c-38.4 0-70.4-32-70.4-70.4v-19.2c0-19.2-19.2-38.4-38.4-38.4s-38.4 19.2-38.4 38.4v19.2c0 83.2 64 147.2 147.2 147.2h595.2c83.2 0 147.2-64 147.2-147.2V620.8c44.8-19.2 70.4-57.6 70.4-108.8z m-108.8 51.2c-25.6 0-51.2-19.2-51.2-51.2 0-25.6 19.2-51.2 51.2-51.2s51.2 19.2 51.2 51.2c-6.4 25.6-25.6 51.2-51.2 51.2z" p-id="5131"></path><path d="M659.2 332.8H345.6c-19.2 0-38.4-12.8-38.4-38.4 0-19.2 19.2-38.4 38.4-38.4h313.6c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4zM659.2 550.4H345.6c-19.2 0-38.4-12.8-38.4-38.4 0-19.2 19.2-38.4 38.4-38.4h313.6c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4zM659.2 768H345.6c-19.2 0-38.4-19.2-38.4-38.4s19.2-38.4 38.4-38.4h313.6c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4z" p-id="5132"></path><path d="M153.6 768H44.8c-19.2 0-38.4-19.2-38.4-38.4s19.2-38.4 38.4-38.4h108.8c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4z" p-id="5133"></path><path d="M153.6 332.8H44.8c-25.6 0-38.4-12.8-38.4-38.4 0-19.2 12.8-38.4 38.4-38.4h108.8c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4z" p-id="5134"></path></svg>
<svg t="1713863250860" fill="gray" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5129" width="14" height="14"><path d="M96 652.8c-19.2 0-38.4-19.2-38.4-38.4V409.6c0-19.2 19.2-38.4 38.4-38.4s38.4 19.2 38.4 38.4v204.8c0 25.6-12.8 38.4-38.4 38.4z" p-id="5130"></path><path d="M1017.6 512c0-51.2-32-89.6-76.8-102.4V160c0-83.2-64-147.2-147.2-147.2H204.8C121.6 12.8 57.6 76.8 57.6 160v19.2c0 19.2 19.2 38.4 38.4 38.4s38.4-19.2 38.4-38.4v-19.2c0-38.4 32-70.4 70.4-70.4h595.2c38.4 0 70.4 32 70.4 70.4V409.6c-38.4 12.8-76.8 57.6-76.8 102.4 0 51.2 32 89.6 76.8 102.4v249.6c0 38.4-32 70.4-70.4 70.4H204.8c-38.4 0-70.4-32-70.4-70.4v-19.2c0-19.2-19.2-38.4-38.4-38.4s-38.4 19.2-38.4 38.4v19.2c0 83.2 64 147.2 147.2 147.2h595.2c83.2 0 147.2-64 147.2-147.2V620.8c44.8-19.2 70.4-57.6 70.4-108.8z m-108.8 51.2c-25.6 0-51.2-19.2-51.2-51.2 0-25.6 19.2-51.2 51.2-51.2s51.2 19.2 51.2 51.2c-6.4 25.6-25.6 51.2-51.2 51.2z" p-id="5131"></path><path d="M659.2 332.8H345.6c-19.2 0-38.4-12.8-38.4-38.4 0-19.2 19.2-38.4 38.4-38.4h313.6c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4zM659.2 550.4H345.6c-19.2 0-38.4-12.8-38.4-38.4 0-19.2 19.2-38.4 38.4-38.4h313.6c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4zM659.2 768H345.6c-19.2 0-38.4-19.2-38.4-38.4s19.2-38.4 38.4-38.4h313.6c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4z" p-id="5132"></path><path d="M153.6 768H44.8c-19.2 0-38.4-19.2-38.4-38.4s19.2-38.4 38.4-38.4h108.8c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4z" p-id="5133"></path><path d="M153.6 332.8H44.8c-25.6 0-38.4-12.8-38.4-38.4 0-19.2 12.8-38.4 38.4-38.4h108.8c19.2 0 38.4 19.2 38.4 38.4 0 25.6-19.2 38.4-38.4 38.4z" p-id="5134"></path></svg>
</div>
<div class="log__info" @click="handleChangePanel">
<span v-html="lastLog"></span>
......@@ -13,7 +13,7 @@
<svg t="1713929532584" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4248" width="16" height="16"><path d="M572.16 512l183.466667-183.04a42.666667 42.666667 0 1 0-60.586667-60.586667L512 451.84l-183.04-183.466667a42.666667 42.666667 0 0 0-60.586667 60.586667l183.466667 183.04-183.466667 183.04a42.666667 42.666667 0 0 0 0 60.586667 42.666667 42.666667 0 0 0 60.586667 0l183.04-183.466667 183.04 183.466667a42.666667 42.666667 0 0 0 60.586667 0 42.666667 42.666667 0 0 0 0-60.586667z" p-id="4249"></path></svg>
</div>
</div>
<div class='logs-content'>
<div class='logs-content' ref="logsContent">
<div v-for='item in renderLogs' :key='item'>
<p v-html='item'></p>
</div>
......@@ -23,7 +23,7 @@
</template>
<script setup lang="ts">
import { io } from 'socket.io-client';
import { Socket, io } from 'socket.io-client';
import { useUserStore } from "@/store/user"
const userStore = useUserStore()
......@@ -41,10 +41,8 @@ const renderLogs = computed(() => {
})
userStore.$subscribe(function (mutation, state) {
if (state.username) {
initWebsocket(state.username)
}
})
initWebsocket(state.username)
}, { once: true })
function addColorfulTag(log: string) {
let value = log
......@@ -55,12 +53,7 @@ function addColorfulTag(log: string) {
}
function initWebsocket (username: string) {
const socket = io({
path: '/socket.io',
auth: {
username
}
});
let socket: Socket = getWebSocket()
// eslint-disable-next-line no-control-regex
const removeLogPrefix = (log: string) => log.replace(/^\[.*?\]\s/, '').replace(/[\u0000-\u0009]/g, '').replace(/[\u000B-\u001F]/g, '')
......@@ -74,6 +67,9 @@ function initWebsocket (username: string) {
}
}
})
socket.on('ClearLog', () => {
logs.value = []
})
}
function handleChangePanel () {
......
This diff is collapsed.
This diff is collapsed.
......@@ -50,5 +50,7 @@
#app .maintab{
flex: 1;
overflow: hidden;
margin: 0 auto;
max-width: 800px;
}
</style>
import { useUserStore } from "~/store/user"
export default defineNuxtRouteMiddleware((to, from) => {
if (to.path === '/') {
return navigateTo('/login')
} else if (to.path !== '/login' && !useUserStore().username) {
// 检查是否登录
return navigateTo('/login')
}
})
\ No newline at end of file
......@@ -3,24 +3,6 @@
<div class='content'>
<div class='container'>
<form class='form' @submit.prevent>
<div class='form-group'>
<div class='form-group__label'>
<label>Email</label>
<p>用户的 Gitlab 邮箱账号</p>
</div>
<div class='form-group__body'>
<input v-model='form.email' />
</div>
</div>
<div class='form-group'>
<div class='form-group__label'>
<label>SSH Key</label>
<p>使用上述的 Email 邮箱生成 Ssh key,用于 Gitlab 中用户认证</p>
</div>
<div class='form-group__body'>
<button class='primary' @click='handleGenerate'>生成 ssh key</button>
</div>
</div>
<div class='form-group'>
<div class='form-group__label'>
<label>V2 分支管理</label>
......@@ -32,16 +14,13 @@
<span>所有分支</span>
<span>
<select v-model='form.targetBranchV2'>
<option v-for='item in branchs' :key='item'>{{ item }}</option>
<option v-for='item in branchsV2' :key='item'>{{ item }}</option>
</select>
</span>
<p>
<button @click='handleCheckout("v2")'>切换分支</button>
</p>
</span>
</div>
<div class='form-group__item'>
<span>刷新分支</span>
<p>刷新当前分支</p>
<span><button @click='handleFetch("v2")'>刷新</button></span>
</div>
</div>
......@@ -59,14 +38,11 @@
<select v-model='form.targetBranchV1'>
<option v-for='item in branchsV1' :key='item'>{{ item }}</option>
</select>
</span>
<p>
<button @click='handleCheckout("v1")'>切换分支</button>
</p>
</span>
</div>
<div class='form-group__item'>
<span>刷新分支</span>
<p>刷新当前分支</p>
<span><button @click='handleFetch("v1")'>刷新</button></span>
</div>
</div>
......@@ -78,6 +54,7 @@
</template>
<script lang="ts" setup>
import { useUserStore } from '~/store/user';
const form = ref({
email: '',
......@@ -86,86 +63,46 @@ const form = ref({
targetBranchV2: '',
targetBranchV1: ''
})
const branchs = ref([])
const branchsV2 = ref([])
const branchsV1 = ref([])
onMounted(() => {
onMounted(async () => {
getUserInfo()
getCurrentBranchV2()
getCurrentBranchV1()
getAllBranchV2()
getAllBranchV1()
getAllBranch('v1')
getAllBranch('v2')
})
function getUserInfo() {
$fetch('/api/user/getProjectInfo').then((res: any) => {
form.value.email = res.username + '@greaconsulting.com'
console.log(form)
})
}
function getAllBranchV2() {
return $fetch('/api/git/getAllBranchs', { query: { platform: 'v2' } }).then((res: any) => {
branchs.value = res.split('\n').map((o: string) => o.trim()).filter((o: string) => !!o)
})
}
function getAllBranchV1() {
return $fetch('/api/git/getAllBranchs', { query: { platform: 'v1' } }).then((res: any) => {
branchsV1.value = res.split('\n').map((o: string) => o.trim()).filter((o: string) => !!o)
})
}
function getCurrentBranchV2() {
return $fetch('/api/git/getCurrentBranch', { query: { platform: 'v2' } }).then((res: any) => {
form.value.currentBranchV2 = res.trim()
form.value.targetBranchV2 = form.value.currentBranchV2
})
form.value.email = useUserStore().username + '@greaconsulting.com'
form.value.currentBranchV1 = useUserStore().branchV1
form.value.currentBranchV2 = useUserStore().branchV2
form.value.targetBranchV1 = form.value.currentBranchV1
form.value.targetBranchV2 = form.value.currentBranchV2
}
function getCurrentBranchV1() {
return $fetch('/api/git/getCurrentBranch', { query: { platform: 'v1' } }).then((res: any) => {
form.value.currentBranchV1 = res.trim()
form.value.targetBranchV1 = form.value.currentBranchV1
})
}
function handleGenerate() {
$fetch('/api/git/generateSsh', { method: 'post', body: { email: form.value.email } }).then(res => {
if (res) {
const input = document.createElement('input')
input.value = res
document.body.appendChild(input)
input.select()
document.execCommand('copy')
alert('已拷贝 SSH Key, 请前往 Gitlab 更新个人 SSH Key 配置')
document.body.removeChild(input)
function getAllBranch(platform: 'v1' | 'v2') {
return $fetch('/api/git/getAllBranchs', { query: { platform } }).then((res: any) => {
if (platform === 'v1') {
branchsV1.value = res.split('\n').map((o: string) => o.trim()).filter((o: string) => !!o)
} else {
branchsV2.value = res.split('\n').map((o: string) => o.trim()).filter((o: string) => !!o)
}
})
}
async function handleFetch(platform: 'v1' | 'v2') {
const branch = platform === 'v2' ? form.value.currentBranchV2 : form.value.currentBranchV1
if (!branch) return
await $fetch('/api/git/fetch', { method: 'post', body: { branch, platform }})
if (platform === 'v1') {
await getCurrentBranchV1()
await getAllBranchV1()
} else {
await getCurrentBranchV2()
await getAllBranchV2()
}
alert('刷新分支完成,请重新编译运行')
await getAllBranch(platform)
}
async function handleCheckout(platform: 'v1' | 'v2') {
try {
const branch = platform === 'v1' ? form.value.targetBranchV1 : form.value.targetBranchV2
await $fetch('/api/git/checkout', { method: 'post', body: { platform, branch } })
if (platform === 'v1') {
await getCurrentBranchV1()
form.value.currentBranchV1 = form.value.targetBranchV1
} else {
await getCurrentBranchV2()
form.value.currentBranchV2 = form.value.targetBranchV2
}
alert('切换分支完成,请重新编译运行')
// 后端更新完毕
} catch (err) {
console.log(err)
const branch = platform === 'v1' ? form.value.targetBranchV1 : form.value.targetBranchV2
await $fetch('/api/git/checkout', { method: 'post', body: { platform, branch } })
if (platform === 'v1') {
form.value.currentBranchV1 = form.value.targetBranchV1
} else {
form.value.currentBranchV2 = form.value.targetBranchV2
}
alert('切换分支完成,请重新编译运行')
}
</script>
......@@ -176,4 +113,8 @@ async function handleCheckout(platform: 'v1' | 'v2') {
height: 100%;
padding: 24px;
}
.content select{
width: 200px;
margin-right: 10px;
}
</style>
\ No newline at end of file
......@@ -8,79 +8,6 @@
</template>
<script lang="ts" setup>
import { useUserStore } from '~/store/user';
const username = ref('')
const status = ref('null') // null | created | stopped | running | creating | compiling
const statusV1 = ref('null')
const loading = ref(false)
const logLevel = ref('progress') // info | progress
const logs = ref([] as string[])
const port = ref(0)
onMounted(async () => {
await getUserInfomation()
})
async function getUserInfomation() {
const res = await $fetch('/api/user/getProjectInfo')
if (res) {
useUserStore().setUserConfig(res.username, { port: res["port"] })
}
}
function handleInstallV1() {
if (loading.value) return
logs.value = []
loading.value = true
statusV1.value = 'creating'
$fetch('/api/devops/v1/install', { method: 'post' })
.then(getUserInfomation, getUserInfomation)
.finally(() => {
loading.value = false
})
}
function handleCompileV1() {
if (loading.value) return
loading.value = true
logs.value = []
resetV2()
$fetch('/api/devops/v1/compile', { method: 'post'}).then(() => {
return getUserInfomation()
}).finally(() => {
loading.value = false
})
}
function handleExecuteV1() {
if (loading.value) return
loading.value = true
logs.value = []
resetV2()
$fetch('/api/devops/v1/execute', { method: 'post'}).then(() => {
return getUserInfomation()
}).finally(() => {
loading.value = false
})
}
function handleStopV1() {
if (loading.value) return
logs.value = []
loading.value = true
$fetch('/api/devops/v1/stop', { method: 'post'}).then(() => {
return getUserInfomation()
}).finally(() => {
loading.value = false
})
}
function handleOpenVscodeV1() {
window.open(window.location.protocol + '//' + window.location.hostname + ':' + port + '/vscode?folder=/var/logwire-platform', '_blank')
}
function resetV1() {
statusV1.value = 'created'
}
function resetV2() {
status.value = 'created'
}
</script>
<style scoped>
......
......@@ -32,13 +32,11 @@ function handleLogin () {
$fetch('/api/user/login', {
method: 'post',
body: { username: username.value }
}).then((value) => {
if (value) {
userStore.setUserConfig(username.value, { port: value["port"] })
navigateTo('/home')
} else {
navigateTo('/prepare')
}
}).then(value => {
userStore.setUserName({ username: value!.username })
userStore.setPort({ port: value!.port })
setWebSocket(username.value, true)
navigateTo('/home')
})
}
</script>
......
<template>
<div class="prepare">
<span>准备数据库服务中......</span>
</div>
</template>
<script setup lang="ts">
import { useUserStore } from '~/store/user';
const { data } = useLazyFetch('/api/user/prepare', { method: 'post' })
watch(data, function (value) {
if (value) {
useUserStore().setUserConfig(value.username, { port: value['port'] })
navigateTo('/home')
}
})
</script>
<style scoped>
.prepare{
height: 100vh;
width: 100vw;
text-align: center;
line-height: 100vh;
}
span{
font-weight: bold;
}
</style>
\ No newline at end of file
......@@ -5,8 +5,9 @@ export default defineEventHandler(async (event) => {
let username = event.context.username
try {
let docker = createDockerFactory(username)
LogUtil.clear(username)
setPgTableData( 'v1', username, 'status', 'compiling')
await changeProjectStatus( 'v1', username, 'status', 'compiling')
// 每次编译前把已有的 tenants_config 文件夹拷贝到一个地方,编译完成后,再拷贝回来
let container = await docker.checkContainer( username + '.node')
......@@ -37,9 +38,9 @@ export default defineEventHandler(async (event) => {
await docker.execContainerCommand({ container, cmd: 'rm ../tenants.tar.gz', dir: '/var/logwire-platform/dist'})
await copyAndCreateServerPropertiesV1InDocker(username)
LogUtil.printInfo(username, '编译完成')
await setPgTableData( 'v1', username, 'status', 'compiled')
await changeProjectStatus( 'v1', username, 'status', 'compiled')
} catch (err) {
await setPgTableData( 'v1', username, 'status', 'created')
await changeProjectStatus( 'v1', username, 'status', 'created')
LogUtil.printError(username, err instanceof Error ? err.message : JSON.stringify(err))
setResponseStatus(event, 500)
return err
......
import LogUtil from "~/server/utils/log"
export default defineEventHandler(async (event) => {
let username = event.context.username
let username = event.context.username
try {
LogUtil.clear(username)
let docker = createDockerFactory(username)
let container = await docker.checkContainer( username + '.node')
const row = await getPgTableData( 'user', username)
const port = row?.["port"]
LogUtil.printInfo(username, '程序启动中')
await changeProjectStatus( 'v1', username, 'status', 'running')
if (!container) {
throw new Error('没有创建容器,请先初始化容器')
}
......@@ -22,6 +25,10 @@ export default defineEventHandler(async (event) => {
LogUtil.print(username, `[progress] [[1;34mInfo[m] 程序运行中...... \n`)
LogUtil.print(username, `[progress] [[1;34mInfo[m] 请代理后端请求到 <strong>${HOST}:${port}</strong> 上 \n`)
await setPgTableData( 'v1', username, 'status', 'running')
await changeProjectStatus( 'v1', username, 'status', 'launched')
} catch (err) {
await changeProjectStatus( 'v2', username, 'status', 'compiled')
LogUtil.print(username, '[error] [[1;31mError[m]] ' + (err instanceof Error ? err.message : JSON.stringify(err)))
setResponseStatus(event, 500)
}
})
\ No newline at end of file
......@@ -6,6 +6,7 @@ export default defineEventHandler(async (event) => {
let username = event.context.username
let pgClient = await createPgClientFactory(username)
try {
LogUtil.clear(username)
let docker = createDockerFactory(username)
const rowV2 = await getPgTableData( 'v2', username)
......@@ -14,7 +15,7 @@ export default defineEventHandler(async (event) => {
}
let rowV1 = await getPgTableData('v1', username)
if (!rowV1) await insertPgTableData('v1', username)
await setPgTableData( 'v1', username, 'status', 'creating')
await changeProjectStatus( 'v1', username, 'status', 'creating')
let container = await docker.checkContainer( username + '.node') as Dockerode.Container
if (!container) {
throw new Error('没有创建容器,请先初始化容器')
......@@ -62,11 +63,11 @@ export default defineEventHandler(async (event) => {
await docker.execContainerCommand({ container, cmd: 'tar -zvxf book.tar -C /var/logwire-platform/dist/projects/demo', dir: '/var/logwire-demo'})
})
await setPgTableData( 'v1', username, 'status', 'created')
await changeProjectStatus( 'v1', username, 'status', 'created')
await stopPgClient(pgClient)
LogUtil.printSuccess(username, 'installed')
} catch (err: any) {
await setPgTableData( 'v1', username, 'status', 'null')
await changeProjectStatus( 'v1', username, 'status', 'null')
await stopPgClient(pgClient)
LogUtil.printError(username, (err instanceof Error ? err.message : JSON.stringify(err)))
setResponseStatus(event, 500)
......
......@@ -2,6 +2,7 @@ import LogUtil from "~/server/utils/log"
export default defineEventHandler(async (event) => {
let username = event.context.username
LogUtil.clear(username)
let docker = createDockerFactory(username)
let container = await docker.checkContainer( username + '.node')
if (!container) {
......@@ -10,5 +11,5 @@ export default defineEventHandler(async (event) => {
LogUtil.printInfo(username, `程序停止中......`)
await docker.execContainerCommand({ container, cmd: 'pm2 delete platform', quiet: true })
LogUtil.printInfo(username, `程序已停止`)
await setPgTableData( 'v1', username, 'status', 'compiled')
await changeProjectStatus( 'v1', username, 'status', 'compiled')
})
\ No newline at end of file
......@@ -5,9 +5,10 @@ export default defineEventHandler(async (event) => {
let username = event.context.username
try {
let username = event.context.username
LogUtil.clear(username)
let docker = createDockerFactory(username)
await setPgTableData( 'v2', username, 'status', 'compiling')
await changeProjectStatus( 'v2', username, 'status', 'compiling')
// TODO: 在后端发送 websocket 通知前端状态变更
// 每次编译前把已有的 tenants_config 文件夹拷贝到一个地方,编译完成后,再拷贝回来
......@@ -36,9 +37,9 @@ export default defineEventHandler(async (event) => {
copyAndCreateGatewayPropertiesV2InDocker(username)
LogUtil.print(username, `[progress] [[1;34mInfo[m] 编译完成 \n`)
await setPgTableData( 'v2', username, 'status', 'compiled')
await changeProjectStatus( 'v2', username, 'status', 'compiled')
} catch (err) {
await setPgTableData( 'v2', username, 'status', 'created')
await changeProjectStatus( 'v2', username, 'status', 'created')
LogUtil.print(username, '[error] [[1;31mError[m]] ' + (err instanceof Error ? err.message : JSON.stringify(err)))
setResponseStatus(event, 500)
}
......
......@@ -3,17 +3,17 @@ import LogUtil from "~/server/utils/log"
export default defineEventHandler(async (event) => {
// 先判断服务是否启动,启动则关闭,然后调用新的命令启动 java 端
let username = event.context.username
LogUtil.clear(username)
let docker = createDockerFactory(username)
let container = await docker.checkContainer( username + '.node')
if (!container) {
throw new Error('没有创建容器,请先初始化容器')
}
const rowV2 = await getPgTableData( 'v2', username)
const status = rowV2?.status
const tenants = rowV2?.tenants
const tenants = rowV2!.tenants
const rowUser = await getPgTableData( 'user', username)
const port = rowUser?.["port"]
const debug = rowV2?.debug
const port = rowUser!.port
const debug = rowV2!.debug
// 有可能本身就关闭了
try {
......@@ -63,5 +63,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] 调试程序已启动,请IP地址为 <strong>${debug?.host}</strong> 后端访问 <strong>${HOST}:${port}</strong> 进行调试\n`)
await setPgTableData( 'v2', username, 'status', 'running')
await changeProjectStatus( 'v2', username, 'status', 'running')
})
\ No newline at end of file
......@@ -2,25 +2,18 @@ import LogUtil from "~/server/utils/log"
export default defineEventHandler(async (event) => {
let username = event.context.username
let pgClient = await createPgClientFactory(username)
try {
let username = event.context.username
let docker = createDockerFactory(username)
// 创建 node 容器
let container = await docker.checkContainer( username + '.node')
let row = await getPgTableData( 'user', username)
let port = row?.["port"]
if (container) {
LogUtil.print(username, `[progress] [[1;34mInfo[m] 打包微信小程序zip \n`)
await docker.execContainerCommand({ container, cmd: 'rm -f weapp.zip', dir: '/var/logwire-backend/build-output/backend' })
await docker.execContainerCommand({ container, cmd: `zip -q -r weapp.zip miniapp/main/dist miniapp/main/src/pages miniapp/main/src/app.config.ts`, dir: '/var/logwire-backend/build-output/backend' })
LogUtil.print(username, `[progress] [[1;34mInfo[m] 打包结束,访问 <a target="_blank" href="http://192.168.0.4:${port}/download/backend/">http://192.168.0.4:${port}/download/backend/</a> 下载 webapp.zip 文件 \n`)
} else {
throw new Error('没有创建容器,请先初始化容器')
}
} catch (err) {
await stopPgClient(pgClient)
setResponseStatus(event, 500)
return err
LogUtil.clear(username)
let docker = createDockerFactory(username)
// 创建 node 容器
let container = await docker.checkContainer( username + '.node')
let row = await getPgTableData( 'user', username)
let port = row?.["port"]
if (container) {
LogUtil.print(username, `[progress] [[1;34mInfo[m] 打包微信小程序zip \n`)
await docker.execContainerCommand({ container, cmd: 'rm -f weapp.zip', dir: '/var/logwire-backend/build-output/backend' })
await docker.execContainerCommand({ container, cmd: `zip -q -r weapp.zip miniapp/main/dist miniapp/main/src/pages miniapp/main/src/app.config.ts`, dir: '/var/logwire-backend/build-output/backend' })
LogUtil.print(username, `[progress] [[1;34mInfo[m] 打包结束,访问 <a target="_blank" href="http://192.168.0.4:${port}/download/backend/">http://192.168.0.4:${port}/download/backend/</a> 下载 webapp.zip 文件 \n`)
} else {
throw new Error('没有创建容器,请先初始化容器')
}
})
\ No newline at end of file
......@@ -4,6 +4,7 @@ export default defineEventHandler(async (event) => {
let username = event.context.username
try {
let username = event.context.username
LogUtil.clear(username)
let docker = createDockerFactory(username)
let container = await docker.checkContainer( username + '.node')
let rowUser = await getPgTableData( 'user', username)
......@@ -12,6 +13,7 @@ export default defineEventHandler(async (event) => {
let port = rowUser?.["port"]
LogUtil.printInfo(username, `程序初始化中......`)
await changeProjectStatus( 'v2', username, 'status', 'running')
if (!container) {
throw new Error('没有创建容器,请先初始化容器')
}
......@@ -32,8 +34,9 @@ export default defineEventHandler(async (event) => {
LogUtil.printInfo(username, `请代理后端请求到 <strong>${HOST}:${port}</strong> 上`)
LogUtil.printInfo(username, `请设置开发环境域名和端口号 <strong>${tenants?.host}</strong> 上`)
await setPgTableData( 'v2', username, 'status', 'running')
await changeProjectStatus( 'v2', username, 'status', 'launched')
} catch (err) {
await changeProjectStatus( 'v2', username, 'status', 'compiled')
LogUtil.printError(username, (err instanceof Error ? err.message : JSON.stringify(err)))
setResponseStatus(event, 500)
return err
......
import Dockerode from "dockerode"
import LogUtil from "~/server/utils/log"
import LogUtil, { sendProjectStatus } from "~/server/utils/log"
import fs from 'fs'
import path from 'path'
import { changeProjectStatus } from "~/server/utils/postgres"
export default defineEventHandler(async (event) => {
let username = event.context.username
let pgClient = await createPgClientFactory('backend_helper')
try {
LogUtil.clear(username)
let docker = createDockerFactory(username)
let host = docker.host
let container: Dockerode.Container = {} as Dockerode.Container
const port = (await getPgTableData( 'user', username))?.port
const row = await getPgTableData('v2', username)
if (!row) await insertPgTableData('v2', username)
await setPgTableData( 'v2', username, 'status', 'creating')
await changeProjectStatus( 'v2', username, 'status', 'creating')
// 必须要保证创建容器是首先执行
// node 容器根据 dev/prod 环境与否,决定在哪里创建,远程容器还是本机容器
await LogUtil.run(username, '创建 node 容器', async () => {
......@@ -186,11 +188,11 @@ export default defineEventHandler(async (event) => {
}
await setPgTableData('v2', username, 'debug', JSON.stringify(debug))
})
await setPgTableData( 'v2', username, 'status', 'created')
await changeProjectStatus( 'v2', username, 'status', 'created')
await stopPgClient(pgClient)
LogUtil.printSuccess(username, '安装成功')
} catch (err: any) {
await setPgTableData( 'v2', username, 'status', 'null')
await changeProjectStatus( 'v2', username, 'status', 'null')
await stopPgClient(pgClient)
LogUtil.printError(username, (err instanceof Error ? err.message : JSON.stringify(err)))
setResponseStatus(event, 500)
......
......@@ -2,6 +2,7 @@ import LogUtil from "~/server/utils/log"
export default defineEventHandler(async (event) => {
let username = event.context.username
LogUtil.clear(username)
let docker = createDockerFactory(username)
let container = await docker.checkContainer( username + '.node')
if (!container) {
......@@ -12,5 +13,5 @@ export default defineEventHandler(async (event) => {
await docker.execContainerCommand({ container, cmd: 'pm2 delete gateway', quiet: true })
LogUtil.print(username, `程序已停止`)
await setPgTableData( 'v2', username, 'status', 'compiled')
await changeProjectStatus( 'v2', username, 'status', 'compiled')
})
\ No newline at end of file
export default defineEventHandler(async (event) => {
const username = event.context.username
let client = await createPgClientFactory('backend_helper')
let result = await getPgTableData( 'user', username)
return result
})
\ No newline at end of file
import { PgPort } from "~/server/utils/postgres"
import { TableUser } from "~/server/utils/postgres"
import { SESSION_PASSWORD } from "../../utils"
export default defineEventHandler(async (event) => {
try {
const body = await readBody(event)
const username = body.username
const session = await useSession(event, { password: SESSION_PASSWORD })
await session.update({ username })
// 生产环境要求必须是先创建好服务器,再启动服务
if (process.env.NODE_ENV === 'development') {
return false
} else {
let result = await getPgTableData('user', username)
return result
}
} catch (err) {
throw createError({
statusCode: 500,
statusMessage: '登录失败'
})
const body = await readBody(event)
const username = body.username
const session = await useSession(event, { password: SESSION_PASSWORD })
await session.update({ username })
let user = await getPgTableData('user', username)
if (!user) {
const port = await getAvailableNodePort(HOST)
await insertPgTableData('user', username)
await setPgTableData('user', username, 'port', port)
user = await getPgTableData('user', username)
}
return user
})
\ No newline at end of file
import fs from 'fs'
import path from 'path'
export default defineEventHandler(async (event) => {
let username = event.context.username
let docker = createDockerFactory(username)
export default defineNitroPlugin(async (nitroApp) => {
let docker = createDockerFactory('ADMIN')
let postgres = await docker.checkContainer('postgres_12')
if (!postgres) {
postgres = await docker.checkAndCreateContainer({ name: 'postgres_12', img: 'postgres:12', env: ["POSTGRES_PASSWORD=postgres"], portBindings: { '5432/tcp': [{ HostPort: PgPort.toString() }] } })
......@@ -13,25 +12,16 @@ export default defineEventHandler(async (event) => {
await docker.startContainer({ container: postgres })
await sleep(3000)
}
let client = await createPgClientFactory()
let result = await executePgQuery({ client, query: "SELECT u.datname FROM pg_catalog.pg_database u where u.datname='backend_helper';" })
if (result.rows.length === 0) {
await executePgQuery({ client, query: 'CREATE DATABASE backend_helper'})
await executePgQuery({ client, query: fs.readFileSync(path.resolve('./public/files/postgres/create_backend_helper.sql'), { encoding: 'utf-8'})})
await client.end()
client = await createPgClientFactory('backend_helper')
const sqlCreateUser = fs
await executePgQuery({ client, query: fs.readFileSync(path.resolve('./public/files/postgres/create_user.sql'), { encoding: 'utf-8' })})
await executePgQuery({ client, query: fs.readFileSync(path.resolve('./public/files/postgres/create_v2.sql'), { encoding: 'utf-8' })})
await executePgQuery({ client, query: fs.readFileSync(path.resolve('./public/files/postgres/create_v1.sql'), { encoding: 'utf-8'})})
} else {
client = await createPgClientFactory('backend_helper')
}
let user = await getPgTableData('user', username)
if (result.rowCount === 0) {
const port = await getAvailableNodePort(HOST)
await executePgQuery({ client, query: `INSERT INTO public."user"(username, port) VALUES ('${username}', '${port}');`})
user = await getPgTableData('user', username)
await client.end()
}
return user
})
\ No newline at end of file
......@@ -12,7 +12,6 @@ export default defineNitroPlugin((nitroApp: NitroApp) => {
io.on("connection", (socket: any) => {
let username = socket.handshake.auth['username']
console.log('connected success!', username)
setWebsocketIo(username, socket)
});
......
declare module global {
namespace NodeJS {
interface ProcessEnv {
HOST: string
DEVHOST: string
NODE_ENV: string
PGUSER: string
postgres: string
......
import fs from 'fs'
export const HOST = process.env.NODE_ENV === 'production' ? '192.168.0.4' : (process.env.HOST || '192.168.0.190')
export const HOST = process.env.NODE_ENV === 'production' ? '192.168.0.4' : (process.env.DEVHOST || '192.168.0.190')
export function readJson(path: string): Record<string, any> {
try {
......
......@@ -13,6 +13,12 @@ export function getWebsocketIo (username: string) {
return websocket.get(username) as Socket
}
export function sendProjectStatus (platform: 'v1' | 'v2', username: string, status: string) {
const eventName = platform === 'v1' ? 'ChangeV1Status' : 'ChangeV2Status'
const socket = getWebsocketIo(username)
socket.emit(eventName, status)
}
export default class LogUtil {
// 根据 log 判断用户是否已经执行过
static async run (username: string, log: string, cb: () => Promise<void>) {
......@@ -40,4 +46,8 @@ export default class LogUtil {
static async printWarning (username: string, log: string) {
}
static clear (username: string) {
let socket = getWebsocketIo(username)
socket.emit('ClearLog')
}
}
import pg from 'pg'
import { sendProjectStatus } from './log'
export const PgPort = process.env.NODE_ENV?.trim() === 'production' ? 25556 : 30001
export const PgHost = process.env.NODE_ENV?.trim() === 'production' ? '192.168.0.4' : process.env.HOST
export const PgHost = process.env.NODE_ENV?.trim() === 'production' ? '192.168.0.4' : process.env.DEVHOST
let pool: pg.Pool = new pg.Pool({
host: PgHost,
......@@ -41,7 +42,7 @@ export type TableUser = { username: string, port: number }
export type TableV2 = {
username: string
status: 'null' | 'created' | 'stopped' | 'running' | 'creating' | 'compiling' | 'compiled'
status: 'null' | 'created' | 'stopped' | 'running' | 'launched' | 'creating' | 'compiling' | 'compiled'
tenants: Record<string, any>
debug: Record<string, any>
has_debugged: boolean
......@@ -50,7 +51,7 @@ export type TableV2 = {
export type TableV1 = {
username: string
status: 'null' | 'created' | 'stopped' | 'running' | 'creating' | 'compiling' | 'compiled'
status: 'null' | 'created' | 'stopped' | 'running' | 'launched' | 'creating' | 'compiling' | 'compiled'
serverProperties: { id: any, key: string, value: string }[]
}
......@@ -65,7 +66,7 @@ export async function getPgTableData (table: string, username: string) {
export async function setPgTableData (table: 'user', username: string, key: keyof TableUser, value: TableUser[keyof TableUser]): Promise<void>;
export async function setPgTableData (table: 'v2', username: string, key: keyof TableV2, value: TableV2[keyof TableV2]): Promise<void>;
export async function setPgTableData (table: 'v1', username: string, key: keyof TableV1, value: TableV1[keyof TableV1]): Promise<void>;
export async function setPgTableData (table: string, username: string, key: string, value: any) {
export async function setPgTableData (table: 'v1' | 'v2' | 'user', username: string, key: string, value: any) {
await pool.query(`UPDATE public.${table} SET "${key}"='${value}' WHERE username='${username}'`)
}
......@@ -76,3 +77,10 @@ export async function insertPgTableData (table: string, username: string) {
await pool.query(`INSERT INTO public."${table}"(username) VALUES ('${username}');`)
}
export async function changeProjectStatus (table: 'v2', username: string, key: keyof TableV2, value: TableV2[keyof TableV2]): Promise<void>;
export async function changeProjectStatus (table: 'v1', username: string, key: keyof TableV1, value: TableV1[keyof TableV1]): Promise<void>;
export async function changeProjectStatus (table: string, username: string, key: string, value: any) {
await setPgTableData(table as any, username, key as any, value)
sendProjectStatus(table as any, username, value)
}
......@@ -2,15 +2,22 @@ import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', () => {
const username = ref('')
const config = ref<{ port?: string }>({})
const port = ref(0)
const branchV1 = ref('')
const branchV2 = ref('')
function setUserName (name: string, p?: string) {
username.value = name
function setUserName (payload: { username: string }) {
username.value = payload.username
}
function setUserConfig (name: string, obj: Object) {
config.value = obj
username.value = name
function setPort (payload: { port: number }) {
port.value = payload.port
}
function setBranchV1 (payload: { branchV1: string }) {
branchV1.value = payload.branchV1
}
function setBranchV2 (payload: { branchV2: string }) {
branchV2.value = payload.branchV2
}
return { username, config, setUserName, setUserConfig }
return { username, port, branchV1, branchV2, setUserName, setPort , setBranchV1, setBranchV2 }
})
\ No newline at end of file
import { io, Socket } from "socket.io-client";
let socket: Socket
export function setWebSocket (username: string, force?: boolean) {
if (!socket || force) {
socket = io({
path: '/socket.io',
auth: {
username
}
});
}
}
export function getWebSocket () {
return socket
}
\ No newline at end of file
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