Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nuxt-backend-helper
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
王曜嵚 Wang Yaoqin
nuxt-backend-helper
Commits
75221ace
Commit
75221ace
authored
May 06, 2024
by
王曜嵚 Wang Yaoqin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dev: 调试接口
parent
24900cd7
Changes
13
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
166 additions
and
50 deletions
+166
-50
ProjectV1.vue
components/ProjectV1.vue
+29
-9
ProjectV2.vue
components/ProjectV2.vue
+34
-11
compile.post.ts
server/api/devops/v1/compile.post.ts
+5
-1
execute.post.ts
server/api/devops/v1/execute.post.ts
+4
-0
install.post.ts
server/api/devops/v1/install.post.ts
+44
-16
stop.post.ts
server/api/devops/v1/stop.post.ts
+1
-0
compile.post.ts
server/api/devops/v2/compile.post.ts
+5
-0
debug.post.ts
server/api/devops/v2/debug.post.ts
+6
-1
execute.post.ts
server/api/devops/v2/execute.post.ts
+4
-0
install.post.ts
server/api/devops/v2/install.post.ts
+17
-8
stop.post.ts
server/api/devops/v2/stop.post.ts
+1
-0
log.ts
server/utils/log.ts
+14
-2
postgres.ts
server/utils/postgres.ts
+2
-2
No files found.
components/ProjectV1.vue
View file @
75221ace
...
@@ -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
;
...
...
components/ProjectV2.vue
View file @
75221ace
...
@@ -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
;
...
...
server/api/devops/v1/compile.post.ts
View file @
75221ace
...
@@ -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'
)
...
...
server/api/devops/v1/execute.post.ts
View file @
75221ace
...
@@ -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
(
'没有创建容器,请先初始化容器'
)
}
}
...
...
server/api/devops/v1/install.post.ts
View file @
75221ace
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
...
...
server/api/devops/v1/stop.post.ts
View file @
75221ace
...
@@ -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'
)
...
...
server/api/devops/v2/compile.post.ts
View file @
75221ace
...
@@ -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 文件夹拷贝到一个地方,编译完成后,再拷贝回来
...
...
server/api/devops/v2/debug.post.ts
View file @
75221ace
...
@@ -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
server/api/devops/v2/execute.post.ts
View file @
75221ace
...
@@ -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
(
'没有创建容器,请先初始化容器'
)
}
}
...
...
server/api/devops/v2/install.post.ts
View file @
75221ace
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
...
...
server/api/devops/v2/stop.post.ts
View file @
75221ace
...
@@ -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
,
`程序已停止`
)
...
...
server/utils/log.ts
View file @
75221ace
...
@@ -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
))
}
}
}
server/utils/postgres.ts
View file @
75221ace
...
@@ -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
}[]
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment