diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000..99a8c7683a
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,207 @@
+### Maven template
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+# https://github.com/takari/maven-wrapper#usage-without-binary-jar
+.mvn/wrapper/maven-wrapper.jar
+
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+### Node template
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+web_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+#.env
+#.env.test
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+out
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and not Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+# yarn v2
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
+.git
+modules/server/logs
+modules/agent/logs
diff --git a/.editorconfig b/.editorconfig
index e64c56b7b9..fffe95ac2f 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,3 +1,13 @@
+#
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+#
+
# http://editorconfig.org
root = true
@@ -10,17 +20,35 @@ trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 200
-[*.{json, yml}]
+[*.{json,yml}]
indent_style = space
indent_size = 2
+max_line_length = off
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
+max_line_length = off
+indent_style = space
+indent_size = 2
[*.bat]
end_of_line = crlf
-[*.vue]
+[*.sh]
+end_of_line = lf
+indent_style = space
+indent_size = 2
+max_line_length = off
+
+[*.{vue,js,ts}]
+indent_style = space
+indent_size = 2
+
+[*.ts]
indent_style = space
indent_size = 2
+
+[*.{java,xml,sql}]
+indent_style = space
+indent_size = 4
diff --git a/.env b/.env
new file mode 100644
index 0000000000..91dc2b61ce
--- /dev/null
+++ b/.env
@@ -0,0 +1,3 @@
+JPOM_VERSION=2.11.6
+# Server Token 生产部署请更换
+SERVER_TOKEN=7094f673-2c53-4fc1-82e7-86e528449d97
diff --git a/.gitee/ISSUE_TEMPLATE/bug.yml b/.gitee/ISSUE_TEMPLATE/bug.yml
new file mode 100644
index 0000000000..16fd364408
--- /dev/null
+++ b/.gitee/ISSUE_TEMPLATE/bug.yml
@@ -0,0 +1,75 @@
+#
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+#
+
+name: Bug 反馈
+description: 当你在使用中发现了一个 Bug,导致应用崩溃或抛出异常,或者有一个页面存在问题,或者某些地方看起来不对劲。
+title: "[Bug]: "
+labels: ["bug"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ 感谢对项目的支持与关注。在提出问题之前,请确保你已查看相关使用文档、常见问题、实践案例:
+ - https://jpom.top
+ - type: checkboxes
+ attributes:
+ label: 这个问题是否已经存在?
+ options:
+ - label: 我已经搜索过现有的问题 (https://gitee.com/dromara/Jpom/issues)
+ required: true
+ - type: input
+ id: jpom_version
+ attributes:
+ label: Jpom 版本
+ description: 你当前正在使用我们软件的哪个版本
+ validations:
+ required: true
+ - type: input
+ id: jdk_version
+ attributes:
+ label: JDK 版本
+ description: 你当前正在使用JDK的哪个版本
+ validations:
+ required: true
+ - type: input
+ id: os_version
+ attributes:
+ label: 操作系统版本
+ description: 你当前正在使用系统类型以及哪个版本
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: 如何复现
+ description: 请详细告诉我们如何复现你遇到的问题,并使用反引号```附上它
+ placeholder: |
+ 1. ...
+ 2. ...
+ 3. ...
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: 预期结果
+ description: 请告诉我们你预期会发生什么。
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: 实际结果
+ description: 请告诉我们实际发生了什么。
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: 截图或视频
+ description: 如果可以的话,上传任何关于 bug 的截图。
+ value: |
+ [在这里上传图片]
diff --git a/.gitee/ISSUE_TEMPLATE/config.yaml b/.gitee/ISSUE_TEMPLATE/config.yaml
new file mode 100644
index 0000000000..695b6e882b
--- /dev/null
+++ b/.gitee/ISSUE_TEMPLATE/config.yaml
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+#
+
+blank_issues_enabled: false
+contact_links:
+ - name: Jpom 官方文档
+ url: https://jpom.top/
+ about: 提供 Jpom 使用指南、教程、基本功能使用、介绍和常见问题解答
diff --git a/.gitee/ISSUE_TEMPLATE/feature.yml b/.gitee/ISSUE_TEMPLATE/feature.yml
new file mode 100644
index 0000000000..3ecb1d832d
--- /dev/null
+++ b/.gitee/ISSUE_TEMPLATE/feature.yml
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+#
+
+name: 功能建议
+description: 对本项目提出一个功能建议
+title: "[功能建议]: "
+labels: ["enhancement"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ 感谢提出功能建议,我们将仔细考虑!
+ - type: textarea
+ id: related-problem
+ attributes:
+ label: 你的功能建议是否和某个问题相关?
+ description: 清晰并简洁地描述问题是什么,例如,当我...时,我总是感到困扰。
+ validations:
+ required: false
+ - type: textarea
+ id: desired-solution
+ attributes:
+ label: 你希望看到什么解决方案?
+ description: 清晰并简洁地描述你希望发生的事情。
+ validations:
+ required: true
+ - type: textarea
+ id: alternatives
+ attributes:
+ label: 你考虑过哪些替代方案?
+ description: 清晰并简洁地描述你考虑过的任何替代解决方案或功能。
+ validations:
+ required: false
+ - type: textarea
+ id: additional-context
+ attributes:
+ label: 你有其他上下文或截图吗?
+ description: 在此处添加有关功能请求的任何其他上下文或截图。
+ validations:
+ required: false
+ - type: checkboxes
+ attributes:
+ label: 意向参与贡献
+ options:
+ - label: 我有意向参与具体功能的开发实现并将代码贡献回到上游社区
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000000..1637a6f7b9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,5 @@
+### 使用的JDK版本、Jpom版本、操作系统及系统版本
+
+### 问题描述(包括截图)
+
+### 报错信息
\ No newline at end of file
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000000..30da6a8be5
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,32 @@
+name: build
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+
+ build:
+
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ node-version: [ 18.x ]
+ # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
+ steps:
+ - uses: actions/checkout@v2
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v2
+ with:
+ node-version: ${{ matrix.node-version }}
+ - run: cd web-vue && npm i && npm run build
+ - name: Set up JDK 8
+ uses: actions/setup-java@v2
+ with:
+ java-version: '8'
+ distribution: 'temurin'
+ cache: maven
+ - name: Build with Maven
+ run: mvn -B package
diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml
new file mode 100644
index 0000000000..1e54b74087
--- /dev/null
+++ b/.github/workflows/codecov.yml
@@ -0,0 +1,23 @@
+name: codecov2
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK 8
+ uses: actions/setup-java@v2
+ with:
+ java-version: '8'
+ distribution: 'temurin'
+ cache: maven
+ - name: Build with Maven cobertura
+ run: mvn cobertura:cobertura -Pcobertura
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v2
\ No newline at end of file
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 0000000000..65f1d85fb0
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,70 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ master ]
+ schedule:
+ - cron: '23 6 * * 0'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'java', 'javascript' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
+ # Learn more about CodeQL language support at https://git.io/codeql-language-support
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v1
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v1
+
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 https://git.io/JvXDl
+
+ # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ #- run: |
+ # make bootstrap
+ # make release
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v1
diff --git a/.github/workflows/package-testing.bak-yml b/.github/workflows/package-testing.bak-yml
new file mode 100644
index 0000000000..ebb41d1625
--- /dev/null
+++ b/.github/workflows/package-testing.bak-yml
@@ -0,0 +1,43 @@
+name: Package Testing
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+
+ build:
+
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ node-version: [ 16.x ]
+ # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
+ steps:
+ - uses: actions/checkout@v2
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v2
+ with:
+ node-version: ${{ matrix.node-version }}
+ #cache: 'npm'
+ #cache-dependency-path: './web-vue/package-lock.json'
+ #- run: npm ci
+ # working-directory: './web-vue'
+ #- run: npm run build
+ # working-directory: './web-vue'
+ - run: cd web-vue && npm i && npm run build
+ - name: Set up JDK 8
+ uses: actions/setup-java@v2
+ with:
+ java-version: '8'
+ distribution: 'temurin'
+ cache: maven
+ - name: Build with Maven
+ run: mvn -B package
+ #file: ./zhuzhu-project/target/site/jacoco/jacoco.xml
+# run: |
+# docker buildx create --use
+# docker buildx build --platform linux/amd64,linux/arm64 -t jpomdocker/jpom:2.8.16 -f ./modules/server/DockerfileRelease --push .
+# docker buildx build --platform linux/amd64,linux/arm64 -t jpomdocker/jpom:latest -f ./modules/server/DockerfileRelease --push .
diff --git a/.gitignore b/.gitignore
index c94e2fa4b9..5b8bb87679 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,11 @@ target/
venv/
node_modules/
+# Jrebel
+rebel.xml
+
+#
+apidoc/
# dependencies
@@ -15,7 +20,7 @@ _roadhog-api-doc
# production
dist/
-/.vscode
+#/.vscode
# misc
.DS_Store
@@ -26,8 +31,10 @@ yarn-error.log
.idea
yarn.lock
package-lock.json
+pnpm-lock.yaml
*bak
-.vscode
+pom.xml.versionsBackup
+#.vscode
# visual studio code
.history
@@ -43,3 +50,6 @@ functions/*
screenshot
.firebase
.eslintcache
+
+web-vue/stats.html
+.baidubce.token
diff --git a/.workflow/MasterPipeline.yml b/.workflow/MasterPipeline.yml
index c008d7fc8b..1e3070d51e 100644
--- a/.workflow/MasterPipeline.yml
+++ b/.workflow/MasterPipeline.yml
@@ -1,56 +1,70 @@
+#
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+#
+
version: '1.0'
name: master-pipeline
displayName: MasterPipeline
+triggers:
+ trigger: manual
+ push:
+ branches:
+ precise:
+ - master
+ - dev
stages:
- - stage:
- name: compile
+ - name: compile
displayName: 编译
+ strategy: naturally
+ trigger: auto
steps:
- step: build@maven
name: build_maven
displayName: Maven 构建
- # 支持6、7、8、9、10、11六个版本
jdkVersion: 8
- # 支持2.2.1、3.2.5、3.3.9、3.5.2、3.5.3、3.5.4、3.6.1、3.6.3八个版本
mavenVersion: 3.6.3
- # 构建命令
commands:
- - mvn -B clean package -Dmaven.test.skip=true
- # 非必填字段,开启后表示将构建产物暂存,但不会上传到制品库中,7天后自动清除
+ - curl -LfsSo /opt/node-v18.19.0-linux-x64.tar.gz https://npmmirror.com/mirrors/node/v18.19.0/node-v18.19.0-linux-x64.tar.gz
+ - tar -zxf /opt/node-v18.19.0-linux-x64.tar.gz -C /opt/ && export PATH=/opt/node-v18.19.0-linux-x64/bin:$PATH
+ - npm config set registry https://registry.npmmirror.com/
+ - cd web-vue && npm install && npm run build
+ - cd ..
+ - mvn -B -e clean package -Dmaven.test.skip=true -Dmaven.compile.fork=true -s script/settings.xml
artifacts:
- # 构建产物名字,作为产物的唯一标识可向下传递,支持自定义,默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- - name: BUILD_ARTIFACT
- # 构建产物获取路径,是指代码编译完毕之后构建物的所在路径,如通常jar包在target目录下。当前目录为代码库根目录
+ - name: all_zip
+ path:
+ - modules/server/target/server-2.11.6-release.zip
+ - modules/agent/target/agent-2.11.6-release.zip
+ - name: server_zip
+ path:
+ - modules/server/target/server-2.11.6-release.zip
+ - name: agent_zip
path:
- - modules/server/target/*.zip
- - modules/agent/target/*.zip
+ - modules/agent/target/agent-2.11.6-release.zip
+ settings: []
+ strategy:
+ retry: '0'
+ - name: stage-0aa9dee2
+ displayName: 打包
+ strategy: naturally
+ trigger: auto
+ executor: []
+ steps:
- step: publish@general_artifacts
name: publish_general_artifacts
- displayName: 上传制品
- # 上游构建任务定义的产物名,默认BUILD_ARTIFACT
- dependArtifact: BUILD_ARTIFACT
- # 构建产物制品库,默认default,系统默认创建
- artifactRepository: default
- # 上传到制品库时的制品命名,默认build
- artifactName: jpom-server
- dependsOn: build_maven
-# - stage:
-# name: release
-# displayName: 发布
-# steps:
-# - step: publish@release_artifacts
-# name: publish_release_artifacts
-# displayName: '发布'
-# # 上游上传制品任务的产出
-# dependArtifact: jpom-server
-# # 发行版制品库,默认release,系统默认创建
-# artifactRepository: release
-# # 发布制品版本号
-# version: '1.0.0.0'
-# # 是否开启版本号自增,默认开启
-# autoIncrement: true
-triggers:
- push:
- branches:
- include:
- - master
+ displayName: 合并打包
+ dependArtifact: all_zip
+ artifactName: jpom-2.11.6
+ strategy:
+ retry: '0'
+strategy:
+ blocking: true
+permissions:
+ - role: admin
+ members: []
diff --git a/.workflow/docker-hub.yml b/.workflow/docker-hub.yml
new file mode 100644
index 0000000000..db05b17b0b
--- /dev/null
+++ b/.workflow/docker-hub.yml
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+#
+
+version: '1.0'
+name: pipeline-20220528
+displayName: docker-hub
+triggers:
+ trigger: manual
+ push:
+ branches:
+ precise:
+ - dev
+ tags:
+ prefix:
+ - v
+stages:
+ - name: stage-1b917201
+ displayName: 容器发布
+ strategy: naturally
+ trigger: auto
+ executor: []
+ steps:
+ - step: execute@docker
+ name: execute_by_docker
+ displayName: 基于镜像的脚本执行
+ image: hub.docker.com/bash:latest
+ command:
+ - echo 'success!'
+ - '# 服务端'
+ - docker buildx build --platform linux/amd64,linux/arm64 -t jpomdocker/jpom:2.8.22 -f ./modules/server/DockerfileRelease --push .
+ - '#'
+ - docker buildx build --platform linux/amd64,linux/arm64 -t jpomdocker/jpom:latest -f ./modules/server/DockerfileRelease --push .
+ strategy:
+ retry: '0'
+strategy:
+ blocking: true
+permissions:
+ - role: admin
+ members: []
diff --git a/.workflow/pipeline-opensca.yml b/.workflow/pipeline-opensca.yml
new file mode 100644
index 0000000000..84f86e1e1b
--- /dev/null
+++ b/.workflow/pipeline-opensca.yml
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+#
+
+version: '1.0'
+name: pipeline-20221101
+displayName: pipeline-20221101
+triggers:
+ trigger: auto
+ push:
+ branches:
+ prefix:
+ - ''
+stages:
+ - name: stage-98f2727d
+ displayName: 检测
+ strategy: naturally
+ trigger: auto
+ executor: []
+ steps:
+ - step: sc@opensca
+ name: open_sca
+ displayName: OpenSCA 开源组件检测
+ detectPath: ./
+ notify: []
+ strategy:
+ retry: '0'
diff --git a/CHANGELOG-BETA.md b/CHANGELOG-BETA.md
new file mode 100644
index 0000000000..f04c73a588
--- /dev/null
+++ b/CHANGELOG-BETA.md
@@ -0,0 +1,590 @@
+# 🚀 版本日志
+
+## 2.11.6.6-beta (2024-06-19)
+
+### 🐣 新增功能
+
+1. 【all】新增 国际化语言支持:繁體中文(中國香港)、繁體中文(中國臺灣)
+
+### ⚠️ 注意
+
+- 前端国际化翻译程度:98%
+- 后端已翻译语言可以度:95%(部分异步执行日志等目前未支持)
+
+------
+
+## 2.11.6.5-beta (2024-06-17)
+
+### 🐣 新增功能
+
+1. 【server】新增 服务端脚本、SSH 脚本支持引用全局脚本库(`G@("xx")` xx 为脚本标记)
+2. 【agent】新增 节点脚本支持引用全局脚本库(`G@("xx")` xx 为脚本标记)
+
+### 🐞 解决BUG、优化功能
+
+1. 【agent】修复 不同工作空间下同一个机器节点相同的项目ID的项目数据被覆盖(感谢@小朱)
+2. 【agent】优化 DSL 项目支持引用脚本库中的脚本(G@xxxx)xxxx 为脚本标记
+3. 【all】优化 新增系统语言配置 `jpom.system.lang`
+4. 【server】优化 前端紧凑模式在浅色模式下也生效
+
+### ⚠️ 注意
+
+- 前端国际化翻译程度:90%
+- 后端已翻译语言可以度:80%(部分异步执行日志等目前未支持)
+
+后端日志国际化需要新增或者修改 `jpom.system.lang` 配置项
+
+------
+
+## 2.11.6.4-beta (2024-06-14)
+
+### 🐣 新增功能
+
+1. 【all】新增 支持 i18n 语言国际化(zh-CN、en-US)
+
+### ⚠️ 注意
+
+#### 翻译进度
+
+- 前端国际化翻译程度:80%
+- 后端国际化翻译程度:90%
+
+#### 使用程度
+
+- 前端已翻译语言可以度:100%
+- 后端已翻译语言可以度:60%(后端日志、异步执行日志等目前未支持)
+
+### 🤝致谢
+
+感谢 [@a20070322](https://gitee.com/a20070322) / Controllers 大佬贡献 Jpom 前端 i18n 工具。
+
+------
+
+## 2.11.6.3-beta (2024-06-14)
+
+### 🐣 新增功能
+
+1. 【agent】新增 全局脚本库(DSL 项目可引用)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 gogs 仓库令牌导入异常(感谢@张飞鸿)
+2. 【server】修复 自定义仓库令牌导入后页面异常(感谢@张飞鸿)
+
+------
+
+## 2.11.6.2-beta (2024-06-06)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 没有端口的容器重建页面异常(感谢@冰淇淋还是冰激凌)
+2. 【server】修复 工作空间菜单配置错误(感谢@Again... .)
+3. 【server】优化 ssh 管理独立 tab 页面使用默认的字符串排序
+4. 【server】修复 服务端脚本无法执行、参数值描述不对应(感谢@冰淇淋还是冰激凌)
+
+------
+
+## 2.11.6.1-beta (2024-06-04)
+
+### 🐣 新增功能
+
+1. 【agent】新增 项目文件支持快捷复制到当前文件夹
+2. 【agent】新增 项目文件夹支持快捷压缩(感谢[@yiziyu](https://gitee.com/yiziyu) [Gitee issues I9737L](https://gitee.com/dromara/Jpom/issues/I9737L) )
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 部分参数、环境变量配置交互优化取消文本输入框采用标签模式(感谢@湘江夜色)
+2. 【server】修复 部分页面中文描述未正常显示
+3. 【server】优化 文件发布支持选择脚本模板(感谢[@linCodeTest](https://gitee.com/linWorld) [Gitee issues I9P0EU](https://gitee.com/dromara/Jpom/issues/I9P0EU) )
+4. 【server】优化 升级 postgresql 版本(感谢@ʟᴊx💎💎)
+5. 【server】修复 机器相关授权配置文件后缀输入框未正常显示(@感谢@ccx2480)
+
+------
+
+## 2.11.5.2-beta (2024-05-30)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 自动续签采用无感模式(感谢@湘江夜色)
+2. 【server】优化 容器构建执行配置自定义 host 参数(感谢@冰淇淋还是冰激凌)
+3. 【all】升级 tomcat、yaml 版本(感谢@佳驰)
+4. 【all】升级 bcprov-jdk18on 版本
+
+------
+
+## 2.11.5.1-beta (2024-04-30)
+
+### 🐣 新增功能
+
+1. 【agent】新增 项目支持配置禁止扫描目录避免大目录页面超时(感谢@我)
+
+------
+
+## 2.11.5.0-beta (2024-04-29)
+
+### 🐣 新增功能
+
+1. 【all】新增 自由脚本方便调试机器节点
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 资产管理 SSH 配置禁用命令无法回显(感谢@zhangw)
+2. 【server】修复 资产管理 SSH 未配置授权目录时 NPE (感谢[@Anley](https://gitee.com/MrAnley) [Gitee issues I9J17G](https://gitee.com/dromara/Jpom/issues/I9J17G) )
+3. 【agent】优化 监控机器网络流程支持配置排除网卡或者仅统计对应的网卡
+4. 【server】修复 退出登录时页面会提示需要登录相关信息
+5. 【server】优化 页面检测新版本判断是否加入 beta
+6. 【agent】优化 添加数据记录修改人(感谢[@陈旭](https://gitee.com/chenxu8989) [Gitee issues I9JSY7](https://gitee.com/dromara/Jpom/issues/I9JSY7) )
+7. 【server】优化 插件端注册到服务端,网络测试支持 ping + telnet (感谢@泊凉青川)
+
+------
+
+## 2.11.4.2-beta (2024-04-22)
+
+### 🐣 新增功能
+
+1. 【server】新增 发布系统公告
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】升级 前端组件版本
+2. 【all】优化 管理脚本删除 `-XX:-UseBiasedLocking` 使其能在高版本 jdk 运行
+3. 【server】修复 构建列表卡片模式按钮文字错乱
+4. 【server】修复 项目列表和逻辑节点卡片视图冲突
+5. 【server】修复 docker管理新增docker选择证书界面权重异常 (感谢[@伤感的风铃草](https://gitee.com/bwy-flc) [Gitee issues I9GYVA](https://gitee.com/dromara/Jpom/issues/I9GYVA) )
+6. 【server】修复 系统管理中用户管理中登录日志无法筛选
+7. 【server】优化 用户登录记录操作日志(保证操作监控能记录)
+8. 【server】修复 系统管理中用户登录日志无法分页
+9. 【server】优化 Oauth2 支持配置创建账号配置权限组
+10. 【server】修复 文件发布权限为执行权限、文件发布记录删除无记录日志 (感谢@蓝枫)
+
+------
+
+## 2.11.4.1-beta (2024-04-12)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 构建相关页面无法正常打开
+2. 【server】优化 Git 仓库地址不正确相关提示更准确(感谢@易自玉)
+
+------
+
+## 2.11.4.0-beta (2024-04-12)
+
+### 🐣 新增功能
+
+1. 【server】新增 Oauth2 新增【飞书账号】、【自建 Gitlab】登录(感谢[@鸡皮蒜毛与鸡毛蒜皮](https://gitee.com/cuia) [Gitee issues I9ELGS](https://gitee.com/dromara/Jpom/issues/I9ELGS) )
+2. 【server】新增 Oauth2 新增企业微信登录
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 oauth2 第三方平台登录解析用户名将依次尝试:平台用户名、邮箱、uuid
+2. 【server】修复 无法查询到分组信息(页面下拉框)(感谢[@Robot](https://gitee.com/robot1937) [Gitee issues I9FN9U](https://gitee.com/dromara/Jpom/issues/I9FN9U) )
+3. 【all】升级 hutool 版本
+4. 【server】修复 修复孤独数据描述错别字(感谢[@cuiyongsheng](https://github.com/Cuiys1458) [Github issues 77](https://github.com/dromara/Jpom/issues/77) )
+5. 【server】修复 前端地址栏输入二级路径 404 页面卡死问题
+
+------
+
+## 2.11.3.2-beta (2024-04-07)
+
+### 🐣 新增功能
+
+1. 【server】新增 Oauth2 新增钉钉扫码登录
+
+### 🐞 解决BUG、优化功能
+
+1. 【agent】优化 DSL 项目支持配置在特定目录执行脚本(run.execPath)
+2. 【agent】优化 管理脚本 -Xss 默认值修改为 512k(感谢@Again... )
+3. 【server】优化 管理脚本 -Xss 默认值修改为 1024k(感谢@Again... )
+4. 【server】优化 声明使用开源软件列表、增加本软件开源协议声明
+
+------
+
+## 2.11.3.1-beta (2024-04-02)
+
+### 🐣 新增功能
+
+1. 【server】新增 数据库支持 *mariadb*
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 无法查询到分组信息(页面下拉框)(感谢@猫猫向钱跑)
+2. 【server】修复 【项目文件管理远程下载】、【镜像创建容器】确认按钮无法使用(感谢@猫猫向钱跑)
+3. 【server】修改 资产管理机器管理删除按钮无法正常使用(感谢@🇩)
+4. 【server】修复 SSH 面板文件管理无法正常切换(感谢@勤思·)
+5. 【server】优化 部分页面在火狐浏览器无法正常打开(感谢[@sparkarvin](https://gitee.com/arvinlovegood_admin) [Gitee issues I96IOA](https://gitee.com/dromara/Jpom/issues/I96IOA) )
+ (感谢[@a20070322](https://gitee.com/a20070322) [Gitee Pr 221](https://gitee.com/dromara/Jpom/pulls/221) )
+
+------
+
+## 2.11.3.0-beta (2024-03-21)
+
+### 🐣 新增功能
+
+1. 【server】新增 数据库支持 *postgresql* (感谢[@王先生](https://gitee.com/whz_gmg1))[Gitee Pr 223](https://gitee.com/dromara/Jpom/pulls/223)
+
+### 🐞 解决BUG、优化功能
+
+1. 【all】优化 新增 `jpom.system.command-use-sudo` 配置属性控制是否使用 sudo 执行部分系统命令
+2. 【server】优化 前端页面 keep-alive 可能导致的内存泄漏问题(感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I9510M](https://gitee.com/dromara/Jpom/issues/I9510M) )
+3. 【server】修复 部分弹窗不生效问题(感谢[@a20070322](https://gitee.com/a20070322) [Gitee Pr 215](https://gitee.com/dromara/Jpom/pulls/215) )
+4. 【server】优化 前端 ES lint 配置规范前端代码(感谢[@a20070322](https://gitee.com/a20070322) [Gitee Pr 214](https://gitee.com/dromara/Jpom/pulls/214) / [Gitee Pr 215](https://gitee.com/dromara/Jpom/pulls/215) / [Gitee Pr 217](https://gitee.com/dromara/Jpom/pulls/217) )
+5. 【server】修复 docker 控制台网络选项卡页面空白(感谢@破冰)
+6. 【server】修复 节点历史监控统计图表时间查询不生效(感谢@九問)
+7. 【server】优化 SSH 脚本触发器支持传入参数当环境变量(感谢@小朱)
+8. 【server】修复 h2迁移其它数据库时部分数据丢失(感谢[@王先生](https://gitee.com/whz_gmg1))[Gitee issues I9977K](https://gitee.com/dromara/Jpom/issues/I9977K)
+9. 【server】优化 逐步引入新版表格(构建、项目、节点、资产机器)(感谢[@a20070322](https://gitee.com/a20070322) [Gitee Pr 218](https://gitee.com/dromara/Jpom/pulls/218) / [Gitee Pr 220](https://gitee.com/dromara/Jpom/pulls/220) / [Gitee Pr 222](https://gitee.com/dromara/Jpom/pulls/222) )
+10. 【server】优化 工作空间概括构建日志支持快速查看详情(感谢@Roger.cao)
+
+------
+
+## 2.11.2.3 (2024-02-29)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 系统文件占用空间统计周期调整为每天2次(感谢[@singlethread](https://gitee.com/zengwei_joni) [Gitee issues I9302U](https://gitee.com/dromara/Jpom/issues/I9302U) )
+2. 【server】优化 支持配置前端所有参数编码来规避部分安全规则检查(感谢[@zhaozxc2010](https://gitee.com/zhaozxc2010) [Gitee issues I8Z1VJ](https://gitee.com/dromara/Jpom/issues/I8Z1VJ) )
+3. 【server】优化 上传文件空文件提示文件路径(感谢[@SchuckBate](https://gitee.com/skBate) [Gitee issues I93FI6](https://gitee.com/dromara/Jpom/issues/I93FI6) )
+4. 【server】优化 监听日志文件消息发送失败后自动移除会话(感谢[@singlethread](https://gitee.com/zengwei_joni) [Gitee issues I93ZFX](https://gitee.com/dromara/Jpom/issues/I93ZFX) )
+5. 【server】优化 容器构建产物为文件时保存路径层级错误(感谢[@vfhky](https://github.com/vfhky) [Github Pr 71](https://github.com/dromara/Jpom/pull/71) )
+
+------
+
+## 2.11.2.2 (2024-02-22)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 升级 docker-java、jgit 版本
+2. 【all】优化 升级 commons-compress 版本
+3. 【agent】优化 升级 oshi 版本
+4. 【server】优化 新增配置节点 websocket 通讯消息大小限制(jpom.node.web-socket-message-size-limit)(感谢@长弘)
+
+------
+
+## 2.11.2.1 (2024-02-19)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 构建代码未变动流程打断触发器未传入原因(statusMsg)(感谢@烛孩)
+2. 【server】修复 项目控制台日志删除弹窗未能正常关闭(感谢@%)
+3. 【server】修复 脚本日志时间筛选不生效(感谢[@zhaozxc2010](https://gitee.com/zhaozxc2010) [Gitee issues I8ZNKL](https://gitee.com/dromara/Jpom/issues/I8ZNKL) )
+4. 【server】优化 页面左侧菜单固定悬浮不跟随屏幕滚动条滚动(感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I8ZOOB](https://gitee.com/dromara/Jpom/issues/I8ZOOB) / [Gitee Pr 201](https://gitee.com/dromara/Jpom/pulls/201) )
+5. 【server】优化 新增机器节点提示未选择协议(感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I8ZDZT](https://gitee.com/dromara/Jpom/issues/I8ZDZT) / [Gitee Pr 202](https://gitee.com/dromara/Jpom/pulls/202) )
+6. 【server】修复 SSH 资产硬盘信息显示错误(感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I8ZY7K](https://gitee.com/dromara/Jpom/issues/I8ZY7K) )
+7. 【server】优化 表格搜索区域小屏幕适配 (感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I8ZY0B](https://gitee.com/dromara/Jpom/issues/I8ZY0B) )
+8. 【server】优化 SSH 文件管理树操作优化 (感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I9054L](https://gitee.com/dromara/Jpom/issues/I9054L) / [Gitee issues I5DMKG](https://gitee.com/dromara/Jpom/issues/I5DMKG) )
+9. 【server】优化 整体页面顶部菜单吸顶效果(感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I907Y8](https://gitee.com/dromara/Jpom/issues/I907Y8) )
+10. 【server】优化 资产监控线程池独立管理(感谢[@singlethread](https://gitee.com/zengwei_joni) [Gitee issues I918AB](https://gitee.com/dromara/Jpom/issues/I918AB) )
+11. 【server】优化 构建回滚使用构建独立线程池
+12. 【all】优化 升级 hutool 版本(主要解决版本号排序异常)(感谢 [@Tom Xin](https://gitee.com/meiMingle) [Gitee issues I8Z3TI](https://gitee.com/dromara/Jpom/issues/I8Z3TI) / [Hutool issues I8Z3VE](https://gitee.com/dromara/hutool/issues/I8Z3VE))
+13. 【all】优化 升级 fastjson 版本
+14. 【server】优化 页面整体滚动条兼容高版本浏览器(感谢@Controllers)
+
+### 🤝致谢
+
+感谢 [@a20070322](https://gitee.com/a20070322) / Controllers 大佬帮助优化 Jpom 前端部分老大难问题。
+
+------
+
+## 2.11.2.0 (2024-01-22)
+
+### 🐞 解决BUG、优化功能
+
+1. 【agent】修复 修改项目日志路径如果文件夹不存在报错(感谢@长弘)
+2. 【server】修复 节点机器日志无法下载(感谢@Again...)
+3. 【all】升级 hutool 版本
+4. 【agent】升级 oshi 版本
+5. 【server】升级 mwiede、apache-sshd 版本(感谢@*斌)
+6. 【server】优化 项目列表 file 类型正常排序(不再排序到最后)(感谢[@pal865](https://gitee.com/pal865) [Gitee issues I8XU32](https://gitee.com/dromara/Jpom/issues/I8XU32) )
+7. 【all】修复 windows 环境保存配置并重启失败(感谢[@Robot](https://gitee.com/robot1937) [Gitee issues I8Y01T](https://gitee.com/dromara/Jpom/issues/I8Y01T) )
+8. 【server】修复 新版本页面部分分页切换失效(构建详情、资产机器、逻辑节点)(感谢@zac)
+
+------
+
+## 2.11.1.5 (2024-01-18)
+
+### 🐞 解决BUG、优化功能
+
+1. 【agent】修复 插件端非默认工作空间项目重启后变为孤独数据(感谢@ccx2480)
+2. 【server】修复 新增节点分发项目数据为孤独数据
+
+------
+
+## 2.11.1.3/4-beta (2024-01-17)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 修复页面打包页面底部白屏
+
+------
+
+## 2.11.1.2-beta (2024-01-17)
+
+### 🐣 新增功能
+
+1. 【server】新增 触发器调用次数统计、触发器统一管理
+2. 【server】新增 本地构建命令执行支持配置多线程方式(多线程接收输出流,避免极端情况卡死)
+
+### 🐞 解决BUG、优化功能
+
+1. 【all】优化 机器状态新增:资源监控异常(资源监控异常不影响功能使用)
+2. 【server】优化 取消登录页动态背景图
+3. 【server】修复 节点分发文件中心、静态文件后文件自动被删除(感谢@九問)
+4. 【server】优化 容器构建支持配置容器资源(HostConfig)(感谢@珂儿)
+
+------
+
+## 2.11.1.1-beta (2024-01-16)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 静态文件名太短(100个字符)(感谢@*斌)
+2. 【server】修复 还原数据库弹窗内容提示为空(感谢@伤感的风铃草🌿)
+3. 【server】优化 echarts 支持跟随深色模式
+4. 【server】修复 编辑节点分发服务端脚本弹窗被挡住(感谢@🇩)
+5. 【server】优化 前端打包(缩减首屏加载时间)(感谢@曾梦想仗剑走天涯)
+
+------
+
+## 2.11.1.0-beta (2024-01-15)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 docker TLS 证书无法查看全部、证书无法编辑(新版遗漏)
+2. 【server】优化 docker 资产监控支持自定义配置 cron `jpom.assets.docker.monitor-cron`
+3. 【server】修复 容器终端、容器日志无法正常使用
+4. 【server】修复 新版本页面多处无法正常使用相关问题(优化部分提示说明)
+
+------
+
+## 2.11.0.13-beta (2024-01-12)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 部分 mysql 存储创建索引异常
+2. 【agent】优化 插件端自由脚本(分发文件脚本)大小限制调整为 5M(感谢@九問)
+3. 【server】修复 新版本 UI 部分错别字、日志阅读查看无法正常使用等
+4. 【server】优化 编辑器样式、DSL 配置样式
+
+------
+
+## 2.11.0.12-beta (2024-01-12)
+
+### 🐣 新增功能
+
+1. 【server】新增 资产总览统计
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 mysql 存储使用游标查询报错(不使用游标)(感谢@🇩)
+2. 【server】修复 新版 UI 下拉框搜索不生效
+3. 【server】优化 **添加**关键词替换为**新增**
+4. 【server】优化 部分页面无数据提示
+5. 【server】修复 节点分发构建产物选择构建历史为匹配对应构建
+6. 【server】修复 部分操作构建环境变量丢失(保存并构建、后台构建、直接构建)
+
+------
+
+## 2.11.0.11-beta (2024-01-11)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 编辑器无法加载样式
+2. 【server】优化 本地 git 联动严格执行开关
+3. 【server】修复 打包后终端弹窗样式错乱(感谢@🇩)
+4. 【server】修复 切换账户、退出登录菜单未刷新问题(感谢@ccx2480)
+5. 【server】修复 登录账户未跳转配置的第一个工作空间(未遵循自定义配置)
+
+------
+
+## 2.11.0.10-beta (2024-01-10)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 系统Git拉取代码时,强制云端最新代码覆盖本地代码
+2. 【server】修复 升级页面更新日志样式错乱
+3. 【server】修复 切换账户后用户信息未自动刷新
+4. 【agent】修复 **部分操作引起项目节点分发属性丢失问题**
+5. 【server】修复 无法新增项目(权限判断异常)(感谢@群友)
+6. 【agent】修复 插件端环境变量值获取异常
+7. 【agent】优化 插件端 java 项目启动支持读取环境变量
+8. 【server】修复 项目列表选择错乱、批量操作无法正常使用(感谢@🇩)
+
+------
+
+## 2.11.0.9-beta (2024-01-10)
+
+### 🐣 新增功能
+
+1. 【all】新增 孤独数据管理(查看孤独数据、修正孤独数据)(感谢[@陈旭](https://gitee.com/chenxu8989) [Gitee issues I8UNXZ](https://gitee.com/dromara/Jpom/issues/I8UNXZ))
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 上传文件前解析文件信息采用全局 loading
+2. 【server】优化 构建流程交互(采用步骤条)
+3. 【server】修复 部分 icon 未更新、部分弹窗列表数据不能正常显示
+4. 【server】修复 docker-compose 容器状态无非正确显示
+5. 【agent】修复 低版本项目数据未存储节点ID
+6. 【server】优化 节点项目、节点脚本操作鉴权(需要服务端缓存中有对应的数据)
+
+------
+
+## 2.11.0.8-beta (2024-01-09)
+
+### 🐣 新增功能
+
+1. 【server】新增 前端 UI 支持配置浅色、深色主题、左边菜单主题
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 容器构建 DSL 未回显任何内容
+2. 【server】修复 登录页面禁用验证码失效(感谢@ccx2480)
+
+------
+
+## 2.11.0.7-beta (2024-01-08)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】升级 页面 UI 组件、VUE 版本升级到最新
+2. 【server】修复 部分低频功能无法正常使用(项目备份文件管理等)
+3. 【server】修复 部分执行异常未输出到操作日志文件中(感谢@闫淼淼)
+
+### ⚠️ 注意
+
+1. 取消全局 loading(局部loading)
+2. 编辑器延迟 1 秒加载(避免样式错乱)
+3. 所有快捷复制区域变小为一个点击复制图标
+4. 弹窗、抽屉样式变动
+5. 取消操作引导(临时)
+6. 表格将跟随列内容长度自动拉伸出现横向滚动(不会折叠)
+7. 个性化配置取消:【页面自动撑开、滚动条显示、页面导航】
+8. 新版本前端 node 版本推荐:18.19.0
+9. json viewer 还未实现
+
+------
+
+## 2.11.0.6-beta (2024-01-05)
+
+### 🐞 解决BUG、优化功能
+
+1. 【all】优化 日志记录器提升日志记录性能
+2. 【server】优化 取消/停止构建采用异常来打断子进程
+3. 【server】修复 本地构建无法取消
+4. 【server】修复 服务端脚本触发器、节点脚本触发器提示找不到用户(感谢@LYY)
+
+------
+
+## 2.11.0.5-beta (2024-01-04)
+
+### 🐣 新增功能
+
+1. 【server】新增 工作空间管理中新增概括总览页面
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 支持批量删除构建信息(感谢@奇奇)
+2. 【server】修复 删除项目、删除分发检查关联构建失败问题
+3. 【all】优化 关闭 Process 方式
+4. 【server】优化 节点分发相关页面问题(感谢[@陈旭](https://gitee.com/chenxu8989) [Gitee issues I8TMDW](https://gitee.com/dromara/Jpom/issues/I8TMDW))
+
+------
+
+## 2.11.0.4-beta (2024-01-03)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 工作空间菜单配置无法使用(感谢@新)
+2. 【server】优化 重新同步节点项目、节点脚本缓存交互
+3. 【server】优化 SSH 脚本执行模板独立(`/exec/template.sh` -> `/ssh/template.sh`)
+4. 【server】优化 服务端脚本支持加载脚本模板来实现自动加载部分环境变量
+
+### ⚠️ 注意
+
+如果您自定义过 SSH 脚本默认那么您需要重新同步一下脚本模板`/exec/template.sh` -> `/ssh/template.sh`
+
+新版本 `/exec/template.sh` 中仅在服务端中生效(本地构建脚本、服务端脚本、本地发布脚本)
+
+------
+
+## 2.11.0.3-beta (2024-01-02)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 没有对应的工作空间权限
+
+------
+
+## 2.11.0.2-beta (2024-01-02)
+
+### 🐞 解决BUG、优化功能
+
+1. 【all】修复 环境变量为 null 是未忽略
+
+------
+
+## 2.11.0.1-beta (2024-01-02)
+
+### 🐣 新增功能
+
+1. 【all】新增 项目支持软链其他项目(代替项目副本)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 新版页面漏掉项目复制按钮
+2. 【server】优化 逻辑节点中项目数和脚本数仅显示当前工作空间数量
+3. 【server】优化 项目编辑和节点分发页面支持快捷配置授权目录
+4. 【server】优化 项目编辑支持切换节点(快速同步其他节点项目)
+5. 【server】修复 没有工作空间权限时页面循环跳转(感谢[@王先生](https://gitee.com/whz_gmg1) [Gitee issues I8RR01](https://gitee.com/dromara/Jpom/issues/I8RR01))
+6. 【all】优化 授权目录判断逻辑
+7. 【agent】取消 插件端授权目录关闭包含判断(`jpom.whitelist.check-starts-with`)
+8. 【server】优化 触发器清理优化、删除用户主动删除关联触发器
+9. 【server】优化 DSL 项目控制台支持快捷编辑节点脚本(查看流程信息)
+10. 【server】修复 项目触发器无法调用
+
+### ⚠️ 注意
+
+1. 如果您配置了授权目录但是保存项目报错您可以尝试重新报错一下授权目录来自动修复授权目录配置数据
+2. 项目控制台日志默认路径调整为插件端数据目录下`project-log/${projectId}/${projectId}.log`
+3. 项目控制台日志备份默认路径调整为插件端数据目录下`project-log/${projectId}/back/${projectId}-xxxxxxx.log`
+
+------
+
+## 2.11.0.0-beta (2023-12-29)
+
+### 🐣 新增功能
+
+1. 【server】新增 节点分发可以指定构建历史产物发布
+2. 【server】新增 节点分发可以指定文件中心发布
+3. 【server】新增 DSL 项目新增 reload 事件(可以开启文件变动触发)
+4. 【server】新增 静态文件授权服务端指定目录到工作空间来管理(分发)(感谢@*斌)
+5. 【server】新增 节点分发可以指定静态文件发布
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 项目列表批量操作弹窗定时刷新引起异常(感谢@曾梦想仗剑走天涯)
+2. 【all】下架 全面下架项目副本功能(请使用 DSL 模式代替)
+3. 【all】下架 全面节点证书管理功能(请使用工作空间证书代替)
+4. 【all】下架 全面架节点 NGINX 管理功能(请使用 DSL 模式代替)
+5. 【server】优化 **节点管理仅保留项目管理、脚本管理、脚本日志(其他功能迁移到机器资产管理)**
+6. 【server】修复 项目复制按钮点击无响应
+7. 【all】优化 查看插件端和服务端的系统日志 websocket 地址
+8. 【server】优化 监控机器系统负载保留2位小数
+9. 【server】下架 取消节点管理员权限
+10. 【server】修复 文件变动触发器不生效的问题
+11. 【all】优化 项目操作接口合并(4 合 1)
+12. 【server】优化 配置授权目录需要使用到绝对路径
+
+### ⚠️ 注意
+
+1. 全面下架项目副本功能(请使用 DSL 模式代替)如果您当前使用到此功能请先手动备份相关数据
+2. 升级后项目副本数据会被人工或者系统更新项目数据自动删除(请一定提前做好备份操作)
+3. 全面下架节点证书管理功能(请使用工作空间证书代替)如果您当前使用到此功能请先手动备份相关数据
+4. 全面下架全下架节点 NGINX 管理功能(请使用 DSL 模式代替)如果您当前使用到此功能请先手动备份相关数据
+
+> ❓ 为什么要下架上述功能:由于版本迭代已经有更好的新功能可以代替之前旧功能,并且新功能从另一种角度更方便。下架也是为了我们后续版本维护迭代更高效
+
+- 【白名单】关键词统一调整为【授权】
+- 【黑名单】关键词统一调整为【禁止】
+
+------
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cb8c373e05..028902c705 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,405 +1,1669 @@
-# 版本日志
-
-# 2.8.0 (beta)
-
-### 新增功能
-
-1. 【server】新增工作空间概念(取代角色相关)【系统将自动创建默认工作空间、默认工作空间是不能删除】
-2. 【server】用户新增可以配置管理员功能【管理员可以管理系统中的账号、系统管理等功能(除升级系统、导入数据外)】
-3. 【server】新增超级管理员(第一次初始化系统等账号为超级管理员),超级可以拥有整个系统权限不受任何限制
-4. 【server】列表数据都新增分页、搜索、排序功能(搜索字段、排序字段正在完善补充中)
-5. 【server】新增通过命令行重置 IP 白名单配置参数 `--rest:ip_config`
-6. 【server】新增通过命令行重置超级管理员参数 `--rest:super_user_pwd`
-7. 【server】新增通过命令行重新加载数据库初始化操作参数 `--rest:load_init_db`
-8. 【server】构建新增`本地命令`发布方式 用户在服务端执行相关命令进行发布操作
-9. 【server】发布命令(SSH发布命令、本地命令)支持变量替换:`#{BUILD_ID}`、`#{BUILD_NAME}`、`#{BUILD_RESULT_FILE}`、`#{BUILD_NUMBER_ID}`
-10. 【server】新增自动备份全量数据配置 `db.autoBackupIntervalDay` 默认一天备份一次,执行备份时间 凌晨0点或者中午12点
-11. 【agent】项目的 webhook 新增项目启动成功后通知,并且参数新增 `type` 指包括:`beforeStop`,`start`,`stop`,`beforeRestart`
-12. 【agent】项目新增自启动配置项,在 agent 启动时候检查对应项目是否启动,未启动执行启动逻辑
-13. 【server】构建新增 webhook,实时通知构建进度
-14. 【server】节点分发新增分发间隔时间配置
-
-### 解决BUG、优化功能
-
-1. 【server】用户账号、节点、SSH、监控、节点分发等数据由 JSON 文件转存 h2
-2. 【server】取消节点、构建分组字段
-3. 【server】取消角色概念(新增工作空间取代)
-4. 【server】操作监控数据由于数据字段不兼容将不自动升级需要用户重新配置
-5. 【server】系统参数相关配置都由 JSON 转存 h2(邮箱配置、IP白名单、节点分发白名单、节点升级)
-6. 【server】关联节点项目支持绑定单个节点不同项目
-7. 【server】构建触发器新增跟随创建用户走,历史 url 将失效,需要重新生成
-8. 【server】仓库`假删`功能下线,已经删除的仓库将恢复正常(假删功能后续重新开发)
-9. 【agent】项目数据新增工作空间字段、取消分组字段
-10. 【server】节点 ID 取消用户自定义采用系统生成
-11. 【server】优化节点弹窗和菜单折叠页面布局
-12. 【server】编辑节点、SSH、邮箱配置不回显密码字段
-13. 【server】优化 SSH 终端不能自动换行问题
-
-> 注意:
->
-> 【特别说明】:分组字段将失效,目前所有数据在升级后都将默认跟随`默认工作空间`。
->
-> 1: 升级该版本会自动将原 JSON 文件数据转存到 h2 中,如果转存成功旧数据文件将自动移动到数据目录中的 `backup_old_data` 文件夹中
->
-> 2: 升级过程请注意控制台日志是否出现异常
->
-> 3: 操作监控数据由于数据字段不兼容将不自动升级需要用户重新配置
->
-> 4: 监控报警记录、构建记录、操作记录由于字段兼容问题存在部分字段为空的情况
->
-> 5:非超级管理员用户会出现由于未分配工作空间不能正常登录或者不能使用的情况,需要分配工作空间才能登录
->
-> 6: 用户绑定工作空间后,用户在对应工作空间下可以创建、修改、删除对应的数据(包括但不限于管理节点)
->
-> 7: 此次升级启动耗时可能需要2分钟以上(耗时根据数据量来决定),请耐心等待和观察控制台日志输出
->
-> 8: 一个节点建议不要被多个服务端绑定(可能出现数据工作空间错乱情况)
+# 🚀 版本日志
+
+## 2.11.7-release (2024-06-19)
+
+### 🐣 新增功能
+
+1. 【agent】新增 项目文件支持快捷复制到当前文件夹
+2. 【agent】新增 项目文件夹支持快捷压缩(感谢[@yiziyu](https://gitee.com/yiziyu) [Gitee issues I9737L](https://gitee.com/dromara/Jpom/issues/I9737L) )
+3. 【agent】新增 全局脚本库(DSL 项目可引用)
+4. 【all】新增 支持 i18n 语言国际化:简体中文、英语、繁體中文(中國香港)、繁體中文(中國臺灣)
+5. 【server】新增 服务端脚本、SSH 脚本支持引用全局脚本库(`G@("xx")` xx 为脚本标记)
+6. 【agent】新增 节点脚本支持引用全局脚本库(`G@("xx")` xx 为脚本标记)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 部分参数、环境变量配置交互优化取消文本输入框采用标签模式(感谢@湘江夜色)
+2. 【server】修复 部分页面中文描述未正常显示
+3. 【server】优化 文件发布支持选择脚本模板(感谢[@linCodeTest](https://gitee.com/linWorld) [Gitee issues I9P0EU](https://gitee.com/dromara/Jpom/issues/I9P0EU) )
+4. 【server】优化 升级 postgresql 版本(感谢@ʟᴊx💎💎)
+5. 【server】修复 机器相关授权配置文件后缀输入框未正常显示(@感谢@ccx2480)
+6. 【server】修复 没有端口的容器重建页面异常(感谢@冰淇淋还是冰激凌)
+7. 【server】优化 ssh 管理独立 tab 页面使用默认的字符串排序
+8. 【server】修复 服务端脚本无法执行、参数值描述不对应(感谢@冰淇淋还是冰激凌)
+9. 【server】修复 gogs 仓库令牌导入异常(感谢@张飞鸿)
+10. 【server】修复 自定义仓库令牌导入后页面异常(感谢@张飞鸿)
+11. 【agent】修复 不同工作空间下同一个机器节点相同的项目ID的项目数据被覆盖(感谢@小朱)
+12. 【agent】优化 DSL 项目支持引用脚本库中的脚本(G@xxxx)xxxx 为脚本标记
+13. 【all】优化 新增系统语言配置 `jpom.system.lang`
+14. 【server】优化 前端紧凑模式在浅色模式下也生效
+
+### ⚠️ 注意
+
+- 前端国际化翻译程度:98%
+- 后端已翻译语言可以度:95%(部分异步执行日志等目前未支持)
+
+后端日志国际化需要新增或者修改 `jpom.system.lang` 配置项
+
+### 🤝致谢
+
+感谢 [@a20070322](https://gitee.com/a20070322) / Controllers 大佬贡献 Jpom 前端 i18n 工具。
+
------
-# 2.7.3
+## 2.11.6-release (2024-05-30)
-### 新增功能
-
-1. 【server】新增自定义系统网页标题配置`jpom.name`
-2. 【server】新增自定义系统网页 logo 配置`jpom.logoFile`
-3. 【server】新增自定义系统登录页面标题配置`jpom.loginTitle`
-4. 【server】新增自定义系统 logo 文字标题配置`jpom.subTitle`
-5. 新增在线下载最新版本更新包功能(在线检测最新版本)
-6. 【server】新增菜单`系统管理-数据库备份`,支持 Jpom 使用的 H2 数据库备份、还原
-
-### 解决BUG、优化功能
-
-1. 【server】修护构建产物为匹配符无法正常发布问题(感谢@Kay)
-2. 【server】修护在线升级页面在二级路径下无法使用的问题 (感谢@hu丶向...🤡)
-3. 【server】修护构建执行命令阻塞问题(感谢@小猿同学)
-4. 【server】修护限制 IP 访问和插件端授权信息不正确状态码冲突(感谢@小龙、@大灰灰)
-5. 取消 tools.jar 依赖
-6. 【server】优化初始化数据库流程,避免多次执行相同修改,节省启动时间
-7. 【fix】修护项目副本集乱码(感谢@ʟᴊx)
-8. 【server】添加在线升级完成后的回调提示
-9. 【server】ssh安装节点按钮动态显示
-10. 【server】修护构建信息中脚本过长无法构建的bug(感谢@Dream)
-11. 在网页的编辑器中修改配置文件时兼容tab键(感谢@Dream)
-
-> 取消 tools.jar 依赖后,Java 项目状态监控使用 `jps` 命令实现
-
-------
-
-# 2.7.2 (fix)
-
-### 新增功能
-
-### 解决BUG、优化功能
-
-1. 【agent】解决 nginx 编辑配置文件 url 编码问题
-3. 【server】新增配置构建命令支持不检测删除命令 `build.checkDeleteCommand` (感谢@Dream)
-
-------
-
-# 2.7.1 (fix)
-
-### 新增功能
-
-### 解决BUG、优化功能
-
-1. 解决插件端请求参数 url 编码无法解析问题(感谢@知识就是力量)
-2. 【agent】项目文件夹为空不再提示错误信息
-3. 【server】fix 编辑构建选择 ssh 发布无法保存 (感谢 @Peision [Gitee issues I4CQWA](https://gitee.com/dromara/Jpom/issues/I4CQWA) )
-4. 【server】fix ssh 终端未配置禁用命令不能输入空格问题
-
-------
-
-# 2.7.0 (beta)
-
-### 新增功能
-
-1. **【server】构建中的仓库独立管理**
-2. **【server】构建信息存储方式调整为 h2 数据库,不再存储到 json 文件中**
-3. **【server】构建触发器地址变更**
-4. 【agent】新增文件管理中允许编辑的文件后缀,以及对应后缀的文件编码
-5. 项目文件管理中新增编辑按钮,支持编辑文本文件( 新版本 UI 同步新增该功能)
-6. 程序启动输出默认 IP 地址和当前运行端口信息
-7. bat 管理命令(windows)启动后输出日志文件,方便排查当前启动情况
-8. 【server】上传文件到插件端(节点)超时配置独立,采用 server 端全局配置,配置参数 `node.uploadFileTimeOut`
- (感谢 @LW 根据 Gitee [issues I3O8YE](https://gitee.com/dromara/Jpom/issues/I3O8YE) )
-9. 【server】角色新增添加权限配置 (感谢@misaka [Gitee pr](https://gitee.com/dromara/Jpom/pulls/141) )
-10. 【server】节点升级上传新包成功后删除历史包
-11. 【server】新版本 UI 菜单系统管理、节点升级只有系统管理员可见
-12. 【server】新版本 UI 脚本模板同步添加执行参数(感谢@轻描淡写 [Gitee issues I43G4B](https://gitee.com/dromara/Jpom/issues/I43G4B) )
-13. 【server】新版本 UI 同步添加 common.js
-14. 【agent】项目文件管理新增下载远程文件功能
-15. 【agent】节点首页监控新增实际使用内存占比(linux系统) (感谢@大灰灰)
-16. 【server】ssh 新增操作记录(方便查看执行历史回溯操作)
-17. 【server】新增 h2 控制台配置属性,基于 SpringBoot,配置参数`spring.h2.console.enabled`
-18. 【server】节点分发支持下载远程文件 (感谢@落泪归枫 [Gitee issues I1LM27](https://gitee.com/dromara/Jpom/issues/I1LM27) )
-19. 【server】节点分发支持 file 类型项目
-20. 【agent】项目新增配置日志文件输出到指定目录
-21. 【server】构建产物目录支持通配符`AntPathMatcher`模式 (感谢@saysay [Gitee issues I455FM](https://gitee.com/dromara/Jpom/issues/I455FM) )
-22. 【server】新增 h2 数据库缓存大小配置 [CACHE_SIZE](http://www.h2database.com/html/features.html#cache_settings) `db.cacheSize
-23. 【server】构建触发器新增延迟执行参数(感谢@Steve.Liu)
-24. 【server】增加全局项目搜索功能
-25. 【agent】项目增加批量启动关闭重启
-26. 【server】节点分发文件支持上传非压缩包(感谢@Sam、風中飛絮 [Gitee issues I3YNA5](https://gitee.com/dromara/Jpom/issues/I3YNA5) )
-27. 【server】nginx 二级代理无法访问(感谢@hu丶向...🤡)
-28. 【server】ssh文件管理新增在线编辑(感谢@嗳啨 [Gitee issues I4ADTA](https://gitee.com/dromara/Jpom/issues/I4ADTA) )
-29. 在线升级支持上传 zip 包自动解析(感谢@Sam)
-30. 【server】ssh 安装插件端新增等待次数配置(感谢@hu丶向...🤡)
-31. 【server】新增前端接口请求超时配置 `jpom.webApiTimeOut`(感谢@hu丶向...🤡)
-32. 【server】构建支持 tag 通配符 (感谢@落泪归枫 [Gitee issues I1LM1V](https://gitee.com/dromara/Jpom/issues/I1LM1V) )
-
-### 解决BUG、优化功能
-
-1. 【server】添加节点时候限制超时时间,避免配置错误一直等待情况
-2. 【server】优化限制 IP 白名单相关判断,避免手动修改错误后一直限制访问
-3. 【server】添加 QQ 邮箱配置参照说明 [QQ邮箱官方文档](https://service.mail.qq.com/cgi-bin/help?subtype=1&&no=369&&id=28)
-4. 【server】fix: 删除临时文件出现 `AccessDeniedException` 更新文件权限为可读(取消只读权限)
-5. 【server】拉取 GIT 代码根据仓库路径添加 `synchronized`
-6. 【server】节点管理页面支持刷新当前节点页面(刷新不再回到首页)
-7. 【server】 jpom-service.sh 文件加载环境变量修改为 判断模式
-8. 【agent】fix: windows 环境保存配置文件错误问题
-9. 【agent】fix: 在线升级页面在没有配置白名单时候无法显示节点信息
-10. 【server】ssh 快捷安装插件端检查配置文件不在使用 SpringBoot 非 public 工具类
-11. 【server】请求节点发生异常打印具体堆栈、接口异常拦截器里面默认不打印堆栈 (根据 Gitee [issues I3O8YE](https://gitee.com/dromara/Jpom/issues/I3O8YE) )
-12. 【server】节点升级中偶尔出现无法获取到对应的版本信息问题(感谢@misaka Gitee issues [I41TDY](https://gitee.com/dromara/Jpom/issues/I41TDY) )
-13. 本地运行数据目录位置改为`${user.home}/jpom/xxxx`、日志路径改为项目模块下
-14. 【agent】升级 `commons-compress` 依赖 (来自 GitHub [advisories](https://github.com/advisories) )
-15. agent 和 server 间的 websocket 鉴权调整
-16. 【server】update: 刷新整个页面的时候重新加载菜单
-17. 历史监控图表查询报时间格式化错误(字符串工具类) (感谢@misaka [Gitee pr](https://gitee.com/dromara/Jpom/pulls/142) )
-18. 【agent】nginx 配置文件取消强制检测 server 节点
-19. 【server】仓库密码改为隐藏
-20. 解决退出登录验证码没有刷新问题 (感谢群友:Steve.Liu)
-21. 【agent】节点分发清空发布无效(感谢@Sam)
-22. 【server】编写分发项目时,当分发节点做替换、新增的操作后,点击确认,控制台报错(感谢@tan90°)
-
-> 【特别声明】当前版本 仓库和构建并没有接入动态数据权限,如果对权限敏感的用户建议等待下一个版本优化权限后再升级(如有疑问可以微信群沟通)
-
-> 注意1:由于构建信息全部存储到 h2 数据库中,之前到构建信息会自动同步,在升级后到第一次启动需观察控制台信息,启动成功后请检查构建信息,仓库信息是否同步正确
->
-> 注意2:构建的触发器地址有更新,需要重新获取触发器地址
->
-> 注意3:升级到该版本需要保证 agent、server 都保持同步,如果只升级 server 会出现项目控制台等功能无法正常使用
->
-> 注意4:升级 2.7.x 后不建议降级操作,会涉及到数据不兼容到情况
+### 🐣 新增功能
+
+1. 【all】新增 自由脚本方便调试机器节点
+2. 【agent】新增 项目支持配置禁止扫描目录避免大目录页面超时(感谢@我)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 资产管理 SSH 配置禁用命令无法回显(感谢@zhangw)
+2. 【server】修复 资产管理 SSH 未配置授权目录时 NPE (感谢[@Anley](https://gitee.com/MrAnley) [Gitee issues I9J17G](https://gitee.com/dromara/Jpom/issues/I9J17G) )
+3. 【agent】优化 监控机器网络流程支持配置排除网卡或者仅统计对应的网卡
+4. 【server】修复 退出登录时页面会提示需要登录相关信息
+5. 【server】优化 页面检测新版本判断是否加入 beta
+6. 【agent】优化 添加数据记录修改人(感谢[@陈旭](https://gitee.com/chenxu8989) [Gitee issues I9JSY7](https://gitee.com/dromara/Jpom/issues/I9JSY7) )
+7. 【server】优化 插件端注册到服务端,网络测试支持 ping + telnet (感谢@泊凉青川)
+8. 【server】优化 自动续签采用无感模式(感谢@湘江夜色)
+9. 【server】优化 容器构建执行配置自定义 host 参数(感谢@冰淇淋还是冰激凌)
+10. 【all】升级 tomcat、yaml 版本(感谢@佳驰)
+11. 【all】升级 bcprov-jdk18on 版本
+
+------
+
+## 2.11.5-release (2024-04-23)
+
+### 🐣 新增功能
+
+1. 【server】新增 Oauth2 新增【飞书账号】、【自建 Gitlab】登录(感谢[@鸡皮蒜毛与鸡毛蒜皮](https://gitee.com/cuia) [Gitee issues I9ELGS](https://gitee.com/dromara/Jpom/issues/I9ELGS) )
+2. 【server】新增 Oauth2 新增企业微信登录
+3. 【server】新增 发布系统公告
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 oauth2 第三方平台登录解析用户名将依次尝试:平台用户名、邮箱、uuid
+2. 【server】修复 无法查询到分组信息(页面下拉框)(感谢[@Robot](https://gitee.com/robot1937) [Gitee issues I9FN9U](https://gitee.com/dromara/Jpom/issues/I9FN9U) )
+3. 【all】升级 hutool 版本
+4. 【server】修复 修复孤独数据描述错别字(感谢[@cuiyongsheng](https://github.com/Cuiys1458) [Github issues 77](https://github.com/dromara/Jpom/issues/77) )
+5. 【server】修复 前端地址栏输入二级路径 404 页面卡死问题
+6. 【server】优化 Git 仓库地址不正确相关提示更准确(感谢@易自玉)
+7. 【server】升级 前端组件版本
+8. 【all】优化 管理脚本删除 `-XX:-UseBiasedLocking` 使其能在高版本 jdk 运行
+9. 【server】修复 构建列表卡片模式按钮文字错乱
+10. 【server】修复 项目列表和逻辑节点卡片视图冲突
+11. 【server】修复 docker管理新增docker选择证书界面权重异常 (感谢[@伤感的风铃草](https://gitee.com/bwy-flc) [Gitee issues I9GYVA](https://gitee.com/dromara/Jpom/issues/I9GYVA) )
+12. 【server】修复 系统管理中用户管理中登录日志无法筛选
+13. 【server】优化 用户登录记录操作日志(保证操作监控能记录)
+14. 【server】修复 系统管理中用户登录日志无法分页
+15. 【server】优化 Oauth2 支持配置创建账号配置权限组
+16. 【server】修复 文件发布权限为执行权限、文件发布记录删除无记录日志 (感谢@蓝枫)
+17. 【server】修复 资产管理 SSH 配置禁用命令无法回显(感谢@zhangw)
------
-# 2.6.4-patch
+## 2.11.4 (2024-04-07)
+
+### 🐣 新增功能
+
+1. 【server】新增 数据库支持 *postgresql* (感谢[@王先生](https://gitee.com/whz_gmg1))[Gitee Pr 223](https://gitee.com/dromara/Jpom/pulls/223)
+2. 【server】新增 数据库支持 *mariadb*
+3. 【server】新增 Oauth2 新增钉钉扫码登录
+
+### 🐞 解决BUG、优化功能
+
+1. 【all】优化 新增 `jpom.system.command-use-sudo` 配置属性控制是否使用 sudo 执行部分系统命令
+2. 【server】优化 前端页面 keep-alive 可能导致的内存泄漏问题(感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I9510M](https://gitee.com/dromara/Jpom/issues/I9510M) )
+3. 【server】修复 部分弹窗不生效问题(感谢[@a20070322](https://gitee.com/a20070322) [Gitee Pr 215](https://gitee.com/dromara/Jpom/pulls/215) )
+4. 【server】优化 前端 ES lint 配置规范前端代码(感谢[@a20070322](https://gitee.com/a20070322) [Gitee Pr 214](https://gitee.com/dromara/Jpom/pulls/214) / [Gitee Pr 215](https://gitee.com/dromara/Jpom/pulls/215) / [Gitee Pr 217](https://gitee.com/dromara/Jpom/pulls/217) )
+5. 【server】修复 docker 控制台网络选项卡页面空白(感谢@破冰)
+6. 【server】修复 节点历史监控统计图表时间查询不生效(感谢@九問)
+7. 【server】优化 SSH 脚本触发器支持传入参数当环境变量(感谢@小朱)
+8. 【server】修复 h2迁移其它数据库时部分数据丢失(感谢[@王先生](https://gitee.com/whz_gmg1))[Gitee issues I9977K](https://gitee.com/dromara/Jpom/issues/I9977K)
+9. 【server】优化 逐步引入新版表格(构建、项目、节点、资产机器)(感谢[@a20070322](https://gitee.com/a20070322) [Gitee Pr 218](https://gitee.com/dromara/Jpom/pulls/218) / [Gitee Pr 220](https://gitee.com/dromara/Jpom/pulls/220) / [Gitee Pr 222](https://gitee.com/dromara/Jpom/pulls/222) )
+10. 【server】优化 工作空间概括构建日志支持快速查看详情(感谢@Roger.cao)
+11. 【server】修复 无法查询到分组信息(页面下拉框)(感谢@猫猫向钱跑)
+12. 【server】修复 【项目文件管理远程下载】、【镜像创建容器】确认按钮无法使用(感谢@猫猫向钱跑)
+13. 【server】修改 资产管理机器管理删除按钮无法正常使用(感谢@🇩)
+14. 【server】修复 SSH 面板文件管理无法正常切换(感谢@勤思·)
+15. 【server】优化 部分页面在火狐浏览器无法正常打开(感谢[@sparkarvin](https://gitee.com/arvinlovegood_admin) [Gitee issues I96IOA](https://gitee.com/dromara/Jpom/issues/I96IOA) )
+ (感谢[@a20070322](https://gitee.com/a20070322) [Gitee Pr 221](https://gitee.com/dromara/Jpom/pulls/221) )
+16. 【agent】优化 DSL 项目支持配置在特定目录执行脚本(run.execPath)
+17. 【agent】优化 管理脚本 -Xss 默认值修改为 512k(感谢@Again... )
+18. 【server】优化 管理脚本 -Xss 默认值修改为 1024k(感谢@Again... )
+19. 【server】优化 声明使用开源软件列表、增加本软件开源协议声明
-### 新增功能
+------
+
+## 2.11.3 (2024-03-01)
+
+### 🐞 解决BUG、优化功能
+
+1. 【agent】修复 修改项目日志路径如果文件夹不存在报错(感谢@长弘)
+2. 【server】修复 节点机器日志无法下载(感谢@Again...)
+3. 【agent】升级 oshi 版本
+4. 【server】升级 mwiede、apache-sshd 版本(感谢@*斌)
+5. 【server】优化 项目列表 file 类型正常排序(不再排序到最后)(感谢[@pal865](https://gitee.com/pal865) [Gitee issues I8XU32](https://gitee.com/dromara/Jpom/issues/I8XU32) )
+6. 【all】修复 windows 环境保存配置并重启失败(感谢[@Robot](https://gitee.com/robot1937) [Gitee issues I8Y01T](https://gitee.com/dromara/Jpom/issues/I8Y01T) )
+7. 【server】修复 新版本页面部分分页切换失效(构建详情、资产机器、逻辑节点)(感谢@zac)
+8. 【server】优化 构建代码未变动流程打断触发器未传入原因(statusMsg)(感谢@烛孩)
+9. 【server】修复 项目控制台日志删除弹窗未能正常关闭(感谢@%)
+10. 【server】修复 脚本日志时间筛选不生效(感谢[@zhaozxc2010](https://gitee.com/zhaozxc2010) [Gitee issues I8ZNKL](https://gitee.com/dromara/Jpom/issues/I8ZNKL) )
+11. 【server】优化 页面左侧菜单固定悬浮不跟随屏幕滚动条滚动(感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I8ZOOB](https://gitee.com/dromara/Jpom/issues/I8ZOOB) / [Gitee Pr 201](https://gitee.com/dromara/Jpom/pulls/201) )
+12. 【server】优化 新增机器节点提示未选择协议(感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I8ZDZT](https://gitee.com/dromara/Jpom/issues/I8ZDZT) / [Gitee Pr 202](https://gitee.com/dromara/Jpom/pulls/202) )
+13. 【server】修复 SSH 资产硬盘信息显示错误(感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I8ZY7K](https://gitee.com/dromara/Jpom/issues/I8ZY7K) )
+14. 【server】优化 表格搜索区域小屏幕适配 (感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I8ZY0B](https://gitee.com/dromara/Jpom/issues/I8ZY0B) )
+15. 【server】优化 SSH 文件管理树操作优化 (感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I9054L](https://gitee.com/dromara/Jpom/issues/I9054L) / [Gitee issues I5DMKG](https://gitee.com/dromara/Jpom/issues/I5DMKG) )
+16. 【server】优化 整体页面顶部菜单吸顶效果(感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I907Y8](https://gitee.com/dromara/Jpom/issues/I907Y8) )
+17. 【server】优化 资产监控线程池独立管理(感谢[@singlethread](https://gitee.com/zengwei_joni) [Gitee issues I918AB](https://gitee.com/dromara/Jpom/issues/I918AB) )
+18. 【server】优化 构建回滚使用构建独立线程池
+19. 【all】优化 升级 hutool 版本(主要解决版本号排序异常)(感谢 [@Tom Xin](https://gitee.com/meiMingle) [Gitee issues I8Z3TI](https://gitee.com/dromara/Jpom/issues/I8Z3TI) / [Hutool issues I8Z3VE](https://gitee.com/dromara/hutool/issues/I8Z3VE))
+20. 【all】优化 升级 fastjson 版本
+21. 【server】优化 页面整体滚动条兼容高版本浏览器(感谢@Controllers)
+22. 【server】优化 升级 docker-java、jgit 版本
+23. 【all】优化 升级 commons-compress 版本
+24. 【server】优化 新增配置节点 websocket 通讯消息大小限制(jpom.node.web-socket-message-size-limit)(感谢@长弘)
+25. 【server】优化 系统文件占用空间统计周期调整为每天2次(感谢[@singlethread](https://gitee.com/zengwei_joni) [Gitee issues I9302U](https://gitee.com/dromara/Jpom/issues/I9302U) )
+26. 【server】优化 支持配置前端所有参数编码来规避部分安全规则检查(感谢[@zhaozxc2010](https://gitee.com/zhaozxc2010) [Gitee issues I8Z1VJ](https://gitee.com/dromara/Jpom/issues/I8Z1VJ) )
+27. 【server】优化 上传文件空文件提示文件路径(感谢[@SchuckBate](https://gitee.com/skBate) [Gitee issues I93FI6](https://gitee.com/dromara/Jpom/issues/I93FI6) )
+28. 【server】优化 监听日志文件消息发送失败后自动移除会话(感谢[@singlethread](https://gitee.com/zengwei_joni) [Gitee issues I93ZFX](https://gitee.com/dromara/Jpom/issues/I93ZFX) )
+29. 【server】优化 容器构建产物为文件时保存路径层级错误(感谢[@vfhky](https://github.com/vfhky))[Github Pr 71](https://github.com/dromara/Jpom/pull/71) )
+30. 【server】优化 个性配置区内容主题支持“跟随系统”(感谢[@a20070322](https://gitee.com/a20070322) [Gitee issues I94SPA](https://gitee.com/dromara/Jpom/issues/I94SPA) )
+
+------
-### 解决BUG、优化功能
+## 2.11.2 (2024-03-01)
-1. 【server】构建触发器新增延迟执行参数(感谢@Steve.Liu)
-2. 【server】数据库字段类型超大的 varchar 改为 CLOB(感谢@Alex)
-3. 【server】获取仓库分支方式修改(避免大仓库执行时间太长)(感谢@自作多情)
+### ⚠️ 注意
+
+此版本是一个空版本,为了更好地兼容后续 beta 和 release 版本发布特意创建的空版本
+
+2.11.2 版本等同于 2.11.3 版本
------
-# 2.6.3-patch
+## 2.11.1 (2024-01-18)
+
+### 🐣 新增功能
-### 新增功能
+1. 【server】新增 触发器调用次数统计、触发器统一管理
+2. 【server】新增 本地构建命令执行支持配置多线程方式(多线程接收输出流,避免极端情况卡死)
-### 解决BUG、优化功能
+### 🐞 解决BUG、优化功能
-1. 【agent】mac 进程号转换问题修护
-2. 【server】节点分发的项目白名单路径回显错误(感谢@tan90°)
-3. 【agent】自定义日志路径自动创建(感谢@tan90°)
+1. 【server】修复 docker TLS 证书无法查看全部、证书无法编辑(新版遗漏)
+2. 【server】优化 docker 资产监控支持自定义配置 cron `jpom.assets.docker.monitor-cron`
+3. 【server】修复 容器终端、容器日志无法正常使用
+4. 【server】修复 新版本页面多处无法正常使用相关问题(优化部分提示说明)
+5. 【server】修复 静态文件名太短(100个字符)(感谢@*斌)
+6. 【server】修复 还原数据库弹窗内容提示为空(感谢@伤感的风铃草🌿)
+7. 【server】优化 echarts 支持跟随深色模式
+8. 【server】修复 编辑节点分发服务端脚本弹窗被挡住(感谢@🇩)
+9. 【server】优化 前端打包(缩减首屏加载时间)(感谢@曾梦想仗剑走天涯)
+10. 【all】优化 机器状态新增:资源监控异常(资源监控异常不影响功能使用)
+11. 【server】优化 取消登录页动态背景图
+12. 【server】修复 节点分发文件中心、静态文件后文件自动被删除(感谢@九問)
+13. 【server】优化 容器构建支持配置容器资源(HostConfig)(感谢@珂儿)
+14. 【agent】修复 插件端非默认工作空间项目重启后变为孤独数据(感谢@ccx2480)
+15. 【server】修复 新增节点分发项目数据为孤独数据
------
-# 2.6.2-patch
+## 2.11.0 (2024-01-12)
+
+### 🐣 新增功能
+
+1. 【all】新增 **项目支持软链其他项目(代替项目副本)**
+2. 【server】新增 **工作空间管理中新增概括总览页面、资产总览统计**
+3. 【server】升级 **页面 UI 组件、VUE 版本升级到最新(支持配置浅色、深色主题、左边菜单主题)**
+4. 【all】新增 **孤独数据管理(查看孤独数据、修正孤独数据)**(感谢[@陈旭](https://gitee.com/chenxu8989) [Gitee issues I8UNXZ](https://gitee.com/dromara/Jpom/issues/I8UNXZ))
+5. 【server】新增 节点分发可以指定构建历史产物发布
+6. 【server】新增 节点分发可以指定文件中心发布
+7. 【server】新增 DSL 项目新增 reload 事件(可以开启文件变动触发)
+8. 【server】新增 静态文件授权服务端指定目录到工作空间来管理(分发)(感谢@*斌)
+9. 【server】新增 节点分发可以指定静态文件发布
+10. 【server】修复 没有工作空间权限时页面循环跳转(感谢[@王先生](https://gitee.com/whz_gmg1) [Gitee issues I8RR01](https://gitee.com/dromara/Jpom/issues/I8RR01))
+11. 【all】优化 授权目录判断逻辑
+12. 【agent】取消 插件端授权目录关闭包含判断(`jpom.whitelist.check-starts-with`)
+13. 【server】优化 触发器清理优化、删除用户主动删除关联触发器
+14. 【server】优化 DSL 项目控制台支持快捷编辑节点脚本(查看流程信息)
+15. 【server】修复 项目触发器无法调用
+
+### 🐞 解决BUG、优化功能
+
+1. 【all】下架 **全面下架项目副本功能(请使用 DSL 模式或者软链项目代替)**
+2. 【all】下架 **全面节点证书管理功能(请使用工作空间证书代替)**
+3. 【all】下架 **全面架节点 NGINX 管理功能(请使用 DSL 模式代替)**
+4. 【server】优化 **构建编辑页面交互、编辑器样式、DSL 配置样式**
+5. 【server】优化 **节点管理仅保留项目管理、脚本管理、脚本日志(其他功能迁移到机器资产管理)**
+6. 【all】优化 查看插件端和服务端的系统日志 websocket 地址
+7. 【server】优化 监控机器系统负载保留2位小数
+8. 【server】下架 取消节点管理员权限
+9. 【server】修复 文件变动触发器不生效的问题
+10. 【all】优化 项目操作接口合并(4 合 1)
+11. 【server】优化 配置授权目录需要使用到绝对路径
+12. 【server】优化 重新同步节点项目、节点脚本缓存交互
+13. 【server】优化 SSH 脚本执行模板独立(`/exec/template.sh` -> `/ssh/template.sh`)
+14. 【server】优化 服务端脚本支持加载脚本模板来实现自动加载部分环境变量
+15. 【all】优化 关闭 Process 方式
+16. 【server】优化 支持批量删除构建信息(感谢@奇奇)
+17. 【server】修复 删除项目、删除分发检查关联构建失败问题
+18. 【all】优化 日志记录器提升日志记录性能
+19. 【server】优化 取消/停止构建采用异常来打断子进程
+20. 【server】修复 本地构建无法取消
+21. 【server】修复 服务端脚本触发器、节点脚本触发器提示找不到用户(感谢@LYY)
+22. 【server】修复 部分低频功能无法正常使用(项目备份文件管理等)
+23. 【server】修复 部分执行异常未输出到操作日志文件中(感谢@闫淼淼)
+24. 【server】优化 系统Git拉取代码时,强制云端最新代码覆盖本地代码
+25. 【agent】优化 插件端 java 项目启动支持读取环境变量
+26. 【agent】修复 插件端环境变量值获取异常
+27. 【server】优化 本地 git 联动严格执行开关
+28. 【server】修复 登录账户未跳转配置的第一个工作空间(未遵循自定义配置)
+29. 【server】修复 部分操作构建环境变量丢失(保存并构建、后台构建、直接构建)
+30. 【agent】优化 插件端自由脚本(分发文件脚本)大小限制调整为 5M(感谢@九問)
+
+### ⚠️ 注意
+
+1. 全面下架项目副本功能(请使用 DSL 模式或者软链项目代替)如果您当前使用到此功能请先手动备份相关数据
+2. 升级后项目副本数据会被人工或者系统更新项目数据自动删除(请一定提前做好备份操作)
+3. 全面下架节点证书管理功能(请使用工作空间证书代替)如果您当前使用到此功能请先手动备份相关数据
+4. 全面下架全下架节点 NGINX 管理功能(请使用 DSL 模式代替)如果您当前使用到此功能请先手动备份相关数据
+
+>❓ 为什么要下架上述功能:由于版本迭代已经有更好的新功能可以代替之前旧功能,并且新功能从另一种角度更方便。下架也是为了我们后续版本维护迭代更高效
-### 新增功能
+------
+
+1. 如果您配置了授权目录但是保存项目报错您可以尝试重新报错一下授权目录来自动修复授权目录配置数据
+2. 项目控制台日志默认路径调整为插件端数据目录下`project-log/${projectId}/${projectId}.log`
+3. 项目控制台日志备份默认路径调整为插件端数据目录下`project-log/${projectId}/back/${projectId}-xxxxxxx.log`
-### 解决BUG、优化功能
+---------
-1. 【server】清除构建目录失败(感谢@大灰灰)
-2. 【server】fix: 在线升级页面在没有配置白名单时候无法显示节点信息
-3. 【agent】fix: windows 环境保存配置文件错误问题
-4. 【agent】升级 commons-compress 依赖 (来自 GitHub advisories )
-5. 【server】优化限制 IP 白名单相关判断,避免手动修改错误后一直限制访问
+如果您自定义过 SSH 脚本默认那么您需要重新同步一下脚本模板`/exec/template.sh` -> `/ssh/template.sh`
+
+新版本 `/exec/template.sh` 中仅在服务端中生效(本地构建脚本、服务端脚本、本地发布脚本)
------
-# 2.6.1-patch
+- 【白名单】关键词统一调整为【授权】
+- 【黑名单】关键词统一调整为【禁止】
+- 部分【添加】关键词统一调整为【新增】
-### 新增功能
+### 🤝致谢
-### 解决BUG、优化功能
+感谢所有参与 2.11.0 beta 版本(2.11.0.0 ~ 2.11.0.13)内测的用户。
-1. 【agent】 当自定义配置授权信息后增加控制台输出信息,避免用户无感(感谢@南)
-2. 【server】增加构建日志表构建命令字段长度,变更后长度为5000
-3. 【server】调整编辑构建弹窗布局
-4. 【server】ssh 发布命令调整为 sh 命令统一执行,避免类似 `nohup` 一直阻塞不响应
-5. 【server】拦截器文件权限异常,提醒检查目录权限
+------
+
+## 2.10.47 (2023-12-25)
+
+### 🐣 新增功能
+
+1. 【server】新增 容器构建支持自定义插件(感谢[@远方](https://gitee.com/WaHaHaqqww) [Gitee issues I8PEWI](https://gitee.com/dromara/Jpom/issues/I8PEWI))
+2. 【server】新增 容器管理新增导出、导入镜像
+3. 【server】新增 环境变量支持触发器获取、修改
+4. 【server】优化 容器日志、集群任务日志支持下载(感谢@在时间里流浪)
+5. 【all】新增 部分项目支持迁移工作空间和逻辑节点(感谢@奇奇)
+6. 【server】优化 资产管理 SSH 支持配置禁用监控(避免频繁登录)`jpom.assets.ssh.disable-monitor-group-name`(感谢@Again...)
+7. 【server】优化 资产管理 SSH 支持配置监控周期:`jpom.assets.ssh.monitor-cron`
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】升级 数据库 h2 、mwiede、web axios 版本
+2. 【server】修复 构建事件脚本未修改执行状态和退出码问题
+3. 【server】优化 构建事件脚本支持多选(顺序执行其中有一个中断将结束执行后续脚本)(感谢@loyal)
+4. 【server】优化 服务端脚本触发类型新增构建事件
+5. 【agent】删除 项目副本中弃用兼容字段 `parendId`
+6. 【server】优化 Docker 集群任务日志支持筛选行数、是否显示时间戳(感谢@在时间里流浪)
+7. 【server】优化 项目控制台日志输出 N 人查看改为 N 个会话(@冬)
+8. 【server】优化 添加超级管理员账号提醒勿使用常用账号
+9. 【server】优化 逻辑节点节目取消全局 loading(感谢@小菜鸡)
+10. 【server】优化 新增个性化配置全屏打开日志弹窗(构建、SSH、脚本、Docker等日志)(感谢@张飞鸿)
+11. 【server】修复 项目副本无法保存(修改中不能删除副本集、请到副本集中删除)
+12. 【server】优化 服务端中可以支持创建编辑项目、创建节点脚本啦!!!
+13. 【server】优化 项目列表支持删除项目、自动刷新项目
+14. 【server】优化 仓库支持查看关联的构建
+15. 【server】修复 删除服务端脚本日志如果脚本不存在不能删除
+16. 【server】优化 资产机器卡片试图部分场景未对齐问题
+17. 【server】优化 部分页面在小屏兼容(资产 Docker、节点分发)
+18. 【server】优化 节点脚本支持解绑(避免无非使用的服务器无非删除脚本)
+19. 【server】优化 白名单配置提示 nginx、证书功能将下线
+20. 【all】移除 插件端配置远程下载 host 输入框
+21. 【server】优化 导入 SSH、项目 CSV 数据自动识别编码格式
+22. 【server】优化 执行 SSH 脚本获取流异常:getInputStream() should be called before connect()
+
+### ⚠️ 注意
+
+新增容器构建自定义插件说明:
+
+1. 到 【系统管理】->【配置管理】->【系统配置目录】 中找到 `docker/uses` 目录
+2. 添加插件配置文件 `/docker/uses/java8/install.sh` 其中 `java8` 为新增的插件名
+3. 注意脚本中需要自行控制插件相关依赖的文件,需要将最新的文件保持到 `/opt/${name}/` 目录下,其中 ${name} 为插件名
+4. 辅助说明1:插件支持自定义环境变量
+5. 辅助说明2:自定义环境变量中需要引用插件目录请使用 `${JPOM_PLUGIN_PATH}`
+6. 系统默认集成了:`java`、`maven`、`node`、`go`、`python3`、`gradle`、`cache` 默认插件有依赖版本检查如果您的网络不通建议自行创建插件来规避默认检查
------
-# 2.6.0-beta
+## 2.10.46 (2023-12-18)
-### 新增功能
+### 🐞 解决BUG、优化功能
-1. 【server】新增配置 h2 数据账号密码参数(注意之前已经存在的数据不能直接配置、会出现登录不成功情况)
-2. 【agent】项目新增配置控制台日志输出目录 (感谢@落泪归枫 [Gitee I22O4N](https://gitee.com/dromara/Jpom/issues/I22O4N))
-3. 【server】新增配置 jwt token 签名 key 参数
-4. 【server】ssh 新增配置禁止执行的命令,避免执行高风险命令
-5. 【server】构建发布方式为 ssh 检查发布命令是否包含禁止执行的命令
-6. 【server】新增 ssh 执行命令初始化环境变量配置 `ssh.initEnv`
+1. 【server】修复 容器构建下载产物未关闭文件流占用句柄问题(感谢@在时间里流浪)
+2. 【all】优化 ConcurrentHashMap 修改为线程安全的 hutoll[SafeConcurrentHashMap](感谢@在时间里流浪)
+3. 【all】升级 mwiede.jsch、oshi、fastjson、hutool、spring-boot、docker-java
+4. 【server】优化 SSH 脚本在部分场景阻塞卡死(ChannelType.EXEC 不添加超时时间)
+5. 【server】优化 SSH 脚本执行输出退出码
+6. 【server】优化 解决构建流程,环境变量env里出现value==null出现null报错
+ (感谢 [@周冰](https://gitee.com/NineAsk) [Gitee pr 197](https://gitee.com/dromara/Jpom/pulls/197) )
+7. 【server】优化 SSH 脚本执行记录退出码
+8. 【server】优化 服务端脚本执行记录新增执行状态和退出码
-### 解决BUG、优化功能
+------
-1. 【agent】 修护 nginx 重载判断问题(@大灰灰大 码云 issue [I40UE7](https://gitee.com/dromara/Jpom/issues/I40UE7) )
-2. 【server】修护 ssh 上传文件时候不会自动创建多级文件夹(@大灰灰大)
-3. 【server】角色动态权限显示分组
-4. 【agent】 新增 stop 项目等待进程关闭时间配置 `project.stopWaitTime`、停止项目输出 kill 执行结果
-5. bat 管理命令更新环境变量,避免部分服务器出现无法找到 taskkill 命令( 感谢@Sunny°晴天、[@zt0330](https://gitee.com/zt0330) )
-6. 升级SpringBoot、Hutool等 第三方依赖版本
-7. 去掉旧版本 ui (thymeleaf、layui)
-8. 【server】fix: ssh 分发执行命令找不到环境变量问题
-9. 【server】在线升级显示打包时间、并发执行分发 jar 包、部分逻辑优化
-10. 【server】 构建历史增加下载构建产物按钮(感谢@房东的喵。)
-11. 【server】项目控制台新增心跳消息,避免超过一定时间后无法操作的情况
-12. 【server】ssh 新增心跳消息,避免超过一定时间后无法操作的情况
-13. 【server】系统缓存中的文件占用空间大小调整为定时更新(10分钟)
-14. 【server】修复 bug:分发列表页面点击【创建分发项目】按钮之后不能正常显示【分发节点】感谢 @xingenhi [点击查看提交记录](https://gitee.com/dromara/Jpom/commit/bd38528fbd3067d220b7569f08449d7796e07c74) [@Hotstrip](https://gitee.com/hotstrip)
-15. 【server】fix: 编辑管理员时用户名不可修改
-16. 【server】折叠显示部分列表操作按钮(减少误操作)
+## 2.10.45 (2023-10-17)
-> 注意:当前版本为 beta 版本。项目中升级了较多依赖版本、新增了部分重要配置(建议确认好后再配置).如果大家在升级后使用中发现任何问题请及时到微信群反馈,我们会尽快协助排查解决
->
-> 1. 如果是已经安装 Jpom、升级到当前版本请勿直接配置数据库账号密码,如果需要配置请手动连接数据库人工修改密码后再配置
-
-------
-
-# 2.5.2
-
-### 新增功能
-
-1. 【agent+server】 新增节点批量升级功能(注意,之前的节点版本不支持该功能需要升级当前版本后才能使用该功能)
-2. 【server】节点配置的超时时间单位由毫秒改为秒,并且最小值为2秒
-3. 【server】新增构建合并分支日志(便于判断分支冲突问题)
-
-### 解决BUG、优化功能
-
-1. 【server】fix bug:
- 分发列表页面,展开某个节点之后点击操作按钮会出现新的一行无效数据。[点击查看提交记录](https://gitee.com/dromara/Jpom/commit/e28b14bcf3dce402ce170a40f9bb93c4d25d0935) [@Hotstrip](https://gitee.com/hotstrip)
-2. 【server】fix bug:
- 项目监控页面,线程数据加载失败问题 [点击查看提交记录](https://gitee.com/dromara/Jpom/commit/b11c5443db6468a2bf7f6a9fa933f8d965899624) [@Hotstrip](https://gitee.com/hotstrip)
-3. 【server】fix bug: 修复低版本浏览器不支持 `.replaceAll()`
- 方法 [点击查看提交记录](https://gitee.com/dromara/Jpom/commit/0fb475963153b76546409ac3065a0efe9e647541) [@杨巍](https://gitee.com/fat_magpie_beijing_tony)
-4. 【server】update: 更新分发列表 -- 关联分发项目页面操作逻辑(跟老版本操作逻辑一致)[点击查看提交记录](https://gitee.com/dromara/Jpom/commit/cd6e4ae89f833e5e7ef11bd12c324a487de27b1a) [@李道甫](https://gitee.com/koushare_dfli)
-5. 【server】update: 优化项目文件管理页面,加载目录树时会多次显示 loading 层 [点击查看提交记录](https://gitee.com/dromara/Jpom/commit/71b3779bffb36259e0980ce25d4e4082a9d7c2e6) [@Hotstrip](https://gitee.com/hotstrip)
-6. 【server】fix bug: 修复节点请求超时可能导致节点项目列表为空 bug [点击查看提交记录](https://gitee.com/dromara/Jpom/commit/e3182dfa04c27e63a29d67b292a7bfef834f875e) [@Hotstrip](https://gitee.com/hotstrip)
-7. 【agent】 fix bug: index 获取进程列表 NPE (感谢@夏末秋初)
-8. 【server】fix bug: 修复上传项目压缩文件创建项目目录异常[点击这里查看对应 issue](https://gitee.com/dromara/Jpom/issues/I29FRJ)
-9. 【server】fix bug:创建构建时,如果选择
- svn,隐藏掉分支选项。[点击这里查看对应 issue](https://gitee.com/dromara/Jpom/issues/I3TA6S) [感谢 Alexa 提出 issue](https://gitee.com/alexa1989) [@Hotstrip](https://gitee.com/dromara/Jpom/compare/180914f4ddda4dc34fa2df9b169bac7b593dedb0...aa6bb065b6f507ad0bf42225a2aad40e2d25597f)
-10. 【server】 fix bug: ssh 构建发布清空历史文件失败(感谢@金晨曦)
-11. 【server】update 构建初始化仓库拉取指定分支,不先拉取主分支再切换到指定分支(感谢@大灰灰)
-12. 【server】程序关闭时候自动关闭 h2 数据连接池,避免数据库文件被损坏
-13. 【server】style:
- 优化logo,登录页面,初始化页面 [点击查看对应提交记录](https://gitee.com/dromara/Jpom/commit/5d4783f0be7d44bb04275b059ccd1509620c5828) [@长得丑活得久i](https://gitee.com/zsf_008)
-14. 【server】fix bug:
- 修复在没有配置nginx白名单时访问nginx列表数据一直加载中问题[点击这里查看对应 issue](https://github.com/dromara/Jpom/issues/5) [@长得丑活得久i](https://gitee.com/zsf_008)
-15. 新增 .gitattributes 文件控制命令文件的编码格式以及换行符(感谢@ℳ๓₯㎕斌)
-
-------
-
-# 2.5.1
-
-### 新增功能
-
-1. 【Server】保存邮箱信息时候验证邮箱配置是否正确(感谢@maybe)
-2. 【Server】Token 机制采用 jwt
-3. 【Server】git 构建新增进度日志输出
-4. 【Server】添加操作监控相关 api 和页面功能
-5. 【Server】完善 JWT token 过期自动续签功能
-6. 【Server】添加前端页面引导系统(使用 introJs)
-7. 【Server】访问 ip 限制,支持配置白名单和黑名单来控制 ip 访问权限
-8. 【Server】添加服务自启动脚本创建方案,下面贴一下 Server 端自启动方式:
-
-### 解决BUG、优化功能
-
-1. 【Server】全局网络请求新增 loading 状态控制
-2. 【Server】获取构建日志关闭 loading 状态
-3. 【Agent】控制台日志支持定时清空,避免日志文件太大(感谢@南有乔木)
-4. 【Server】在线升级状态判断修复
-5. 【Server】修复项目获取进程信息失败(感谢@onlyonezhongjinhui GitHub issues#7)
-6. 【Server】项目文件管理中显示项目文件存放真实目录
-7. 【Server】项目文件管理中文件夹不存在时,loading不消失(感谢@onlyonezhongjinhui GitHub issues#6)
-8. 【Server】文件管理列表不能正常加载二级以上的目录
-9. 【Server】添加监控判断用户是否配置报警联系方式(感谢@maybe)
-10. 【Server】初始化安装不能自动登录
-11. 【Server】页面组件采用国际化采用 zh_cn
-12. 【Server】服务器中验证码无法加载(感谢@何好听 Gitee issues#I3E7XQ)
-13. 【Agent】解决控制台输出 `Failed to check connection: java.net.ConnectException: Connection refused: connect`,因为没有关闭对应的 jmx
-14. 【Agent】解决首页控制台 java 进程列表慢的问题(采用定时拉取并缓存)
-15. 【server】fix bug:
- 节点列表页面,展开某个节点之后点击操作按钮会出现新的一行无效数据。 [点击查看提交记录](https://gitee.com/dromara/Jpom/commit/b9ecdfa649d27c46bca696e6df088a0908056ff6)
-16. 【server】fix bug: 节点列表页面,在没有安装节点的情况下,点击终端按钮会在控制台报错。[点击这里查看对应 issue](https://gitee.com/dromara/Jpom/issues/I3J4UI)
-17. 【server】fix bug: 节点管理里面的 Nginx 管理,关闭服务的接口参数传递错了。[点击这里查看对应 issue](https://gitee.com/dromara/Jpom/issues/I3IFZY)
-18. 【server】优化系统配置页面的样式,在小屏幕设备上会出现多个竖方向上的滚动条,甚至有时候会遮住底部的操作按钮
-19. 【server】ssh 终端命令交互优化(改优化取消之前版本快捷解压功能,删除命令检查)
-20. 【server】优化表格的排版和高度等样式,适配页面。详情见 [issue](https://gitee.com/dromara/Jpom/issues/I3EE2R)
-20. 【server】优化节点分发关联操作界面。
-
-> 注意事项:
-> 1. ssh 终端的删除命令检查临时取消(后面版本会重新优化)
-> 2. 该版本新增配置 Jpom 服务方式,需要更新 Server.sh、Agent.sh 文件,在线升级仅升级应用程序不会升级对应的管理命令文件,如果需要使用到该功能还需要手动覆盖更新对应的文件。(如果自定义过管理命令文件则需要差异覆盖)
-
-> 开机自启动:
+### 🐣 新增功能
+
+1. 【server】新增 SSH 新增独立管理面板(感谢[@超人那个超i](https://gitee.com/chao_a) [Gitee issues I7UFEX](https://gitee.com/dromara/Jpom/issues/I7UFEX))
+2. 【agent】新增 DSL 项目支持配置脚本环境变量(感谢[@陈旭](https://gitee.com/chenxu8989) [Gitee issues I80PTK](https://gitee.com/dromara/Jpom/issues/I80PTK))
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 构建产物同步到文件中心支持独立配置保留天数(感谢[@zhangxin2477](https://gitee.com/zhangxin1229) [Gitee issues I82G2F](https://gitee.com/dromara/Jpom/issues/I82G2F))
+2. 【server】优化 不能删除超级管理员账号
+3. 【agent】修复 Agent.sh 脚本的缺少方法问题(感谢[@Siwen Yu](https://github.com/yusiwen) [Github issues 64](https://github.com/dromara/Jpom/issues/64))
+4. 【server】优化 系统管理查看操作日志显示全部工作空间
+5. 【server】优化 容器构建判断构建异常(严格模式异常中断构建)(感谢@在时间里流浪)
+6. 【server】修复 构建流程中断触发 success 事件(感谢@在时间里流浪)
+7. 【server】优化 SSH 独立管理面板支持快捷使用文件管理
+8. 【server】优化 构建详情页面支持快捷回滚、查看构建日志(感谢[@縁來只爲伱](https://gitee.com/taochach) [Gitee issues I7YSNH](https://gitee.com/dromara/Jpom/issues/I7YSNH))
+9. 【all】升级 hutool、commons-compress
+10. 【agent】修复 重启项目偶发 NPE(监听日志关闭事件)(感谢[@caiqy](https://gitee.com/caiqiaoyu) [Gitee issues I7Z2U6](https://gitee.com/dromara/Jpom/issues/I7Z2U6))
+11. 【server】优化 构建支持配置环境变量实现产物打包为 `tar.gz` (**USE_TAR_GZ=1**)
+12. 【server】修复 文件管理偶发无法查看发片下载地址
+
+------
+
+## 2.10.44 (2023-09-06)
+
+### 🐣 新增功能
+
+1. 【server】新增 支持 git submodules
+ (感谢 [@Croce](https://gitee.com/Croce) [Gitee pr 195](https://gitee.com/dromara/Jpom/pulls/195) )
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 资产管理共享仓库新建归属到工作空间问题(感谢@沈钊)
+2. 【server】升级 springboot 、oshi、docker-java、jgit
+3. 【server】升级 mwiede.jsch 版本
+4. 【server】优化 构建回滚创建新的构建记录(感谢[@Smith](https://gitee.com/autools) [Gitee issues I7VEJA](https://gitee.com/dromara/Jpom/issues/I7VEJA))
+5. 【server】修复 新增资产无法正常监控问题(感谢@乔、@MichelleChung、@Pluto)
+6. 【server】优化 编辑集群地址不验证,调整到心跳检测验证(感谢@黄纲)
+7. 【server】优化 构建新增环境变量:BUILD_ORIGINAL_RESULT_DIR_FILE、BUILD_RESULT_DIR_FILE(发布流程)(感谢@黄纲)
+
+------
+
+## 2.10.43 (2023-08-25)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 未配置集群地址时无法切换工作空间(感谢@黄纲)
+
+------
+
+## 2.10.42 (2023-08-24)
+
+### 🐣 新增功能
+
+1. 【server】新增 集群化管理工作空间(感谢@定格、[@paobu](https://gitee.com/iniushi) [Gitee issues I7UG5V](https://gitee.com/dromara/Jpom/issues/I7UG5V))
+2. 【server】优化 ssh 相关功能支持 openssh8+
+ (感谢 [@孤城落寞](https://gitee.com/gclm) [Gitee pr 193](https://gitee.com/dromara/Jpom/pulls/193) )
+3. 【server】新增 SSH
+ 文件管理修改文件权限功能(感谢 [@MichelleChung](https://gitee.com/michelle1028) [Gitee issues I6VDXS](https://gitee.com/dromara/Jpom/issues/I6VDXS) )
+4. 【server】新增 Docker 容器重建功能,即删除原有的容器,重新创建一个新的容器
+5. 【server】新增 Docker 管理增加 SSH 连接
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 资产管理 SSH 管理系统名称显示未知问题(感谢@勤思·)
+2. 【server】优化 资产管理 Docker 管理支持配置分组
+3. 【server】优化 仓库管理支持配置分组
+4. 【server】优化 SSH 文件夹支持前端排序(感谢@勤思·)
+5. 【server】优化 仓库账号、 SSH 证书密码支持选择环境变量
+6. 【all】升级 commons-compress、fastjson、hutool 版本
+7. 【server】优化 maven 依赖冲突
+8. 【server】优化 文件发布-节点发布文件名使用真实名称(感谢@勤思·)
+9. 【server】优化 文件发布-ssh发布新增变量:FILE_NAME、FILE_EXT_NAME
+10. 【server】升级 h2、SpringBoot 版本
+11. 【server】使用系统git时,无法克隆tag问题优化 (感谢@唐明)
+12. 【server】优化 SSH 和 代码仓库的密码从工作空间变量中读取
+13. 【server】优化
+ 删除工作空间前预检查关联数据存在情况(感谢 [@陈旭](https://gitee.com/chenxu8989) [Gitee issues I7F0ZN](https://gitee.com/dromara/Jpom/issues/I7F0ZN) )
+14. 【server】优化
+ 退出登录支持彻底退出、切换账号退出(感谢 [@wangfubiao](https://gitee.com/wangfubiao) [Gitee issues I7GA5Q](https://gitee.com/dromara/Jpom/issues/I7GA5Q) )
+15. 【server】优化 IP 白名单验证忽略 IPV6 情况
+16. 【server】优化 服务端缓存管理支持查看黑名单 IP 详细信息(感谢@酱总)
+17. 【server】修复 SSH
+ 编辑输入框出现部分关键词时保持报错(感谢 [@一只羊](https://gitee.com/hjdyzy) [Gitee issues I7E3UG](https://gitee.com/dromara/Jpom/issues/I7E3UG) )
+18. 【server】优化 日志组件支持显示 \t 制表符、清空缓冲区滚动到顶部
+19. 【server】修复 彻底删除节点分发时未自动删除关联日志(感谢@ccx2480)
+20. 【server】修复
+ 节点管理中脚本模板翻页无效(感谢 [@wangfubiao](https://gitee.com/wangfubiao) [Gitee issues I7F0RS](https://gitee.com/dromara/Jpom/issues/I7F0RS) )
+21. 【server】优化
+ 工作空间配置页面中新增节点分发白名单配置入口(感谢 [@陈旭](https://gitee.com/chenxu8989) [Gitee issues I7F0W0](https://gitee.com/dromara/Jpom/issues/I7F0W0) )
+22. 【server】优化 构建附加环境变量支持解析 URL 参数格式
+ (感谢 [@爱琳琳真是太好了](https://gitee.com/qiqi513_admin) [Gitee issues I7FROG](https://gitee.com/dromara/Jpom/issues/I7FROG) )
+23. 【server】优化 构建支持单个配置保留天数和保留个数
+ (感谢 [@阿超](https://gitee.com/VampireAchao) [Gitee issues I7FOG2](https://gitee.com/dromara/Jpom/issues/I7FOG2) )
+
+------
+
+## 2.10.41 (2023-06-16)
+
+### 🐣 新增功能
+
+1. 【server】新增 SSH 列表支持显示 docker 版本信息
+2. 【server】优化 Docker 镜像增加批量删除(已经被容器使用的镜像不会删除)
+3. 【server】优化 启用 Jpom 新版专属 logo
+4. 【server】新增 工作空间新增分组字段(存在多个分组时页面切换将使用二级选择)(感谢@酱总)
+5. 【server】新增 仓库支持导入导出
+6. 【server】新增 镜像创建容器支持配置 hostname、集群服务支持配置 hostname(感谢@心光)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 查看 docker 容器日志 web socket 线程被阻塞问题
+2. 【server】优化 日志组件显示高亮、滚动条样式优化
+3. 【server】优化 web socket 会话关闭显示分类
+4. 【server】优化 页面滚动条样式
+5. 【server】优化 编辑关联分发,选择项目下拉框不能显示项目全名称(tooltip)(感谢@LYY)
+6. 【server】优化 监听页面关闭事件,主动关闭 websocket
+7. 【server】修复 批量构建触发器无法正常使用(感谢 [@botboy](https://github.com/cheakin) [Github issues 48](https://github.com/dromara/Jpom/issues/48) )
+8. 【server】修复 页面关闭 docker 终端未主动关闭后台终端进程问题
+9. 【server】优化 docker 终端页面缓冲区大小自动适应
+10. 【server】优化 项目列表可以查看项目日志(避免控制台卡顿无法操作下载日志)(感谢@阿超)
+11. 【server】优化 日志组件采用虚拟滚动渲染,避免日志过多浏览器卡死
+12. 【server】优化 资产管理支持管理共享仓库
+13. 【server】优化 增大验证码检测功能异常捕捉范围
+14. 【server】修复 令牌导入仓库令牌长度不足问题(感谢 [@Sherman Chu](https://github.com/yeliulee) [Github issues 45](https://github.com/dromara/Jpom/issues/45) )
+15. 【server】修复 分发列表配置功能无法使用(感谢 [@Free](https://gitee.com/fjlyy321) [Gitee issues I716UI](https://gitee.com/dromara/Jpom/issues/I716UI) )
+16. 【server】修复 构建卡片布局、构建详情中构建方式显示不正确(感谢@A)
+
+### ⚠️ 注意
+
+1. 如果自定义过 SSH 监控脚本需要自行同步获取 docker 信息脚本
+
+------
+
+## 2.10.40 (2023-04-19)
+
+### 🐣 新增功能
+
+1. 【server】新增 容器构建中对 gradle 插件的支持(感谢 [@xiaozhi](https://gitee.com/XiaoZhiGongChengShi) [Gitee pr 188](https://gitee.com/dromara/Jpom/pulls/188) )
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 日志搜索控制台无法正常使用(感谢@左手生活,右手浪漫)
+2. 【server】修复 项目文件跟踪控制台无法正常使用(感谢@左手生活,右手浪漫)
+3. 【server】修复 插件端日志无法正常差异
+4. 【server】修复 docker 拉取镜像不能识别私有仓库地址(@章强)
+5. 【server】优化 编辑构建无法重置已经选择的事件脚本 (感谢@左手生活,右手浪漫)
+6. 【server】优化 登录页面切换验证码自动清空验证码输入框(感谢@TrouBles)
+7. 【server】修复 docker 集群日志查看后未自动关闭造成日志文件继续增长的问题(@无味。)
+8. 【server】优化 服务端缓存项目信息的创建时间和修改时间同步为节点中的数据创建、修改时间
+9. 【server】优化 文件管理支持批量删除(感谢@左手生活,右手浪漫)
+10. 【agent】优化 取消 hutool-cache 包依赖
+11. 【server】优化 JustAuth fastjson 依赖配置为 fastjson2
+12. 【agent】修复 获取项目状态部分情况出现 NPE (感谢@酱总)
+13. 【server】修复 清空浏览器缓存未跳转到登录页面
+14. 【server】优化 构建拉取 git 仓库支持使用服务器中的 git 插件,实现配置克隆深度参数
+15. 【server】修复 删除节点脚本报错(感谢 [@xiaozhi](https://gitee.com/XiaoZhiGongChengShi) [Gitee issues I6USMY](https://gitee.com/dromara/Jpom/issues/I6USMY) )
+16. 【server】优化 构建 SSH 发布命令支持 `SSH_RELEASE_PATH` 环境变量(感谢@定格)
+17. 【server】修复 全屏终端无法打开文件管理(感谢@Pluto)
+18. 【server】优化 自动探测服务端登录验证码是否可用
+19. 【all】优化 文件编辑后缀识别支持配置文件名或者正则表达式(感谢@MichelleChung)
+20. 【server】优化 支持自动执行触发器清理
+21. 【server】优化 重新登录未加载管理员菜单(@A)
+22. 【server】修复 第三方登录跳转测试丢失
+23. 【server】修复 仓库编辑清除密码按钮弹窗层级问题(感谢 [@轩辕豆豆](https://gitee.com/xuanyuandoudou) [Gitee issues I6VSCR](https://gitee.com/dromara/Jpom/issues/I6VSCR) )
+24. 【server】修复 优化构建列表卡片布局存在未构建数据布局错乱问题(感谢 [@lin_yeqi](https://gitee.com/lin_yeqi) [Gitee issues I6VUB7](https://gitee.com/dromara/Jpom/issues/I6VUB7) )
+
+------
+
+## 2.10.39 (2023-04-04)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 资产管理机器管理单个分配工作空间无法正常使用(感谢@咻咻咻秀啊)
+2. 【server】修复 资产管理相关权限、操作日志无法记录问题(感谢@咻咻咻秀啊)
+3. 【server】修复 docker 控制台 、日志无法正常使用
+4. 【server】优化 docker 控制台页面布局优化,支持单独查看 docker-compose
+5. 【server】优化 docker 实时查看日志支持配置是否显示时间戳
+6. 【server】修复 查看文件发布详情节点名称未显示
+7. 【server】优化 发布记录重建不能选中节点
+8. 【server】修复 构建同步到文件管理中心失败(感谢@破冰)
+9. 【server】优化 登录成功主动刷新菜单缓存、切换账号登录工作空间无权限页面白屏(感谢@A、@零壹)
+10. 【all】更名 变更包名为 `org.dromara.jpom`
+11. 【server】修复 编辑 docker 导入证书弹窗无法正常显示问题(感谢@左手生活,右手浪漫)
+12. 【server】修复 工作空间中资产管理相关页面搜索无数据时出现操作引导提示(感谢@酱总)
+
+------
+
+## 2.10.38 (2023-03-31)
+
+### 🐣 新增功能
+
+1. 【server】新增 证书管理全部迁移到服务端统一导入 (感谢@.)
+2. 【server】新增 节点项目支持导入,导出(感谢@酱总)
+3. 【server】新增 支持 oauth2 登录(maxkey、gitee、github) (感谢 [@MaxKeyTop](https://gitee.com/maxkeytop_admin) [Gitee pr 183](https://gitee.com/dromara/Jpom/pulls/183) 、@A)
+4. 【all】新增 文件管理发布支持发布到节点指定目录
+5. 【server】新增 构建新增配置排除发布目录表达式(感谢@毛毛虫)
+6. 【all】新增 节点脚本支持全局共享(感谢@奇奇)
+7. 【server】新增 构建状态新增队列等待,用于标记当前构建存于线程排队中(感谢@酱总)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 清理单项构建历史保留个数只判断(构建结束、发布中、发布失败、发布失败)有效构建状态,避免无法保留有效构建历史(感谢@张飞鸿)
+2. 【server】优化 节点监控超时时间调整为 30 秒(避免 windows 服务器频繁超时)(感谢@波比)
+3. 【server】优化 打开节点管理页面不刷新节点列表
+4. 【agent】修复 未配置节点白名单时直接创建分发项目报错(感谢@奋起的大牛)
+5. 【server】修复 SSH 关联工作空间的授权目录无法取消
+6. 【server】优化 查看分发项目状态取消折叠 table,调整为独立页面
+7. 【server】优化 逻辑节点没有显示快速安装按钮问题(感谢@酱总)
+8. 【server】优化 docker TLS 证书全部迁移到证书管理,配置证书支持快捷选择 (感谢@.)
+9. 【server】修复 仓库 ssh 协议配置超时时间无法正常拉取代码(感谢@毛毛虫)
+10. 【server】优化 环境管理页面支持查看间隔任务统计信息
+11. 【server】优化 令牌导入仓库模块统一调整为模板配置(部分方式不支持搜索)(感谢@魏宏斌)
+12. 【agent】优化 DSL 项目报警内容添加状态消息(感谢@核桃)
+13. 【server】优化 服务端脚本支持配置全局共享(感谢@酱总)
+14. 【server】优化 删除管理脚本中的 `-XX:+AggressiveOpts` 参数
+ (感谢 [@牛孝祖](https://gitee.com/niuxiaozu) [Gitee issues I6PUNM](https://gitee.com/dromara/Jpom/issues/I6PUNM) )
+15. 【all】升级 springboot、hutool、fastjson2、svnkit 版本
+16. 【server】修复 资产管理 ssh 分组不生效问题(感谢@A)
+17. 【server】优化 构建详情页面布局(构建触发器、查看构建历史)
+18. 【server】优化 新增构建状态描述来记录构建异常信息
+19. 【server】优化 构建页面新增卡片布局方式
+20. 【server】修复 SSH 分组无法正常搜索、排序异常(感谢@A)
+21. 【server】优化 构建命令支持引用脚本模板内容(便于复杂构建命令管理)(感谢@毛毛虫)
+22. 【server】新增 构建状态新增`队列等待`,用于标记当前构建存于线程排队中(感谢@酱总)
+23. 【server】修复 创建构建选择命令模板无法修改(感谢@定格)
+24. 【server】优化 构建新增配置是否发布隐藏文件属性(感谢@简单)
+
+### ⚠️ 注意
+
+1. 如果节点已经配置过项目文件下载远程地址白名单需要统一配置到服务端的工作空间的白名单。
+2. 已经配置节点项目远程下载白名单将保留只读,不做实际判断
+3. 构建触发器变动,发生异常时 type 为 error,并且新增:statusMsg 字段
+
+### ❌ 不兼容功能
+
+1. 【agent】取消 节点管理证书管理取消上传编辑功能(保留查询删除功能)
+2. 【agent】取消 节点白名单配置取消 ssl 证书路径配置
+3. 【agent】取消 节点项目文件下载远程文件白名单统一调整到服务端白名单配置
+
+------
+
+## 2.10.37 (2023-03-21)
+
+### 🐣 新增功能
+
+1. 【server】新增 文件中心添加别名码来为文件进行分类下载,构建添加别名码可以同步到文件中心
+ (感谢 [@大灰灰大](https://gitee.com/linjianhui) [Gitee issues I6OUC8](https://gitee.com/dromara/Jpom/issues/I6OUC8) )
+2. 【server】新增 服务端在线升级支持配置 beta 计划(”妈妈“再也不用担心没有稳定版了)(感谢@罗俊)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 容器构建 maven 插件版本错误提示可用版本号,如果构建容器已经存在则忽略远程版本(感谢@大灰灰)
+2. 【server】优化 脚本列表显示脚本 ID,方便快速查看复制
+ (感谢 [@大灰灰大](https://gitee.com/linjianhui) [Gitee issues I6OUDT](https://gitee.com/dromara/Jpom/issues/I6OUDT) )
+3. 【server】优化 文件管理列表显示,小屏幕部分字段被隐藏(感谢@tinsang)
+4. 【server】优化 docker 拉取镜像自动解析 tag,避免拉取所有镜像,如果没有配置 tag 默认使用 latest(感谢@Again... .)
+5. 【server】修复 数据库迁移到 mysql 报错(字段不存在)(感谢@轩辕豆豆)
+6. 【server】修复 节点统计页面错乱问题
+ (感谢 [@轩辕豆豆](https://gitee.com/xuanyuandoudou) [Gitee issues I6OYSU](https://gitee.com/dromara/Jpom/issues/I6OYSU) )
+
+------
+
+## 2.10.36 (2023-03-20)
+
+### 🐞 解决BUG、优化功能
+
+1. 【all】优化 缓存管理统一全局任务刷新
+2. 【server】优化 修复数据关联的工作空间ID sql(避免 '' 或者 'null' 无法修复)
+3. 【server】优化 支持手动清理错误工作空间 ID 的数据
+4. 【server】修复 构建 git 仓库无法正常获取问题(感谢@小翼哥)
+
+------
+
+## 2.10.35 (2023-03-20)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 mysql 数据库无法正常加载(感谢@酱总)
+
+------
+
+## 2.10.34 (2023-03-20)
+
+### 🐣 新增功能
+
+1. 【server】新增 资产管理 SSH 管理支持导入导出数据(感谢@吃葫芦娃的土拨鼠)
+2. 【server】新增 文件管理中心(用于统一存储管理公共文件)
+3. 【server】新增 仓库令牌导入支持 gogs (gogs 和 gitea 标准一致)
+ (感谢 [@爱琳琳真是太好了](https://gitee.com/qiqi513_admin) [Gitee issues I6CRPS](https://gitee.com/dromara/Jpom/issues/I6CRPS) )
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 构建 SSH 发布上传文件执行输出上传进度
+2. 【server】优化 在线构建产物支持同步到文件管理中心
+3. 【server】优化 节点分发、在线构建 webhook 添加 `triggerUser` 参数(感谢@酱总)
+4. 【server】优化 SSH 文件夹管理支持重命名文件夹(感谢@零壹)
+5. 【server】优化 机器名称和 hostname、SSH 机器名称和 hostname 限制字段长度
+6. 【server】优化 DSL 项目支持解析多 PID :`running:109,205:8080,8082`(感谢@酱总)
+7. 【server】优化 缓存管理页面支持查看运行中的线程同步器、正在构建的ID
+8. 【server】优化 SSH 脚本批量执行采用线程同步器执行(避免线程数大于 CPU 核心数)
+9. 【server】优化 构建 SSH 发布命令响应方式调整为逐行(避免长时间没有任何信息输出)
+10. 【server】优化 资产管理支持批量分配到工作空间
+
+### ⚠️ 注意
+
+1. 【server】节点管理和项目管理菜单合并到一个菜单
+2. 【server】节点统计页面合并到逻辑节点中不同视图模式查看
+
+### ❌ 不兼容功能
+
+1. 【server】取消 低版本(2.9.x 及其一下)的构建触发器 token 自动同步为新版本
+
+------
+
+## 2.10.33 (2023-03-16)
+
+### 🐣 新增功能
+
+1. 【server】新增 ssh 基础信息监控(非报警监控)
+2. 【agent】新增 DSL 项目支持解析端口号:`running:109:8080,8082`
+ (感谢 [@大灰灰大](https://gitee.com/linjianhui) [Gitee issues I6N35H](https://gitee.com/dromara/Jpom/issues/I6N35H) )
+3. 【server】新增 用户支持自定义工作空间名,排序 (感谢@酱总)
+4. 【server】新增 节点分发项目支持排序,设置项目启用/禁用状态(感谢@酱总)
+5. 【server】新增 节点分发支持手动释放删除指定项目
+6. 【server】新增 docker 镜像创建容器新增 runtime 参数
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 插件端在线升级页面无法正常使用(调用到服务端在线升级接口)
+2. 【server】优化 节点在线升级统一管理避免出现 null
+3. 【server】修复 节点信息编码在部分接口出现 NPE (感谢@酱总)
+4. 【server】优化 工作空间中不存在资产管理相关的数据添加默认缺省页(仅管理员显示)
+5. 【server】优化 支持手动释放节点项目的分发属性
+
+### ❌ 不兼容功能
+
+1. 【agent】取消 节点进程列表显示 jpom 项目名
+
+### ⚠️ 注意
+
+1. 【server】优化 在线工具菜单更名为其他管理
+
+------
+
+## 2.10.32 (2023-03-14)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 mysql 数据库因为字段长度问题初始化失败(感谢@xuejun)
+
+------
+
+## 2.10.31 (2023-03-14)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 未配置节点编码方式无法正常保存问题(感谢@初凡 ³)
+
+------
+
+## 2.10.30 (2023-03-14)
+
+### 🐣 新增功能
+
+1. 【all】新增 插件端支持配置发送请求消息编码方式(编码、混淆明文、规避防火墙)
+ (感谢 [@Mr_loyal](https://gitee.com/Mr_loyal) [Gitee pr 179](https://gitee.com/dromara/Jpom/pulls/179) )
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 导入 gitea 仓库搜索、分页无法正常使用问题
+ (感谢 [@Smith](https://gitee.com/autools) [Gitee pr 175](https://gitee.com/dromara/Jpom/pulls/175) [Gitee pr 174](https://gitee.com/dromara/Jpom/pulls/174) )
+2. 【server】优化 镜像启动容器不填写运行命令行导致容器启动失败(部分低版本)
+ (感谢 [@失落的世界](https://gitee.com/marmotgo) [Gitee pr 176](https://gitee.com/dromara/Jpom/pulls/176) )
+3. 【server】修复 节点分发 webhook 输入框的错别字(感谢 @大灰灰 )
+4. 【server】修复 工作空间环境变量操作日志记录错误问题
+5. 【all】更新 fastjson2 版本
+6. 【all】优化 SSH 命令脚本、服务端脚本、插件端脚本执行参数优化
+ (感谢 [@大灰灰大](https://gitee.com/linjianhui) [Gitee issues I6IPDY](https://gitee.com/dromara/Jpom/issues/I6IPDY) )
+7. 【server】优化 导入仓库页面提示信息错乱(感谢@零壹)
+8. 【agent】修复 项目修改路径为子目录时 mv 文件触发死循环(感谢@D¹⁹⁹¹)
+9. 【server】修复 查询构建日志可能出现 NPE 问题
+ (感谢 [@Tom Xin](https://gitee.com/meiMingle) [Gitee issues I6MX9G](https://gitee.com/dromara/Jpom/issues/I6MX9G) )
+10. 【server】优化 系统缓存页面显示当前服务器时间、时区信息
+11. 【server】修复 还原数据后备份状态错误问题
+ (感谢 [@lin_yeqi](https://gitee.com/lin_yeqi) [Gitee issues I6MVL7](https://gitee.com/dromara/Jpom/issues/I6MVL7) )
+12. 【agent】修复 DSL 项目状态不判断 jps 命令是否正常(感谢@大灰灰)
+13. 【agent】修复 未配置节点白名单时直接创建分发项目报错(感谢@波比)
+
+### ❌ 不兼容功能
+
+1. 【server】删除 COMMAND_INFO 表 type 字段
+
+### ⚠️ 注意
+
+SSH 命令脚本、服务端脚本、插件端脚本默认参数规则变化:参数描述将必填,默认参数在手动执行时无法删除并且可以查看对应参数描述
+
+------
+
+## 2.10.29 (2023-03-10)
+
+### 🐣 新增功能
+
+1. 【server】新增 导入仓库支持 `gitea` 系统
+ (感谢 [@Smith](https://gitee.com/autools) [Gitee pr 173](https://gitee.com/dromara/Jpom/pulls/173) )
+2. 【server】新增 用户登录日志(取消用户登录生成操作日志的执行日志)
+3. 【server】新增 在线工具验证 cron 表达式 (感谢@奇奇)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 SSH 并发执行脚本引起脚本丢失错误(感谢@墨汁)
+2. 【server】优化 docker 编辑无法连接提示异常详情信息(感谢@章强)
+3. 【agent】优化 节点分发配置白名单到插件端需要验证合法性
+4. 【server】优化 docker 创建容器忽略未配置存储选项参数(感谢@D¹⁹⁹¹)
+5. 【server】优化 docker 管理裁剪功能独立菜单
+6. 【server】修复 资产管理未记录操作日志的问题
+7. 【server】优化 操作日志存储用户名、工作空间名字段
+8. 【server】优化 容器构建查询可用标签容器相关提示
+9. 【server】优化 构建历史列表页面在小屏幕数据显示不全
+ (感谢 [@一只羊](https://gitee.com/hjdyzy) [Gitee issues I6LLA0](https://gitee.com/dromara/Jpom/issues/I6LLA0) )
+10. 【server】修复 在线构建发布到集群无法正常选择集群服务(感谢@心光)
+
+------
+
+## 2.10.28 (2023-03-08)
+
+### 🐣 新增功能
+
+1. 【agent】新增 项目触发器新增 fileChange 事件(文件变动对应触发点:上传、删除、远程下载、编辑、新增目录或者文件、重命名)
+ (感谢 [@胡明](https://gitee.com/pig_home) [Gitee issues I6KKEK](https://gitee.com/dromara/Jpom/issues/I6KKEK) )
+2. 【server】新增 镜像创建容器支持配置存储选项(感谢@topsuder、@章强)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 新增 docker 无法使用在线构建功能
+ (感谢 [@失落的世界](https://gitee.com/marmotgo) [Gitee issues I6KTLQ](https://gitee.com/dromara/Jpom/issues/I6KTLQ) )
+2. 【server】优化 项目文件列表支持前端排序(文件大小、修改时间)
+3. 【server】优化 关闭程序时依次关闭线程池
+4. 【server】优化 工作空间环境变量开放给普通用户编辑
+
+### ⚠️ 注意
+
+插件端需要同步升级,否则项目文件列表排序无法正常使用
+
+------
+
+## 2.10.27 (2023-03-06)
+
+### 🐣 新增功能
+
+1. 【server】新增 资产管理新增 docker 、集群管理
+
+### 🐞 解决BUG、优化功能
+
+1. 【all】升级 springboot 版本
+2. 【server】优化 系统自动同步 docker 已经安装的集群信息
+3. 【server】更新 mysql maven 坐标:`mysql-connector-j`
+4. 【server】修复 构建产物模糊匹配二级剔除配置 `/` 无效
+
+### ⚠️ 注意
+
+新增 docker 资产管理,系统会自动将已经存在的 docker 信息根据 host 去重同步到资产管理中(如果 host
+存在多个工作空间将根据最后更新时间排序使用最新的一条数据)
+
+更新后 docker、集群列表中状态如果出现:`信息丢失` 表示关联数据存在异常不能正常使用,需要删除对应数据重新关联
+
+------
+
+## 2.10.26 (2023-03-03)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 初始化数据库未删除完整问题(感谢@酱总)
+2. 【server】优化 日志阅读选项卡 tab 名称添加项目名称(感谢@tinsang)
+
+------
+
+## 2.10.25 (2023-03-03)
+
+### 🐣 新增功能
+
+1. 【server】新增 构建历史新增产物文件大小
+2. 【all】新增 机器安装 ID 文件(请勿删除数据目录 `INSTALL.json` 文件)
+3. 【agent】新增 插件端新增虚拟内存和交互内存监控趋势
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 构建发布完成,自动删除压缩包文件(节省空间占用大小)(感谢@轩辕豆豆)
+2. 【server】修复 更新构建历史环境变量失败
+3. 【server】取消 SSH 脚本命令参数描述(避免误导用户)
+ (感谢 [@大灰灰大](https://gitee.com/linjianhui) [Gitee issues I6IPDY](https://gitee.com/dromara/Jpom/issues/I6IPDY) )
+4. 【server】优化 编辑项目文件回显错乱问题
+5. 【server】优化 日志阅读菜单更名日志搜索
+6. 【server】优化 差异构建时,触发取消构建标记构建状态为`构建中断` (感谢@张飞鸿)
+7. 【server】优化 部分窄下拉框新增 tooltip,避免内容过长无法查看 (感谢@墨汁)
+
+### ❌ 不兼容功能
+
+1. 【server】删除 弃用表 NODE_STAT
+2. 【server】删除 弃用表 SYSTEMMONITORLOG
+3. 【server】删除 相关表中的 strike 字段
+
+------
+
+## 2.10.24 (2023-03-01)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 在线构建容器镜像构建参数和镜像标签支持解析环境变量
+2. 【server】优化 替换环境变量,支持 $xxx ${xxx} (感谢@大锅饭集团)
+3. 【server】修复 配置节点分发白名单报错 (感谢@酱总)
+4. 【server】优化 节点分发配置【配置管理-白名单配置】菜单移动到功能管理中【项目管理-分发白名单】
+5. 【server】修复 非管理员无法使用 SSH 终端问题
+ (感谢 [@lilinLue](https://gitee.com/ljlToTlj) [Gitee issues I6IRJV](https://gitee.com/dromara/Jpom/issues/I6IRJV) )
+
+### ⚠️ 注意
+
+节点分发白名单可能失效,需要重新配置
+
+------
+
+## 2.10.23 (2023-03-01)
+
+### 🐣 新增功能
+
+1. 【server】新增 控制台输出工作空间关联数据错误未关联的表和条数
+2. 【server】新增 资产管理-SSH管理
+3. 【server】新增 构建 SSH 发布支持配置发布前执行命令 (感谢@daniel)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 使用 ANT 产物目录会自动生成模糊匹配表达式文件夹(感谢@leonchen21)
+2. 【server】修复 启动时候未自动触发修复数据逻辑
+3. 【server】修复 SSH 文件管理二级目录以下无法重命名
+4. 【server】优化 SSH 配置授权目录、允许编辑文件后缀、禁止命令移动到资产管理中
+5. 【all】优化 SSH文件、项目文件允许编辑文件的后缀支持配置 * (前提编辑格式统一)
+6. 【server】优化 升级 docker-java 、svnkit 依赖版本
+7. 【server】优化 SSH 支持清空隐藏字段
+
+### ⚠️ 注意
+
+由于新增 SSH 资产管理,之前ssh 配置如果引用的工作空间变量的配置信息可能将失效(作用域不同).
+如果仍需要变量信息还需要将对应的信息迁移到全局变量中才可以正常使用
+
+------
+
+## 2.10.22 (2023-02-24)
+
+### 🐣 新增功能
+
+1. 【server】新增 仓库新增配置超时属性(避免仓库拉取代码超时)(感谢 [@阿超](https://gitee.com/VampireAchao) )
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 容器构建无法下载产物(感谢@张飞鸿)
+
+------
+
+## 2.10.21 (2023-02-23)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 容器构建自动删除构建容器
+2. 【server】优化 系统管理菜单名:变更为`插件端配置`,`服务端配置` (感谢@ccx2480)
+3. 【server】修复 机器管理节点配置同步获取信息错乱(使用到服务端配置)(感谢@ccx2480)
+
+------
+
+## 2.10.20 (2023-02-23)
+
+### 🐞 解决BUG、优化功能
+
+1. 【agent】修复 插件端验证项目白名单路径失败(感谢@ccblandy)
+
+------
+
+## 2.10.19 (2023-02-22)
+
+### 🐣 新增功能
+
+1. 【server】新增 容器构建缓存插件支持按照 `path` 全局缓存 `type: global`
+2. 【server】新增 容器构建缓存插件支持缓存 node_modules `mode: copy`
+ (避免出现:[https://github.com/npm/cli/issues/3669](https://github.com/npm/cli/issues/3669))
+3. 【server】新增 构建列表新增批量构建
+ (感谢 [@爱笑的眼睛](https://gitee.com/175cm75kg18cm) [Gitee issues I6GNV2](https://gitee.com/dromara/Jpom/issues/I6GNV2) )
+4. 【server】新增 机器管理新增查看关联节点功能
+5. 【server】新增 机器新增网络、硬件硬盘查看
+6. 【server】新增 机器管理列表新增表格视图
+7. 【server】新增 手动分发文件、构建分发弹窗新增筛选指定项目进行分发
+ (感谢 [@Smith](https://gitee.com/autools) [Gitee issues I6GQNG](https://gitee.com/dromara/Jpom/issues/I6GQNG) )
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 构建读取附件环境变量时机调整到 pull 后
+2. 【agent】优化 白名单路径原样保存(避免部分安全组件拦截)
+3. 【server】修复 编辑机器分组名失效问题
+4. 【server】优化 工作空间菜单配置由系统管理移动到工作空间列表管理中
+5. 【server】优化 节点白名单配置分发功能移动到机器管理表格视图中(模板节点)
+6. 【server】优化 节点配置分发功能移动到机器管理表格视图中(模板节点)
+
+------
+
+## 2.10.18 (2023-02-20)
+
+### 🐣 新增功能
+
+1. 【server】新增 资产管理->机器管理
+2. 【server】新增 配置属性:jpom.node.stat-log-keep-days(节点统计日志保留天数)
+3. 【all】新增 机器节点硬盘信息统计
+4. 【all】新增 机器节点网络流量信息统计
+5. 【server】新增 构建触发器新增获取构建日志接口
+ (感谢 [@黑黑](https://gitee.com/c180) [Gitee issues I6G0AT](https://gitee.com/dromara/Jpom/issues/I6G0AT) )
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】更名 节点列表更名逻辑节点
+2. 【server】修复 节点分发编辑 webhook 字段回显(感谢@酱总)
+3. 【server】优化 在线升级统一机器管理(无需切换工作空间)
+4. 【server】优化 节点管理>在线升级菜单移动到机器管理中
+
+### ❌ 不兼容功能
+
+1. 【server】删除 node_info unLockType 字段
+2. 【server】取消 节点解绑功能
+3. 【server】停止 使用 NODE_STAT 表(暂时保留相关数据)
+4. 【server】替代 MACHINE_NODE_STAT_LOG 表替代 SYSTEMMONITORLOG 表(并暂时保留 SYSTEMMONITORLOG 数据)
+
+### ⚠️ 注意
+
+由于新增机器管理,程序将自动同步节点表中的所有数据`以节点地址去重`后保存到机器表中,如果同一个节点地址出现多条数据(节点存在不同的工作空间)将跟进节点更新时间最新的为准
+
+插件端需要同步更新,否则节点状态、机器状态为:`状态码错误`
+
+如果更新当前版本后出现节点授权码错误:可能原因是之前同一个机器添加多个节点到不同的工作空间并且最后更新的节点中保存的授权信息是错误,导致数据自动同步后仍然是错误的授权信息
+
+------
+
+## 2.10.17 (2023-02-16)
+
+### 🐣 新增功能
+
+1. 【server】新增 构建配置新增严格执行命令模式(判断命令执行状态码是否为0)
+ (感谢@阿克苏市姑墨信息科技有限公司) [Gitee pr 169](https://gitee.com/dromara/Jpom/pulls/169) )
+2. 【server】新增 节点分发新增 webhook 配置属性(感谢@酱总)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 构建产物配置单属性时,二次匹配不能匹配到文件问题
+ (感谢 [@伤感的风铃草](https://gitee.com/bwy-flc) [Gitee issues I6FETS](https://gitee.com/dromara/Jpom/issues/I6FETS) )
+2. 【server】优化 构建历史回滚输出相关操作日志(感谢@酱总)
+3. 【server】修复 windows 容器构建无法上传文件到容器问题
+
+------
+
+## 2.10.16 (2023-02-14)
+
+### 🐣 新增功能
+
+1. 【server】新增 docker 列表支持跨工作空间同步
+ (感谢 @[清风柳絮II号](https://gitee.com/zhangfeihong_597) [Gitee issues I6EOIR](https://gitee.com/dromara/Jpom/issues/I6EOIR) )
+2. 【server】新增 构建历史保存构建环境变量(为回滚流程使用)
+
+### 🐞 解决BUG、优化功能
+
+1. 【all】优化 解压工具支持多种编码格式(GBK、UTF8)(感谢@Again... . )
+2. 【server】优化 在线构建新增配置文件环境变量测试(`BUILD_CONFIG_BRANCH_NAME`)(感谢@阿克苏市姑墨信息科技有限公司)
+3. 【server】修复 节点分发回滚 NPE (感谢@酱总)
+4. 【server】优化 构建弹窗部分下拉支持手动刷新数据(感谢@张飞鸿)
+
+------
+
+## 2.10.15 (2023-02-13)
+
+### 🐣 新增功能
+
+1. 【server】新增 构建 pull 流程之后新增 `BUILD_COMMIT_ID` 变量
+2. 【server】新增 执行脚本输出可用环境变量(服务端脚本、节点脚本、SSH 脚本、在线构建 pull 成功之后、构建事件脚本)
+3. 【server】新增 构建确认弹窗新增配置构建环境变量
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 节点分发二级路径不能删除问题(感谢@张飞鸿)
+2. 【agent】优化 服务端环境隐私变量字段传递到插件端(已经存在的插件端环境变量默认为隐私变量)
+3. 【agent】修复 DSL 项目模式 status 事件写入日志编码格式跟随系统配置,避免编码格式不正确(已经存在的日志文件可能会乱码,可以删除文件解决)
+4. 【server】优化 提前构建加载附加环境变量(startReady 事件)
+5. 【agent】优化 节点进程列表、内存、cpu、硬盘加载方式采用 oshi
+6. 【server】优化 在线升级页面新版本检测支持本地网络检测
+
+### ⚠️ 注意
+
+插件端需要同步更新,否则节点首页进程列表数据将不能正常显示
+
+------
+
+## 2.10.14 (2023-02-10)
+
+### 🐣 新增功能
+
+1. 【server】新增 构建状态新增`构建中断`(执行事件脚本返回中断构建)
+2. 【server】新增 构建事件脚本支持返回指定关键词中断构建(需要执行事件脚本输出的最后一行,`interrupt $type`)
+3. 【server】新增 构建触发器将请求参数传入构建环境变量(`triggerContentType`、`triggerBodyData`)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 构建产物为文件夹打包位置优化(避免存放位置错乱)
+2. 【server】修复 构建触发修改构建产物路径未验证 slip 问题
+3. 【server】优化 本地构建产物模糊匹配(ant path)支持配置截取路径、合并文件
+4. 【server】优化 构建日志输出信息(部分调整为中文、消息标签和级别)
+5. 【server】优化 切换工作空间刷新菜单(感谢@ccx2480)
+6. 【server】优化 用户密码提示改为弹窗并且可以快捷复制
+7. 【agent】修复 保存 DSL 项目判断是否存在 status 节点,避免无法删除情况(感谢@张飞鸿)
+8. 【agent】修复 节点项目修改路径移动文件不生效问题
+9. 【agent】取消 编辑项目校验目录存在情况
+10. 【server】优化 项目ID、节点分发ID 支持前端快捷生成
+11. 【server】优化 构建执行事件脚本描述匹配支持 all 关键词 (匹配所有事件)
+12. 【server】修复 执行脚本文件的换行符合跟随系统,避免 windows 中出现异常
+13. 【server】优化 解绑操作提示弹窗更明确(减少误操作)(感谢@酱总)
+
+### ⚠️ 注意
+
+如果使用到产物模糊匹配的请关注是否需要重新调整匹配符。
+
+新版本匹配符支持配置三个属性:
+
+属性1:属性2[可选]:属性3[可选]
+
+**属性1**:为模糊匹配的表达式 ( `Ant-style` )
+
+**属性2**:匹配到的文件保留方式,可用值:`KEEP_DIR`、`SAME_DIR`。(大小写均兼容、配置错误默认为 KEEP_DIR)
+
+KEEP_DIR: 保留匹配到的文件的文件层级
+
+SAME_DIR: 将匹配到的文件均保留到同一个层级(合并到一个文件夹下)。慎用该方式,如果多目录存在相同的文件名会出现合并后只保留匹配到的最后一个文件
+
+**属性3**: 需要剔除匹配到多级文件夹的指定目录,(可以配置为空)。建议配合属性2的`KEEP_DIR`使用。剔除目录可以理解为二次过滤前缀匹配文件
+
+#### 🌰 举个栗子
+
+##### 栗子1: `/web*/**/*.html:KEEP_DIR:/web2/`
+
+表示匹配执行构建后,对应目录下的:已 web 开头的目录下面的所有 html 文件,并且保留文件夹层级关系,最后发布时候需要剔除 /web2/
+
+假设:目录下有如下文件
+
+```log
+/vue/vue.html
+/web/web1.html
+/a/b/t.html
+/web2/a.html
+/web2/b/a.html
+/web1/aa/t.html
+```
+
+执行匹配后的文件
+
+```log
+a.html
+/b/a.html
+```
+
+##### 栗子2: `/web*/**/*.html:SAME_DIR:`
+
+表示匹配执行构建后,对应目录下的:已 web 开头的目录下面的所有 html 文件,并且合并文件到同一个目录,最后发布时候需要剔除
+/web2/
+
+假设:目录下有如下文件
+
+```log
+/vue/vue.html
+/web/web1.html
+/a/b/t.html
+/web2/a.html
+/web2/b/a.html
+/web1/aa/t.html
+```
+
+执行匹配后的文件
+
+```log
+web1.html
+a.html
+t.html
+```
+
+##### 栗子3: `/web*/**/*.html:KEEP_DIR:`
+
+表示匹配执行构建后,对应目录下的:已 web 开头的目录下面的所有 html 文件,并且保留文件夹层级关系,最后发布时候按照原目录结构发布
+
+假设:目录下有如下文件
+
+```log
+/vue/vue.html
+/web/web1.html
+/a/b/t.html
+/web2/a.html
+/web2/b/a.html
+/web1/aa/t.html
+```
+
+执行匹配后的文件
+
+```log
+/web/web1.html
+/web2/a.html
+/web2/b/a.html
+/web1/aa/t.html
+```
+
+------
+
+## 2.10.13 (2023-02-08)
+
+### 🐣 新增功能
+
+1. 【server】新增 项目支持配置分组属性,方便项目列表筛选
+ (感谢 @[hjk2008](https://gitee.com/hjk2008) [Gitee issues I63PEN](https://gitee.com/dromara/Jpom/issues/I63PEN) )
+2. 【server】新增 节点分发支持配置分组属性,方便列表筛选
+3. 【agent】新增 DSL 项目支持配置自定义备份路径
+ (感谢 @[陈旭](https://gitee.com/chenxu8989) [Gitee issues I57ZKJ](https://gitee.com/dromara/Jpom/issues/I57ZKJ) )
+
+### 🐞 解决BUG、优化功能
+
+1. 【all】修复 linux 无法正常安装 service (感谢@山上雪)
+2. 【server】优化 构建的节点分发模式增加二级目录
+ (感谢 [@爱琳琳真是太好了](https://gitee.com/qiqi513_admin) [Gitee issues I6DNMX](https://gitee.com/dromara/Jpom/issues/I6DNMX) )
+3. 【server】优化 构建不保留产物时自动删除产物为目录时的压缩包文件
+4. 【server】优化 构建状态等待`节点分发`完成(阻塞执行节点分发)
+5. 【server】修复 构建选择`节点分发`并关闭`保留产物`,会导致分发失败。
+ (感谢 [@爱琳琳真是太好了](https://gitee.com/qiqi513_admin) [Gitee issues I6DII6](https://gitee.com/dromara/Jpom/issues/I6DII6) )
+6. 【server】修复 构建分发为`节点分发`,产物为文件时导致的不能回滚
+ (感谢 [@Smith](https://gitee.com/mrsmith) [Gitee issues I6DNSM](https://gitee.com/dromara/Jpom/issues/I6DNSM) )
+7. 【server】优化 定时构建支持配置禁用表达式,方便临时关闭定时执行
+ (感谢 [@阿超](https://gitee.com/VampireAchao) [Gitee issues I6DNBW](https://gitee.com/dromara/Jpom/issues/I6DNBW) )
+8. 【server】修复 DSL 项目配置文件备份数量不生效问题
+
+### ⚠️ 注意
+
+Linux 环境 已经安装的需要手动更新一下服务管理脚本
+
+**服务端**:(需要到安装目录的 bin 下执行)
+
+```shell
+curl -LfsSo Service.sh https://gitee.com/dromara/Jpom/raw/master/modules/server/src/main/bin/Service.sh
+```
+
+**插件端** :(需要到安装目录的 bin 下执行)
+
+```shell
+curl -LfsSo Service.sh https://gitee.com/dromara/Jpom/raw/master/modules/agent/src/main/bin/Service.sh
+```
+
+------
+
+## 2.10.12 (2023-01-29)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 在线终端断开连接时提醒并支持重连
+2. 【server】修复 线程同步器,避免任务过多造成线程数不可控(节点分发相关功能)
+3. 【server】优化 前端打包取消 .map 文件,缩少发布包大小
+ (感谢 [@金技](https://gitee.com/jinjiG) [Gitee issues I6AK0N](https://gitee.com/dromara/Jpom/issues/I6AK0N) )
+4. 【all】优化 分片上传文件名采用分片序号(伪装文件后缀)(感谢@冷月)
+5. 【all】优化 分片上传文件签名由 sha1 改为 md5 提升效率
+6. 【server】优化 构建历史页面鼠标移到名称下拉项显示文字
+ (感谢 [@伤感的风铃草](https://gitee.com/bwy-flc) [Gitee pr 167](https://gitee.com/dromara/Jpom/pulls/167) )
+7. 【all】修复 日志监听器 catch 异常日志造成会话未自动删除问题
+ (感谢 [@金技](https://gitee.com/jinjiG) [Gitee issues I6A5QW](https://gitee.com/dromara/Jpom/issues/I6A5QW) )
+8. 【server】修复 仓库地址 https 证书验证问题(自动忽略验证)
+ (感谢 [@arstercz](https://github.com/arstercz) [Github issues 32](https://github.com/dromara/Jpom/issues/32) )
+
+### ⚠️ 注意
+
+1. 插件端需要同步升级,否则不能正常使用节点上传文件相关功能
+
+------
+
+## 2.10.11 (2023-01-10)
+
+### 🐣 新增功能
+
+1. 【server】新增 系统缓存新增分片操作数查看
+2. 【server】新增 节点分片上传支持配置并发数:`jpom.node.upload-file-concurrent`
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 迁移数据添加更多日志输出
+2. 【server】优化 分片上传解析文件数据采用分片形式,避免大文件造成浏览器奔溃
+3. 【server】优化 插件端在线升级管理页面错误信息提示由弹窗改到对应节点
+4. 【server】修复 迁移数据出现监控报警记录表字段不全问题 (感谢@loyal)
+5. 【server】修复 迁移系统参数表中的 sync_trigger_token 数据重复问题(感谢@loyal)
+6. 【server】优化 取消迁移数据忽略处理(避免默认工作空间名称不迁移)(感谢@loyal)
+7. 【server】优化 获取项目运行状态失败弹窗提醒改为单条数据异常提醒
+8. 【server】优化 服务端项目管理项目列表获取运行状态改为并发执行,缩短加载时间
+9. 【server】优化 分片上传文件中文件选择器禁用
+
+### ❌ 不兼容功能
+
+1. 【server】取消 监控记录实体中的 logId 字段 (感谢@loyal)
+2. 【all】取消 启动时候判断重复启动
+
+------
+
+## 2.10.10 (2023-01-09)
+
+### 🐣 新增功能
+
+1. 【all】新增 在线升级是否允许降级操作配置属性`jpom.system.allowed-downgrade`
+2. 【server】新增 分发整体状态新增`分发失败`
+3. 【server】新增 构建日志显示进度折叠率配置:`jpom.build.log-reduce-progress-ratio`
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 mysql 环境非`allowMultiQueries`初始化表结构失败(感谢@丿幼儿园逃犯)
+2. 【server】修复 部分表字段缺失问题(strike)
+3. 【server】优化 迁移数据到 mysql 字段大小写跟随实体(感谢@丿幼儿园逃犯)
+4. 【server】修复 导入数据库备份文件目录不存在时报错(感谢@丿幼儿园逃犯)
+5. 【all】优化 节点上传项目文件采用分片上传、并且支持进度显示
+6. 【all】优化 在线升级上传项目包采用分片上传、并且支持进度显示
+7. 【all】优化 在线升级,默认禁止降级操作
+8. 【server】优化 节点分发上传文件采用分片上传、并且支持进度显示
+9. 【server】优化 分发单项的状态信息存储于日志记录中(取消 json 字段存储)
+10. 【server】优化 节点分发子项展示逻辑(同步改异步加载,避免长时间加载)
+11. 【server】优化 构建日志输出各个流程耗时
+12. 【server】优化 构建发布项目文件采用分片上传、并且支持进度显示
+13. 【agent】优化 配置文件中上传文件大小限制由 1G 改为 10MB 节省插件端占用内存大小(采用分片代替)
+14. 【server】优化 手动上传的节点分发文件将自动删除,节省存储空间
+15. 【server】优化 节点分发日志支持显示进度信息
+
+### ⚠️ 注意
+
+1. 插件端需要同步升级,否则节点分发项目无法显示项目名称
+2. 插件端需要同步升级,否则会出现部分接口 404 或者参数不正确的情况
+3. 建议升级验证上传项目文件无问题后,将插件端上传文件大小限制配置属性大改小
+ 1. spring.servlet.multipart.max-file-size=5MB
+ 2. spring.servlet.multipart.max-request-size=20MB
+
+**如果需要使用 mysql 存储,则需要修改配置**
+
+1. 修改 `jpom.db.mode` 为 `MYSQL`
+2. 修改 `jpom.db.url` 为您 mysql 的 jdbc 地址( jdbc:mysql://127.0.0.1:
+ 3306/jpom?useUnicode=true&characterEncoding=UTF-8&useSSL=false)
+3. 修改 `jpom.db.user-name` 为对应 mysql 账户
+4. 修改 `jpom.db.user-pwd` 为对应 mysql 密码
+
+如果您需要迁移之前 h2 数据库中的数据到 mysql(需要先将 mysql 的连接信息配置好后才能迁移)
+
+```shell
+bash ./bin/Server.sh restart -15 --h2-migrate-mysql --h2-user=jpom --h2-pass=jpom
+
+```
+
+------
+
+## 2.10.9 (2023-01-06)
+
+### 🐣 新增功能
+
+1. 【server】新增 服务端数据存储支持 mysql
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 在线编辑配置文件报错并修改数据库密码问题
+2. 【server】~~三次修复~~ 在线终端输入部分字符后自动断开连接问题
+3. 【server】升级 svnkit 依赖版本
+4. 【server】优化 docker 标签查询精准查询
+5. 【server】更名 阅读文件更名为跟踪文件
+
+### ❌ 不兼容功能
+
+1. 【server】删除 数据库中多个数据表中弃用字段
+
+### ⚠️ 注意
+
+如果需要使用 mysql 存储,则需要修改配置:
+
+1. 修改 `jpom.db.mode` 为 `MYSQL`
+2. 修改 `jpom.db.url` 为您 mysql 的 jdbc 地址( jdbc:mysql://127.0.0.1:
+ 3306/jpom?useUnicode=true&characterEncoding=UTF-8&useSSL=false)
+3. 修改 `jpom.db.user-name` 为对应 mysql 账户
+4. 修改 `jpom.db.user-pwd` 为对应 mysql 密码
+
+如果您需要迁移之前 h2 数据库中的数据到 mysql(需要先将 mysql 的连接信息配置好后才能迁移)
+
+```shell
+bash ./bin/Server.sh restart -15 --h2-migrate-mysql --h2-user=jpom --h2-pass=jpom
+
+```
+
+------
+
+## 2.10.8 (2023-01-05)
+
+### 🐞 解决BUG、优化功能
+
+1. 【all】优化 程序运行的 tmp 文件夹(`java.io.tmpdir`)跟随项目目录
+2. 【all】优化 判断目录越级 `checkSlip` 目录转义至 tmpdir,避免在用户目录生成空白文件夹
+
+### ❌ 不兼容功能
+
+1. 【all】取消 程序启动写入全局临时信息
+2. 【server】取消 服务端没有节点自动探测本地节点功能
+
+### ⚠️ 注意
+
+Linux、Windows 环境 已经安装 2.10.0 ~ 2.10.7 的需要手动更新一下管理脚本
+
+> 建议先更新脚本再升级插件端或者服务端
>
-> > 1. 在 Server 端找到 Server.sh 文件,执行命令 `./Server.sh create`,会在当前目录下生成 jpom-server 文件,这个文件就是 Server 端的自启动的文件
-> > 2. 在 Agent 端找到 Agent.sh 文件,执行命令 `./Agent.sh create`,会在当前目录下生成 jpom-agent 文件,这个文件就是 Agent 端的自启动的文件
-> > 3. 把刚刚生成的自启动文件移动到 /etc/init.d/ 目录
-> > 4. 到 /etc/init.d/ 目录让自启动文件拥有执行权限,执行命令 `chmod +x jpom-server` 或者 `chmod +x jpom-agent`
-> > 5. 注册到 chkconfig 列表里面,就可以实现开机自启,执行命令 `chkconfig --add jpom-server` 或者 `chkconfig --add jpom-agent`
-> > 6. 执行完第 4 步就可以通过 `service jpom-xxx {status | start | stop}` 来管理 Jpom 服务
-> > 7. 目前仅通过 Cent OS 服务器测试,其他服务器可能会无效
+> Windows 用户需要自行下载脚本替换
------------------------------------------------------------
+**服务端**:(需要到安装目录的 bin 下执行)
-# 2.5.0
+```shell
+curl -LfsSo Server.sh https://gitee.com/dromara/Jpom/raw/master/modules/server/src/main/bin/Server.sh
+```
-### 新增功能
+**插件端** :(需要到安装目录的 bin 下执行)
-1. 【server】接入全局 loading 控件
-2. 【server】默认进入新版UI
+```shell
+curl -LfsSo Agent.sh https://gitee.com/dromara/Jpom/raw/master/modules/agent/src/main/bin/Agent.sh
+```
+
+------
-### 解决BUG、优化功能
+## 2.10.7 (2023-01-04)
-1. 【Server】fix bug: ssh 列表页面编辑弹窗无法加载(当没有设置文件目录时)
-2. 【Server】fix bug: 分发列表,项目运行状态显示错误
-3. 【Server】fix bug:第一次安装未能正常打开初始化账号密码页面
-4. 【server】fix bug: 独立分发项目编辑时,jvm args 等参数不会回显
-5. 【server】fix: 点击构建自动打开构建日志、构建日志弹窗自动滚动到底部
-6. 【server】add: index.html 添加打包时间
-7. 【server】fix bug:添加、编辑用户原始密码进行了sha1
-8. 【server】add: 添加构建历史回滚操作(感谢@李道甫)
-9. 【server】add: 添加项目文件管理页面上传压缩文件(感谢@李道甫)
-10. 【server】fix bug: 文件上传时显示上传进度(感谢@李道甫)
-11. 【server】fix bug: 项目文件管理的侧边文件树优化(感谢@李道甫)
-12. 【server】fix: 控制台日志弹窗自动滚动到底部(感谢@南有乔木)
-13. 【server】add: File方式创建项目 项目控制台互调(感谢@李道甫 贡献)
-13. 【server】add: 分发提示修改 分发项目显示 (感谢@李道甫 贡献)
+### 🐣 新增功能
-> 注意:目前新版本登录状态采用固定 token 模式,登录后将一直保持在线状态,如需要退出或者离线需要进行退出登录操作。(该问题将于后面版本进行优化调整)
+1. 【server】新增 配置管理新增配置目录在线编辑功能
+2. 【server】新增 容器构建新增 `ubuntu-git` 镜像
------------------------------------------------------------
+### 🐞 解决BUG、优化功能
-# 2.4.0 ~ 2.4.9 版本日志
+1. 【server】修复 在线终端输入部分字符后自动断开连接问题(感谢 @Again.... )
+2. 【server】修复 执行 SSH 脚本未正常加载环境变量问题
+3. 【server】修复 快速安装(绑定)插件端的命令特殊字符转义问题 (感谢@张飞鸿)
+4. 【server】优化 节点在线升级确认操作提醒要升级的目标版本号(感谢@木迷榖)
+5. 【server】优化 modal 弹窗新增 destroyOnClose , 优化页面卡顿和组件样式冲突
+6. 【server】修复 windows nginx 配置文件编辑白名单路径非绝对路径时出现名称错误
-[https://gitee.com/dromara/Jpom/blob/master/docs/changelog/2.4.x.md](https://gitee.com/dromara/Jpom/blob/master/docs/changelog/2.4.x.md)
+### ❌ 不兼容功能
+
+1. 【server】下架 构建配置管理功能(请使用配置目录管理功能代替)
+
+------
------------------------------------------------------------
+## 2.10.6 (2022-12-29)
-# 2.3.1 ~ 2.3.2 版本日志
+### 🐣 新增功能
-[https://gitee.com/dromara/Jpom/blob/master/docs/changelog/2.3.x.md](https://gitee.com/dromara/Jpom/blob/master/docs/changelog/2.3.x.md)
+1. 【agent】新增 上传项目文件,下载远程文件 压缩包支持自动剔除文件夹
+2. 【server】新增 节点分发新增手动取消分发任务功能
+ (感谢 [@gxw](https://gitee.com/yinxianer) [Gitee issues I61SBB](https://gitee.com/dromara/Jpom/issues/I61SBB) )
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 SSH 终端 JSCH 新增日志实现,方便排查问题
+2. 【agent】优化 部分下载接口取消返回值,避免控制台出现错误日志
+3. 【server】优化 服务端代理插件端的 websocket 超时问题
+4. 【server】修复 在线终端输入部分字符后自动断开连接问题(感谢 @Again.... )
+5. 【server】修复 部分下拉框无法正常搜索文件(感谢 @Again.... )
+6. 【agent】优化 同时上传相同的文件名时可能异常
+7. 【server】优化 节点分发状态新增(等待分发、手动取消状态)
+8. 【server】修复 状态为未分发时分发失败引起的状态错误
+
+------
+
+## 2.10.5 (2022-12-27)
+
+### 🐣 新增功能
+
+1. 【server】新增 操作日志新增数据名称字段
+
+### 🐞 解决BUG、优化功能
+
+1. 【agent】修复 项目文件夹不存在时不能下载远程文件
+2. 【all】升级 fastjson 升级为 fastjson2
+3. 【all】升级 SpringBoot 2.7.7 、commons-compress
+4. 【server】移除 空闲依赖 jaxb-api
+5. 【all】优化 启动加载流程,保存顺序加载
+6. 【all】修复 启动成功写入全局信息由于没有权限造成的异常
+ (感谢 [@LeonChen21](https://gitee.com/leonchen21) [Gitee issues I67C3C](https://gitee.com/dromara/Jpom/issues/I67C3C) )
+7. 【server】优化 websocket 控制台操作日志记录
+8. 【server】修复 超级管理的 websocket 操作日志记录工作空间不正确
+9. 【agent】优化 插件端删除 spring-boot-starter-websocket 依赖
+10. 【server】优化 服务端删除 Java-WebSocket 依赖(采用统一模块管理)
+11. 【server】修复 更新构建状态互斥,避免状态被异步更新冲突
+12. 【server】优化 下载文件采用标签页面形式取消 blob
+
+### ❌ 不兼容功能
+
+1. 【server】取消 兼容低版本插件端的 websocket 授权信息传输方式(低版本插件端请同步升级到最新)
+2. 【server】取消 服务端取消向插件端传递操作人的用户名
+3. 【server】取消 服务端数据库用户操作日志表对 REQID 字段兼容(2.9.1 以下)
+
+------
------------------------------------------------------------
+## 2.10.4 (2022-12-23)
-# 2.0 ~ 2.2 版本日志
+### 🐞 解决BUG、优化功能
+
+1. 【all】修复 linux 管理脚本中的 pid 文件内容与真实进程不一致问题
+2. 【all】恢复 linux 管理脚本支持创建服务管理
+
+### ⚠️ 注意
+
+Linux 环境 已经安装 2.10.3 ~ 2.10.0 的需要手动更新一下管理脚本
+
+> 需要`创建服务来管理`的需要更新后才能正常使用在线升级和保存配置并重启
+
+> 建议先更新脚本再升级插件端或者服务端
+
+**服务端**:(需要到安装目录的 bin 下执行)
+
+```shell
+curl -LfsSo Server.sh https://gitee.com/dromara/Jpom/raw/master/modules/server/src/main/bin/Server.sh
+```
+
+```shell
+curl -LfsSo Service.sh https://gitee.com/dromara/Jpom/raw/master/modules/server/src/main/bin/Service.sh
+```
+
+**插件端** :(需要到安装目录的 bin 下执行)
+
+```shell
+curl -LfsSo Agent.sh https://gitee.com/dromara/Jpom/raw/master/modules/agent/src/main/bin/Agent.sh
+```
+
+```shell
+curl -LfsSo Service.sh https://gitee.com/dromara/Jpom/raw/master/modules/agent/src/main/bin/Service.sh
+```
+
+------
+
+## 2.10.3 (2022-12-22)
+
+### 🐣 新增功能
+
+1. 【server】新增 在线构建新增 `packageFile` 流程 编译 webhook 或者事件脚本调用
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 快速导入节点工作空间id `undefined`
+2. 【server】修复 本地运行脚本默认找不到的情况
+3. 【agent】优化 项目控制台日志文件默认编码格式判断系统 windows 默认 GBK,其他默认 UTF-8
+ (感谢 [@gf_666](https://gitee.com/gf_666) [Gitee issues I66ZZZ](https://gitee.com/dromara/Jpom/issues/I66ZZZ) )
+4. 【server】优化 在线构建 ssh 清空产物异常不标记发布异常
+
+### ⚠️ 注意
+
+Linux 环境 已经安装 2.10.2 ~ 2.10.0 的需要手动更新一下管理脚本,之前管理脚本存在部分场景日志输出错乱的问题
+
+> 建议先更新脚本再升级插件端或者服务端
+
+**服务端**:(需要到安装目录的 bin 下执行)
+
+```shell
+curl -LfsSo Server.sh https://gitee.com/dromara/Jpom/raw/master/modules/server/src/main/bin/Server.sh
+```
+
+**插件端** :(需要到安装目录的 bin 下执行)
+
+```shell
+curl -LfsSo Agent.sh https://gitee.com/dromara/Jpom/raw/master/modules/agent/src/main/bin/Agent.sh
+```
+
+------
+
+## 2.10.2 (2022-12-21)
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】节点快速安装命令示例提供默认安装命令
+2. 【server】修复 docker 插件未正常加载问题(感谢@顺子)
+3. 【server】优化 本地构建命令执行方式由逐行改为脚本执行
+4. 【server】修复 构建未配置 webhook 控制台报错
+5. 【server】修复 构建未配置 webhook 不触发事件脚本
+
+### ❌ 不兼容功能
+
+1. 【server】下架 SSH 上传文件安装插件端方式,采用快速安装命令代替
+2. 【server】取消 构建命令和本地命令发布 不支持 #{} 变量替换
+3. 【server】取消 SSH 命令模板 不支持 #{} 变量替换(仅支持 ${} 替换)
+
+------
+
+## 2.10.1 (2022-12-20)
+
+### 🐣 新增功能
+
+1. 【server】新增 节点项目支持快速复制操作
+ (感谢[@mt-mored](https://gitee.com/mt-mored) [Gitee issues I653O3](https://gitee.com/dromara/Jpom/issues/I653O3) )
+2. 【all】新增 节点项目、独立节点分发支持彻底删除
+3. 【agent】新增 DSL 项目模式执行脚本支持节点环境变量
+ (感谢[@苏生不语](https://gitee.com/sushengbuyu) [Gitee issues I66MNP](https://gitee.com/dromara/Jpom/issues/I66MNP) )
+4. 【all】新增 构建项目发布、节点分发支持配置发布前先停止(避免 windows 环境文件被占用)
+ (感谢 [@yiziyu](https://gitee.com/yiziyu) [Gitee issues I65MS1](https://gitee.com/dromara/Jpom/issues/I65MS1)、[@all-around-badass](https://gitee.com/all-around-badass) [Gitee issues I66PYU](https://gitee.com/dromara/Jpom/issues/I66PYU) )
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】优化 节点分发菜单更名为项目管理
+2. 【server】优化 节点分发添加项目限制数量由 2 调整为 1
+ (感谢[@苏生不语](https://gitee.com/sushengbuyu) [Gitee issues I66R73](https://gitee.com/dromara/Jpom/issues/I66R73) )
+3. 【server】修复 节点分发手动上传文件二级目录出现 `undefined`
+4. 【agent】修复 默认项目模式执行命令存在 `null` 字符串
+5. 【server】修复 初次安装服务端初始化数据库失败问题 (感谢@lg)
+6. 【server】优化 日志显示组件(取消正则搜索),日志删除 `ansi` 颜色
+ (感谢[@苏生不语](https://gitee.com/sushengbuyu) [Gitee issues I657JR](https://gitee.com/dromara/Jpom/issues/I657JR) )
+7. 【server】优化 编辑组件可能出现行错和内容错乱问题
+8. 【server】优化 查看系统日志的多次切换内容返回错乱问题
+
+### ❌ 不兼容功能
+
+1. 【agent】取消 DSL 项目脚本的 #{} 替换变量
+
+### ⚠️ 注意
+
+Linux 环境 已经安装 2.10.0 的需要手动更新一下管理脚本,2.10.0 管理脚本存在在线升级和在线重启日志输出重复问题
+
+> 建议先更新脚本再升级插件端或者服务端
+
+**服务端**:(需要到安装目录的 bin 下执行)
+
+```shell
+curl -LfsSo Server.sh https://gitee.com/dromara/Jpom/raw/master/modules/server/src/main/bin/Server.sh
+```
+
+**插件端** :(需要到安装目录的 bin 下执行)
+
+```shell
+curl -LfsSo Agent.sh https://gitee.com/dromara/Jpom/raw/master/modules/agent/src/main/bin/Agent.sh
+```
+
+------
+
+## 2.10.0 (2022-12-19)
+
+### 🐣 新增功能
+
+1. 【all】外置 `logback` 配置文件
+2. 【server】服务端管理相关功能独立页面菜单
+3. 【server】新增项目触发器用于管理项目状态
+4. 【all】新增 构建项目发布支持配置发布到二级目录
+5. 【server】新增 节点分发发布支持配置发布到二级目录
+
+### 🐞 解决BUG、优化功能
+
+1. 【all】启动相关信息由控制台输出改为 `logback`
+2. 【all】节点管理中 `其他功能` 菜单更名为 `脚本管理`
+3. 【all】优化版本升级修改管理脚本里变量,采用文件记录方式
+4. 【server】优化容器启动脚本,支持监听进程已经终端重启操作
+5. 【server】修复 自动刷新页面已经关闭的标签页,后台仍然在发送请求
+ (感谢[@苏生不语](https://gitee.com/sushengbuyu) [Gitee issues I664OP](https://gitee.com/dromara/Jpom/issues/I664OP) )
+6. 【server】修正触发器说明错别字
+
+### ❌ 不兼容功能
+
+1. 【server】取消支持 2.8.0 以下 json 文件转存数据库
+2. 【all】下架 JDK 管理模块(请使用 DSL 项目模式代替)
+3. 【all】下架 TOMCAT 管理模块(请使用 DSL 项目模式代替)
+4. 【all】删除 项目内存监控页面
+5. 【all】配置文件名称由 `extConfig.yml` 变更为 `application.yml`
+6. 【all】调整项目打包目录结构
+7. 【all】取消兼容低版本数据目录文件迁移(调试运行)
+8. 【all】取消自动识别文件编码格式模块 `auto-charset-jchardet`
+9. 【all】更新管理脚本,进程标识更新(已经存在的需要手动停止)
+10. 【all】取消插件端配置化向服务端注册功能(采用快速导入方式替代)
+11. 【server】取消服务端授权 token 配置
+12. 【all】下架 节点脚本导入功能
+13. 【server】取消限制创建用户最大数配置:`user.maxCount`
+14. 【server】删除 node_info 表 cycle 字段
+15. 【agent】删除项目回收记录功能
+
+### ❌ 不兼容的属性配置变更
+
+> 属性配置支持驼峰和下划线
+
+1. 【agent】`whitelistDirectory.checkStartsWith` -> `jpom.whitelist-directory.check-starts-with`
+2. 【agent】`project.stopWaitTime` -> `jpom.project.statusWaitTime`
+3. 【agent】`project.*` -> `jpom.project.*`
+4. 【agent】修正拼写错误 `log.*back*` -> `jpom.project.log.*backup*`
+5. 【agent】`log.*` -> `jpom.project.log.*`
+6. 【agent】`log.intiReadLine` -> `jpom.init-read-line`
+7. 【agent】 `log.autoBackConsoleCron` 不支持配置 none (none 使用 `jpom.project.log.autoBackupToFile` 代替)
+8. 【all】删除 `consoleLog.reqXss` 、`consoleLog.reqResponse`
+9. 【all】`consoleLog.charset` -> `jpom.system.console-charset`
+10. 【server】`node.uploadFileTimeOut` -> `jpom.node.uploadFileTimeout`
+11. 【server】`system.nodeHeartSecond` -> `jpom.node.heartSecond`
+12. 【server】`user.*` -> `jpom.user.*`
+13. 【server】`jpom.authorize.expired` -> `jpom.user.tokenExpired`
+14. 【server】`jpom.authorize.renewal` -> `jpom.user.tokenRenewal`
+15. 【server】`jpom.authorize.key` -> `jpom.user.tokenJwtKey`
+16. 【server】`jpom.webApiTimeout` -> `jpom.web.api-timeout`
+17. 【server】删除 `ssh.initEnv`
+18. 【server】批量修正前端相关配置属性均修改到 `jpom.web.*`
+19. 【server】`db.*` -> `jpom.db.*`
+20. 【server】`build.*` -> `jpom.build.*`
+
+### ⚠️ 注意
+
+> 此版本为不兼容升级,需要手动升级修改相关配置才能正常使用
+
+#### 简洁的升级流程
+
+1. 停止正在运行的程序插件端或者服务端
+2. 备份已经存在的插件端或者服务端的数据目录
+3. 手动安装新版本 `2.10.0+`
+4. 还原数据:将备份的数据目录迁移到新安装的数据目录(需要再未运行的状态下操作)
+5. 重启程序
+
+详细的升级文档:[https://jpom.top/pages/upgrade/2.9.x-to-2.10.x/](https://jpom.top/pages/upgrade/2.9.x-to-2.10.x/)
+
+------
-[https://gitee.com/dromara/Jpom/blob/master/docs/changelog/2.x.md](https://gitee.com/dromara/Jpom/blob/master/docs/changelog/2.x.md)
\ No newline at end of file
diff --git a/CLA.md b/CLA.md
new file mode 100644
index 0000000000..e2ef18753d
--- /dev/null
+++ b/CLA.md
@@ -0,0 +1,86 @@
+# Jpom 贡献者许可协议
+
+感谢您对 Jpom 项目(“社区”或者“我们”)拥有及/或管理的开源项目(“项目”)的关注,请完整、仔细、充分阅读本《贡献者许可协议》(“协议”)后,在对协议项下条款均无异议的前提下,签署本协议。
+
+**提交贡献即认为签署了本协议,若对本协议有异议,请勿提交贡献。**
+
+为确保社区及项目合法合规,同时也避免侵犯任何人士的合法权益,我们希望确保:
+(1)您对您所提交的贡献具有完整充分的合法权利;
+(2)您的提交行为合法且不侵权。
+
+您在提交贡献后,仍然对贡献享有应有的合法权利。您不会因为提交贡献而承担任何未约定的义务。
+
+## 一、定义
+
+为本协议之目的,除非上下文另有说明,本协议中用语分别具有本条所指含义:
+1.1 “中国”指中华人民共和国。
+
+1.2 “法律”包括但不限于任何适用的法典、法律、法规、规章、司法解释及规范性文件,包括但不限于《中华人民共和国著作权法》(“著作权法”)、《中华人民共和国计算机软件保护条例》、《中华人民共和国专利法》(“专利法”)。如无特别说明或者其他约定,本协议项下争议优先适用中国法律。
+
+1.3 “社区”或“我们”指 Jpom 项目。
+
+1.4 “项目”指社区拥有及/或管理的项目,包括但不限于软件、软件所包含的程序、代码、文字、图片、图形、文档或者其他信息。于本协议签署之日,项目托管于Gitee [https://gitee.com/dromara/Jpom](https://gitee.com/dromara/Jpom),托管地址今后可能随实际情况发生变化,具体访问地址以社区实时公布为准。
+
+1.5 “贡献者”指签署本协议并向社区提交贡献的任何自然人、法人、其他组织以及法律规定的其他主体。
+
+1.6 “贡献”指由贡献者根据本协议向社区提交的任何程序、代码、文字、图片、图形、文档或者其他作品。
+
+1.7 “提交”指将“贡献”通过电子邮件或者其他形式发送给“项目”或者“社区”,其他形式包括但不限于讨论、在“项目”相关的电子邮件列表上的交流、在“项目”相关的源代码修订控制、问题跟踪等系统中的操作,但不包括以书面方式明确标记为“非贡献”的交流。
+
+1.8 “著作权”指《著作权法》规定的各项权利;在任何不适用中国法律的争议中,应指包括《保护文学艺术作品伯尔尼公约》、《世界知识产权组织版权公约》、《与贸易有关的知识产权协定》等国际公约及争议准据法项下规定在内的全部可适用权利。
+
+1.9 “专利权”指《专利法》规定的各项权利;在任何不适用中国法律的争议中,应指包括《保护工业产权巴黎公约》、《与贸易有关的知识产权协定》等国际公约及争议准据法项下规定在内的全部可适用权利。
+
+1.10 “合法权利”包括但不限于著作权、版权、专利权、商标权、隐私权以及法律规定的其他权利。
+
+1.11 “作品”指《著作权法》规定的在文学、艺术和科学领域内具有独创性并能以一定形式表现的智力成果以及《专利法》规定的产品、方法或者其改进所提出的新的技术方案、对产品的形状、构造或者其结合所提出的适于实用的新的技术方案、对产品的整体或者局部的形状、图案或者其结合以及色彩与形状、图案的结合所作出的富有美感并适于工业应用的新设计。在任何不适用中国法律的争议中,应指与著作权及专利权相对应的全部可适用标的。
+
+1.12 “原创作品”指贡献者作为作者创作、开发的作品或者发明创造。
+
+1.13 “职务作品”指贡献者作为作者创作、开发但依法属于《著作权法》规定的职务作品的作品或者《专利法》规定的职务发明创造。
+
+1.14 “合作作品”指贡献者作为作者之一创作、开发但依法属于《著作权法》规定的合作作品的作品或者《专利法》规定的合作完成的发明创造。
+
+1.15 “委托作品”指贡献者作为作者创作、开发但依法属于《著作权法》规定的委托作品的作品或者《专利法》规定的委托完成的发明创造。
+
+1.16 “非原创作品”指贡献者以外的人创作、开发的作品。为免歧义,贡献者作为作者之一参与的合作作品属于原创作品,但作为贡献提交时,贡献者应取得合作作者的合法授权。
+
+## 二、著作权许可授权
+
+2.1 贡献一经提交,即视为贡献者免费且不可撤销地授予社区、项目及其全部或者部分的接收者永久、非排他、全球性的著作权许可,修改、复制、发行、传播、改编、注释、整理、汇编、开发、展示、分发、再许可或以其他合法方式使用贡献及使用贡献产生的成果。
+
+## 三、专利权许可授权
+
+3.1 贡献一经提交,即视为贡献者免费且不可撤销地授予社区、项目及其全部或者部分的接收者永久、非排他、全球性的专利权许可,制造、委托制造、销售、许诺销售、进口或以其他合法方式使用贡献及使用贡献产生的成果。
+
+## 四、原创及不侵权承诺
+
+4.1 除严格按第4.4条要求明确标记为非原创的情形之外,贡献者承诺所提交的贡献完全为原创作品,不侵害他人的合法权利,且无以下任何一种情况:
+
+ 4.1.1 属于职务作品,单位未签署本协议及/或未同意贡献者提交;
+
+ 4.1.2 属于合作作品,合作作者未签署本协议及/或未同意贡献者提交;
+
+ 4.1.3 属于委托作品或者著作权、专利权已经对外转让,著作权、专利权的实际持有人未签署本协议及/或未同意贡献者提交。
+
+4.2 如存在第4.1条任何一种情形的,贡献者应先取得相应授权后再进行提交:
+
+ 4.2.1 如有第4.1.1条的情形,贡献者应事先取得单位的授权;
+
+ 4.2.2 如有第4.1.2条的情形,贡献者应事先取得合作作者的授权;
+
+ 4.2.3 如有第4.1条的情形,贡献者应事先取得著作权、专利权实际持有人的授权。
+
+4.3 在遵守本第五条约定的基础上,单位作为贡献者签署本协议的,可以授权指定人士以单位名义、单位员工名义或者个人名义提交贡献。
+
+4.4 如贡献者提交的贡献为非原创作品,则贡献者应当明确标记出非原创部分,并完整列出原创者及/或著作权、专利权持有者的名称。
+
+4.5 除其他条款约定外,如贡献者提交的贡献在使用时可能涉及任何第三方权利,则贡献者还应当在提交时予以说明,并披露该等限制的完整详细信息。
+
+4.6 请留意:社区希望保护贡献者的合法权益,免受任何人士的侵犯;社区也倡导尊重原创、保护知识产权,不允许侵犯他人的合法权益。如贡献者提交贡献时,冒名、盗用或者擅自提交他人享有著作权或其他合法权利的作品或者以其他方式侵犯他人合法权益,导致社区承担责任和损失的,社区保留追究责任的权利。
+
+## 五、贡献者权利保护
+
+5.1 贡献者签署本协议不应视为放弃原创者身份或署名权。本协议不影响贡献者将其贡献合法用于其他任何目的的权利,社区或者任何其他人士亦不应凭借本协议要求贡献者放弃其他任何合法权利。
+
+5.2 贡献者签署本协议不应视为承诺对其提交的贡献承担后续支持、维保、适用性、品质保证等义务。社区或者任何其他人士亦不应凭借本协议要求贡献者承担任何未约定的义务。
\ No newline at end of file
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000..0e502fd208
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,116 @@
+# Jpom 贡献说明
+
+## 目录说明
+
+```
+.
+├── .gitee => gitee 配置
+├── docs => 一键安装的命令脚本以及版本号文件
+├── modules => java 后端目录(agent、server)
+ ├── agent => 插件端代码
+ ├── common => 这个项目的公共模块(插件端、服务端都依赖该模块)
+ ├── server => 服务端代码
+ ├── sub-plugin => 插件模块
+├── script => 一些通用脚本
+├── web-vue => 前端 vue 目录
+ ├── .editorconfig => 前端(vue)代码格式配置
+├── .editorconfig => 全局代码格式配置
+├── .gitattributes => 文件编码格式配置
+└── .... => 仓库一些默认配置
+```
+
+## 一些规范说明
+
+1. 写完代码后在保证不影响其他的人的代码情况下尽量统一格式化一下代码
+ 1. 采用 4 个空格缩进,禁止使用 tab 字符
+ 2. 如果使用 tab 缩进,必须设置 1 个 tab 为 4 个空格。IDEA 设置 tab 为 4 个空格时,
+ 请勿勾选 Use tab character;而在 eclipse 中,必须勾选 insert spaces for tabs
+2. Java 代码需要保证新增方法都有充足、标准的 JavaDoc 注释
+3. 在修改 Bug、新增功能尽量保证最小提交的方式提交代码,减少多个功能一个 commit
+4. 所有接口 url 都需要遵循下划线模式
+5. Java 代码、方法需要遵循小驼峰法
+6. Java 类名需要遵循大驼峰法
+7. 前端项目统一采用 `prettier` 方式来格式化(需要安装插件)
+8. 所有 controller 层的接口都需要添加文档注释(至少包含接口的作用说明、参数说明、返回值说明及添加 apiDoc 文档注释)
+
+> 注:由于旧代码存在很多不规范问题,会逐步调整为新规范。在新写的代码都需要需要遵循上面说明
+>
+>
+### 类的文档注释规范(Javadoc)
+
+```
+/**
+ * xxxxxxxx
+ * @author xxxx
+ * @since ${DATE}
+ */
+```
+
+> 这里采用 `@since` 声明创建日期是因为 `Javadoc` 规范里面并没有 `@date` 标记所以采用 `@since` 代替
+
+### Java 代码规范
+
+> 推荐安装 `Alibaba Java Coding Guidelines`(`p3c`) 插件
+
+##### 代码级别的多行注释
+
+[https://www.e-learn.cn/topic/3680721](https://www.e-learn.cn/topic/3680721)
+
+## changelog 更新规范
+
+> 在新加功能、修复bug、优化功能在完成时候都需要在 [CHANGELOG.md](./CHANGELOG.md) 记录
+
+1. 如果是使用者反馈的bug,在修复后需要备注反馈人的昵称
+2. 如果是 issue 需要备注 issue 地址以及平台(Gitee、GitHub)
+3. 如果是 pr 需要备注 pr 地址以及平台(Gitee、GitHub)
+4. 根据变动情况确定影响范围:如果影响 只:`agent`、`server` 其中一个,就使用【agent】、【server】开头,如果都影响就不用
+5. 可以视情况添加其他说明:如提交记录
+6. emoji 表情参考:[https://emojixd.com/](https://emojixd.com/)
+
+## apiDoc 文档注释规范
+### 【强制】所有需要包含在 apiDoc 文档中的接口,都必须有 `@api` 文档标记
+说明:如果没有 `@api` 文档标记,则定义的文档不会出现在生成后的 apiDoc 文档中。
+
+### 【强制】所有 apiDoc 的文档标记必须定义在 javaDoc 标记的后面
+说明:如果先定义 javaDoc 文档标记,再定义 apiDoc 的文档标记,则 javaDoc 的标记可能会包含在 apiDoc 的标记属性中,这并不是我们想要的结果。
+
+正例:
+```
+/**
+* @author hjk
+* @api {method} path title
+* @apiParam {Number} id Users unique ID.
+*/
+```
+
+反例:
+
+说明:参数 id 的说明应该是 Users unique ID. 如果这样定义则变成了 Users unique ID.@author hjk
+```
+/**
+* @api {method} path title
+* @apiParam {Number} id Users unique ID.
+* @author hjk
+*/
+```
+
+### 【强制】定义通用文档块
+
+说明:使用 `@apiDefine` 定义通用的文档块,然后使用 `@apiUse` 来引用,增强文档块的复用性。
+
+所有的文档块统一定义在 `server` 模块下的 `org.dromara.jpom.ApiDoc`
+
+
+## 分支说明
+
+1. 新功能都提交到 dev 分支, 不能提交到 master 分支
+2. PR 提交到 dev 分支
+3. 一般功能开发可以直接提交到 dev 分支,较大功能开发需要新建分支提交
+
+## 需要的小组
+
+1. 后端小组 (主要任务:根据需求开发对应的接口)
+2. 前端小组 (主要任务:优化前端 UI 交互和对接部分接口)
+3. 文档小组 (主要任务:完善、补充 Jpom 使用文档)
+4. 视频小组 (主要任务:录制 Jpom 相关的使用视频)
+5. 测试小组 (主要任务:参与 Jpom 新版内测、日常开发测试相关任务)
\ No newline at end of file
diff --git a/HEADER.txt b/HEADER.txt
new file mode 100644
index 0000000000..017f46077c
--- /dev/null
+++ b/HEADER.txt
@@ -0,0 +1,7 @@
+Copyright (c) 2019 Of Him Code Technology Studio
+Jpom is licensed under Mulan PSL v2.
+You can use this software according to the terms and conditions of the Mulan PSL v2.
+You may obtain a copy of Mulan PSL v2 at:
+ http://license.coscl.org.cn/MulanPSL2
+THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+See the Mulan PSL v2 for more details.
diff --git a/LICENSE b/LICENSE
index bcd8fb2e0a..84931bc19e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,20 +1,127 @@
-The MIT License (MIT)
-
-Copyright (c) 2019 码之科技工作室
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ 木兰宽松许可证, 第2版
+
+ 木兰宽松许可证, 第2版
+ 2020年1月 http://license.coscl.org.cn/MulanPSL2
+
+
+ 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束:
+
+ 0. 定义
+
+ “软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
+
+ “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
+
+ “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
+
+ “法人实体”是指提交贡献的机构及其“关联实体”。
+
+ “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
+
+ 1. 授予版权许可
+
+ 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
+
+ 2. 授予专利许可
+
+ 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
+
+ 3. 无商标许可
+
+ “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。
+
+ 4. 分发限制
+
+ 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
+
+ 5. 免责声明与责任限制
+
+ “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
+
+ 6. 语言
+ “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。
+
+ 条款结束
+
+ 如何将木兰宽松许可证,第2版,应用到您的软件
+
+ 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步:
+
+ 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
+
+ 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中;
+
+ 3, 请将如下声明文本放入每个源文件的头部注释中。
+
+ Copyright (c) 2019 Of Him Code Technology Studio
+ Jpom is licensed under Mulan PSL v2.
+ You can use this software according to the terms and conditions of the Mulan PSL v2.
+ You may obtain a copy of Mulan PSL v2 at:
+ http://license.coscl.org.cn/MulanPSL2
+ THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ See the Mulan PSL v2 for more details.
+
+
+ Mulan Permissive Software License,Version 2
+
+ Mulan Permissive Software License,Version 2 (Mulan PSL v2)
+ January 2020 http://license.coscl.org.cn/MulanPSL2
+
+ Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions:
+
+ 0. Definition
+
+ Software means the program and related documents which are licensed under this License and comprise all Contribution(s).
+
+ Contribution means the copyrightable work licensed by a particular Contributor under this License.
+
+ Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
+
+ Legal Entity means the entity making a Contribution and all its Affiliates.
+
+ Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
+
+ 1. Grant of Copyright License
+
+ Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
+
+ 2. Grant of Patent License
+
+ Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
+
+ 3. No Trademark License
+
+ No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4.
+
+ 4. Distribution Restriction
+
+ You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
+
+ 5. Disclaimer of Warranty and Limitation of Liability
+
+ THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+ 6. Language
+
+ THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL.
+
+ END OF THE TERMS AND CONDITIONS
+
+ How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software
+
+ To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps:
+
+ i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
+
+ ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package;
+
+ iii Attach the statement to the appropriate annotated syntax at the beginning of each source file.
+
+
+ Copyright (c) 2019 Of Him Code Technology Studio
+ Jpom is licensed under Mulan PSL v2.
+ You can use this software according to the terms and conditions of the Mulan PSL v2.
+ You may obtain a copy of Mulan PSL v2 at:
+ http://license.coscl.org.cn/MulanPSL2
+ THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ See the Mulan PSL v2 for more details.
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000000..51889e2dfa
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,12 @@
+Jpom-An open-source, Project operation and maintenance system.
+Jpom-项目运维系统。
+
+Jpom Declaration / Jpom 声明
+
+It can be used directly without authorization. All copyrights, patents, trademarks and ownership statements in the product and source code must be retained.
+可直接免费商用,但必须保留本作品及源码中的所有版权、专利、商标和归属声明。
+
+The attribution statement and copyright notice in the footer cannot be ignored, otherwise it will be deemed as infringement.
+页面等页脚中归属声明及版权声明不可忽略,否则视为侵权。
+
+Copyright https://www.jpom.top All Rights Reserved.
diff --git a/PLANS.md b/PLANS.md
index 45b9c34c7a..4b481fd1c1 100644
--- a/PLANS.md
+++ b/PLANS.md
@@ -1,14 +1,106 @@
-### 开发计划
-
-# 2.7.x
-
-1. 自定义检查项目状态
-2. 自定义启动项目脚本
-3. 重构用户角色(计划引入工作空间)
-4. ssh 批量执行命令
-5. 数据导入导出
-
-# 2.6.0
+# 开发计划
+
+## 2.11.x
+
+1. **构建流水线**
+2. **netty-agent**
+3. 凭证管理
+4. 升级 JDK 11 或者 17
+5. 端口监控、监控报警、机器监控、ssh 监控报警
+6. 资产监控
+7. nginx 流量切换(nginx 功能可能下线)
+8. acme.sh ui
+9. 执行审计
+10. 执行部分命令耗时和直接执行相差太大
+11. **非 root 用户提升权限写入 root 用户文件**
+12. 部分数据迁移工作空间(~~项目~~,构建,仓库、节点分发)
+13. 前端表格用户自定义列显示
+14. 节点取消,白名单配置和下载白名单(统一到服务端工作空间配置)
+15. 隧道节点
+16. docker-compose sh
+17. 监控通知模块优化支持更多(飞书) zx
+18. 数据库支持 mariadb
+
+## 2.10.x
+
+1. ~~前端升级 vue3~~
+2. `导入云效仓库 (zx) 依赖太重,非单接口实现(需要标准验证流程)`
+3. ~~仓库~~、构建、分发、~~项目~~导入导出
+4. ~~docker 容器编辑重建(zx)~~
+5. ~~前端主题切换~~
+6. ~~仓库密码、ssh 密码引用环境变量支持使用下拉框 sh~~
+7. ~~SSH 修改文件权限 zx~~
+8. ~~vue3 资产管理 zs~~
+9. ~~vue3 用户管理 zs~~
+
+### DONE
+
+1. ~~SSH 连接 docker (sh)~~
+2. ~~批量删除镜像 (sh)~~
+3. **资产管理**
+ 1. ~~机器管理~~
+ 2. ~~机器监控~~
+ 3. ~~SSH 管理~~
+ 4. ~~dokcer 管理~~
+ 5. ~~docker 集群~~
+ 6. ~~ssh 监控~~
+ 7. ~~仓库管理(待定,可以和凭证管理一起考虑)~~
+4. ~~使用服务端的 git 插件~~
+5. ~~日志组件卡顿~~
+6. ~~清理触发器表~~
+7. ~~scp 发布实践案例~~
+8. ~~SSH 上传文件进度(前端分片+进度)~~
+9. ~~**用户体系支持接入第三方系统**~~
+10. ~~传输信息加密(混淆,避免 http 明文传输)~~
+11. ~~插件端证书验证迁移到服务端~~
+12. ~~稳定版/体验版~~
+13. ~~插件端自定义发布文件~~
+14. ~~容器构建基础镜像的管理~~
+15. ~~tomcat 实践案例~~
+16. ~~**分片上传文件**~~
+17. ~~**支持 mysql 数据库**~~
+18. ~~配置文件优化~~
+19. ~~项目触发器~~
+20. ~~节点转发模块优化~~
+21. ~~构建事件触发新增更多(前后)~~
+22. ~~复制项目~~
+23. ~~测命令行参数~~
+24. ~~标签页缓存问题(定时器未清空)~~
+25. ~~发布到指定目录~~
+
+## 2.8.x
+
+1. ~~h2 数据库升级 2.0~~
+2. ~~文件管理支持备份~~
+3. ~~节点工作空间变量~~
+4. ~~操作监控优化~~
+5. ~~节点日志文件搜索~~
+6. ~~监控 webhook~~
+7. ~~构建判断仓库代码是否变动~~
+8. ~~批量执行节点脚本~~
+
+## 2.8.x
+--
+
+1. ~~ssh 批量执行命令~~
+2. ~~容器编排~~
+3. ~~自定义检查项目状态~~
+ 1. `for /f "tokens=1 delims= " %i in ('jps -l ^| findstr "JpomServer"') do @echo %i`
+4. ~~自定义启动项目脚本~~
+5. ~~快速安装导入插件端~~
+6. ~~容器构建~~
+7. ~~docker ui~~
+8. ~~节点大屏~~
+9. ~~实时阅读日志文件~~
+10. ~~配置分发~~
+11. ~~修改数据库密码~~
+
+## 2.7.x
+
+1. ~~重构用户角色(计划引入工作空间)~~
+2. ~~数据导入导出~~
+
+## 2.6.0
1. ~~取消thymeleaf~~
2. ~~git 证书拉取代码~~
@@ -18,12 +110,9 @@
6. ~~节点分发功能增加SSH部署-按指定地址下载应用~~
7. ~~项目文件管理支持远程下载~~
8. ~~jwt 更换~~
-9. 压缩工具类优化
-10. 文件管理支持备份
-11. 文件管理备份
-
+9. ~~压缩工具类优化~~
-# 2.5.1
+## 2.5.1
1. ~~token 机制问题(@ArnoHand 4月4日前)~~
2. ~~控制台文件太大问题(@蒋小小 4月4日前)~~
@@ -32,11 +121,11 @@
======================
-# 2.5.2
+## 2.5.2
1. ~~agent统一升级管理(@蓝枫 4月17日前)~~
2. ~~git 证书拉取代码~~
-3. 项目列表新增运行方式筛选
+3. ~~项目列表新增运行方式筛选~~
4. ~~及时刷新菜单~~
5. ~~远程升级(jpom 官方服务)~~
@@ -45,29 +134,29 @@
* 主要管理页面兼容移动端
* ssl 到期提醒、快捷续签
* Tomcat管理优化
- * 优化启动(期望能使用到tomcat原生配置文件中的参数)
- * 在线修改配置
-* 支持docker容器部署
+ * 优化启动(期望能使用到tomcat原生配置文件中的参数)
+ * 在线修改配置
+* ~~支持docker容器部署~~
* ~~jdk选择~~
* ~~开机自动启动~~
* ~~IP白名单~~
-* socket 日志
+* ~~socket 日志~~
* ~~单节点支持项目副本~~
* 构建发布到同一个节点多个项目
-* 集群环境自动注册节点
-* 文件管理优化
+* ~~集群环境自动注册节点~~
+* ~~文件管理优化~~
* ~~agent统一升级管理~~
* ~~ssh文件管理(还原,之前有pr被合并错了)~~
-* 用户权限
-* 数据存储
-* 账号密码安全性
+* ~~用户权限~~
+* ~~数据存储~~
+* ~~账号密码安全性~~
--------------------
* Jpom 接口文档整理
-* 部分服务器ssh不能退格
+* ~~部分服务器ssh不能退格~~
* ~~Token 机制问题~~
* ~~控制台日志文件过大~~
diff --git a/PRIVACY.md b/PRIVACY.md
new file mode 100644
index 0000000000..2fc60682ab
--- /dev/null
+++ b/PRIVACY.md
@@ -0,0 +1,54 @@
+# Jpom项目运维本地部署版隐私协议
+
+**一、引言**
+
+**1.1** 我们诚挚欢迎并感谢您选用开源软件——Jpom项目运维的本地部署版本(以下简称“本软件”)。本隐私协议旨在全面介绍和阐明我们在您本地部署和使用本软件时,关于数据处理的各种活动规范,覆盖但不限于数据的搜集、运用、存储和防护等各个阶段。敬请您在安装并启用本软件之前,务必详尽阅读并深刻理解本协议各项条款。
+
+**二、数据处理与本地化规范**
+
+**2.1** **本地数据操作**
+本软件所有数据处理活动严格限制在您指定和管控的本地服务器或设备上执行,我们不会直接获取或远程访问这些数据资源。为保证软件的正常运行,可能需要处理如配置信息、错误日志、临时文件等本地生成的各类数据。
+
+**2.2** **必要数据操作原则**
+为确保软件基础功能稳定、性能卓越、技术问题有效解决以及优化用户使用体验,本软件可能会对上述部分或全部数据进行必要的处理。请注意,此类数据操作完全局限于本地环境,并严格遵循软件设计的规范与标准。
+
+**三、开源与透明度**
+
+**3.1** 本软件基于 MulanPSL2 开源许可协议发布,其源代码面向公众开放,意味着您有权审查软件源码以验证其数据处理行为符合您的隐私期待。我们积极倡议用户共同参与和监督,共同营造一个高度尊重数据隐私的应用生态体系。
+
+**四、数据主权与控制**
+
+**4.1** 用户对其在本地部署环境中生成的所有数据享有完整的控制权和所有权,这涵盖了从数据的创建、修改、删除到数据传输方式及存储地点的决定权。
+
+**五、数据安全保护**
+
+**5.1** 尽管本软件自带一定的内在安全机制,但用户仍需自行负责在本地部署环境中实施高效的数据安全措施,包括但不限于数据加密、访问控制、安全审计及数据备份策略等。对于因用户本地部署环境引发的数据安全事件,我们不承担直接法律责任。
+
+**六、数据交互与隐私承诺**
+
+本软件坚守最高的数据隐私保护原则,明确规定未经用户明确授权,本软件决不会主动对外向任何第三方透露您系统内的任何敏感信息。
+
+我们尤为重视并全力支持用户对数据安全性的深度审视诉求,确保每位用户有权详尽审查软件源代码,以亲手验证我们在数据处理与安全防护措施层面的严密性和合规性。
+我们通过这种开诚布公、负责任的方式,共同致力于最大程度地保障用户数据安全与隐私不受侵犯。
+
+**6.1** 个人信息收集政策
+
+我们严格遵循不收集原则,除非必要,否则不涉及收集用户的个人身份识别信息,例如姓名、电子邮件地址、电话号码、身份证件号码等。
+
+**6.2** 可能收集的数据类别
+
+在您使用我们产品和服务的过程中,为确保正常运行和提供更好的服务体验,我们有可能会收集与产品使用紧密相关的一些必要信息,包括但不限于IP地址、Cookies、页面路由、地理位置信息、设备制造商、设备型号、设备唯一标识符以及设备相关数据等。
+
+**6.3** 数据信息处理方式
+
+在必须收集相关信息的情况下,我们会在遵循相关法律法规及本隐私协议的基础上,将这些数据传输至我们的官方服务器(https://jpom.top),并在严格的规则约束下进行管理和使用。
+
+**七、法律合规与用户责任**
+
+**7.1** 在本软件的研发和运营过程中,我们严格遵守中国各地关于数据保护和隐私权的各项法律法规。
+
+**7.2** 用户在部署和使用本软件时,同样需遵循相关法律法规,承诺在使用过程中秉持合法、合理原则,不得利用本软件从事非法行为、侵犯他人合法权益,也不得在违反我国法律法规的项目或平台上部署和使用本软件。
+
+**八、隐私政策更新**
+
+**8.1** 我们保留在必要时适时更新和完善本隐私协议的权利,并将通过官方网站、软件更新公告或其他醒目位置公布修订内容。对于重要的政策变更,我们将提前通知用户,用户在变更后继续使用本软件即视作已同意并接受新的隐私协议。
\ No newline at end of file
diff --git a/README-en.md b/README-en.md
new file mode 100644
index 0000000000..2e8cc8ffc9
--- /dev/null
+++ b/README-en.md
@@ -0,0 +1,527 @@
+
+
+
+
+
+
+ 🚀Simple and lightweight low-invasive online build, automated deployment, daily operations, and project monitoring software.
+
+
+ 【It is also a native ops software / 中文 】
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 👉 https://jpom.top/ 👈
+
+
+## 😭 Do you experience these pain points in your daily development?
+
+- **No dedicated operations team, so developers have to handle operations tasks** , including manual project building and deployment.
+- Different projects require different build and deployment commands.
+- Need to package for various environments like development, testing, and production.
+- Need to monitor the status of multiple projects simultaneously.
+- Need to download SSH tools to remotely connect to servers.
+- *Need to download FTP tools* to transfer files to servers.
+- Syncing account passwords across multiple servers and computers is inconvenient.
+- Want to use automation tools, but they are high-demanding on server performance and too complicated to set up.
+- **Have specific needs for automation tools and want to modify the project**, but existing tools are too complex.
+
+> For distributed projects, these steps are even more cumbersome.
+>
+> Let Jpom help you solve these pain points! And these are just the basic features that Jpom offers.
+
+### 😁 After using [Jpom](https://gitee.com/dromara/Jpom)
+
+- Convenient User Management
+ 1. User activity monitoring, with email notifications for specific user actions
+ 2. Multi-user management with independent project permissions (control over upload and delete rights), comprehensive operation logs, and workspace-based permission isolation
+ 3. Accounts can enable **MFA (Multi-Factor Authentication)** for security
+- Real-time interface to view project status, console logs, and manage project files
+ 1. Edit project text files online
+- Docker container management and Docker Swarm cluster management(**Docker UI**)
+- **Online SSH Terminal**, allowing easy server management without using PuTTY, Xshell, FinalShell, etc.
+ 1. No need to know server passwords after logging into the Jpom system
+ 2. Specify forbidden SSH commands to prevent high-risk operations and automatically log command execution
+ 3. Set file directories to manage project files and configuration files online
+ 4. Execute SSH command templates and schedule scripts online
+ 5. Edit text files online
+ 6. **Lightweight implementation of basic"bastion host"functionality**
+- One-click cluster project deployment using project distribution
+- Online build process eliminates the need for manual project updates and upgrades
+ 1. Supports pulling from GIT and SVN repositories
+ 2. **Supports container builds (docker)**
+ 3. Supports SSH-based deployment
+ 4. Supports scheduled builds
+ 5. Supports WebHook-triggered builds
+- Supports online editing of nginx configuration files and automatic reload operations
+ 1. Manage nginx status and SSL certificates
+- Automatic alerts and restart attempts for abnormal project status
+ 1. Supports notifications via email, DingTalk groups, and WeChat groups, actively monitoring project status
+- Node script templates with scheduling or triggers for expanded functionality
+- Configurable authorization for important paths to prevent user errors with system files
+
+### 🔔️ Special Reminders
+
+> 1. On Windows servers, some features may have compatibility issues due to system characteristics. It is recommended to thoroughly test in practical use. Linux currently has good compatibility.
+> 2. Install the server and plugin components in different directories; do not install them in the same directory.
+> 3. To uninstall Jpom plugin or server components, first stop the corresponding service, then delete the related program files, log folders, and data directories.
+> 4. Local builds depend on the system environment. If build commands require Maven or Node.js,
+ ensure the corresponding environment is installed on the build server. If the environment is installed after the server is started, restart the server via the command line for the environment to take effect.
+> 5. On Ubuntu/Debian servers, the plugin component may fail to add. Please create a .bash_profile file in the root directory of the current user.
+> 6. After upgrading to version 2.7.x, downgrading is not recommended due to potential data incompatibility issues.
+> 7. Currently, version 2.x.x uses HTTP for communication between the plugin and server components, so ensure network connectivity between them during use.
+> 8. Jpom version 3.0 is already being planned. Stay tuned for the new release!
+
+### 🗒️ [Changelog](https://gitee.com/dromara/Jpom/blob/master/CHANGELOG.md)
+
+Must-read before upgrading: [CHANGELOG.md](https://gitee.com/dromara/Jpom/blob/master/CHANGELOG.md)
+
+## 📥 Installing Jpom
+
+Jpom supports various installation methods to meet different user needs. Just choose one method to install.
+
+### Method 1: 🚀(Recommended) One-click Installation (Linux)
+
+#### One-click Server Installation
+
+> **Note: The installation directory is the current directory where the command is executed!**
+>
+> ⚠️ Special Reminder: When using the one-click installation, ensure the command is executed in different directories. The Server and Agent cannot be installed in the same directory!
+>
+> To change the data and log storage paths of the server,
+> modify the `jpom.path` configuration property in the file
+> [`application.yml`](https://gitee.com/dromara/Jpom/blob/master/modules/server/src/main/resources/config_default/application.yml)
+
+```shell
+# Default one-click installation
+curl -fsSL https://jpom.top/docs/install.sh | bash -s Server jdk+default
+# Default one-click installation and automatic startup service configuration
+curl -fsSL https://jpom.top/docs/install.sh | bash -s Server jdk+default+service
+
+# Install server and jdk environment
+yum install -y wget && \
+wget -O install.sh https://jpom.top/docs/install.sh && \
+bash install.sh Server jdk
+
+# Install server and jdk, maven environment
+yum install -y wget && \
+wget -O install.sh https://jpom.top/docs/install.sh && \
+bash install.sh Server jdk+mvn
+
+# ubuntu
+apt-get install -y wget && \
+wget -O install.sh https://jpom.top/docs/install.sh && \
+bash install.sh Server jdk
+```
+
+After a successful startup, the server port is `2122`. You can access the management page via `http://127.0.0.1:2122/`
+(if not accessing from the local machine, replace 127.0.0.1 with the IP address of the installed server).
+
+> If you cannot access the management system, run the command `systemctl status firewalld` to check if the firewall is enabled.
+> If you see `Active: active (running)` in green in the status bar, you need to allow port `2122`.
+>
+>```bash
+># Allow port 2122 for the management system
+>firewall-cmd --add-port=2122/tcp --permanent
+># Reload the firewall to take effect
+>firewall-cmd --reload
+>```
+>
+>If you have allowed the port in the operating system but still cannot access it, and you are using a cloud server, check the security group rules in the cloud server's control panel to see if port 2122 is allowed.
+>
+>⚠️ Note: There are multiple firewalls in Linux systems: Firewall, Iptables, SELinux, etc. When checking firewall configurations, make sure to check all of them.
+
+#### One-Click Agent Installation
+
+> If the server where the server side is installed also needs to be managed, you need to install the agent on the server side as well (both the server and agent can be installed on the same server but in different directories).
+>
+> ⚠️ Special reminder: Do not execute the one-click installation command in the same directory for both the Server and Agent!
+>
+> If you need to modify the agent data and log storage paths, update the `jpom.path` configuration property in the file
+> [`application.yml`](https://gitee.com/dromara/Jpom/blob/master/modules/agent/src/main/resources/config_default/application.yml)
+
+```shell
+# Default one-click installation
+curl -fsSL https://jpom.top/docs/install.sh | bash -s Agent jdk+default
+# Default one-click installation and auto-configure startup service
+curl -fsSL https://jpom.top/docs/install.sh | bash -s Agent jdk+default+service
+
+# Install agent and JDK environment
+yum install -y wget && \
+wget -O install.sh https://jpom.top/docs/install.sh && \
+bash install.sh Agent jdk
+
+# ubuntu
+apt-get install -y wget && \
+wget -O install.sh https://jpom.top/docs/install.sh && \
+bash install.sh Agent jdk
+```
+
+After a successful startup, the agent port is `2123`, which is used by the server.
+
+### Method 2: 📦 Container Installation
+
+> ⚠️ Note: Container installation requires Docker to be installed first. [Click here for Docker installation documentation](https://jpom.top/pages/b63dc5/)
+
+#### One-Command Installation
+
+```shell
+docker run -p 2122:2122 --name jpom-server jpomdocker/jpom
+```
+
+#### Using Mount to Store Data (may have compatibility issues in some environments)
+
+```shell
+docker pull jpomdocker/jpom
+mkdir -p /home/jpom-server/logs
+mkdir -p /home/jpom-server/data
+mkdir -p /home/jpom-server/conf
+docker run -d -p 2122:2122 \
+ --name jpom-server \
+ -v /home/jpom-server/logs:/usr/local/jpom-server/logs \
+ -v /home/jpom-server/data:/usr/local/jpom-server/data \
+ -v /home/jpom-server/conf:/usr/local/jpom-server/conf \
+ jpomdocker/jpom
+```
+
+#### Using Docker Volumes to Store Data
+
+```shell
+docker pull jpomdocker/jpom
+docker volume create jpom-server-data
+docker volume create jpom-server-logs
+docker volume create jpom-server-conf
+docker run -d -p 2122:2122 \
+ --name jpom-server \
+ -v jpom-server-data:/usr/local/jpom-server/data \
+ -v jpom-server-logs:/usr/local/jpom-server/logs \
+ -v jpom-server-conf:/usr/local/jpom-server/conf \
+ jpomdocker/jpom
+```
+
+> Container installation only provides the server version. Due to isolation between the container and the host environment, many functionalities of the agent cannot be used properly. Therefore, containerization of the agent is not very meaningful.
+>
+> For more information on installing Docker, configuring images, auto-start, and locating the installation directory, refer to the documentation
+> [https://jpom.top/pages/b63dc5/](https://jpom.top/pages/b63dc5/)
+>
+> In lower versions of Docker, you may encounter the error `ls: cannot access'/usr/local/jpom-server/lib/': Operation not permitted`
+> In this case, add the `--privileged` parameter
+> Example: `docker run -p 2122:2122 --name jpom-server jpomdocker/jpom --privileged`
+
+### Method 3: 💾 Download and Install
+
+1. Download the installation package from [https://jpom.top/pages/all-downloads/](https://jpom.top/pages/all-downloads/)
+2. Extract the files
+3. Install the agent:
+ 1. The `agent-x.x.x-release` directory contains all the installation files for the agent
+ 2. Upload the entire directory to the corresponding server
+ 3. Start the agent. Use the bat script on Windows and the sh script on Linux (if there are garbled characters or execution issues, check the encoding format and line endings)
+ 4. The default running port for the agent is `2123`
+4. Install the server:
+ 1. The `server-x.x.x-release` directory contains all the installation files for the server
+ 2. Upload the entire directory to the corresponding server
+ 3. Start the server. Use the bat script on Windows and the sh script on Linux (if there are garbled characters or execution issues, check the encoding format and line endings)
+ 4. The default running port for the server is `2122`. Access the management page at `http://127.0.0.1:2122/` (if not accessed locally, replace `127.0.0.1` with your server's IP address)
+
+### Method 4: ⌨️ Compile and Install
+
+1. Visit the [Jpom](https://gitee.com/dromara/Jpom) Gitee page and pull the latest complete code (recommended to use the master branch)
+2. Switch to the `web-vue` directory and run `npm install` (you need to have the Vue environment set up in advance; refer to the README.md in the web-vue directory for details)
+3. Run `npm run build` to package the Vue project
+4. Switch to the project root directory and run: `mvn clean package`
+5. Install the agent:
+ 1. Check the agent installation package in `modules/agent/target/agent-x.x.x-release`
+ 2. Upload the entire directory to the server
+ 3. Start the agent. Use the bat script on Windows and the sh script on Linux (if there are garbled characters or execution issues, check the encoding format and line endings)
+ 4. The default running port for the agent is `2123`
+6. Install the server:
+ 1. Check the server installation package in `modules/server/target/server-x.x.x-release`
+ 2. Upload the entire directory to the server
+ 3. Start the server. Use the bat script on Windows and the sh script on Linux (if there are garbled characters or execution issues, check the encoding format and line endings)
+ 4. The default running port for the server is `2122`. Access the management page at `http://127.0.0.1:2122/` (if not accessed locally, replace `127.0.0.1` with your server's IP address)
+
+> You can also use `script/release.bat` or `script/release.sh` for quick packaging.
+
+### Method 5: 📦 One-Click Start with Docker-Compose
+
+- No environment installation required; automatically compiles and builds
+
+> Note: Remember to modify the token value in the `.env` file
+
+```shell
+yum install -y git
+git clone https://gitee.com/dromara/Jpom.git
+cd Jpom
+docker-compose -f docker-compose.yml up
+# docker-compose -f docker-compose.yml up --build
+# docker-compose -f docker-compose.yml build --no-cache
+# docker-compose -f docker-compose-local.yml up
+# docker-compose -f docker-compose-local.yml build --build-arg TEMP_VERSION=.0
+# docker-compose -f docker-compose-cluster.yml up --build
+```
+
+### Method 6: 💻 Compile and Run
+
+1. Visit the [Jpom](https://gitee.com/dromara/Jpom) Gitee page and pull the latest complete code (it's recommended to use the master branch, but if you want to experience new features, you can use the
+ dev branch)
+2. Run the agent:
+ 1. Run `org.dromara.jpom.JpomAgentApplication`
+ 2. Note the default username and password information printed in the console.
+ 3. The agent's default running port: `2123`
+3. Run the server:
+ 1. Run `org.dromara.jpom.JpomServerApplication`
+ 2. The server's default running port: `2122`
+4. Build the Vue page, switch to the `web-vue` directory (make sure you have node and npm environments set up locally).
+5. Install the Vue project dependencies by executing `npm install` in the console.
+6. Start development mode by executing `npm run dev` in the console.
+7. Access the frontend page using the address output in the console: `http://127.0.0.1:3000/` (if not accessing from the local machine, replace `127.0.0.1` with your server's IP address).
+
+## Managing Jpom Commands
+
+1. Using BAT Script Files on Windows
+
+```bash
+# Server management scripts (command line)
+./bin/Server.bat start # Start the Jpom server
+./bin/Server.bat stop # Stop the Jpom server
+./bin/Server.bat restart # Restart the Jpom server
+./bin/Server.bat status # Check the Jpom server status
+# Server management script (control panel), follow the panel prompts for operations
+./bin/Server.bat
+
+# Agent management scripts
+./bin/Agent.bat start # Start the Jpom agent
+./bin/Agent.bat stop # Stop the Jpom agent
+./bin/Agent.bat restart # Restart the Jpom agent
+./bin/Agent.bat status # Check the Jpom agent status
+# Agent management script (control panel), follow the panel prompts for operations
+./bin/Agent.bat
+
+```
+
+> After executing the startup script on Windows, follow the logs to check the startup status. If you encounter garbled text, check or modify the encoding format. It is recommended to use
+> `GB2312` for BAT script encoding on Windows.
+
+2. Using SH Script Files on Linux
+
+```bash
+# Server management scripts
+./bin/Server.sh start # Start the Jpom server
+./bin/Server.sh stop # Stop the Jpom server
+./bin/Server.sh restart # Restart the Jpom server
+./bin/Server.sh status # Check the Jpom server status
+./bin/Service.sh install # Create a service for the Jpom server (jpom-server)
+
+# Agent management scripts
+./bin/Agent.sh start # Start the Jpom agent
+./bin/Agent.sh stop # Stop the Jpom agent
+./bin/Agent.sh restart # Restart the Jpom agent
+./bin/Agent.sh status # Check the Jpom agent status
+./bin/Service.sh install # Create a service for the Jpom agent (jpom-agent)
+```
+
+## Linux Service Management
+
+> The following service installation instructions are for reference only; customize configurations as needed.
+>
+> After successfully using `./bin/Service.sh install`:
+>
+> systemctl {status | start | stop | restart} jpom-server
+>
+> systemctl {status | start | stop | restart} jpom-agent
+
+## ⚙️ Jpom Configuration Parameters
+
+Located in the project's root path:
+
+### Application Configuration `./conf/application.yml`
+
+1. Agent example:
+ [`application.yml`](https://gitee.com/dromara/Jpom/blob/master/modules/agent/src/main/resources/config_default/application.yml)
+2. Server example:
+ [`application.yml`](https://gitee.com/dromara/Jpom/blob/master/modules/server/src/main/resources/config_default/application.yml)
+
+### Project Logs `./conf/logback.xml`
+
+1. Agent example:
+ [`logback.xml`](https://gitee.com/dromara/Jpom/blob/master/modules/agent/src/main/resources/config_default/logback.xml)
+2. Server example:
+ [`logback.xml`](https://gitee.com/dromara/Jpom/blob/master/modules/server/src/main/resources/config_default/logback.xml)
+
+## 📝 Frequently Asked Questions and User Guide
+
+- [Home Page](https://jpom.top/)
+- [FQA](https://jpom.top/pages/FQA/)
+- [Glossary](https://jpom.top/pages/FQA/proper-noun/)
+
+### Practical Examples
+
+> Some images may load slowly.
+
+1. [Local Build + SSH Deployment for Java Projects](https://jpom.top/pages/practice/build-java-ssh-release/)
+2. [Local Build + Project Deployment for Node Projects](https://jpom.top/pages/practice/build-node-release/)
+3. [Local Build + SSH Deployment for Node Projects](https://jpom.top/pages/practice/build-node-ssh-release/)
+4. [Local Build + Custom Management for Python Projects](https://jpom.top/pages/practice/project-dsl-python/)
+5. [Custom Management for Java Projects](https://jpom.top/pages/practice/project-dsl-java/)
+6. [Managing Compiled and Installed Nginx](https://jpom.top/pages/practice/node-nginx/)
+7. [Managing Docker](https://jpom.top/pages/practice/docker-cli/)
+8. [Container Build + Project Deployment for Java Projects](https://jpom.top/pages/practice/build-docker-java-node-release/)
+9. [More Practical Examples>>](https://jpom.top/pages/practice/)
+
+## Example Code Repositories
+
+1. [Jboot Example Code](https://gitee.com/keepbx/Jpom-demo-case/tree/master/jboot-test)
+2. [SpringBoot Example Code (ClassPath)](https://gitee.com/keepbx/Jpom-demo-case/tree/master/springboot-test)
+3. [SpringBoot Example Code (Jar)](https://gitee.com/keepbx/Jpom-demo-case/tree/master/springboot-test-jar)
+4. [Node Vue Example Code (antdv)](https://gitee.com/keepbx/Jpom-demo-case/tree/master/antdv)
+5. [Python Example Code](https://gitee.com/keepbx/Jpom-demo-case/tree/master/python)
+
+> Node.js compile specific directory:
+
+```bash
+yarn --cwd xxxx/ install
+yarn --cwd xxxx/ build
+```
+
+> Maven compile specific directory:
+
+```bash
+mvn -f xxxx/pom.xml clean package
+```
+
+## 🛠️ Overall Architecture
+
+
+
+
+## 🐞 Community Discussion, Bug Reports, Suggestions, etc.
+
+1. Scan the QR code below on the left to join our WeChat group! (Add the assistant and mention Jpom to join the group)
+2. Open source projects rely on community support. If Jpom has helped you, consider buying us a coffee.
+ You can scan the [WeChat and Alipay QR codes](https://jpom.top/images/qrcode/praise-all.png)
+ or support us through [Gitee sponsorship](https://gitee.com/dromara/Jpom)
+ (click the donate button at the bottom of the project homepage, supports WeChat and Alipay). [Sponsorship records](https://jpom.top/pages/praise/publicity/)
+3. Purchase open source merchandise: [Merchandise Introduction](https://jpom.top/pages/shop/)
+4. For enterprise technical services, please contact us directly to discuss service plans.
+5. For bug reports and suggestions, feel free to create [issues](https://gitee.com/dromara/Jpom/issues); developers will respond periodically.
+6. To contribute, please see the [Contribution Guide](#Contribution Guide)。
+
+Thank you to all sponsors and contributors; your support is our motivation for continuous updates and improvements!
+
+
+
+
+## 💖 Merchandise
+
+To better support the open-source project, we have decided to launch merchandise.
+
+By purchasing, you get a small item, and we receive the profit from your purchase (the prices of the merchandise may be slightly higher than market prices; please be aware before ordering).
+
+
+
+
+
+## 🔨Contribution Guide
+
+> By contributing, you agree to the terms of the [CLA](https://gitee.com/dromara/Jpom/blob/master/CLA.md) agreement
+
+### Contribution Guidelines
+
+As an open-source project, Jpom relies on community support and welcomes contributions from everyone. Whether big or small, your contributions will help thousands of users and developers. Your contributions will also be permanently recorded in the list of contributors, which is the essence of open-source projects!
+
+To ensure code quality and standards, and to help you quickly understand the project structure, please read the following before contributing:
+
+- [Jpom Contribution Guide](https://gitee.com/dromara/Jpom/blob/master/CODE_OF_CONDUCT.md)
+- [Typography Specifications (Chinese and English)](https://gitee.com/dromara/Jpom/blob/dev/typography-specification.md)
+
+### Contribution Steps
+
+1. Fork this repository.
+
+2. Clone your forked repository to your local machine.
+
+ Replace `branch-name` and `username` with the appropriate values.
+
+ Use `dev` for code contributions and `docs` for documentation contributions.
+
+ ```bash
+ git clone -b branch-name https://gitee.com/username/Jpom.git
+ ```
+
+3. Modify the code/documentation and commit your changes.
+
+ ```bash
+ # Add your changes to the staging area
+ git add .
+ # Commit your changes with a descriptive message
+ git commit -m 'Describe your changes'
+ # Push to your remote repository, replacing branch-name with dev or docs
+ git push origin branch-name
+ ```
+
+4. Create a Pull Request (PR).
+
+ Go to your repository on Gitee, create a PR request, and wait for the administrators to merge your changes.
+
+### Branch Explanation
+
+| Branch | Description |
+|--------|------------------------------------------------------|
+| master | Main branch, protected. Does not accept PRs. Merges from the beta branch after testing. |
+| beta | Beta version branch, protected. Does not accept PRs. Merges from the dev branch after testing. |
+| dev | Development branch, accepts PRs. Please submit PRs to the dev branch. |
+| docs | Documentation branch, accepts PRs. Used for project documentation, feature introductions, and FAQ summaries. |
+
+> Primarily use the dev and docs branches for PR submissions. Other branches are for archiving and can be ignored by contributors.
+
+## 🌍 Knowledge Planet
+
+
+
+
+
+## 🔔 Recommended Projects
+
+| Project Name | Project Link | Description |
+|---------------|----------------------------------------------------------------------------|-----------------------------------------------|
+| SpringBoot_v2 | [https://gitee.com/bdj/SpringBoot_v2](https://gitee.com/bdj/SpringBoot_v2) | A pure SpringBoot scaffold |
+| TLog GVP Project | [https://gitee.com/dromara/TLog](https://gitee.com/dromara/TLog) | A lightweight distributed log tagging and tracking tool for microservices |
+| Sa-Token | [https://gitee.com/dromara/sa-token](https://gitee.com/dromara/sa-token) | Possibly the most feature-rich Java authentication framework |
+| Erupt | [https://gitee.com/erupt/erupt](https://gitee.com/erupt/erupt) | Zero frontend code, pure annotation-based admin backend development |
+| hippo4j | [https://gitee.com/magegoofy/hippo4j](https://gitee.com/magegoofy/hippo4j) | Powerful dynamic thread pool framework with monitoring and alert features |
+| HertzBeat | [https://gitee.com/dromara/hertzbeat](https://gitee.com/dromara/hertzbeat) | Easy-to-use cloud monitoring system with strong custom monitoring capability |
+
+## 🤝 Acknowledgements
+
+- Special thanks to JetBrains for providing a free open-source license:
+
+
+
+
diff --git a/README.md b/README.md
index de5b847295..f56d806486 100644
--- a/README.md
+++ b/README.md
@@ -1,307 +1,534 @@
-
-
+
+
- 简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件
+ 🚀简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件
+
+
+ 【更是一款原生 ops 软件 / English 】
-
-
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
-
-
+
+
-
+
- https://jpom.io/ | https://jpom-site.keepbx.cn/ | https://jpom.keepbx.cn/
+ 👉 https://jpom.top/ 👈
-#### 你为什么需要 [Jpom](https://gitee.com/dromara/Jpom)
-
-> Java 项目在实际部署运维,通用的方法是登录服务器上传新的项目包,执行相应命令管理,如果管理多个项目则重复操作上述步骤
-
-> 此方法不足的是:
-> 1. 需要每次登录服务器(专业软件)
-> 2. 多个项目有多个管理命令(不易记、易混淆)
-> 3. 查看项目运行状态需要再次使用命令
-> 4. 同时面对多个运维都需要知道服务器密码(安全性低)
-> 5. 集群项目需要挨个操作项目步骤
-
-> 在使用Jpom后:
-> 1. 使用浏览器登录方便快捷管理项目
-> 2. 界面形式实时查看项目运行状态以及控制台日志
-> 3. 运维有对应的账号密码不需要知道服务器密码(并且有操作日志)
-> 4. 集群项目使用项目分发一键搞定多机部署
-> 5. 项目状态监控异常自动报警
-> 6. 在线构建不用手动上传项目包
-
-#### 项目主要功能及特点
-
-1. 创建、修改、删除项目、Jar包管理
-2. 实时查看控制台日志、备份日志、删除日志、导出日志
-3. 在线构建项目发布项目一键搞定
-4. 多节点管理、多节点自动分发
-5. 在线 SSH 终端,并且有终端日志和禁用命令
-6. 实时监控项目状态异常自动报警
-7. ~~cpu、ram 监控、(已经取消该功能)~~ 导出堆栈信息、查看项目进程端口、服务器状态监控
-8. 多用户管理,用户项目权限独立(上传、删除权限可控制),完善的操作日志
-9. 系统路径白名单模式,杜绝用户误操作系统文件
-10. 在线管理 Nginx 配置文件、ssl 证书文件
-11. ~~Tomcat状态、文件、war包在线实时管理 (不再长期维护)~~
-
-> 特别提醒:
-> 1. 在 Windows 服务器中可能有部分功能因为系统特性造成兼容性问题,建议在实际使用中充分测试。Linux 目前兼容良好
+## 😭 日常开发中,您是否有以下痛点?
+
+- **团队中没有专业的运维,开发还要做运维的活** ,需要自己手动构建、部署项目。
+- 不同的项目有不同的构建、部署命令。
+- 有开发、测试、生产等多环境打包的需求。
+- 需要同时监控多个项目的运行状态。
+- 需要下载 SSH 工具 远程连接服务器。
+- *需要下载 FTP 工具*传输文件到服务器。
+- 多台服务器时,在不同电脑之间账号密码同步不方便。
+- 想使用一些自动化工具,但是对服务器性能太高,搭建太麻烦。
+- **对自动化工具有个性化的需求,想自己修改项目**,但是市面上的工具太复杂了。
+
+> 如果是分布式的项目,以上步骤则更加繁琐。
+>
+> 让 Jpom 来帮您解决这些痛点吧!然而,这些只是 Jpom 解决的最基础的功能。
+
+### 😁 使用 [Jpom](https://gitee.com/dromara/Jpom) 后
+
+- 方便的用户管理
+ 1. 用户操作监控,监控指定用户指定操作以邮件形式通知
+ 2. 多用户管理,用户项目权限独立(上传、删除权限可控制),完善的操作日志,使用工作空间隔离权限
+ 3. 账号可以开启 **MFA 两步验证**提高账号安全性
+- 界面形式实时查看项目运行状态、控制台日志、管理项目文件
+ 1. 在线修改项目文本文件
+- Docker 容器管理、Docker Swarm 集群管理(**Docker UI**)
+- **在线 SSH 终端**,让您在没有 PuTTY、Xshell、FinalShell 等软件也能轻松管理服务器
+ 1. 登录 Jpom 系统后不需要知道服务器密码
+ 2. 能指定 SSH 禁止执行的命令,避免执行高风险命令,并且能自动执行命令日志
+ 3. 设置文件目录,在线查看管理对应项目文件及配置文件
+ 4. SSH 命令模版在线执行脚本还能定时执行
+ 5. 在线修改文本文件
+ 6. **轻量的实现了简单的"堡垒机"功能**
+- 使用项目分发一键搞定集群项目多机部署
+- 在线构建不用手动更新升级项目
+ 1. 支持拉取 GIT、SVN 仓库
+ 2. **支持容器构建(docker)**
+ 3. 支持 SSH 方式发布
+ 4. 支持定时构建
+ 5. 支持 WebHook 形式触发构建
+- 支持在线编辑 nginx 配置文件并自动 reload 等操作
+ 1. 管理 nginx 状态,管理 SSL 证书
+- 项目状态监控异常自动报警、自动尝试重启
+ 1. 支持邮件 + 钉钉群 + 微信群通知,主动感知项目运行状况
+- 节点脚本模版+定时执行或者触发器,拓展更多功能
+- 重要路径授权配置,杜绝用户误操作系统文件
+
+### 🔔️ 特别提醒
+
+> 1. 在 Windows 服务器中可能有部分功能因为系统特性造成兼容性问题,建议在实际使用中充分测试。Linux 目前兼容性良好
> 2. 服务端和插件端请安装到不同目录中,切勿安装到同一目录中
-> 3. 卸载 Jpom 插件端或者服务端,先停止对应服务,删除对应的程序文件、日志文件夹、数据目录文件夹即可
-> 4. 构建依赖的是系统环境,如果需要 maven 或者 node 需要服务端所在的服务器中有对应插件,如果已经启动服务端再安装的对应环境需要通过命令行重启服务端后才生效。
+> 3. 卸载 Jpom 插件端或者服务端,先停止对应服务,然后删除对应的程序文件、日志文件夹、数据目录文件夹即可
+> 4. 本地构建依赖的是系统环境,如果构建命令需要使用 maven 或者 node
+ 需要在构建项目的服务器安装好对应的环境。如果已经启动服务端再安装的对应环境需要通过命令行重启服务端后环境才会生效。
+> 5. 在 Ubuntu/Debian 服务器作为插件端可能会添加失败,请在当前用户的根目录创建 .bash_profile 文件
+> 6. 升级 2.7.x 后不建议降级操作,会涉及到数据不兼容的情况
+> 7. 由于目前 2.x.x 版本插件端和服务端主要采用 http 协议通讯,插件端和服务端网络要求互通,在使用的时候请注意。
+> 8. Jpom 3.0 版本已经开始规划更新了,尽请期待新版本的诞生吧
+
+### 🗒️ [版本更新日志](https://gitee.com/dromara/Jpom/blob/master/CHANGELOG.md)
+
+升级前必看:[CHANGELOG.md](https://gitee.com/dromara/Jpom/blob/master/CHANGELOG.md)
+
+## 📥 安装 Jpom
+
+Jpom 支持多种安装方式,满足不同用户的个性化需求,您只需要选择一种方式安装即可。
+
+### 方式一:🚀(推荐) 一键安装(Linux)
+
+#### 一键安装服务端
+
+> **注意:安装的目录位于执行命令的目录!**
+>
+> ⚠️ 特别提醒:一键安装的时候注意执行命令不可在同一目录下,即 Server 端和 Agent 端不可安装在同一目录下!
+>
+> 如果需要修改服务端数据、日志存储的路径请修改
+> [`application.yml`](https://gitee.com/dromara/Jpom/blob/master/modules/server/src/main/resources/config_default/application.yml)
+> 文件中 `jpom.path` 配置属性。
+
+```shell
+# 一键默认安装
+curl -fsSL https://jpom.top/docs/install.sh | bash -s Server jdk+default
+# 一键默认安装 + 自动配置开机自启服务
+curl -fsSL https://jpom.top/docs/install.sh | bash -s Server jdk+default+service
+
+# 安装服务端和 jdk 环境
+yum install -y wget && \
+wget -O install.sh https://jpom.top/docs/install.sh && \
+bash install.sh Server jdk
+
+# 安装服务端和 jdk、maven 环境
+yum install -y wget && \
+wget -O install.sh https://jpom.top/docs/install.sh && \
+bash install.sh Server jdk+mvn
+
+# ubuntu
+apt-get install -y wget && \
+wget -O install.sh https://jpom.top/docs/install.sh && \
+bash install.sh Server jdk
+```
-> 升级 2.7.x 后不建议降级操作,会涉及到数据不兼容到情况
->
-> [2.6.x "稳定版" 分支](https://gitee.com/dromara/Jpom/tree/2.6.x/)
+启动成功后,服务端的端口为 `2122`,可通过 `http://127.0.0.1:2122/`
+访问管理页面(如果不是本机访问,需要把 127.0.0.1 换成您安装的服务器 IP 地址)。
+
+> 如无法访问管理系统,执行命令 `systemctl status firewalld` 检查下是否开启了防火墙
+> ,如状态栏看到绿色显示 `Active: active (running)` 需要放行 `2122` 端口。
+>
+>```bash
+># 放行管理系统的 2122 端口
+>firewall-cmd --add-port=2122/tcp --permanent
+># 重启防火墙才会生效
+>firewall-cmd --reload
+>```
+>
+>如果在操作系统上放行了端口仍无法访问,并且您使用的是云服务器,请到云服务器后台中检查安全组规则是否放行 2122 端口。
+>
+>⚠️ 注意: Linux 系统中有多种防火墙:Firewall、Iptables、SELinux 等,再检查防火墙配置时候需要都检查一下。
+
+#### 一键安装插件端
+
+> 如果安装服务端的服务器也需要被管理,在服务端上也需要安装插件端(同一个服务器中可以同时安装服务端和插件端)
+>
+> ⚠️ 特别提醒:一键安装的时候注意执行命令不可在同一目录下,即 Server 端和 Agent 端不可安装在同一目录下!
+>
+> 如果需要修改插件端数据、日志存储的路径请修改
+> [`application.yml`](https://gitee.com/dromara/Jpom/blob/master/modules/agent/src/main/resources/config_default/application.yml)
+> 文件中 `jpom.path` 配置属性。
+
+```shell
+# 一键默认安装
+curl -fsSL https://jpom.top/docs/install.sh | bash -s Agent jdk+default
+# 一键默认安装 + 自动配置开机自启服务
+curl -fsSL https://jpom.top/docs/install.sh | bash -s Agent jdk+default+service
+
+# 安装插件端和 jdk 环境
+yum install -y wget && \
+wget -O install.sh https://jpom.top/docs/install.sh && \
+bash install.sh Agent jdk
+
+# ubuntu
+apt-get install -y wget && \
+wget -O install.sh https://jpom.top/docs/install.sh && \
+bash install.sh Agent jdk
+```
-#### 版本更新日志
+启动成功后,插件端的端口为 `2123`,插件端提供给服务端使用。
-[CHANGELOG.md](https://gitee.com/dromara/Jpom/blob/master/CHANGELOG.md)
+### 方式二:📦 容器化安装
-### 一键安装(Linux)(推荐)
+> ⚠️ 注意:容器化安装方式需要先安装 docker,[点击跳转docker安装文档](https://jpom.top/pages/b63dc5/)
-#### 插件端
-> 如果服务端也需要被管理,在服务端上也需要安装插件端
->
-> 安装的路径位于执行命令目录(数据、日志存放目录默认位于安装路径,如需要修改参考配置文件:[`extConfig.yml`](https://gitee.com/dromara/Jpom/blob/master/modules/agent/src/main/resources/bin/extConfig.yml) )
+#### 一条命令安装
+```shell
+docker run -p 2122:2122 --name jpom-server jpomdocker/jpom
```
-yum install -y wget && wget -O install.sh https://dromara.gitee.io/jpom/docs/install.sh && bash install.sh Agent
-备用地址
+#### 使用挂载方式存储相关数据(在部分环境可能出现兼容性问题)
+
+```shell
+docker pull jpomdocker/jpom
+mkdir -p /home/jpom-server/logs
+mkdir -p /home/jpom-server/data
+mkdir -p /home/jpom-server/conf
+docker run -d -p 2122:2122 \
+ --name jpom-server \
+ -v /home/jpom-server/logs:/usr/local/jpom-server/logs \
+ -v /home/jpom-server/data:/usr/local/jpom-server/data \
+ -v /home/jpom-server/conf:/usr/local/jpom-server/conf \
+ jpomdocker/jpom
+```
-yum install -y wget && wget -O install.sh https://cdn.jsdelivr.net/gh/dromara/Jpom/docs/install.sh && bash install.sh Agent
+#### 使用容器卷方式存储相关数据
+
+```shell
+docker pull jpomdocker/jpom
+docker volume create jpom-server-data
+docker volume create jpom-server-logs
+docker volume create jpom-server-conf
+docker run -d -p 2122:2122 \
+ --name jpom-server \
+ -v jpom-server-data:/usr/local/jpom-server/data \
+ -v jpom-server-logs:/usr/local/jpom-server/logs \
+ -v jpom-server-conf:/usr/local/jpom-server/conf \
+ jpomdocker/jpom
+```
-支持自动安装jdk环境
+> 容器化安装仅提供服务端版。由于容器和宿主机环境隔离,而导致插件端的很多功能无法正常使用,因此对插件端容器化意义不大。
+>
+> 安装docker、配置镜像、自动启动、查找安装后所在目录等可参考文档
+> [https://jpom.top/pages/b63dc5/](https://jpom.top/pages/b63dc5/)
+>
+> 在低版本 docker 中运行可能出现 `ls: cannot access'/usr/local/jpom-server/lib/': Operation not permitted`
+> 错误,此时需要添加 `--privileged` 参数
+> 如:`docker run -p 2122:2122 --name jpom-server jpomdocker/jpom --privileged`
-yum install -y wget && wget -O install.sh https://dromara.gitee.io/jpom/docs/install.sh && bash install.sh Agent jdk
+### 方式三:💾 下载安装
+1. 下载安装包 [https://jpom.top/pages/all-downloads/](https://jpom.top/pages/all-downloads/)
+2. 解压文件
+3. 安装插件端
+ 1. `agent-x.x.x-release` 目录为插件端的全部安装文件
+ 2. 上传到对应服务器(整个目录)
+ 3. 启动插件端,Windows 环境用 bat 脚本,Linux 环境用 sh 脚本。(如果出现乱码或者无法正常执行,请检查编码格式、换行符是否匹配。)
+ 4. 插件端默认运行端口:`2123`
+4. 安装服务端
+ 1. `server-x.x.x-release` 目录为服务端的全部安装文件
+ 2. 上传到对应服务器(整个目录)
+ 3. 启动服务端,Windows 环境用 bat 脚本,Linux 环境用 sh 脚本。(如果出现乱码或者无法正常执行,请检查编码格式、换行符是否匹配。)
+ 4. 服务端默认运行端口:`2122`,访问管理页面:`http://127.0.0.1:2122/`(非本机访问把 `127.0.0.1` 换成您的服务器 IP 地址)
+
+### 方式四:⌨️ 编译安装
+
+1. 访问 [Jpom](https://gitee.com/dromara/Jpom) 的码云主页,拉取最新完整代码(建议使用 master 分支)
+2. 切换到 `web-vue` 目录,执行 `npm install`(vue 环境需要提前搭建和安装依赖包详情可以查看 web-vue 目录下 README.md)
+3. 执行 `npm run build` 进行 vue 项目打包
+4. 切换到项目根目录执行:`mvn clean package`
+5. 安装插件端
+ 1. 查看插件端安装包 `modules/agent/target/agent-x.x.x-release`
+ 2. 打包上传服务器运行(整个目录)
+ 3. 启动插件端,Windows 环境用 bat 脚本,Linux 环境用 sh 脚本。(如果出现乱码或者无法正常执行,请检查编码格式、换行符是否匹配。)
+ 4. 默认运行端口:`2123`
+6. 安装服务端
+ 1. 查看插件端安装包 `modules/server/target/server-x.x.x-release`
+ 2. 打包上传服务器运行(整个目录)
+ 3. 启动服务端,Windows 环境用 bat 脚本,Linux 环境用 sh 脚本。(如果出现乱码或者无法正常执行,请检查编码格式、换行符是否匹配。)
+ 4. 服务端默认运行端口:`2122`,访问管理页面:`http://127.0.0.1:2122/`(非本机访问把 `127.0.0.1` 换成您的服务器 IP 地址)
+
+> 也可以使用 `script/release.bat` 或 `script/release.sh` 快速打包。
+
+### 方式五:📦 一键启动 docker-compose
+
+- 无需安装任何环境,自动编译构建
+
+> 需要注意修改 `.env` 文件中的 token 值
+
+```shell
+yum install -y git
+git clone https://gitee.com/dromara/Jpom.git
+cd Jpom
+docker-compose -f docker-compose.yml up
+# docker-compose -f docker-compose.yml up --build
+# docker-compose -f docker-compose.yml build --no-cache
+# docker-compose -f docker-compose-local.yml up
+# docker-compose -f docker-compose-local.yml build --build-arg TEMP_VERSION=.0
+# docker-compose -f docker-compose-cluster.yml up --build
```
-启动成功后,插件端的端口为 `2123`
-
-#### 服务端
+### 方式六:💻 编译运行
-> 安装的路径位于执行命令目录(数据、日志存放目录默认位于安装路径,如需要修改参考配置文件:[`extConfig.yml`](https://gitee.com/dromara/Jpom/blob/master/modules/server/src/main/resources/bin/extConfig.yml) )
->
-> 如果需要修改数据、日志存储路径请参照 `extConfig.yml` 文件中 `jpom.path` 配置属性
+1. 访问 [Jpom](https://gitee.com/dromara/Jpom) 的码云主页 拉取最新完整代码 (建议使用 master 分支,如果想体验新功能可以使用
+ dev 分支)
+2. 运行插件端
+ 1. 运行 `org.dromara.jpom.JpomAgentApplication`
+ 2. 留意控制台打印的默认账号密码信息
+ 3. 插件端默认运行端口:`2123`
+3. 运行服务端
+ 1. 运行 `org.dromara.jpom.JpomServerApplication`
+ 2. 服务端默认运行端口:`2122`
+4. 构建 vue 页面,切换到 `web-vue` 目录(前提需要本地开发环境有 node、npm 环境)
+5. 安装项目 vue 依赖,控制台执行 `npm install`
+6. 启动开发模式,控制台执行 `npm run dev`
+7. 根据控制台输出的地址访问前端页面:`http://127.0.0.1:3000/`(非本机访问把 `127.0.0.1` 换成您的服务器 IP 地址)
+
+## 管理 Jpom 命令
+
+1. Windows 系统使用 bat 脚本文件。
+
+```bash
+# 服务端管理脚本 (命令行)
+./bin/Server.bat start # 启动Jpom服务端
+./bin/Server.bat stop # 停止Jpom服务端
+./bin/Server.bat restart # 重启Jpom服务端
+./bin/Server.bat status # 查看Jpom服务端运行状态
+# 服务端管理脚本 (控制面板),按照面板提示输入操作
+./bin/Server.bat
+
+# 插件端管理脚本
+./bin/Agent.bat start # 启动Jpom插件端
+./bin/Agent.bat stop # 停止Jpom插件端
+./bin/Agent.bat restart # 重启Jpom插件端
+./bin/Agent.bat status # 查看Jpom插件端运行状态
+# 插件端管理脚本(控制面板),按照面板提示输入操作
+./bin/Agent.bat
```
-yum install -y wget && wget -O install.sh https://dromara.gitee.io/jpom/docs/install.sh && bash install.sh Server
-备用地址
+> Windows 系统中执行启动后需要根据日志去跟进启动的状态,如果出现乱码请检查或者修改编码格式,Windows 系统中 bat
+> 编码格式推荐为 `GB2312`
-yum install -y wget && wget -O install.sh https://cdn.jsdelivr.net/gh/dromara/Jpom/docs/install.sh && bash install.sh Server
+2. Linux 系统中使用 sh 脚本文件。
+```bash
+# 服务端
+./bin/Server.sh start # 启动Jpom服务端
+./bin/Server.sh stop # 停止Jpom服务端
+./bin/Server.sh restart # 重启Jpom服务端
+./bin/Server.sh status # 查看Jpom服务端运行状态
+./bin/Service.sh install # 创建Jpom服务端的应用服务(jpom-server)
-支持自动安装jdk环境
+# 插件端
+./bin/Agent.sh start # 启动Jpom插件端
+./bin/Agent.sh stop # 停止Jpom插件端
+./bin/Agent.sh restart # 重启Jpom插件端
+./bin/Agent.sh status # 查看Jpom插件端运行状态
+./bin/Service.sh install # 创建Jpom插件端的应用服务(jpom-agent)
+```
-yum install -y wget && wget -O install.sh https://dromara.gitee.io/jpom/docs/install.sh && bash install.sh Server jdk
+## Linux 服务方式管理
-支持自动安装jdk和maven环境
+> 这里安装服务仅供参考,实际中可以根据需求自定义配置
+>
+> 在使用 `./bin/Service.sh install` 成功后
+>
+> systemctl {status | start | stop | restart} jpom-server
+>
+> systemctl {status | start | stop | restart} jpom-agent
-yum install -y wget && wget -O install.sh https://dromara.gitee.io/jpom/docs/install.sh && bash install.sh Server jdk+mvn
+## ⚙️ Jpom 的参数配置
-```
+在项目运行的根路径下的 :
-启动成功后,服务端的端口为 `2122` 访问管理页面 例如`http://127.0.0.1:2122/`
+### 程序配置 `./conf/application.yml`
-> 特别提醒:一键安装的时候注意执行命令不可在同一目录下,即Server端和Agent端不可安装在同一目录下
->
-> 如无法访问,检查下是否开启了防火墙`systemctl status firewalld`,如状态显示为绿色`Active: active (running)`可临时关闭防火墙`systemctl stop firewalld`,然后重启防火墙`firewall-cmd --reload`(建议仅测试环境下使用,生产环境下慎用)
-> 如关闭防火墙后仍无法访问,并且使用的是云服务器,还需要到云服务器管理后台中关闭防火墙
+1. 插件端示例:
+ [`application.yml`](https://gitee.com/dromara/Jpom/blob/master/modules/agent/src/main/resources/config_default/application.yml)
+2. 服务端示例:
+ [`application.yml`](https://gitee.com/dromara/Jpom/blob/master/modules/server/src/main/resources/config_default/application.yml)
-### 容器化安装
+### 项目日志 `./conf/logback.xml`
-#### 插件端
+1. 插件端示例:
+ [`logback.xml`](https://gitee.com/dromara/Jpom/blob/master/modules/agent/src/main/resources/config_default/logback.xml)
+2. 服务端示例:
+ [`logback.xml`](https://gitee.com/dromara/Jpom/blob/master/modules/server/src/main/resources/config_default/logback.xml)
-```
-docker pull samho2008/jpom-agent
-docker volume create jpom-agent-vol
-docker run -d -p 2123:2123 --name jpom-agent -v /etc/localtime:/etc/localtime:ro -v jpom-agent-vol:/usr/local/jpom-agent samho2008/jpom-agent
-```
+## 📝 常见问题、操作说明
-#### 服务端
+- [文档主页](https://jpom.top/)
+- [FQA](https://jpom.top/pages/FQA/)
+- [名词解释](https://jpom.top/pages/FQA/proper-noun/)
-```
-docker pull samho2008/jpom-server
-docker volume create jpom-server-vol
-docker run -d -p 2122:2122 --name jpom-server -v /etc/localtime:/etc/localtime:ro -v jpom-server-vol:/usr/local/jpom-server samho2008/jpom-server
-```
+### 实践案例
-### 下载安装
+> 里面有部分图片加载可能比较慢
-> [帮助文档](https://jpom-site.keepbx.cn/docs/#/安装使用/开始安装)
+1. [本地构建 + SSH 发布 java 项目](https://jpom.top/pages/practice/build-java-ssh-release/)
+2. [本地构建 + 项目发布 node 项目](https://jpom.top/pages/practice/build-node-release/)
+3. [本地构建 + SSH 发布 node 项目](https://jpom.top/pages/practice/build-node-ssh-release/)
+4. [本地构建 + 自定义管理 python 项目](https://jpom.top/pages/practice/project-dsl-python/)
+5. [自定义管理 java 项目](https://jpom.top/pages/practice/project-dsl-java/)
+6. [管理编译安装的 nginx](https://jpom.top/pages/practice/node-nginx/)
+7. [管理 docker](https://jpom.top/pages/practice/docker-cli/)
+8. [容器构建 + 项目发布 java 项目](https://jpom.top/pages/practice/build-docker-java-node-release/)
+9. [更新实践案例>>](https://jpom.top/pages/practice/)
-1. 下载安装包 [https://gitee.com/dromara/Jpom/attach_files](https://gitee.com/dromara/Jpom/attach_files)
-2. 解压文件
-3. 安装插件端( [流程说明](https://jpom-site.keepbx.cn/docs/#/安装使用/开始安装?id=安装插件端) )
- 1. agent-x.x.x-release 目录为插件端的全部安装文件
- 2. 上传到对应服务器
- 3. 命令运行(Agent.sh、Agent.bat)
- 4. 默认运行端口:`2123`
-4. 安装服务端( [流程说明](https://jpom-site.keepbx.cn/docs/#/安装使用/开始安装?id=安装服务端) )
- 1. server-x.x.x-release 目录为服务端的全部安装文件
- 2. 上传到对应服务器
- 3. 命令运行(Server.sh、Server.bat)
- 4. 默认运行端口:`2122` 访问管理页面 例如`http://127.0.0.1:2122/`
-
-### 编译安装
-
-> [帮助文档](https://jpom-site.keepbx.cn/docs/#/安装使用/开始安装)
-
-1. 访问 [Jpom](https://gitee.com/dromara/Jpom) 的码云主页,拉取最新完整代码(建议使用master分支)
-2. 切换到`web-vue`目录 执行`npm install` (vue环境需要提前搭建和安装依赖包详情可以查看web-vue目录下README.md)
-3. 执行`npm build`进行vue项目打包(vue环境需要提前搭建和安装依赖包详情可以查看web-vue目录下README.md)
-4. 切换到项目根目录执行:`mvn clean package`
-5. 安装插件端( [流程说明](https://jpom-site.keepbx.cn/docs/#/安装使用/开始安装?id=安装插件端) )
- 1. 查看插件端安装包 modules/agent/target/agent-x.x.x-release
- 2. 打包上传服务器运行
- 3. 命令运行(Agent.sh、Agent.bat)
- 4. 默认运行端口:`2123`
-6. 安装服务端( [流程说明](https://jpom-site.keepbx.cn/docs/#/安装使用/开始安装?id=安装服务端) )
- 1. 查看插件端安装包 modules/server/target/server-x.x.x-release
- 2. 打包上传服务器运行
- 3. 命令运行(Server.sh、Server.bat)
- 4. 默认运行端口:`2122` 访问管理页面 例如`http://127.0.0.1:2122/`
-
-> 也可以使用 `script/release.bat` `script/release.sh` 快速打包
-
-### 编译运行
-
-1. 访问 [Jpom](https://gitee.com/dromara/Jpom) 的码云主页,拉取最新完整代码(建议使用master分支、如果想体验新功能请使用dev分支)
-2. 运行插件端
- 1. 运行`io.jpom.JpomAgentApplication`
- 2. 注意控制台打印的默认账号密码信息
- 3. 默认运行端口:`2123`
-3. 运行服务端
- 1. 运行`io.jpom.JpomServerApplication`
- 2. 默认运行端口:`2122`
-4. 构建vue页面 切换到`web-vue`目录(前提需要本地开发环境有node、npm环境)
-5. 安装项目vue依赖 控制台执行 `npm install`
-6. 启动开发模式 控制台执行 `npm serve`
-7. 根据控制台输出的地址访问前端页面 例如`http://127.0.0.1:3000/`
+## 构建案例仓库代码
-### 管理命令
+1. [Jboot 案例代码](https://gitee.com/keepbx/Jpom-demo-case/tree/master/jboot-test)
+2. [SpringBoot 案例代码(ClassPath)](https://gitee.com/keepbx/Jpom-demo-case/tree/master/springboot-test)
+3. [SpringBoot 案例代码(Jar)](https://gitee.com/keepbx/Jpom-demo-case/tree/master/springboot-test-jar)
+4. [node vue 案例代码(antdv)](https://gitee.com/keepbx/Jpom-demo-case/tree/master/antdv)
+5. [python 案例代码](https://gitee.com/keepbx/Jpom-demo-case/tree/master/python)
-1. windows 中 Agent.bat 、Server.bat
+> Node.js 编译指定目录:
+```bash
+yarn --cwd xxxx/ install
+yarn --cwd xxxx/ build
```
-# 服务端
-Server.bat 启动管理面板(按照面板提示输入操作)
-# 插件端
-Agent.bat 启动管理面板(按照面板提示输入操作)
+> Maven 编译指定目录:
+
+```bash
+mvn -f xxxx/pom.xml clean package
```
-> windows 中执行启动后需要根据日志取跟进启动的状态
+## 🛠️ 整体架构
-2. linux 中 Agent.sh 、Server.sh
+
-```
-# 服务端
-Server.sh start 启动Jpom服务端
-Server.sh stop 停止Jpom服务端
-Server.sh restart 重启Jpom服务端
-Server.sh status 查看Jpom服务端运行状态
-Server.sh create 创建Jpom服务端的应用服务(jpom-server)
-# 插件端
-Agent.sh start 启动Jpom插件端
-Agent.sh stop 停止Jpom插件端
-Agent.sh restart 重启Jpom插件端
-Agent.sh status 查看Jpom插件端运行状态
-Agent.sh create 创建Jpom插件端的应用服务(jpom-agent)
-```
+## 🐞 交流讨论 、反馈 BUG、提出建议等
-### linux 服务方式管理
+1. 快扫描下方左侧微信群二维码和我们一起交流讨论吧!(添加小助手:备注 Jpom 进群)
+2. 开源项目离不开社区的支持,如果项目帮助到了您,并且想给我们加个餐。
+ 欢迎扫描下方[微信、支付宝收款码赞赏](https://jpom.top/images/qrcode/praise-all.png)
+ 或通过[码云赞赏](https://gitee.com/dromara/Jpom)
+ (在项目首页下方点击捐赠,支持微信和支付宝)。[赞赏记录](https://jpom.top/pages/praise/publicity/)
+3. 购买开源周边商品:[周边介绍](https://jpom.top/pages/shop/)
+4. 企业技术服务请单独与我们联系沟通服务方案
+5. 反馈 BUG、提出建议,欢迎新建:[issues](https://gitee.com/dromara/Jpom/issues),开发人员会不定时查看回复。
+6. 参与贡献,请查看[贡献指南](#贡献指南)。
-> 在使用 `Server.sh create`/`Agent.sh create` 成功后
->
-> service jpom-server {status | start | stop}
->
-> service jpom-agent {status | start | stop}
+感谢所有赞赏以及参与贡献的小伙伴,您们的支持是我们不断更新前进的动力!
+
+
+
-### Jpom 的参数配置
+## 💖 周边商品
-在项目运行的根路径下的`extConfig.yml`文件
+为了更好地维持开源项目,我们决定推出周边商品。
-1. 插件端示例:[`extConfig.yml`](https://gitee.com/dromara/Jpom/blob/master/modules/agent/src/main/resources/bin/extConfig.yml)
-2. 服务端示例:[`extConfig.yml`](https://gitee.com/dromara/Jpom/blob/master/modules/server/src/main/resources/bin/extConfig.yml)
+购买支持我们这样您既获得了一份小商品我们也获得了您购买商品的利润(周边商品的价格会比市场价稍高,介意请勿下单)
-### 演示项目
+
+
+
-[https://jpom.keepbx.cn](https://jpom.keepbx.cn)
+## 🔨贡献指南
-```
-账号:demo
-密码:demo123
-```
+> 提交贡献即认为签署了 [CLA](https://gitee.com/dromara/Jpom/blob/master/CLA.md) 协议
-> 演示系统有部分功能做了限制,完整功能请自行部署体验
+### 贡献须知
-> 如果出现登录不上,请联系我们,联系方式在最底部
+Jpom 作为开源项目,离不开社区的支持,欢迎任何人修改和提出建议。贡献无论大小,您的贡献会帮助背后成千上万的使用者以及开发者,您做出的贡献也会永远的保留在项目的贡献者名单中,这也是开源项目的意义所在!
-1. [Jboot案例代码](https://gitee.com/keepbx/Jpom-demo-case/tree/master/jboot-test)
-2. [SpringBoot案例代码(ClassPath)](https://gitee.com/keepbx/Jpom-demo-case/tree/master/springboot-test)
-3. [SpringBoot案例代码(Jar)](https://gitee.com/keepbx/Jpom-demo-case/tree/master/springboot-test-jar)
+为了保证项目代码的质量与规范,以及帮助您更快的了解项目的结构,请在贡献之前阅读:
-### 常见问题、操作说明
+- [Jpom 贡献说明](https://gitee.com/dromara/Jpom/blob/master/CODE_OF_CONDUCT.md)
+- [中英文排版规范](https://gitee.com/dromara/Jpom/blob/dev/typography-specification.md)
-[https://jpom-site.keepbx.cn/docs/](https://jpom-site.keepbx.cn/docs/)
+### 贡献步骤
-[https://jpom-site.keepbx.cn/docs/#/FQA/FQA](https://jpom-site.keepbx.cn/docs/#/FQA/FQA)
+1. Fork 本仓库。
-[Jpom 插件开发](https://gitee.com/keepbx/Jpom-Plugin)
+2. Fork 后会在您的账号下多了一个和本仓库一模一样的仓库,把您账号的仓库 clone 到本地。
-### 交流讨论 、提供bug反馈或建议
+ 注意替换掉链接中的`分支名`和`用户名`。
-1. 微信群二维码(添加小助手:备注Jpom 进群)
+ 如果是贡献代码,分支名填 `dev`;如果是贡献文档,分支名填 `docs`
-
+ ```bash
+ git clone -b 分支名 https://gitee.com/用户名/Jpom.git
+ ```
-2. 微信公众号:[CodeGzh](https://cdn.jsdelivr.net/gh/jiangzeyin/Jpom-site/docs/images/CodeGzh-QrCode.jpg) 查看一些基础教程
+3. 修改代码/文档,修改后提交上来。
-3. 码云: [issues](https://gitee.com/dromara/Jpom/issues)
+ ```bash
+ # 把修改的文件添加到暂存区
+ git add .
+ # 提交到本地仓库,说明您具体做了什么修改
+ git commit -m '填写您做了什么修改'
+ # 推送到远程仓库,分支名替换成 dev 或者 docs
+ git push origin 分支名
+ ```
-4. [码云赞赏: 在码云仓库项目首页下方捐赠、打赏](https://gitee.com/dromara/Jpom)
+4. 登录您的仓库,然后会看到一条 PR 请求,点击请求合并,等待管理员把您的代码合并进来。
-5. 微信赞赏 [赞赏记录](./docs/praise/praise.md)
+### 项目分支说明
-
+| 分支 | 说明 |
+|--------|------------------------------------------------------|
+| master | 主分支,受保护分支,此分支不接受 PR。在 beta 分支后经过测试没问题后会合并到此分支。 |
+| beta | beta 版本 分支,受保护分支,此分支不接受 PR。在 dev 分支后经过测试没问题后会合并到此分支。 |
+| dev | 开发分支,接受 PR,PR 请提交到 dev 分支。 |
+| docs | 项目文档分支,接受 PR,介绍项目功能、汇总常见问题等。 |
+> 目前用到的主要是 dev 和 docs 分支,接受 PR 修改,其他的分支为归档分支,贡献者可以不用管。
-### 精品项目推荐
+### 贡献者
-|项目名称 | 项目地址 | 项目介绍 |
-|---|---|---|
-| SpringBoot_v2 | [https://gitee.com/bdj/SpringBoot_v2](https://gitee.com/bdj/SpringBoot_v2) | 基于springboot的一款纯净脚手架|
-| TLog GVP 项目 | [https://gitee.com/dromara/TLog](https://gitee.com/dromara/TLog) | 一个轻量级的分布式日志标记追踪神器,10分钟即可接入,自动对日志打标签完成微服务的链路追踪 |
-| Sa-Token | [https://gitee.com/dromara/sa-token](https://gitee.com/dromara/sa-token) | 这可能是史上功能最全的 Java 权限认证框架! |
-| Erupt | [https://gitee.com/erupt/erupt](https://gitee.com/erupt/erupt) | 零前端代码,纯注解开发 admin 管理后台 |
+
+
+
-### giteye
+Made with [contrib.rocks](https://contrib.rocks).
-[](https://giteye.net/chart/N4VGB7ZB)
\ No newline at end of file
+## 🌍 知识星球
+
+
+
+
+
+## 🔔 精品项目推荐
+
+| 项目名称 | 项目地址 | 项目介绍 |
+|---------------|----------------------------------------------------------------------------|-----------------------------------------------|
+| SpringBoot_v2 | [https://gitee.com/bdj/SpringBoot_v2](https://gitee.com/bdj/SpringBoot_v2) | 基于springboot的一款纯净脚手架 |
+| TLog GVP 项目 | [https://gitee.com/dromara/TLog](https://gitee.com/dromara/TLog) | 一个轻量级的分布式日志标记追踪神器,10分钟即可接入,自动对日志打标签完成微服务的链路追踪 |
+| Sa-Token | [https://gitee.com/dromara/sa-token](https://gitee.com/dromara/sa-token) | 这可能是史上功能最全的 Java 权限认证框架! |
+| Erupt | [https://gitee.com/erupt/erupt](https://gitee.com/erupt/erupt) | 零前端代码,纯注解开发 admin 管理后台 |
+| hippo4j | [https://gitee.com/magegoofy/hippo4j](https://gitee.com/magegoofy/hippo4j) | 强大的动态线程池框架,附带监控报警功能。 |
+| HertzBeat | [https://gitee.com/dromara/hertzbeat](https://gitee.com/dromara/hertzbeat) | 易用友好的云监控系统, 无需 Agent, 强大自定义监控能力。 |
+
+## 🤝 鸣谢
+
+- 感谢 JetBrains 提供的免费开源 License:
+
+
+
+
diff --git a/README_CONTRIBUTE.md b/README_CONTRIBUTE.md
deleted file mode 100644
index f12f797b89..0000000000
--- a/README_CONTRIBUTE.md
+++ /dev/null
@@ -1,71 +0,0 @@
-# Jpom 贡献说明
-
-## 目录说明
-
-```
-.
-├── .gitee => gitee 配置
-├── docs => 一键安装的命令脚本以及版本号文件
-├── modules => java 后端目录(agent、server)
- ├── agent => 插件端代码
- ├── commone => 这个项目的公共模块(插件端、服务端都依赖该模块)
- ├── server => 服务端代码
-├── script => 一些通用脚本
-├── web-vue => 前端 vue 目录
- ├── .editorconfig => 前端(vue)代码格式配置
-├── .editorconfig => 全局代码格式配置
-├── .gitattributes => 文件编码格式配置
-└── .... => 仓库一些默认配置
-```
-
-## 一些规范说明
-
-1. 写完代码后在保证不影响其他的人的代码情况下尽量统一格式化一下代码
-2. Java 代码需要保证新增方法都有充足、标准的 JavaDoc 注释
-3. 在修改 Bug、新增功能尽量保证最小提交的方式提交代码,减少多个功能一个 commit
-4. 所有接口 url 都需要遵循下划线模式
-5. Java 代码、方法需要遵循小驼峰法
-6. Java 类名需要遵循大驼峰法
-7. 前端项目统一采用 `prettier` 方式来格式化(需要安装插件)
-
-> 注:由于旧代码存在很多不规范问题,会逐步调整为新规范。在新写的代码都需要需要遵循上面说明
->
->
-### 类的文档注释规范(Javadoc)
-
-```
-/**
- * xxxxxxxx
- * @author xxxx
- * @since ${DATE}
- */
-```
-
-> 这里采用 `@since` 声明创建日期是因为 `Javadoc` 规范里面并没有 `@date` 标记所以采用 `@since` 代替
-
-### Java 代码规范
-
-> 推荐安装 `Alibaba Java Coding Guidelines`(`p3c`) 插件
-
-##### 代码级别的多行注释
-
-[https://www.e-learn.cn/topic/3680721](https://www.e-learn.cn/topic/3680721)
-
-## changelog 更新规范
-
-> 在新加功能、修护bug、优化功能在完成时候都需要在 [CHANGELOG.md](./CHANGELOG.md) 记录
-
-1. 如果是使用者反馈的bug,在修护后需要备注反馈人的昵称
-2. 如果是 issue 需要备注 issue 地址以及平台(Gitee、GitHub)
-3. 如果是 pr 需要备注 pr 地址以及平台(Gitee、GitHub)
-4. 根据变动情况确定影响范围:如果影响 只:`agent`、`server` 其中一个,就使用【agent】、【server】开头,如果都影响就不用
-5. 可以视情况添加其他说明:如提交记录
-
-
-## 需要的小组
-
-1. 后端小组 (主要任务:根据需求开发对应的接口)
-2. 前端小组 (主要任务:优化前端 UI 交互和对接部分接口)
-3. 文档小组 (主要任务:完善、补充 Jpom 使用文档)
-4. 视频小组 (主要任务:录制 Jpom 相关的使用视频)
-5. 测试小组 (主要任务:参与 Jpom 新版内测、日常开发测试相关任务)
\ No newline at end of file
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000000..a2210d5740
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,23 @@
+# Security Policy
+
+## Supported Versions
+
+Use this section to tell people about which versions of your project are
+currently being supported with security updates.
+
+| Version | Supported |
+|-------------|--------------------|
+| 2.11.x | :white_check_mark: |
+| 2.10.x | :white_check_mark: |
+| 2.9.x | :white_check_mark: |
+| 2.8.x | :x: |
+| 2.8.1-2.8.6 | :x: |
+| < 2.7 | :x: |
+
+## Reporting a Vulnerability
+
+Use this section to tell people how to report a vulnerability.
+
+Tell them where to go, how often they can expect to get an update on a
+reported vulnerability, what to expect if the vulnerability is accepted or
+declined, etc.
diff --git a/best_practices.md b/best_practices.md
deleted file mode 100644
index d7f0a7430f..0000000000
--- a/best_practices.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Jpom最佳实践征文
-
-## 活动介绍
-
-在我们使用Jpom部署运维过程中,经常会get到一些最佳的解决方法,或者在使用过程中遇到不太明白的问题,再使用比较早或者大佬已经知道怎么更好的使用Jpom实现需要的效果,
-为了更好地帮忙大家使用Jpom,在此举办最佳实践征文,为后面使用Jpom的同学提供参考,
-快来秀一秀你使用Jpom部署运维的的神操作,顺便拿个大奖~
-
-## 奖品
-
-1. 一篇有效博文链接10-50元现金红包
-2. 一篇搜索引擎收录博文链接20-50元现金红包
-
-## 参与方式
-
-1. oschina(开源中国)
-2. csdn
-3. 简书
-4. 博客园
-
-## 推荐博文主题
-
-1. 如何部署Jpom
-2. 集群环境使用Jpom
-3. Jpom 节点管理
-4. Jpom的基础配置
-
-## 领奖方式
-
-1. 加入微信群:添加微信 `jpom66` 根据提示进入微信群,发博文链接,管理确认后将进行现金私发红包
diff --git a/docker-compose-cluster.yml b/docker-compose-cluster.yml
new file mode 100644
index 0000000000..7ff60f23d3
--- /dev/null
+++ b/docker-compose-cluster.yml
@@ -0,0 +1,95 @@
+#
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+#
+
+version: '3.8'
+services:
+ server:
+ env_file:
+ - env-beta.env
+ image: jpomdocker/jpom:server-${JPOM_VERSION}
+ build:
+ dockerfile: ./modules/server/Dockerfile
+ context: .
+ args:
+ JPOM_VERSION: ${JPOM_VERSION}
+ environment:
+ "JPOM_SERVER_TEMP_TOKEN": ${SERVER_TOKEN}
+ "jpom.cluster.id": server00
+ volumes:
+ - jpom-server-data:/usr/local/jpom-server/data
+ - jpom-server-logs:/usr/local/jpom-server/logs
+ - jpom-server-conf:/usr/local/jpom-server/conf
+ ports:
+ - "2122:2122"
+ hostname: server
+ server01:
+ env_file:
+ - env-beta.env
+ image: jpomdocker/jpom:server-${JPOM_VERSION}
+ build:
+ dockerfile: ./modules/server/Dockerfile
+ context: .
+ args:
+ JPOM_VERSION: ${JPOM_VERSION}
+ environment:
+ "JPOM_SERVER_TEMP_TOKEN": ${SERVER_TOKEN}
+ "jpom.cluster.id": server01
+ volumes:
+ - jpom-server01-data:/usr/local/jpom-server/data
+ - jpom-server01-logs:/usr/local/jpom-server/logs
+ - jpom-server01-conf:/usr/local/jpom-server/conf
+ ports:
+ - "2120:2122"
+ hostname: server01
+ agent01:
+ env_file:
+ - env-beta.env
+ image: jpomdocker/jpom:agent-${JPOM_VERSION}
+ build:
+ dockerfile: ./modules/agent/Dockerfile
+ context: .
+ args:
+ JPOM_VERSION: ${JPOM_VERSION}
+ RUN_ARG: --auto-push-to-server 'http://server:2122/api/node/receive_push?token=${SERVER_TOKEN}&workspaceId=DEFAULT'
+
+ volumes:
+ - jpom-agent01:/usr/local/jpom-agent
+ ports:
+ - "2123:2123"
+ depends_on:
+ - server
+ hostname: agent01
+ agent02:
+ env_file:
+ - env-beta.env
+ image: jpomdocker/jpom:agent-${JPOM_VERSION}
+ build:
+ dockerfile: ./modules/agent/Dockerfile
+ context: .
+ args:
+ JPOM_VERSION: ${JPOM_VERSION}
+ RUN_ARG: --auto-push-to-server 'http://server01:2122/api/node/receive_push?token=${SERVER_TOKEN}&workspaceId=DEFAULT'
+
+ volumes:
+ - jpom-agent02:/usr/local/jpom-agent
+ ports:
+ - "2124:2123"
+ depends_on:
+ - server01
+ hostname: agent02
+volumes:
+ jpom-agent01:
+ jpom-agent02:
+ jpom-server-data:
+ jpom-server-logs:
+ jpom-server-conf:
+ jpom-server01-data:
+ jpom-server01-logs:
+ jpom-server01-conf:
diff --git a/docker-compose-local.yml b/docker-compose-local.yml
new file mode 100644
index 0000000000..1c8be68bc0
--- /dev/null
+++ b/docker-compose-local.yml
@@ -0,0 +1,72 @@
+#
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+#
+
+version: '3.8'
+services:
+ server:
+ env_file:
+ - env-release.env
+ image: jpomdocker/jpom:server-${JPOM_VERSION}
+ build:
+ dockerfile: ./modules/server/Dockerfile
+ context: .
+ args:
+ JPOM_VERSION: ${JPOM_VERSION}
+ environment:
+ "JPOM_SERVER_TEMP_TOKEN": ${SERVER_TOKEN}
+ volumes:
+ - jpom-server-data:/usr/local/jpom-server/data
+ - jpom-server-logs:/usr/local/jpom-server/logs
+ - jpom-server-conf:/usr/local/jpom-server/conf
+ ports:
+ - "2122:2122"
+ hostname: server
+ agent01:
+ env_file:
+ - env-release.env
+ image: jpomdocker/jpom:agent-${JPOM_VERSION}
+ build:
+ dockerfile: ./modules/agent/Dockerfile
+ context: .
+ args:
+ JPOM_VERSION: ${JPOM_VERSION}
+ RUN_ARG: --auto-push-to-server 'http://server:2122/api/node/receive_push?token=${SERVER_TOKEN}&workspaceId=DEFAULT'
+
+ volumes:
+ - jpom-agent01:/usr/local/jpom-agent
+ ports:
+ - "2123:2123"
+ depends_on:
+ - server
+ hostname: agent01
+ agent02:
+ env_file:
+ - env-release.env
+ image: jpomdocker/jpom:agent-${JPOM_VERSION}
+ build:
+ dockerfile: ./modules/agent/Dockerfile
+ context: .
+ args:
+ JPOM_VERSION: ${JPOM_VERSION}
+ RUN_ARG: --auto-push-to-server 'http://server:2122/api/node/receive_push?token=${SERVER_TOKEN}&workspaceId=DEFAULT'
+
+ volumes:
+ - jpom-agent02:/usr/local/jpom-agent
+ ports:
+ - "2124:2123"
+ depends_on:
+ - server
+ hostname: agent02
+volumes:
+ jpom-agent01:
+ jpom-agent02:
+ jpom-server-data:
+ jpom-server-logs:
+ jpom-server-conf:
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000000..4425bfb519
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+#
+
+version: '3.8'
+services:
+ server:
+ env_file:
+ - env-release.env
+ image: jpomdocker/jpom:server-${JPOM_VERSION}
+ build:
+ dockerfile: ./modules/server/Dockerfile
+ context: .
+ args:
+ JPOM_VERSION: ${JPOM_VERSION}
+ environment:
+ "jpom.authorize.token": ${SERVER_TOKEN}
+ volumes:
+ - jpom-server-data:/usr/local/jpom-server/data
+ - jpom-server-logs:/usr/local/jpom-server/logs
+ - jpom-server-conf:/usr/local/jpom-server/conf
+ ports:
+ - "2122:2122"
+volumes:
+ jpom-server-data:
+ jpom-server-logs:
+ jpom-server-conf:
diff --git a/docs/apidoc.json b/docs/apidoc.json
new file mode 100644
index 0000000000..f884ff94d3
--- /dev/null
+++ b/docs/apidoc.json
@@ -0,0 +1,8 @@
+{
+ "name": "Jpom 服务端接口文档",
+ "version": "1.0.0",
+ "description": "Jpom 服务端接口文档",
+ "title": "Jpom 服务端接口文档",
+ "url": "http://127.0.0.1:2122/",
+ "sampleUrl": "http://127.0.0.1:2122/"
+}
\ No newline at end of file
diff --git a/docs/changelog/2.3.x.md b/docs/changelog/2.3.x.md
deleted file mode 100644
index b5a10b9180..0000000000
--- a/docs/changelog/2.3.x.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# 2.3.1 ~ 2.3.2 版本日志
-
-# 2.3.2
-
-### 新增功能
-
-1. 控制台日志支持配置保留天数
-2. 项目列表状态跟随控制台刷新
-3. 项目配置页面优化交互流程
-4. 项目列表显示正在运行的项目的端口号(感谢@洋芋)
-5. 新版的Windows管理命令(感谢@洋芋)
-6. 支持类似于Nginx二级代理配置(感谢@№譜樋)
-7. 记录启动、重启、停止项目的操作人
-8. Jpom 数据路径默认为程序运行的路径(感谢@〓下页)
-9. 首页进程监听表格显示端口号(感谢@洋芋)
-10. 保存时检查Oss信息是否正确
-11. Jpom管理命令新增判断`JAVA_HOME`环境变量
-12. 修改用户信息,在线用户需要重新登录
-
-### 解决BUG、优化功能
-
-1. 修改WebHooks 不生效
-2. 初始化系统白名单初始化失败(感谢@洋芋)
-3. 指定Cookie名称防止名称相同被踢下线(感谢@洋芋)
-4. 优化未加载到tools.jar的提示(感谢@№譜樋)
-5. 构建按钮移动到文件管理页面中
-6. 优化nginx列表显示数据、取消nginx快捷配置
-7. 证书管理页面交互优化
-8. 取消安全模式功能(有更完善的权限代替)
-9. 管理员不能修改自己的信息
-
------------------------------------------------------------
-
-# 2.3.1
-
-#### 新增功能
-
-1. 添加创建项目判断项目id是否被占用
-2. 项目列表中添加悬停突出显示效果
-3. 生产环境中检查Jpom 运行标识和项目id是否冲突
-4. windows 管理命令支持停止Jpom
-5. 防止暴力登录新增限制ip登录失败次数
-6. 用户前台输入密码传输加密(感谢@JAVA jesion)
-7. 首页页面自动刷新按钮状态记忆功能(感谢@Mark)
-8. Jpom启动成功会自动在数据目录中创建进程id信息文件如`pid.27936`
-9. 证书管理支持导出、查看代码模板功能
-
-#### 解决BUG
-
-1. 解决配置JVM、ARGS时,不能获取到程序运行信息bug(感谢@Agoni 、)
-2. 减少登录图形验证码干扰线(感谢@Mark)
-3. 项目编辑页面JVM、ARGS调整为多行文本(感谢@JAVA jesion)
-4. jar模式MainClass非必填
-4. 优化JDK32位和64位冲突时自动跳过(感谢@13145597)
-5. 用户授权项目权限不足问题
-
-#### 升级注意事项
-
-1. 由2.2及以下升级到 2.3.x 需要手动删除Jpom数据目录中的`data/user.json` 文件、所有用户账户信息将失效需要重新添加
-
------------------------------------------------------------
\ No newline at end of file
diff --git a/docs/changelog/2.4.x.md b/docs/changelog/2.4.x.md
deleted file mode 100644
index e4e42f9c13..0000000000
--- a/docs/changelog/2.4.x.md
+++ /dev/null
@@ -1,303 +0,0 @@
-# 2.4.0 ~ 2.4.9 版本日志
-
-
-# 2.4.9 - 3.0.0(beta)
-
-> 当前版本为重构页面后的预览版本
-
-### 新增功能
-
-1. 【Server】新增监控用户操作记录
-2. 【Agent】新增配置是否禁用根据jmx获取项目状态(默认启用)
-3. 项目文件管理支持在线修改文件(感谢@Chen 贡献)
-4. 3.0.0bata版本的页面重构[采用vue项目编写](感谢@Hotstrip)
-5. 新增项目启动banner输出(感谢@Hotstrip)
-
-### 解决BUG、优化功能
-
-1. 【Server】 优化判断构建命令中的删除命令关键词
-2. 【Server】 优化删除构建历史、构建代码(避免不能删除情况)
-3. 【Agent】 调整项目的jvm 和 args参数支持url编码。避免xss后冲突
-4. 优化获取项目当前运行路径问题
-5. 【Server】开始构建时输出代码目录
-6. 【Server】编辑构建类型为SVN没有分组bug(感谢@JAVA-落泪归枫)
-7. 更新文档Jpom 的JDK要为1.8.0_40+(感谢@JAVA 企鹅)
-8. 【Server】数据库初始化时间前置,打印成功日志,未初始化结束数据库相关操作都忽略
-9. 【Server】修复报警恢复后,报警列表中的报警状态显示报警中的错误(感谢@南有乔木)
-10. 更新hutool 版本至5.4.x (能避免系统缓存页面里面获取文件大小卡死)
-11. 调整Jpom启动输出日志,启动消息采用控制台输出不再打印error级别的启动消息
-
-> 特别感谢:@Hotstrip 对Jpom的前端页面采用vue重构编写
->
-> 当前版本为3.x版本前的过渡版本
-
------------------------------------------------------------
-
-# 2.4.8
-
-### 新增功能
-
-1. 【Agent】读取进程新增 `ps -ef | grep xxx` 方式(感谢@JAVA-落泪归枫)
-
-### 解决BUG、优化功能
-
-1. 【Server】构建历史中记录字段不全问题(感谢@£天空之城~龙)
-2. 【Server】Java-WebSocket 模块漏洞版本更新 来源 [Github GHSA-gw55-jm4h-x339](https://github.com/advisories/GHSA-gw55-jm4h-x339)
-3. 【Server】节点分发列表点击控制台、文件管理404
-4. 【Server】节点分发顺序重启休眠时间取构建名称最后的时间(测试构建:10 则睡眠时间为10秒)
-5. 【Agent】启动完成打印授权信息日志级别调至error
-6. CommandUtil.asyncExeLocalCommand 方法格式化命令中的换行
-7. 优化启动读取进程文件目录避免包含node_modules 目录卡死
-8. 【Server】修复构建命令中判断是否包含【rm、del、rd】bug (感谢@落泪归枫)
-9. 【Server】修改删除节点会修改掉非管理员的账号密码bug
-10. 【Server】 构建历史根据权限查询
-
------------------------------------------------------------
-
-# 2.4.7
-
-### 新增功能
-
-1. [支持maven快速编辑节点项目](https://gitee.com/keepbx/Jpom-Plugin/tree/master/jpom-maven-plugin) (配合`jpom-maven-plugin`使用)(
- 感谢@夜空中最亮的星)
-2. 【Agent】 新增jdk 管理,不同项目选择不同的jdk (GITEE@IV8ZZ)
-3. 【Server】构建新增分组属性,方便快速选择
-4. 【Agent】 新增[JavaExtDirsCp] 运行模式 (感谢@TXpcmgr(Geiger))
-5. 【Server】 ssh 连接方式新增私钥证书连接
-6. 【Server】 ssh文件管理新增解压操作(感谢@TXpcmgr(Geiger)贡献)
-7. 【Agent】 项目新建副本集,方便单机快速运行多个副本
-8. 【Server】构建发布后操作支持副本集相关操作
-
-### 解决BUG、优化功能
-
-1. 完善使用nginx之类代理二级目录,指定端口路径跳转问题(感谢@😯😨😰😱 )
-2. 解决菜单路径不正确问题(GITEE@I15O46)
-3. 【Agent】 windows中Agent关闭,Agent中所有项目跟随关闭(感谢@java gods)
-4. 【Server】构建命令包含删除命令误判断(感谢@Sawyer)
-5. 【Server】构建历史支持配置单个构建最多保存多少个历史
-6. 【Server】解决节点分组筛选bug(感谢gitee@I17XEH)
-7. 【Server】角色权限动态数据,单个节点异常不影响所有节点配置(感谢@£天空之城~龙)
-8. 【Server】关联节点分发项目支持修改发布后操作
-9. 补充说明文档:[详情](https://jpom-site.keepbx.cn/docs/index.html#/) (感谢@TXpcmgr(Geiger))
-10. 更新部分插件依赖版本【hutool、fast-boot、fastjson】
-
-> 注意:如果在2.4.7以下项目运行方式中使用过【War】模式的由于【War】更名为【JarWar】 所有在升级后请重新修改运行方式后再运行对应项目
-
------------------------------------------------------------
-
-# 2.4.6
-
-### 新增功能
-
-1. 【Agent】 nginx管理支持自定义编译运行,管理方式变更
-2. 【Server】 监控通知新增企业微信(感谢@TinyBao。)
-3. 管理脚本支持自动识别环境变量和java路径(linux环境)
-4. 项目类型新增File(快速管理纯静态文件)
-
-### 解决BUG、优化功能
-
-1. 【Server】解决分发列表项目状态显示不正确(感谢@群友)
-2. 【Server】修复权限选择错乱和无法正确过滤问题【注意此版本的角色动态权限不兼容旧数据,需要重新授权动态数据权限】(感谢@Java-OutMan)
-3. 调整项目日志输出
-4. 更新【commons-compress】依赖版本[漏洞升级]
-5. 【Server】构建弹窗条件构建名称(感谢@Sawyer)
-6. json文件读取异常提示(感谢@Taller)
-9. 【Server】 优化ssh上传文件、删除文件
-10. InternalError 异常捕捉
-11. 【Server】优化Nginx 非80、443端口 二级路径代理重定向问题(感谢@😯😨😰😱 )
-
-### 升级注意
-
-1. 此版本更新控制台日志级别有调整,如果使用管理命令方式运行日志级别将不再打印info级别,如果需要打印info级别的请调整管理命令中的`--spring.profiles.active=pro`
- 为 `--spring.profiles.active=dev`
-2. 使用Nginx 二级路径代理请一定使用Jpom 推荐nginx配置[查看配置](https://jpom-site.keepbx.cn/docs/index.html#/辅助配置/nginx-config)
-
------------------------------------------------------------
-
-# 2.4.5
-
-### 新增功能
-
-1. 【Server】节点列表支持筛选(感谢@£天空之城~龙)
-2. 【Server】新增构建触发器(感谢@java 麦田英雄)
-3. 【Server】新增自动清理过量的构建历史记录和文件(感谢@Sawyer、@Jvmlz)
-4. 【Server】构建支持ssh发布(感谢@£天空之城~龙)
-5. 【Server】节点新增分组属性,方便多节点快速筛选(感谢@£天空之城~龙)
-6. 新增windows快速升级
-7. 【Server】layui升级到最新版,文件上传支持进度条
-8. 新增节点内存、cpu、硬盘使用情况采集报表(感谢@£天空之城~龙)
-9. 节点首页新增快速结束进程方式
-
-### 解决BUG、优化功能
-
-1. 【Server】节点分发需要节点数大于二(感谢@Sawyer)
-2. 修复未加载到tools.jar判断(感谢@java-磊)
-3. 【Server】控制台新增自动清屏开关(感谢@Jvmlz)
-4. 上传文件大小限制,配置化
-5. 【Server】构建文件copy忽略隐藏文件
-6. 【Server】不能清除错误进程缓存(感谢@java 李道甫)
-7. 【Agent】长时间运行jpom无法监控到项目运行状态(感谢@java 李道甫、@洋芋)
-8. 【Server】节点分发编辑支持修改分发后的操作
-9. 【Agent】脚本模板跟随系统编码
-10. 【Server】tomcat控制台删除日志文件错误(感谢@Java-iwen)
-11. 【Agent】自动备份控制台日志表达式为none,不生成日志备份
-12. 【Server】角色授权编辑权限不能创建数据(感谢@Lostshadow)
-13. 【Server】tomcat动态权限配置不正确(感谢@Lostshadow)
-
------------------------------------------------------------
-
-# 2.4.4
-
-### 新增功能
-
-1. 【Agent】添加对SpringBoot war包支持
-
-### 解决BUG、优化功能
-
-1. 【Server】新项目打开项目控制台页面报错(感谢@黄战虎)
-2. 【Server】修改邮箱不及时生效问题(感谢@WeChat)
-3. 【Server】修复发布构建产物路径bug(感谢@Sawyer)
-4. 优化执行命令方式
-5. 脚本模板在linux 不添加权限(采用sh 方式执行)
-6. 【Server】修复添加节点分发项目报错的数据异常(感谢@WeChat)
-
------------------------------------------------------------
-
-# 2.4.3
-
-### 新增功能
-
-1. SpringBoot 升级到2.1.x
-2. 【Server】velocity模板引擎升级为thymeleaf
-3. 【Server】构建支持svn类型仓库(感谢@群友 .)
-4. 插件端自动注册到服务端(感谢@群友 .)
-5. 新增在线修改配置并可及时重启
-6. 新增WebSSH 管理功能
-7. 【Server】用户新增邮箱和钉钉群webhook 属性
-8. 【Server】监控报警通知改为联系人
-9. 【Server】引人netty插件(感谢@夜空中最亮的星)
-10. 支持docker 容器运行(感谢@24k)
-11. 【Server】 新增清空构建代码(解决代码冲突)(感谢@xieyue200810)
-12. 搭建插件化基础架构
-13. 用户权限重构,使用角色支持更细粒的权限控制
-14. 新增ssh快速部署插件端
-15. 新增一键安装脚本[详情](https://gitee.com/dromara/Jpom/#%E4%B8%80%E9%94%AE%E5%AE%89%E8%A3%85)
-
-### 解决BUG、优化功能
-
-1. 【Server】未登录重定向带入参数
-2. 【Server】页面登录方法调整支持自定义事件登录
-3. 【Server】删除节点、分发验证是否存在关联数据,分发释放分发关系
-4. 项目白名单目录调整为属性
-5. 【Server】编辑用户回显节点选中错乱问题
-6. 调整linux管理命令脚本防止在线升级产生tail 进程
-7. 【Agent】插件端的脚本模板路径切换到数据目录下
-8. 【Agent】Windows异步执行命令调整不使用[INHERIT](防止插件端进程阻塞)
-9. 【Server】分页查询会存在字段not found
-10. 【Server】构建命令不能包含删除命令(del,rd,rm)
-11. 支持配置初始读取日志文件最后多少行【log.intiReadLine】(感谢@夜空中最亮的星)
-12. 优化节点首页饼状图统计
-13. 取消用户输入脚本模板id
-14. 重定向支持自动识别 Proto(解决http-> https iframe报错)
-15. 构建执行命令存在错误只是提示,不取消执行(感谢@Sawyer)
-16. 构建打包目录没有文件名异常(感谢@Sawyer)
-17. 修改为专属包名【io.jpom】
-
-### 升级注意事项
-
-1. 由于修改包名引起:如果在旧版本中使用过在线升级,本次升级需要手动上传jar到到服务器中执行命令升级,并且删除旧包并且覆盖管理命令文件
-
------------------------------------------------------------
-
-# 2.4.2
-
-### 新增功能
-
-1. 新增实时查看tomcat日志
-2. 【Server】分发包支持更多压缩格式
-3. 页面菜单采用json文件配置(支持二级菜单)
-4. 【Server】分发包支持更多类型的压缩格式
-5. 【Server】节点支持配置请求超时时间
-6. 支持配置是否记录请求、响应日志【consoleLog.reqXss、consoleLog.reqResponse】
-7. 新增日志记录最大记录条数【默认100000】
-8. 【Server】layui 升级到2.5.4
-9. 【Server】新增项目监控功能
-10. 【Server】新增在线构建项目功能
-11. 【Server】新增查看项目实际执行的命令行
-12. 【Server】新增分发日志
-13. 新增清空文件缓存、临时数据缓存
-14. 在线查看、下载Jpom运行日志(windows不能实时查看)
-15. 新增linux在线升级
-
-### 解决BUG、优化功能
-
-1. 【Agent】logBack页面最后修改时间不能正确显示(感谢@JAVA jesion)
-2. 【Agent】nginx修改内容截断,不正确情况(感谢@JAVA jesion)
-3. 【Agent】nginx、脚本模板保存内容xss标签还原
-4. 【Server】节点分发页面的交互方式
-5. 【Server】页面菜单分类整理
-6. 【Agent】修复SpringBoot相对文件夹下无法读取配置问题
-7. 【Agent】缓存异常的jvm进程,避免卡死状态(感谢@java 李道甫)
-8. 【Server】节点分发状态更新到所有节点状态
-9. 【Server】节点分发白名单独立页面配置
-10. 【Server】项目控制台未运行能查看已经存在的最后的日志
-11. 【Agent】删除阿里云oss构建,已经有在线构建功能代替
-12. 【Server】修改证书名称和导出证书问题
-13. 打包方式改为一个可执行的jar
-14. 【Server】解决编辑用户页面json转换异常(感谢@JAVA jesion)
-15. 分发项目新增清空发布防止新旧jar冲突
-16. 【Server】优化节点列表页面加载速度[不显示运行的项目数](感谢@java 李道甫)
-17. 【Agent】调整启动,关闭进程命令执行方式[解决重启不能监控项目状态](感谢@java 李道甫)
-18. 【Agent】调整进程标识传入参数到JVM参数中,避免和部分框架冲突(感谢@java-杨侨)
-
-### 升级注意事项
-
-1. 需要删除旧lib目录所有文件
-2. 覆盖旧版管理命令文件
-
------------------------------------------------------------
-
-# 2.4.1
-
-### 新增功能
-
-1. 【Agent】新增线程列表监控(感谢@其锋)
-2. 【Agent】新增节点脚本模板(感谢@其锋)
-3. 【Server】新增所有页面添加公共Html代码
-4. 新增Tomcat管理
-5. 【Agent】导入证书文件新增对cer、crt文件支持
-6. 【Agent】导入项目包时指出多压缩包[tar|bz2|gz|zip|tar.bz2|tar.gz] (感谢@群友)
-7. 【Agent】新增配置控制台日志文件编码格式(详情查看extConfig.yml)
-
-### 解决BUG、优化功能
-
-1. 【Server】节点首页,右上角管理路径错误(感谢@其锋)
-2. 【Server】查看用户操作日志支持筛选用户
-3. 【Server】页面数据路径权限判断修复(感谢@Will)
-4. 【Agent】优化获取进程监听端口的,防止卡死
-5. 文件的读写锁不使用 synchronized关键字提高效率
-6. 优化数据id字段的输入限制,数字+字母+中划线+下划线(感谢@JAVA jesion)
-7. 【Agent】连接JVM失败则跳过(感谢@JAVA jesion)
-8. 【Server】编辑用户页面优化选择授权项目
-9. 【Agent】项目Jvm参数和Args参数兼容回车符(感谢@牛旺)
-
------------------------------------------------------------
-
-# 2.4.0
-
-### 新增功能
-
-1. 首页进程列表显示属于Jpom项目名称(感谢@〓下页)
-2. 多节点统一管理(插件模式)
-3. 证书解析支持cer 证书(感谢@JAVA jesion)
-4. 新增记录用户操作日志[采用H2数据库](感谢@〓下页)
-5. 节点分发功能、合并管理项目(感谢@其锋)
-
-### 解决BUG、优化功能
-
-1. 解析端口信息兼容`:::8084`(感谢@Agoni 、)
-2. 进程id解析端口、解析项目名称带缓存
-3. 项目分组变更,项目列表及时刷新(感谢@〓下页)
-4. 批量上传文件数量进度显示(感谢@群友)
-5. linux udp端口信息解析失败(感谢@Ruby)
-6. jar模式读取主jar包错误(感谢@其锋)
\ No newline at end of file
diff --git a/docs/changelog/2.x.md b/docs/changelog/2.x.md
deleted file mode 100644
index 687d83722c..0000000000
--- a/docs/changelog/2.x.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# 2.0 ~ 2.2 版本日志
-
-# 2.2
-
-1. 解决批量上传文件造成卡死的问题
-2. 控制台读取自动识别文件编码格式
-3. 退出登录出现异常页面
-4. 根据对应权限显示对应菜单
-5. 系统管理员可以在线解锁锁定的用户
-
------------------------------------------------------------
-
-# 2.1
-
-1. 全面取消调用命令文件执行
-2. 静态资源缓存问题
-3. 首页监控图表更新
-4. 多处细节优化
-5. 分别支持ClassPath和Jar模式
-6. 证书文件支持验证私钥是否匹配
-
------------------------------------------------------------
-
-# 2.0
-
-1. 优化安全问题
-2. 兼容windows
-3. 使用JVM获取运行状态
diff --git a/docs/fun-releases/.funignore b/docs/fun-releases/.funignore
deleted file mode 100644
index a69cf12257..0000000000
--- a/docs/fun-releases/.funignore
+++ /dev/null
@@ -1,3 +0,0 @@
-.env
-template.yml
-.funignore
diff --git a/docs/fun-releases/index.py b/docs/fun-releases/index.py
deleted file mode 100644
index 284c4e27fc..0000000000
--- a/docs/fun-releases/index.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# -*- coding: utf-8 -*-
-import requests
-
-OK = '200 OK'
-FOUND = '302 FOUND'
-TEXT_HEADER = [('Content-type', 'text/plain')]
-TAB_NAME = 'tag_name'
-
-
-# 使用码云资源
-def ossDownload(environ, start_response):
- # 查询版本
- result = requests.get('https://dromara.gitee.io/jpom/docs/versions.json')
- json = result.json()
- return doJson(environ, start_response, json)
-
-
-# 使用GitHub
-def githubOssDownload(environ, start_response):
- # 查询版本
- result = requests.get('https://api.github.com/repos/dromara/Jpom/releases/latest')
- json = result.json()
- return doJson(environ, start_response, json)
-
-
-# 查询版本号
-def showVersion(environ, start_response):
- # 查询版本
- result = requests.get('https://api.github.com/repos/dromara/Jpom/releases/latest')
- json = result.json()
- tag_name = getVersion(json)
- if tag_name == '':
- return responseOK('没有tagName', start_response)
- return responseOK(tag_name, start_response)
-
-
-def getVersion(json):
- if json and TAB_NAME in json:
- tag_name = json[TAB_NAME]
- if tag_name and tag_name.strip() != '':
- tag_name = tag_name.replace('v', '')
- return tag_name.strip()
- else:
- return ''
- else:
- return ''
-
-
-# 处理查询到的版本json
-def doJson(environ, start_response, json):
- tag_name = getVersion(json)
- if tag_name == '':
- return responseOK('没有tagName', start_response)
- # 处理请求参数
- try:
- query_string = environ['QUERY_STRING']
- except KeyError:
- query_string = ""
- pars = query_string.split('&')
- typeName = 'Server'
- for par in pars:
- if par.startswith('type='):
- typeName = par.strip().split("=")[1]
- # 重定向到下载地址
- url = "https://jpom-releases.oss-cn-hangzhou.aliyuncs.com/" + typeName.lower() + "-" + tag_name + "-release.zip"
- start_response(FOUND, [('Location', url)])
- return [bytes(url, encoding="utf8")]
-
-
-# 响应ok
-def responseOK(value, start_response):
- start_response(OK, TEXT_HEADER)
- return [bytes(value, encoding="utf8")]
diff --git a/docs/fun-releases/local.py b/docs/fun-releases/local.py
deleted file mode 100644
index 89cb3ababb..0000000000
--- a/docs/fun-releases/local.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# -*- coding:utf-8 -*-
-# -*- created by: mo -*-
-
-
-import requests
-import tornado.ioloop
-import tornado.web
-
-
-class MainHandler(tornado.web.RequestHandler):
- def get(self):
- """get请求"""
- type = self.get_argument('type')
- result = requests.get('https://api.github.com/repos/dromara/Jpom/releases/latest')
- json = result.json()
- tag_name = json['tag_name']
- if tag_name.strip() == '':
- self.write("没有发布版")
- return
- tag_name = tag_name.replace('v', '')
- print(tag_name)
- url = "https://jpom-releases.oss-cn-hangzhou.aliyuncs.com/" + type + "-" + tag_name + "-release.zip"
- print(url)
- self.redirect(url)
-
-
-application = tornado.web.Application([(r"/", MainHandler), ])
-
-if __name__ == "__main__":
- application.listen(8868)
- tornado.ioloop.IOLoop.instance().start()
diff --git a/docs/fun-releases/template.yml b/docs/fun-releases/template.yml
deleted file mode 100644
index 143b25b42b..0000000000
--- a/docs/fun-releases/template.yml
+++ /dev/null
@@ -1,56 +0,0 @@
-# https://github.com/alibaba/funcraft/blob/master/docs/specs/2018-04-03-zh-cn.md
-ROSTemplateFormatVersion: '2015-09-01'
-Transform: 'Aliyun::Serverless-2018-04-03'
-Resources:
- jpom:
- Type: 'Aliyun::Serverless::Service'
- Properties:
- Description: 'jpom'
- jpom-releases:
- Type: 'Aliyun::Serverless::Function'
- Properties:
- Handler: index.ossDownload
- Runtime: python3
- CodeUri: './'
- Description: 'Jpom gitee安装url处理'
- MemorySize: 320
- Timeout: 5
- InitializationTimeout: 5
- Events:
- install-api:
- Type: HTTP
- Properties:
- AuthType: ANONYMOUS
- Methods: ['GET']
- jpom-releases2:
- Type: 'Aliyun::Serverless::Function'
- Properties:
- Handler: index.githubOssDownload
- Runtime: python3
- CodeUri: './'
- Description: 'Jpom github安装url处理'
- MemorySize: 320
- Timeout: 5
- InitializationTimeout: 5
- Events:
- install-api:
- Type: HTTP
- Properties:
- AuthType: ANONYMOUS
- Methods: ['GET']
- jpom-getVerson:
- Type: 'Aliyun::Serverless::Function'
- Properties:
- Handler: index.showVersion
- Runtime: python3
- CodeUri: './'
- Description: 'Jpom 查询最新版本号'
- MemorySize: 320
- Timeout: 5
- InitializationTimeout: 5
- Events:
- install-api:
- Type: HTTP
- Properties:
- AuthType: ANONYMOUS
- Methods: ['GET']
\ No newline at end of file
diff --git a/docs/install.sh b/docs/install.sh
deleted file mode 100644
index cc8e66a8ba..0000000000
--- a/docs/install.sh
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/bin/bash
-PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:$(cd `dirname $0`; pwd)
-export PATH
-LANG=en_US.UTF-8
-
-# 解压命令
-if [[ ! -f "/usr/bin/unzip" ]];then
- #rm -f /etc/yum.repos.d/epel.repo
- yum install unzip -y
-fi
-TYPE="$1"
-
-module="$2"
-
-# 判断是否包含jdk
-installJd="jdk"
-
-if [[ $module = *$installJdk* ]]; then
- if [[ ! -x "${JAVA_HOME}/bin/java" ]]; then
- JAVA=`which java`
- if [[ ! -x "$JAVA" ]]; then
- # 判断是否存在文件
- if [[ ! -f "jdk-8u251-linux-x64.tar.gz" ]]; then
- wget -O jdk-8u251-linux-x64.tar.gz https://jpom-releases.oss-cn-hangzhou.aliyuncs.com/jdk-8u251-linux-x64.tar.gz
- fi
- mkdir /usr/java/
- #
- tar -zxf jdk-8u251-linux-x64.tar.gz -C /usr/java/
- #
- #PATH=$PATH:/usr/java/jdk1.8.0_251/bin
- #export PATH
- echo '安装jdk,路径/usr/java/jdk1.8.0_251/'
- # 修改环境变量
- echo ''>>/etc/profile
- echo 'export JAVA_HOME=/usr/java/jdk1.8.0_251'>>/etc/profile
- echo 'export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar'>>/etc/profile
- echo 'export PATH=$PATH:$JAVA_HOME/bin'>>/etc/profile
- #export JAVA_HOME=/usr/java/jdk1.8.0_251
- # 更新环境变量
- source /etc/profile
- # 删除jdk压缩包
- rm -f jdk-8u251-linux-x64.tar.gz
- else
- echo "已经存在java环境${JAVA}/bin/java"
- fi
- else
- echo "已经存在java环境${JAVA_HOME}/bin/java"
- fi
-fi
-
-# 判断是否包含mvn
-installMvn="mvn"
-
-if [[ $module = *$installMvn* ]]; then
- if [[ ! -x "${MAVEN_HOME}/bin/mvn" ]]; then
- MVN=`which mvn`
- if [[ ! -x "$MVN" ]]; then
- # 判断是否存在文件
- if [[ ! -f "apache-maven-3.6.3-bin.tar.gz" ]]; then
- wget -O apache-maven-3.6.3-bin.tar.gz https://jpom-releases.oss-cn-hangzhou.aliyuncs.com/apache-maven-3.6.3-bin.tar.gz
- fi
- mkdir /usr/maven/
- #
- tar -zxf apache-maven-3.6.3-bin.tar.gz -C /usr/maven/
- #
- echo '安装maven,路径/usr/maven/apache-maven-3.6.3/'
- # 修改环境变量
- echo ''>>/etc/profile
- echo 'export MAVEN_HOME=/usr/maven/apache-maven-3.6.3/'>>/etc/profile
- echo 'export PATH=$PATH:$MAVEN_HOME/bin'>>/etc/profile
-
- export MAVEN_HOME=/usr/maven/apache-maven-3.6.3/
- export PATH=$MAVEN_HOME/bin:$PATH
- # 删除maven压缩包
- rm -f apache-maven-3.6.3-bin.tar.gz
- else
- echo "已经存在maven环境${MVN}/bin/mvn"
- fi
- else
- echo "已经存在maven环境${MAVEN_HOME}/bin/mvn"
- fi
-fi
-
-# 判断
-if [[ -z "${TYPE}" ]] ; then
- TYPE="Server";
-fi
-# 判断是否在文件
-if [[ ! -f "${TYPE}.zip" ]]; then
- # 下载
- wget -O ${TYPE}.zip https://1232788122276831.cn-beijing.fc.aliyuncs.com/2016-08-15/proxy/jpom/jpom-releases/?type=${TYPE}
-fi
-# 解压
-unzip -o ${TYPE}.zip
-# 删除安装包
-rm -f ${TYPE}.zip
-# 删除安装命令
-rm -f install.sh
-# 添加权限
-chmod 755 ${TYPE}.sh
-# 启动
-sh ${TYPE}.sh start
diff --git a/docs/jpom-service.sh b/docs/jpom-service.sh
deleted file mode 100644
index 212b0fac54..0000000000
--- a/docs/jpom-service.sh
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/bin/bash
-# chkconfig: 356 10 90
-# description: Jpom-Server service
-# processname: jpom-server
-# The MIT License (MIT)
-#
-# Copyright (c) 2019 码之科技工作室
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy of
-# this software and associated documentation files (the "Software"), to deal in
-# the Software without restriction, including without limitation the rights to
-# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-# the Software, and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.' > $FILE_NAME
-
-# loading env
-if [ -f /etc/profile ]; then
- . /etc/profile
-fi
-if [ -f /etc/bashrc ]; then
- . /etc/bashrc
-fi
-if [ -f ~/.bashrc ]; then
- . ~/.bashrc
-fi
-if [ -f ~/.bash_profile ]; then
- . ~/.bash_profile
-fi
-
-RUN_PATH="JPOM_RUN_PATH"
-
-# 启动程序
-function start() {
- sh ${RUN_PATH} start
-}
-
-# 停止程序
-function stop() {
- sh ${RUN_PATH} stop
-}
-
-# 获取程序状态
-function status() {
- sh ${RUN_PATH} status
-}
-
-# 提示使用语法
-function usage() {
- echo "Usage: $0 {start|stop|restart|status}"
- RETVAL="2"
-}
-
-# See how we were called.
-RETVAL="0"
-case "$1" in
- start)
- start
- ;;
- stop)
- stop
- ;;
- restart)
- stop
- start
- ;;
- status)
- status
- ;;
- *)
- usage
- ;;
-esac
-
-exit $RETVAL
diff --git a/docs/js/version.js b/docs/js/version.js
deleted file mode 100644
index 9c27caddb6..0000000000
--- a/docs/js/version.js
+++ /dev/null
@@ -1 +0,0 @@
-var version = '2.7.3';
diff --git a/docs/praise/praise.md b/docs/praise/praise.md
deleted file mode 100644
index 794337ee29..0000000000
--- a/docs/praise/praise.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# 赞赏公示
-
-| 日期 | 渠道 | 金额 | 昵称 |
-|------------|---|-----|---------|
-| 2021-12-10 | 微信赞赏码 | 50 | Dream |
-| 2021-10-25 | 微信赞赏码 | 1 | Jame |
-| 2021-10-11 | 微信赞赏码 | 10 | chenice |
-| 2021-10-11 | 微信赞赏码 | 1 | chenice |
-| 2021-09-01 | 微信赞赏码 | 100 | CoCo |
-| 2021-09-01 | 微信赞赏码 | 20 | 大灰灰 |
-| 2021-08-31 | 微信赞赏码 | 1 | 大灰灰 |
-
-
-### 历史赞赏(已经消费)
-
-
-| 日期 | 渠道 | 金额 | 昵称 |
-|---|---|---|---|
-| 2021-04-21 | 码云捐赠 | 10 | [jason](https://gitee.com/bwcx_jzy) |
-| 2020-03-31 | 码云捐赠 | 20 | [开源oschina](https://gitee.com/bdj) |
-| 2020-02-25 | 码云捐赠 | 20 | [辣椒酱](https://gitee.com/yokead_admin) |
-| 2020-02-13 | 码云捐赠 | 100 | [大森林](https://gitee.com/jmdhappy) |
-| 2019-08-20 | 码云捐赠 | 15 | [YountMan](https://gitee.com/YountMan) |
-| 2019-07-29 | 码云捐赠 | 50 | [Yashin](https://gitee.com/yashin) |
-| 2019-07-28 | 码云捐赠 | 100 | 老李 |
-| 2019-03-27 | 码云捐赠 | 10 | [jason](https://gitee.com/bwcx_jzy) |
\ No newline at end of file
diff --git a/docs/versions.json b/docs/versions.json
deleted file mode 100644
index 384f113b97..0000000000
--- a/docs/versions.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "tag_name": "v2.7.3",
- "agentUrl": "https://jpom-releases.oss-cn-hangzhou.aliyuncs.com/agent-2.7.3-release.zip",
- "serverUrl": "https://jpom-releases.oss-cn-hangzhou.aliyuncs.com/server-2.7.3-release.zip",
- "changelogUrl": "https://gitee.com/dromara/Jpom/raw/master/CHANGELOG.md"
-}
diff --git a/docs/wx_qrcode.jpg b/docs/wx_qrcode.jpg
deleted file mode 100644
index ff651a74e9..0000000000
Binary files a/docs/wx_qrcode.jpg and /dev/null differ
diff --git a/env-beta.env b/env-beta.env
new file mode 100644
index 0000000000..5b5fa58aa4
--- /dev/null
+++ b/env-beta.env
@@ -0,0 +1,3 @@
+JPOM_VERSION=2.11.6.6
+# Server Token 生产部署请更换
+SERVER_TOKEN=7094f673-2c53-4fc1-82e7-86e528449d97
diff --git a/env-release.env b/env-release.env
new file mode 100644
index 0000000000..91dc2b61ce
--- /dev/null
+++ b/env-release.env
@@ -0,0 +1,3 @@
+JPOM_VERSION=2.11.6
+# Server Token 生产部署请更换
+SERVER_TOKEN=7094f673-2c53-4fc1-82e7-86e528449d97
diff --git a/index.html b/index.html
deleted file mode 100644
index ca2301dbe5..0000000000
--- a/index.html
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
- jpom
-
-
- 进入中:https://jpom-site.keepbx.cn
-
-
\ No newline at end of file
diff --git a/modules/agent-transport/agent-transport-common/pom.xml b/modules/agent-transport/agent-transport-common/pom.xml
new file mode 100644
index 0000000000..fbb83741f5
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/pom.xml
@@ -0,0 +1,51 @@
+
+
+
+ 4.0.0
+
+ org.dromara.jpom.agent-transport
+ jpom-agent-transport-parent
+ 2.11.6.6
+ ../pom.xml
+
+
+ agent-transport-common
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ cn.hutool
+ hutool-core
+
+
+
+ org.slf4j
+ slf4j-api
+ true
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+ true
+
+
+
+
diff --git a/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/DataContentType.java b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/DataContentType.java
new file mode 100644
index 0000000000..f654d5d1a1
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/DataContentType.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport;
+
+/**
+ * 请求数据传输类型
+ *
+ * @author bwcx_jzy
+ * @since 2022/12/24
+ */
+public enum DataContentType {
+ /**
+ * URL
+ */
+ FORM_URLENCODED,
+ /**
+ * JSON
+ */
+ JSON
+}
diff --git a/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/DownloadCallback.java b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/DownloadCallback.java
new file mode 100644
index 0000000000..19fbed9bb5
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/DownloadCallback.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.InputStream;
+
+/**
+ * @author bwcx_jzy
+ * @since 2022/12/24
+ */
+@Builder
+@Data
+public class DownloadCallback {
+
+ private String contentDisposition;
+
+ private String contentType;
+
+ private InputStream inputStream;
+}
diff --git a/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/INodeInfo.java b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/INodeInfo.java
new file mode 100644
index 0000000000..6491c5c0ba
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/INodeInfo.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport;
+
+import java.net.Proxy;
+
+/**
+ * 节点通讯的 接口
+ *
+ * @author bwcx_jzy
+ * @since 2022/12/23
+ */
+public interface INodeInfo {
+
+ /**
+ * 节点名称
+ *
+ * @return 名称
+ */
+ String name();
+
+ /**
+ * 节点 url
+ *
+ * HOST:PORT
+ *
+ * @return 节点 url
+ */
+ String url();
+
+ /**
+ * 协议
+ *
+ * @return http
+ */
+ String scheme();
+
+ /**
+ * 节点 授权信息
+ * sha1(user@pwd)
+ *
+ * @return 用户
+ */
+ String authorize();
+
+ /**
+ * 节点通讯代理
+ *
+ * @return proxy
+ */
+ Proxy proxy();
+
+ /**
+ * 超时时间
+ *
+ * @return 超时时间 单位秒
+ */
+ Integer timeout();
+
+ /**
+ * 传输加密方式
+ *
+ * @return 传输加密方式 0 不加密 1 BASE64 2 AES
+ */
+ Integer transportEncryption();
+}
diff --git a/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/IProxyWebSocket.java b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/IProxyWebSocket.java
new file mode 100644
index 0000000000..905947b6b1
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/IProxyWebSocket.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.function.Consumer;
+
+/**
+ * @author bwcx_jzy
+ * @since 2022/12/26
+ */
+public interface IProxyWebSocket extends AutoCloseable {
+
+ /**
+ * 关闭连接
+ *
+ * @throws IOException 关闭异常
+ */
+ void close() throws IOException;
+
+ /**
+ * 打开连接,默认停留一秒
+ *
+ * @return 打开状态
+ */
+ boolean connect();
+
+ /**
+ * 重新打开连接
+ *
+ * @return 打开状态
+ * @throws IOException 关闭异常
+ */
+ default boolean reconnect() throws IOException {
+ this.close();
+ return this.connect();
+ }
+
+ /**
+ * 重新打开连接
+ *
+ * @return 打开状态
+ * @throws IOException 关闭异常
+ */
+ default boolean reconnectBlocking() throws IOException {
+ this.close();
+ return this.connectBlocking();
+ }
+
+ /**
+ * 打开连接,使用节点配置的超时时间
+ *
+ * @return 打开状态
+ */
+ boolean connectBlocking();
+
+ /**
+ * 打开连接,阻塞指定时间
+ *
+ * @param seconds 阻塞时间 建议大于 1秒
+ * @return 打开状态
+ */
+ boolean connectBlocking(int seconds);
+
+ /**
+ * 发送消息
+ *
+ * @param msg 消息
+ * @throws IOException 发送异常
+ */
+ void send(String msg) throws IOException;
+
+ /**
+ * 发送消息
+ *
+ * @param bytes 消息
+ * @throws IOException 发送异常
+ */
+ void send(ByteBuffer bytes) throws IOException;
+
+ /**
+ * 收到消息
+ *
+ * @param consumer 回调
+ */
+ void onMessage(Consumer consumer);
+
+ /**
+ * 是否连接上
+ *
+ * @return true
+ */
+ boolean isConnected();
+
+ /**
+ * 获取关闭状态描述
+ *
+ * @return 状态描述
+ */
+ String getCloseStatusMsg();
+}
diff --git a/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/IUrlItem.java b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/IUrlItem.java
new file mode 100644
index 0000000000..e1d6da6c62
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/IUrlItem.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport;
+
+import java.util.Map;
+
+/**
+ * @author bwcx_jzy
+ * @since 2022/12/23
+ */
+public interface IUrlItem {
+
+ /**
+ * 请求路径
+ *
+ * @return path
+ */
+ String path();
+
+ /**
+ * 请求超时时间
+ * 单位秒
+ *
+ * @return 超时时间
+ */
+ Integer timeout();
+
+ /**
+ * 当前工作空间id
+ *
+ * @return 工作空间
+ */
+ String workspaceId();
+
+ /**
+ * 请求类型
+ *
+ * @return contentType
+ */
+ DataContentType contentType();
+
+ /**
+ * 请求头
+ *
+ * @return 请求头
+ */
+ Map header();
+}
diff --git a/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransformServer.java b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransformServer.java
new file mode 100644
index 0000000000..c1267d6cfd
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransformServer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport;
+
+import com.alibaba.fastjson2.TypeReference;
+
+/**
+ * 消息转换服务
+ *
+ * @author bwcx_jzy
+ * @since 2022/12/24
+ */
+public interface TransformServer {
+
+ /**
+ * 数据类型转换
+ *
+ * @param data 数据
+ * @param tTypeReference 类型
+ * @param 范型
+ * @return data
+ */
+ T transform(String data, TypeReference tTypeReference);
+
+ /**
+ * 数据类型转换,只返回成功的数据
+ *
+ * @param data 数据
+ * @param tClass 类型
+ * @param 范型
+ * @return data
+ */
+ T transformOnlyData(String data, Class tClass);
+
+ /**
+ * 转换异常
+ *
+ * @param e 请求的异常
+ * @param nodeInfo 节点信息
+ * @return 转换后的异常
+ */
+ default Exception transformException(Exception e, INodeInfo nodeInfo) {
+ return e;
+ }
+}
diff --git a/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransformServerFactory.java b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransformServerFactory.java
new file mode 100644
index 0000000000..c549bc0c51
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransformServerFactory.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport;
+
+import cn.hutool.core.lang.Singleton;
+import cn.hutool.core.util.ServiceLoaderUtil;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author bwcx_jzy
+ * @since 2022/12/24
+ */
+@Slf4j
+public class TransformServerFactory {
+
+ /**
+ * 获得单例的 TransformServer
+ *
+ * @return 单例的 TransformServer
+ */
+ public static TransformServer get() {
+ return Singleton.get(TransformServer.class.getName(), TransformServerFactory::doCreate);
+ }
+
+ /**
+ * 根据用户引入的 Transform 客户端引擎jar,自动创建对应的拼音引擎对象
+ * 推荐创建的引擎单例使用,此方法每次调用会返回新的引擎
+ *
+ * @return {@code TransformServer}
+ */
+ public static TransformServer of() {
+ final TransformServer transportServer = doCreate();
+ log.debug("Use [{}] Agent Transport As Default.", transportServer.getClass().getSimpleName());
+ return transportServer;
+ }
+
+
+ /**
+ * 根据用户引入的拼音引擎jar,自动创建对应的拼音引擎对象
+ * 推荐创建的引擎单例使用,此方法每次调用会返回新的引擎
+ *
+ * @return {@code EngineFactory}
+ */
+ private static TransformServer doCreate() {
+ final TransformServer engine = ServiceLoaderUtil.loadFirstAvailable(TransformServer.class);
+ if (null != engine) {
+ return engine;
+ }
+
+ throw new RuntimeException("No jpom agent transform jar found ! Please add one of it to your project !");
+ }
+}
diff --git a/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransportAgentException.java b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransportAgentException.java
new file mode 100644
index 0000000000..3effc42997
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransportAgentException.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport;
+
+import lombok.NoArgsConstructor;
+
+/**
+ * @author bwcx_jzy
+ * @since 2022/12/24
+ */
+@NoArgsConstructor
+public class TransportAgentException extends RuntimeException {
+
+ public TransportAgentException(String message) {
+ super(message);
+ }
+}
diff --git a/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransportServer.java b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransportServer.java
new file mode 100644
index 0000000000..89233a6e5e
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransportServer.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport;
+
+import com.alibaba.fastjson2.TypeReference;
+
+import java.util.function.Consumer;
+
+/**
+ * 插件端消息传输服务
+ *
+ * @author bwcx_jzy
+ * @since 2022/12/18
+ */
+public interface TransportServer {
+
+ /**
+ * 请求 header
+ */
+ String WORKSPACE_ID_REQ_HEADER = "workspaceId";
+
+ String JPOM_AGENT_AUTHORIZE = "Jpom-Agent-Authorize";
+
+ String TRANSPORT_ENCRYPTION = "transport-encryption";
+
+ /**
+ * 执行请求
+ *
+ * @param nodeInfo 节点信息
+ * @param urlItem 请求 item
+ * @param data 参数
+ * @return 响应的字符串
+ */
+ String execute(INodeInfo nodeInfo, IUrlItem urlItem, Object data);
+
+ /**
+ * 执行请求,返回响应的所有数据
+ *
+ * @param nodeInfo 节点信息
+ * @param urlItem 请求 item
+ * @param data 参数
+ * @param tTypeReference 返回的泛型
+ * @param 泛型
+ * @return 响应的字符串
+ */
+ default T executeToType(INodeInfo nodeInfo, IUrlItem urlItem, Object data, TypeReference tTypeReference) {
+ String body = this.execute(nodeInfo, urlItem, data);
+ return TransformServerFactory.get().transform(body, tTypeReference);
+ }
+
+ /**
+ * 执行请求,仅返回成功的数据
+ *
+ * @param nodeInfo 节点信息
+ * @param urlItem 请求 item
+ * @param data 参数
+ * @param tClass 返回的泛型
+ * @param 泛型
+ * @return 响应的字符串
+ */
+ default T executeToTypeOnlyData(INodeInfo nodeInfo, IUrlItem urlItem, Object data, Class tClass) {
+ String body = this.execute(nodeInfo, urlItem, data);
+ return TransformServerFactory.get().transformOnlyData(body, tClass);
+ }
+
+ /**
+ * 下载文件
+ *
+ * @param nodeInfo 节点信息
+ * @param urlItem 请求 item
+ * @param data 参数
+ * @param consumer 回调
+ */
+ void download(INodeInfo nodeInfo, IUrlItem urlItem, Object data, Consumer consumer);
+
+ /**
+ * 创建 websocket 连接
+ *
+ * @param nodeInfo 节点信息
+ * @param urlItem 请求 item
+ * @param parameters 参数
+ * @return websocket
+ */
+ IProxyWebSocket websocket(INodeInfo nodeInfo, IUrlItem urlItem, Object... parameters);
+}
diff --git a/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransportServerFactory.java b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransportServerFactory.java
new file mode 100644
index 0000000000..838e77888e
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/TransportServerFactory.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport;
+
+import cn.hutool.core.lang.Singleton;
+import cn.hutool.core.util.ServiceLoaderUtil;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author bwcx_jzy
+ * @since 2022/12/23
+ */
+@Slf4j
+public class TransportServerFactory {
+
+ /**
+ * 获得单例的 TransportServer
+ *
+ * @return 单例的 TransportServer
+ */
+ public static TransportServer get() {
+ return Singleton.get(TransportServer.class.getName(), TransportServerFactory::doCreate);
+ }
+
+ /**
+ * 根据用户引入的 Transport 客户端引擎jar,自动创建对应的拼音引擎对象
+ * 推荐创建的引擎单例使用,此方法每次调用会返回新的引擎
+ *
+ * @return {@code TransportServer}
+ */
+ public static TransportServer of() {
+ final TransportServer transportServer = doCreate();
+ log.debug("Use [{}] Agent Transport As Default.", transportServer.getClass().getSimpleName());
+ return transportServer;
+ }
+
+
+ /**
+ * 根据用户引入的拼音引擎jar,自动创建对应的拼音引擎对象
+ * 推荐创建的引擎单例使用,此方法每次调用会返回新的引擎
+ *
+ * @return {@code EngineFactory}
+ */
+ private static TransportServer doCreate() {
+ final TransportServer engine = ServiceLoaderUtil.loadFirstAvailable(TransportServer.class);
+ if (null != engine) {
+ return engine;
+ }
+
+ throw new RuntimeException("No jpom agent transport jar found ! Please add one of it to your project !");
+ }
+}
diff --git a/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/i18n/II18nMessageUtil.java b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/i18n/II18nMessageUtil.java
new file mode 100644
index 0000000000..189f2c542f
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/i18n/II18nMessageUtil.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport.i18n;
+
+/**
+ * @author bwcx_jzy1
+ * @since 2024/6/11
+ */
+public interface II18nMessageUtil {
+
+ /**
+ * 获取翻译
+ *
+ * @param key 键
+ * @return 翻译
+ */
+ String get(String key);
+}
diff --git a/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/i18n/TransportI18nMessageUtil.java b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/i18n/TransportI18nMessageUtil.java
new file mode 100644
index 0000000000..a0ae9b250c
--- /dev/null
+++ b/modules/agent-transport/agent-transport-common/src/main/java/org/dromara/jpom/transport/i18n/TransportI18nMessageUtil.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport.i18n;
+
+import cn.hutool.core.lang.Singleton;
+import cn.hutool.core.util.ServiceLoaderUtil;
+
+/**
+ * @author bwcx_jzy1
+ * @since 2024/6/11
+ */
+public class TransportI18nMessageUtil {
+
+ /**
+ * 获得单例的 TransportServer
+ *
+ * @return 单例的 TransportServer
+ */
+ public static String get(String key) {
+ return Singleton.get(II18nMessageUtil.class.getName(), TransportI18nMessageUtil::doCreate).get(key);
+ }
+
+
+ /**
+ * 根据用户引入的拼音引擎jar,自动创建对应的拼音引擎对象
+ * 推荐创建的引擎单例使用,此方法每次调用会返回新的引擎
+ *
+ * @return {@code EngineFactory}
+ */
+ private static II18nMessageUtil doCreate() {
+ final II18nMessageUtil engine = ServiceLoaderUtil.loadFirstAvailable(II18nMessageUtil.class);
+ if (null != engine) {
+ return engine;
+ }
+
+ throw new RuntimeException("No jpom IMessageUtil jar found ! Please add one of it to your project !");
+ }
+}
diff --git a/modules/agent-transport/agent-transport-http/pom.xml b/modules/agent-transport/agent-transport-http/pom.xml
new file mode 100644
index 0000000000..e8acaa36bd
--- /dev/null
+++ b/modules/agent-transport/agent-transport-http/pom.xml
@@ -0,0 +1,69 @@
+
+
+
+ 4.0.0
+
+ org.dromara.jpom.agent-transport
+ jpom-agent-transport-parent
+ 2.11.6.6
+ ../pom.xml
+
+
+ agent-transport-http
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ org.dromara.jpom.plugins
+ encrypt
+ ${project.version}
+
+
+
+ org.dromara.jpom.agent-transport
+ agent-transport-common
+ ${project.version}
+
+
+
+ cn.hutool
+ hutool-http
+
+
+
+ org.slf4j
+ slf4j-api
+ true
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+ true
+
+
+
+
diff --git a/modules/agent-transport/agent-transport-http/src/main/java/org/dromara/jpom/transport/HttpTransportServer.java b/modules/agent-transport/agent-transport-http/src/main/java/org/dromara/jpom/transport/HttpTransportServer.java
new file mode 100644
index 0000000000..9b244c94d4
--- /dev/null
+++ b/modules/agent-transport/agent-transport-http/src/main/java/org/dromara/jpom/transport/HttpTransportServer.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.resource.Resource;
+import cn.hutool.core.net.url.UrlBuilder;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.*;
+import com.alibaba.fastjson2.JSONObject;
+import lombok.Lombok;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.encrypt.EncryptFactory;
+import org.dromara.jpom.encrypt.Encryptor;
+import org.dromara.jpom.transport.i18n.TransportI18nMessageUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+/**
+ * 插件端消息传输服务
+ *
+ * @author bwcx_jzy
+ * @since 2022/12/18
+ */
+@Slf4j
+public class HttpTransportServer implements TransportServer {
+
+
+ private HttpRequest createRequest(INodeInfo nodeInfo, IUrlItem urlItem, Method method) {
+ String url = StrUtil.format("{}://{}/", nodeInfo.scheme(), nodeInfo.url());
+ UrlBuilder urlBuilder = UrlBuilder.of(url).addPath(urlItem.path());
+ HttpRequest httpRequest = HttpRequest.of(urlBuilder);
+ httpRequest.setMethod(method);
+ // 添加请求头
+ Map header = urlItem.header();
+ httpRequest.headerMap(header, true);
+
+ Optional.ofNullable(urlItem.timeout()).ifPresent(integer -> httpRequest.timeout(integer * 1000));
+
+ httpRequest.header(TRANSPORT_ENCRYPTION, nodeInfo.transportEncryption() + "");
+
+ httpRequest.header(JPOM_AGENT_AUTHORIZE, nodeInfo.authorize());
+ //
+ httpRequest.header(WORKSPACE_ID_REQ_HEADER, urlItem.workspaceId());
+ Optional.ofNullable(nodeInfo.proxy()).ifPresent(httpRequest::setProxy);
+ return httpRequest;
+ }
+
+ private HttpRequest createRequest(INodeInfo nodeInfo, IUrlItem urlItem) {
+ return createRequest(nodeInfo, urlItem, Method.POST);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void appendRequestData(HttpRequest httpRequest, IUrlItem urlItem, Object data, INodeInfo nodeInfo) {
+ DataContentType dataContentType = urlItem.contentType();
+ Optional.ofNullable(data).ifPresent(o -> {
+ Encryptor encryptor;
+ try {
+ encryptor = EncryptFactory.createEncryptor(nodeInfo.transportEncryption());
+ if (dataContentType == DataContentType.FORM_URLENCODED) {
+ if (o instanceof Map) {
+ Map map = (Map) o;
+ Map encryptedMap = new HashMap<>();
+ for (Map.Entry entry : map.entrySet()) {
+ String encryptedKey = encryptor.encrypt(entry.getKey());
+ Object value = entry.getValue();
+ Object newValue;
+ if (value instanceof String[]) {
+ String[] valueStr = (String[]) value;
+ for (int i = 0; i < valueStr.length; i++) {
+ valueStr[i] = encryptor.encrypt(valueStr[i]);
+ }
+ newValue = valueStr;
+ } else if (value instanceof Resource) {
+ newValue = value;
+ } else {
+ newValue = encryptor.encrypt(StrUtil.toStringOrNull(entry.getValue()));
+ }
+ encryptedMap.put(encryptedKey, newValue);
+ }
+ httpRequest.form(encryptedMap);
+ } else {
+ throw new IllegalArgumentException(TransportI18nMessageUtil.get("i18n.unsupported_type_with_colon.1050") + o.getClass());
+ }
+ } else if (dataContentType == DataContentType.JSON) {
+ httpRequest.body(encryptor.encrypt(JSONObject.toJSONString(o)), ContentType.JSON.getValue());
+ } else {
+ throw new IllegalArgumentException(TransportI18nMessageUtil.get("i18n.content_type_not_supported.81a9"));
+ }
+ } catch (Exception e) {
+ log.error(TransportI18nMessageUtil.get("i18n.encoding_error.b685"), e);
+ throw new TransportAgentException(TransportI18nMessageUtil.get("i18n.node_transfer_info_encoding_exception.12c8") + e.getMessage());
+ }
+ });
+ }
+
+ private String executeRequest(HttpRequest httpRequest, INodeInfo nodeInfo, IUrlItem urlItem) {
+ //
+ if (log.isDebugEnabled()) {
+ log.debug("{}[{}] -> {} {}", nodeInfo.name(), httpRequest.getUrl(), urlItem.workspaceId(), Optional.ofNullable((Object) httpRequest.form()).orElse("-"));
+ }
+ return httpRequest.thenFunction(response -> {
+ int status = response.getStatus();
+ String body = response.body();
+ log.debug("Completed {}", body);
+ if (status != HttpStatus.HTTP_OK) {
+ log.warn(TransportI18nMessageUtil.get("i18n.response_exception_status_code.cbca"), nodeInfo.name(), status, body);
+ throw new TransportAgentException(nodeInfo.name() + TransportI18nMessageUtil.get("i18n.node_response_error.efc6") + status);
+ }
+ return body;
+ });
+ }
+
+ @Override
+ public String execute(INodeInfo nodeInfo, IUrlItem urlItem, Object data) {
+ HttpRequest httpRequest = this.createRequest(nodeInfo, urlItem);
+ this.appendRequestData(httpRequest, urlItem, data, nodeInfo);
+ try {
+ return this.executeRequest(httpRequest, nodeInfo, urlItem);
+ } catch (Exception e) {
+ throw Lombok.sneakyThrow(TransformServerFactory.get().transformException(e, nodeInfo));
+ }
+ }
+
+
+ @Override
+ public void download(INodeInfo nodeInfo, IUrlItem urlItem, Object data, Consumer consumer) {
+ HttpRequest httpRequest = this.createRequest(nodeInfo, urlItem, Method.GET);
+ httpRequest.setFollowRedirects(true);
+ this.appendRequestData(httpRequest, urlItem, data, nodeInfo);
+ try (HttpResponse response1 = httpRequest.execute()) {
+ String contentDisposition = response1.header(Header.CONTENT_DISPOSITION);
+ String contentType = response1.header(Header.CONTENT_TYPE);
+ DownloadCallback build = DownloadCallback.builder()
+ .contentDisposition(contentDisposition).contentType(contentType).inputStream(response1.bodyStream())
+ .build();
+ consumer.accept(build);
+ } catch (Exception e) {
+ throw Lombok.sneakyThrow(TransformServerFactory.get().transformException(e, nodeInfo));
+ }
+ }
+
+ @Override
+ public IProxyWebSocket websocket(INodeInfo nodeInfo, IUrlItem urlItem, Object... parameters) {
+ String url = StrUtil.format("{}://{}/", nodeInfo.scheme(), nodeInfo.url());
+ UrlBuilder urlBuilder = UrlBuilder.of(url).addPath(urlItem.path());
+ //
+ urlBuilder.addQuery(JPOM_AGENT_AUTHORIZE, nodeInfo.authorize());
+ //
+ urlBuilder.addQuery(WORKSPACE_ID_REQ_HEADER, urlItem.workspaceId());
+ for (int i = 0; i < parameters.length; i += 2) {
+ Object parameter = parameters[i + 1];
+ String value = Convert.toStr(parameter, StrUtil.EMPTY);
+ urlBuilder.addQuery(parameters[i].toString(), value);
+ }
+ urlBuilder.setWithEndTag(false);
+ String uriTemplate = urlBuilder.build();
+ uriTemplate = StrUtil.removePrefixIgnoreCase(uriTemplate, nodeInfo.scheme());
+ String wss = "wss";
+ String ws = "ws";
+ String protocol = "https".equalsIgnoreCase(nodeInfo.scheme()) ? wss : ws;
+ uriTemplate = StrUtil.format("{}{}", protocol, uriTemplate);
+ //
+ if (log.isDebugEnabled()) {
+ log.debug("{}[{}] -> {}", nodeInfo.name(), uriTemplate, urlItem.workspaceId());
+ }
+ Integer timeout = urlItem.timeout();
+ return new ServletWebSocketClientHandler(uriTemplate, timeout);
+ }
+}
diff --git a/modules/agent-transport/agent-transport-http/src/main/java/org/dromara/jpom/transport/ServletWebSocketClientHandler.java b/modules/agent-transport/agent-transport-http/src/main/java/org/dromara/jpom/transport/ServletWebSocketClientHandler.java
new file mode 100644
index 0000000000..ceb771812b
--- /dev/null
+++ b/modules/agent-transport/agent-transport-http/src/main/java/org/dromara/jpom/transport/ServletWebSocketClientHandler.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.transport;
+
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.SystemPropsUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.transport.i18n.TransportI18nMessageUtil;
+import org.springframework.util.Assert;
+import org.springframework.util.unit.DataSize;
+import org.springframework.web.socket.BinaryMessage;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+import org.springframework.web.socket.client.WebSocketConnectionManager;
+import org.springframework.web.socket.client.standard.StandardWebSocketClient;
+import org.springframework.web.socket.handler.AbstractWebSocketHandler;
+import org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * @author bwcx_jzy
+ * @since 2022/12/26
+ */
+@Slf4j
+public class ServletWebSocketClientHandler extends AbstractWebSocketHandler implements IProxyWebSocket {
+
+ private static final StandardWebSocketClient CLIENT = new StandardWebSocketClient();
+
+ private WebSocketSession session;
+ private final Integer timeout;
+ private final String uriTemplate;
+ private Consumer consumerText;
+ private WebSocketConnectionManager manager;
+ private CloseStatus closeStatus;
+
+ public ServletWebSocketClientHandler(String uriTemplate, Integer timeout) {
+ this.uriTemplate = uriTemplate;
+ this.timeout = timeout;
+ }
+
+ @Override
+ public void onMessage(Consumer consumer) {
+ this.consumerText = consumer;
+ }
+
+ @Override
+ protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
+ Optional.ofNullable(this.consumerText).ifPresent(consumer -> consumer.accept(message.getPayload()));
+ }
+
+ @Override
+ public void afterConnectionEstablished(WebSocketSession session) throws Exception {
+ // 发送消息时间限制 60 秒
+ long messageSizeLimit = SystemPropsUtil.getLong("JPOM_NODE_WEB_SOCKET_MESSAGE_SIZE_LIMIT", DataSize.ofMegabytes(5).toBytes());
+ this.session = new ConcurrentWebSocketSessionDecorator(session, 60 * 1000, (int) messageSizeLimit);
+ // 消息大小限制
+ this.session.setTextMessageSizeLimit((int) messageSizeLimit);
+ this.session.setBinaryMessageSizeLimit((int) messageSizeLimit);
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (this.manager == null) {
+ return;
+ }
+ this.manager.stop();
+ this.manager = null;
+ this.session = null;
+ }
+
+ @Override
+ public boolean connect() {
+ Assert.isNull(this.manager, "The connection has been established, do not repeat the connection");
+ this.manager = new WebSocketConnectionManager(CLIENT, this, this.uriTemplate);
+ this.manager.start();
+ // 时间不能太短,需要大于 1 秒
+ return this.blocking(5);
+ }
+
+ @Override
+ public boolean connectBlocking() {
+ int maxTimeout = Optional.ofNullable(this.timeout).orElse(60);
+ return this.connectBlocking(maxTimeout);
+ }
+
+ @Override
+ public boolean connectBlocking(int seconds) {
+ if (this.connect()) {
+ return true;
+ }
+ return this.blocking(seconds);
+ }
+
+ private boolean blocking(int seconds) {
+ int waitTime = 0;
+ do {
+ if (this.isConnected()) {
+ return true;
+ }
+ waitTime++;
+ ThreadUtil.sleep(500, TimeUnit.MILLISECONDS);
+ } while (waitTime * 2 <= seconds);
+ return false;
+ }
+
+ @Override
+ public void send(String msg) throws IOException {
+ Assert.notNull(this.session, TransportI18nMessageUtil.get("i18n.not_connected.fa55"));
+ session.sendMessage(new TextMessage(msg));
+ }
+
+ @Override
+ public void send(ByteBuffer bytes) throws IOException {
+ Assert.notNull(this.session, TransportI18nMessageUtil.get("i18n.not_connected.fa55"));
+ session.sendMessage(new BinaryMessage(bytes));
+ }
+
+ @Override
+ public boolean isConnected() {
+ if (this.manager == null) {
+ return false;
+ }
+ return this.manager.isConnected();
+ }
+
+ @Override
+ public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
+ log.error(TransportI18nMessageUtil.get("i18n.websocket_error.2bb4"), session.getId(), exception);
+ }
+
+ @Override
+ public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
+ this.closeStatus = status;
+ log.warn(TransportI18nMessageUtil.get("i18n.connection_closed.6d4e"), status.getCode(), status.getReason());
+ }
+
+ @Override
+ public String getCloseStatusMsg() {
+ return Optional.ofNullable(this.closeStatus)
+ .map(closeStatus -> StrUtil.format("{}:{}", closeStatus.getCode(), closeStatus.getReason()))
+ .orElse(StrUtil.EMPTY);
+ }
+}
diff --git a/modules/agent-transport/agent-transport-http/src/main/resources/META-INF/services/org.dromara.jpom.transport.TransportServer b/modules/agent-transport/agent-transport-http/src/main/resources/META-INF/services/org.dromara.jpom.transport.TransportServer
new file mode 100644
index 0000000000..6f02d2f6f1
--- /dev/null
+++ b/modules/agent-transport/agent-transport-http/src/main/resources/META-INF/services/org.dromara.jpom.transport.TransportServer
@@ -0,0 +1 @@
+org.dromara.jpom.transport.HttpTransportServer
diff --git a/modules/agent-transport/pom.xml b/modules/agent-transport/pom.xml
new file mode 100644
index 0000000000..29c7d8de82
--- /dev/null
+++ b/modules/agent-transport/pom.xml
@@ -0,0 +1,173 @@
+
+
+
+
+ jpom-parent
+ org.dromara.jpom
+ 2.11.6.6
+ ../../pom.xml
+
+ pom
+
+ agent-transport-common
+ agent-transport-http
+
+ 4.0.0
+ 2.11.6.6
+ org.dromara.jpom.agent-transport
+ jpom-agent-transport-parent
+ Jpom Agent Transport
+
+ Jpom java 插件传输模块
+
+
+ UTF-8
+ 1.8
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.0
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.22.0
+
+ once
+ -Dfile.encoding=UTF-8
+
+
+
+
+
+
+
+ release
+
+
+ maven-repo
+ https://oss.sonatype.org/content/repositories/snapshots/
+
+
+ maven-repo
+ https://oss.sonatype.org/service/local/staging/deploy/maven2/
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 2.4
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.0.0
+
+
+ attach-javadoc
+ package
+
+ jar
+
+
+
+
+
+
+ date
+ a
+ 创建时间
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 3.0.1
+
+
+ verify-gpg
+ verify
+
+ sign
+
+
+
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.6.13
+ true
+
+ sonatype-nexus-staging
+ https://oss.sonatype.org/
+ true
+
+
+
+
+
+
+
+
+
+ master
+ git@gitee.com:dromara/Jpom.git
+ scm:git:git@gitee.com:dromara/Jpom.git
+ scm:git:git@gitee.com:dromara/Jpom.git
+
+
+
+ bwcx_jzy
+ bwcx_jzy@163.com
+ bwcx_jzy
+
+
+
+
diff --git a/modules/agent/Dockerfile b/modules/agent/Dockerfile
index 3599a8604a..7b4e5b452d 100644
--- a/modules/agent/Dockerfile
+++ b/modules/agent/Dockerfile
@@ -1,52 +1,52 @@
#
-# The MIT License (MIT)
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
#
-# Copyright (c) 2019 码之科技工作室
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy of
-# this software and associated documentation files (the "Software"), to deal in
-# the Software without restriction, including without limitation the rights to
-# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-# the Software, and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-FROM centos:7
-ENV LANG en_US.utf8
+FROM maven:3.9.6-eclipse-temurin-8 as builder
+WORKDIR /target/dependency
+COPY . .
-ENV JPOM_HOME /usr/local/jpom-agent
-ENV JPOM_PKG agent-2.8.0-release.zip
+VOLUME ["/root/.m2"]
+# 多次 builder 不同的版本号
+ARG TEMP_VERSION=""
+ARG JPOM_VERSION
+ENV USE_JPOM_VERSION=${JPOM_VERSION}${TEMP_VERSION}
+RUN --mount=type=cache,target=/root/.m2 sh ./script/replaceVersion.sh ${USE_JPOM_VERSION} "release"
-ADD jdk-8u202-linux-x64.tar.gz /usr/local/java/
-ENV JAVA_HOME /usr/local/java/jdk1.8.0_202
-ENV CLASSPATH .:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
-ENV PATH $JAVA_HOME/bin:$PATH
+RUN --mount=type=cache,target=/root/.m2 mvn -B -e -T 1C clean package -pl modules/agent -am -Dmaven.test.skip=true -Dmaven.compile.fork=true -s script/settings.xml
-ADD apache-maven-3.8.4-bin.tar.gz /usr/local/maven/
-ENV MAVEN_HOME /usr/local/maven/apache-maven-3.8.4
-ENV PATH $MAVEN_HOME/bin:$PATH
+FROM openjdk:8
+ARG BUILD_DATE
+ARG JPOM_VERSION
+ARG TEMP_VERSION=""
+ARG RUN_ARG=""
+ARG DEPENDENCY=/target/dependency
-RUN yum install -y unzip
+LABEL build_info="dromara/Jpom build-date:- ${BUILD_DATE}"
+LABEL maintainer="bwcx-jzy "
+LABEL documentation="https://jpom.top"
-RUN mkdir -p $JPOM_HOME
-COPY $JPOM_PKG $JPOM_HOME
-RUN unzip -o $JPOM_HOME/$JPOM_PKG -d $JPOM_HOME
-RUN chmod +x $JPOM_HOME/Agent.sh
-RUN rm -rf $JPOM_HOME/$JPOM_PKG
+ENV JPOM_HOME /usr/local/jpom-agent
+ENV JPOM_PKG_VERSION ${JPOM_VERSION}${TEMP_VERSION}
+ENV JPOM_PKG agent-${JPOM_PKG_VERSION}-release
+ENV RUN_ARG ${RUN_ARG}
WORKDIR $JPOM_HOME
+COPY --from=builder ${DEPENDENCY}/modules/agent/target/${JPOM_PKG} ${JPOM_HOME}
+
+# 时区
+ENV TZ Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+VOLUME $JPOM_HOME
EXPOSE 2123
-ENTRYPOINT ["/bin/sh", "Agent.sh", "start"]
+ENTRYPOINT ["/bin/bash", "./bin/Agent.sh", "start"]
+
diff --git a/modules/agent/pom.xml b/modules/agent/pom.xml
index 3a535dbc94..df68cd6518 100644
--- a/modules/agent/pom.xml
+++ b/modules/agent/pom.xml
@@ -1,141 +1,212 @@
+
-
- jpom-parent
- io.jpom
- 2.8.0
- ../../pom.xml
-
- 4.0.0
- agent
- 2.8.0
- Jpom 插件端
-
- io.jpom.JpomAgentApplication
-
-
-
- io.jpom
- common
- ${pom.version}
-
-
-
- com.github.odiszapc
- nginxparser
- 0.9.6
-
-
-
- org.bouncycastle
- bcprov-jdk15on
- 1.69
-
-
- org.apache.commons
- commons-compress
- 1.21
-
-
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
- 3.1.1
-
-
-
- ${start-class}
-
- true
-
- ./
-
-
-
- ${project.version}
-
- ${maven.build.timestamp}
- ${project.artifactId}
- https://gitee.com/dromara/Jpom
-
-
-
-
-
-
-
-
- false
- ../../
-
- CHANGELOG.md
- LICENSE
-
-
-
- src/main/resources
- false
-
-
-
-
-
- agent-default-profile
-
- true
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
- true
- ${start-class}
- -Dfile.encoding=UTF-8
-
-
-
-
- repackage
-
-
-
-
-
- org.apache.maven.plugins
- maven-assembly-plugin
- 3.1.1
-
- ${project.build.sourceEncoding}
-
- script/release.xml
-
- target
-
-
-
- make-assembly
- package
-
- single
-
-
-
-
-
-
-
-
-
- install-plugin-profile
-
-
- release-plugin-profile
-
-
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ jpom-parent
+ org.dromara.jpom
+ 2.11.6.6
+ ../../pom.xml
+
+ 4.0.0
+ agent
+ 2.11.6.6
+ Jpom Agent
+
+ org.dromara.jpom.JpomAgentApplication
+
+ 1.0.0
+
+
+
+
+ org.dromara.jpom
+ common
+ ${project.version}
+
+
+
+ org.dromara.jpom.plugins
+ webhook
+ ${project.version}
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+ com.github.oshi
+ oshi-core
+ ${oshi.version}
+
+
+
+ commons-codec
+ commons-codec
+ 1.15
+
+
+
+
+
+
+
+
+
+
+ false
+ ../../
+
+ CHANGELOG.md
+ CHANGELOG-BETA.md
+ LICENSE
+
+
+
+ src/main/resources
+ false
+
+
+
+
+
+ agent-default-profile
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.3.0
+
+
+
+ ${start-class}
+
+ true
+
+ ./
+
+
+
+ ${project.version}
+
+ ${maven.build.timestamp}
+ ${project.artifactId}
+ https://gitee.com/dromara/Jpom
+ ${jpom-min-version}
+
+ true
+
+
+ logback.xml
+ application.yml
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ true
+ ${start-class}
+ -Dfile.encoding=UTF-8
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+ repackage
+
+
+
+
+
+
+
+
+
+ install-assembly
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 3.3.0
+
+ ${project.build.sourceEncoding}
+
+ src/main/assembly/release.xml
+
+ ${project.build.directory}
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+
+ net.nicoulaj.maven.plugins
+ checksum-maven-plugin
+ 1.11
+
+
+ checksum-maven-plugin-files
+ package
+
+ files
+
+
+
+
+
+
+ ${project.build.directory}
+
+ *.jar
+ *.zip
+ *.tar.gz
+
+
+
+
+ SHA-1
+
+
+
+
+
+
+
diff --git a/modules/agent/script/Agent.bat b/modules/agent/script/Agent.bat
deleted file mode 100644
index 8dc80dbaa3..0000000000
--- a/modules/agent/script/Agent.bat
+++ /dev/null
@@ -1,142 +0,0 @@
-@REM The MIT License (MIT)
-@REM
-@REM Copyright (c) 2019 码之科技工作室
-@REM
-@REM Permission is hereby granted, free of charge, to any person obtaining a copy of
-@REM this software and associated documentation files (the "Software"), to deal in
-@REM the Software without restriction, including without limitation the rights to
-@REM use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-@REM the Software, and to permit persons to whom the Software is furnished to do so,
-@REM subject to the following conditions:
-@REM
-@REM The above copyright notice and this permission notice shall be included in all
-@REM copies or substantial portions of the Software.
-@REM
-@REM THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-@REM IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-@REM FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-@REM COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-@REM IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-@REM CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-@REM
-
-@echo off
-CHCP 65001
-setlocal enabledelayedexpansion
-
-@REM 设置环境变量,避免部分服务器没有 taskkill
-set PATH = %PATH%;C:\Windows\system32;C:\Windows;C:\Windows\system32\Wbem
-
-set Tag=KeepBx-Agent-System-JpomAgentApplication
-set MainClass=org.springframework.boot.loader.JarLauncher
-set basePath=%~dp0
-set Lib=%basePath%lib\
-@REM 请勿修改----------------------------------↓
-set LogName=agent.log
-@REM 在线升级会自动修改此属性
-set RUNJAR=
-@REM 请勿修改----------------------------------↑
-@REM 是否开启控制台日志文件备份
-set LogBack=true
-set JVM=-server -Xms200m -Xmx400m
-set ARGS= --jpom.applicationTag=%Tag% --jpom.log=%basePath%log --spring.profiles.active=pro --server.port=2123
-
-@REM 读取jar
-call:listDir
-
-if "%1"=="" (
- color 0a
- TITLE Jpom管理系统BAT控制台
- echo. ***** Jpom管理系统BAT控制台 *****
- ::*************************************************************************************************************
- echo.
- echo. [1] 启动 start
- echo. [2] 关闭 stop
- echo. [3] 查看运行状态 status
- echo. [4] 重启 restart
- echo. [5] 帮助 use
- echo. [6] 清除 IP 白名单配置
- echo. [0] 退 出 0
- echo.
- @REM 输入
- echo.请输入选择的序号:
- set /p ID=
- IF "!ID!"=="1" call:start
- IF "!ID!"=="2" call:stop
- IF "!ID!"=="3" call:status
- IF "!ID!"=="4" call:restart
- IF "!ID!"=="5" call:use
- IF "!ID!"=="6" call:restart --rest:ip_config
- IF "!ID!"=="0" EXIT
-)else (
- if "%1"=="restart" (
- call:restart
- )else (
- call:use
- )
-)
-if "%2" NEQ "upgrade" (
- PAUSE
-)else (
- @REM 升级直接结束
-)
-EXIT 0
-
-@REM 启动
-:start
- if "%JAVA_HOME%"=="" (
- echo 请配置【JAVA_HOME】环境变量
- PAUSE
- EXIT 2
- )
-
- echo 启动中.....启动成功后关闭窗口不影响运行
- echo 启动详情请查看:%LogName%
- javaw %JVM% -Djava.class.path="%RUNJAR%" -Dapplication=%Tag% -Dbasedir=%basePath% %MainClass% %ARGS% %1 >> %basePath%%LogName%
- timeout 3
-goto:eof
-
-
-@REM 获取jar
-:listDir
- if "%RUNJAR%"=="" (
- for /f "delims=" %%I in ('dir /B %Lib%') do (
- if exist %Lib%%%I if not exist %Lib%%%I\nul (
- if "%%~xI" ==".jar" (
- if "%RUNJAR%"=="" (
- set RUNJAR=%Lib%%%I
- )
- )
- )
- )
- )else (
- set RUNJAR=%Lib%%RUNJAR%
- )
- echo 运行:%RUNJAR%
-goto:eof
-
-@REM 关闭Jpom
-:stop
- java -Djava.class.path="%JAVA_HOME%/lib/tools.jar;%RUNJAR%" %MainClass% %ARGS% --event=stop
-goto:eof
-
-@REM 查看Jpom运行状态
-:status
- java -Djava.class.path="%JAVA_HOME%/lib/tools.jar;%RUNJAR%" %MainClass% %ARGS% --event=status
-goto:eof
-
-@REM 重启Jpom
-:restart
- echo 停止中....
- call:stop
- timeout 3
- echo 启动中....
- call:start %1
-goto:eof
-
-@REM 提示用法
-:use
- echo please use (start、stop、restart、status)
-goto:eof
-
-
diff --git a/modules/agent/script/Agent.sh b/modules/agent/script/Agent.sh
deleted file mode 100644
index 5f55275942..0000000000
--- a/modules/agent/script/Agent.sh
+++ /dev/null
@@ -1,219 +0,0 @@
-#!/bin/bash
-# The MIT License (MIT)
-#
-# Copyright (c) 2019 码之科技工作室
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy of
-# this software and associated documentation files (the "Software"), to deal in
-# the Software without restriction, including without limitation the rights to
-# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-# the Software, and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-# ssh 支持读取环境变量
-if [ -f /etc/profile ]; then
- . /etc/profile
-fi
-if [ -f /etc/bashrc ]; then
- . /etc/bashrc
-fi
-if [ -f ~/.bash_profile ]; then
- . ~/.bash_profile
-fi
-if [ -f ~/.bashrc ]; then
- . ~/.bashrc
-fi
-# 请不要修改 tag 属性的值,修改后会影响程序的停止、查看状态
-Tag="KeepBx-Agent-System-JpomAgentApplication"
-# 自动获取当前路径
-Path=$(
- cd $(dirname $0)
- pwd
-)"/"
-Lib="${Path}lib/"
-RUNJAR=""
-Log="${Path}agent.log"
-LogBack="${Path}log/"
-JVM="-server -Xms200m -Xmx400m"
-# 修改项目端口号 日志路径
-ARGS="--jpom.applicationTag=${Tag} --spring.profiles.active=pro --server.port=2123 --jpom.log=${Path}log $@"
-
-echo ${Tag}
-echo ${Path}
-RETVAL="0"
-# 升级执行命令标识
-upgrade="$2"
-
-# now set the path to java
-if [[ -x "${JAVA_HOME}/bin/java" ]]; then
- JAVA="${JAVA_HOME}/bin/java"
- NOW_JAVA_HOME="${JAVA_HOME}"
-else
- set +e
- JAVA=$(which java)
- NOW_JAVA_HOME="${JAVA}/../"
- set -e
-fi
-
-if [[ ! -x "$JAVA" ]]; then
- echo "没有找到JAVA 文件,请配置【JAVA_HOME】环境变量"
- exit 1
-fi
-
-# 启动程序
-function start() {
- pid=$(getPid)
- if [[ "$pid" != "" ]]; then
- echo "程序正在运行中:${pid}"
- exit 2
- fi
- echo ${Log}
- # 备份日志
- if [[ -f ${Log} ]]; then
- if [[ ! -d ${LogBack} ]]; then
- mkdir ${LogBack}
- fi
- cur_dateTime="$(date +%Y-%m-%d_%H:%M:%S).log"
- mv ${Log} ${LogBack}${cur_dateTime}
- echo "mv to $LogBack$cur_dateTime"
- touch ${Log}
- fi
- # jar
- if [[ -z "${RUNJAR}" ]]; then
- RUNJAR=$(listDir ${Lib})
- echo "自动运行:${RUNJAR}"
- fi
- # error
- if [[ -z "${RUNJAR}" ]]; then
- echo "没有找到jar"
- exit 2
- fi
-
- nohup ${JAVA} ${JVM} -jar ${Lib}${RUNJAR} -Dapplication=${Tag} -Dbasedir=${Path} ${ARGS} >>${Log} 2>&1 &
- # 升级不执行查看日志
- if [[ ${upgrade} == "upgrade" ]]; then
- exit 0
- fi
- if [[ -f ${Log} ]]; then
- tail -f ${Log}
- else
- sleep 3
- if [[ -f ${Log} ]]; then
- tail -f ${Log}
- else
- echo "还没有生成日志文件:${Log}"
- fi
- fi
-}
-
-# 找出第一个jar包
-function listDir() {
- ALL=""
- for file in "$1"/*.jar; do
- if [[ -f "${file}" ]]; then
- #得到文件的完整的目录
- ALL="${file}"
- break
- fi
- done
- echo ${ALL##*/}
-}
-
-# 停止程序
-function stop() {
- pid=$(getPid)
- if [[ "$pid" != "" ]]; then
- echo -n "boot ( pid $pid) is running"
- echo
- echo -n $"Shutting down boot: wait"
- kill $(pgrep -f ${Tag}) 2>/dev/null
- sleep 3
- pid=$(getPid)
- if [[ "$pid" != "" ]]; then
- echo "kill boot process"
- kill -9 "$pid"
- fi
- else
- echo "boot is stopped"
- fi
-
- status
-}
-
-# 获取程序状态
-function status() {
- pid=$(getPid)
- #echo "$pid"
- if [[ "$pid" != "" ]]; then
- echo "boot is running,pid is $pid"
- else
- echo "boot is stopped"
- fi
-}
-
-function getPid() {
- pid=$(ps -ef | grep -v 'grep' | egrep ${Tag} | awk '{printf $2 " "}')
- echo ${pid}
-}
-
-# 提示使用语法
-function usage() {
- echo "Usage: $0 {start|stop|restart|status|create}"
- RETVAL="2"
-}
-
-# 创建自启动服务文件
-function create() {
- yum install -y wget && wget -O jpom-agent https://dromara.gitee.io/jpom/docs/jpom-service.sh
- #判断当前脚本是否为绝对路径,匹配以/开头下的所有
- if [[ $0 =~ ^\/.* ]]
- then
- selfpath=$0
- else
- selfpath=$(pwd)/$0
- fi
- #获取文件的真实路径
- selfpath=`readlink -f $selfpath`
- # 替换路径
- sed -i "s|JPOM_RUN_PATH|${selfpath}|g" jpom-agent
- echo 'create jpom-agent file done'
- mv -f jpom-agent /etc/init.d/jpom-agent
- chmod +x /etc/init.d/jpom-agent
- chkconfig --add jpom-agent
- echo 'create jpom-agent success'
-}
-
-# See how we were called.
-RETVAL="0"
-case "$1" in
-start)
- start
- ;;
-stop)
- stop
- ;;
-restart)
- stop
- start
- ;;
-status)
- status
- ;;
-create)
- create
- ;;
-*)
- usage
- ;;
-esac
-
-exit $RETVAL
diff --git a/modules/agent/script/release.xml b/modules/agent/script/release.xml
deleted file mode 100644
index d58a4dc8bc..0000000000
--- a/modules/agent/script/release.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
- release
- false
-
- dir
- zip
-
-
-
-
-
- script/
- /
-
- Agent.sh
- Agent.bat
-
-
-
-
- src/main/resources/bin/
- /
-
- extConfig.yml
-
-
-
-
- ../../
- /
-
- LICENSE
-
-
-
-
-
-
-
- lib
-
- io.jpom:agent
-
-
-
-
-
diff --git a/modules/agent/src/main/assembly/release.xml b/modules/agent/src/main/assembly/release.xml
new file mode 100644
index 0000000000..950a30bdc9
--- /dev/null
+++ b/modules/agent/src/main/assembly/release.xml
@@ -0,0 +1,71 @@
+
+
+
+ release
+ false
+
+ dir
+ zip
+ tar.gz
+
+
+
+
+
+ ./src/main/bin
+ bin
+
+ *.sh
+
+ unix
+
+
+ ./src/main/bin
+ bin
+
+ *.bat
+
+ dos
+
+
+
+ ./src/main/resources/config_default/
+ /conf
+
+ logback.xml
+ application.yml
+
+
+
+
+ ../../
+ /
+
+ LICENSE
+
+
+
+
+
+
+
+ lib
+
+ org.dromara.jpom:agent
+
+
+
+
+
diff --git a/modules/agent/src/main/bin/Agent.bat b/modules/agent/src/main/bin/Agent.bat
new file mode 100644
index 0000000000..1a7ad522eb
--- /dev/null
+++ b/modules/agent/src/main/bin/Agent.bat
@@ -0,0 +1,171 @@
+@REM
+@REM Copyright (c) 2019 Of Him Code Technology Studio
+@REM Jpom is licensed under Mulan PSL v2.
+@REM You can use this software according to the terms and conditions of the Mulan PSL v2.
+@REM You may obtain a copy of Mulan PSL v2 at:
+@REM http://license.coscl.org.cn/MulanPSL2
+@REM THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+@REM See the Mulan PSL v2 for more details.
+@REM
+
+@echo off
+@if not "%ECHO%" == "" echo %ECHO%
+setlocal enabledelayedexpansion
+set ENV_PATH=.\
+if "%OS%" == "Windows_NT" set ENV_PATH=%~dp0%
+
+@REM Set environment variables to prevent some servers from failing to taskkill
+set PATH = %PATH%;C:\Windows\system32;C:\Windows;C:\Windows\system32\Wbem
+
+if "%JAVA_HOME%"=="" (
+ echo please configure [JAVA_HOME] environment variable
+ PAUSE
+ EXIT 2
+)
+
+set PID_TAG="JPOM_AGENT_APPLICATION"
+set conf_dir="%ENV_PATH%/../conf/"
+set tmpdir="%ENV_PATH%/../tmp/"
+if not exist %tmpdir% md %tmpdir%
+
+@REM see org.springframework.util.StringUtils.cleanPath
+@REM set org.springframework.boot.context.config.StandardConfigDataLocationResolver.getResourceLocation
+cd %conf_dir%
+set conf_dir=%cd%
+cd %tmpdir%
+set tmpdir=%cd%
+cd %ENV_PATH%
+
+set log_dir=%ENV_PATH%\..\logs
+set logback_configurationFile=%conf_dir%\logback.xml
+set application_conf=%conf_dir%\application.yml
+
+set Lib=%ENV_PATH%\..\lib\
+set "RUN_JAR="
+set "JAR_MSG="
+set agent_log="%log_dir%\agent.log"
+set stdout_log="%log_dir%\stdout.log"
+
+set JAVA_MEM_OPTS= -Xms200m -Xmx600m -XX:+UseG1GC
+set JAVA_OPTS_EXT= -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Dapplication.codeset=UTF-8 -Dfile.encoding=UTF-8 -Djava.io.tmpdir="%tmpdir%"
+set APP_OPTS= -Djpom.application.tag="%PID_TAG%" -Dlogging.config="%logback_configurationFile%" -Dspring.config.location="%application_conf%"
+set JAVA_OPTS= %JAVA_MEM_OPTS% %JAVA_OPTS_EXT% %APP_OPTS%
+
+set ARGS=%*
+set JPOM_LOG=%log_dir%
+if not exist %log_dir% md %log_dir%
+
+@REM get list jar
+call:listDir
+
+if "%1"=="" (
+ color 0a
+ TITLE Jpom management system BAT console
+ echo. ***** Jpom management system BAT console *****
+ echo. !JAR_MSG!
+ ::*************************************************************************************************************
+ echo.
+ echo. [1] start
+ echo. [2] status
+ echo. [3] restart
+ echo. [4] stop
+ echo. [0] exit 0
+ echo.
+ @REM enter
+ for /l %%i in (1,1,10000) do (
+ echo. Please enter the selected serial number:
+ set /p ID=
+ IF "!ID!"=="1" call:start
+ IF "!ID!"=="2" call:status
+ IF "!ID!"=="3" call:restart
+ IF "!ID!"=="4" call:stop
+ IF "!ID!"=="0" EXIT
+ )
+)else (
+ if "%1"=="restart" (
+ call:restart
+ )else if "%1"=="start" (
+ call:start
+ )else if "%1"=="status" (
+ call:status
+ )else if "%1"=="stop" (
+ call:stop
+ )else (
+ call:use
+ )
+)
+if "%2" == "upgrade" (
+ @REM The upgrade ends directly
+ EXIT 0
+)
+
+:end
+goto:eof
+
+@REM start
+:start
+ echo Starting..... Closing the window after a successful start does not affect the operation
+ echo Please check for startup details:%agent_log% or !stdout_log!
+ start /b javaw %JAVA_OPTS% -jar %Lib%!RUN_JAR! %ARGS% > "!stdout_log!" 2>&1
+ @REM timeout 3 > NUL
+ ping 127.0.0.1 -n 3 > nul
+goto:eof
+
+
+@REM get jar
+:listDir
+ if "%RUN_JAR%"=="" (
+ if exist "%Lib%\run.bin" (
+ set /P RUN_JAR=<"%Lib%\run.bin"
+ set JAR_MSG=specify running !RUN_JAR!
+ )else (
+ for /f "delims=" %%I in ('dir /B %Lib%') do (
+ if exist %Lib%%%I if not exist %Lib%%%I\nul (
+ if "%%~xI" ==".jar" (
+ if "%RUN_JAR%"=="" (
+ set "RUN_JAR=%%I"
+ )
+ )
+ )
+ )
+ set JAR_MSG=auto running !RUN_JAR!
+ )
+ )else (
+ set JAR_MSG=specify2 running %RUN_JAR%
+ )
+ if not exist %Lib%!RUN_JAR! (
+ echo %JAR_MSG%
+ echo file not exist %Lib%!RUN_JAR!
+ PAUSE
+ EXIT -1
+ )
+ @REM stdout_log
+ if exist "%Lib%\run.bin" (
+ set /P RUN_LOG=<"%Lib%\run.log"
+ set stdout_log="%log_dir%\!RUN_LOG!"
+ )
+goto:eof
+
+@REM stop Jpom
+:stop
+ echo "jpom agent stop "
+ for /f "tokens=1 delims= " %%I in ('jps -v ^| findstr "%PID_TAG%"') do taskkill /F /PID %%I
+goto:eof
+
+@REM view Jpom status
+:status
+ echo "jpom agent status "
+ set pid=
+ for /f "tokens=1 delims= " %%I in ('jps -v ^| findstr "%PID_TAG%"') do set pid=%%I
+ echo "running: %pid%"
+goto:eof
+
+@REM restart Jpom
+:restart
+ echo Stopping....
+ call:stop
+ @REM timeout 3 > NUL
+ ping 127.0.0.1 -n 3 > nul
+ echo starting....
+ call:start %1
+goto:eof
diff --git a/modules/agent/src/main/bin/Agent.sh b/modules/agent/src/main/bin/Agent.sh
new file mode 100644
index 0000000000..968177cb6c
--- /dev/null
+++ b/modules/agent/src/main/bin/Agent.sh
@@ -0,0 +1,274 @@
+#!/bin/bash
+#
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+#
+
+# description: Auto-starts jpom agent
+
+case "$(uname)" in
+Linux)
+ bin_abs_path=$(readlink -f "$(dirname "$0")")
+ ;;
+*)
+ bin_abs_path=$(
+ cd "$(dirname "$0")" || exit
+ pwd
+ )
+ ;;
+esac
+
+command_exists() {
+ command -v "$@" >/dev/null 2>&1
+}
+
+function errorExit() {
+ echo "$1" 2>&2
+ if [ "${mode}" == "-s" ]; then
+ logStdout "$1"
+ fi
+ exit 1
+}
+
+function logStdout() {
+ # out stdout
+ if [ ! -f "$Log" ]; then
+ touch "$Log"
+ fi
+ echo "$1" >"$Log"
+}
+
+base=${bin_abs_path}/..
+
+conf_path="${base}/conf"
+Lib="${base}/lib/"
+LogPath="${base}/logs/"
+tmpdir="${base}/tmp/"
+Log="${LogPath}/stdout.log"
+logback_configurationFile="${conf_path}/logback.xml"
+application_conf="${conf_path}/application.yml"
+pidfile="$base/bin/agent.pid"
+
+export JPOM_LOG=${LogPath}
+
+PID_TAG="JPOM_AGENT_APPLICATION"
+agent_log="${LogPath}/agent.log"
+
+## set java path
+if [ -z "$JAVA" ]; then
+ JAVA=$(which java)
+fi
+if [ -z "$JAVA" ]; then
+ if command_exists java; then
+ JAVA="java"
+ fi
+fi
+if [ -z "$JAVA" ]; then
+ echo "Cannot find a Java JDK. Please set either set JAVA or put java (>=1.8) in your PATH." 2>&2
+ exit 1
+fi
+
+JavaVersion=$($JAVA -version 2>&1 | awk 'NR==1{ gsub(/"/,""); print $3 }' | awk -F '.' '{print $1}')
+Java64Str=$($JAVA -version 2>&1 | grep -E '64-bit|64-Bit')
+JAVA_OPTS="$JAVA_OPTS -Xss512k -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$LogPath"
+
+if [ "${JavaVersion}" -ge 11 ]; then
+ JAVA_OPTS="$JAVA_OPTS"
+else
+ JAVA_OPTS="$JAVA_OPTS -XX:+UseFastAccessorMethods -XX:+PrintAdaptiveSizePolicy -XX:+PrintTenuringDistribution"
+fi
+
+#-Xms500m -Xmx1024m
+if [[ -z "${USR_JVM_SIZE}" ]]; then
+ USR_JVM_SIZE="-Xms200m -Xmx600m"
+fi
+
+if [ -n "$Java64Str" ]; then
+ # For G1
+ JAVA_OPTS="-server ${USR_JVM_SIZE} -XX:+UseG1GC -XX:MaxGCPauseMillis=250 -XX:+UseGCOverheadLimit -XX:+ExplicitGCInvokesConcurrent $JAVA_OPTS"
+else
+ JAVA_OPTS="-server ${USR_JVM_SIZE} -XX:NewSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=128m $JAVA_OPTS"
+fi
+JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8"
+JAVA_OPTS="$JAVA_OPTS -Dlogging.config=$logback_configurationFile -Dspring.config.location=$application_conf"
+JAVA_OPTS="$JAVA_OPTS -Djava.io.tmpdir=$tmpdir"
+
+if [[ -z "${RUN_ARG}" ]]; then
+ MAIN_ARGS="$*"
+else
+ # docker run
+ MAIN_ARGS="${RUN_ARG}"
+fi
+
+# mode -s -9
+mode="$2"
+
+RUN_JAR=""
+
+function checkConfig() {
+ if [ ! -d "$LogPath" ]; then
+ mkdir -p "$LogPath"
+ fi
+ if [[ ! -f "$logback_configurationFile" ]] || [[ ! -f "$application_conf" ]]; then
+ echo "Cannot find $application_conf or $logback_configurationFile"
+ exit 1
+ fi
+
+ if [[ -z "${RUN_JAR}" ]]; then
+ if [ -f "$Lib/run.bin" ]; then
+ RUN_JAR=$(cat "$Lib/run.bin")
+ if [ ! -f "$Lib/$RUN_JAR" ]; then
+ echo "Cannot find $Lib/$RUN_JAR jar" 2>&2
+ exit 1
+ fi
+ echo "specify running:${RUN_JAR}"
+ else
+ RUN_JAR=$(find "${Lib}" -type f -name "*.jar" -exec ls -t {} + | head -1 | sed 's#.*/##')
+ # error
+ if [[ -z "${RUN_JAR}" ]]; then
+ echo "Jar not found"
+ exit 2
+ fi
+ echo "automatic running:${RUN_JAR}"
+ fi
+ fi
+ mkdir -p "$tmpdir"
+}
+
+function getPid() {
+ cygwin=false
+ linux=false
+ case "$(uname)" in
+ CYGWIN*)
+ cygwin=true
+ ;;
+ Linux*)
+ linux=true
+ ;;
+ esac
+ if $cygwin; then
+ JAVA_CMD="$JAVA_HOME\bin\java"
+ JAVA_CMD=$(cygpath --path --unix "$JAVA_CMD")
+ JAVA_PID=$(ps | grep "$JAVA_CMD" | awk '{print $1}')
+ else
+ if $linux; then
+ JAVA_PID=$(ps -C java -f --width 1000 | grep "$PID_TAG" | grep -v grep | awk '{print $2}')
+ else
+ JAVA_PID=$(ps aux | grep "$PID_TAG" | grep -v grep | awk '{print $2}')
+ fi
+ fi
+ echo "$JAVA_PID"
+}
+
+# See how we were called.
+function start() {
+ echo $PID_TAG
+ # check running
+ pid=$(getPid)
+ #echo "$pid"
+ if [ "$pid" != "" ]; then
+ echo "Running, please do not run repeatedly:$pid"
+ exit 0
+ fi
+ checkConfig
+
+ if [ ! -f "$agent_log" ]; then
+ touch "$agent_log"
+ fi
+ # start
+ command="${JAVA} -Djpom.application.tag=${PID_TAG} ${JAVA_OPTS} -jar ${Lib}${RUN_JAR} ${MAIN_ARGS}"
+ echo "$command" >"$Log"
+ eval "nohup $command >>$Log 2>&1 &"
+ echo $! >"$pidfile"
+
+ pid=$(cat "$pidfile")
+
+ if [ "${mode}" == "-s" ] || [ "${mode}" == "upgrade" ]; then
+ echo "silence auto exit 0,${pid}"
+ exit 0
+ fi
+ echo "Jpom agent starting:$pid"
+ pid=$(getPid)
+ if [ "$pid" == "" ]; then
+ echo "Please check the $Log for failure details"
+ errorExit "Jpom agent Startup failed"
+ fi
+ tail -fn 0 --pid="$pid" "$agent_log"
+}
+
+function stop() {
+ pid=$(getPid)
+ killMode=""
+ if [ "${mode}" == "-s" ] || [ "${mode}" == "upgrade" ]; then
+ # Compatible with online upgrade ./Agent.sh restart upgrade or ./Agent.sh restart -s
+ killMode=""
+ else
+ killMode=${mode}
+ fi
+ if [ "$pid" != "" ]; then
+ echo -n "jpom agent ( pid $pid) is running"
+ echo
+ echo -n $"Shutting down (kill $killMode $pid) jpom server: "
+ if [ "$killMode" == "" ]; then
+ kill "$pid"
+ else
+ kill "$killMode" "$pid"
+ fi
+ LOOPS=0
+ while (true); do
+ pid=$(getPid)
+ if [ "$pid" == "" ]; then
+ echo "Stop and end, in $LOOPS seconds"
+ break
+ fi
+ ((LOOPS++)) || true
+ sleep 1
+ done
+ else
+ echo "jpom agent is stopped"
+ fi
+ eval "$(rm -f "$pidfile")"
+}
+
+function status() {
+ pid=$(getPid)
+ #echo "$pid"
+ if [ "$pid" != "" ]; then
+ echo "jpom agent running:$pid"
+ else
+ echo "jpom agent is stopped"
+ fi
+}
+
+function usage() {
+ echo "Usage: $0 {start|stop|restart|status}" 2>&2
+ RETVAL="2"
+}
+
+# See how we were called.
+RETVAL="0"
+case "$1" in
+start)
+ start
+ ;;
+stop)
+ stop
+ ;;
+restart)
+ stop
+ start
+ ;;
+status)
+ status
+ ;;
+*)
+ usage
+ ;;
+esac
+
+exit $RETVAL
diff --git a/modules/agent/src/main/bin/Service.sh b/modules/agent/src/main/bin/Service.sh
new file mode 100644
index 0000000000..ad89ec4007
--- /dev/null
+++ b/modules/agent/src/main/bin/Service.sh
@@ -0,0 +1,185 @@
+#!/bin/bash
+#
+# Copyright (c) 2019 Of Him Code Technology Studio
+# Jpom is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+#
+
+# description: manage jpom agent Service
+
+function absPath() {
+ dir="$1"
+ case "$(uname)" in
+ Linux)
+ abs_path=$(readlink -f "$dir")
+ ;;
+ *)
+ abs_path=$(
+ cd "$dir" || exit
+ pwd
+ )
+ ;;
+ esac
+ #
+ echo "$abs_path"
+}
+
+command_exists() {
+ command -v "$@" >/dev/null 2>&1
+}
+
+binAbsPath=$(absPath "$(dirname "$0")")
+serviceName="jpom-agent.service"
+serviceFile="/etc/systemd/system/$serviceName"
+binAbsName=$(absPath "$binAbsPath/Agent.sh")
+pidfile="$binAbsPath/agent.pid"
+
+#
+user="$(id -un 2>/dev/null || true)"
+user_group="$(id -gn 2>/dev/null || true)"
+
+sh_c='sh -c'
+exec_user=""
+if [ "$user" != 'root' ]; then
+ if command_exists sudo; then
+ sh_c='sudo -E sh -c'
+ elif command_exists su; then
+ sh_c='su -c'
+ else
+ cat >&2 <<-EOF
+ Error: this installer needs the ability to run commands as root.
+ We are unable to find either "sudo" or "su" available to make this happen.
+ EOF
+ exit 1
+ fi
+ exec_user="$user"
+fi
+
+function install() {
+
+ if [ -f "$serviceFile" ]; then
+ echo "service file already exists" 2>&2
+ exit 2
+ fi
+ if [ ! -f "$binAbsName" ]; then
+ echo "$binAbsName not found" 2>&2
+ exit 2
+ fi
+ if [ -z "$JAVA_HOME" ]; then
+ echo "JAVA_HOME variable not found" 2>&2
+ exit 2
+ fi
+ if [ -z "$CLASSPATH" ]; then
+ echo "CLASSPATH variable not found" 2>&2
+ exit 2
+ fi
+
+ $sh_c "cat >$serviceFile" <&2 <<-EOF
+ ERROR: $serviceName write failed Installing the service requires the ability to run commands as root.
+ EOF
+ exit 1
+ fi
+
+ echo "$serviceName write success :$serviceFile"
+
+ $sh_c 'systemctl daemon-reload'
+
+ cat >&2 <<-EOF
+ INFO: You can execute the following commands to manage $serviceName.
+ INFO: systemctl start $serviceName (Start the service )
+ INFO: systemctl stop $serviceName (Stop the service)
+ INFO: systemctl enable $serviceName (Set up autostart)
+ INFO: systemctl disable $serviceName (stop autostart)
+ INFO: systemctl status $serviceName (View the current status of the service)
+ INFO: systemctl restart $serviceName (Restart the service)
+ EOF
+}
+
+function uninstall() {
+ if [ -f "$serviceFile" ]; then
+ $sh_c "systemctl disable $serviceName"
+ $sh_c "systemctl stop $serviceName"
+ $sh_c "rm -f $serviceFile"
+ if [ -f "$serviceFile" ]; then
+ cat >&2 <<-EOF
+ ERROR: $serviceName write uninstall .
+ EOF
+ exit 1
+ fi
+ echo "$serviceName uninstalled successfully"
+ $sh_c 'systemctl daemon-reload'
+ else
+ echo "$serviceFile not found"
+ fi
+}
+
+function enable() {
+ if [ -f "$serviceFile" ]; then
+ $sh_c "systemctl enable $serviceName"
+ else
+ echo "$serviceFile not found" 2>&2
+ echo "Usage: $0 install" 2>&2
+ fi
+}
+
+function action() {
+ case "$1" in
+ install)
+ install
+ ;;
+ uninstall)
+ uninstall
+ ;;
+ reinstall)
+ uninstall
+ echo "--------------------------------------"
+ install
+ ;;
+ enable)
+ enable
+ ;;
+ *)
+ echo "Usage: $0 {install|uninstall|reinstall|enable}" 2>&2
+ exit 1
+ ;;
+ esac
+
+}
+
+if [ -z "$1" ]; then
+ echo "Usage: $0 {install|uninstall|reinstall|enable}" 2>&2
+ exit 1
+fi
+
+for i in "$@"; do
+ action "$i"
+done
diff --git a/modules/agent/src/main/java/io/jpom/JpomAgentApplication.java b/modules/agent/src/main/java/io/jpom/JpomAgentApplication.java
index f20383c8d7..cc3c643aa8 100644
--- a/modules/agent/src/main/java/io/jpom/JpomAgentApplication.java
+++ b/modules/agent/src/main/java/io/jpom/JpomAgentApplication.java
@@ -1,64 +1,23 @@
/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
*/
package io.jpom;
-import cn.hutool.core.date.BetweenFormatter;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.date.SystemClock;
-import cn.hutool.core.lang.Console;
-import cn.jiangzeyin.common.EnableCommonBoot;
-import io.jpom.common.Type;
-import io.jpom.common.interceptor.AuthorizeInterceptor;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.web.servlet.ServletComponentScan;
-
/**
- * jpom 启动类
+ * 兼容低版本包检查是否为 jpom 对应类型的程序
*
- * @author jiangzeyin
- * @date 2017/9/14.
+ * @author bwcx_jzy
+ * @since 2023/3/31
*/
-@SpringBootApplication
-@ServletComponentScan
-@EnableCommonBoot
+@Deprecated
public class JpomAgentApplication {
-
- /**
- * 启动执行
- *
- * @param args 参数
- * @throws Exception 异常
- */
- public static void main(String[] args) throws Exception {
- long time = SystemClock.now();
- JpomApplication jpomApplication = new JpomApplication(Type.Agent, JpomAgentApplication.class, args);
- jpomApplication
- // 拦截器
- .addInterceptor(AuthorizeInterceptor.class)
- // 添加 参数 url 解码
- // .addHandlerMethodArgumentResolver(UrlDecodeHandlerMethodArgumentResolver.class)
- .run(args);
- Console.log("本次启动耗时:{}", DateUtil.formatBetween(SystemClock.now() - time, BetweenFormatter.Level.MILLISECOND));
- }
-
+ public static void main(String[] args) throws Exception {
+ org.dromara.jpom.JpomAgentApplication.main(args);
+ }
}
diff --git a/modules/agent/src/main/java/io/jpom/common/AgentExceptionHandler.java b/modules/agent/src/main/java/io/jpom/common/AgentExceptionHandler.java
deleted file mode 100644
index 386ab62062..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/AgentExceptionHandler.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common;
-
-import cn.hutool.core.exceptions.ValidateException;
-import cn.hutool.extra.servlet.ServletUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import io.jpom.system.JpomRuntimeException;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.ControllerAdvice;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * 全局异常处理
- *
- * @author jiangzeyin
- * @date 2019/04/17
- */
-@ControllerAdvice
-public class AgentExceptionHandler {
-
- /**
- * 声明要捕获的异常
- *
- * @param request 请求
- * @param response 响应
- * @param e 异常
- */
- @ExceptionHandler({JpomRuntimeException.class, RuntimeException.class, Exception.class})
- public void defExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) {
- DefaultSystemLog.getLog().error("controller " + request.getRequestURI(), e);
- if (e instanceof JpomRuntimeException) {
- ServletUtil.write(response, JsonMessage.getString(500, e.getMessage()), MediaType.APPLICATION_JSON_VALUE);
- } else {
- ServletUtil.write(response, JsonMessage.getString(500, "服务异常:" + e.getMessage()), MediaType.APPLICATION_JSON_VALUE);
- }
- }
-
- /**
- * 声明要捕获的异常 (参数或者状态异常)
- *
- * @param request 请求
- * @param response 响应
- * @param e 异常
- */
- @ExceptionHandler({IllegalArgumentException.class, IllegalStateException.class, ValidateException.class})
- public void paramExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) {
- DefaultSystemLog.getLog().error("controller " + request.getRequestURI(), e);
- ServletUtil.write(response, JsonMessage.getString(405, e.getMessage()), MediaType.APPLICATION_JSON_VALUE);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/BaseAgentController.java b/modules/agent/src/main/java/io/jpom/common/BaseAgentController.java
deleted file mode 100644
index 8e3306dda8..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/BaseAgentController.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common;
-
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.core.util.URLUtil;
-import cn.hutool.extra.servlet.ServletUtil;
-import cn.jiangzeyin.controller.base.AbstractController;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.service.manage.ProjectInfoService;
-import io.jpom.system.ConfigBean;
-import org.springframework.web.context.request.ServletRequestAttributes;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-import java.util.Objects;
-
-/**
- * agent 端
- *
- * @author jiangzeyin
- * @date 2019/4/17
- */
-public abstract class BaseAgentController extends BaseJpomController {
- @Resource
- protected ProjectInfoService projectInfoService;
-
- protected String getUserName() {
- return getUserName(getRequest());
- }
-
- /**
- * 获取server 端操作人
- *
- * @param request req
- * @return name
- */
- private static String getUserName(HttpServletRequest request) {
- String name = ServletUtil.getHeaderIgnoreCase(request, ConfigBean.JPOM_SERVER_USER_NAME);
- name = CharsetUtil.convert(name, CharsetUtil.CHARSET_ISO_8859_1, CharsetUtil.CHARSET_UTF_8);
- name = StrUtil.emptyToDefault(name, StrUtil.DASHED);
- return URLUtil.decode(name, CharsetUtil.CHARSET_UTF_8);
- }
-
- /**
- * 获取server 端操作人
- *
- * @return name
- */
- public static String getNowUserName() {
- ServletRequestAttributes servletRequestAttributes = AbstractController.tryGetRequestAttributes();
- if (servletRequestAttributes == null) {
- return StrUtil.DASHED;
- }
- HttpServletRequest request = servletRequestAttributes.getRequest();
- return getUserName(request);
- }
-
- protected String getWorkspaceId() {
- return ServletUtil.getHeader(getRequest(), Const.WORKSPACEID_REQ_HEADER, CharsetUtil.CHARSET_UTF_8);
- }
-
- /**
- * 获取拦截器中缓存的项目信息
- *
- * @return this
- */
- protected NodeProjectInfoModel getProjectInfoModel() {
- NodeProjectInfoModel nodeProjectInfoModel = tryGetProjectInfoModel();
- Objects.requireNonNull(nodeProjectInfoModel, "获取项目信息失败");
- return nodeProjectInfoModel;
- }
-
- protected NodeProjectInfoModel tryGetProjectInfoModel() {
- NodeProjectInfoModel nodeProjectInfoModel = null;
- String id = getParameter("id");
- if (StrUtil.isNotEmpty(id)) {
- nodeProjectInfoModel = projectInfoService.getItem(id);
- }
- return nodeProjectInfoModel;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/UrlDecodeHandlerMethodArgumentResolver.java b/modules/agent/src/main/java/io/jpom/common/UrlDecodeHandlerMethodArgumentResolver.java
deleted file mode 100644
index 165f501ca9..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/UrlDecodeHandlerMethodArgumentResolver.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common;
-
-import cn.hutool.core.util.ReflectUtil;
-import cn.hutool.core.util.URLUtil;
-import cn.jiangzeyin.common.interceptor.DefaultHandlerMethodArgumentResolver;
-import io.jpom.model.BaseJsonModel;
-import org.springframework.core.MethodParameter;
-import org.springframework.web.bind.support.WebDataBinderFactory;
-import org.springframework.web.context.request.NativeWebRequest;
-import org.springframework.web.method.support.ModelAndViewContainer;
-
-import java.lang.reflect.Field;
-
-/**
- * 解析 参数 url 编码
- *
- * @author bwcx_jzy
- * @since 2021/10/25
- */
-public class UrlDecodeHandlerMethodArgumentResolver extends DefaultHandlerMethodArgumentResolver {
-
-// @Override
-// public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
-// Object argument = super.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
-// if (argument instanceof String) {
-// // 解码
-// return URLUtil.decode(argument.toString());
-// } else if (argument instanceof BaseJsonModel) {
-// // 解码对象属性
-// Field[] fields = ReflectUtil.getFields(argument.getClass());
-// for (Field field : fields) {
-// Class> type = field.getType();
-// if (type == String.class) {
-// String fieldValue = (String) ReflectUtil.getFieldValue(argument, field);
-// fieldValue = URLUtil.decode(fieldValue);
-// ReflectUtil.setFieldValue(argument, field, fieldValue);
-// }
-// }
-// }
-// return argument;
-// }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/AbstractProjectCommander.java b/modules/agent/src/main/java/io/jpom/common/commander/AbstractProjectCommander.java
deleted file mode 100644
index e967661360..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/AbstractProjectCommander.java
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander;
-
-import cn.hutool.cache.impl.LRUCache;
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.date.DatePattern;
-import cn.hutool.core.date.DateTime;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.lang.JarClassLoader;
-import cn.hutool.core.text.StrSplitter;
-import cn.hutool.core.thread.ThreadUtil;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.http.HttpRequest;
-import cn.hutool.http.HttpUtil;
-import cn.hutool.system.SystemUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.spring.SpringUtil;
-import io.jpom.common.commander.impl.LinuxProjectCommander;
-import io.jpom.common.commander.impl.MacOSProjectCommander;
-import io.jpom.common.commander.impl.WindowsProjectCommander;
-import io.jpom.model.RunMode;
-import io.jpom.model.data.JdkInfoModel;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.model.system.NetstatModel;
-import io.jpom.service.manage.JdkInfoService;
-import io.jpom.service.manage.ProjectInfoService;
-import io.jpom.system.AgentExtConfigBean;
-import io.jpom.system.JpomRuntimeException;
-import io.jpom.util.CommandUtil;
-import io.jpom.util.FileUtils;
-import io.jpom.util.JvmUtil;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.jar.Attributes;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-
-/**
- * 项目命令执行基类
- *
- * @author Administrator
- */
-public abstract class AbstractProjectCommander {
-
- public static final String RUNNING_TAG = "running";
- public static final String STOP_TAG = "stopped";
-
- private static AbstractProjectCommander abstractProjectCommander = null;
-
- /**
- * 进程id 对应Jpom 名称
- */
- public static final ConcurrentHashMap PID_JPOM_NAME = new ConcurrentHashMap<>();
- /**
- * 进程Id 获取端口号
- */
- public static final LRUCache PID_PORT = new LRUCache<>(100, TimeUnit.MINUTES.toMillis(10));
-
- /**
- * 实例化Commander
- *
- * @return 命令执行对象
- */
- public static AbstractProjectCommander getInstance() {
- if (abstractProjectCommander != null) {
- return abstractProjectCommander;
- }
- if (SystemUtil.getOsInfo().isLinux()) {
- // Linux系统
- abstractProjectCommander = new LinuxProjectCommander();
- } else if (SystemUtil.getOsInfo().isWindows()) {
- // Windows系统
- abstractProjectCommander = new WindowsProjectCommander();
- } else if (SystemUtil.getOsInfo().isMac()) {
- abstractProjectCommander = new MacOSProjectCommander();
- } else {
- throw new JpomRuntimeException("不支持的:" + SystemUtil.getOsInfo().getName());
- }
- return abstractProjectCommander;
- }
-
- //---------------------------------------------------- 基本操作----start
-
- /**
- * 生成可以执行的命令
- *
- * @param nodeProjectInfoModel 项目
- * @param javaCopyItem 副本信息
- * @return null 是条件不足
- */
- public abstract String buildCommand(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem);
-
- protected String getRunJavaPath(NodeProjectInfoModel nodeProjectInfoModel, boolean w) {
- if (StrUtil.isEmpty(nodeProjectInfoModel.getJdkId())) {
- return w ? "javaw" : "java";
- }
- JdkInfoService bean = SpringUtil.getBean(JdkInfoService.class);
- JdkInfoModel item = bean.getItem(nodeProjectInfoModel.getJdkId());
- if (item == null) {
- return w ? "javaw" : "java";
- }
- String jdkJavaPath = FileUtils.getJdkJavaPath(item.getPath(), w);
- if (jdkJavaPath.contains(StrUtil.SPACE)) {
- jdkJavaPath = String.format("\"%s\"", jdkJavaPath);
- }
- return jdkJavaPath;
- }
-
- /**
- * 启动
- *
- * @param nodeProjectInfoModel 项目
- * @return 结果
- * @throws Exception 异常
- */
- public String start(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) throws Exception {
- String msg = checkStart(nodeProjectInfoModel, javaCopyItem);
- if (msg != null) {
- return msg;
- }
- String command = buildCommand(nodeProjectInfoModel, javaCopyItem);
- if (command == null) {
- return "没有需要执行的命令";
- }
- // 执行命令
- ThreadUtil.execute(() -> {
- try {
- File file = FileUtil.file(nodeProjectInfoModel.allLib());
- if (SystemUtil.getOsInfo().isWindows()) {
- CommandUtil.execSystemCommand(command, file);
- } else {
- CommandUtil.asyncExeLocalCommand(file, command);
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("执行命令失败", e);
- }
- });
- //
- loopCheckRun(nodeProjectInfoModel.getId(), true);
- String status = status(nodeProjectInfoModel.getId());
- this.asyncWebHooks(nodeProjectInfoModel, javaCopyItem, "start", "result", status);
- return status;
- }
-
- /**
- * 查询出指定端口信息
- *
- * @param pid 进程id
- * @param listening 是否只获取检查状态的
- * @return 数组
- */
- public abstract List listNetstat(int pid, boolean listening);
-
- /**
- * 停止
- *
- * @param nodeProjectInfoModel 项目
- * @return 结果
- * @throws Exception 异常
- */
- public String stop(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) throws Exception {
- String tag = javaCopyItem == null ? nodeProjectInfoModel.getId() : javaCopyItem.getTagId();
- String beforeStop = this.webHooks(nodeProjectInfoModel, javaCopyItem, "beforeStop");
- if (StrUtil.isNotEmpty(beforeStop)) {
- return beforeStop;
- }
- // 再次查看进程信息
- String result = status(tag);
- //
- int pid = parsePid(result);
- if (pid > 0) {
- // 清空名称缓存
- PID_JPOM_NAME.remove(pid);
- // 端口号缓存
- PID_PORT.remove(pid);
- }
- this.asyncWebHooks(nodeProjectInfoModel, javaCopyItem, "stop", "result", result);
- return result;
- }
-
- /**
- * 执行 webhooks 通知
- *
- * @param nodeProjectInfoModel 项目信息
- * @param javaCopyItem 副本信息
- * @param type 类型
- * @param other 其他参数
- */
- private void asyncWebHooks(NodeProjectInfoModel nodeProjectInfoModel,
- NodeProjectInfoModel.JavaCopyItem javaCopyItem,
- String type, Object... other) {
- ThreadUtil.execute(() -> this.webHooks(nodeProjectInfoModel, javaCopyItem, type, other));
- }
-
- /**
- * 执行 webhooks 通知
- *
- * @param nodeProjectInfoModel 项目信息
- * @param javaCopyItem 副本信息
- * @param type 类型
- * @param other 其他参数
- * @return 结果
- */
- private String webHooks(NodeProjectInfoModel nodeProjectInfoModel,
- NodeProjectInfoModel.JavaCopyItem javaCopyItem,
- String type, Object... other) {
- String token = nodeProjectInfoModel.getToken();
- if (StrUtil.isEmpty(token)) {
- return StrUtil.EMPTY;
- }
- try {
- HttpRequest httpRequest = HttpUtil.createGet(token);
- httpRequest.form("projectId", nodeProjectInfoModel.getId());
- httpRequest.form("projectName", nodeProjectInfoModel.getName());
- httpRequest.form("type", type, other);
- if (javaCopyItem != null) {
- httpRequest.form("copyId", javaCopyItem.getId());
- }
- String body = httpRequest.execute().body();
- DefaultSystemLog.getLog().info(nodeProjectInfoModel.getName() + ":" + body);
- return body;
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("WebHooks 调用错误", e);
- return "WebHooks error:" + e.getMessage();
- }
- }
-
- /**
- * 重启
- *
- * @param nodeProjectInfoModel 项目
- * @return 结果
- * @throws Exception 异常
- */
- public String restart(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) throws Exception {
- this.asyncWebHooks(nodeProjectInfoModel, javaCopyItem, "beforeRestart");
- boolean run = this.isRun(nodeProjectInfoModel, javaCopyItem);
- if (run) {
- stop(nodeProjectInfoModel, javaCopyItem);
- }
- return start(nodeProjectInfoModel, javaCopyItem);
- }
-
- /**
- * 启动项目前基本检查
- *
- * @param nodeProjectInfoModel 项目
- * @return null 检查一切正常
- * @throws Exception 异常
- */
- private String checkStart(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) throws Exception {
- int pid = javaCopyItem == null ? getPid(nodeProjectInfoModel.getId()) : this.getPid(javaCopyItem.getTagId());
- if (pid > 0) {
- return "当前程序正常运行中,不能重复启动,PID:" + pid;
- }
- String lib = nodeProjectInfoModel.allLib();
- File fileLib = new File(lib);
- File[] files = fileLib.listFiles();
- if (files == null || files.length <= 0) {
- return "没有jar包,请先到文件管理中上传程序的jar";
- }
- //
- if (nodeProjectInfoModel.getRunMode() == RunMode.ClassPath || nodeProjectInfoModel.getRunMode() == RunMode.JavaExtDirsCp) {
- JarClassLoader jarClassLoader = JarClassLoader.load(fileLib);
- // 判断主类
- try {
- jarClassLoader.loadClass(nodeProjectInfoModel.getMainClass());
- } catch (ClassNotFoundException notFound) {
- return "没有找到对应的MainClass:" + nodeProjectInfoModel.getMainClass();
- }
- } else {
- List fileList = NodeProjectInfoModel.listJars(nodeProjectInfoModel);
- if (fileList.size() <= 0) {
- return String.format("没有%s包,请先到文件管理中上传程序的%s", nodeProjectInfoModel.getRunMode().name(), nodeProjectInfoModel.getRunMode().name());
- }
- File jarFile = fileList.get(0);
- String checkJar = checkJar(jarFile);
- if (checkJar != null) {
- return checkJar;
- }
- }
- // 备份日志
- backLog(nodeProjectInfoModel, javaCopyItem);
- return null;
- }
-
- private static String checkJar(File jarFile) {
- try (JarFile jarFile1 = new JarFile(jarFile)) {
- Manifest manifest = jarFile1.getManifest();
- Attributes attributes = manifest.getMainAttributes();
- String mainClass = attributes.getValue(Attributes.Name.MAIN_CLASS);
- if (mainClass == null) {
- return jarFile.getAbsolutePath() + "中没有找到对应的MainClass属性";
- }
- JarClassLoader jarClassLoader = JarClassLoader.load(jarFile);
- try {
- jarClassLoader.loadClass(mainClass);
- } catch (ClassNotFoundException notFound) {
- return jarFile.getAbsolutePath() + "中没有找到对应的MainClass:" + mainClass;
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("解析jar", e);
- return jarFile.getAbsolutePath() + " 解析错误:" + e.getMessage();
- }
- return null;
- }
-
- /**
- * 清空日志信息
- *
- * @param nodeProjectInfoModel 项目
- * @return 结果
- */
- public String backLog(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) {
- File file = javaCopyItem == null ? new File(nodeProjectInfoModel.getLog()) : nodeProjectInfoModel.getLog(javaCopyItem);
- if (!file.exists() || file.isDirectory()) {
- return "not exists";
- }
- // 文件内容太少不处理
- if (file.length() <= 1000) {
- return "ok";
- }
- if (AgentExtConfigBean.getInstance().openLogBack()) {
- // 开启日志备份才移动文件
- File backPath = javaCopyItem == null ? nodeProjectInfoModel.getLogBack() : nodeProjectInfoModel.getLogBack(javaCopyItem);
- backPath = new File(backPath, DateTime.now().toString(DatePattern.PURE_DATETIME_FORMAT) + ".log");
- FileUtil.copy(file, backPath, true);
- }
- // 清空日志
- String r = AbstractSystemCommander.getInstance().emptyLogFile(file);
- if (StrUtil.isNotEmpty(r)) {
- DefaultSystemLog.getLog().info(r);
- }
- return "ok";
- }
-
- public String status(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) {
- String tag = javaCopyItem == null ? nodeProjectInfoModel.getId() : javaCopyItem.getTagId();
- return this.status(tag);
- }
-
- /**
- * 查看状态
- *
- * @param tag 运行标识
- * @return 查询结果
- */
- protected String status(String tag) {
- String jpsStatus = getJpsStatus(tag);
- if (StrUtil.equals(AbstractProjectCommander.STOP_TAG, jpsStatus) && SystemUtil.getOsInfo().isLinux()) {
- return getLinuxPsStatus(tag);
- }
- return jpsStatus;
- }
-
- /**
- * 尝试jps 中查看进程id
- *
- * @param tag 进程标识
- * @return 运行标识
- */
- private String getJpsStatus(String tag) {
- Integer pid = JvmUtil.getPidByTag(tag);
- if (pid == null || pid <= 0) {
- return AbstractProjectCommander.STOP_TAG;
- }
- return StrUtil.format("{}:{}", AbstractProjectCommander.RUNNING_TAG, pid);
- }
-
-
- /**
- * 尝试ps -ef | grep 中查看进程id
- *
- * @param tag 进程标识
- * @return 运行标识
- */
- private String getLinuxPsStatus(String tag) {
- String execSystemCommand = CommandUtil.execSystemCommand("ps -ef | grep " + tag);
- List list = StrSplitter.splitTrim(execSystemCommand, StrUtil.LF, true);
- for (String item : list) {
- if (JvmUtil.checkCommandLineIsJpom(item, tag)) {
- String[] split = StrUtil.splitToArray(item, StrUtil.SPACE);
- return StrUtil.format("{}:{}", AbstractProjectCommander.RUNNING_TAG, split[1]);
- }
- }
- return AbstractProjectCommander.STOP_TAG;
- }
-
- //---------------------------------------------------- 基本操作----end
-
- /**
- * 获取进程占用的主要端口
- *
- * @param pid 进程id
- * @return 端口
- */
- public String getMainPort(int pid) {
- String cachePort = PID_PORT.get(pid);
- if (cachePort != null) {
- return cachePort;
- }
- List list = listNetstat(pid, true);
- if (list == null) {
- return StrUtil.DASHED;
- }
- List ports = new ArrayList<>();
- for (NetstatModel model : list) {
- String local = model.getLocal();
- String portStr = getPortFormLocalIp(local);
- if (portStr == null) {
- continue;
- }
- // 取最小的端口号
- int minPort = Convert.toInt(portStr, Integer.MAX_VALUE);
- if (minPort == Integer.MAX_VALUE) {
- continue;
- }
- ports.add(minPort);
- }
- if (CollUtil.isEmpty(ports)) {
- return StrUtil.DASHED;
- }
- String allPort = CollUtil.join(ports, ",");
- // 缓存
- PID_PORT.put(pid, allPort);
- return allPort;
- }
-
- /**
- * 判断ip 信息是否为本地ip
- *
- * @param local ip信息
- * @return true 是本地ip
- */
- private String getPortFormLocalIp(String local) {
- if (StrUtil.isEmpty(local)) {
- return null;
- }
- List ipPort = StrSplitter.splitTrim(local, StrUtil.COLON, true);
- if (ipPort.isEmpty()) {
- return null;
- }
- if ("0.0.0.0".equals(ipPort.get(0)) || ipPort.size() == 1) {
- // 0.0.0.0:8084 || :::18000
- return ipPort.get(ipPort.size() - 1);
- }
- return null;
- }
-
-
- /**
- * 根据指定进程id获取Jpom 名称
- *
- * @param pid 进程id
- * @return false 不是来自Jpom
- * @throws IOException 异常
- */
- public String getJpomNameByPid(int pid) throws IOException {
- String name = PID_JPOM_NAME.get(pid);
- if (name != null) {
- return name;
- }
- DefaultSystemLog.getLog().debug("getJpomNameByPid pid: {}", pid);
- ProjectInfoService projectInfoService = SpringUtil.getBean(ProjectInfoService.class);
- List nodeProjectInfoModels = projectInfoService.list();
- if (nodeProjectInfoModels == null || nodeProjectInfoModels.isEmpty()) {
- return StrUtil.DASHED;
- }
- String virtualMachine = JvmUtil.getVirtualMachineInfo(pid);
- if (virtualMachine == null) {
- return StrUtil.DASHED;
- }
-
- for (NodeProjectInfoModel nodeProjectInfoModel : nodeProjectInfoModels) {
- if (JvmUtil.checkCommandLineIsJpom(virtualMachine, nodeProjectInfoModel.getId())) {
- name = nodeProjectInfoModel.getName();
- break;
- }
- }
-
- if (name != null) {
- PID_JPOM_NAME.put(pid, name);
- return name;
- }
- return StrUtil.DASHED;
- }
-
-
- /**
- * 获取进程id
- *
- * @param tag 项目Id
- * @return 未运行 返回 0
- * @throws Exception 异常
- */
- public int getPid(String tag) throws Exception {
- String result = status(tag);
- return parsePid(result);
- }
-
- /**
- * 转换pid
- *
- * @param result 查询信息
- * @return int
- */
- public static int parsePid(String result) {
- if (result.startsWith(AbstractProjectCommander.RUNNING_TAG)) {
- String[] split = result.split(":");
- return Convert.toInt(ArrayUtil.get(split, 1), 0);
- }
- return 0;
- }
-
- /**
- * 是否正在运行
- *
- * @param nodeProjectInfoModel 项目
- * @return true 正在运行
- */
- public boolean isRun(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) {
- String tag = javaCopyItem == null ? nodeProjectInfoModel.getId() : javaCopyItem.getTagId();
- String result = this.status(tag);
- return result.contains(AbstractProjectCommander.RUNNING_TAG);
- }
-
- /**
- * 是否正在运行
- *
- * @param tag 运行标识
- * @return true 正在运行
- */
- private boolean isRun(String tag) {
- String result = this.status(tag);
- return result.contains(AbstractProjectCommander.RUNNING_TAG);
- }
-
- /***
- * 阻塞检查程序状态
- * @param tag 程序tag
- * @param status 要检查的状态
- * @throws Exception 异常
- * @return 和参数status相反
- */
- protected boolean loopCheckRun(String tag, boolean status) throws Exception {
- int stopWaitTime = AgentExtConfigBean.getInstance().getStopWaitTime();
- stopWaitTime = Math.max(stopWaitTime, 1);
- int loopCount = (int) (TimeUnit.SECONDS.toMillis(stopWaitTime) / 500);
- int count = 0;
- do {
- if (isRun(tag) == status) {
- return status;
- }
- ThreadUtil.sleep(500);
- } while (count++ < loopCount);
- return !status;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/AbstractSystemCommander.java b/modules/agent/src/main/java/io/jpom/common/commander/AbstractSystemCommander.java
deleted file mode 100644
index 54b8d8af74..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/AbstractSystemCommander.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander;
-
-import cn.hutool.system.SystemUtil;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.commander.impl.LinuxSystemCommander;
-import io.jpom.common.commander.impl.MacOSSystemCommander;
-import io.jpom.common.commander.impl.WindowsSystemCommander;
-import io.jpom.model.system.ProcessModel;
-import io.jpom.system.JpomRuntimeException;
-import io.jpom.util.CommandUtil;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * 系统监控命令
- *
- * @author jiangzeyin
- * @date 2019/4/16
- */
-public abstract class AbstractSystemCommander {
-
- private static AbstractSystemCommander abstractSystemCommander = null;
-
- public static AbstractSystemCommander getInstance() {
- if (abstractSystemCommander != null) {
- return abstractSystemCommander;
- }
- if (SystemUtil.getOsInfo().isLinux()) {
- // Linux系统
- abstractSystemCommander = new LinuxSystemCommander();
- } else if (SystemUtil.getOsInfo().isWindows()) {
- // Windows系统
- abstractSystemCommander = new WindowsSystemCommander();
- } else if (SystemUtil.getOsInfo().isMac()) {
- abstractSystemCommander = new MacOSSystemCommander();
- } else {
- throw new JpomRuntimeException("不支持的:" + SystemUtil.getOsInfo().getName());
- }
- return abstractSystemCommander;
- }
-
- /**
- * 获取整个服务器监控信息
- *
- * @return data
- */
- public abstract JSONObject getAllMonitor();
-
- /**
- * 获取当前服务器的所有进程列表
- *
- * @return array
- */
- public abstract List getProcessList();
-
- /**
- * 获取指定进程的 内存信息
- *
- * @param pid 进程id
- * @return json
- */
- public abstract ProcessModel getPidInfo(int pid);
-
- /**
- * 清空文件内容
- *
- * @param file 文件
- * @return 执行结果
- */
- public abstract String emptyLogFile(File file);
-
- /**
- * 磁盘占用
- *
- * @return 磁盘占用
- */
- protected static String getHardDisk() {
- File[] files = File.listRoots();
- double totalSpace = 0;
- double useAbleSpace = 0;
- for (File file : files) {
- double total = file.getTotalSpace();
- totalSpace += total;
- useAbleSpace += total - file.getUsableSpace();
- }
- return totalSpace <= 0 ? "0" : String.format("%.2f", useAbleSpace / totalSpace * 100);
- }
-
- /**
- * 查询服务状态
- *
- * @param serviceName 服务名称
- * @return true 运行中
- */
- public abstract boolean getServiceStatus(String serviceName);
-
- /**
- * 启动服务
- *
- * @param serviceName 服务名称
- * @return 结果
- */
- public abstract String startService(String serviceName);
-
- /**
- * 关闭服务
- *
- * @param serviceName 服务名称
- * @return 结果
- */
- public abstract String stopService(String serviceName);
-
- /**
- * 构建kill 命令
- *
- * @param pid 进程编号
- * @return 结束进程命令
- */
- public abstract String buildKill(int pid);
-
- /**
- * kill
- *
- * @param pid 进程编号
- */
- public String kill(File file, int pid) {
- String kill = buildKill(pid);
- return CommandUtil.execSystemCommand(kill, file);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/AbstractTomcatCommander.java b/modules/agent/src/main/java/io/jpom/common/commander/AbstractTomcatCommander.java
deleted file mode 100644
index c29b4f1cee..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/AbstractTomcatCommander.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander;
-
-import cn.hutool.core.thread.ThreadUtil;
-import cn.hutool.http.HttpRequest;
-import cn.hutool.system.SystemUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import io.jpom.common.commander.impl.LinuxTomcatCommander;
-import io.jpom.common.commander.impl.WindowsTomcatCommander;
-import io.jpom.model.data.TomcatInfoModel;
-import io.jpom.system.JpomRuntimeException;
-
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-
-/**
- * tomcat命令执行工具类
- *
- * @author LF
- */
-public abstract class AbstractTomcatCommander {
-
- private static AbstractTomcatCommander abstractTomcatCommander;
-
- public static AbstractTomcatCommander getInstance() {
- if (abstractTomcatCommander != null) {
- return abstractTomcatCommander;
- }
- if (SystemUtil.getOsInfo().isLinux()) {
- // Linux系统
- abstractTomcatCommander = new LinuxTomcatCommander();
- } else if (SystemUtil.getOsInfo().isWindows()) {
- // Windows系统
- abstractTomcatCommander = new WindowsTomcatCommander();
- } else if (SystemUtil.getOsInfo().isMac()) {
- abstractTomcatCommander = new LinuxTomcatCommander();
- } else {
- throw new JpomRuntimeException("不支持的:" + SystemUtil.getOsInfo().getName());
- }
- return abstractTomcatCommander;
- }
-
- /**
- * 执行tomcat命令
- *
- * @param tomcatInfoModel tomcat信息
- * @param cmd 执行的命令,包括start stop
- * @return 返回tomcat启动结果
- */
- public abstract String execCmd(TomcatInfoModel tomcatInfoModel, String cmd);
-
- /**
- * 检查tomcat状态
- *
- * @param tomcatInfoModel tomcat信息
- * @param cmd 操作命令
- * @return 状态结果
- */
- protected String getStatus(TomcatInfoModel tomcatInfoModel, String cmd) {
- String strReturn = "start".equals(cmd) ? "stopped" : "started";
- int i = 0;
- while (i < 10) {
- int result = 0;
- String url = String.format("http://127.0.0.1:%d/", tomcatInfoModel.getPort());
- HttpRequest httpRequest = new HttpRequest(url);
- // 设置超时时间为3秒
- httpRequest.setConnectionTimeout(3000);
- try {
- httpRequest.execute();
- result = 1;
- } catch (Exception ignored) {
- }
-
- i++;
- if ("start".equals(cmd) && result == 1) {
- strReturn = "started";
- break;
- }
- if ("stop".equals(cmd) && result == 0) {
- strReturn = "stopped";
- break;
- }
- ThreadUtil.sleep(1000);
- }
- return strReturn;
- }
-
- protected void exec(String command, boolean close) {
- DefaultSystemLog.getLog().info(command);
- try {
- // 执行命令
- Process process = Runtime.getRuntime().exec(command);
- process.getInputStream().close();
- process.getErrorStream().close();
- process.getOutputStream().close();
- process.waitFor(5, TimeUnit.SECONDS);
- if (close) {
- process.destroy();
- }
- } catch (IOException | InterruptedException e) {
- DefaultSystemLog.getLog().error("tomcat执行名称失败", e);
- }
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/impl/LinuxProjectCommander.java b/modules/agent/src/main/java/io/jpom/common/commander/impl/LinuxProjectCommander.java
deleted file mode 100644
index f710b6b90a..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/impl/LinuxProjectCommander.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.text.StrSplitter;
-import cn.hutool.core.util.StrUtil;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.common.commander.AbstractSystemCommander;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.model.system.NetstatModel;
-import io.jpom.util.CommandUtil;
-import io.jpom.util.JvmUtil;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * linux
- *
- * @author Administrator
- */
-public class LinuxProjectCommander extends AbstractProjectCommander {
-
- @Override
- public String buildCommand(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) {
- String path = NodeProjectInfoModel.getClassPathLib(nodeProjectInfoModel);
- if (StrUtil.isBlank(path)) {
- return null;
- }
- String tag = javaCopyItem == null ? nodeProjectInfoModel.getId() : javaCopyItem.getTagId();
- return String.format("nohup %s %s %s" +
- " %s %s %s >> %s 2>&1 &",
- getRunJavaPath(nodeProjectInfoModel, false),
- javaCopyItem == null ? nodeProjectInfoModel.getJvm() : javaCopyItem.getJvm(),
- JvmUtil.getJpomPidTag(tag, nodeProjectInfoModel.allLib()),
- path,
- nodeProjectInfoModel.getMainClass(),
- javaCopyItem == null ? nodeProjectInfoModel.getArgs() : javaCopyItem.getArgs(),
- nodeProjectInfoModel.getAbsoluteLog(javaCopyItem));
- }
-
- @Override
- public String stop(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) throws Exception {
- String result = super.stop(nodeProjectInfoModel, javaCopyItem);
- int pid = parsePid(result);
- if (pid > 0) {
- String kill = AbstractSystemCommander.getInstance().kill(FileUtil.file(nodeProjectInfoModel.allLib()), pid);
- if (loopCheckRun(nodeProjectInfoModel.getId(), false)) {
- // 强制杀进程
- String cmd = String.format("kill -9 %s", pid);
- CommandUtil.asyncExeLocalCommand(FileUtil.file(nodeProjectInfoModel.allLib()), cmd);
- }
- String tag = javaCopyItem == null ? nodeProjectInfoModel.getId() : javaCopyItem.getTagId();
- result = status(tag) + StrUtil.SPACE + kill;
- }
- return result;
- }
-
- @Override
- public List listNetstat(int pId, boolean listening) {
- String cmd;
- if (listening) {
- cmd = "netstat -antup | grep " + pId + " |grep \"LISTEN\" | head -20";
- } else {
- cmd = "netstat -antup | grep " + pId + " |grep -v \"CLOSE_WAIT\" | head -20";
- }
- String result = CommandUtil.execSystemCommand(cmd);
- List netList = StrSplitter.splitTrim(result, "\n", true);
- if (netList == null || netList.size() <= 0) {
- return null;
- }
- List array = new ArrayList<>();
- for (String str : netList) {
- List list = StrSplitter.splitTrim(str, " ", true);
- if (list.size() < 5) {
- continue;
- }
- NetstatModel netstatModel = new NetstatModel();
- netstatModel.setProtocol(list.get(0));
- netstatModel.setReceive(list.get(1));
- netstatModel.setSend(list.get(2));
- netstatModel.setLocal(list.get(3));
- netstatModel.setForeign(list.get(4));
- if ("tcp".equalsIgnoreCase(netstatModel.getProtocol())) {
- netstatModel.setStatus(CollUtil.get(list, 5));
- netstatModel.setName(CollUtil.get(list, 6));
- } else {
- netstatModel.setStatus(StrUtil.DASHED);
- netstatModel.setName(CollUtil.get(list, 5));
- }
- array.add(netstatModel);
- }
- return array;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/impl/LinuxSystemCommander.java b/modules/agent/src/main/java/io/jpom/common/commander/impl/LinuxSystemCommander.java
deleted file mode 100644
index 0ddca8c76f..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/impl/LinuxSystemCommander.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander.impl;
-
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.text.StrSplitter;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.system.SystemUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.commander.AbstractSystemCommander;
-import io.jpom.model.system.ProcessModel;
-import io.jpom.util.CommandUtil;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author jiangzeyin
- * @date 2019/4/16
- */
-public class LinuxSystemCommander extends AbstractSystemCommander {
-
- @Override
- public JSONObject getAllMonitor() {
- String result = CommandUtil.execSystemCommand("top -i -b -n 1");
- if (StrUtil.isEmpty(result)) {
- return null;
- }
- String[] split = result.split(StrUtil.LF);
- int length = split.length;
- JSONObject jsonObject = new JSONObject();
- if (length >= 2) {
- String cpus = split[2];
- //cpu占比
- String cpu = getLinuxCpu(cpus);
- jsonObject.put("cpu", cpu);
- }
- if (length >= 3) {
- String mem = split[3];
- //内存占比
- String[] memory = getLinuxMemory(mem);
- jsonObject.put("memory", ArrayUtil.get(memory, 0));
- // @author jzy
- jsonObject.put("memoryUsed", ArrayUtil.get(memory, 1));
- }
- jsonObject.put("disk", getHardDisk());
- return jsonObject;
- }
-
- @Override
- public List getProcessList() {
- String s = CommandUtil.execSystemCommand("top -b -n 1 | grep java");
- return formatLinuxTop(s, false);
- }
-
-
- @Override
- public ProcessModel getPidInfo(int pid) {
- String command = "top -b -n 1 -p " + pid;
- String internal = CommandUtil.execSystemCommand(command);
- List processModels = formatLinuxTop(internal, true);
- if (processModels == null || processModels.isEmpty()) {
- return null;
- }
- return processModels.get(0);
- }
-
-
- @Override
- public String emptyLogFile(File file) {
- return CommandUtil.execSystemCommand("cp /dev/null " + file.getAbsolutePath());
- }
-
- /**
- * 将linux的top信息转为集合
- *
- * @param top top
- */
- private static List formatLinuxTop(String top, boolean header) {
- List list = StrSplitter.splitTrim(top, StrUtil.LF, true);
- if (list.size() <= 0) {
- return null;
- }
- List list1 = new ArrayList<>();
- ProcessModel processModel;
- for (int i = header ? 6 : 0, len = list.size(); i < len; i++) {
- processModel = new ProcessModel();
- String item = list.get(i);
- List values = StrSplitter.splitTrim(item, StrUtil.SPACE, true);
- processModel.setPid(Integer.parseInt(values.get(0)));
- processModel.setUser(values.get(1));
- processModel.setPr(values.get(2));
- processModel.setNi(values.get(3));
- //
- processModel.setVirt(formSize(values.get(4)));
- processModel.setRes(formSize(values.get(5)));
- processModel.setShr(formSize(values.get(6)));
- //
- processModel.setStatus(formStatus(values.get(7)));
- //
- processModel.setCpu(values.get(8) + "%");
- processModel.setMem(values.get(9) + "%");
- //
- processModel.setTime(values.get(10));
- processModel.setCommand(values.get(11));
- list1.add(processModel);
- }
- return list1;
- }
-
-
- private static String formStatus(String val) {
- String value = "未知";
- if ("S".equalsIgnoreCase(val)) {
- value = "睡眠";
- } else if ("R".equalsIgnoreCase(val)) {
- value = "运行";
- } else if ("T".equalsIgnoreCase(val)) {
- value = "跟踪/停止";
- } else if ("Z".equalsIgnoreCase(val)) {
- value = "僵尸进程 ";
- } else if ("D".equalsIgnoreCase(val)) {
- value = "不可中断的睡眠状态 ";
- } else if ("i".equalsIgnoreCase(val)) {
- value = "多线程 ";
- }
- return value;
- }
-
- private static String formSize(String val) {
- if (StrUtil.endWithIgnoreCase(val, "g")) {
- String newVal = val.substring(0, val.length() - 1);
- return String.format("%.2f MB", Convert.toDouble(newVal, 0D) * 1024);
- }
- if (StrUtil.endWithIgnoreCase(val, "m")) {
- String newVal = val.substring(0, val.length() - 1);
- return Convert.toLong(newVal, 0L) / 1024 + " MB";
- }
- return Convert.toLong(val, 0L) / 1024 + " MB";
- }
-
- /**
- * 获取内存信息
- *
- * @param info 内存信息
- * @return 内存信息
- */
- private static String[] getLinuxMemory(String info) {
- if (StrUtil.isEmpty(info)) {
- return null;
- }
- int index = info.indexOf(":") + 1;
- String[] split = info.substring(index).split(",");
-// 509248k total — 物理内存总量(509M)
-// 495964k used — 使用中的内存总量(495M)
-// 13284k free — 空闲内存总量(13M)
-// 25364k buffers — 缓存的内存量 (25M)
- double total = 0, free = 0, used = 0;
- for (String str : split) {
- str = str.trim();
- if (str.endsWith("free")) {
- // 减去了 buff
- String value = str.replace("free", "").replace("k", "").trim();
- free = Convert.toDouble(value, 0.0);
- }
- if (str.endsWith("total")) {
- String value = str.replace("total", "").replace("k", "").trim();
- total = Convert.toDouble(value, 0.0);
- }
- if (str.endsWith("used")) {
- // 计算出时间使用
- String value = str.replace("used", "").replace("k", "").trim();
- used = Convert.toDouble(value, 0.0);
- }
- }
- return new String[]{String.format("%.2f", (total - free) / total * 100), String.format("%.2f", (used) / total * 100)};
- }
-
- /**
- * 获取占用cpu信息
- *
- * @param info cpu信息
- * @return cpu信息
- */
- private static String getLinuxCpu(String info) {
- if (StrUtil.isEmpty(info)) {
- return null;
- }
- int i = info.indexOf(":");
- String[] split = info.substring(i + 1).split(",");
-// 1.3% us — 用户空间占用CPU的百分比。
-// 1.0% sy — 内核空间占用CPU的百分比。
-// 0.0% ni — 改变过优先级的进程占用CPU的百分比
-// 97.3% id — 空闲CPU百分比
-// 0.0% wa — IO等待占用CPU的百分比
-// 0.3% hi — 硬中断(Hardware IRQ)占用CPU的百分比
-// 0.0% si — 软中断(Software Interrupts)占用CPU的百分比
- for (String str : split) {
- str = str.trim();
- String value = str.substring(0, str.length() - 2).trim();
- String tag = str.substring(str.length() - 2);
- if ("id".equalsIgnoreCase(tag)) {
- value = value.replace("%", "");
- double val = Convert.toDouble(value, 0.0);
- return String.format("%.2f", 100.00 - val);
- }
- }
- return "0";
- }
-
- @Override
- public boolean getServiceStatus(String serviceName) {
- if (StrUtil.startWith(serviceName, StrUtil.SLASH)) {
- String ps = getPs(serviceName);
- return StrUtil.isNotEmpty(ps);
- }
- String format = StrUtil.format("service {} status", serviceName);
- String result = CommandUtil.execSystemCommand(format);
- return StrUtil.containsIgnoreCase(result, "RUNNING");
- }
-
- @Override
- public String startService(String serviceName) {
- if (StrUtil.startWith(serviceName, StrUtil.SLASH)) {
- try {
- CommandUtil.asyncExeLocalCommand(new File(SystemUtil.getUserInfo().getHomeDir()), serviceName);
- return "ok";
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("执行异常", e);
- return "执行异常:" + e.getMessage();
- }
- }
- String format = StrUtil.format("service {} start", serviceName);
- return CommandUtil.execSystemCommand(format);
- }
-
- @Override
- public String stopService(String serviceName) {
- if (StrUtil.startWith(serviceName, StrUtil.SLASH)) {
- String ps = getPs(serviceName);
- List list = StrUtil.splitTrim(ps, StrUtil.LF);
- if (list == null || list.isEmpty()) {
- return "stop";
- }
- String s = list.get(0);
- list = StrUtil.splitTrim(s, StrUtil.SPACE);
- if (list == null || list.size() < 2) {
- return "stop";
- }
- File file = new File(SystemUtil.getUserInfo().getHomeDir());
- int pid = Convert.toInt(list.get(1), 0);
- if (pid <= 0) {
- return "error stop";
- }
- return kill(file, pid);
- }
- String format = StrUtil.format("service {} stop", serviceName);
- return CommandUtil.execSystemCommand(format);
- }
-
- @Override
- public String buildKill(int pid) {
- return String.format("kill %s", pid);
- }
-
- private String getPs(String serviceName) {
- String ps = StrUtil.format("ps -ef | grep -v 'grep' | egrep {}", serviceName);
- return CommandUtil.execSystemCommand(ps);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/impl/LinuxTomcatCommander.java b/modules/agent/src/main/java/io/jpom/common/commander/impl/LinuxTomcatCommander.java
deleted file mode 100644
index bef7f1d6d4..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/impl/LinuxTomcatCommander.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander.impl;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.text.StrSplitter;
-import cn.hutool.core.util.NumberUtil;
-import cn.hutool.core.util.StrUtil;
-import io.jpom.common.commander.AbstractTomcatCommander;
-import io.jpom.model.data.TomcatInfoModel;
-import io.jpom.util.CommandUtil;
-
-import java.util.List;
-
-/**
- * tomcat的linux管理命令
- *
- * @author LF
- */
-public class LinuxTomcatCommander extends AbstractTomcatCommander {
-
- @Override
- public String execCmd(TomcatInfoModel tomcatInfoModel, String cmd) {
- String tomcatPath = tomcatInfoModel.pathAndCheck();
- if (StrUtil.isBlank(tomcatPath)) {
- return "tomcat path blank";
- }
- String command = null;
- if ("stop".equals(cmd)) {
- String setPidCmd = CommandUtil.execSystemCommand("jps -mv");
- List list = StrSplitter.splitTrim(setPidCmd, StrUtil.LF, true);
- for (String item : list) {
- //路径格式转换
- String msg = FileUtil.normalize(item + StrUtil.SLASH);
- //判断集合中元素是否包含指定Tomcat路径
- boolean w = msg.contains(tomcatInfoModel.getPath());
- if (w) {
- //截取TomcatPid
- if (msg.indexOf(" ") > 1) {
- String tmPid = msg.substring(0, msg.indexOf(" "));
- //判断截取的PID是否为纯数字
- if (NumberUtil.isInteger(tmPid)) {
- command = String.format("kill -9 %s", tmPid);
- exec(command, false);
- }
- }
- }
- }
- } else {
- command = String.format("/bin/sh -c %s/bin/startup.sh", tomcatPath);
- //
- exec(command, false);
- }
- if (StrUtil.isBlank(tomcatPath)) {
- return "tomcat path blank";
- }
- // 查询操作结果并返回
- return getStatus(tomcatInfoModel, cmd);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/impl/MacOSProjectCommander.java b/modules/agent/src/main/java/io/jpom/common/commander/impl/MacOSProjectCommander.java
deleted file mode 100644
index 26b7bec999..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/impl/MacOSProjectCommander.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.text.StrSplitter;
-import cn.hutool.core.util.StrUtil;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.common.commander.AbstractSystemCommander;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.model.system.NetstatModel;
-import io.jpom.util.CommandUtil;
-import io.jpom.util.JvmUtil;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * MacOSProjectCommander
- *
- * @author Hotstrip
- * @Description some commands cannot execute success on Mac OS
- */
-public class MacOSProjectCommander extends AbstractProjectCommander {
-
- @Override
- public String buildCommand(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) {
- String path = NodeProjectInfoModel.getClassPathLib(nodeProjectInfoModel);
- if (StrUtil.isBlank(path)) {
- return null;
- }
- String tag = javaCopyItem == null ? nodeProjectInfoModel.getId() : javaCopyItem.getTagId();
- return String.format("nohup %s %s %s" +
- " %s %s %s >> %s 2>&1 &",
- getRunJavaPath(nodeProjectInfoModel, false),
- javaCopyItem == null ? nodeProjectInfoModel.getJvm() : javaCopyItem.getJvm(),
- JvmUtil.getJpomPidTag(tag, nodeProjectInfoModel.allLib()),
- path,
- nodeProjectInfoModel.getMainClass(),
- javaCopyItem == null ? nodeProjectInfoModel.getArgs() : javaCopyItem.getArgs(),
- nodeProjectInfoModel.getAbsoluteLog(javaCopyItem));
- }
-
- @Override
- public List listNetstat(int pId, boolean listening) {
- String cmd;
- if (listening) {
- cmd = "lsof -n -P -iTCP -sTCP:LISTEN |grep " + pId + " | head -20";
- } else {
- cmd = "lsof -n -P -iTCP -sTCP:CLOSE_WAIT |grep " + pId + " | head -20";
- }
- String result = CommandUtil.execSystemCommand(cmd);
- //DefaultSystemLog.getLog().debug("Mac OS lsof data: {}", result);
- List netList = StrSplitter.splitTrim(result, "\n", true);
- if (netList == null || netList.size() <= 0) {
- return null;
- }
- List array = new ArrayList<>();
- for (String str : netList) {
- List list = StrSplitter.splitTrim(str, " ", true);
- if (list.size() < 5) {
- continue;
- }
- NetstatModel netstatModel = new NetstatModel();
- netstatModel.setProtocol(list.get(0));
- netstatModel.setReceive(list.get(1));
- netstatModel.setSend(list.get(2));
- netstatModel.setLocal(list.get(3));
- netstatModel.setForeign(list.get(4));
- if ("tcp".equalsIgnoreCase(netstatModel.getProtocol())) {
- netstatModel.setStatus(CollUtil.get(list, 5));
- netstatModel.setName(CollUtil.get(list, 6));
- } else {
- netstatModel.setStatus(StrUtil.DASHED);
- netstatModel.setName(CollUtil.get(list, 5));
- }
- array.add(netstatModel);
- }
- return array;
- }
-
- @Override
- public String stop(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) throws Exception {
- String result = super.stop(nodeProjectInfoModel, javaCopyItem);
- int pid = parsePid(result);
- if (pid > 0) {
- String kill = AbstractSystemCommander.getInstance().kill(FileUtil.file(nodeProjectInfoModel.allLib()), pid);
- if (loopCheckRun(nodeProjectInfoModel.getId(), false)) {
- // 强制杀进程
- String cmd = String.format("kill -9 %s", pid);
- CommandUtil.asyncExeLocalCommand(FileUtil.file(nodeProjectInfoModel.allLib()), cmd);
- }
- String tag = javaCopyItem == null ? nodeProjectInfoModel.getId() : javaCopyItem.getTagId();
- result = status(tag) + StrUtil.SPACE + kill;
- }
- return result;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/impl/MacOSSystemCommander.java b/modules/agent/src/main/java/io/jpom/common/commander/impl/MacOSSystemCommander.java
deleted file mode 100644
index 9615e32726..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/impl/MacOSSystemCommander.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander.impl;
-
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.text.StrSplitter;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.system.SystemUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.commander.AbstractSystemCommander;
-import io.jpom.model.system.ProcessModel;
-import io.jpom.util.CommandUtil;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author User
- */
-public class MacOSSystemCommander extends AbstractSystemCommander {
-
- @Override
- public JSONObject getAllMonitor() {
- String result = CommandUtil.execSystemCommand("top -l 1 | head");
- if (StrUtil.isEmpty(result)) {
- return null;
- }
- String[] split = result.split(StrUtil.LF);
- int length = split.length;
- JSONObject jsonObject = new JSONObject();
- // cpu 在第 4 行,下标为 3
- if (length > 3) {
- String cpus = split[3];
- // cpu占比
- String cpu = getLinuxCpu(cpus);
- jsonObject.put("cpu", cpu);
- }
- // 内存占比 第 7 行 下标为 6
- if (length > 6) {
- String mem = split[6];
- //内存占比
- String memory = getLinuxMemory(mem);
- jsonObject.put("memory", memory);
- }
- jsonObject.put("disk", getHardDisk());
- DefaultSystemLog.getLog().info("Mac OS monitor data: {}", jsonObject.toJSONString());
- return jsonObject;
- }
-
- /**
- * 返回内存占比信息
- * 这里返回的数据跟 Mac OS 自带活动监视器显示的内存压力不是同一种东西
- * 内存使用占比高,不代表内存压力就大
- *
- * @param info
- * @return 已使用的 / 总内存 * 100%
- */
- private String getLinuxMemory(final String info) {
- if (StrUtil.isEmpty(info)) {
- return null;
- }
- double used = 0, free = 0;
- DefaultSystemLog.getLog().debug("Mac Os mem info: {}", info);
- int index = info.indexOf(":") + 1;
- String[] split = info.substring(index).split(",");
- for (String str : split) {
- str = str.trim();
- if (str.contains("unused.")) {
- String value = str.split("\\s+")[0].replace("M", "");
- free = Convert.toDouble(value, 0.0);
- } else if (str.contains("used")) {
- String value = str.split("\\s+")[0].replace("M", "");
- used = Convert.toDouble(value, 0.0);
- }
- }
- DefaultSystemLog.getLog().debug("Mac OS mem: used: {}, unused: {}", used, free);
- return String.format("%.2f", used / (used + free) * 100);
- }
-
- /**
- * 返回 Mac OS cpu 占用信息
- *
- * @param info
- * @return 100 - idle (100 - 空闲的 cpu)
- */
- private String getLinuxCpu(final String info) {
- if (StrUtil.isEmpty(info)) {
- return null;
- }
- DefaultSystemLog.getLog().debug("Mac Os cpu info: {}", info);
- int i = info.indexOf(":");
- String[] split = info.substring(i + 1).split(",");
- for (String str : split) {
- str = str.trim();
- if (str.contains("idle")) {
- String value = str.split("\\s+")[0].replace("%", "");
- double val = Convert.toDouble(value, 0.0);
- return String.format("%.2f", 100.00 - val);
- }
- }
- return "0";
- }
-
- @Override
- public List getProcessList() {
- String s = CommandUtil.execSystemCommand("top -l 1 | grep java");
- return formatLinuxTop(s, false);
- }
-
- @Override
- public String emptyLogFile(File file) {
- return CommandUtil.execSystemCommand("cp /dev/null " + file.getAbsolutePath());
- }
-
- /**
- * 把 top 返回的数据组装成集合
- *
- * @param top
- * @param header 是否有 header
- * @return
- */
- private List formatLinuxTop(final String top, final boolean header) {
- List list = StrSplitter.splitTrim(top, StrUtil.LF, true);
- if (list.size() <= 0) {
- return null;
- }
- List list1 = new ArrayList<>();
- ProcessModel processModel;
- for (String item : list) {
- processModel = new ProcessModel();
- DefaultSystemLog.getLog().debug("process item: {}", item);
- List values = StrSplitter.splitTrim(item, StrUtil.SPACE, true);
- DefaultSystemLog.getLog().debug(JSON.toJSONString(values));
- processModel.setPid(Convert.toInt(values.get(0),0));
- processModel.setPort(values.get(6));
- processModel.setCommand(values.get(1));
- processModel.setCpu(values.get(2) + "%");
- processModel.setMem(values.get(14) + "%");
- processModel.setStatus(formStatus(values.get(12)));
- processModel.setTime(values.get(3));
- processModel.setRes(values.get(7));
- processModel.setUser(values.get(29));
- list1.add(processModel);
- }
- return list1;
- }
-
- private String formStatus(final String val) {
- String tempVal = val.toUpperCase();
- String value = "未知";
- if (tempVal.startsWith("S")) {
- value = "睡眠";
- } else if (tempVal.startsWith("R")) {
- value = "运行";
- } else if (tempVal.startsWith("T")) {
- value = "跟踪/停止";
- } else if (tempVal.startsWith("Z")) {
- value = "僵尸进程 ";
- } else if (tempVal.startsWith("D")) {
- value = "不可中断的睡眠状态 ";
- } else if (tempVal.startsWith("I")) {
- value = "多线程 ";
- }
- return value;
- }
-
- @Override
- public ProcessModel getPidInfo(int pid) {
- String command = "top -l 1 | grep " + pid;
- String internal = CommandUtil.execSystemCommand(command);
- List processModels = formatLinuxTop(internal, true);
- if (processModels == null || processModels.isEmpty()) {
- return null;
- }
- return processModels.get(0);
- }
-
- @Override
- public boolean getServiceStatus(String serviceName) {
- if (StrUtil.startWith(serviceName, StrUtil.SLASH)) {
- String ps = getPs(serviceName);
- return StrUtil.isNotEmpty(ps);
- }
- /**
- * Mac OS 里面查询服务的命令是 launchctl list | grep serverName
- * 第一个数字是进程的 PID,如果进程正在运行,如果它不在运行,则显示 "-"
- * 第二个数字是进程的退出代码(如果已完成)。如果为负,则为终止信号的数量
- * 第三列进程名称
- */
- String format = StrUtil.format("service {} status", serviceName);
- String result = CommandUtil.execSystemCommand(format);
- return StrUtil.containsIgnoreCase(result, "RUNNING");
- }
-
- private String getPs(final String serviceName) {
- String ps = StrUtil.format(" ps -ef |grep -w {} | grep -v grep", serviceName);
- return CommandUtil.execSystemCommand(ps);
- }
-
- @Override
- public String startService(String serviceName) {
- if (StrUtil.startWith(serviceName, StrUtil.SLASH)) {
- try {
- CommandUtil.asyncExeLocalCommand(new File(SystemUtil.getUserInfo().getHomeDir()), serviceName);
- return "ok";
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("执行异常", e);
- return "执行异常:" + e.getMessage();
- }
- }
- /**
- * Mac OS 里面启动服务命令是 launchctl start serverName
- */
- String format = StrUtil.format("service {} start", serviceName);
- return CommandUtil.execSystemCommand(format);
- }
-
- @Override
- public String stopService(String serviceName) {
- if (StrUtil.startWith(serviceName, StrUtil.SLASH)) {
- String ps = getPs(serviceName);
- List list = StrUtil.splitTrim(ps, StrUtil.LF);
- if (list == null || list.isEmpty()) {
- return "stop";
- }
- String s = list.get(0);
- list = StrUtil.splitTrim(s, StrUtil.SPACE);
- if (list == null || list.size() < 2) {
- return "stop";
- }
- File file = new File(SystemUtil.getUserInfo().getHomeDir());
- int pid = Convert.toInt(list.get(1), 0);
- if (pid <= 0) {
- return "error stop";
- }
- return kill(file, pid);
- }
- /**
- * Mac OS 里面启动服务命令是 launchctl stop serverName
- */
- String format = StrUtil.format("service {} stop", serviceName);
- return CommandUtil.execSystemCommand(format);
- }
-
- @Override
- public String buildKill(int pid) {
- return String.format("kill %s", pid);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/impl/WindowsProjectCommander.java b/modules/agent/src/main/java/io/jpom/common/commander/impl/WindowsProjectCommander.java
deleted file mode 100644
index e0d253764d..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/impl/WindowsProjectCommander.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander.impl;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.text.StrSplitter;
-import cn.hutool.core.util.StrUtil;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.common.commander.AbstractSystemCommander;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.model.system.NetstatModel;
-import io.jpom.util.CommandUtil;
-import io.jpom.util.JvmUtil;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * windows 版
- *
- * @author Administrator
- */
-public class WindowsProjectCommander extends AbstractProjectCommander {
-
- @Override
- public String buildCommand(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) {
- String classPath = NodeProjectInfoModel.getClassPathLib(nodeProjectInfoModel);
- if (StrUtil.isBlank(classPath)) {
- return null;
- }
- // 拼接命令
- String jvm = javaCopyItem == null ? nodeProjectInfoModel.getJvm() : javaCopyItem.getJvm();
- String tag = javaCopyItem == null ? nodeProjectInfoModel.getId() : javaCopyItem.getTagId();
- String mainClass = nodeProjectInfoModel.getMainClass();
- String args = javaCopyItem == null ? nodeProjectInfoModel.getArgs() : javaCopyItem.getArgs();
- return String.format("%s %s %s " +
- "%s %s %s >> %s &",
- getRunJavaPath(nodeProjectInfoModel, true),
- jvm, JvmUtil.getJpomPidTag(tag, nodeProjectInfoModel.allLib()),
- classPath, mainClass, args, nodeProjectInfoModel.getAbsoluteLog(javaCopyItem));
- }
-
- @Override
- public String stop(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) throws Exception {
- String result = super.stop(nodeProjectInfoModel, javaCopyItem);
- String tag = javaCopyItem == null ? nodeProjectInfoModel.getId() : javaCopyItem.getTagId();
- // 查询状态,如果正在运行,则执行杀进程命令
- int pid = parsePid(result);
- if (pid > 0) {
- String kill = AbstractSystemCommander.getInstance().kill(FileUtil.file(nodeProjectInfoModel.allLib()), pid);
- loopCheckRun(nodeProjectInfoModel.getId(), false);
- result = status(tag) + StrUtil.SPACE + kill;
- }
- return result;
- }
-
- @Override
- public List listNetstat(int pId, boolean listening) {
- String cmd;
- if (listening) {
- cmd = "netstat -nao -p tcp | findstr \"LISTENING\" | findstr " + pId;
- } else {
- cmd = "netstat -nao -p tcp | findstr /V \"CLOSE_WAIT\" | findstr " + pId;
- }
- String result = CommandUtil.execSystemCommand(cmd);
- List netList = StrSplitter.splitTrim(result, StrUtil.LF, true);
- if (netList == null || netList.size() <= 0) {
- return null;
- }
- List array = new ArrayList<>();
- for (String str : netList) {
- List list = StrSplitter.splitTrim(str, " ", true);
- if (list.size() < 5) {
- continue;
- }
- NetstatModel netstatModel = new NetstatModel();
- netstatModel.setProtocol(list.get(0));
- netstatModel.setLocal(list.get(1));
- netstatModel.setForeign(list.get(2));
- netstatModel.setStatus(list.get(3));
- netstatModel.setName(list.get(4));
- array.add(netstatModel);
- }
- return array;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/impl/WindowsSystemCommander.java b/modules/agent/src/main/java/io/jpom/common/commander/impl/WindowsSystemCommander.java
deleted file mode 100644
index 60e7a699f2..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/impl/WindowsSystemCommander.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander.impl;
-
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.text.StrSplitter;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.cron.CronUtil;
-import cn.hutool.cron.Scheduler;
-import cn.hutool.cron.task.Task;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import com.alibaba.fastjson.JSONObject;
-import com.sun.management.OperatingSystemMXBean;
-import io.jpom.common.commander.AbstractSystemCommander;
-import io.jpom.model.system.ProcessModel;
-import io.jpom.util.CommandUtil;
-
-import java.io.File;
-import java.lang.management.ManagementFactory;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * windows 系统查询命令
- *
- * @author jiangzeyin
- * @date 2019/4/16
- */
-public class WindowsSystemCommander extends AbstractSystemCommander {
-
- private static String lastResult;
-
- private static final String ID = "windows_system_process_list";
-
- /**
- * 获取windows 监控
- * https://docs.oracle.com/javase/7/docs/jre/api/management/extension/com/sun/management/OperatingSystemMXBean.html
- *
- * @return 返回cpu占比和内存占比
- */
- @Override
- public JSONObject getAllMonitor() {
- OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
- JSONObject jsonObject = new JSONObject();
- double total = operatingSystemMXBean.getTotalPhysicalMemorySize();
- double free = operatingSystemMXBean.getFreePhysicalMemorySize();
- jsonObject.put("memory", String.format("%.2f", (total - free) / total * 100));
- //最近系统cpu使用量
- double systemCpuLoad = operatingSystemMXBean.getSystemCpuLoad();
- if (systemCpuLoad <= 0) {
- systemCpuLoad = 0;
- }
- jsonObject.put("cpu", String.format("%.2f", systemCpuLoad * 100));
- jsonObject.put("disk", getHardDisk());
- return jsonObject;
- }
-
- @Override
- public List getProcessList() {
- Scheduler scheduler = CronUtil.getScheduler();
- Task task = scheduler.getTask(ID);
- if (task == null) {
- CronUtil.schedule(ID, "0 0/1 * * * ?", () -> {
- try {
- lastResult = CommandUtil.execSystemCommand("tasklist /V | findstr java");
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("执行控制台进程统计错误", e);
- }
- });
- }
- if (lastResult == null) {
- // 返回上一次结果
- lastResult = CommandUtil.execSystemCommand("tasklist /V | findstr java");
- }
- return formatWindowsProcess(lastResult, false);
- }
-
- @Override
- public ProcessModel getPidInfo(int pid) {
- String command = "tasklist /V /FI \"pid eq " + pid + "\"";
- String result = CommandUtil.execSystemCommand(command);
- List array = formatWindowsProcess(result, true);
- if (array == null || array.isEmpty()) {
- return null;
- }
- return array.get(0);
- }
-
- @Override
- public String emptyLogFile(File file) {
- return CommandUtil.execSystemCommand("echo \"\" > " + file.getAbsolutePath());
- }
-
- /**
- * 将windows的tasklist转为集合
- *
- * @param header 是否包含投信息
- * @param result 进程信息
- * @return jsonArray
- */
- private static List formatWindowsProcess(String result, boolean header) {
- List list = StrSplitter.splitTrim(result, StrUtil.LF, true);
- if (list.isEmpty()) {
- return null;
- }
- List processModels = new ArrayList<>();
- for (int i = header ? 2 : 0, len = list.size(); i < len; i++) {
- String param = list.get(i);
- List memList = StrSplitter.splitTrim(param, StrUtil.SPACE, true);
- ProcessModel processModel = new ProcessModel();
- int pid = Convert.toInt(memList.get(1), 0);
- processModel.setPid(pid);
- //
- String name = memList.get(0);
- processModel.setCommand(name);
- //使用内存 kb
- String mem = memList.get(4).replace(",", "");
- long aLong = Convert.toLong(mem, 0L);
-// FileUtil.readableFileSize()
- processModel.setRes(aLong / 1024 + " MB");
- String status = memList.get(6);
- processModel.setStatus(formatStatus(status));
- //
- processModel.setUser(memList.get(7));
- processModel.setTime(memList.get(8));
-
- try {
-// JvmUtil.getOperatingSystemMXBean(memList.get(1), operatingSystemMXBean -> {
-// if (operatingSystemMXBean != null) {
-// //最近jvm cpu使用率
-// double processCpuLoad = operatingSystemMXBean.getProcessCpuLoad() * 100;
-// if (processCpuLoad <= 0) {
-// processCpuLoad = 0;
-// }
-// processModel.setCpu(String.format("%.2f", processCpuLoad) + "%");
-// //服务器总内存
-// long totalMemorySize = operatingSystemMXBean.getTotalPhysicalMemorySize();
-// BigDecimal total = new BigDecimal(totalMemorySize / 1024);
-// // 进程
-// double v = new BigDecimal(aLong).divide(total, 4, BigDecimal.ROUND_HALF_UP).doubleValue() * 100;
-// processModel.setMem(String.format("%.2f", v) + "%");
-// }
-// });
-
- } catch (Exception ignored) {
-
- }
- processModels.add(processModel);
- }
- return processModels;
- }
-
- private static String formatStatus(String status) {
- if ("RUNNING".equalsIgnoreCase(status)) {
- return "运行";
- }
- if ("SUSPENDED".equalsIgnoreCase(status)) {
- return "睡眠";
- }
- if ("NOT RESPONDING".equalsIgnoreCase(status)) {
- return "无响应";
- }
- if ("Unknown".equalsIgnoreCase(status)) {
- return "未知";
- }
- return status;
- }
-
- @Override
- public boolean getServiceStatus(String serviceName) {
- String result = CommandUtil.execSystemCommand("sc query " + serviceName);
- return StrUtil.containsIgnoreCase(result, "RUNNING");
- }
-
- @Override
- public String startService(String serviceName) {
- String format = StrUtil.format("net start {}", serviceName);
- return CommandUtil.execSystemCommand(format);
- }
-
- @Override
- public String stopService(String serviceName) {
- String format = StrUtil.format("net stop {}", serviceName);
- return CommandUtil.execSystemCommand(format);
- }
-
- @Override
- public String buildKill(int pid) {
- return String.format("taskkill /F /PID %s", pid);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/impl/WindowsTomcatCommander.java b/modules/agent/src/main/java/io/jpom/common/commander/impl/WindowsTomcatCommander.java
deleted file mode 100644
index f7ebeee4d7..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/impl/WindowsTomcatCommander.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander.impl;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.text.StrSplitter;
-import cn.hutool.core.util.NumberUtil;
-import cn.hutool.core.util.StrUtil;
-import io.jpom.common.commander.AbstractTomcatCommander;
-import io.jpom.model.data.TomcatInfoModel;
-import io.jpom.util.CommandUtil;
-
-import java.util.List;
-
-/**
- * tomcat的Windows管理命令
- *
- * @author LF
- */
-public class WindowsTomcatCommander extends AbstractTomcatCommander {
-
- /**
- * windows下执行tomcat命令
- *
- * @param tomcatInfoModel tomcat信息
- * @param cmd 执行的命令,包括start stop
- * @return 返回tomcat启动结果
- */
- @Override
- public String execCmd(TomcatInfoModel tomcatInfoModel, String cmd) {
- String tomcatPath = tomcatInfoModel.pathAndCheck();
- //截取盘符
- String dcPath = null;
- if (tomcatPath != null && tomcatPath.indexOf(StrUtil.SLASH) > 1) {
- dcPath = tomcatPath.substring(0, tomcatPath.indexOf(StrUtil.SLASH));
- }
- String command = null;
- if (StrUtil.isBlank(tomcatPath)) {
- return "tomcat path blank";
- }
-
- if ("stop".equals(cmd)) {
- String setPidCmd = CommandUtil.execSystemCommand("jps -mv");
- List list = StrSplitter.splitTrim(setPidCmd, StrUtil.LF, true);
- for (String item : list) {
- //window下路径格式转换
- String msg = FileUtil.normalize(item + StrUtil.SLASH);
- //判断集合中元素是否包含指定Tomcat路径
- boolean w = msg.contains(tomcatInfoModel.getPath());
- if (w) {
- //截取TomcatPid
- if (msg.indexOf(" ") > 1) {
- String tmPid = msg.substring(0, msg.indexOf(" "));
- //判断截取的PID是否为纯数字
- if (NumberUtil.isInteger(tmPid)) {
- command = String.format("taskkill /F /PID %s", tmPid);
- exec(command, true);
- }
- }
- }
- }
- } else {
- command = String.format("cmd /k %s && cd %s/bin && start startup.bat", dcPath, tomcatPath);
- exec(command, true);
- }
-
- // 查询操作结果并返回
- return getStatus(tomcatInfoModel, cmd);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/impl/package-info.java b/modules/agent/src/main/java/io/jpom/common/commander/impl/package-info.java
deleted file mode 100644
index 838bea1d34..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/impl/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander.impl;
\ No newline at end of file
diff --git a/modules/agent/src/main/java/io/jpom/common/commander/package-info.java b/modules/agent/src/main/java/io/jpom/common/commander/package-info.java
deleted file mode 100644
index 5f5d676fcd..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/commander/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.commander;
\ No newline at end of file
diff --git a/modules/agent/src/main/java/io/jpom/common/interceptor/AuthorizeInterceptor.java b/modules/agent/src/main/java/io/jpom/common/interceptor/AuthorizeInterceptor.java
deleted file mode 100644
index 6a39c807c3..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/interceptor/AuthorizeInterceptor.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.interceptor;
-
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.servlet.ServletUtil;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.common.interceptor.BaseInterceptor;
-import cn.jiangzeyin.common.interceptor.InterceptorPattens;
-import io.jpom.system.AgentAuthorize;
-import io.jpom.system.ConfigBean;
-import org.springframework.http.MediaType;
-import org.springframework.web.method.HandlerMethod;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * 授权拦截
- *
- * @author jiangzeyin
- * @date 2019/4/17
- */
-@InterceptorPattens()
-public class AuthorizeInterceptor extends BaseInterceptor {
-
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- super.preHandle(request, response, handler);
- if (handler instanceof HandlerMethod) {
- HandlerMethod handlerMethod = (HandlerMethod) handler;
- NotAuthorize notAuthorize = handlerMethod.getMethodAnnotation(NotAuthorize.class);
- if (notAuthorize == null) {
- String authorize = ServletUtil.getHeaderIgnoreCase(request, ConfigBean.JPOM_AGENT_AUTHORIZE);
- if (StrUtil.isEmpty(authorize)) {
- this.error(response);
- return false;
- }
- if (!AgentAuthorize.getInstance().checkAuthorize(authorize)) {
- this.error(response);
- return false;
- }
- }
- }
- return true;
- }
-
- private void error(HttpServletResponse response) {
- ServletUtil.write(response, JsonMessage.getString(ConfigBean.AUTHORIZE_ERROR, "授权信息错误"), MediaType.APPLICATION_JSON_VALUE);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/common/interceptor/NotAuthorize.java b/modules/agent/src/main/java/io/jpom/common/interceptor/NotAuthorize.java
deleted file mode 100644
index 88cf4e7b74..0000000000
--- a/modules/agent/src/main/java/io/jpom/common/interceptor/NotAuthorize.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.common.interceptor;
-
-import java.lang.annotation.*;
-
-/**
- * 不需要授权
- *
- * @author jiangzeyin
- * @date 2019/4/17
- */
-@Documented
-@Target(ElementType.METHOD)
-@Inherited
-@Retention(RetentionPolicy.RUNTIME)
-public @interface NotAuthorize {
-}
-
diff --git a/modules/agent/src/main/java/io/jpom/controller/IndexController.java b/modules/agent/src/main/java/io/jpom/controller/IndexController.java
deleted file mode 100644
index 3280bc3dbb..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/IndexController.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.system.SystemUtil;
-import cn.jiangzeyin.common.JsonMessage;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.BaseAgentController;
-import io.jpom.common.JpomManifest;
-import io.jpom.common.RemoteVersion;
-import io.jpom.common.interceptor.NotAuthorize;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.service.WhitelistDirectoryService;
-import io.jpom.service.manage.ProjectInfoService;
-import io.jpom.util.JvmUtil;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-import java.util.List;
-
-/**
- * 首页
- *
- * @author jiangzeyin
- * @date 2019/4/17
- */
-@RestController
-public class IndexController extends BaseAgentController {
- @Resource
- private WhitelistDirectoryService whitelistDirectoryService;
- @Resource
- private ProjectInfoService projectInfoService;
-
- @RequestMapping(value = {"index", "", "index.html", "/"}, produces = MediaType.TEXT_PLAIN_VALUE)
- @NotAuthorize
- public String index() {
- return "Jpom-Agent,Can't access directly,Please configure it to JPOM server";
- }
-
- @RequestMapping(value = "info", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String info() {
- int code;
- if (whitelistDirectoryService.isInstalled()) {
- code = 200;
- } else {
- code = 201;
- }
- JpomManifest instance = JpomManifest.getInstance();
- RemoteVersion remoteVersion = RemoteVersion.cacheInfo();
- //
- JSONObject jsonObject = new JSONObject();
- jsonObject.put("manifest", instance);
- jsonObject.put("remoteVersion", remoteVersion);
- return JsonMessage.getString(code, "", jsonObject);
- }
-
- /**
- * 返回节点项目状态信息
- *
- * @return array
- */
- @RequestMapping(value = "status", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String status() {
- List nodeProjectInfoModels = projectInfoService.list();
- JSONObject jsonObject = new JSONObject();
- jsonObject.put("javaVirtualCount", JvmUtil.getJavaVirtualCount());
- jsonObject.put("osName", JpomManifest.getInstance().getOsName());
- jsonObject.put("jpomVersion", JpomManifest.getInstance().getVersion());
- jsonObject.put("javaVersion", SystemUtil.getJavaRuntimeInfo().getVersion());
- // 获取JVM中内存总大小
- long totalMemory = SystemUtil.getTotalMemory();
- jsonObject.put("totalMemory", FileUtil.readableFileSize(totalMemory));
- //
- long freeMemory = SystemUtil.getFreeMemory();
- jsonObject.put("freeMemory", FileUtil.readableFileSize(freeMemory));
- int count = 0;
- if (nodeProjectInfoModels != null) {
- count = nodeProjectInfoModels.size();
- }
- jsonObject.put("count", count);
- // 运行时间
- jsonObject.put("runTime", JpomManifest.getInstance().getUpTime());
- return JsonMessage.getString(200, "", jsonObject);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/WelcomeController.java b/modules/agent/src/main/java/io/jpom/controller/WelcomeController.java
deleted file mode 100644
index 0033420075..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/WelcomeController.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller;
-
-import cn.hutool.cache.impl.CacheObj;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.controller.base.AbstractController;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.JpomManifest;
-import io.jpom.common.commander.AbstractSystemCommander;
-import io.jpom.model.system.ProcessModel;
-import io.jpom.system.TopManager;
-import io.jpom.util.StringUtil;
-import org.springframework.http.MediaType;
-import org.springframework.util.Assert;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * @author jiangzeyin
- * @date 2019/4/16
- */
-@RestController
-public class WelcomeController extends AbstractController {
-
- @RequestMapping(value = "getDirectTop", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getDirectTop() {
- JSONObject topInfo = AbstractSystemCommander.getInstance().getAllMonitor();
- //
- topInfo.put("time", System.currentTimeMillis());
- return JsonMessage.getString(200, "ok", topInfo);
- }
-
- @RequestMapping(value = "getTop", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getTop(Long millis) {
- Iterator> cacheObjIterator = TopManager.get();
- List series = new ArrayList<>();
- List scale = new ArrayList<>();
- int count = 60;
- int minSize = 12;
- while (cacheObjIterator.hasNext()) {
- CacheObj cacheObj = cacheObjIterator.next();
- String key = cacheObj.getKey();
- scale.add(key);
- JSONObject value = cacheObj.getValue();
- series.add(value);
- }
- //限定数组最大数量
- if (series.size() > count) {
- series = series.subList(series.size() - count, series.size());
- scale = scale.subList(scale.size() - count, scale.size());
- }
- while (scale.size() <= minSize) {
- if (scale.size() == 0) {
- scale.add(DateUtil.formatTime(DateUtil.date()));
- }
- String time = scale.get(scale.size() - 1);
- String newTime = StringUtil.getNextScaleTime(time, millis);
- scale.add(newTime);
- }
- JSONObject object = new JSONObject();
- object.put("scales", scale);
- object.put("series", series);
- return JsonMessage.getString(200, "", object);
- }
-
-
- @RequestMapping(value = "processList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- @ResponseBody
- public String getProcessList() {
- List array = AbstractSystemCommander.getInstance().getProcessList();
- if (array != null && !array.isEmpty()) {
- array.sort(Comparator.comparingInt(ProcessModel::getPid));
- return JsonMessage.getString(200, "", array);
- }
- return JsonMessage.getString(402, "没有获取到进程信息");
- }
-
-
- @RequestMapping(value = "kill.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- @ResponseBody
- public String kill(int pid) {
- long jpomAgentId = JpomManifest.getInstance().getPid();
- Assert.state(StrUtil.equals(StrUtil.toString(jpomAgentId), StrUtil.toString(pid)), "不支持在线关闭 Jpom Agent 进程");
- String result = AbstractSystemCommander.getInstance().kill(null, pid);
- if (StrUtil.isEmpty(result)) {
- result = "成功kill";
- }
- return JsonMessage.getString(200, result);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/manage/JdkListController.java b/modules/agent/src/main/java/io/jpom/controller/manage/JdkListController.java
deleted file mode 100644
index 973e2823bc..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/manage/JdkListController.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.manage;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.IdUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.JsonMessage;
-import io.jpom.common.BaseAgentController;
-import io.jpom.model.data.JdkInfoModel;
-import io.jpom.service.manage.JdkInfoService;
-import io.jpom.util.FileUtils;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-import java.io.File;
-import java.util.List;
-
-/**
- * @author bwcx_jzy
- * @date 2019/11/1
- */
-@RestController
-@RequestMapping(value = "/manage/jdk/")
-public class JdkListController extends BaseAgentController {
-
- @Resource
- private JdkInfoService jdkInfoService;
-
- @RequestMapping(value = "list", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String list() {
- List list = jdkInfoService.list();
- return JsonMessage.getString(200, "", list);
- }
-
- @RequestMapping(value = "update", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String update(JdkInfoModel model) {
- String path = model.getPath();
- if (StrUtil.isEmpty(path)) {
- return JsonMessage.getString(400, "请填写jdk路径");
- }
- String newPath = FileUtil.normalize(path);
- File file = FileUtil.file(newPath);
- //去除bin
- if ("bin".equals(file.getName())) {
- newPath = file.getParentFile().getAbsolutePath();
- }
- if (!FileUtils.isJdkPath(newPath)) {
- return JsonMessage.getString(400, "路径错误,该路径不是jdk路径");
- }
- model.setPath(newPath);
- String id = model.getId();
- String jdkVersion = FileUtils.getJdkVersion(newPath);
- model.setVersion(jdkVersion);
- String name = model.getName();
- if (StrUtil.isEmpty(name)) {
- model.setName(jdkVersion);
- }
- if (StrUtil.isEmpty(id)) {
- model.setId(IdUtil.fastSimpleUUID());
- jdkInfoService.addItem(model);
- return JsonMessage.getString(200, "添加成功");
- }
- jdkInfoService.updateItem(model);
- return JsonMessage.getString(200, "修改成功");
- }
-
- @RequestMapping(value = "delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String delete(String id) {
- if (StrUtil.isEmpty(id)) {
- return JsonMessage.getString(400, "删除失败");
- }
- jdkInfoService.deleteItem(id);
- return JsonMessage.getString(200, "删除成功");
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/manage/ManageEditProjectController.java b/modules/agent/src/main/java/io/jpom/controller/manage/ManageEditProjectController.java
deleted file mode 100644
index a413571cda..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/manage/ManageEditProjectController.java
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.manage;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.lang.RegexPool;
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import io.jpom.JpomApplication;
-import io.jpom.common.BaseAgentController;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.model.RunMode;
-import io.jpom.model.data.JdkInfoModel;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.service.WhitelistDirectoryService;
-import io.jpom.service.manage.JdkInfoService;
-import io.jpom.system.ConfigBean;
-import io.jpom.util.StringUtil;
-import org.springframework.http.MediaType;
-import org.springframework.util.Assert;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.io.File;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 编辑项目
- *
- * @author jiangzeyin
- * @date 2019/4/16
- */
-@RestController
-@RequestMapping(value = "/manage/")
-public class ManageEditProjectController extends BaseAgentController {
-
- private final WhitelistDirectoryService whitelistDirectoryService;
- private final JdkInfoService jdkInfoService;
-
- public ManageEditProjectController(WhitelistDirectoryService whitelistDirectoryService,
- JdkInfoService jdkInfoService) {
- this.whitelistDirectoryService = whitelistDirectoryService;
- this.jdkInfoService = jdkInfoService;
- }
-
- /**
- * 基础检查
- *
- * @param projectInfo 项目实体
- * @param whitelistDirectory 白名单
- * @param previewData 预检查数据
- */
- private void checkParameter(NodeProjectInfoModel projectInfo, String whitelistDirectory, boolean previewData) {
- String id = projectInfo.getId();
- Assert.state(!StrUtil.isEmptyOrUndefined(id), "项目id不能为空");
- Assert.state(StringUtil.isGeneral(id, 2, 20), "项目id 长度范围2-20(英文字母 、数字和下划线)");
- Assert.state(!JpomApplication.SYSTEM_ID.equals(id), "项目id " + JpomApplication.SYSTEM_ID + " 关键词被系统占用");
- // 防止和Jpom冲突
- ConfigBean instance = ConfigBean.getInstance();
- Assert.state(!instance.applicationTag.equalsIgnoreCase(id), "当前项目id已经被Jpom占用");
- // 运行模式
- String runMode = getParameter("runMode");
- RunMode runMode1 = RunMode.ClassPath;
- try {
- runMode1 = RunMode.valueOf(runMode);
- } catch (Exception ignored) {
- }
- projectInfo.setRunMode(runMode1);
- // 监测
- if (runMode1 == RunMode.ClassPath || runMode1 == RunMode.JavaExtDirsCp) {
- Assert.hasText(projectInfo.getMainClass(), "ClassPath、JavaExtDirsCp 模式 MainClass必填");
- } else if (runMode1 == RunMode.Jar || runMode1 == RunMode.JarWar) {
- projectInfo.setMainClass(StrUtil.EMPTY);
- }
- if (runMode1 == RunMode.JavaExtDirsCp) {
- Assert.hasText(projectInfo.getJavaExtDirsCp(), "JavaExtDirsCp 模式 javaExtDirsCp必填");
- }
- // 判断是否为分发添加
- String strOutGivingProject = getParameter("outGivingProject");
- boolean outGivingProject = Boolean.parseBoolean(strOutGivingProject);
-
- projectInfo.setOutGivingProject(outGivingProject);
- if (!previewData) {
- // 不是预检查数据才效验白名单
- if (!whitelistDirectoryService.checkProjectDirectory(whitelistDirectory)) {
- if (outGivingProject) {
- whitelistDirectoryService.addProjectWhiteList(whitelistDirectory);
- } else {
- throw new IllegalArgumentException("请选择正确的项目路径,或者还没有配置白名单");
- }
- }
- String logPath = projectInfo.getLogPath();
- if (StrUtil.isNotEmpty(logPath)) {
- if (!whitelistDirectoryService.checkProjectDirectory(logPath)) {
- if (outGivingProject) {
- whitelistDirectoryService.addProjectWhiteList(logPath);
- } else {
- throw new IllegalArgumentException("请填写的项目日志存储路径,或者还没有配置白名单");
- }
- }
- }
- }
- //
- String lib = projectInfo.getLib();
- Assert.state(StrUtil.isNotEmpty(lib) && !StrUtil.SLASH.equals(lib) && !Validator.isChinese(lib), "项目Jar路径不能为空,不能为顶级目录,不能包含中文");
-
- Assert.state(checkPathSafe(lib), "项目Jar路径存在提升目录问题");
-
- // java 程序副本
- if (runMode1 == RunMode.ClassPath || runMode1 == RunMode.Jar || runMode1 == RunMode.JarWar || runMode1 == RunMode.JavaExtDirsCp) {
- String javaCopyIds = getParameter("javaCopyIds");
- if (StrUtil.isEmpty(javaCopyIds)) {
- projectInfo.setJavaCopyItemList(null);
- } else {
- String[] split = StrUtil.splitToArray(javaCopyIds, StrUtil.COMMA);
- List javaCopyItemList = new ArrayList<>(split.length);
- for (String copyId : split) {
- String jvm = getParameter("jvm_" + copyId);
- String args = getParameter("args_" + copyId);
- //
- NodeProjectInfoModel.JavaCopyItem javaCopyItem = new NodeProjectInfoModel.JavaCopyItem();
- javaCopyItem.setId(copyId);
- javaCopyItem.setParendId(id);
- javaCopyItem.setModifyTime(DateUtil.now());
- javaCopyItem.setJvm(StrUtil.emptyToDefault(jvm, StrUtil.EMPTY));
- javaCopyItem.setArgs(StrUtil.emptyToDefault(args, StrUtil.EMPTY));
- javaCopyItemList.add(javaCopyItem);
- }
- projectInfo.setJavaCopyItemList(javaCopyItemList);
- }
- } else {
- projectInfo.setJavaCopyItemList(null);
- }
- }
-
-
- @RequestMapping(value = "saveProject", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String saveProject(NodeProjectInfoModel projectInfo) {
- // 预检查数据
- String strPreviewData = getParameter("previewData");
- boolean previewData = Convert.toBool(strPreviewData, false);
- String whitelistDirectory = projectInfo.getWhitelistDirectory();
- //
- this.checkParameter(projectInfo, whitelistDirectory, previewData);
-
- String id = projectInfo.getId();
- //
- String allLib = projectInfo.allLib();
- // 重复lib
- List list = projectInfoService.list();
- if (list != null) {
- for (NodeProjectInfoModel nodeProjectInfoModel : list) {
- if (!nodeProjectInfoModel.getId().equals(id) && nodeProjectInfoModel.allLib().equals(allLib)) {
- return JsonMessage.getString(401, "当前项目Jar路径已经被【" + nodeProjectInfoModel.getName() + "】占用,请检查");
- }
- }
- }
- File checkFile = new File(allLib);
- if (checkFile.exists() && checkFile.isFile()) {
- return JsonMessage.getString(401, "项目Jar路径是一个已经存在的文件");
- }
- // 自动生成log文件
-// String log = new File(allLib).getParent();
-// log = String.format("%s/%s.log", log, id);
-// projectInfo.setLog(FileUtil.normalize(log));
- String log = projectInfo.getLog();
- Assert.hasText(log, "项目log解析读取失败");
- checkFile = new File(log);
- if (checkFile.exists() && checkFile.isDirectory()) {
- return JsonMessage.getString(401, "项目log是一个已经存在的文件夹");
- }
- //
- String token = projectInfo.getToken();
- if (StrUtil.isNotEmpty(token)) {
- Validator.validateMatchRegex(RegexPool.URL_HTTP, token, "WebHooks 地址不合法");
- }
- // 判断空格
- if (id.contains(StrUtil.SPACE) || allLib.contains(StrUtil.SPACE)) {
- return JsonMessage.getString(401, "项目Id、项目Jar不能包含空格");
- }
- String jdkId = projectInfo.getJdkId();
- if (StrUtil.isNotEmpty(jdkId)) {
- JdkInfoModel item = jdkInfoService.getItem(jdkId);
- Assert.notNull(item, "jdk 信息错误");
- }
- return save(projectInfo, previewData);
- }
-
- /**
- * 保存项目
- *
- * @param projectInfo 项目
- * @param previewData 是否是预检查
- * @return 错误信息
- */
- private String save(NodeProjectInfoModel projectInfo, boolean previewData) {
- projectInfo.setWorkspaceId(getWorkspaceId());
- NodeProjectInfoModel exits = projectInfoService.getItem(projectInfo.getId());
- try {
- this.checkPath(projectInfo);
- if (exits == null) {
- // 检查运行中的tag 是否被占用
- Assert.state(!AbstractProjectCommander.getInstance().isRun(projectInfo, null), "当前项目id已经被正在运行的程序占用");
- if (previewData) {
- // 预检查数据
- return JsonMessage.getString(200, "检查通过");
- } else {
- projectInfoService.addItem(projectInfo);
- return JsonMessage.getString(200, "新增成功!");
- }
- }
- if (previewData) {
- // 预检查数据
- return JsonMessage.getString(200, "检查通过");
- } else {
- exits.setLog(projectInfo.getLog());
- exits.setLogPath(projectInfo.getLogPath());
- exits.setName(projectInfo.getName());
-// exits.setGroup(projectInfo.getGroup());
- exits.setAutoStart(projectInfo.getAutoStart());
- exits.setMainClass(projectInfo.getMainClass());
- exits.setLib(projectInfo.getLib());
- exits.setJvm(projectInfo.getJvm());
- exits.setArgs(projectInfo.getArgs());
- exits.setWorkspaceId(this.getWorkspaceId());
- exits.setOutGivingProject(projectInfo.isOutGivingProject());
- exits.setRunMode(projectInfo.getRunMode());
- exits.setWhitelistDirectory(projectInfo.getWhitelistDirectory());
- exits.setToken(projectInfo.getToken());
- exits.setJdkId(projectInfo.getJdkId());
- // 检查是否非法删除副本集
- List javaCopyItemList = exits.getJavaCopyItemList();
- List javaCopyItemList1 = projectInfo.getJavaCopyItemList();
- if (CollUtil.isNotEmpty(javaCopyItemList) && !CollUtil.containsAll(javaCopyItemList1, javaCopyItemList)) {
- // 重写了 equals
- return JsonMessage.getString(405, "修改中不能删除副本集、请到副本集中删除");
- }
- exits.setJavaCopyItemList(javaCopyItemList1);
- exits.setJavaExtDirsCp(projectInfo.getJavaExtDirsCp());
- //
- moveTo(exits, projectInfo);
- projectInfoService.updateItem(exits);
- return JsonMessage.getString(200, "修改成功");
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().error(e.getMessage(), e);
- return JsonMessage.getString(500, "保存数据异常");
- }
- }
-
- private void moveTo(NodeProjectInfoModel old, NodeProjectInfoModel news) {
- // 移动目录
- if (!old.allLib().equals(news.allLib())) {
- File oldLib = new File(old.allLib());
- if (oldLib.exists()) {
- File newsLib = new File(news.allLib());
- FileUtil.move(oldLib, newsLib, true);
- }
- }
- // log
- if (!old.getLog().equals(news.getLog())) {
- File oldLog = new File(old.getLog());
- if (oldLog.exists()) {
- File newsLog = new File(news.getLog());
- FileUtil.move(oldLog, newsLog, true);
- }
- // logBack
- File oldLogBack = old.getLogBack();
- if (oldLogBack.exists()) {
- FileUtil.move(oldLogBack, news.getLogBack(), true);
- }
- }
-
- }
-
- /**
- * 路径存在包含关系
- *
- * @param nodeProjectInfoModel 比较的项目
- */
- private void checkPath(NodeProjectInfoModel nodeProjectInfoModel) {
- List nodeProjectInfoModelList = projectInfoService.list();
- if (nodeProjectInfoModelList == null) {
- return;
- }
- NodeProjectInfoModel nodeProjectInfoModel1 = null;
- for (NodeProjectInfoModel model : nodeProjectInfoModelList) {
- if (!model.getId().equals(nodeProjectInfoModel.getId())) {
- File file1 = new File(model.allLib());
- File file2 = new File(nodeProjectInfoModel.allLib());
- if (FileUtil.pathEquals(file1, file2)) {
- nodeProjectInfoModel1 = model;
- break;
- }
- // 包含关系
- if (FileUtil.isSub(file1, file2) || FileUtil.isSub(file2, file1)) {
- nodeProjectInfoModel1 = model;
- break;
- }
- }
- }
- if (nodeProjectInfoModel1 != null) {
- throw new IllegalArgumentException("项目Jar路径和【" + nodeProjectInfoModel1.getName() + "】项目冲突:" + nodeProjectInfoModel1.allLib());
- }
- }
-
- /**
- * 删除项目
- *
- * @return json
- */
- @RequestMapping(value = "deleteProject", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String deleteProject(String copyId) {
- NodeProjectInfoModel nodeProjectInfoModel = tryGetProjectInfoModel();
- Assert.notNull(nodeProjectInfoModel, "项目不存在");
- try {
- NodeProjectInfoModel.JavaCopyItem copyItem = nodeProjectInfoModel.findCopyItem(copyId);
-
- if (copyItem == null) {
- // 运行判断
- boolean run = AbstractProjectCommander.getInstance().isRun(nodeProjectInfoModel, null);
- Assert.state(!run, "不能删除正在运行的项目");
- projectInfoService.deleteItem(nodeProjectInfoModel.getId());
- } else {
- boolean run = AbstractProjectCommander.getInstance().isRun(nodeProjectInfoModel, copyItem);
- Assert.state(!run, "不能删除正在运行的项目副本");
- boolean removeCopyItem = nodeProjectInfoModel.removeCopyItem(copyId);
- Assert.state(removeCopyItem, "删除对应副本集不存在");
- projectInfoService.updateItem(nodeProjectInfoModel);
- }
- return JsonMessage.getString(200, "删除成功!");
- } catch (Exception e) {
- DefaultSystemLog.getLog().error(e.getMessage(), e);
- return JsonMessage.getString(500, "删除异常:" + e.getMessage());
- }
- }
-
- @RequestMapping(value = "releaseOutGiving", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String releaseOutGiving() {
- NodeProjectInfoModel nodeProjectInfoModel = tryGetProjectInfoModel();
- if (nodeProjectInfoModel != null) {
- nodeProjectInfoModel.setOutGivingProject(false);
- projectInfoService.updateItem(nodeProjectInfoModel);
- }
- return JsonMessage.getString(200, "ok");
- }
-
- /**
- * 检查项目lib 情况
- *
- * @param id 项目id
- * @param newLib 新路径
- * @return 状态码,400是一定不能操作的,401 是提醒
- */
- @RequestMapping(value = "judge_lib.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String saveProject(String id, String newLib) {
- File file = new File(newLib);
- // 填写的jar路径是一个存在的文件
- Assert.state(!FileUtil.isFile(file), "填写jar目录当前是一个已经存在的文件,请修改");
-
- NodeProjectInfoModel exits = projectInfoService.getItem(id);
- if (exits == null) {
- // 创建项目 填写的jar路径是已经存在的文件夹
- Assert.state(!FileUtil.exist(file), "填写jar目录当前已经在,创建成功后会自动同步文件");
- } else {
- // 已经存在的项目
- File oldLib = new File(exits.allLib());
- Path newPath = file.toPath();
- Path oldPath = oldLib.toPath();
- if (newPath.equals(oldPath)) {
- // 新 旧没有变更
- return JsonMessage.getString(200, "");
- }
- if (file.exists()) {
- String msg;
- if (oldLib.exists()) {
- // 新旧jar路径都存在,会自动覆盖新的jar路径中的文件
- msg = "原jar目录已经存在并且新的jar目录已经存在,保存将覆盖新文件夹并会自动同步原jar目录";
- } else {
- msg = "填写jar目录当前已经在,创建成功后会自动同步文件";
- }
- return JsonMessage.getString(401, msg);
- }
- }
- Assert.state(!Validator.isChinese(newLib), "不建议使用中文目录");
-
- return JsonMessage.getString(200, "");
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/manage/ProjectFileControl.java b/modules/agent/src/main/java/io/jpom/controller/manage/ProjectFileControl.java
deleted file mode 100644
index e65fe4868b..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/manage/ProjectFileControl.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.manage;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.thread.ThreadUtil;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.BooleanUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.servlet.ServletUtil;
-import cn.hutool.http.HttpUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.controller.multipart.MultipartFileBuilder;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.BaseAgentController;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.model.AfterOpt;
-import io.jpom.model.BaseEnum;
-import io.jpom.model.data.AgentWhitelist;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.service.WhitelistDirectoryService;
-import io.jpom.service.manage.ConsoleService;
-import io.jpom.socket.ConsoleCommandOp;
-import io.jpom.system.AgentConfigBean;
-import io.jpom.util.CompressionFileUtil;
-import io.jpom.util.FileUtils;
-import io.jpom.util.StringUtil;
-import org.springframework.http.MediaType;
-import org.springframework.util.Assert;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-import java.io.File;
-import java.nio.charset.Charset;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-/**
- * 项目文件管理
- *
- * @author jiangzeyin
- * @date 2019/4/17
- */
-@RestController
-@RequestMapping(value = "/manage/file/")
-public class ProjectFileControl extends BaseAgentController {
-
- @Resource
- private ConsoleService consoleService;
-
- @Resource
- private WhitelistDirectoryService whitelistDirectoryService;
-
- @RequestMapping(value = "getFileList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getFileList(String id, String path) {
- // 查询项目路径
- NodeProjectInfoModel pim = projectInfoService.getItem(id);
- Assert.notNull(pim, "查询失败:项目不存在");
- String lib = pim.allLib();
- File fileDir = FileUtil.file(lib, StrUtil.emptyToDefault(path, FileUtil.FILE_SEPARATOR));
- boolean exist = FileUtil.exist(fileDir);
- if (!exist) {
- return JsonMessage.getString(200, "查询成功", new JSONArray());
- }
- //
- File[] filesAll = fileDir.listFiles();
- if (ArrayUtil.isEmpty(filesAll)) {
- return JsonMessage.getString(200, "查询成功", new JSONArray());
- }
- JSONArray arrayFile = FileUtils.parseInfo(filesAll, false, lib);
- AgentWhitelist whitelist = whitelistDirectoryService.getWhitelist();
- for (Object o : arrayFile) {
- JSONObject jsonObject = (JSONObject) o;
- String filename = jsonObject.getString("filename");
- jsonObject.put("textFileEdit", AgentWhitelist.checkSilentFileSuffix(whitelist.getAllowEditSuffix(), filename));
- }
-
- return JsonMessage.getString(200, "查询成功", arrayFile);
- }
-
-
- @RequestMapping(value = "upload", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String upload() throws Exception {
- NodeProjectInfoModel pim = getProjectInfoModel();
- MultipartFileBuilder multipartFileBuilder = createMultipart()
- .addFieldName("file");
- // 压缩文件
- String type = getParameter("type");
- // 是否清空
- String clearType = getParameter("clearType");
- String levelName = getParameter("levelName");
- File lib;
- if (StrUtil.isEmpty(levelName)) {
- lib = new File(pim.allLib());
- } else {
- lib = FileUtil.file(pim.allLib(), levelName);
- }
- // 判断是否需要清空
- if ("clear".equalsIgnoreCase(clearType)) {
- if (!FileUtil.clean(lib)) {
- FileUtil.del(lib.toPath());
- //return JsonMessage.getString(500, "清除旧lib失败");
- }
- }
- if ("unzip".equals(type)) {
- multipartFileBuilder.setFileExt(StringUtil.PACKAGE_EXT);
- multipartFileBuilder.setSavePath(AgentConfigBean.getInstance().getTempPathName());
- String path = multipartFileBuilder.save();
- // 解压
- File file = new File(path);
- try {
- CompressionFileUtil.unCompress(file, lib);
- } finally {
- if (!FileUtil.del(file)) {
- DefaultSystemLog.getLog().error("删除文件失败:" + file.getPath());
- }
- }
- } else {
- multipartFileBuilder.setSavePath(FileUtil.getAbsolutePath(lib))
- .setUseOriginalFilename(true);
- // 保存
- multipartFileBuilder.save();
- }
- // 修改使用状态
- pim.setUseLibDesc("upload");
- projectInfoService.updateItem(pim);
- //
- String after = getParameter("after");
- if (StrUtil.isNotEmpty(after)) {
- //
- List javaCopyItemList = pim.getJavaCopyItemList();
- //
- AfterOpt afterOpt = BaseEnum.getEnum(AfterOpt.class, Convert.toInt(after, AfterOpt.No.getCode()));
- if ("restart".equalsIgnoreCase(after) || afterOpt == AfterOpt.Restart) {
- String result = consoleService.execCommand(ConsoleCommandOp.restart, pim, null);
- // 自动处理副本集
- if (javaCopyItemList != null) {
- ThreadUtil.execute(() -> javaCopyItemList.forEach(javaCopyItem -> {
- try {
- consoleService.execCommand(ConsoleCommandOp.restart, pim, javaCopyItem);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("重启副本集失败", e);
- }
- }));
- }
- return JsonMessage.getString(200, "上传成功并重启:" + result);
- }
- if (afterOpt == AfterOpt.Order_Restart || afterOpt == AfterOpt.Order_Must_Restart) {
- boolean restart = this.restart(pim, null, afterOpt);
- if (javaCopyItemList != null) {
- ThreadUtil.execute(() -> {
- // 副本
- for (NodeProjectInfoModel.JavaCopyItem javaCopyItem : javaCopyItemList) {
- if (!this.restart(pim, javaCopyItem, afterOpt)) {
- return;
- }
- // 休眠30秒 等待之前项目正常启动
- try {
- TimeUnit.SECONDS.sleep(30);
- } catch (InterruptedException ignored) {
- }
- }
- });
- }
- }
- }
- return JsonMessage.getString(200, "上传成功");
- }
-
-
- private boolean restart(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem, AfterOpt afterOpt) {
- try {
- String result = consoleService.execCommand(ConsoleCommandOp.restart, nodeProjectInfoModel, javaCopyItem);
- int pid = AbstractProjectCommander.parsePid(result);
- if (pid <= 0) {
- // 完整重启,不再继续剩余的节点项目
- return afterOpt != AfterOpt.Order_Must_Restart;
- }
- return true;
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("重复失败", e);
- // 完整重启,不再继续剩余的节点项目
- return afterOpt != AfterOpt.Order_Must_Restart;
- }
- }
-
- @RequestMapping(value = "deleteFile", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String deleteFile(String filename, String type, String levelName) {
- NodeProjectInfoModel pim = getProjectInfoModel();
- if ("clear".equalsIgnoreCase(type)) {
- // 清空文件
- File file = new File(pim.allLib());
- if (FileUtil.clean(file)) {
- return JsonMessage.getString(200, "清除成功");
- }
- boolean run = AbstractProjectCommander.getInstance().isRun(pim, null);
- Assert.state(!run, "文件被占用,请先停止项目");
- return JsonMessage.getString(500, "删除失败:" + file.getAbsolutePath());
- } else {
- // 删除文件
- String fileName = pathSafe(filename);
- if (StrUtil.isEmpty(fileName)) {
- return JsonMessage.getString(405, "非法操作");
- }
- File file;
- if (StrUtil.isEmpty(levelName)) {
- file = FileUtil.file(pim.allLib(), fileName);
- } else {
- file = FileUtil.file(pim.allLib(), levelName, fileName);
- }
- if (file.exists()) {
- if (FileUtil.del(file)) {
- return JsonMessage.getString(200, "删除成功");
- }
- } else {
- return JsonMessage.getString(404, "文件不存在");
- }
- return JsonMessage.getString(500, "删除失败");
- }
- }
-
- /**
- * 读取文件内容 (只能处理文本文件)
- *
- * @param filePath 相对项目文件的文件夹
- * @param filename 读取的文件名
- * @return json
- */
- @PostMapping(value = "read_file", produces = MediaType.APPLICATION_JSON_VALUE)
- public String readFile(String filePath, String filename) {
- NodeProjectInfoModel pim = getProjectInfoModel();
- filePath = StrUtil.emptyToDefault(filePath, File.separator);
- // 判断文件后缀
- AgentWhitelist whitelist = whitelistDirectoryService.getWhitelist();
- Charset charset = AgentWhitelist.checkFileSuffix(whitelist.getAllowEditSuffix(), filename);
- File file = FileUtil.file(pim.allLib(), filePath, filename);
- String ymlString = FileUtil.readString(file, charset);
- return JsonMessage.getString(200, "", ymlString);
- }
-
- /**
- * 保存文件内容 (只能处理文本文件)
- *
- * @param filePath 相对项目文件的文件夹
- * @param filename 读取的文件名
- * @param fileText 文件内容
- * @return json
- */
- @PostMapping(value = "update_config_file", produces = MediaType.APPLICATION_JSON_VALUE)
- public String updateConfigFile(String filePath, String filename, String fileText) {
- NodeProjectInfoModel pim = getProjectInfoModel();
- filePath = StrUtil.emptyToDefault(filePath, File.separator);
- // 判断文件后缀
- AgentWhitelist whitelist = whitelistDirectoryService.getWhitelist();
- Charset charset = AgentWhitelist.checkFileSuffix(whitelist.getAllowEditSuffix(), filename);
- FileUtil.writeString(fileText, FileUtil.file(pim.allLib(), filePath, filename), charset);
- return JsonMessage.getString(200, "文件写入成功");
- }
-
-
- /**
- * 将执行文件下载到客户端 本地
- *
- * @param id 项目id
- * @param filename 文件名
- * @param levelName 文件夹名
- * @return 正常情况返回文件流,非正在返回 text plan
- */
- @GetMapping(value = "download", produces = MediaType.APPLICATION_JSON_VALUE)
- public String download(String id, String filename, String levelName) {
- String safeFileName = pathSafe(filename);
- if (StrUtil.isEmpty(safeFileName)) {
- return JsonMessage.getString(405, "非法操作");
- }
- try {
- NodeProjectInfoModel pim = projectInfoService.getItem(id);
- File file = FileUtil.file(pim.allLib(), StrUtil.emptyToDefault(levelName, FileUtil.FILE_SEPARATOR), filename);
- if (file.isDirectory()) {
- return "暂不支持下载文件夹";
- }
- ServletUtil.write(getResponse(), file);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("下载文件异常", e);
- }
- return "下载失败。请刷新页面后重试";
- }
-
- /**
- * 下载远程文件
- *
- * @param id 项目id
- * @param url 远程 url 地址
- * @param levelName 保存的文件夹
- * @param unzip 是否为压缩包、true 将自动解压
- * @return json
- */
- @PostMapping(value = "remote_download", produces = MediaType.APPLICATION_JSON_VALUE)
- public String remoteDownload(String id, String url, String levelName, String unzip) {
- if (StrUtil.isEmpty(url)) {
- return JsonMessage.getString(405, "请输入正确的远程地址");
- }
- AgentWhitelist whitelist = whitelistDirectoryService.getWhitelist();
- Set allowRemoteDownloadHost = whitelist.getAllowRemoteDownloadHost();
- Assert.state(CollUtil.isNotEmpty(allowRemoteDownloadHost), "还没有配置运行的远程地址");
- List collect = allowRemoteDownloadHost.stream().filter(s -> StrUtil.startWith(url, s)).collect(Collectors.toList());
- Assert.state(CollUtil.isNotEmpty(collect), "不允许下载当前地址的文件");
- try {
- NodeProjectInfoModel pim = projectInfoService.getItem(id);
- File file = FileUtil.file(pim.allLib(), StrUtil.emptyToDefault(levelName, FileUtil.FILE_SEPARATOR));
- File downloadFile = HttpUtil.downloadFileFromUrl(url, file);
- if (BooleanUtil.toBoolean(unzip)) {
- // 需要解压文件
- try {
- CompressionFileUtil.unCompress(file, downloadFile);
- } finally {
- if (!FileUtil.del(downloadFile)) {
- DefaultSystemLog.getLog().error("删除文件失败:" + file.getPath());
- }
- }
- }
- return JsonMessage.getString(200, "下载成功文件大小:" + FileUtil.readableFileSize(downloadFile));
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("下载远程文件异常", e);
- return JsonMessage.getString(500, "下载远程文件失败:" + e.getMessage());
- }
- }
-
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/manage/ProjectListController.java b/modules/agent/src/main/java/io/jpom/controller/manage/ProjectListController.java
deleted file mode 100644
index e60bd0fb25..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/manage/ProjectListController.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.manage;
-
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.BaseAgentController;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.model.data.NodeProjectInfoModel;
-import org.springframework.http.MediaType;
-import org.springframework.util.Assert;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.List;
-
-/**
- * 管理的信息获取接口
- *
- * @author jiangzeyin
- * @date 2019/4/16
- */
-@RestController
-@RequestMapping(value = "/manage/")
-public class ProjectListController extends BaseAgentController {
-
- /**
- * 获取项目的信息
- *
- * @param id id
- * @return item
- * @see NodeProjectInfoModel
- */
- @RequestMapping(value = "getProjectItem", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getProjectItem(String id) {
- NodeProjectInfoModel nodeProjectInfoModel = projectInfoService.getItem(id);
- if (nodeProjectInfoModel != null) {
- // 返回实际执行的命令
- String command = AbstractProjectCommander.getInstance().buildCommand(nodeProjectInfoModel, null);
- nodeProjectInfoModel.setRunCommand(command);
- }
- return JsonMessage.getString(200, "", nodeProjectInfoModel);
- }
-
- /**
- * 程序项目信息
- *
- * @return json
- */
- @RequestMapping(value = "getProjectInfo", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getProjectInfo() {
- try {
- // 查询数据
- List nodeProjectInfoModels = projectInfoService.list();
- return JsonMessage.getString(200, "查询成功!", nodeProjectInfoModels);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error(e.getMessage(), e);
- return JsonMessage.getString(500, "查询异常:" + e.getMessage());
- }
- }
-
- /**
- * 展示项目页面
- */
- @RequestMapping(value = "project_copy_list", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String projectCopyList(String id) {
- NodeProjectInfoModel nodeProjectInfoModel = projectInfoService.getItem(id);
- Assert.notNull(nodeProjectInfoModel, "没有对应项目");
-
- List javaCopyItemList = nodeProjectInfoModel.getJavaCopyItemList();
- Assert.notEmpty(javaCopyItemList, "对应项目没有副本集");
- JSONArray array = new JSONArray();
- for (NodeProjectInfoModel.JavaCopyItem javaCopyItem : javaCopyItemList) {
- JSONObject object = javaCopyItem.toJson();
- boolean run = AbstractProjectCommander.getInstance().isRun(nodeProjectInfoModel, javaCopyItem);
- object.put("status", run);
- array.add(object);
- }
- return JsonMessage.getString(200, "", array);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/manage/ProjectRecoverControl.java b/modules/agent/src/main/java/io/jpom/controller/manage/ProjectRecoverControl.java
deleted file mode 100644
index 39abf1491d..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/manage/ProjectRecoverControl.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.manage;
-
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.JsonMessage;
-import io.jpom.common.BaseJpomController;
-import io.jpom.model.data.ProjectRecoverModel;
-import io.jpom.service.manage.ProjectRecoverService;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-import java.io.IOException;
-import java.util.List;
-
-/**
- * 回收站管理
- *
- * @author jiangzeyin
- * @date 2019/4/16
- */
-@RestController
-@RequestMapping(value = "/manage/recover")
-public class ProjectRecoverControl extends BaseJpomController {
- @Resource
- private ProjectRecoverService projectRecoverService;
-
- @RequestMapping(value = "list_data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String projectInfo() {
- List projectInfoModels = projectRecoverService.list();
- return JsonMessage.getString(200, "", projectInfoModels);
- }
-
- @RequestMapping(value = "item_data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String project(String id) throws IOException {
- if (StrUtil.isEmpty(id)) {
- return JsonMessage.getString(400, "项目id错误");
- }
- ProjectRecoverModel item = projectRecoverService.getItem(id);
- return JsonMessage.getString(200, "", item);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/manage/ProjectStatusController.java b/modules/agent/src/main/java/io/jpom/controller/manage/ProjectStatusController.java
deleted file mode 100644
index e9c48cdbe1..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/manage/ProjectStatusController.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.manage;
-
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.common.validator.ValidatorConfig;
-import cn.jiangzeyin.common.validator.ValidatorItem;
-import cn.jiangzeyin.common.validator.ValidatorRule;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.BaseAgentController;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.service.manage.ConsoleService;
-import io.jpom.socket.ConsoleCommandOp;
-import org.springframework.http.MediaType;
-import org.springframework.util.Assert;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.List;
-
-/**
- * 项目文件管理
- *
- * @author jiangzeyin
- * @date 2019/4/17
- */
-@RestController
-@RequestMapping(value = "/manage/")
-public class ProjectStatusController extends BaseAgentController {
-
- private final ConsoleService consoleService;
-
- public ProjectStatusController(ConsoleService consoleService) {
- this.consoleService = consoleService;
- }
-
-
- /**
- * 获取项目的进程id
- *
- * @param id 项目id
- * @return json
- */
- @RequestMapping(value = "getProjectStatus", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getProjectStatus(@ValidatorConfig(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "项目id 不正确")) String id, String getCopy) {
- NodeProjectInfoModel nodeProjectInfoModel = tryGetProjectInfoModel();
- Assert.notNull(nodeProjectInfoModel, "项目id不存在");
- int pid = 0;
- try {
- pid = AbstractProjectCommander.getInstance().getPid(id);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("获取项目pid 失败", e);
- }
- JSONObject jsonObject = new JSONObject();
- jsonObject.put("pId", pid);
- //
- if (StrUtil.isNotEmpty(getCopy)) {
- List javaCopyItemList = nodeProjectInfoModel.getJavaCopyItemList();
- JSONArray copys = new JSONArray();
- if (javaCopyItemList != null) {
- for (NodeProjectInfoModel.JavaCopyItem javaCopyItem : javaCopyItemList) {
- JSONObject jsonObject1 = new JSONObject();
- jsonObject1.put("copyId", javaCopyItem.getId());
- boolean run = AbstractProjectCommander.getInstance().isRun(nodeProjectInfoModel, javaCopyItem);
- jsonObject1.put("status", run);
- copys.add(jsonObject1);
- }
- }
- jsonObject.put("copys", copys);
- }
- return JsonMessage.getString(200, "", jsonObject);
- }
-
- /**
- * 获取项目的运行端口
- *
- * @param ids ids
- * @return obj
- */
- @RequestMapping(value = "getProjectPort", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getProjectPort(String ids) {
- Assert.hasText(ids, "没有要获取的信息");
- JSONArray jsonArray = JSONArray.parseArray(ids);
- JSONObject jsonObject = new JSONObject();
- JSONObject itemObj;
- for (Object object : jsonArray) {
- String item = object.toString();
- int pid;
- try {
- pid = AbstractProjectCommander.getInstance().getPid(item);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("获取端口错误", e);
- continue;
- }
- if (pid <= 0) {
- continue;
- }
- itemObj = new JSONObject();
- String port = AbstractProjectCommander.getInstance().getMainPort(pid);
- itemObj.put("port", port);
- itemObj.put("pid", pid);
- jsonObject.put(item, itemObj);
- }
- return JsonMessage.getString(200, "", jsonObject);
- }
-
-
- /**
- * 获取项目的运行端口
- *
- * @param id 项目id
- * @param copyIds 副本 ids ["aa","ss"]
- * @return obj
- */
- @RequestMapping(value = "getProjectCopyPort", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getProjectPort(String id, String copyIds) {
- if (StrUtil.isEmpty(copyIds) || StrUtil.isEmpty(id)) {
- return JsonMessage.getString(400, "");
- }
- NodeProjectInfoModel nodeProjectInfoModel = getProjectInfoModel();
-
- JSONArray jsonArray = JSONArray.parseArray(copyIds);
- JSONObject jsonObject = new JSONObject();
- JSONObject itemObj;
- for (Object object : jsonArray) {
- String item = object.toString();
- NodeProjectInfoModel.JavaCopyItem copyItem = nodeProjectInfoModel.findCopyItem(item);
- int pid;
- try {
- pid = AbstractProjectCommander.getInstance().getPid(copyItem.getTagId());
- if (pid <= 0) {
- continue;
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("获取端口错误", e);
- continue;
- }
- itemObj = new JSONObject();
- String port = AbstractProjectCommander.getInstance().getMainPort(pid);
- itemObj.put("port", port);
- itemObj.put("pid", pid);
- jsonObject.put(item, itemObj);
- }
- return JsonMessage.getString(200, "", jsonObject);
- }
-
- @RequestMapping(value = "restart", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String restart(@ValidatorConfig(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "项目id 不正确")) String id, String copyId) {
- NodeProjectInfoModel item = projectInfoService.getItem(id);
- Assert.notNull(item, "没有找到对应的项目");
- NodeProjectInfoModel.JavaCopyItem copyItem = item.findCopyItem(copyId);
-
- String result;
- try {
- result = consoleService.execCommand(ConsoleCommandOp.restart, item, copyItem);
- boolean status = AbstractProjectCommander.getInstance().isRun(item, copyItem);
- if (status) {
- return JsonMessage.getString(200, result);
- }
- return JsonMessage.getString(201, "重启项目失败:" + result);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("获取项目pid 失败", e);
- result = "error:" + e.getMessage();
- return JsonMessage.getString(500, "重启项目异常:" + result);
- }
- }
-
-
- @RequestMapping(value = "stop", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String stop(@ValidatorConfig(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "项目id 不正确")) String id, String copyId) {
- NodeProjectInfoModel item = projectInfoService.getItem(id);
- Assert.notNull(item, "没有找到对应的项目");
- NodeProjectInfoModel.JavaCopyItem copyItem = item.findCopyItem(copyId);
-
- String result;
- try {
- result = consoleService.execCommand(ConsoleCommandOp.stop, item, copyItem);
- boolean status = AbstractProjectCommander.getInstance().isRun(item, copyItem);
- if (!status) {
- return JsonMessage.getString(200, result);
- }
- return JsonMessage.getString(201, "关闭项目失败:" + result);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("获取项目pid 失败", e);
- result = "error:" + e.getMessage();
- return JsonMessage.getString(500, "关闭项目异常:" + result);
- }
- }
-
-
- @RequestMapping(value = "start", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String start(@ValidatorConfig(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "项目id 不正确")) String id, String copyId) {
- NodeProjectInfoModel item = projectInfoService.getItem(id);
- Assert.notNull(item, "没有找到对应的项目");
- NodeProjectInfoModel.JavaCopyItem copyItem = item.findCopyItem(copyId);
- String result;
- try {
- result = consoleService.execCommand(ConsoleCommandOp.start, item, copyItem);
- boolean status = AbstractProjectCommander.getInstance().isRun(item, copyItem);
- if (status) {
- return JsonMessage.getString(200, result);
- }
- return JsonMessage.getString(201, "启动项目失败:" + result);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("获取项目pid 失败", e);
- result = "error:" + e.getMessage();
- return JsonMessage.getString(500, "启动项目异常:" + result);
- }
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/manage/log/LogBackController.java b/modules/agent/src/main/java/io/jpom/controller/manage/log/LogBackController.java
deleted file mode 100644
index 2fa8de45e4..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/manage/log/LogBackController.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.manage.log;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.servlet.ServletUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.BaseAgentController;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.util.FileUtils;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.servlet.http.HttpServletResponse;
-import java.io.File;
-
-/**
- * @author jiangzeyin
- * @date 2019/4/17
- */
-@RestController
-@RequestMapping(value = "manage/log")
-public class LogBackController extends BaseAgentController {
-
- @RequestMapping(value = "logSize", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String logSize(String id, String copyId) {
- NodeProjectInfoModel nodeProjectInfoModel = getProjectInfoModel();
- JSONObject jsonObject = new JSONObject();
- //
- NodeProjectInfoModel.JavaCopyItem copyItem = nodeProjectInfoModel.findCopyItem(copyId);
- //获取日志备份路径
- File logBack = copyItem == null ? nodeProjectInfoModel.getLogBack() : nodeProjectInfoModel.getLogBack(copyItem);
- boolean logBackBool = logBack.exists() && logBack.isDirectory();
- jsonObject.put("logBack", logBackBool);
- String info = projectInfoService.getLogSize(nodeProjectInfoModel, copyItem);
- jsonObject.put("logSize", info);
- return JsonMessage.getString(200, "", jsonObject);
- }
-
- @RequestMapping(value = "resetLog", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String resetLog(String copyId) {
- NodeProjectInfoModel pim = getProjectInfoModel();
- NodeProjectInfoModel.JavaCopyItem copyItem = pim.findCopyItem(copyId);
- try {
- String msg = AbstractProjectCommander.getInstance().backLog(pim, copyItem);
- if (msg.contains("ok")) {
- return JsonMessage.getString(200, "重置成功");
- }
- return JsonMessage.getString(201, "重置失败:" + msg);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error(e.getMessage(), e);
- return JsonMessage.getString(500, "重置日志失败");
- }
- }
-
- @RequestMapping(value = "logBack_delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String clear(String name, String copyId) {
- name = pathSafe(name);
- if (StrUtil.isEmpty(name)) {
- return JsonMessage.getString(405, "非法操作:" + name);
- }
- NodeProjectInfoModel pim = getProjectInfoModel();
- NodeProjectInfoModel.JavaCopyItem copyItem = pim.findCopyItem(copyId);
- File logBack = copyItem == null ? pim.getLogBack() : pim.getLogBack(copyItem);
- if (logBack.exists() && logBack.isDirectory()) {
- logBack = FileUtil.file(logBack, name);
- if (logBack.exists()) {
- FileUtil.del(logBack);
- return JsonMessage.getString(200, "删除成功");
- }
- return JsonMessage.getString(500, "没有对应文件");
- } else {
- return JsonMessage.getString(500, "没有对应文件夹");
- }
- }
-
- @RequestMapping(value = "logBack_download", method = RequestMethod.GET)
- public String download(String key, String copyId) {
- key = pathSafe(key);
- if (StrUtil.isEmpty(key)) {
- return JsonMessage.getString(405, "非法操作");
- }
- try {
- NodeProjectInfoModel pim = getProjectInfoModel();
- NodeProjectInfoModel.JavaCopyItem copyItem = pim.findCopyItem(copyId);
- File logBack = copyItem == null ? pim.getLogBack() : pim.getLogBack(copyItem);
- if (logBack.exists() && logBack.isDirectory()) {
- logBack = FileUtil.file(logBack, key);
- ServletUtil.write(getResponse(), logBack);
- } else {
- return "没有对应文件";
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("下载文件异常", e);
- }
- return "下载失败。请刷新页面后重试";
- }
-
- @RequestMapping(value = "logBack", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String console(String copyId) {
- // 查询项目路径
- NodeProjectInfoModel pim = getProjectInfoModel();
- NodeProjectInfoModel.JavaCopyItem copyItem = pim.findCopyItem(copyId);
- JSONObject jsonObject = new JSONObject();
-
- File logBack = copyItem == null ? pim.getLogBack() : pim.getLogBack(copyItem);
- if (logBack.exists() && logBack.isDirectory()) {
- File[] filesAll = logBack.listFiles();
- if (filesAll != null) {
- JSONArray jsonArray = FileUtils.parseInfo(filesAll, true, null);
- jsonObject.put("array", jsonArray);
- }
- }
- jsonObject.put("id", pim.getId());
- jsonObject.put("logPath", copyItem == null ? pim.getLog() : pim.getLog(copyItem));
- jsonObject.put("logBackPath", logBack.getAbsolutePath());
- return JsonMessage.getString(200, "", jsonObject);
- }
-
- @RequestMapping(value = "export.html", method = RequestMethod.GET)
- @ResponseBody
- public String export(String copyId) {
- NodeProjectInfoModel pim = getProjectInfoModel();
- NodeProjectInfoModel.JavaCopyItem copyItem = pim.findCopyItem(copyId);
- File file = copyItem == null ? new File(pim.getLog()) : pim.getLog(copyItem);
- if (!file.exists()) {
- return JsonMessage.getString(400, "没有日志文件:" + file.getPath());
- }
- HttpServletResponse response = getResponse();
- ServletUtil.write(response, file);
- return JsonMessage.getString(200, "");
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/monitor/InternalController.java b/modules/agent/src/main/java/io/jpom/controller/monitor/InternalController.java
deleted file mode 100644
index bd670052de..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/monitor/InternalController.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.monitor;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.servlet.ServletUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import io.jpom.common.BaseAgentController;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.system.AgentConfigBean;
-import io.jpom.util.CommandUtil;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.servlet.http.HttpServletResponse;
-import java.io.File;
-
-/**
- * 内存查看
- *
- * @author Administrator
- */
-@RestController
-@RequestMapping(value = "/manage/")
-public class InternalController extends BaseAgentController {
-
- /**
- * 获取内存信息
- *
- * @param tag 程序运行标识
- * @return json
- * @throws Exception 异常
- */
- @RequestMapping(value = "internal_data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getInternal(String tag, String copyId) throws Exception {
-// String tagId = ProjectInfoModel.JavaCopyItem.getTagId(tag, copyId);
-// int pid = AbstractProjectCommander.getInstance().getPid(tagId);
-// if (pid <= 0) {
-// return JsonMessage.getString(400, "");
-// }
-// JSONObject jsonObject = new JSONObject();
-// ProcessModel item = AbstractSystemCommander.getInstance().getPidInfo(pid);
-// jsonObject.put("process", item);
-// JSONObject beanMem = getBeanMem(tagId);
-// jsonObject.put("beanMem", beanMem);
-// //获取端口信息
-// List netstatModels = AbstractProjectCommander.getInstance().listNetstat(pid, false);
-// jsonObject.put("netstat", netstatModels);
-// return JsonMessage.getString(200, "", jsonObject);
- return JsonMessage.getString(404, "功能已经下架");
- }
-
- /**
- * 查询监控线程列表
- *
- * @param tag 程序运行标识
- * @return json
- * @throws Exception 异常
- */
- @RequestMapping(value = "threadInfos", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getThreadInfos(String tag, String copyId) throws Exception {
-// int limit = getParameterInt("limit", 10);
-// int page = getParameterInt("page", 1);
-//
-// ThreadMXBean bean = JvmUtil.getThreadMXBean(ProjectInfoModel.JavaCopyItem.getTagId(tag, copyId));
-// if (bean == null) {
-// return JsonMessage.getString(400, "未获取到对应信息");
-// }
-// //启用线程争用监视
-// bean.setThreadContentionMonitoringEnabled(true);
-// ThreadInfo[] threadInfos = bean.dumpAllThreads(false, false);
-// if (threadInfos == null || threadInfos.length <= 0) {
-// return JsonMessage.getString(404, "没有获取到任何线程");
-// }
-//
-// JSONArray array = new JSONArray();
-// int index = PageUtil.getStart(page, limit);
-// int len = limit + index;
-// int length = threadInfos.length;
-// if (len > length) {
-// len = length;
-// }
-// for (int i = index; i < len; i++) {
-// ThreadInfo threadInfo = threadInfos[i];
-// Thread.State threadState = threadInfo.getThreadState();
-// JSONObject object = new JSONObject();
-// object.put("id", threadInfo.getThreadId());
-// object.put("name", threadInfo.getThreadName());
-// object.put("status", threadState);
-// object.put("waitedCount", threadInfo.getWaitedCount());
-// object.put("waitedTime", threadInfo.getWaitedTime());
-// object.put("blockedCount", threadInfo.getBlockedCount());
-// object.put("blockedTime", threadInfo.getBlockedTime());
-// object.put("isInNative", threadInfo.isInNative());
-// object.put("isSuspended", threadInfo.isSuspended());
-// array.add(object);
-// }
-// JSONObject object = new JSONObject();
-// object.put("count", length);
-// object.put("data", array);
-// return JsonMessage.getString(200, "", object);
- return JsonMessage.getString(404, "功能已经下架");
- }
-
-// /**
-// * 获取jvm内存
-// *
-// * @param tag tag
-// * @return JSONObject
-// */
-// private JSONObject getBeanMem(String tag) {
-// try {
-// MemoryMXBean bean = JvmUtil.getMemoryMXBean(tag);
-// if (bean == null) {
-// return null;
-// }
-// JSONObject jsonObject = new JSONObject();
-// jsonObject.put("mount", bean.getObjectPendingFinalizationCount());
-// //堆内存
-// MemoryUsage memory = bean.getHeapMemoryUsage();
-// //非堆内存
-// MemoryUsage nonHeapMemoryUsage = bean.getNonHeapMemoryUsage();
-// long used = memory.getUsed();
-// long max = memory.getMax();
-// //未定义
-// if (-1 == max) {
-// max = memory.getCommitted();
-// }
-// //计算使用内存占最大内存的百分比
-// double v = new BigDecimal(used).divide(new BigDecimal(max), 2, BigDecimal.ROUND_HALF_UP).doubleValue() * 100;
-// jsonObject.put("heapUsed", FileUtil.readableFileSize(used));
-// jsonObject.put("heapProportion", String.format("%.2f", v) + "%");
-// jsonObject.put("heapCommitted", FileUtil.readableFileSize(memory.getCommitted()));
-// long nonUsed = nonHeapMemoryUsage.getUsed();
-// long nonMax = nonHeapMemoryUsage.getMax();
-// long nonCommitted = nonHeapMemoryUsage.getCommitted();
-// if (-1 == nonMax) {
-// nonMax = nonCommitted;
-// }
-// jsonObject.put("nonHeapUsed", FileUtil.readableFileSize(nonUsed));
-// double proportion = new BigDecimal(nonUsed).divide(new BigDecimal(nonMax), 2, BigDecimal.ROUND_HALF_UP).doubleValue() * 100;
-// jsonObject.put("nonHeapProportion", String.format("%.2f", proportion) + "%");
-// jsonObject.put("nonHeapCommitted", FileUtil.readableFileSize(nonCommitted));
-// return jsonObject;
-// } catch (Exception e) {
-// DefaultSystemLog.getLog().error(e.getMessage(), e);
-// }
-// return null;
-// }
-
-
- /**
- * 导出堆栈信息
- *
- * @param tag 程序运行标识
- * @return json
- */
- @RequestMapping(value = "internal_stack", method = RequestMethod.GET)
- @ResponseBody
- public String stack(String tag, String copyId) {
- tag = NodeProjectInfoModel.JavaCopyItem.getTagId(tag, copyId);
- //
- String fileName = AgentConfigBean.getInstance().getTempPathName() + StrUtil.SLASH + tag + "_java_cpu.txt";
- fileName = FileUtil.normalize(fileName);
- try {
- int pid = AbstractProjectCommander.getInstance().getPid(tag);
- if (pid <= 0) {
- return JsonMessage.getString(400, "未运行");
- }
- String command = String.format("jstack -F %s >> %s ", pid, fileName);
- CommandUtil.execSystemCommand(command);
- downLoad(getResponse(), fileName);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error(e.getMessage(), e);
-// getResponse().sendRedirect("internal?tag=" + tag);
- }
- return JsonMessage.getString(200, "");
- }
-
- /**
- * 导出内存信息
- *
- * @param tag 程序运行标识
- * @return json
- */
- @RequestMapping(value = "internal_ram", method = RequestMethod.GET)
- @ResponseBody
- public String ram(String tag, String copyId) {
- tag = NodeProjectInfoModel.JavaCopyItem.getTagId(tag, copyId);
- //
- String fileName = AgentConfigBean.getInstance().getTempPathName() + StrUtil.SLASH + tag + "_java_ram.txt";
- fileName = FileUtil.normalize(fileName);
- try {
- int pid = AbstractProjectCommander.getInstance().getPid(tag);
- if (pid <= 0) {
- return JsonMessage.getString(400, "未运行");
- }
- String command = String.format("jmap -histo:live %s >> %s", pid, fileName);
- CommandUtil.execSystemCommand(command);
- downLoad(getResponse(), fileName);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error(e.getMessage(), e);
-// getResponse().sendRedirect("internal?tag=" + tag);
- }
- return JsonMessage.getString(200, "");
- }
-
- /**
- * 下载文件
- *
- * @param response response
- * @param fileName 文件名字
- */
- private void downLoad(HttpServletResponse response, String fileName) {
- //获取项目根路径
- File file = new File(fileName);
- ServletUtil.write(response, file);
- FileUtil.del(file);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/script/ScriptController.java b/modules/agent/src/main/java/io/jpom/controller/script/ScriptController.java
deleted file mode 100644
index d7bec3fe7a..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/script/ScriptController.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.script;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.IdUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.http.HtmlUtil;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.controller.multipart.MultipartFileBuilder;
-import io.jpom.JpomApplication;
-import io.jpom.common.BaseAgentController;
-import io.jpom.model.data.ScriptModel;
-import io.jpom.service.script.ScriptServer;
-import io.jpom.system.AgentConfigBean;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-import java.io.File;
-import java.io.IOException;
-
-/**
- * 脚本管理
- *
- * @author jiangzeyin
- * @date 2019/4/24
- */
-@RestController
-@RequestMapping(value = "/script")
-public class ScriptController extends BaseAgentController {
- @Resource
- private ScriptServer scriptServer;
-
- @RequestMapping(value = "list.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String list() {
- return JsonMessage.getString(200, "", scriptServer.list());
- }
-
- @RequestMapping(value = "item.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String item(String id) {
- return JsonMessage.getString(200, "", scriptServer.getItem(id));
- }
-
- @RequestMapping(value = "save.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String save(ScriptModel scriptModel, String type) {
- if (scriptModel == null) {
- return JsonMessage.getString(405, "没有数据");
- }
- if (StrUtil.isEmpty(scriptModel.getContext())) {
- return JsonMessage.getString(405, "内容为空");
- }
- //
- scriptModel.setContext(HtmlUtil.unescape(scriptModel.getContext()));
- ScriptModel eModel = scriptServer.getItem(scriptModel.getId());
- if ("add".equalsIgnoreCase(type)) {
- if (eModel != null) {
- return JsonMessage.getString(405, "id已经存在啦");
- }
- scriptModel.setId(IdUtil.fastSimpleUUID());
- File file = scriptModel.getFile(true);
- if (file.exists() || file.isDirectory()) {
- return JsonMessage.getString(405, "当地id路径文件已经存在来,请修改");
- }
- scriptServer.addItem(scriptModel);
- return JsonMessage.getString(200, "添加成功");
- }
- if (eModel == null) {
- return JsonMessage.getString(405, "对应数据不存在");
- }
- eModel.setName(scriptModel.getName());
- eModel.setContext(scriptModel.getContext());
- scriptServer.updateItem(eModel);
- return JsonMessage.getString(200, "修改成功");
- }
-
- @RequestMapping(value = "del.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String del(String id) {
- scriptServer.deleteItem(id);
- return JsonMessage.getString(200, "删除成功");
- }
-
- @RequestMapping(value = "upload.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String upload() throws IOException {
- MultipartFileBuilder multipartFileBuilder = createMultipart()
- .addFieldName("file").setFileExt("bat", "sh");
- multipartFileBuilder.setSavePath(AgentConfigBean.getInstance().getTempPathName());
- multipartFileBuilder.setUseOriginalFilename(true);
- String path = multipartFileBuilder.save();
- File file = FileUtil.file(path);
- String context = FileUtil.readString(path, JpomApplication.getCharset());
- if (StrUtil.isEmpty(context)) {
- return JsonMessage.getString(405, "脚本内容为空");
- }
- String id = file.getName();
- ScriptModel eModel = scriptServer.getItem(id);
- if (eModel != null) {
- return JsonMessage.getString(405, "对应脚本模板已经存在啦");
- }
- eModel = new ScriptModel();
- eModel.setId(id);
- eModel.setName(id);
- eModel.setContext(context);
- file = eModel.getFile(true);
- if (file.exists() || file.isDirectory()) {
- return JsonMessage.getString(405, "当地id路径文件已经存在来,请修改");
- }
- scriptServer.addItem(eModel);
- return JsonMessage.getString(200, "导入成功");
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/system/AgentCacheManageController.java b/modules/agent/src/main/java/io/jpom/controller/system/AgentCacheManageController.java
deleted file mode 100644
index b078987484..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/system/AgentCacheManageController.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.system;
-
-import cn.hutool.core.io.FileUtil;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.common.validator.ValidatorItem;
-import cn.jiangzeyin.common.validator.ValidatorRule;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.BaseAgentController;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.socket.AgentFileTailWatcher;
-import io.jpom.system.ConfigBean;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.io.File;
-
-/**
- * 缓存管理
- *
- * @author bwcx_jzy
- * @date 2019/7/20
- */
-@RestController
-@RequestMapping(value = "system")
-public class AgentCacheManageController extends BaseAgentController {
-
- /**
- * 缓存信息
- *
- * @return json
- */
- @RequestMapping(value = "cache", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String cache() {
- JSONObject jsonObject = new JSONObject();
- //
- File file = ConfigBean.getInstance().getTempPath();
- String fileSize = FileUtil.readableFileSize(FileUtil.size(file));
- jsonObject.put("fileSize", fileSize);
- //
- jsonObject.put("pidName", AbstractProjectCommander.PID_JPOM_NAME.size());
- jsonObject.put("pidPort", AbstractProjectCommander.PID_PORT.size());
-
- int oneLineCount = AgentFileTailWatcher.getOneLineCount();
- jsonObject.put("readFileOnLineCount", oneLineCount);
- //
- return JsonMessage.getString(200, "ok", jsonObject);
- }
-
- /**
- * 清空缓存
- *
- * @param type 缓存类型
- * @return json
- */
- @RequestMapping(value = "clearCache", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String clearCache(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "类型错误") String type) {
- switch (type) {
- case "pidPort":
- AbstractProjectCommander.PID_PORT.clear();
- break;
- case "pidName":
- AbstractProjectCommander.PID_JPOM_NAME.clear();
- break;
- case "fileSize":
- boolean clean = FileUtil.clean(ConfigBean.getInstance().getTempPath());
- if (!clean) {
- return JsonMessage.getString(504, "清空文件缓存失败");
- }
- break;
- default:
- return JsonMessage.getString(405, "没有对应类型:" + type);
-
- }
- return JsonMessage.getString(200, "清空成功");
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/system/CertificateController.java b/modules/agent/src/main/java/io/jpom/controller/system/CertificateController.java
deleted file mode 100644
index 7024ae5006..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/system/CertificateController.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.system;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.core.util.ZipUtil;
-import cn.hutool.extra.servlet.ServletUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.controller.multipart.MultipartFileBuilder;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.BaseAgentController;
-import io.jpom.model.data.CertModel;
-import io.jpom.service.WhitelistDirectoryService;
-import io.jpom.service.system.CertService;
-import io.jpom.system.AgentConfigBean;
-import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-/**
- * 证书管理
- *
- * @author Arno
- */
-@RestController
-@RequestMapping(value = "/system/certificate")
-public class CertificateController extends BaseAgentController {
-
- @Resource
- private CertService certService;
- @Resource
- private WhitelistDirectoryService whitelistDirectoryService;
-
-
- /**
- * 保存证书
- *
- * @return json
- */
- @RequestMapping(value = "/saveCertificate", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String saveCertificate() {
- String data = getParameter("data");
- JSONObject jsonObject = JSONObject.parseObject(data);
- String type = jsonObject.getString("type");
- String id = jsonObject.getString("id");
- try {
- CertModel certModel;
- if ("add".equalsIgnoreCase(type)) {
- if (certService.getItem(id) != null) {
- return JsonMessage.getString(405, "证书id已经存在啦");
- }
- certModel = new CertModel();
- String error = getCertModel(certModel, jsonObject);
- if (error != null) {
- return error;
- }
- if (!hasFile()) {
- return JsonMessage.getString(405, "请选择证书包文件");
- }
- error = getCertFile(certModel, true);
- if (error != null) {
- return error;
- }
- certService.addItem(certModel);
- } else {
- certModel = certService.getItem(id);
- if (certModel == null) {
- return JsonMessage.getString(404, "没有找到对应证书文件");
- }
- String name = jsonObject.getString("name");
- if (StrUtil.isEmpty(name)) {
- return JsonMessage.getString(400, "请填写证书名称");
- }
- certModel.setName(name);
- if (ServletFileUpload.isMultipartContent(getRequest()) && hasFile()) {
- String error = getCertFile(certModel, false);
- if (error != null) {
- return error;
- }
- }
- certService.updateItem(certModel);
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("证书文件", e);
- return JsonMessage.getString(400, "解析证书文件失败:" + e.getMessage());
- }
- return JsonMessage.getString(200, "提交成功");
- }
-
-
- /**
- * 获取证书信息
- *
- * @param certModel 实体
- * @param jsonObject json对象
- * @return 错误消息
- */
- private String getCertModel(CertModel certModel, JSONObject jsonObject) {
- String id = jsonObject.getString("id");
- String path = jsonObject.getString("path");
- String name = jsonObject.getString("name");
- if (StrUtil.isEmpty(id)) {
- return JsonMessage.getString(400, "请填写证书id");
- }
- if (Validator.isChinese(id)) {
- return JsonMessage.getString(400, "证书id不能使用中文");
- }
- if (StrUtil.isEmpty(name)) {
- return JsonMessage.getString(400, "请填写证书名称");
- }
- if (!whitelistDirectoryService.checkCertificateDirectory(path)) {
- return JsonMessage.getString(400, "请选择正确的项目路径,或者还没有配置白名单");
- }
- certModel.setId(id);
- certModel.setWhitePath(path);
- certModel.setName(name);
- return null;
- }
-
- private Object getUpdateFileInfo(CertModel certModel, String certPath) throws IOException {
- String pemPath = null, keyPath = null;
- String path = AgentConfigBean.getInstance().getTempPathName();
- try (ZipFile zipFile = new ZipFile(certPath)) {
- Enumeration extends ZipEntry> zipEntryEnumeration = zipFile.entries();
- while (zipEntryEnumeration.hasMoreElements()) {
- ZipEntry zipEntry = zipEntryEnumeration.nextElement();
- if (zipEntry.isDirectory()) {
- continue;
- }
- String keyName = zipEntry.getName();
- // pem、cer、crt
- if (pemPath == null && (StrUtil.endWith(keyName, ".pem", true) ||
- StrUtil.endWith(keyName, ".cer", true) ||
- StrUtil.endWith(keyName, ".crt", true))) {
- String eNmae = FileUtil.extName(keyName);
- CertModel.Type type = CertModel.Type.valueOf(eNmae.toLowerCase());
- String filePathItem = String.format("%s/%s/%s", path, certModel.getId(), keyName);
- InputStream inputStream = zipFile.getInputStream(zipEntry);
- FileUtil.writeFromStream(inputStream, filePathItem);
- certModel.setType(type);
- pemPath = filePathItem;
- }
- //
- if (keyPath == null && StrUtil.endWith(keyName, ".key", true)) {
- String filePathItem = String.format("%s/%s/%s", path, certModel.getId(), keyName);
- InputStream inputStream = zipFile.getInputStream(zipEntry);
- FileUtil.writeFromStream(inputStream, filePathItem);
- keyPath = filePathItem;
- }
- if (pemPath != null && keyPath != null) {
- break;
- }
- }
- if (pemPath == null || keyPath == null) {
- return JsonMessage.getString(405, "证书包中文件不完整,需要包含key、pem");
- }
- JSONObject jsonObject = CertModel.decodeCert(pemPath, keyPath);
- if (jsonObject == null) {
- return JsonMessage.getString(405, "解析证书失败");
- }
- return jsonObject;
- }
- }
-
- private String getCertFile(CertModel certModel, boolean add) throws IOException {
- String certPath = null;
- try {
- String path = AgentConfigBean.getInstance().getTempPathName();
- MultipartFileBuilder cert = createMultipart().addFieldName("file").setSavePath(path);
- certPath = cert.save();
- Object val = getUpdateFileInfo(certModel, certPath);
- if (val instanceof String) {
- return val.toString();
- }
- JSONObject jsonObject = (JSONObject) val;
- String domain = jsonObject.getString("domain");
- if (add) {
- List array = certService.list();
- if (array != null) {
- for (CertModel certModel1 : array) {
- if (StrUtil.emptyToDefault(domain, "").equals(certModel1.getDomain())) {
- return JsonMessage.getString(405, "证书的域名已经存在啦");
- }
- }
- }
- } else {
- if (!StrUtil.emptyToDefault(domain, "").equals(certModel.getDomain())) {
- return JsonMessage.getString(405, "新证书的域名不一致");
- }
- }
- // 移动位置
- String temporary = certModel.getWhitePath() + StrUtil.SLASH + certModel.getId() + StrUtil.SLASH;
- File pemFile = FileUtil.file(temporary + certModel.getId() + "." + certModel.getType().name());
- File keyFile = FileUtil.file(temporary + certModel.getId() + ".key");
- if (add) {
- if (pemFile.exists()) {
- return JsonMessage.getString(405, pemFile.getAbsolutePath() + " 已经被占用啦");
- }
- if (keyFile.exists()) {
- return JsonMessage.getString(405, keyFile.getAbsolutePath() + " 已经被占用啦");
- }
- }
- String pemPath = jsonObject.getString("pemPath");
- String keyPath = jsonObject.getString("keyPath");
- FileUtil.move(FileUtil.file(pemPath), pemFile, true);
- FileUtil.move(FileUtil.file(keyPath), keyFile, true);
- certModel.setCert(pemFile.getAbsolutePath());
- certModel.setKey(keyFile.getAbsolutePath());
- //
- certModel.setDomain(domain);
- certModel.setExpirationTime(jsonObject.getLongValue("expirationTime"));
- certModel.setEffectiveTime(jsonObject.getLongValue("effectiveTime"));
- } finally {
- if (certPath != null) {
- FileUtil.del(certPath);
- }
- }
- return null;
- }
-
-
- /**
- * 证书列表
- *
- * @return json
- */
- @RequestMapping(value = "/getCertList", produces = MediaType.APPLICATION_JSON_VALUE)
- public String getCertList() {
- List array = certService.list();
- return JsonMessage.getString(200, "", array);
- }
-
- /**
- * 删除证书
- *
- * @param id id
- * @return json
- */
- @RequestMapping(value = "/delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String delete(String id) {
- if (StrUtil.isEmpty(id)) {
- return JsonMessage.getString(400, "删除失败");
- }
- certService.deleteItem(id);
- return JsonMessage.getString(200, "删除成功");
- }
-
-
- /**
- * 导出证书
- *
- * @param id 项目id
- * @return 结果
- */
- @RequestMapping(value = "/export", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
- public String export(String id) {
- CertModel item = certService.getItem(id);
- if (null == item) {
- return JsonMessage.getString(400, "导出失败");
- }
- String parent = FileUtil.file(item.getCert()).getParent();
- File zip = ZipUtil.zip(parent);
- ServletUtil.write(getResponse(), zip);
- FileUtil.del(zip);
- return JsonMessage.getString(400, "导出成功");
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/system/LogManageController.java b/modules/agent/src/main/java/io/jpom/controller/system/LogManageController.java
deleted file mode 100644
index e897746f0a..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/system/LogManageController.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.system;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.extra.servlet.ServletUtil;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.common.spring.SpringUtil;
-import cn.jiangzeyin.common.validator.ValidatorItem;
-import cn.jiangzeyin.common.validator.ValidatorRule;
-import com.alibaba.fastjson.JSONArray;
-import io.jpom.common.BaseAgentController;
-import io.jpom.system.WebAopLog;
-import io.jpom.util.LayuiTreeUtil;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.io.File;
-import java.util.concurrent.TimeUnit;
-
-/**
- * 系统日志管理
- *
- * @author bwcx_jzy
- * @date 2019/7/20
- */
-@RestController
-@RequestMapping(value = "system")
-public class LogManageController extends BaseAgentController {
-
-
- @RequestMapping(value = "log_data.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String logData() {
- WebAopLog webAopLog = SpringUtil.getBean(WebAopLog.class);
- JSONArray data = LayuiTreeUtil.getTreeData(webAopLog.getPropertyValue());
- return JsonMessage.getString(200, "", data);
- }
-
-
- @RequestMapping(value = "log_del.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- @ResponseBody
- public String logData(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "path错误") String path) {
- WebAopLog webAopLog = SpringUtil.getBean(WebAopLog.class);
- File file = FileUtil.file(webAopLog.getPropertyValue(), path);
- // 判断修改时间
- long modified = file.lastModified();
- if (System.currentTimeMillis() - modified < TimeUnit.DAYS.toMillis(1)) {
- return JsonMessage.getString(405, "不能删除当天的日志");
- }
- if (FileUtil.del(file)) {
- return JsonMessage.getString(200, "删除成功");
- }
- return JsonMessage.getString(500, "删除失败");
- }
-
-
- @RequestMapping(value = "log_download", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
- @ResponseBody
- public void logDownload(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "path错误") String path) {
- WebAopLog webAopLog = SpringUtil.getBean(WebAopLog.class);
- File file = FileUtil.file(webAopLog.getPropertyValue(), path);
- if (file.isFile()) {
- ServletUtil.write(getResponse(), file);
- }
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/system/NginxController.java b/modules/agent/src/main/java/io/jpom/controller/system/NginxController.java
deleted file mode 100644
index 6c2da87c3e..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/system/NginxController.java
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.system;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.text.StrSplitter;
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.system.SystemUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.common.validator.ValidatorItem;
-import cn.jiangzeyin.common.validator.ValidatorRule;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.github.odiszapc.nginxparser.NgxBlock;
-import com.github.odiszapc.nginxparser.NgxConfig;
-import com.github.odiszapc.nginxparser.NgxEntry;
-import com.github.odiszapc.nginxparser.NgxParam;
-import io.jpom.common.BaseAgentController;
-import io.jpom.common.commander.AbstractSystemCommander;
-import io.jpom.service.WhitelistDirectoryService;
-import io.jpom.service.system.NginxService;
-import io.jpom.util.CommandUtil;
-import io.jpom.util.StringUtil;
-import org.springframework.http.MediaType;
-import org.springframework.util.Assert;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-
-/**
- * nginx 列表
- *
- * @author jiangzeyin
- * @date 2019/4/17
- */
-@RestController
-@RequestMapping("/system/nginx")
-public class NginxController extends BaseAgentController {
-
- @Resource
- private NginxService nginxService;
- @Resource
- private WhitelistDirectoryService whitelistDirectoryService;
-
- /**
- * 配置列表
- *
- * @return json
- */
- @RequestMapping(value = "list_data.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String list(String whitePath, String name) {
- boolean checkNgxDirectory = whitelistDirectoryService.checkNgxDirectory(whitePath);
- Assert.state(checkNgxDirectory, "文件路径错误,非白名单路径");
- if (StrUtil.isEmpty(name)) {
- name = StrUtil.SLASH;
- }
- String newName = pathSafe(name);
- JSONArray array = nginxService.list(whitePath, newName);
- return JsonMessage.getString(200, "", array);
- }
-
- /**
- * nginx列表
- */
- @RequestMapping(value = "tree.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String tree() {
- JSONArray array = nginxService.tree();
- return JsonMessage.getString(200, "", array);
- }
-
- /**
- * 获取配置文件信息页面
- *
- * @param path 白名单路径
- * @param name 名称
- * @return 页面
- */
- @RequestMapping(value = "item_data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String itemData(String path, String name) {
- boolean ngxDirectory = whitelistDirectoryService.checkNgxDirectory(path);
- Assert.state(ngxDirectory, "文件路径错误,非白名单路径");
-
- File file = FileUtil.file(path, name);
- Assert.state(FileUtil.isFile(file), "对应对配置文件不存在");
- JSONObject jsonObject = new JSONObject();
- String string = FileUtil.readUtf8String(file);
- jsonObject.put("context", string);
- String rName = StringUtil.delStartPath(file, path, true);
- // nginxService.paresName(path, file.getAbsolutePath())
- jsonObject.put("name", rName);
- jsonObject.put("whitePath", path);
- return JsonMessage.getString(200, "", jsonObject);
-// setAttribute("data", jsonObject);
- }
-
- /**
- * 新增或修改配置
- *
- * @param name 文件名
- * @param whitePath 白名单路径
- * @param genre 操作类型
- * @return json
- */
- @RequestMapping(value = "updateNgx", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String updateNgx(String name, String whitePath, String genre, String context) {
- Assert.hasText(name, "请填写文件名");
- Assert.state(name.endsWith(".conf"), "文件后缀必须为\".conf\"");
- //
- boolean ngxDirectory = whitelistDirectoryService.checkNgxDirectory(whitePath);
- Assert.state(ngxDirectory, "请选择正确的白名单");
- //nginx文件
- File file = FileUtil.file(whitePath, name);
- if ("add".equals(genre) && file.exists()) {
- return JsonMessage.getString(400, "该文件已存在");
- }
- //String context = getUnescapeParameter("context");
- if (StrUtil.isEmpty(context)) {
- return JsonMessage.getString(400, "请填写配置信息");
- }
- InputStream inputStream = new ByteArrayInputStream(context.getBytes());
- try {
- NgxConfig conf = NgxConfig.read(inputStream);
- List list = conf.findAll(NgxBlock.class, "server");
- // 取消 nginx 内容必须检测 @jzy 2021-09-11
- // if (list == null || list.size() <= 0) {
- // return JsonMessage.getString(404, "内容解析为空");
- // }
- for (NgxEntry ngxEntry : list) {
- NgxBlock ngxBlock = (NgxBlock) ngxEntry;
- // 检查日志路径
- NgxParam accessLog = ngxBlock.findParam("access_log");
- if (accessLog != null) {
- FileUtil.mkParentDirs(accessLog.getValue());
- }
- accessLog = ngxBlock.findParam("error_log");
- if (accessLog != null) {
- FileUtil.mkParentDirs(accessLog.getValue());
- }
- // 检查证书文件
- NgxParam sslCertificate = ngxBlock.findParam("ssl_certificate");
- if (sslCertificate != null && !FileUtil.exist(sslCertificate.getValue())) {
- return JsonMessage.getString(404, "证书文件ssl_certificate,不存在");
- }
- NgxParam sslCertificateKey = ngxBlock.findParam("ssl_certificate_key");
- if (sslCertificateKey != null && !FileUtil.exist(sslCertificateKey.getValue())) {
- return JsonMessage.getString(404, "证书文件ssl_certificate_key,不存在");
- }
- if (!checkRootRole(ngxBlock)) {
- return JsonMessage.getString(405, "非系统管理员,不能配置静态资源代理");
- }
- }
- } catch (IOException e) {
- DefaultSystemLog.getLog().error("解析失败", e);
- return JsonMessage.getString(500, "解析失败");
- }
- try {
- FileUtil.writeString(context, file, CharsetUtil.UTF_8);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error(e.getMessage(), e);
- return JsonMessage.getString(400, "操作失败:" + e.getMessage());
- }
- String msg = this.reloadNginx();
- return JsonMessage.getString(200, "提交成功" + msg);
- }
-
- private String reloadNginx() {
- String serviceName = nginxService.getServiceName();
- try {
- String format = StrUtil.format("{} -s reload", serviceName);
- String msg = CommandUtil.execSystemCommand(format);
- if (StrUtil.isNotEmpty(msg)) {
- DefaultSystemLog.getLog().info(msg);
- return "(" + msg + ")";
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("reload nginx error", e);
- }
- return StrUtil.EMPTY;
- }
-
- /**
- * 权限检查 防止非系统管理员配置静态资源访问
- *
- * @param ngxBlock 代码片段
- * @return false 不正确
- */
- private boolean checkRootRole(NgxBlock ngxBlock) {
-// UserModel userModel = getUser();
- // List locationAll = ngxBlock.findAll(NgxBlock.class, "location");
- // if (locationAll != null) {
- // for (NgxEntry ngxEntry1 : locationAll) {
- // NgxBlock ngxBlock1 = (NgxBlock) ngxEntry1;
- // NgxParam locationMain = ngxBlock1.findParam("root");
- // if (locationMain == null) {
- // locationMain = ngxBlock1.findParam("alias");
- // }
- //
- // }
- // }
- return true;
- }
-
- /**
- * 删除配置
- *
- * @param path 文件路径
- * @param name 文件名
- * @return json
- */
- @RequestMapping(value = "delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String delete(String path, String name) {
- if (!whitelistDirectoryService.checkNgxDirectory(path)) {
- return JsonMessage.getString(400, "非法操作");
- }
- String safePath = pathSafe(path);
- String safeName = pathSafe(name);
- if (StrUtil.isEmpty(safeName)) {
- return JsonMessage.getString(400, "删除失败,请正常操作");
- }
- File file = FileUtil.file(safePath, safeName);
- try {
- FileUtil.rename(file, file.getName() + "_back", false, true);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("删除nginx", e);
- return JsonMessage.getString(400, "删除失败:" + e.getMessage());
- }
- String msg = this.reloadNginx();
- return JsonMessage.getString(200, "删除成功" + msg);
- }
-
- /**
- * 获取nginx状态
- *
- * @return json
- */
- @RequestMapping(value = "status", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String status() {
- String name = nginxService.getServiceName();
- if (StrUtil.isEmpty(name)) {
- return JsonMessage.getString(500, "服务名错误");
- }
- JSONObject jsonObject = new JSONObject();
- jsonObject.put("name", name);
- boolean serviceStatus = AbstractSystemCommander.getInstance().getServiceStatus(name);
- jsonObject.put("status", serviceStatus);
- return JsonMessage.getString(200, "", jsonObject);
- }
-
- /**
- * 修改nginx配置
- *
- * @param name 服务名
- * @return json
- */
- @RequestMapping(value = "updateConf", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String updateConf(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "服务名称错误") String name) {
- JSONObject ngxConf = nginxService.getNgxConf();
- ngxConf.put("name", name);
- nginxService.save(ngxConf);
- return JsonMessage.getString(200, "修改成功");
- }
-
- /**
- * 获取配置信息
- *
- * @return json
- */
- @RequestMapping(value = "config", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String config() {
- JSONObject ngxConf = nginxService.getNgxConf();
- return JsonMessage.getString(200, "", ngxConf);
- }
-
- /**
- * 启动nginx
- *
- * @return json
- */
- @RequestMapping(value = "open", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String open() {
- String name = nginxService.getServiceName();
- String result = AbstractSystemCommander.getInstance().startService(name);
- return JsonMessage.getString(200, "nginx服务已启动 " + result);
- }
-
- /**
- * 关闭nginx
- *
- * @return json
- */
- @RequestMapping(value = "close", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String close() {
- String name = nginxService.getServiceName();
- String result = AbstractSystemCommander.getInstance().stopService(name);
- return JsonMessage.getString(200, result);
- }
-
- /**
- * 重新加载
- *
- * @return json
- */
- @RequestMapping(value = "reload", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String reload() {
- String name = nginxService.getServiceName();
- String checkResult = StrUtil.EMPTY;
- if (SystemUtil.getOsInfo().isLinux()) {
- checkResult = CommandUtil.execSystemCommand(StrUtil.format("{} -t", name));
- } else if (SystemUtil.getOsInfo().isWindows()) {
- checkResult = CommandUtil.execSystemCommand("sc qc " + name);
- List strings = StrSplitter.splitTrim(checkResult, "\n", true);
- //服务路径
- File file = null;
- for (String str : strings) {
- str = str.toUpperCase().trim();
- if (str.startsWith("BINARY_PATH_NAME")) {
- String path = str.substring(str.indexOf(":") + 1).replace("\"", "").trim();
- file = FileUtil.file(path).getParentFile();
- break;
- }
- }
- checkResult = CommandUtil.execSystemCommand("nginx -t", file);
- }
- if (StrUtil.isNotEmpty(checkResult) && !StrUtil.containsIgnoreCase(checkResult, "successful")) {
- return JsonMessage.getString(400, checkResult);
- }
- String reloadMsg = this.reloadNginx();
- return JsonMessage.getString(200, "重新加载成功:" + reloadMsg, checkResult);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/system/SystemConfigController.java b/modules/agent/src/main/java/io/jpom/controller/system/SystemConfigController.java
deleted file mode 100644
index 938d31489a..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/system/SystemConfigController.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.system;
-
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.thread.ThreadUtil;
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.JpomApplication;
-import io.jpom.common.BaseAgentController;
-import io.jpom.common.Const;
-import io.jpom.common.JpomManifest;
-import io.jpom.system.ExtConfigBean;
-import org.springframework.boot.env.YamlPropertySourceLoader;
-import org.springframework.core.io.ByteArrayResource;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-
-/**
- * 系统配置
- *
- * @author bwcx_jzy
- * @date 2019/08/08
- */
-@RestController
-@RequestMapping(value = "system")
-public class SystemConfigController extends BaseAgentController {
-
- @RequestMapping(value = "getConfig.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String config() throws IOException {
- String content = IoUtil.read(ExtConfigBean.getResource().getInputStream(), CharsetUtil.CHARSET_UTF_8);
- JSONObject json = new JSONObject();
- json.put("content", content);
- return JsonMessage.getString(200, "ok", json);
- }
-
- @RequestMapping(value = "save_config.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String saveConfig(String content, String restart) {
- if (StrUtil.isEmpty(content)) {
- return JsonMessage.getString(405, "内容不能为空");
- }
- try {
- YamlPropertySourceLoader yamlPropertySourceLoader = new YamlPropertySourceLoader();
- // @author hjk 前端编辑器允许使用tab键,并设定为2个空格,再转换为yml时要把tab键换成2个空格
- ByteArrayResource resource = new ByteArrayResource(content.replace("\t", " ").getBytes(StandardCharsets.UTF_8));
- yamlPropertySourceLoader.load("test", resource);
- } catch (Exception e) {
- DefaultSystemLog.getLog().warn("内容格式错误,请检查修正", e);
- return JsonMessage.getString(500, "内容格式错误,请检查修正:" + e.getMessage());
- }
- if (JpomManifest.getInstance().isDebug()) {
- return JsonMessage.getString(405, "调试模式下不支持在线修改,请到resources目录下的bin目录修改extConfig.yml");
- }
- File resourceFile = ExtConfigBean.getResourceFile();
- FileUtil.writeString(content, resourceFile, CharsetUtil.CHARSET_UTF_8);
-
- if (Convert.toBool(restart, false)) {
- // 重启
- ThreadUtil.execute(() -> {
- ThreadUtil.sleep(2000);
- JpomApplication.restart();
- });
- return JsonMessage.getString(200, Const.UPGRADE_MSG);
- }
- return JsonMessage.getString(200, "修改成功");
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/system/SystemUpdateController.java b/modules/agent/src/main/java/io/jpom/controller/system/SystemUpdateController.java
deleted file mode 100644
index 39f359bc69..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/system/SystemUpdateController.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.system;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.io.resource.ResourceUtil;
-import cn.hutool.core.lang.Tuple;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.core.util.URLUtil;
-import cn.hutool.http.HttpStatus;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.controller.multipart.MultipartFileBuilder;
-import io.jpom.JpomApplication;
-import io.jpom.common.*;
-import io.jpom.system.AgentConfigBean;
-import io.jpom.system.ConfigBean;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Objects;
-
-/**
- * 在线升级
- *
- * @author bwcx_jzy
- * @date 2019/7/22
- */
-@RestController
-@RequestMapping(value = "system")
-public class SystemUpdateController extends BaseAgentController {
-
- @PostMapping(value = "uploadJar.json", produces = MediaType.APPLICATION_JSON_VALUE)
- public String uploadJar() throws IOException {
- //
- Objects.requireNonNull(JpomManifest.getScriptFile());
- MultipartFileBuilder multipartFileBuilder = createMultipart();
- String absolutePath = AgentConfigBean.getInstance().getTempPath().getAbsolutePath();
- multipartFileBuilder
- .setFileExt("jar", "zip")
- .addFieldName("file")
- .setUseOriginalFilename(true)
- .setSavePath(absolutePath);
- String path = multipartFileBuilder.save();
- // 解析压缩包
- File file = JpomManifest.zipFileFind(path, Type.Agent, absolutePath);
- path = FileUtil.getAbsolutePath(file);
- // 基础检查
- JsonMessage error = JpomManifest.checkJpomJar(path, Type.Agent);
- if (error.getCode() != HttpStatus.HTTP_OK) {
- return error.toString();
- }
- String version = error.getMsg();
- JpomManifest.releaseJar(path, version);
- //
- JpomApplication.restart();
- return JsonMessage.getString(200, Const.UPGRADE_MSG);
- }
-
- @PostMapping(value = "change_log", produces = MediaType.APPLICATION_JSON_VALUE)
- public String changeLog() {
- //
- URL resource = ResourceUtil.getResource("CHANGELOG.md");
- String log = StrUtil.EMPTY;
- if (resource != null) {
- InputStream stream = URLUtil.getStream(resource);
- log = IoUtil.readUtf8(stream);
- }
- return JsonMessage.getString(200, "", log);
- }
-
- /**
- * 检查是否存在新版本
- *
- * @return json
- * @see RemoteVersion
- */
- @PostMapping(value = "check_version.json", produces = MediaType.APPLICATION_JSON_VALUE)
- public String checkVersion() {
- RemoteVersion remoteVersion = RemoteVersion.loadRemoteInfo();
- return JsonMessage.getString(200, "", remoteVersion);
- }
-
- /**
- * 远程下载升级
- *
- * @return json
- * @see RemoteVersion
- */
- @PostMapping(value = "remote_upgrade.json", produces = MediaType.APPLICATION_JSON_VALUE)
- public String upgrade() throws IOException {
- RemoteVersion.upgrade(ConfigBean.getInstance().getTempPath().getAbsolutePath());
- return JsonMessage.getString(200, Const.UPGRADE_MSG);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/system/WhitelistDirectoryController.java b/modules/agent/src/main/java/io/jpom/controller/system/WhitelistDirectoryController.java
deleted file mode 100644
index 14d97b6317..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/system/WhitelistDirectoryController.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.system;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.lang.RegexPool;
-import cn.hutool.core.text.StrSplitter;
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.ReUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.JsonMessage;
-import io.jpom.common.BaseJpomController;
-import io.jpom.model.data.AgentWhitelist;
-import io.jpom.service.WhitelistDirectoryService;
-import io.jpom.system.AgentExtConfigBean;
-import org.springframework.http.MediaType;
-import org.springframework.util.Assert;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-import java.util.List;
-
-/**
- * @author jiangzeyin
- * @date 2019/4/16
- */
-@RestController
-@RequestMapping(value = "/system")
-public class WhitelistDirectoryController extends BaseJpomController {
-
- @Resource
- private WhitelistDirectoryService whitelistDirectoryService;
-
- @RequestMapping(value = "whitelistDirectory_data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String whiteListDirectoryData() {
- AgentWhitelist agentWhitelist = whitelistDirectoryService.getWhitelist();
- return JsonMessage.getString(200, "", agentWhitelist);
- }
-
-
- @RequestMapping(value = "whitelistDirectory_submit", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String whitelistDirectorySubmit(String project, String certificate, String nginx, String allowEditSuffix, String allowRemoteDownloadHost) {
- if (StrUtil.isEmpty(project)) {
- return JsonMessage.getString(401, "项目路径白名单不能为空");
- }
- List list = AgentWhitelist.parseToList(project, true, "项目路径白名单不能为空");
- //
- List certificateList = AgentWhitelist.parseToList(certificate, "证书路径白名单不能为空");
- List nList = AgentWhitelist.parseToList(nginx, "nginx路径白名单不能为空");
- List allowEditSuffixList = AgentWhitelist.parseToList(allowEditSuffix, "允许编辑的文件后缀不能为空");
- List allowRemoteDownloadHostList = AgentWhitelist.parseToList(allowRemoteDownloadHost, "允许远程下载的 host 不能配置为空");
- return save(list, certificateList, nList, allowEditSuffixList, allowRemoteDownloadHostList).toString();
- }
-//
-// private JsonMessage save(String project, List certificate, List nginx, List allowEditSuffixList) {
-//
-// return save(list, certificate, nginx);
-// }
-
-
- private JsonMessage save(List projects,
- List certificate,
- List nginx,
- List allowEditSuffixList,
- List allowRemoteDownloadHostList) {
- List projectArray;
- {
- projectArray = AgentWhitelist.covertToArray(projects, "项目路径白名单不能位于Jpom目录下");
-
- String error = findStartsWith(projectArray, 0);
- if (error != null) {
- return new JsonMessage<>(401, "白名单目录中不能存在包含关系:" + error);
- }
- }
- List certificateArray = null;
- if (certificate != null && !certificate.isEmpty()) {
- certificateArray = AgentWhitelist.covertToArray(certificate, "证书路径白名单不能位于Jpom目录下");
-
- String error = findStartsWith(certificateArray, 0);
- if (error != null) {
- return new JsonMessage<>(401, "证书目录中不能存在包含关系:" + error);
- }
- }
- List nginxArray = null;
- if (nginx != null && !nginx.isEmpty()) {
- nginxArray = AgentWhitelist.covertToArray(nginx, "nginx路径白名单不能位于Jpom目录下");
-
- String error = findStartsWith(nginxArray, 0);
- if (error != null) {
- return new JsonMessage<>(401, "nginx目录中不能存在包含关系:" + error);
- }
- }
- //
- if (CollUtil.isNotEmpty(allowEditSuffixList)) {
- for (String s : allowEditSuffixList) {
- List split = StrUtil.split(s, StrUtil.AT);
- if (split.size() > 1) {
- String last = CollUtil.getLast(split);
- try {
- CharsetUtil.charset(last);
- } catch (Exception e) {
- throw new IllegalArgumentException("配置的字符编码格式不合法:" + s);
- }
- }
- }
- }
- if (CollUtil.isNotEmpty(allowRemoteDownloadHostList)) {
- for (String s : allowRemoteDownloadHostList) {
- Assert.state(ReUtil.isMatch(RegexPool.URL_HTTP, s), "配置的远程地址不规范,请重新填写:" + s);
- }
- }
-
- AgentWhitelist agentWhitelist = whitelistDirectoryService.getWhitelist();
-
- agentWhitelist.setProject(projectArray);
- agentWhitelist.setCertificate(certificateArray);
- agentWhitelist.setNginx(nginxArray);
- agentWhitelist.setAllowEditSuffix(allowEditSuffixList);
- agentWhitelist.setAllowRemoteDownloadHost(allowRemoteDownloadHostList == null ? null : CollUtil.newHashSet(allowRemoteDownloadHostList));
- whitelistDirectoryService.saveWhitelistDirectory(agentWhitelist);
- return new JsonMessage<>(200, "保存成功");
- }
-
- /**
- * 检查白名单包含关系
- *
- * @param jsonArray 要检查的对象
- * @param start 检查的坐标
- * @return null 正常
- */
- private String findStartsWith(List jsonArray, int start) {
- if (jsonArray == null || !AgentExtConfigBean.getInstance().whitelistDirectoryCheckStartsWith) {
- return null;
- }
- String str = jsonArray.get(start);
- int len = jsonArray.size();
- for (int i = 0; i < len; i++) {
- if (i == start) {
- continue;
- }
- String findStr = jsonArray.get(i);
- if (findStr.startsWith(str)) {
- return str;
- }
- }
- if (start < len - 1) {
- return findStartsWith(jsonArray, start + 1);
- }
- return null;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/tomcat/TomcatEditController.java b/modules/agent/src/main/java/io/jpom/controller/tomcat/TomcatEditController.java
deleted file mode 100644
index 28207bf750..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/tomcat/TomcatEditController.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.tomcat;
-
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.crypto.SecureUtil;
-import cn.jiangzeyin.common.JsonMessage;
-import io.jpom.common.BaseAgentController;
-import io.jpom.model.data.TomcatInfoModel;
-import io.jpom.service.manage.TomcatEditService;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * tomcat 编辑
- *
- * @author bwcx_jzy
- * @date 2019/7/21
- */
-@RestController
-@RequestMapping(value = "/tomcat/")
-public class TomcatEditController extends BaseAgentController {
- @Resource
- private TomcatEditService tomcatEditService;
-
-
- /**
- * 列出所有的tomcat
- *
- * @return Tomcat列表
- */
- @RequestMapping(value = "list", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String list() {
- // 查询tomcat列表
- List tomcatInfoModels = tomcatEditService.list();
- return JsonMessage.getString(200, "查询成功", tomcatInfoModels);
- }
-
- /**
- * 根据Id查询Tomcat信息
- *
- * @param id Tomcat的主键
- * @return 操作结果
- */
- @RequestMapping(value = "getItem", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getItem(String id) {
- // 查询tomcat列表
- return JsonMessage.getString(200, "查询成功", tomcatEditService.getItem(id));
- }
-
-
- /**
- * 添加Tomcat
- *
- * @param tomcatInfoModel Tomcat信息
- * @return 操作结果
- */
- @RequestMapping(value = "add", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String add(TomcatInfoModel tomcatInfoModel) {
- // 根据Tomcat名称查询tomcat是否已经存在
- String name = tomcatInfoModel.getName();
- TomcatInfoModel tomcatInfoModelTemp = tomcatEditService.getItemByName(name);
- if (tomcatInfoModelTemp != null) {
- return JsonMessage.getString(401, "名称已经存在,请使用其他名称!");
- }
- tomcatInfoModel.setId(SecureUtil.md5(DateUtil.now()));
- tomcatInfoModel.setCreator(getUserName());
-
- // 设置tomcat路径,去除多余的符号
- tomcatInfoModel.setPath(FileUtil.normalize(tomcatInfoModel.getPath()));
- Objects.requireNonNull(tomcatInfoModel.pathAndCheck());
- tomcatEditService.addItem(tomcatInfoModel);
- tomcatInfoModel.initTomcat();
- return JsonMessage.getString(200, "保存成功");
- }
-
-
- /**
- * 修改Tomcat信息
- *
- * @param tomcatInfoModel Tomcat信息
- * @return 操作结果
- */
- @RequestMapping(value = "update", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String update(TomcatInfoModel tomcatInfoModel) {
- // 根据Tomcat名称查询tomcat是否已经存在
- String name = tomcatInfoModel.getName();
- TomcatInfoModel tomcatInfoModelTemp = tomcatEditService.getItemByName(name);
- if (tomcatInfoModelTemp != null && !tomcatInfoModelTemp.getId().equals(tomcatInfoModel.getId())) {
- return JsonMessage.getString(401, "名称已经存在,请使用其他名称!");
- }
-
- tomcatInfoModel.setModifyUser(getUserName());
- // 设置tomcat路径,去除多余的符号
- tomcatInfoModel.setPath(FileUtil.normalize(tomcatInfoModel.getPath()));
- Objects.requireNonNull(tomcatInfoModel.pathAndCheck());
- tomcatEditService.updateItem(tomcatInfoModel);
- tomcatInfoModel.initTomcat();
- return JsonMessage.getString(200, "修改成功");
-
- }
-
-
- /**
- * 删除tomcat
- *
- * @param id tomcat id
- * @return 操作结果
- */
- @RequestMapping(value = "delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String delete(String id) {
- tomcatEditService.deleteItem(id);
- return JsonMessage.getString(200, "删除成功");
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/tomcat/TomcatManageController.java b/modules/agent/src/main/java/io/jpom/controller/tomcat/TomcatManageController.java
deleted file mode 100644
index f2fee83fb7..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/tomcat/TomcatManageController.java
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.tomcat;
-
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.servlet.ServletUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.common.validator.ValidatorItem;
-import cn.jiangzeyin.common.validator.ValidatorRule;
-import cn.jiangzeyin.controller.multipart.MultipartFileBuilder;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.BaseAgentController;
-import io.jpom.common.commander.AbstractTomcatCommander;
-import io.jpom.model.data.TomcatInfoModel;
-import io.jpom.service.manage.TomcatEditService;
-import io.jpom.service.manage.TomcatManageService;
-import io.jpom.socket.AgentFileTailWatcher;
-import io.jpom.util.LayuiTreeUtil;
-import io.jpom.util.StringUtil;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-import java.io.File;
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author lf
- */
-@RestController
-@RequestMapping(value = "/tomcat/")
-public class TomcatManageController extends BaseAgentController {
-
- @Resource
- private TomcatEditService tomcatEditService;
- @Resource
- private TomcatManageService tomcatManageService;
-
- /**
- * 列出所有的tomcat项目列表
- *
- * @param id 项目id
- * @return Tomcat下的项目列表
- */
- @RequestMapping(value = "getTomcatProjectList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getTomcatProjectList(String id) {
- JSONArray array = tomcatManageService.getTomcatProjectList(id);
- return JsonMessage.getString(200, "查询成功", array);
- }
-
- /**
- * 查询tomcat状态
- *
- * @param id tomcat的id
- * @return tomcat运行状态
- */
- @RequestMapping(value = "getTomcatStatus", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getStatus(String id) {
- return JsonMessage.getString(200, "查询成功", tomcatManageService.getTomcatStatus(id));
- }
-
-
- /**
- * 启动tomcat
- *
- * @param id tomcat id
- * @return 操作结果
- */
- @RequestMapping(value = "start", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String start(String id) {
- // 查询tomcat信息
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(id);
-
- String result = AbstractTomcatCommander.getInstance().execCmd(tomcatInfoModel, "start");
- String msg = "启动成功";
- if ("stopped".equals(result)) {
- msg = "启动失败";
- }
- return JsonMessage.getString(200, msg, result);
- }
-
-
- /**
- * 删除tomcat
- *
- * @param id tomcat id
- * @return 操作结果
- */
- @RequestMapping(value = "stop", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String stop(String id) {
- // 查询tomcat信息
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(id);
-
- String result = AbstractTomcatCommander.getInstance().execCmd(tomcatInfoModel, "stop");
- String msg = "停止成功";
- if ("started".equals(result)) {
- msg = "停止失败";
- }
- return JsonMessage.getString(200, msg, result);
- }
-
- /**
- * 重启tomcat
- *
- * @param id tomcat id
- * @return 操作结果
- */
- @RequestMapping(value = "restart", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String restart(String id) {
- // 查询tomcat信息
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(id);
-
- String stopResult = AbstractTomcatCommander.getInstance().execCmd(tomcatInfoModel, "stop");
- String startResult = AbstractTomcatCommander.getInstance().execCmd(tomcatInfoModel, "start");
- return JsonMessage.getString(200, StrUtil.format("重启成功 {} {}", stopResult, startResult));
- }
-
- /**
- * tomcat项目管理
- *
- * @param id tomcat id
- * @param path 项目路径
- * @param op 执行的操作
- * @return 操作结果
- */
- @RequestMapping(value = "tomcatProjectManage", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String tomcatProjectManage(String id, String path,
- @ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "操作项不对") String op) {
-
- TomcatOp tomcatOp = TomcatOp.valueOf(op);
- return tomcatManageService.tomcatProjectManage(id, path, tomcatOp).toString();
- }
-
- /**
- * 获取项目文件列表
- *
- * @param id tomcat id
- * @param path 项目路径
- * @return 文件列表
- */
- @RequestMapping(value = "getFileList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getFileList(String id, String path) {
- // 查询项目路径
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(id);
- if (tomcatInfoModel == null) {
- return JsonMessage.getString(500, "查询失败:项目不存在");
- }
- if (StrUtil.isEmptyOrUndefined(path)) {
- return JsonMessage.getString(500, "path value error");
- }
- String appBasePath = tomcatInfoModel.getAppBase();
- File fileDir = FileUtil.file(appBasePath, FileUtil.normalize(path));
- if (!fileDir.exists()) {
- return JsonMessage.getString(500, "目录不存在");
- }
- File[] filesAll = fileDir.listFiles();
- if (filesAll == null) {
- return JsonMessage.getString(500, "目录是空");
- }
-
- // JSONArray arrayFile = FileUtils.parseInfo(filesAll, false, appBasePath);
- JSONArray arrayFile = new JSONArray();
- JSONArray arrayDir = new JSONArray();
- for (File file : filesAll) {
- JSONObject jsonObject = new JSONObject();
- String parentPath = StringUtil.delStartPath(file, appBasePath, false);
- jsonObject.put("parentPath", parentPath);
- jsonObject.put("filename", file.getName());
- long mTime = file.lastModified();
- jsonObject.put("modifyTimeLong", mTime);
- jsonObject.put("modifyTime", DateUtil.date(mTime).toString());
-
- if (file.isDirectory()) {
- jsonObject.put("isDirectory", true);
- long sizeFile = FileUtil.size(file);
- jsonObject.put("fileSize", FileUtil.readableFileSize(sizeFile));
- arrayDir.add(jsonObject);
- } else {
- jsonObject.put("fileSize", FileUtil.readableFileSize(file.length()));
- arrayFile.add(jsonObject);
- }
- }
-
- JSONArray resultArray = new JSONArray();
- resultArray.addAll(arrayDir);
- resultArray.addAll(arrayFile);
- return JsonMessage.getString(200, "查询成功", resultArray);
- }
-
-
- /**
- * 上传文件
- *
- * @param id tomcat id
- * @param path 文件路径
- * @return 操作结果
- */
- @RequestMapping(value = "upload", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String upload(String id, String path) {
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(id);
-
- MultipartFileBuilder multipartFileBuilder = createMultipart()
- .addFieldName("file");
-
- File dir = new File(tomcatInfoModel.getAppBase().concat(FileUtil.normalize(path)));
-
- multipartFileBuilder.setSavePath(dir.getAbsolutePath())
- .setUseOriginalFilename(true);
- // 保存
- try {
- multipartFileBuilder.save();
- } catch (IOException e) {
- return JsonMessage.getString(500, "上传异常");
- }
-
- return JsonMessage.getString(200, "上传成功");
- }
-
- /**
- * 上传war文件
- *
- * @param id tomcat id
- * @return 操作结果
- */
- @RequestMapping(value = "uploadWar", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String uploadWar(String id) {
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(id);
-
- MultipartFileBuilder multipartFileBuilder = createMultipart()
- .addFieldName("file");
-
- File dir = new File(tomcatInfoModel.getAppBase());
-
- multipartFileBuilder.setSavePath(dir.getAbsolutePath())
- .setUseOriginalFilename(true);
- // 保存
- try {
- multipartFileBuilder.save();
- } catch (IOException e) {
- return JsonMessage.getString(500, "上传异常");
- }
-
- return JsonMessage.getString(200, "上传成功");
- }
-
-
- /**
- * 删除文件
- *
- * @param id tomcat id
- * @param filename 文件名
- * @param path tomcat路径
- * @return 操作结果
- */
- @RequestMapping(value = "deleteFile", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String deleteFile(String id, String path, String filename) {
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(id);
- if (tomcatInfoModel == null) {
- return JsonMessage.getString(500, "tomcat不存在");
- }
- File file;
- if ("_tomcat_log".equals(path)) {
- //删除日志文件
- file = FileUtil.file(tomcatInfoModel.getPath(), "logs", filename);
- // 判断修改时间
- long modified = file.lastModified();
- if (System.currentTimeMillis() - modified < TimeUnit.DAYS.toMillis(1)) {
- return JsonMessage.getString(405, "不能删除当天的日志");
- }
- // 判断最后修改日期
- AgentFileTailWatcher.offlineFile(file);
- } else {
- file = FileUtil.file(tomcatInfoModel.getAppBase(), path, filename);
- }
- if (file.exists()) {
- if (file.delete()) {
- return JsonMessage.getString(200, "删除成功");
- } else {
- return JsonMessage.getString(500, "删除失败");
- }
- } else {
- return JsonMessage.getString(404, "文件不存在");
- }
- }
-
- /**
- * 下载文件
- *
- * @param id tomcat id
- * @param filename 文件名
- * @param path tomcat路径
- * @return 操作结果
- */
- @RequestMapping(value = "download", method = RequestMethod.GET)
- public String download(String id, String path, String filename) {
- filename = FileUtil.normalize(filename);
- path = FileUtil.normalize(path);
- try {
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(id);
- File file;
- //下载日志文件
- if ("_tomcat_log".equals(path)) {
- file = FileUtil.file(tomcatInfoModel.getPath(), "logs", filename);
- } else {
- file = FileUtil.file(tomcatInfoModel.getAppBase(), path, filename);
- }
- if (file.isDirectory()) {
- return "暂不支持下载文件夹";
- }
- ServletUtil.write(getResponse(), file);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("下载文件异常", e);
- }
- return "下载失败。请刷新页面后重试";
- }
-
- /**
- * 获取tomcat 日志列表
- *
- * @param id tomcat id
- * @return json
- */
- @RequestMapping(value = "logList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
- public String logList(String id) {
- TomcatInfoModel item = tomcatEditService.getItem(id);
- if (item == null) {
- return JsonMessage.getString(300, "没有对应数据");
- }
- JSONArray jsonArray = LayuiTreeUtil.getTreeData(FileUtil.file(item.pathAndCheck(), "logs").getAbsolutePath());
- return JsonMessage.getString(200, "", jsonArray);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/controller/tomcat/TomcatOp.java b/modules/agent/src/main/java/io/jpom/controller/tomcat/TomcatOp.java
deleted file mode 100644
index b9a3ea7d40..0000000000
--- a/modules/agent/src/main/java/io/jpom/controller/tomcat/TomcatOp.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.controller.tomcat;
-
-/**
- * tomcat操作
- *
- * @author bwcx_jzy
- * @date 2019/7/22
- **/
-public enum TomcatOp {
- /**
- * 启动
- */
- start,
- stop,
- reload,
- /**
- * 删除发布
- */
- undeploy
-}
diff --git a/modules/agent/src/main/java/io/jpom/model/data/CertModel.java b/modules/agent/src/main/java/io/jpom/model/data/CertModel.java
deleted file mode 100644
index c2c82d2be4..0000000000
--- a/modules/agent/src/main/java/io/jpom/model/data/CertModel.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.model.data;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.io.resource.ResourceUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.KeyUtil;
-import cn.hutool.crypto.PemUtil;
-import cn.hutool.crypto.asymmetric.KeyType;
-import cn.hutool.crypto.asymmetric.RSA;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.spring.SpringUtil;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.model.BaseModel;
-import io.jpom.service.system.CertService;
-import io.jpom.system.JpomRuntimeException;
-
-import java.io.InputStream;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.cert.X509Certificate;
-import java.util.Date;
-
-/**
- * 证书实体
- *
- * @author Arno
- */
-public class CertModel extends BaseModel {
-
- private static final String KEY = "Jpom 管理系统";
- /**
- * 证书文件
- */
- private String cert;
- /**
- * 私钥
- */
- private String key;
- /**
- * 证书到期时间
- */
- private long expirationTime;
- /**
- * 证书生效日期
- */
- private long effectiveTime;
- /**
- * 绑定域名
- */
- private String domain;
- /**
- * 白名单路径
- */
- private String whitePath;
- private Type type;
-
- public Type getType() {
- return type;
- }
-
- public void setType(Type type) {
- this.type = type;
- }
-
- public String getWhitePath() {
- return whitePath;
- }
-
- public void setWhitePath(String whitePath) {
- this.whitePath = whitePath;
- }
-
- public String getCert() {
- return cert;
- }
-
- public void setCert(String cert) {
- this.cert = cert;
- }
-
- public String getKey() {
- return key;
- }
-
- public void setKey(String key) {
- this.key = key;
- }
-
- public long getExpirationTime() {
- this.convertInfo();
- return expirationTime;
- }
-
- public void setExpirationTime(long expirationTime) {
- this.expirationTime = expirationTime;
- }
-
- public String getDomain() {
- this.convertInfo();
- return domain;
- }
-
- /**
- * 兼容手动添加的证书文件
- */
- private void convertInfo() {
- if (!StrUtil.isEmpty(domain)) {
- return;
- }
- JSONObject jsonObject = decodeCert(getCert(), getKey());
- if (jsonObject != null) {
- // 获取信息
- this.setDomain(jsonObject.getString("domain"));
- this.setExpirationTime(jsonObject.getLongValue("expirationTime"));
- this.setEffectiveTime(jsonObject.getLongValue("effectiveTime"));
-
- // 数据持久化到文件中
- CertService certService = SpringUtil.getBean(CertService.class);
- certService.updateItem(this);
- }
- }
-
- public void setDomain(String domain) {
- this.domain = domain;
- }
-
- public long getEffectiveTime() {
- this.convertInfo();
- return effectiveTime;
- }
-
- public void setEffectiveTime(long effectiveTime) {
- this.effectiveTime = effectiveTime;
- }
-
- /**
- * 解析证书
- *
- * @param key zip里面文件
- * @param file 证书文件
- * @return 处理后的json
- */
- public static JSONObject decodeCert(String file, String key) {
- if (file == null) {
- return null;
- }
- if (!FileUtil.exist(file)) {
- return null;
- }
- InputStream inputStream = null;
- try {
- inputStream = ResourceUtil.getStream(key);
- PrivateKey privateKey = PemUtil.readPemPrivateKey(inputStream);
- IoUtil.close(inputStream);
- inputStream = ResourceUtil.getStream(file);
- PublicKey publicKey = PemUtil.readPemPublicKey(inputStream);
- IoUtil.close(inputStream);
- RSA rsa = new RSA(privateKey, publicKey);
- String encryptStr = rsa.encryptBase64(KEY, KeyType.PublicKey);
- String decryptStr = rsa.decryptStr(encryptStr, KeyType.PrivateKey);
- if (!KEY.equals(decryptStr)) {
- throw new JpomRuntimeException("证书和私钥证书不匹配");
- }
- } finally {
- IoUtil.close(inputStream);
- }
- try {
- inputStream = ResourceUtil.getStream(file);
- // 创建证书对象
- X509Certificate oCert = (X509Certificate) KeyUtil.readX509Certificate(inputStream);
- //到期时间
- Date expirationTime = oCert.getNotAfter();
- //生效日期
- Date effectiveTime = oCert.getNotBefore();
- //域名
- String name = oCert.getSubjectDN().getName();
- int i = name.indexOf("=");
- String domain = name.substring(i + 1);
- JSONObject jsonObject = new JSONObject();
- jsonObject.put("expirationTime", expirationTime.getTime());
- jsonObject.put("effectiveTime", effectiveTime.getTime());
- jsonObject.put("domain", domain);
- jsonObject.put("pemPath", file);
- jsonObject.put("keyPath", key);
- return jsonObject;
- } catch (Exception e) {
- DefaultSystemLog.getLog().error(e.getMessage(), e);
- } finally {
- IoUtil.close(inputStream);
- }
- return null;
- }
-
- /**
- * 证书类型
- */
- public enum Type {
- /**
- *
- */
- pem,
- /**
- * Windows
- */
- cer,
- /**
- * Linux
- */
- crt
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/model/data/JdkInfoModel.java b/modules/agent/src/main/java/io/jpom/model/data/JdkInfoModel.java
deleted file mode 100644
index b869bfee70..0000000000
--- a/modules/agent/src/main/java/io/jpom/model/data/JdkInfoModel.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.model.data;
-
-import io.jpom.model.BaseModel;
-
-/**
- * jdk 信息
- *
- * @author bwcx_jzy
- * @date 2019/10/29
- */
-public class JdkInfoModel extends BaseModel {
-
- /**
- * jdk 路径
- */
- private String path;
-
- /**
- * jdk 版本
- */
- private String version;
-
- public String getPath() {
- return path;
- }
-
- public void setPath(String path) {
- this.path = path;
- }
-
- public String getVersion() {
- return version;
- }
-
- public void setVersion(String version) {
- this.version = version;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/model/data/NodeProjectInfoModel.java b/modules/agent/src/main/java/io/jpom/model/data/NodeProjectInfoModel.java
deleted file mode 100644
index a9c818dd49..0000000000
--- a/modules/agent/src/main/java/io/jpom/model/data/NodeProjectInfoModel.java
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.model.data;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.http.HtmlUtil;
-import cn.jiangzeyin.common.request.XssFilter;
-import cn.jiangzeyin.common.spring.SpringUtil;
-import io.jpom.model.BaseJsonModel;
-import io.jpom.model.BaseModel;
-import io.jpom.model.RunMode;
-import io.jpom.service.WhitelistDirectoryService;
-import io.jpom.system.JpomRuntimeException;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-/**
- * 项目配置信息实体
- *
- * @author jiangzeyin
- */
-public class NodeProjectInfoModel extends BaseModel {
- // /**
-// * 分组
-// */
-// private String group;
- private String mainClass;
- private String lib;
- /**
- * 白名单目录
- */
- private String whitelistDirectory;
- private String log;
-
- /**
- * 日志目录
- */
- private String logPath;
- /**
- * jvm 参数
- */
- private String jvm;
- /**
- * java main 方法参数
- */
- private String args;
-
- private List javaCopyItemList;
- /**
- * WebHooks
- */
- private String token;
- private boolean status;
- private String createTime;
- private String modifyTime;
- private String jdkId;
- /**
- * lib 目录当前文件状态
- */
- private String useLibDesc;
- /**
- * 当前运行lib 状态
- */
- private String runLibDesc;
- /**
- * 最后修改人
- */
- private String modifyUser;
-
- private RunMode runMode;
- /**
- * 节点分发项目,不允许在项目管理中编辑
- */
- private boolean outGivingProject;
- /**
- * 实际运行的命令
- */
- private String runCommand;
-
- /**
- * -Djava.ext.dirs=lib -cp conf:run.jar
- * 填写【lib:conf】
- */
- private String javaExtDirsCp;
-
- private String workspaceId;
-
- /**
- * 项目自动启动
- */
- private Boolean autoStart;
-
- public String getWorkspaceId() {
- return workspaceId;
- }
-
- public void setWorkspaceId(String workspaceId) {
- this.workspaceId = workspaceId;
- }
-
- public List getJavaCopyItemList() {
- return javaCopyItemList;
- }
-
- public void setJavaCopyItemList(List javaCopyItemList) {
- this.javaCopyItemList = javaCopyItemList;
- }
-
- public String getJavaExtDirsCp() {
- return StrUtil.emptyToDefault(javaExtDirsCp, StrUtil.EMPTY);
- }
-
- public void setJavaExtDirsCp(String javaExtDirsCp) {
- this.javaExtDirsCp = javaExtDirsCp;
- }
-
- public String getRunCommand() {
- return runCommand;
- }
-
- public void setRunCommand(String runCommand) {
- this.runCommand = runCommand;
- }
-
- public boolean isOutGivingProject() {
- return outGivingProject;
- }
-
- public void setOutGivingProject(boolean outGivingProject) {
- this.outGivingProject = outGivingProject;
- }
-
- public RunMode getRunMode() {
- if (runMode == null) {
- return RunMode.ClassPath;
- }
- return runMode;
- }
-
- public void setRunMode(RunMode runMode) {
- this.runMode = runMode;
- }
-
- public String getModifyUser() {
- if (StrUtil.isEmpty(modifyUser)) {
- return StrUtil.DASHED;
- }
- return modifyUser;
- }
-
- public void setModifyUser(String modifyUser) {
- this.modifyUser = modifyUser;
- }
-
- public void setStatus(boolean status) {
- this.status = status;
- }
-
- public String getRunLibDesc() {
- return runLibDesc;
- }
-
- public void setRunLibDesc(String runLibDesc) {
- this.runLibDesc = runLibDesc;
- }
-
- public String getUseLibDesc() {
- return useLibDesc;
- }
-
- public void setUseLibDesc(String useLibDesc) {
- this.useLibDesc = useLibDesc;
- }
-
- public String getModifyTime() {
- return modifyTime;
- }
-
- /**
- * 修改时间
- *
- * @param modifyTime time
- */
- public void setModifyTime(String modifyTime) {
- this.modifyTime = modifyTime;
- }
-
- public String getJvm() {
- String s = StrUtil.emptyToDefault(jvm, StrUtil.EMPTY);
- if (XssFilter.isXSS()) {
- s = HtmlUtil.unescape(s);
- }
- return s;
- }
-
- public void setJvm(String jvm) {
- if (XssFilter.isXSS()) {
- this.jvm = HtmlUtil.unescape(jvm);
- } else {
- this.jvm = jvm;
- }
- }
-
- public Boolean getAutoStart() {
- return autoStart;
- }
-
- public void setAutoStart(Boolean autoStart) {
- this.autoStart = autoStart;
- }
-
- //
-// public String getGroup() {
-// if (StrUtil.isEmpty(group)) {
-// return "默认";
-// }
-// return group;
-// }
-//
-// public void setGroup(String group) {
-// this.group = group;
-// }
-
- public String getMainClass() {
- return StrUtil.emptyToDefault(mainClass, StrUtil.EMPTY);
- }
-
- private void repairWhitelist() {
- if (StrUtil.isEmpty(whitelistDirectory) && StrUtil.isEmpty(lib)) {
- throw new JpomRuntimeException("当前项目lib数据异常");
- }
- if (StrUtil.isNotEmpty(whitelistDirectory)) {
- return;
- }
- WhitelistDirectoryService whitelistDirectoryService = SpringUtil.getBean(WhitelistDirectoryService.class);
- List project = whitelistDirectoryService.getWhitelist().getProject();
- for (String path : project) {
- if (lib.startsWith(path)) {
- String itemWhitelistDirectory = lib.substring(0, path.length());
- lib = lib.substring(path.length());
- setWhitelistDirectory(itemWhitelistDirectory);
- setLib(lib);
- }
- }
- }
-
- public String getWhitelistDirectory() {
- this.repairWhitelist();
- if (StrUtil.isEmpty(whitelistDirectory)) {
- throw new JpomRuntimeException("修护白名单数据异常");
- }
- return whitelistDirectory;
- }
-
- public void setWhitelistDirectory(String whitelistDirectory) {
- this.whitelistDirectory = whitelistDirectory;
- }
-
- public void setMainClass(String mainClass) {
- this.mainClass = mainClass;
- }
-
- public String getLib() {
- this.repairWhitelist();
- return lib;
- }
-
- public String allLib() {
- return FileUtil.file(getWhitelistDirectory(), getLib()).getAbsolutePath();
- }
-
- /**
- * 获取项目文件中的所有jar 文件
- *
- * @param nodeProjectInfoModel 项目
- * @return list
- */
- public static List listJars(NodeProjectInfoModel nodeProjectInfoModel) {
- File fileLib = new File(nodeProjectInfoModel.allLib());
- File[] files = fileLib.listFiles();
- List files1 = new ArrayList<>();
- if (files != null) {
- for (File file : files) {
- if (!file.isFile()) {
- continue;
- }
- if (nodeProjectInfoModel.getRunMode() == RunMode.ClassPath || nodeProjectInfoModel.getRunMode() == RunMode.Jar) {
- if (!StrUtil.endWith(file.getName(), FileUtil.JAR_FILE_EXT, true)) {
- continue;
- }
- } else if (nodeProjectInfoModel.getRunMode() == RunMode.JarWar) {
- if (!StrUtil.endWith(file.getName(), "war", true)) {
- continue;
- }
- }
- files1.add(file);
- }
- }
- return files1;
- }
-
- /**
- * 拼接java 执行的jar路径
- *
- * @param nodeProjectInfoModel 项目
- * @return classpath 或者 jar
- */
- public static String getClassPathLib(NodeProjectInfoModel nodeProjectInfoModel) {
- List files = listJars(nodeProjectInfoModel);
- if (files.size() <= 0) {
- return "";
- }
- // 获取lib下面的所有jar包
- StringBuilder classPath = new StringBuilder();
- RunMode runMode = nodeProjectInfoModel.getRunMode();
- int len = files.size();
- if (runMode == RunMode.ClassPath) {
- classPath.append("-classpath ");
- } else if (runMode == RunMode.Jar || runMode == RunMode.JarWar) {
- classPath.append("-jar ");
- // 只取一个jar文件
- len = 1;
- } else if (runMode == RunMode.JavaExtDirsCp) {
- classPath.append("-Djava.ext.dirs=");
- String javaExtDirsCp = nodeProjectInfoModel.getJavaExtDirsCp();
- String[] split = StrUtil.splitToArray(javaExtDirsCp, StrUtil.COLON);
- if (ArrayUtil.isEmpty(split)) {
- classPath.append(". -cp ");
- } else {
- classPath.append(split[0]).append(" -cp ");
- if (split.length > 1) {
- classPath.append(split[1]).append(FileUtil.PATH_SEPARATOR);
- }
- }
- } else {
- return StrUtil.EMPTY;
- }
- for (int i = 0; i < len; i++) {
- File file = files.get(i);
- classPath.append(file.getAbsolutePath());
- if (i != len - 1) {
- classPath.append(FileUtil.PATH_SEPARATOR);
- }
- }
- return classPath.toString();
- }
-
- public void setLib(String lib) {
- this.lib = lib;
- }
-
-
- public String getLogPath() {
- return StrUtil.emptyToDefault(this.logPath, StrUtil.EMPTY);
- }
-
- public void setLogPath(String logPath) {
- this.logPath = logPath;
- }
-
- public String getLog() {
- if (StrUtil.isEmpty(this.getId())) {
- return StrUtil.EMPTY;
- }
- if (StrUtil.isNotEmpty(this.getLogPath())) {
- return FileUtil.normalize(String.format("%s/%s/%s.log", this.getLogPath(), this.getId(), this.getId()));
- }
- if (StrUtil.isEmpty(this.log)) {
- String log = new File(this.allLib()).getParent();
- this.log = FileUtil.normalize(String.format("%s/%s.log", log, this.getId()));
- }
- return StrUtil.emptyToDefault(this.log, StrUtil.EMPTY);
- }
-
- /**
- * 副本的控制台日志文件
- *
- * @param javaCopyItem 副本信息
- * @return file
- */
- public File getLog(JavaCopyItem javaCopyItem) {
- File file = FileUtil.file(getLog());
- return FileUtil.file(file.getParentFile(), getId() + "_" + javaCopyItem.getId() + ".log");
- }
-
- public String getAbsoluteLog(JavaCopyItem javaCopyItem) {
- File file = javaCopyItem == null ? new File(getLog()) : getLog(javaCopyItem);
- // auto create dir
- FileUtil.mkParentDirs(file);
- return file.getAbsolutePath();
- }
-
- public File getLogBack() {
- return new File(getLog() + "_back");
- }
-
- public File getLogBack(JavaCopyItem javaCopyItem) {
- return new File(getLog(javaCopyItem) + "_back");
- }
-
- public void setLog(String log) {
- this.log = log;
- }
-
- /**
- * 默认
- *
- * @return url token
- */
- public String getToken() {
- // 兼容旧数据
- if ("no".equalsIgnoreCase(this.token)) {
- return "";
- }
- return StrUtil.emptyToDefault(token, StrUtil.EMPTY);
- }
-
- public void setToken(String token) {
- this.token = token;
- }
-
- public String getCreateTime() {
- return createTime;
- }
-
- public void setCreateTime(String createTime) {
- this.createTime = createTime;
- }
-
- public String getArgs() {
- String s = StrUtil.emptyToDefault(args, StrUtil.EMPTY);
- if (XssFilter.isXSS()) {
- s = HtmlUtil.unescape(s);
- }
- return s;
- }
-
- public void setArgs(String args) {
- if (XssFilter.isXSS()) {
- this.args = HtmlUtil.unescape(args);
- } else {
- this.args = args;
- }
- }
-
- public String getJdkId() {
- return jdkId;
- }
-
- public void setJdkId(String jdkId) {
- this.jdkId = jdkId;
- }
-
-
- public JavaCopyItem findCopyItem(String copyId) {
- if (StrUtil.isEmpty(copyId)) {
- return null;
- }
- List javaCopyItemList = getJavaCopyItemList();
- if (CollUtil.isEmpty(javaCopyItemList)) {
- return null;
- }
- Optional first = javaCopyItemList.stream().filter(javaCopyItem -> StrUtil.equals(javaCopyItem.getId(), copyId)).findFirst();
- return first.orElse(null);
- }
-
- public boolean removeCopyItem(String copyId) {
-
- if (StrUtil.isEmpty(copyId) || CollUtil.isEmpty(javaCopyItemList)) {
- return true;
- }
- int size = javaCopyItemList.size();
- List collect = javaCopyItemList.stream().filter(javaCopyItem -> !StrUtil.equals(javaCopyItem.getId(), copyId)).collect(Collectors.toList());
- if (size - 1 == collect.size()) {
- this.javaCopyItemList = collect;
- return true;
- } else {
- return false;
- }
- }
-
- public static class JavaCopyItem extends BaseJsonModel {
- /**
- * 父级项目id
- */
- private String parendId;
- /**
- * id
- */
- private String id;
-
- /**
- * jvm 参数
- */
- private String jvm;
- /**
- * java main 方法参数
- */
- private String args;
-
- private String modifyTime;
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getTagId() {
- return getTagId(parendId, id);
- }
-
- /**
- * 创建进程标记
- *
- * @param id
- * @param copyId
- * @return
- */
- public static String getTagId(String id, String copyId) {
- if (StrUtil.isEmpty(copyId)) {
- return id;
- }
- return StrUtil.format("{}:{}", id, copyId);
- }
-
- public String getModifyTime() {
- return modifyTime;
- }
-
- public void setModifyTime(String modifyTime) {
- this.modifyTime = modifyTime;
- }
-
- public String getParendId() {
- return parendId;
- }
-
- public void setParendId(String parendId) {
- this.parendId = parendId;
- }
-
- public String getJvm() {
- if (XssFilter.isXSS()) {
- return HtmlUtil.unescape(jvm);
- }
- return jvm;
- }
-
- public void setJvm(String jvm) {
- if (XssFilter.isXSS()) {
- this.jvm = HtmlUtil.unescape(jvm);
- } else {
- this.jvm = jvm;
- }
- }
-
- public String getArgs() {
- if (XssFilter.isXSS()) {
- return HtmlUtil.unescape(args);
- }
- return args;
- }
-
- public void setArgs(String args) {
- if (XssFilter.isXSS()) {
- this.args = HtmlUtil.unescape(args);
- } else {
- this.args = args;
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- JavaCopyItem that = (JavaCopyItem) o;
- return Objects.equals(parendId, that.parendId) &&
- Objects.equals(id, that.id);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(parendId, id, jvm, args, modifyTime);
- }
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/model/data/ProjectRecoverModel.java b/modules/agent/src/main/java/io/jpom/model/data/ProjectRecoverModel.java
deleted file mode 100644
index 2405581cf1..0000000000
--- a/modules/agent/src/main/java/io/jpom/model/data/ProjectRecoverModel.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.model.data;
-
-import cn.hutool.core.lang.ObjectId;
-import io.jpom.model.BaseModel;
-
-/**
- * 项目回收记录实体
- *
- * @author jiangzeyin
- */
-public class ProjectRecoverModel extends BaseModel {
- /**
- * 删除人
- */
- private String delUser;
- /**
- * 删除时间
- */
- private String delTime;
- /**
- * 删除的对应项目信息
- */
- private NodeProjectInfoModel nodeProjectInfoModel;
-
- public ProjectRecoverModel(NodeProjectInfoModel nodeProjectInfoModel) {
- this.nodeProjectInfoModel = nodeProjectInfoModel;
- // 生成操作id
- setId(ObjectId.next());
- }
-
- public ProjectRecoverModel() {
- }
-
- public NodeProjectInfoModel getProjectInfoModel() {
- return nodeProjectInfoModel;
- }
-
- public void setProjectInfoModel(NodeProjectInfoModel nodeProjectInfoModel) {
- this.nodeProjectInfoModel = nodeProjectInfoModel;
- }
-
- public String getDelUser() {
- return delUser;
- }
-
- public void setDelUser(String delUser) {
- this.delUser = delUser;
- }
-
- public String getDelTime() {
- return delTime;
- }
-
- public void setDelTime(String delTime) {
- this.delTime = delTime;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/model/data/ScriptModel.java b/modules/agent/src/main/java/io/jpom/model/data/ScriptModel.java
deleted file mode 100644
index 25a0e3bcd7..0000000000
--- a/modules/agent/src/main/java/io/jpom/model/data/ScriptModel.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.model.data;
-
-import cn.hutool.core.date.DatePattern;
-import cn.hutool.core.date.DateTime;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import io.jpom.JpomApplication;
-import io.jpom.model.BaseModel;
-import io.jpom.system.AgentConfigBean;
-import io.jpom.util.CommandUtil;
-
-import java.io.File;
-
-/**
- * 脚本模板
- *
- * @author jiangzeyin
- * @date 2019/4/24
- */
-public class ScriptModel extends BaseModel {
-
- /**
- * 最后执行人员
- */
- private String lastRunUser;
- /**
- * 最后修改时间
- */
- private String modifyTime;
- /**
- * 脚本内容
- */
- private String context;
-
- public String getLastRunUser() {
- return StrUtil.emptyToDefault(lastRunUser, StrUtil.DASHED);
- }
-
- public void setLastRunUser(String lastRunUser) {
- this.lastRunUser = lastRunUser;
- }
-
- public String getModifyTime() {
- return modifyTime;
- }
-
- public void setModifyTime(String modifyTime) {
- this.modifyTime = modifyTime;
- }
-
- public String getContext() {
- return context;
- }
-
- public void setContext(String context) {
- this.context = context;
- }
-
- public File getFile(boolean get) {
- if (StrUtil.isEmpty(getId())) {
- throw new IllegalArgumentException("id 为空");
- }
- File path = AgentConfigBean.getInstance().getScriptPath();
- return FileUtil.file(path, getId(), "script." + CommandUtil.SUFFIX);
- }
-
- public File logFile() {
- if (StrUtil.isEmpty(getId())) {
- throw new IllegalArgumentException("id 为空");
- }
- File path = AgentConfigBean.getInstance().getScriptPath();
- File logFile;
- int count = 0;
- do {
- String now = DateTime.now().toString(DatePattern.PURE_DATETIME_PATTERN);
- logFile = FileUtil.file(path, getId(), "log", now + count + ".log");
- count++;
- } while (FileUtil.exist(logFile));
- return logFile;
- }
-
- public void saveFile() {
- File file = getFile(true);
- FileUtil.writeString(getContext(), file, JpomApplication.getCharset());
-// // 添加权限
-// if (SystemUtil.getOsInfo().isLinux()) {
-// CommandUtil.execCommand("chmod 755 " + FileUtil.getAbsolutePath(file));
-// }
- }
-
- /**
- * 读取文件信息
- */
- public void readFileTime() {
- File file = getFile(true);
- long lastModified = file.lastModified();
- setModifyTime(DateUtil.date(lastModified).toString());
-
- }
-
- public void readFileContext() {
- File file = getFile(true);
- if (FileUtil.exist(file)) {
- //
- String context = FileUtil.readString(file, JpomApplication.getCharset());
- setContext(context);
- }
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/model/data/TomcatInfoModel.java b/modules/agent/src/main/java/io/jpom/model/data/TomcatInfoModel.java
deleted file mode 100644
index ce8ef32b53..0000000000
--- a/modules/agent/src/main/java/io/jpom/model/data/TomcatInfoModel.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.model.data;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.resource.ResourceUtil;
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.core.util.ZipUtil;
-import io.jpom.model.BaseModel;
-import io.jpom.system.JpomRuntimeException;
-
-import java.io.File;
-import java.io.InputStream;
-
-/**
- * tomcat 对象实体
- *
- * @author lf
- */
-public class TomcatInfoModel extends BaseModel {
-
- private String path;
- private int port;
- private int status;
- private String appBase;
- private String creator;
- private String createTime;
- private String modifyUser;
- private String modifyTime;
-
- public String getPath() {
- if (path == null) {
- return null;
- }
- return FileUtil.normalize(path + StrUtil.SLASH);
- }
-
- /**
- * 检测路径是否正确
- *
- * @return path
- */
- public String pathAndCheck() {
- String path = getPath();
- if (path == null) {
- return null;
- }
- if (isTomcatRoot(path)) {
- return path;
- }
- throw new RuntimeException(String.format("没有在路径:%s 下检测到Tomcat", path));
- }
-
- public void setPath(String path) {
- this.path = path;
- }
-
- public int getPort() {
- return port;
- }
-
- public void setPort(int port) {
- this.port = port;
- }
-
- public int getStatus() {
- return status;
- }
-
- public void setStatus(int status) {
- this.status = status;
- }
-
- public String getAppBase() {
- if (StrUtil.isEmpty(appBase)) {
- return FileUtil.normalize(path + "/webapps/");
- }
- return FileUtil.normalize(appBase + StrUtil.SLASH);
- }
-
- public void setAppBase(String appBase) {
- this.appBase = appBase;
- }
-
- public String getCreator() {
- return creator;
- }
-
- public void setCreator(String creator) {
- this.creator = creator;
- }
-
- public String getCreateTime() {
- return createTime;
- }
-
- public void setCreateTime(String createTime) {
- this.createTime = createTime;
- }
-
- public String getModifyUser() {
- return modifyUser;
- }
-
- public void setModifyUser(String modifyUser) {
- this.modifyUser = modifyUser;
- }
-
- public String getModifyTime() {
- return modifyTime;
- }
-
- public void setModifyTime(String modifyTime) {
- this.modifyTime = modifyTime;
- }
-
-
- /**
- * 判断是否是Tomcat的根路径
- *
- * @return 返回是否是Tomcat根路径
- */
- private static boolean isTomcatRoot(String path) {
- File file = new File(path);
- if (!file.exists()) {
- return false;
- }
- if (file.isFile()) {
- return false;
- }
- File[] files = file.listFiles();
- if (files == null) {
- return false;
- }
- // 判断该目录下是否
- for (File child : files) {
- if ("bin".equals(child.getName()) && child.isDirectory()) {
- File[] binFiles = child.listFiles();
- if (binFiles == null) {
- return false;
- }
- for (File binChild : binFiles) {
- if ("bootstrap.jar".equals(binChild.getName()) && binChild.isFile()) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- /**
- * 初始化
- */
- public void initTomcat() {
- String tomcatPath = pathAndCheck();
- String appBase = getAppBase();
- if (StrUtil.isEmpty(appBase) || StrUtil.SLASH.equals(appBase)) {
- File webapps = FileUtil.file(tomcatPath, "webapps");
- setAppBase(webapps.getAbsolutePath());
- } else {
- String path = FileUtil.normalize(appBase);
- if (FileUtil.isAbsolutePath(path)) {
- // appBase如:/project/、D:/project/
- setAppBase(path);
- } else {
- // appBase填写的是对相路径如:project/dir
- File webapps = FileUtil.file(tomcatPath, path);
- setAppBase(webapps.getAbsolutePath());
- }
- }
- InputStream inputStream = ResourceUtil.getStream("classpath:/bin/jpomAgent.zip");
- if (inputStream == null) {
- throw new JpomRuntimeException("jpomAgent.zip不存在");
- }
- // 解压代理工具到tomcat的appBase目录下
- ZipUtil.unzip(inputStream, new File(getAppBase()), CharsetUtil.CHARSET_UTF_8);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/model/data/UploadFileModel.java b/modules/agent/src/main/java/io/jpom/model/data/UploadFileModel.java
deleted file mode 100644
index 84e4981036..0000000000
--- a/modules/agent/src/main/java/io/jpom/model/data/UploadFileModel.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.model.data;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import io.jpom.model.BaseModel;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * @author lf
- */
-public class UploadFileModel extends BaseModel {
- private long size = 0;
- private long completeSize = 0;
- private String savePath;
- private String version;
-
- public long getSize() {
- return size;
- }
-
- public void setSize(long size) {
- this.size = size;
- }
-
- public long getCompleteSize() {
- return completeSize;
- }
-
- public void setCompleteSize(long completeSize) {
- this.completeSize = completeSize;
- }
-
- public String getSavePath() {
- return savePath;
- }
-
- public void setSavePath(String savePath) {
- this.savePath = savePath;
- }
-
- public String getVersion() {
- return version;
- }
-
- public void setVersion(String version) {
- this.version = version;
- }
-
- public void save(byte[] data) {
- this.completeSize += data.length;
- File file = new File(this.getFilePath());
- FileUtil.mkParentDirs(file);
- try (FileOutputStream fileOutputStream = new FileOutputStream(file, true)) {
- fileOutputStream.write(data);
- fileOutputStream.flush();
- } catch (IOException e) {
- DefaultSystemLog.getLog().error(e.getMessage(), e);
- }
- }
-
- public String getFilePath() {
- return savePath + StrUtil.SLASH + getName();
- }
-
- public void remove() {
- FileUtil.del(this.getFilePath());
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/model/system/NetstatModel.java b/modules/agent/src/main/java/io/jpom/model/system/NetstatModel.java
deleted file mode 100644
index 9bde889f9d..0000000000
--- a/modules/agent/src/main/java/io/jpom/model/system/NetstatModel.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.model.system;
-
-import cn.hutool.core.util.StrUtil;
-import io.jpom.model.BaseJsonModel;
-
-/**
- * 网络端口信息实体
- *
- * @author jiangzeyin
- * @date 2019/4/10
- */
-public class NetstatModel extends BaseJsonModel {
- private String protocol;
- private String receive = StrUtil.DASHED;
- private String send = StrUtil.DASHED;
- private String local;
- private String foreign;
- private String status;
- private String name;
-
- public String getProtocol() {
- return protocol;
- }
-
- public void setProtocol(String protocol) {
- this.protocol = protocol;
- }
-
- public String getReceive() {
- return receive;
- }
-
- public void setReceive(String receive) {
- this.receive = receive;
- }
-
- public String getSend() {
- return send;
- }
-
- public void setSend(String send) {
- this.send = send;
- }
-
- public String getLocal() {
- return local;
- }
-
- public void setLocal(String local) {
- this.local = local;
- }
-
- public String getForeign() {
- return foreign;
- }
-
- public void setForeign(String foreign) {
- this.foreign = foreign;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/model/system/ProcessModel.java b/modules/agent/src/main/java/io/jpom/model/system/ProcessModel.java
deleted file mode 100644
index 846aecfdd9..0000000000
--- a/modules/agent/src/main/java/io/jpom/model/system/ProcessModel.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.model.system;
-
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.model.BaseJsonModel;
-
-import java.io.IOException;
-
-/**
- * 进程信息实体
- *
- * @author jiangzeyin
- * @date 2019/4/15
- */
-public class ProcessModel extends BaseJsonModel {
- /**
- * 进程id
- */
- private int pid;
- /**
- * 进程名
- */
- private String command;
- /**
- * 运行状态
- */
- private String status;
- /**
- * 进程仍然在使用的,没被交换出物理内存部分的大小
- */
- private String res;
- /**
- * 所有者
- */
- private String user;
- /**
- * 时间总计
- */
- private String time;
- /**
- * 优先级
- */
- private String pr = StrUtil.DASHED;
- /**
- * nice值
- */
- private String ni = StrUtil.DASHED;
- /**
- * 虚拟内存
- */
- private String virt = StrUtil.DASHED;
- /**
- * 共享内存大小
- */
- private String shr = StrUtil.DASHED;
- /**
- * 内存比重
- */
- private String mem = StrUtil.DASHED;
- /**
- * cpu比重
- */
- private String cpu = StrUtil.DASHED;
- /**
- * 端口
- */
- private String port = StrUtil.DASHED;
- /**
- * Jpom 项目名称
- */
- private String jpomName = StrUtil.DASHED;
-
- public String getPort() {
- return port;
- }
-
- public void setPort(String port) {
- this.port = port;
- }
-
- public String getJpomName() {
- return jpomName;
- }
-
- public void setJpomName(String jpomName) {
- this.jpomName = jpomName;
- }
-
- public int getPid() {
- return pid;
- }
-
- public void setPid(int pid) {
- this.pid = pid;
- if (pid > 0) {
- String port = AbstractProjectCommander.getInstance().getMainPort(pid);
- this.setPort(port);
- //
- try {
- String jpomName = AbstractProjectCommander.getInstance().getJpomNameByPid(pid);
- this.setJpomName(jpomName);
- } catch (IOException e) {
- DefaultSystemLog.getLog().error("解析进程失败", e);
- }
- }
- }
-
- public String getCommand() {
- return command;
- }
-
- public void setCommand(String command) {
- this.command = command;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public String getRes() {
- return res;
- }
-
- public void setRes(String res) {
- this.res = res;
- }
-
- public String getUser() {
- return user;
- }
-
- public void setUser(String user) {
- this.user = user;
- }
-
- public String getTime() {
- return time;
- }
-
- public void setTime(String time) {
- this.time = time;
- }
-
- public String getPr() {
- return pr;
- }
-
- public void setPr(String pr) {
- this.pr = pr;
- }
-
- public String getNi() {
- return ni;
- }
-
- public void setNi(String ni) {
- this.ni = ni;
- }
-
- public String getVirt() {
- return virt;
- }
-
- public void setVirt(String virt) {
- this.virt = virt;
- }
-
- public String getShr() {
- return shr;
- }
-
- public void setShr(String shr) {
- this.shr = shr;
- }
-
- public String getMem() {
- return mem;
- }
-
- public void setMem(String mem) {
- this.mem = mem;
- }
-
- public String getCpu() {
- return cpu;
- }
-
- public void setCpu(String cpu) {
- this.cpu = cpu;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/service/WhitelistDirectoryService.java b/modules/agent/src/main/java/io/jpom/service/WhitelistDirectoryService.java
deleted file mode 100644
index b91f04234d..0000000000
--- a/modules/agent/src/main/java/io/jpom/service/WhitelistDirectoryService.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.service;
-
-import cn.jiangzeyin.common.DefaultSystemLog;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.BaseDataService;
-import io.jpom.model.data.AgentWhitelist;
-import io.jpom.system.AgentConfigBean;
-import io.jpom.util.JsonFileUtil;
-import org.springframework.stereotype.Service;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 白名单服务
- *
- * @author jiangzeyin
- * @date 2019/2/28
- */
-@Service
-public class WhitelistDirectoryService extends BaseDataService {
-
- /**
- * 获取白名单信息配置、如何没有配置或者配置错误将返回新对象
- *
- * @return AgentWhitelist
- */
- public AgentWhitelist getWhitelist() {
- try {
- JSONObject jsonObject = getJSONObject(AgentConfigBean.WHITELIST_DIRECTORY);
- if (jsonObject == null) {
- return new AgentWhitelist();
- }
- return jsonObject.toJavaObject(AgentWhitelist.class);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error(e.getMessage(), e);
- }
- return new AgentWhitelist();
- }
-
- /**
- * 单项添加白名单
- *
- * @param item 白名单
- */
- public void addProjectWhiteList(String item) {
- AgentWhitelist agentWhitelist = getWhitelist();
- List project = agentWhitelist.getProject();
- if (project == null) {
- project = new ArrayList<>();
- }
- project.add(item);
- saveWhitelistDirectory(agentWhitelist);
- }
-
- public boolean isInstalled() {
- AgentWhitelist agentWhitelist = getWhitelist();
- List project = agentWhitelist.getProject();
- return project != null && !project.isEmpty();
- }
-
- private List getNgxDirectory() {
- AgentWhitelist agentWhitelist = getWhitelist();
- return agentWhitelist.getNginx();
- }
-
- public boolean checkProjectDirectory(String path) {
- AgentWhitelist agentWhitelist = getWhitelist();
-
- List list = agentWhitelist.getProject();
- return AgentWhitelist.checkPath(list, path);
- }
-
- public boolean checkNgxDirectory(String path) {
- List list = getNgxDirectory();
- return AgentWhitelist.checkPath(list, path);
- }
-
- private List getCertificateDirectory() {
- AgentWhitelist agentWhitelist = getWhitelist();
-
- return agentWhitelist.getCertificate();
- }
-
- public boolean checkCertificateDirectory(String path) {
- List list = getCertificateDirectory();
- if (list == null) {
- return false;
- }
- return AgentWhitelist.checkPath(list, path);
- }
-
- /**
- * 保存白名单
- *
- * @param jsonObject 实体
- */
- public void saveWhitelistDirectory(AgentWhitelist jsonObject) {
- String path = getDataFilePath(AgentConfigBean.WHITELIST_DIRECTORY);
- JsonFileUtil.saveJson(path, jsonObject.toJson());
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/service/manage/ConsoleService.java b/modules/agent/src/main/java/io/jpom/service/manage/ConsoleService.java
deleted file mode 100644
index b5ca0ff7bd..0000000000
--- a/modules/agent/src/main/java/io/jpom/service/manage/ConsoleService.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.service.manage;
-
-import cn.hutool.core.date.DateUtil;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.socket.ConsoleCommandOp;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-
-/**
- * 控制台
- * Created by jiangzeyin on 2018/9/28.
- *
- * @author jiangzeyin
- */
-@Service
-public class ConsoleService {
- @Resource
- private ProjectInfoService projectInfoService;
-
- /**
- * 执行shell命令
- *
- * @param consoleCommandOp 执行的操作
- * @param nodeProjectInfoModel 项目信息
- * @param copyItem 副本信息
- * @return 执行结果
- * @throws Exception 异常
- */
- public String execCommand(ConsoleCommandOp consoleCommandOp, NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem copyItem) throws Exception {
- String result;
- AbstractProjectCommander abstractProjectCommander = AbstractProjectCommander.getInstance();
- // 执行命令
- switch (consoleCommandOp) {
- case restart:
- result = abstractProjectCommander.restart(nodeProjectInfoModel, copyItem);
- break;
- case start:
- result = abstractProjectCommander.start(nodeProjectInfoModel, copyItem);
- break;
- case stop:
- result = abstractProjectCommander.stop(nodeProjectInfoModel, copyItem);
- break;
- case status: {
- result = abstractProjectCommander.status(nodeProjectInfoModel, copyItem);
- break;
- }
- case top:
- case showlog:
- default:
- throw new IllegalArgumentException(consoleCommandOp + " error");
- }
- // 通知日志刷新
- if (consoleCommandOp == ConsoleCommandOp.start || consoleCommandOp == ConsoleCommandOp.restart) {
- // 修改 run lib 使用情况
- NodeProjectInfoModel modify = projectInfoService.getItem(nodeProjectInfoModel.getId());
- //
- if (copyItem != null) {
- NodeProjectInfoModel.JavaCopyItem copyItem1 = modify.findCopyItem(copyItem.getId());
- copyItem1.setModifyTime(DateUtil.now());
- }
- modify.setRunLibDesc(nodeProjectInfoModel.getUseLibDesc());
- try {
- projectInfoService.updateItem(modify);
- } catch (Exception ignored) {
- }
- }
- return result;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/service/manage/JdkInfoService.java b/modules/agent/src/main/java/io/jpom/service/manage/JdkInfoService.java
deleted file mode 100644
index 864297e084..0000000000
--- a/modules/agent/src/main/java/io/jpom/service/manage/JdkInfoService.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.service.manage;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.IdUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.system.JavaInfo;
-import cn.hutool.system.JavaRuntimeInfo;
-import io.jpom.common.BaseOperService;
-import io.jpom.model.data.JdkInfoModel;
-import io.jpom.system.AgentConfigBean;
-import org.springframework.stereotype.Service;
-
-/**
- * jdk 管理
- *
- * @author Arno
- * @date 2019/11/20
- */
-@Service
-public class JdkInfoService extends BaseOperService {
-
- public JdkInfoService() {
- super(AgentConfigBean.JDK_CONF);
- }
-
- /**
- * 使用中的jdk
- *
- * @return JdkInfoModel
- */
- private JdkInfoModel getDefaultJdk() {
- JavaRuntimeInfo info = new JavaRuntimeInfo();
- String homeDir = info.getHomeDir();
- String version = new JavaInfo().getVersion();
- if (StrUtil.isEmpty(homeDir) || StrUtil.isEmpty(version)) {
- return null;
- }
- String path = FileUtil.normalize(homeDir.replace("jre", ""));
- JdkInfoModel jdkInfoModel = new JdkInfoModel();
- jdkInfoModel.setId(IdUtil.fastUUID());
- jdkInfoModel.setVersion(version);
- jdkInfoModel.setPath(path);
- return jdkInfoModel;
- }
-
-}
diff --git a/modules/agent/src/main/java/io/jpom/service/manage/ProjectInfoService.java b/modules/agent/src/main/java/io/jpom/service/manage/ProjectInfoService.java
deleted file mode 100644
index 4667ef1f7e..0000000000
--- a/modules/agent/src/main/java/io/jpom/service/manage/ProjectInfoService.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.service.manage;
-
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import io.jpom.common.BaseAgentController;
-import io.jpom.common.BaseOperService;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.model.data.ProjectRecoverModel;
-import io.jpom.system.AgentConfigBean;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.io.File;
-
-/**
- * 项目管理
- *
- * @author jiangzeyin
- */
-@Service
-public class ProjectInfoService extends BaseOperService {
- @Resource
- private ProjectRecoverService projectRecoverService;
-
- public ProjectInfoService() {
- super(AgentConfigBean.PROJECT);
- }
-
-// public HashSet getAllGroup() {
-// //获取所有分组
-// List nodeProjectInfoModels = list();
-// HashSet hashSet = new HashSet<>();
-// if (nodeProjectInfoModels == null) {
-// return hashSet;
-// }
-// for (NodeProjectInfoModel nodeProjectInfoModel : nodeProjectInfoModels) {
-// hashSet.add(nodeProjectInfoModel.getGroup());
-// }
-// return hashSet;
-// }
-
-
- /**
- * 删除项目
- *
- * @param id 项目
- */
- @Override
- public void deleteItem(String id) {
- NodeProjectInfoModel projectInfo = getItem(id);
- String userId = BaseAgentController.getNowUserName();
- super.deleteItem(id);
- // 添加回收记录
- ProjectRecoverModel projectRecoverModel = new ProjectRecoverModel(projectInfo);
- projectRecoverModel.setDelUser(userId);
- projectRecoverService.addItem(projectRecoverModel);
- }
-
- /**
- * 修改项目信息
- *
- * @param projectInfo 项目信息
- */
- @Override
- public void updateItem(NodeProjectInfoModel projectInfo) {
- projectInfo.setModifyTime(DateUtil.now());
- String userName = BaseAgentController.getNowUserName();
- if (!StrUtil.DASHED.equals(userName)) {
- projectInfo.setModifyUser(userName);
- }
- super.updateItem(projectInfo);
- }
-
- @Override
- public void addItem(NodeProjectInfoModel nodeProjectInfoModel) {
- nodeProjectInfoModel.setCreateTime(DateUtil.now());
- super.addItem(nodeProjectInfoModel);
- }
-
- /**
- * 查看项目控制台日志文件大小
- *
- * @param nodeProjectInfoModel 项目
- * @param copyItem 副本
- * @return 文件大小
- */
- public String getLogSize(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem copyItem) {
- if (nodeProjectInfoModel == null) {
- return null;
- }
- File file = copyItem == null ? new File(nodeProjectInfoModel.getLog()) : nodeProjectInfoModel.getLog(copyItem);
- if (file.exists()) {
- long fileSize = file.length();
- if (fileSize <= 0) {
- return null;
- }
- return FileUtil.readableFileSize(fileSize);
- }
- return null;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/service/manage/ProjectRecoverService.java b/modules/agent/src/main/java/io/jpom/service/manage/ProjectRecoverService.java
deleted file mode 100644
index 68ad2336ee..0000000000
--- a/modules/agent/src/main/java/io/jpom/service/manage/ProjectRecoverService.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.service.manage;
-
-import cn.hutool.core.date.DateUtil;
-import io.jpom.common.BaseOperService;
-import io.jpom.model.data.ProjectRecoverModel;
-import io.jpom.system.AgentConfigBean;
-import org.springframework.stereotype.Service;
-
-/**
- * 项目管理
- *
- * @author jiangzeyin
- */
-@Service
-public class ProjectRecoverService extends BaseOperService {
-
- public ProjectRecoverService() {
- super(AgentConfigBean.PROJECT_RECOVER);
- }
-
-
- /**
- * 保存项目信息
- *
- * @param projectInfo 项目
- */
- @Override
- public void addItem(ProjectRecoverModel projectInfo) {
- projectInfo.setDelTime(DateUtil.now());
- // 保存
- super.addItem(projectInfo);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/service/manage/TomcatEditService.java b/modules/agent/src/main/java/io/jpom/service/manage/TomcatEditService.java
deleted file mode 100644
index 8e93fc136e..0000000000
--- a/modules/agent/src/main/java/io/jpom/service/manage/TomcatEditService.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.service.manage;
-
-import cn.hutool.core.date.DateUtil;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.BaseOperService;
-import io.jpom.model.data.TomcatInfoModel;
-import io.jpom.system.AgentConfigBean;
-import org.springframework.stereotype.Service;
-
-/**
- * @author lf
- */
-@Service
-public class TomcatEditService extends BaseOperService {
-
-
- public TomcatEditService() {
- super(AgentConfigBean.TOMCAT);
- }
-
-
- /**
- * 根据tomcat名称查询tomcat信息
- *
- * @param name tomcat的名称
- * @return tomcat信息
- */
- public TomcatInfoModel getItemByName(String name) {
- JSONObject allTomcat = getJSONObject(AgentConfigBean.TOMCAT);
-
- if (allTomcat == null) {
- return null;
- }
-
- JSONObject tomcat = null;
- for (String key : allTomcat.keySet()) {
- JSONObject object = allTomcat.getJSONObject(key);
- if (name.equals(object.getString("name"))) {
- tomcat = object;
- break;
- }
- }
-
- return JSONObject.toJavaObject(tomcat, TomcatInfoModel.class);
- }
-
- /**
- * 添加Tomcat
- *
- * @param tomcatInfoModel tomcat信息
- */
- @Override
- public void addItem(TomcatInfoModel tomcatInfoModel) {
- tomcatInfoModel.setCreateTime(DateUtil.now());
- super.addItem(tomcatInfoModel);
- }
-
-
- /**
- * 修改tomcat信息
- *
- * @param tomcatInfoModel tomcat信息
- */
- @Override
- public void updateItem(TomcatInfoModel tomcatInfoModel) {
- tomcatInfoModel.setModifyTime(DateUtil.now());
- super.updateItem(tomcatInfoModel);
-
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/service/manage/TomcatManageService.java b/modules/agent/src/main/java/io/jpom/service/manage/TomcatManageService.java
deleted file mode 100644
index c25ad3f2f4..0000000000
--- a/modules/agent/src/main/java/io/jpom/service/manage/TomcatManageService.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.service.manage;
-
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.http.HttpRequest;
-import cn.hutool.http.HttpResponse;
-import cn.hutool.http.HttpStatus;
-import cn.jiangzeyin.common.JsonMessage;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.controller.tomcat.TomcatOp;
-import io.jpom.model.data.TomcatInfoModel;
-import io.jpom.system.JpomRuntimeException;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-
-/**
- * @author bwcx_jzy
- * @date 2019/7/21
- */
-@Service
-public class TomcatManageService {
-
- @Resource
- private TomcatEditService tomcatEditService;
-
- /**
- * 查询tomcat状态
- *
- * @param id tomcat的id
- * @return tomcat状态0表示未运行,1表示运行中
- */
- public int getTomcatStatus(String id) {
- int result = 0;
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(id);
- String url = String.format("http://127.0.0.1:%d/", tomcatInfoModel.getPort());
- HttpRequest httpRequest = new HttpRequest(url);
- // 设置超时时间为3秒
- httpRequest.setConnectionTimeout(3000);
- try {
- HttpResponse httpResponse = httpRequest.execute();
- result = 1;
- } catch (Exception ignored) {
- }
-
- return result;
- }
-
- /**
- * 查询tomcat的项目列表
- *
- * @param id tomcat的id
- * @return tomcat的项目列表
- */
- public JSONArray getTomcatProjectList(String id) {
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(id);
- String body = tomcatCmd(tomcatInfoModel, "text/list");
-
- String[] result = body.replace(StrUtil.CRLF, "$")
- .replace("\n", "$")
- .split("\\$");
-
- JSONArray jsonArray = new JSONArray();
-
- for (int i = 1; i < result.length; i++) {
- String str = result[i];
- JSONObject jsonObject = new JSONObject();
- String[] strs = str.split(":");
- if (strs[0].endsWith("jpomAgent")) {
- continue;
- }
-
- jsonObject.put("path", StrUtil.SLASH.equals(strs[0]) ? "/ROOT" : strs[0]);
- jsonObject.put("status", strs[1]);
- jsonObject.put("session", strs[2]);
-
- jsonArray.add(jsonObject);
- }
-
- return jsonArray;
- }
-
- /**
- * 访问tomcat Url
- *
- * @param tomcatInfoModel tomcat信息
- * @param cmd 命令
- * @return 访问结果
- */
- private String tomcatCmd(TomcatInfoModel tomcatInfoModel, String cmd) {
- String url = String.format("http://127.0.0.1:%d/jpomAgent/%s", tomcatInfoModel.getPort(), cmd);
- HttpRequest httpRequest = new HttpRequest(url);
- // 设置超时时间为3秒
- httpRequest.setConnectionTimeout(3000);
- String body = "";
-
- try {
- HttpResponse httpResponse = httpRequest.execute();
- if (httpResponse.isOk()) {
- body = httpResponse.body();
- }
- if (httpResponse.getStatus() == HttpStatus.HTTP_NOT_FOUND) {
- // 没有插件
- tomcatInfoModel.initTomcat();
- throw new JpomRuntimeException("tomcat 未初始化,已经重新初始化请稍后再试");
- }
- } catch (JpomRuntimeException jpom) {
- throw jpom;
- } catch (Exception ignored) {
- }
-
- return body;
- }
-
- /**
- * tomcat项目管理
- *
- * @param id tomcat id
- * @param path 项目路径
- * @param tomcatOp 执行的操作 start=启动项目 stop=停止项目 relaod=重启项目
- * @return 操作结果
- */
- public JsonMessage tomcatProjectManage(String id, String path, TomcatOp tomcatOp) {
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(id);
- String result = tomcatCmd(tomcatInfoModel, String.format("text/%s?path=%s", tomcatOp.name(), path));
-
- if (result.startsWith("OK")) {
- return new JsonMessage(200, "操作成功");
- } else {
- return new JsonMessage(500, "操作失败:" + result);
- }
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/service/manage/package-info.java b/modules/agent/src/main/java/io/jpom/service/manage/package-info.java
deleted file mode 100644
index 52bef96375..0000000000
--- a/modules/agent/src/main/java/io/jpom/service/manage/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.service.manage;
\ No newline at end of file
diff --git a/modules/agent/src/main/java/io/jpom/service/script/ScriptServer.java b/modules/agent/src/main/java/io/jpom/service/script/ScriptServer.java
deleted file mode 100644
index 33cb07166c..0000000000
--- a/modules/agent/src/main/java/io/jpom/service/script/ScriptServer.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.service.script;
-
-import cn.hutool.core.io.FileUtil;
-import io.jpom.common.BaseOperService;
-import io.jpom.model.data.ScriptModel;
-import io.jpom.system.AgentConfigBean;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-
-/**
- * 脚本模板管理
- *
- * @author jiangzeyin
- * @date 2019/4/24
- */
-@Service
-public class ScriptServer extends BaseOperService {
-
- public ScriptServer() {
- super(AgentConfigBean.SCRIPT);
- }
-
- @Override
- public List list() {
- List scriptModels = super.list();
- if (scriptModels == null) {
- return null;
- }
- // 读取文件内容
- scriptModels.forEach(ScriptModel::readFileTime);
- return scriptModels;
- }
-
- @Override
- public ScriptModel getItem(String id) {
- ScriptModel scriptModel = super.getItem(id);
- if (scriptModel != null) {
- scriptModel.readFileContext();
- }
- return scriptModel;
- }
-
- @Override
- public void addItem(ScriptModel scriptModel) {
- super.addItem(scriptModel);
- scriptModel.saveFile();
- }
-
- @Override
- public void updateItem(ScriptModel scriptModel) {
- super.updateItem(scriptModel);
- scriptModel.saveFile();
- }
-
- @Override
- public void deleteItem(String id) {
- ScriptModel scriptModel = getItem(id);
- if (scriptModel != null) {
- FileUtil.del(scriptModel.getFile(true).getParentFile());
- }
- super.deleteItem(id);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/service/system/CertService.java b/modules/agent/src/main/java/io/jpom/service/system/CertService.java
deleted file mode 100644
index 1afd4ed4b6..0000000000
--- a/modules/agent/src/main/java/io/jpom/service/system/CertService.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.service.system;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import io.jpom.common.BaseOperService;
-import io.jpom.model.data.CertModel;
-import io.jpom.system.AgentConfigBean;
-import org.springframework.stereotype.Service;
-
-import java.io.File;
-
-/**
- * @author Arno
- */
-@Service
-public class CertService extends BaseOperService {
-
- public CertService() {
- super(AgentConfigBean.CERT);
- }
-
-
- /**
- * 删除证书
- *
- * @param id id
- */
- @Override
- public void deleteItem(String id) {
- CertModel certModel = getItem(id);
- if (certModel == null) {
- return;
- }
- String keyPath = certModel.getCert();
- super.deleteItem(id);
- if (StrUtil.isNotEmpty(keyPath)) {
- // 删除证书文件
- File parentFile = FileUtil.file(keyPath).getParentFile();
- FileUtil.del(parentFile);
- }
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/service/system/NginxService.java b/modules/agent/src/main/java/io/jpom/service/system/NginxService.java
deleted file mode 100644
index 5aaf6973b1..0000000000
--- a/modules/agent/src/main/java/io/jpom/service/system/NginxService.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.service.system;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.github.odiszapc.nginxparser.NgxBlock;
-import com.github.odiszapc.nginxparser.NgxConfig;
-import com.github.odiszapc.nginxparser.NgxEntry;
-import com.github.odiszapc.nginxparser.NgxParam;
-import io.jpom.common.BaseDataService;
-import io.jpom.model.data.AgentWhitelist;
-import io.jpom.service.WhitelistDirectoryService;
-import io.jpom.system.AgentConfigBean;
-import io.jpom.util.JsonFileUtil;
-import io.jpom.util.StringUtil;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.io.File;
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.List;
-
-/**
- * @author Arno
- */
-@Service
-public class NginxService extends BaseDataService {
-
- @Resource
- private WhitelistDirectoryService whitelistDirectoryService;
-
- public JSONArray list(String whitePath, String fileName) {
- AgentWhitelist agentWhitelist = whitelistDirectoryService.getWhitelist();
- if (agentWhitelist == null) {
- return null;
- }
- List ngxDirectory = agentWhitelist.getNginx();
- if (ngxDirectory == null) {
- return null;
- }
- File normalize = FileUtil.file(whitePath, fileName);
- File[] files = FileUtil.ls(normalize.getAbsolutePath());
- if (files == null || files.length <= 0) {
- return null;
- }
- JSONArray array = new JSONArray();
- for (File file : files) {
- String name = file.getName();
- JSONObject jsonObject = new JSONObject();
- jsonObject.put("path", whitePath);
- long time = file.lastModified();
- jsonObject.put("time", DateUtil.date(time).toString());
- jsonObject.put("name", name);
- jsonObject.put("relativePath", FileUtil.normalize(fileName + StrUtil.SLASH + name));
- if (file.isDirectory()) {
- continue;
-// if (FileUtil.isEmpty(file)) {
-// continue;
-// }
-// jsonObject.put("name", name + "【文件夹】");
-// jsonObject.put("isDirectory", true);
- } else {
- if (!name.endsWith(".conf")) {
- continue;
- }
- try {
- NgxConfig config = NgxConfig.read(file.getPath());
- List server = config.findAll(NgxBlock.class, "server");
- JSONObject data = findSeverName(server);
- if (data != null) {
- jsonObject.putAll(data);
- }
- } catch (IOException e) {
- DefaultSystemLog.getLog().error(e.getMessage(), e);
- }
- }
- array.add(jsonObject);
- }
- return array;
- }
-
- /**
- * 获取nginx树型图列表
- *
- * @return JSONArray
- */
- public JSONArray tree() {
- JSONArray treeArray = new JSONArray();
- AgentWhitelist agentWhitelist = whitelistDirectoryService.getWhitelist();
- if (agentWhitelist == null) {
- return treeArray;
- }
- List ngxDirectory = agentWhitelist.getNginx();
- if (ngxDirectory == null) {
- return treeArray;
- }
- for (String str : ngxDirectory) {
- JSONObject object = addChild(str, "");
- if (object != null) {
- object.put("title", str);
- //object.put("spread", true);
- treeArray.add(object);
- }
- }
- return treeArray;
- }
-
- /**
- * 扫描目录下所有nginx配置文件
- *
- * @param whitePath 白名单路径
- * @param fileName 文件路径
- */
- private JSONObject addChild(String whitePath, String fileName) {
- File parentFile = StrUtil.isNotEmpty(fileName) ? FileUtil.file(whitePath, fileName) : FileUtil.file(whitePath);
- if (!FileUtil.isDirectory(parentFile)) {
- return null;
- }
- String absolutePath = parentFile.getAbsolutePath();
- File[] files = FileUtil.ls(absolutePath);
- if (files == null || files.length <= 0) {
- return null;
- }
- JSONObject object = new JSONObject();
- String parentName = parentFile.getName();
- object.put("title", parentName);
- object.put("whitePath", whitePath);
- object.put("path", fileName);
- JSONArray array = new JSONArray();
- for (File file : files) {
- String name = StringUtil.delStartPath(file, whitePath, true);
- if (file.isDirectory()) {
- if (FileUtil.isEmpty(file)) {
- continue;
- }
- JSONObject child = addChild(whitePath, name);
- if (child != null) {
- array.add(child);
- }
- } else {
-// String fName = file.getName();
-// if (fName.endsWith(".conf")) {
-// JSONObject child = new JSONObject();
-// child.put("title", fName);
-// child.put("whitePath", whitePath);
-// child.put("path", name);
-// array.add(child);
-// }
- }
- }
- object.put("children", array);
- return object;
- }
-
- /**
- * 获取域名
- *
- * @param server server块
- * @return 域名
- */
- private JSONObject findSeverName(List server) {
- if (null == server) {
- return null;
- }
- JSONObject jsonObject = new JSONObject();
- HashSet serverNames = new HashSet<>();
- HashSet location = new HashSet<>();
- HashSet listen = new HashSet<>();
- for (NgxEntry ngxEntry : server) {
-
- NgxBlock ngxBlock = (NgxBlock) ngxEntry;
- NgxParam serverName = ngxBlock.findParam("server_name");
- if (null != serverName) {
- serverNames.add(serverName.getValue());
- }
- List locationAll = ngxBlock.findAll(NgxBlock.class, "location");
- if (locationAll != null) {
- locationAll.forEach(ngxEntry1 -> {
- NgxBlock ngxBlock1 = (NgxBlock) ngxEntry1;
- if (!StrUtil.SLASH.equals(ngxBlock1.getValue())) {
- return;
- }
- NgxParam locationMain = ngxBlock1.findParam("proxy_pass");
- if (locationMain == null) {
- locationMain = ngxBlock1.findParam("root");
- }
- if (locationMain == null) {
- locationMain = ngxBlock1.findParam("alias");
- }
- if (locationMain == null) {
- return;
- }
- location.add(locationMain.getValue());
- });
- }
- // 监听的端口
- NgxParam listenParm = ngxBlock.findParam("listen");
- if (listenParm != null) {
- listen.add(listenParm.getValue());
- }
- }
- jsonObject.put("serverCount", server.size());
- jsonObject.put("server_name", CollUtil.join(serverNames, StrUtil.COMMA));
- jsonObject.put("location", CollUtil.join(location, StrUtil.COMMA));
- jsonObject.put("listen", CollUtil.join(listen, StrUtil.COMMA));
- return jsonObject;
- }
-
-
- /**
- * 解析nginx
- *
- * @param path nginx路径
- */
- public JSONObject getItem(String path) {
- JSONObject jsonObject = new JSONObject();
- try {
- NgxConfig conf = NgxConfig.read(path);
- NgxParam cache = conf.findParam("http", "proxy_cache_path");
- if (cache != null) {
- String value = cache.getValue();
- String[] split = value.split(" ");
- jsonObject.put("cachePath", split[0].trim());
- String maxSize = split[3];
- String size = maxSize.substring("max_size=".length(), maxSize.length() - 1);
- jsonObject.put("cacheSize", size);
- String inactive = split[4];
- String time = inactive.substring("inactive=".length(), inactive.length() - 1);
- jsonObject.put("inactive", time);
- }
- List list = conf.findAll(NgxBlock.class, "server");
- if (list == null) {
- return jsonObject;
- }
- boolean main = true;
- for (NgxEntry ngxEntry : list) {
- NgxBlock block = (NgxBlock) ngxEntry;
- NgxParam certificate = block.findParam("ssl_certificate");
- NgxParam key = block.findParam("ssl_certificate_key");
- NgxParam listen = block.findParam("listen");
- NgxParam serverName = block.findParam("server_name");
- NgxParam location = block.findParam("location", "proxy_pass");
- if (certificate != null && main) {
- main = false;
- jsonObject.put("cert", certificate.getValue());
- jsonObject.put("key", key.getValue());
- jsonObject.put("port", listen.getValue());
- jsonObject.put("domain", serverName.getValue());
- jsonObject.put("location", location.getValue());
- }
- NgxParam rewrite = block.findParam("rewrite");
- if (rewrite != null) {
- jsonObject.put("convert", true);
- }
- if (main) {
- jsonObject.put("port", listen.getValue());
- jsonObject.put("domain", serverName.getValue());
- if (null != location) {
- jsonObject.put("location", location.getValue());
- }
- }
-
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().error(e.getMessage(), e);
- }
- return jsonObject;
- }
-
- /**
- * 获取nginx配置
- * name 修改后的服务名
- * status 状态:开启 open/ 关闭close
- */
- public JSONObject getNgxConf() {
- JSONObject object = getJSONObject(AgentConfigBean.NGINX_CONF);
- if (object == null) {
- object = new JSONObject();
- object.put("name", "nginx");
- save(object);
- }
- return object;
- }
-
-
- public String getServiceName() {
- JSONObject ngxConf = getNgxConf();
- return ngxConf.getString("name");
- }
-
- public void save(JSONObject object) {
- String dataFilePath = getDataFilePath(AgentConfigBean.NGINX_CONF);
- JsonFileUtil.saveJson(dataFilePath, object);
- }
-
-}
diff --git a/modules/agent/src/main/java/io/jpom/socket/AgentFileTailWatcher.java b/modules/agent/src/main/java/io/jpom/socket/AgentFileTailWatcher.java
deleted file mode 100644
index 67720e23e4..0000000000
--- a/modules/agent/src/main/java/io/jpom/socket/AgentFileTailWatcher.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.socket;
-
-import cn.hutool.core.io.FileUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import io.jpom.util.BaseFileTailWatcher;
-
-import javax.websocket.Session;
-import java.io.File;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * 文件跟随器
- *
- * @author jiangzeyin
- * @date 2019/3/16
- */
-public class AgentFileTailWatcher extends BaseFileTailWatcher {
- private static final ConcurrentHashMap> CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();
-
-
- private AgentFileTailWatcher(File logFile) throws IOException {
- super(logFile);
- }
-
- public static int getOneLineCount() {
- return CONCURRENT_HASH_MAP.size();
- }
-
- /**
- * 添加文件监听
- *
- * @param file 文件
- * @param session 会话
- * @throws IOException 异常
- */
- public static void addWatcher(File file, Session session) throws IOException {
- if (!file.exists() || file.isDirectory()) {
- DefaultSystemLog.getLog().warn("文件不存在或者是目录:" + file.getPath());
- return;
- }
- AgentFileTailWatcher agentFileTailWatcher = CONCURRENT_HASH_MAP.computeIfAbsent(file, s -> {
- try {
- return new AgentFileTailWatcher<>(file);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("创建文件监听失败", e);
- return null;
- }
- });
- if (agentFileTailWatcher == null) {
- throw new IOException("加载文件失败:" + file.getPath());
- }
- agentFileTailWatcher.add(session, FileUtil.getName(file));
- agentFileTailWatcher.tailWatcherRun.start();
- }
-
- /**
- * 有客户端离线
- *
- * @param session 会话
- */
- public static void offline(Session session) {
- Collection> collection = CONCURRENT_HASH_MAP.values();
- for (AgentFileTailWatcher agentFileTailWatcher : collection) {
- agentFileTailWatcher.socketSessions.removeIf(session::equals);
- if (agentFileTailWatcher.socketSessions.isEmpty()) {
- agentFileTailWatcher.close();
- }
- }
- }
-
- /**
- * 关闭文件读取流
- *
- * @param fileName 文件名
- */
- public static void offlineFile(File fileName) {
- AgentFileTailWatcher agentFileTailWatcher = CONCURRENT_HASH_MAP.get(fileName);
- if (null == agentFileTailWatcher) {
- return;
- }
- Set socketSessions = agentFileTailWatcher.socketSessions;
- for (Session socketSession : socketSessions) {
- offline(socketSession);
- }
- agentFileTailWatcher.close();
- }
-
- /**
- * 关闭文件读取流
- *
- * @param fileName 文件名
- */
- static void offlineFile(File fileName, Session session) {
- AgentFileTailWatcher agentFileTailWatcher = CONCURRENT_HASH_MAP.get(fileName);
- if (null == agentFileTailWatcher) {
- return;
- }
- Set socketSessions = agentFileTailWatcher.socketSessions;
- for (Session socketSession : socketSessions) {
- if (socketSession.equals(session)) {
- offline(socketSession);
- break;
- }
- }
- if (agentFileTailWatcher.socketSessions.isEmpty()) {
- agentFileTailWatcher.close();
- }
-
- }
-
-
- /**
- * 关闭
- */
- @Override
- protected void close() {
- super.close();
- // 清理线程记录
- CONCURRENT_HASH_MAP.remove(this.logFile);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketConfig.java b/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketConfig.java
deleted file mode 100644
index e4c16fa59f..0000000000
--- a/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketConfig.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.socket;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.socket.server.standard.ServerEndpointExporter;
-
-/**
- * 插件端socket 配置
- *
- * @author jiangzeyin
- * @date 2019/4/19
- */
-@Configuration
-public class AgentWebSocketConfig {
-
- @Bean
- public ServerEndpointExporter serverEndpointExporter() {
- return new ServerEndpointExporter();
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketConsoleHandle.java b/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketConsoleHandle.java
deleted file mode 100644
index 5c4711e0e6..0000000000
--- a/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketConsoleHandle.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.socket;
-
-import cn.hutool.core.exceptions.ExceptionUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.common.spring.SpringUtil;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.JpomApplication;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.service.manage.ConsoleService;
-import io.jpom.service.manage.ProjectInfoService;
-import io.jpom.util.SocketSessionUtil;
-import org.springframework.stereotype.Component;
-
-import javax.websocket.*;
-import javax.websocket.server.ServerEndpoint;
-import java.io.File;
-import java.io.IOException;
-
-/**
- * 插件端,控制台socket
- *
- * @author jiangzeyin
- * @date 2019/4/16
- */
-@ServerEndpoint(value = "/console")
-@Component
-public class AgentWebSocketConsoleHandle extends BaseAgentWebSocketHandle {
-
- private static ProjectInfoService projectInfoService;
-
- @OnOpen
- public void onOpen(Session session) {
- try {
- if (super.checkAuthorize(session)) {
- return;
- }
- String projectId = super.getParameters(session, "projectId");
- String copyId = super.getParameters(session, "copyId");
- // 判断项目
- if (!JpomApplication.SYSTEM_ID.equals(projectId)) {
- if (projectInfoService == null) {
- projectInfoService = SpringUtil.getBean(ProjectInfoService.class);
- }
- NodeProjectInfoModel nodeProjectInfoModel = this.checkProject(projectId, copyId, session);
- if (nodeProjectInfoModel == null) {
- return;
- }
- //
- SocketSessionUtil.send(session, "连接成功:" + nodeProjectInfoModel.getName());
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("socket 错误", e);
- try {
- SocketSessionUtil.send(session, JsonMessage.getString(500, "系统错误!"));
- session.close();
- } catch (IOException e1) {
- DefaultSystemLog.getLog().error(e1.getMessage(), e1);
- }
- }
- }
-
- /**
- * 静默消息不做过多处理
- *
- * @param consoleCommandOp 操作
- * @param session 回话
- * @return true
- */
- private boolean silentMsg(ConsoleCommandOp consoleCommandOp, Session session) {
- if (consoleCommandOp == ConsoleCommandOp.heart) {
- return true;
- }
-// if (consoleCommandOp == ConsoleCommandOp.top) {
-// TopManager.addMonitor(session);
-// return true;
-// }
- return false;
- }
-
- private NodeProjectInfoModel checkProject(String projectId, String copyId, Session session) throws IOException {
- NodeProjectInfoModel nodeProjectInfoModel = projectInfoService.getItem(projectId);
- if (nodeProjectInfoModel == null) {
- SocketSessionUtil.send(session, "没有对应项目");
- session.close();
- return null;
- }
- // 判断副本集
- if (StrUtil.isNotEmpty(copyId)) {
- NodeProjectInfoModel.JavaCopyItem copyItem = nodeProjectInfoModel.findCopyItem(copyId);
- if (copyItem == null) {
- SocketSessionUtil.send(session, "获取项目信息错误,没有对应副本:" + copyId);
- session.close();
- return null;
- }
- }
- return nodeProjectInfoModel;
- }
-
- @OnMessage
- public void onMessage(String message, Session session) throws Exception {
- JSONObject json = JSONObject.parseObject(message);
- String op = json.getString("op");
- ConsoleCommandOp consoleCommandOp = ConsoleCommandOp.valueOf(op);
- if (silentMsg(consoleCommandOp, session)) {
- return;
- }
- String projectId = json.getString("projectId");
- String copyId = json.getString("copyId");
- NodeProjectInfoModel nodeProjectInfoModel = this.checkProject(projectId, copyId, session);
- if (nodeProjectInfoModel == null) {
- return;
- }
- runMsg(consoleCommandOp, session, nodeProjectInfoModel, copyId, json);
- }
-
- private void runMsg(ConsoleCommandOp consoleCommandOp, Session session, NodeProjectInfoModel nodeProjectInfoModel, String copyId, JSONObject reqJson) throws Exception {
- ConsoleService consoleService = SpringUtil.getBean(ConsoleService.class);
- //
- NodeProjectInfoModel.JavaCopyItem copyItem = nodeProjectInfoModel.findCopyItem(copyId);
- JSONObject resultData = null;
- String strResult;
- boolean logUser = false;
- try {
- // 执行相应命令
- switch (consoleCommandOp) {
- case start:
- case restart:
- logUser = true;
- strResult = consoleService.execCommand(consoleCommandOp, nodeProjectInfoModel, copyItem);
- if (strResult.contains(AbstractProjectCommander.RUNNING_TAG)) {
- resultData = JsonMessage.toJson(200, "操作成功:" + strResult);
- } else {
- resultData = JsonMessage.toJson(400, strResult);
- }
- break;
- case stop:
- logUser = true;
- // 停止项目
- strResult = consoleService.execCommand(consoleCommandOp, nodeProjectInfoModel, copyItem);
- if (strResult.contains(AbstractProjectCommander.STOP_TAG)) {
- resultData = JsonMessage.toJson(200, "操作成功");
- } else {
- resultData = JsonMessage.toJson(500, strResult);
- }
- break;
- case status:
- // 获取项目状态
- strResult = consoleService.execCommand(consoleCommandOp, nodeProjectInfoModel, copyItem);
- if (strResult.contains(AbstractProjectCommander.RUNNING_TAG)) {
- resultData = JsonMessage.toJson(200, "运行中", strResult);
- } else {
- resultData = JsonMessage.toJson(404, "未运行", strResult);
- }
- break;
- case showlog: {
- // 进入管理页面后需要实时加载日志
- // 日志文件路径
- File file = copyItem == null ? new File(nodeProjectInfoModel.getLog()) : nodeProjectInfoModel.getLog(copyItem);
- try {
- AgentFileTailWatcher.addWatcher(file, session);
- } catch (IOException io) {
- DefaultSystemLog.getLog().error("监听日志变化", io);
- SocketSessionUtil.send(session, io.getMessage());
- }
- break;
- }
- default:
- resultData = JsonMessage.toJson(404, "不支持的方式:" + consoleCommandOp.name());
- break;
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("执行命令失败", e);
- SocketSessionUtil.send(session, "执行命令失败,详情如下:");
- SocketSessionUtil.send(session, ExceptionUtil.stacktraceToString(e));
- return;
- } finally {
- if (logUser) {
- // 记录操作人
- NodeProjectInfoModel newNodeProjectInfoModel = projectInfoService.getItem(nodeProjectInfoModel.getId());
- String name = getOptUserName(session);
- newNodeProjectInfoModel.setModifyUser(name);
- projectInfoService.updateItem(newNodeProjectInfoModel);
- }
- }
- // 返回数据
- if (resultData != null) {
- reqJson.putAll(resultData);
- DefaultSystemLog.getLog().info(reqJson.toString());
- SocketSessionUtil.send(session, reqJson.toString());
- }
- }
-
- @Override
- @OnClose
- public void onClose(Session session) {
- super.onClose(session);
- }
-
- @OnError
- @Override
- public void onError(Session session, Throwable thr) {
- super.onError(session, thr);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketScriptHandle.java b/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketScriptHandle.java
deleted file mode 100644
index 77bc247e1f..0000000000
--- a/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketScriptHandle.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.socket;
-
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.common.spring.SpringUtil;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.model.data.ScriptModel;
-import io.jpom.service.script.ScriptServer;
-import io.jpom.util.SocketSessionUtil;
-import org.springframework.stereotype.Component;
-
-import javax.websocket.*;
-import javax.websocket.server.ServerEndpoint;
-import java.io.IOException;
-
-/**
- * 脚本模板socket
- *
- * @author jiangzeyin
- * @date 2019/4/24
- */
-@ServerEndpoint(value = "/script_run")
-@Component
-public class AgentWebSocketScriptHandle extends BaseAgentWebSocketHandle {
-
- private ScriptServer scriptServer;
-
- @OnOpen
- public void onOpen(Session session) {
- if (scriptServer == null) {
- scriptServer = SpringUtil.getBean(ScriptServer.class);
- }
- try {
- if (super.checkAuthorize(session)) {
- return;
- }
- String id = this.getParameters(session, "id");
- if (StrUtil.isEmpty(id)) {
- SocketSessionUtil.send(session, "脚本模板未知");
- return;
- }
- ScriptModel scriptModel = scriptServer.getItem(id);
- if (scriptModel == null) {
- SocketSessionUtil.send(session, "没有找到对应的脚本模板");
- return;
- }
- SocketSessionUtil.send(session, "连接成功:" + scriptModel.getName());
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("socket 错误", e);
- try {
- SocketSessionUtil.send(session, JsonMessage.getString(500, "系统错误!"));
- session.close();
- } catch (IOException e1) {
- DefaultSystemLog.getLog().error(e1.getMessage(), e1);
- }
- }
- }
-
- @OnMessage
- public void onMessage(String message, Session session) throws Exception {
- JSONObject json = JSONObject.parseObject(message);
- String scriptId = json.getString("scriptId");
- ScriptModel scriptModel = scriptServer.getItem(scriptId);
- if (scriptModel == null) {
- SocketSessionUtil.send(session, "没有对应脚本模板:" + scriptId);
- session.close();
- return;
- }
- String op = json.getString("op");
- ConsoleCommandOp consoleCommandOp = ConsoleCommandOp.valueOf(op);
- switch (consoleCommandOp) {
- case start:
- String args = json.getString("args");
- ScriptProcessBuilder.addWatcher(scriptModel, args, session);
- break;
- case stop:
- ScriptProcessBuilder.stopRun(scriptModel);
- break;
- case heart:
- default:
- return;
- }
- // 记录操作人
- scriptModel = scriptServer.getItem(scriptId);
- String name = getOptUserName(session);
- scriptModel.setLastRunUser(name);
- scriptServer.updateItem(scriptModel);
- json.put("code", 200);
- json.put("msg", "执行成功");
- DefaultSystemLog.getLog().info(json.toString());
- SocketSessionUtil.send(session, json.toString());
- }
-
-
- @Override
- @OnClose
- public void onClose(Session session) {
- super.onClose(session);
- ScriptProcessBuilder.stopWatcher(session);
- }
-
- @OnError
- @Override
- public void onError(Session session, Throwable thr) {
- super.onError(session, thr);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketTomcatHandle.java b/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketTomcatHandle.java
deleted file mode 100644
index bc1ebf305f..0000000000
--- a/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketTomcatHandle.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.socket;
-
-import cn.hutool.core.exceptions.ExceptionUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.common.spring.SpringUtil;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.JpomApplication;
-import io.jpom.model.data.TomcatInfoModel;
-import io.jpom.service.manage.TomcatEditService;
-import io.jpom.system.WebAopLog;
-import io.jpom.util.SocketSessionUtil;
-import org.springframework.stereotype.Component;
-
-import javax.websocket.*;
-import javax.websocket.server.ServerEndpoint;
-import java.io.File;
-import java.io.IOException;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * 插件端,控制台socket
- *
- * @author jiangzeyin
- * @date 2019/4/16
- */
-@ServerEndpoint(value = "/tomcat_log")
-@Component
-public class AgentWebSocketTomcatHandle extends BaseAgentWebSocketHandle {
-
- private TomcatEditService tomcatEditService;
-
- private static final Map CACHE_FILE = new ConcurrentHashMap<>();
-
- @OnOpen
- public void onOpen(Session session) {
- try {
- if (super.checkAuthorize(session)) {
- return;
- }
- String tomcatId = super.getParameters(session, "tomcatId");
- if (tomcatEditService == null) {
- tomcatEditService = SpringUtil.getBean(TomcatEditService.class);
- }
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(tomcatId);
- if (tomcatInfoModel == null && !JpomApplication.SYSTEM_ID.equalsIgnoreCase(tomcatId)) {
- SocketSessionUtil.send(session, "获取tomcat信息错误");
- session.close();
- return;
- }
- SocketSessionUtil.send(session, "连接成功:" + (tomcatInfoModel == null ? "" : tomcatInfoModel.getName()));
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("socket 错误", e);
- try {
- SocketSessionUtil.send(session, JsonMessage.getString(500, "系统错误!"));
- session.close();
- } catch (IOException e1) {
- DefaultSystemLog.getLog().error(e1.getMessage(), e1);
- }
- }
- }
-
- @OnMessage
- public void onMessage(String message, Session session) throws Exception {
- JSONObject json = JSONObject.parseObject(message);
- String op = json.getString("op");
- ConsoleCommandOp consoleCommandOp = ConsoleCommandOp.valueOf(op);
- if (consoleCommandOp == ConsoleCommandOp.heart) {
- return;
- }
- String tomcatId = json.getString("tomcatId");
- if (JpomApplication.SYSTEM_ID.equalsIgnoreCase(tomcatId)) {
- runMsg(session, json);
- } else {
- TomcatInfoModel tomcatInfoModel = tomcatEditService.getItem(tomcatId);
- if (tomcatInfoModel == null) {
- SocketSessionUtil.send(session, "没有对应tomcat");
- session.close();
- return;
- }
- runMsg(session, tomcatInfoModel, json);
- }
- }
-
- private void runMsg(Session session, JSONObject reqJson) throws Exception {
- try {
- String fileName = reqJson.getString("fileName");
- WebAopLog webAopLog = SpringUtil.getBean(WebAopLog.class);
- // 进入管理页面后需要实时加载日志
- File file = FileUtil.file(webAopLog.getPropertyValue(), fileName);
- File file1 = CACHE_FILE.get(session.getId());
- if (file1 != null && !file1.equals(file)) {
- // 离线上一个日志
- AgentFileTailWatcher.offlineFile(file, session);
- }
- try {
- AgentFileTailWatcher.addWatcher(file, session);
- CACHE_FILE.put(session.getId(), file);
- } catch (IOException io) {
- DefaultSystemLog.getLog().error("监听日志变化", io);
- SocketSessionUtil.send(session, io.getMessage());
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("执行命令失败", e);
- SocketSessionUtil.send(session, "执行命令失败,详情如下:");
- SocketSessionUtil.send(session, ExceptionUtil.stacktraceToString(e));
- }
- }
-
- private void runMsg(Session session, TomcatInfoModel tomcatInfoModel, JSONObject reqJson) throws Exception {
- try {
- String fileName = reqJson.getString("fileName");
- // 进入管理页面后需要实时加载日志
- File file = FileUtil.file(tomcatInfoModel.getPath(), "logs", fileName);
- try {
- AgentFileTailWatcher.addWatcher(file, session);
- } catch (IOException io) {
- DefaultSystemLog.getLog().error("监听日志变化", io);
- SocketSessionUtil.send(session, io.getMessage());
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("执行命令失败", e);
- SocketSessionUtil.send(session, "执行命令失败,详情如下:");
- SocketSessionUtil.send(session, ExceptionUtil.stacktraceToString(e));
- }
- }
-
- @Override
- @OnClose
- public void onClose(Session session) {
- super.onClose(session);
- }
-
- @OnError
- @Override
- public void onError(Session session, Throwable thr) {
- super.onError(session, thr);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketUpdateHandle.java b/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketUpdateHandle.java
deleted file mode 100644
index 1e50a926e4..0000000000
--- a/modules/agent/src/main/java/io/jpom/socket/AgentWebSocketUpdateHandle.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.socket;
-
-import cn.hutool.core.lang.Tuple;
-import cn.hutool.http.HttpStatus;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.JpomApplication;
-import io.jpom.common.Const;
-import io.jpom.common.JpomManifest;
-import io.jpom.common.Type;
-import io.jpom.model.AgentFileModel;
-import io.jpom.model.WebSocketMessageModel;
-import io.jpom.model.data.UploadFileModel;
-import io.jpom.system.AgentConfigBean;
-import io.jpom.util.SocketSessionUtil;
-import org.springframework.stereotype.Component;
-
-import javax.websocket.*;
-import javax.websocket.server.ServerEndpoint;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 在线升级
- *
- * @author bwcx_jzy
- * @date 2021/8/3
- */
-@ServerEndpoint(value = "/node_update")
-@Component
-public class AgentWebSocketUpdateHandle extends BaseAgentWebSocketHandle {
-
- private static final Map UPLOAD_FILE_INFO = new HashMap<>();
-
- @OnOpen
- public void onOpen(Session session) {
- if (super.checkAuthorize(session)) {
- return;
- }
- session.setMaxBinaryMessageBufferSize(1024 * 1024);
- //
- }
-
-
- @OnMessage
- public void onMessage(String message, Session session) throws Exception {
- WebSocketMessageModel model = WebSocketMessageModel.getInstance(message);
- switch (model.getCommand()) {
- case "getVersion":
- model.setData(JSONObject.toJSONString(JpomManifest.getInstance()));
- break;
- case "upload":
- AgentFileModel agentFileModel = ((JSONObject) model.getParams()).toJavaObject(AgentFileModel.class);
- UploadFileModel uploadFileModel = new UploadFileModel();
- uploadFileModel.setId(model.getNodeId());
- uploadFileModel.setName(agentFileModel.getName());
- uploadFileModel.setSize(agentFileModel.getSize());
- uploadFileModel.setVersion(agentFileModel.getVersion());
- uploadFileModel.setSavePath(AgentConfigBean.getInstance().getTempPath().getAbsolutePath());
- uploadFileModel.remove();
- UPLOAD_FILE_INFO.put(session.getId(), uploadFileModel);
- break;
- case "restart":
- model.setData(restart(session));
- break;
- default:
- break;
- }
- SocketSessionUtil.send(session, model.toString());
- //session.sendMessage(new TextMessage(model.toString()));
- }
-
- @OnMessage
- public void onMessage(byte[] message, Session session) throws Exception {
- UploadFileModel uploadFileModel = UPLOAD_FILE_INFO.get(session.getId());
- uploadFileModel.save(message);
- // 更新进度
- WebSocketMessageModel model = new WebSocketMessageModel("updateNode", uploadFileModel.getId());
- model.setData(uploadFileModel);
- SocketSessionUtil.send(session, model.toString());
-// session.sendMessage(new TextMessage(model.toString()));
- }
-
- /**
- * 重启
- *
- * @param session 回话
- * @return 结果
- */
- public String restart(Session session) {
- String result = Const.UPGRADE_MSG;
- try {
- UploadFileModel uploadFile = UPLOAD_FILE_INFO.get(session.getId());
- String filePath = uploadFile.getFilePath();
- JsonMessage error = JpomManifest.checkJpomJar(filePath, Type.Agent);
- if (error.getCode() != HttpStatus.HTTP_OK) {
- return error.getMsg();
- }
- JpomManifest.releaseJar(filePath, uploadFile.getVersion(), true);
- JpomApplication.restart();
- } catch (RuntimeException e) {
- result = "重启失败" + e.getMessage();
- DefaultSystemLog.getLog().error("重启失败", e);
- }
- return result;
- }
-
- @Override
- @OnClose
- public void onClose(Session session) {
- super.onClose(session);
- UPLOAD_FILE_INFO.remove(session.getId());
- }
-
- @OnError
- @Override
- public void onError(Session session, Throwable thr) {
- super.onError(session, thr);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/socket/BaseAgentWebSocketHandle.java b/modules/agent/src/main/java/io/jpom/socket/BaseAgentWebSocketHandle.java
deleted file mode 100644
index a3ae3df0ab..0000000000
--- a/modules/agent/src/main/java/io/jpom/socket/BaseAgentWebSocketHandle.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.socket;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.exceptions.ExceptionUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.core.util.URLUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import io.jpom.system.AgentAuthorize;
-import io.jpom.system.ConfigBean;
-import io.jpom.util.SocketSessionUtil;
-
-import javax.websocket.CloseReason;
-import javax.websocket.Session;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import static javax.websocket.CloseReason.CloseCodes.CANNOT_ACCEPT;
-
-/**
- * 插件端socket 基类
- *
- * @author jiangzeyin
- * @date 2019/4/24
- */
-public abstract class BaseAgentWebSocketHandle {
-
- private static final ConcurrentHashMap USER = new ConcurrentHashMap<>();
-
- protected String getParameters(Session session, String name) {
- Map> pathParameters = session.getRequestParameterMap();
- List strings = pathParameters.get(name);
- return CollUtil.join(strings, StrUtil.COMMA);
- }
-
- /**
- * 判断授权信息是否正确
- *
- * @param session session
- * @return true 需要结束回话
- */
- public boolean checkAuthorize(Session session) {
- String authorize = this.getParameters(session, ConfigBean.JPOM_AGENT_AUTHORIZE);
- boolean ok = AgentAuthorize.getInstance().checkAuthorize(authorize);
- if (!ok) {
- try {
- session.close(new CloseReason(CANNOT_ACCEPT, "授权信息错误"));
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("socket 错误", e);
- }
- return true;
- }
- this.addUser(session, this.getParameters(session, "optUser"));
- return false;
- }
-
- /**
- * 添加用户监听的
- *
- * @param session session
- * @param name 用户名
- */
- private void addUser(Session session, String name) {
- String optUser = URLUtil.decode(name);
- USER.put(session.getId(), optUser);
- }
-
- public void onError(Session session, Throwable thr) {
- // java.io.IOException: Broken pipe
- try {
- SocketSessionUtil.send(session, "服务端发生异常" + ExceptionUtil.stacktraceToString(thr));
- } catch (IOException ignored) {
- }
- DefaultSystemLog.getLog().error(session.getId() + "socket 异常", thr);
- }
-
- protected String getOptUserName(Session session) {
- String name = USER.get(session.getId());
- return StrUtil.emptyToDefault(name, StrUtil.DASHED);
- }
-
- public void onClose(Session session) {
- // 清理日志监听
- try {
- AgentFileTailWatcher.offline(session);
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("关闭异常", e);
- }
- // top
- // TopManager.removeMonitor(session);
- USER.remove(session.getId());
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/socket/ScriptProcessBuilder.java b/modules/agent/src/main/java/io/jpom/socket/ScriptProcessBuilder.java
deleted file mode 100644
index cf5349cdff..0000000000
--- a/modules/agent/src/main/java/io/jpom/socket/ScriptProcessBuilder.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.socket;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.IORuntimeException;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.io.LineHandler;
-import cn.hutool.core.thread.ThreadUtil;
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.system.SystemUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.JpomApplication;
-import io.jpom.model.data.ScriptModel;
-import io.jpom.util.CommandUtil;
-import io.jpom.util.SocketSessionUtil;
-
-import javax.websocket.Session;
-import java.io.*;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * 脚本执行
- *
- * @author jiangzeyin
- * @date 2019/4/25
- */
-public class ScriptProcessBuilder implements Runnable {
- private static final ConcurrentHashMap FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();
-
- private final ProcessBuilder processBuilder;
- private final Set sessions = new HashSet<>();
- private final File logFile;
- private final File scriptFile;
- private Process process;
- private InputStream inputStream;
- private InputStream errorInputStream;
-
- private ScriptProcessBuilder(ScriptModel scriptModel, String args) {
- this.logFile = scriptModel.logFile();
- this.scriptFile = scriptModel.getFile(true);
- //
- String script = FileUtil.getAbsolutePath(scriptFile);
- processBuilder = new ProcessBuilder();
- List command = StrUtil.splitTrim(args, StrUtil.SPACE);
- command.add(0, script);
- if (SystemUtil.getOsInfo().isLinux() || SystemUtil.getOsInfo().isMac()) {
- command.add(0, CommandUtil.SUFFIX);
- }
- DefaultSystemLog.getLog().info(CollUtil.join(command, StrUtil.SPACE));
- processBuilder.command(command);
- }
-
- public static void addWatcher(ScriptModel scriptModel, String args, Session session) {
- File file = scriptModel.getFile(true);
- ScriptProcessBuilder scriptProcessBuilder = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.computeIfAbsent(file, file1 -> {
- ScriptProcessBuilder scriptProcessBuilder1 = new ScriptProcessBuilder(scriptModel, args);
- ThreadUtil.execute(scriptProcessBuilder1);
- return scriptProcessBuilder1;
- });
- if (scriptProcessBuilder.sessions.add(session)) {
- if (FileUtil.exist(scriptProcessBuilder.logFile)) {
- // 读取之前的信息并发送
- FileUtil.readLines(scriptProcessBuilder.logFile, CharsetUtil.CHARSET_UTF_8, (LineHandler) line -> {
- try {
- SocketSessionUtil.send(session, line);
- } catch (IOException e) {
- DefaultSystemLog.getLog().error("发送消息失败", e);
- }
- });
- }
- }
- }
-
- public static void stopWatcher(Session session) {
- Collection scriptProcessBuilders = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.values();
- for (ScriptProcessBuilder scriptProcessBuilder : scriptProcessBuilders) {
- Set sessions = scriptProcessBuilder.sessions;
- sessions.removeIf(session1 -> session1.getId().equals(session.getId()));
- }
- }
-
- public static void stopRun(ScriptModel scriptModel) {
- File file = scriptModel.getFile(true);
- ScriptProcessBuilder scriptProcessBuilder = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.get(file);
- if (scriptProcessBuilder != null) {
- scriptProcessBuilder.end("停止运行");
- }
- }
-
- @Override
- public void run() {
- //初始化ProcessBuilder对象
- try {
- process = processBuilder.start();
- {
- inputStream = process.getInputStream();
- InputStreamReader inputStreamReader = new InputStreamReader(inputStream, JpomApplication.getCharset());
- BufferedReader results = new BufferedReader(inputStreamReader);
- IoUtil.readLines(results, (LineHandler) ScriptProcessBuilder.this::handle);
- }
- {
- errorInputStream = process.getErrorStream();
- InputStreamReader inputStreamReader = new InputStreamReader(errorInputStream, JpomApplication.getCharset());
- BufferedReader results = new BufferedReader(inputStreamReader);
- IoUtil.readLines(results, (LineHandler) line -> ScriptProcessBuilder.this.handle("ERROR:" + line));
- }
- JsonMessage jsonMessage = new JsonMessage<>(200, "执行完毕");
- JSONObject jsonObject = jsonMessage.toJson();
- jsonObject.put("op", ConsoleCommandOp.stop.name());
- this.end(jsonObject.toString());
- } catch (IORuntimeException ignored) {
-
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("执行异常", e);
- this.end("执行异常:" + e.getMessage());
- }
- }
-
- /**
- * 结束执行
- *
- * @param msg 响应的消息
- */
- private void end(String msg) {
- if (this.process != null) {
- // windows 中不能正常关闭
- this.process.destroy();
- IoUtil.close(inputStream);
- IoUtil.close(errorInputStream);
- }
- Iterator iterator = sessions.iterator();
- while (iterator.hasNext()) {
- Session session = iterator.next();
- try {
- SocketSessionUtil.send(session, msg);
- } catch (IOException e) {
- DefaultSystemLog.getLog().error("发送消息失败", e);
- }
- iterator.remove();
- }
- FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.remove(this.scriptFile);
- }
-
- /**
- * 响应
- *
- * @param line 信息
- */
- private void handle(String line) {
- // 写入文件
- List fileLine = new ArrayList<>();
- fileLine.add(line);
- FileUtil.appendLines(fileLine, logFile, CharsetUtil.CHARSET_UTF_8);
- Iterator iterator = sessions.iterator();
- while (iterator.hasNext()) {
- Session session = iterator.next();
- try {
- SocketSessionUtil.send(session, line);
- } catch (IOException e) {
- DefaultSystemLog.getLog().error("发送消息失败", e);
- iterator.remove();
- }
- }
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/socket/spring/WebSocketConfig.java b/modules/agent/src/main/java/io/jpom/socket/spring/WebSocketConfig.java
deleted file mode 100644
index 6634ff0fd6..0000000000
--- a/modules/agent/src/main/java/io/jpom/socket/spring/WebSocketConfig.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-//package io.jpom.socket.spring;
-//
-//import io.jpom.socket.spring.handler.NodeUpdateHandler;
-//import io.jpom.socket.spring.interceptor.NodeUpdateInterceptor;
-//import org.springframework.context.annotation.Configuration;
-//import org.springframework.web.socket.config.annotation.EnableWebSocket;
-//import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
-//import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
-//
-///**
-// * @author lf
-// */
-//@Configuration
-//@EnableWebSocket
-//public class WebSocketConfig implements WebSocketConfigurer {
-// private final NodeUpdateInterceptor nodeUpdateInterceptor = new NodeUpdateInterceptor();
-//
-// @Override
-// public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
-// // 节点升级
-// registry.addHandler(new NodeUpdateHandler(), "/node_update").addInterceptors(nodeUpdateInterceptor);
-// }
-//}
diff --git a/modules/agent/src/main/java/io/jpom/socket/spring/handler/NodeUpdateHandler.java b/modules/agent/src/main/java/io/jpom/socket/spring/handler/NodeUpdateHandler.java
deleted file mode 100644
index 950271580a..0000000000
--- a/modules/agent/src/main/java/io/jpom/socket/spring/handler/NodeUpdateHandler.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-//package io.jpom.socket.spring.handler;
-//
-//import cn.jiangzeyin.common.DefaultSystemLog;
-//import com.alibaba.fastjson.JSONObject;
-//import io.jpom.JpomApplication;
-//import io.jpom.common.JpomManifest;
-//import io.jpom.model.AgentFileModel;
-//import io.jpom.model.WebSocketMessageModel;
-//import io.jpom.model.data.UploadFileModel;
-//import io.jpom.system.AgentConfigBean;
-//import org.springframework.web.socket.BinaryMessage;
-//import org.springframework.web.socket.TextMessage;
-//import org.springframework.web.socket.WebSocketSession;
-//import org.springframework.web.socket.handler.AbstractWebSocketHandler;
-//
-//import java.util.HashMap;
-//import java.util.Map;
-//
-///**
-// * 节点升级websocket处理器
-// *
-// * @author lf
-// */
-//public class NodeUpdateHandler extends AbstractWebSocketHandler {
-// private static final Map UPLOAD_FILE_INFO = new HashMap<>();
-//
-// @Override
-// public void afterConnectionEstablished(WebSocketSession session) throws Exception {
-// // 设置二进制消息的最大长度为1M
-// session.setBinaryMessageSizeLimit(1024 * 1024);
-// }
-//
-// @Override
-// protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
-//
-// }
-//
-// @Override
-// protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
-// UploadFileModel uploadFileModel = UPLOAD_FILE_INFO.get(session.getId());
-// uploadFileModel.save(message.getPayload().array());
-// // 更新进度
-// WebSocketMessageModel model = new WebSocketMessageModel("updateNode", uploadFileModel.getId());
-// model.setData(uploadFileModel);
-// session.sendMessage(new TextMessage(model.toString()));
-// }
-//
-// /**
-// * 重启
-// *
-// * @param session
-// * @return
-// */
-// public String restart(WebSocketSession session) {
-// String result = "重启中";
-// try {
-// UploadFileModel uploadFile = UPLOAD_FILE_INFO.get(session.getId());
-// JpomManifest.releaseJar(uploadFile.getFilePath(), uploadFile.getVersion(), true);
-// JpomApplication.restart();
-// } catch (RuntimeException e) {
-// result = e.getMessage();
-// DefaultSystemLog.getLog().error("重启失败", e);
-// }
-// return result;
-// }
-//}
diff --git a/modules/agent/src/main/java/io/jpom/socket/spring/interceptor/NodeUpdateInterceptor.java b/modules/agent/src/main/java/io/jpom/socket/spring/interceptor/NodeUpdateInterceptor.java
deleted file mode 100644
index dfb63140bf..0000000000
--- a/modules/agent/src/main/java/io/jpom/socket/spring/interceptor/NodeUpdateInterceptor.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-//package io.jpom.socket.spring.interceptor;
-//
-//import cn.jiangzeyin.common.DefaultSystemLog;
-//import io.jpom.system.AgentAuthorize;
-//import org.springframework.http.server.ServerHttpRequest;
-//import org.springframework.http.server.ServerHttpResponse;
-//import org.springframework.http.server.ServletServerHttpRequest;
-//import org.springframework.web.socket.WebSocketHandler;
-//import org.springframework.web.socket.server.HandshakeInterceptor;
-//
-//import javax.servlet.http.HttpServletRequest;
-//import java.util.Map;
-//
-///**
-// * @author lf
-// */
-//public class NodeUpdateInterceptor implements HandshakeInterceptor {
-// @Override
-// public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler webSocketHandler, Map map) throws Exception {
-// if (request instanceof ServletServerHttpRequest) {
-// ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
-// HttpServletRequest httpServletRequest = serverHttpRequest.getServletRequest();
-// // 判断用户
-// String name = httpServletRequest.getParameter("name");
-// String password = httpServletRequest.getParameter("password");
-//
-// AgentAuthorize authorize = AgentAuthorize.getInstance();
-// return authorize.getAgentName().equals(name) && authorize.getAgentPwd().equals(password);
-// }
-// return false;
-// }
-//
-// @Override
-// public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception exception) {
-// if (exception != null) {
-// DefaultSystemLog.getLog().error("afterHandshake", exception);
-// }
-// }
-//}
diff --git a/modules/agent/src/main/java/io/jpom/system/AgentAuthorize.java b/modules/agent/src/main/java/io/jpom/system/AgentAuthorize.java
deleted file mode 100644
index d4403017dd..0000000000
--- a/modules/agent/src/main/java/io/jpom/system/AgentAuthorize.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.system;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.lang.Console;
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.RandomUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.SecureUtil;
-import cn.jiangzeyin.common.spring.SpringUtil;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.model.system.AgentAutoUser;
-import io.jpom.util.JsonFileUtil;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * agent 端授权账号信息
- *
- * @author jiangzeyin
- * @date 2019/4/17
- */
-@Configuration
-public class AgentAuthorize {
-
- private static AgentAuthorize agentAuthorize;
- /**
- * 账号
- */
- @Value("${" + ConfigBean.AUTHORIZE_USER_KEY + "}")
- private String agentName;
- /**
- * 密码
- */
- @Value("${" + ConfigBean.AUTHORIZE_AUTHORIZE_KEY + ":}")
- private String agentPwd;
- /**
- * 授权加密字符串
- */
- private String authorize;
-
- /**
- * 单例
- *
- * @return this
- */
- public static AgentAuthorize getInstance() {
- if (agentAuthorize == null) {
- agentAuthorize = SpringUtil.getBean(AgentAuthorize.class);
- // 登录名不能为空
- if (StrUtil.isEmpty(agentAuthorize.agentName)) {
- throw new JpomRuntimeException("agent 端登录名不能为空");
- }
- agentAuthorize.checkPwd();
- // 生成密码授权字符串
- agentAuthorize.authorize = SecureUtil.sha1(agentAuthorize.agentName + "@" + agentAuthorize.agentPwd);
- }
- return agentAuthorize;
- }
-
- public String getAgentName() {
- return agentName;
- }
-
- public String getAgentPwd() {
- return agentPwd;
- }
-
- /**
- * 判断授权是否正确
- *
- * @param authorize 授权
- * @return true 正确
- */
- public boolean checkAuthorize(String authorize) {
- return StrUtil.equals(authorize, this.authorize);
- }
-
- /**
- * 检查是否配置密码
- */
- private void checkPwd() {
- String path = ConfigBean.getInstance().getAgentAutoAuthorizeFile(ConfigBean.getInstance().getDataPath());
- if (StrUtil.isNotEmpty(agentPwd)) {
- // 有指定密码 清除旧密码信息
- FileUtil.del(path);
- Console.log("已经自定义配置授权信息啦,账号:{}", this.agentName);
- return;
- }
- if (FileUtil.exist(path)) {
- // 读取旧密码
- try {
- String json = FileUtil.readString(path, CharsetUtil.CHARSET_UTF_8);
- AgentAutoUser autoUser = JSONObject.parseObject(json, AgentAutoUser.class);
- String oldAgentPwd = autoUser.getAgentPwd();
- if (!StrUtil.equals(autoUser.getAgentName(), this.agentName)) {
- throw new JpomRuntimeException("已经存在的登录名和配置的登录名不一致");
- }
- if (StrUtil.isNotEmpty(oldAgentPwd)) {
- this.agentPwd = oldAgentPwd;
- Console.log("已有授权账号:{} 密码:{} 授权信息保存位置:{}", this.agentName, this.agentPwd, FileUtil.getAbsolutePath(path));
- return;
- }
- } catch (JpomRuntimeException e) {
- throw e;
- } catch (Exception ignored) {
- }
- }
- this.agentPwd = RandomUtil.randomString(10);
- AgentAutoUser autoUser = new AgentAutoUser();
- autoUser.setAgentName(this.agentName);
- autoUser.setAgentPwd(this.agentPwd);
- // 写入文件中
- JsonFileUtil.saveJson(path, autoUser.toJson());
- Console.log("已经自动生成授权账号:{} 密码:{} 授权信息保存位置:{}", this.agentName, this.agentPwd, FileUtil.getAbsolutePath(path));
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/system/AgentConfigBean.java b/modules/agent/src/main/java/io/jpom/system/AgentConfigBean.java
deleted file mode 100644
index 89faee7af5..0000000000
--- a/modules/agent/src/main/java/io/jpom/system/AgentConfigBean.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.system;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.spring.SpringUtil;
-import io.jpom.common.BaseAgentController;
-import org.springframework.context.annotation.Configuration;
-
-import java.io.File;
-
-/**
- * 插件端配置
- *
- * @author jiangzeyin
- * @date 2019/4/16
- */
-@Configuration
-public class AgentConfigBean {
- /**
- * 白名单文件
- */
- public static final String WHITELIST_DIRECTORY = "whitelistDirectory.json";
- /**
- * 项目数据文件
- */
- public static final String PROJECT = "project.json";
-
- public static final String TOMCAT = "tomcat.json";
- /**
- * 项目回收文件
- */
- public static final String PROJECT_RECOVER = "project_recover.json";
- /**
- * 证书文件
- */
- public static final String CERT = "cert.json";
- /**
- * 脚本管理数据文件
- */
- public static final String SCRIPT = "script.json";
- /**
- * 脚本模板存放路径
- */
- public static final String SCRIPT_DIRECTORY = "script";
-
- /**
- * Server 端的信息
- */
- public static final String SERVER_ID = "SERVER.json";
-
- /**
- * nginx配置信息
- */
- public static final String NGINX_CONF = "nginx_conf.json";
-
- /**
- * jdk列表信息
- */
- public static final String JDK_CONF = "jdk_conf.json";
-
- private static AgentConfigBean agentConfigBean;
-
- /**
- * 单利模式
- *
- * @return config
- */
- public static AgentConfigBean getInstance() {
- if (agentConfigBean == null) {
- agentConfigBean = SpringUtil.getBean(AgentConfigBean.class);
- }
- return agentConfigBean;
- }
-
- /**
- * 获取当前登录用户的临时文件存储路径,如果没有登录则抛出异常
- *
- * @return 文件夹
- */
- public String getTempPathName() {
- File file = getTempPath();
- return FileUtil.normalize(file.getPath());
- }
-
- /**
- * 获取当前登录用户的临时文件存储路径,如果没有登录则抛出异常
- *
- * @return file
- */
- public File getTempPath() {
- File file = ConfigBean.getInstance().getTempPath();
- String userName = BaseAgentController.getNowUserName();
- if (StrUtil.isEmpty(userName)) {
- throw new JpomRuntimeException("没有登录");
- }
- file = new File(file, userName);
- FileUtil.mkdir(file);
- return file;
- }
-
- /**
- * 获取脚本模板路径
- *
- * @return file
- */
- public File getScriptPath() {
- return FileUtil.file(ConfigBean.getInstance().getDataPath(), SCRIPT_DIRECTORY);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/system/AgentExtConfigBean.java b/modules/agent/src/main/java/io/jpom/system/AgentExtConfigBean.java
deleted file mode 100644
index 3c5c2842ad..0000000000
--- a/modules/agent/src/main/java/io/jpom/system/AgentExtConfigBean.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.system;
-
-import cn.hutool.core.net.NetUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.SecureUtil;
-import cn.hutool.http.HttpRequest;
-import cn.hutool.http.HttpUtil;
-import cn.jiangzeyin.common.spring.SpringUtil;
-import io.jpom.common.ServerOpenApi;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * agent 端外部配置
- *
- * @author jiangzeyin
- * @date 2019/4/16
- */
-@Configuration
-public class AgentExtConfigBean {
-
- private static AgentExtConfigBean agentExtConfigBean;
- /**
- * 白名单路径是否判断包含关系
- */
- @Value("${whitelistDirectory.checkStartsWith:true}")
- public boolean whitelistDirectoryCheckStartsWith;
-
- /**
- * 自动备份控制台日志,防止日志文件过大,目前暂只支持linux 不停服备份 如果配置none 则不自动备份 默认10分钟扫描一次
- */
- @Value("${log.autoBackConsoleCron:0 0/10 * * * ?}")
- public String autoBackConsoleCron;
- /**
- * 当文件多大时自动备份
- *
- * @see ch.qos.logback.core.util.FileSize
- */
- @Value("${log.autoBackSize:50MB}")
- public String autoBackSize;
- /**
- * 控制台日志保存时长单位天
- */
- @Value("${log.saveDays:7}")
- private int logSaveDays;
-
- @Value("${jpom.agent.id:}")
- private String agentId;
-
- @Value("${jpom.agent.url:}")
- private String agentUrl;
-
- @Value("${jpom.server.url:}")
- private String serverUrl;
-
- @Value("${jpom.server.token:}")
- private String serverToken;
-
- /**
- * 项目状态禁用 调用jmx获取
- */
- @Value("${project.disableVirtualMachine:false}")
- private boolean disableVirtualMachine;
-
- /**
- * 停止项目等待的时长 单位秒,最小为1秒
- */
- @Value("${project.stopWaitTime:10}")
- private int stopWaitTime;
-
- public int getStopWaitTime() {
- return stopWaitTime;
- }
-
- public boolean isDisableVirtualMachine() {
- return disableVirtualMachine;
- }
-
- public String getAgentId() {
- return agentId;
- }
-
- public String getServerUrl() {
- return serverUrl;
- }
-
- public String getServerToken() {
- return serverToken;
- }
-
- /**
- * 获取当前的url
- *
- * @return 如果没有配置将自动生成:http://+本地IP+端口
- */
- public String getAgentUrl() {
- if (StrUtil.isEmpty(agentUrl)) {
- String localhostStr = NetUtil.getLocalhostStr();
- int port = ConfigBean.getInstance().getPort();
- agentUrl = String.format("http://%s:%s", localhostStr, port);
- }
- if (StrUtil.isEmpty(agentUrl)) {
- throw new JpomRuntimeException("获取Agent url失败");
- }
- return agentUrl;
- }
-
- /**
- * 创建请求对象
- *
- * @param openApi url
- * @return HttpRequest
- * @see ServerOpenApi
- */
- public HttpRequest createServerRequest(String openApi) {
- if (StrUtil.isEmpty(getServerUrl())) {
- throw new JpomRuntimeException("请先配置server端url");
- }
- if (StrUtil.isEmpty(getServerToken())) {
- throw new JpomRuntimeException("请先配置server端Token");
- }
- // 加密
- String md5 = SecureUtil.md5(getServerToken());
- md5 = SecureUtil.sha1(md5 + ServerOpenApi.HEAD);
- HttpRequest httpRequest = HttpUtil.createPost(String.format("%s%s", serverUrl, openApi));
- httpRequest.header(ServerOpenApi.HEAD, md5);
- return httpRequest;
- }
-
- /**
- * 配置错误或者没有,默认是7天
- *
- * @return int
- */
- public int getLogSaveDays() {
- if (logSaveDays <= 0) {
- return 7;
- }
- return logSaveDays;
- }
-
- /**
- * 是否开启日志备份
- *
- * @return 如果表达式配置为none 则不配置,重启也不备份
- */
- public boolean openLogBack() {
- String cron = StrUtil.emptyToDefault(autoBackConsoleCron, "none");
- return !"none".equalsIgnoreCase(cron.trim());
- }
-
- /**
- * 单例
- *
- * @return this
- */
- public static AgentExtConfigBean getInstance() {
- if (agentExtConfigBean == null) {
- agentExtConfigBean = SpringUtil.getBean(AgentExtConfigBean.class);
- }
- return agentExtConfigBean;
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/system/AgentLogbackConfig.java b/modules/agent/src/main/java/io/jpom/system/AgentLogbackConfig.java
new file mode 100644
index 0000000000..ee4afc8581
--- /dev/null
+++ b/modules/agent/src/main/java/io/jpom/system/AgentLogbackConfig.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package io.jpom.system;
+
+/**
+ * @author bwcx_jzy
+ * @since 2023/3/31
+ */
+@Deprecated
+public class AgentLogbackConfig extends org.dromara.jpom.system.AgentLogbackConfig {
+}
diff --git a/modules/agent/src/main/java/io/jpom/system/TopManager.java b/modules/agent/src/main/java/io/jpom/system/TopManager.java
deleted file mode 100644
index 870e39fb02..0000000000
--- a/modules/agent/src/main/java/io/jpom/system/TopManager.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.system;
-
-import cn.hutool.cache.impl.CacheObj;
-import cn.hutool.cache.impl.TimedCache;
-import cn.hutool.core.date.DateTime;
-import cn.hutool.core.date.DateUtil;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.commander.AbstractSystemCommander;
-
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.concurrent.TimeUnit;
-
-/**
- * top命令管理,保证整个服务器只获取一个top命令
- *
- * @author jiangzeyin
- * @date 2018/10/2
- */
-public class TopManager {
- /**
- * 最近30分钟监控数据
- */
- private static final TimedCache MONITOR_CACHE = new TimedCache<>(TimeUnit.MINUTES.toMillis(30), new LinkedHashMap<>());
-
- public static Iterator> get() {
- JSONObject topInfo = AbstractSystemCommander.getInstance().getAllMonitor();
- if (topInfo != null) {
- DateTime date = DateUtil.date();
- String time = DateUtil.formatTime(date);
- topInfo.put("time", time);
- topInfo.put("monitorTime", date.getTime());
- MONITOR_CACHE.put(time, topInfo);
- }
- return MONITOR_CACHE.cacheObjIterator();
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/system/init/AutoBackLog.java b/modules/agent/src/main/java/io/jpom/system/init/AutoBackLog.java
deleted file mode 100644
index e4d10abe71..0000000000
--- a/modules/agent/src/main/java/io/jpom/system/init/AutoBackLog.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.system.init;
-
-import ch.qos.logback.core.util.FileSize;
-import cn.hutool.core.date.DateTime;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.cron.CronUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.PreLoadClass;
-import cn.jiangzeyin.common.PreLoadMethod;
-import cn.jiangzeyin.common.spring.SpringUtil;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.service.manage.ProjectInfoService;
-import io.jpom.system.AgentExtConfigBean;
-import io.jpom.util.CronUtils;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * 自动备份控制台日志,防止日志文件过大
- *
- * @author jiangzeyin
- * @date 2019/3/17
- */
-@PreLoadClass
-public class AutoBackLog {
-
- private static final String ID = "auto_back_log";
- private static ProjectInfoService projectInfoService;
-
- private static FileSize MAX_SIZE;
-
- @PreLoadMethod
- private static void startAutoBackLog() {
- if (projectInfoService == null) {
- projectInfoService = SpringUtil.getBean(ProjectInfoService.class);
- }
- // 获取cron 表达式
- String cron = StrUtil.emptyToDefault(AgentExtConfigBean.getInstance().autoBackConsoleCron, "none");
- if ("none".equalsIgnoreCase(cron.trim())) {
- //DefaultSystemLog.getLog().info("没有配置自动备份控制台日志表达式");
- //return;
- cron = "0 0/10 * * * ?";
- }
- String size = StrUtil.emptyToDefault(AgentExtConfigBean.getInstance().autoBackSize, "50MB");
- MAX_SIZE = FileSize.valueOf(size.trim());
- //
- CronUtil.schedule(ID, cron, () -> {
- try {
- List list = projectInfoService.list();
- if (list == null) {
- return;
- }
- list.forEach(projectInfoModel -> {
- checkProject(projectInfoModel, null);
- //
- List javaCopyItemList = projectInfoModel.getJavaCopyItemList();
- if (javaCopyItemList == null) {
- return;
- }
- javaCopyItemList.forEach(javaCopyItem -> checkProject(projectInfoModel, javaCopyItem));
- });
- } catch (Exception e) {
- DefaultSystemLog.getLog().error("定时备份日志失败", e);
- }
- });
- CronUtils.start();
- }
-
- private static void checkProject(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel.JavaCopyItem javaCopyItem) {
- File file = javaCopyItem == null ? new File(nodeProjectInfoModel.getLog()) : nodeProjectInfoModel.getLog(javaCopyItem);
- if (!file.exists()) {
- return;
- }
- long len = file.length();
- if (len > MAX_SIZE.getSize()) {
- try {
- AbstractProjectCommander.getInstance().backLog(nodeProjectInfoModel, javaCopyItem);
- } catch (Exception ignored) {
- }
- }
- // 清理过期的文件
- File logFile = javaCopyItem == null ? nodeProjectInfoModel.getLogBack() : nodeProjectInfoModel.getLogBack(javaCopyItem);
- DateTime nowTime = DateTime.now();
- List files = FileUtil.loopFiles(logFile, pathname -> {
- DateTime dateTime = DateUtil.date(pathname.lastModified());
- long days = DateUtil.betweenDay(dateTime, nowTime, false);
- long saveDays = AgentExtConfigBean.getInstance().getLogSaveDays();
- return days > saveDays;
- });
- files.forEach(FileUtil::del);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/system/init/AutoRegSeverNode.java b/modules/agent/src/main/java/io/jpom/system/init/AutoRegSeverNode.java
deleted file mode 100644
index 9892b0e099..0000000000
--- a/modules/agent/src/main/java/io/jpom/system/init/AutoRegSeverNode.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.system.init;
-
-import cn.hutool.core.date.DateTime;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.core.util.URLUtil;
-import cn.hutool.http.HttpRequest;
-import cn.hutool.http.HttpStatus;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.JsonMessage;
-import cn.jiangzeyin.common.PreLoadClass;
-import cn.jiangzeyin.common.PreLoadMethod;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import io.jpom.common.ServerOpenApi;
-import io.jpom.system.AgentAuthorize;
-import io.jpom.system.AgentConfigBean;
-import io.jpom.system.AgentExtConfigBean;
-import io.jpom.system.ConfigBean;
-import io.jpom.util.JsonFileUtil;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.net.URL;
-
-/**
- * 自动注册server 节点
- *
- * @author bwcx_jzy
- * @date 2019/8/6
- */
-@PreLoadClass
-public class AutoRegSeverNode {
-
- @PreLoadMethod
- private static void reg() throws FileNotFoundException {
- String agentId = AgentExtConfigBean.getInstance().getAgentId();
- String serverUrl = AgentExtConfigBean.getInstance().getServerUrl();
- if (StrUtil.isEmpty(agentId) || StrUtil.isEmpty(serverUrl)) {
- // 如果二者缺一不注册
- return;
- }
- String oldInstallId = null;
- File file = FileUtil.file(ConfigBean.getInstance().getDataPath(), AgentConfigBean.SERVER_ID);
- JSONObject serverJson = null;
- if (file.exists()) {
- serverJson = (JSONObject) JsonFileUtil.readJson(file.getAbsolutePath());
- oldInstallId = serverJson.getString("installId");
- }
- HttpRequest installRequest = AgentExtConfigBean.getInstance().createServerRequest(ServerOpenApi.INSTALL_ID);
- String body1 = installRequest.execute().body();
- JsonMessage jsonMessage = JSON.parseObject(body1, JsonMessage.class);
- if (jsonMessage.getCode() != HttpStatus.HTTP_OK) {
- DefaultSystemLog.getLog().error("获取Server 安装id失败:" + jsonMessage);
- return;
- }
- String installId = jsonMessage.dataToString();
- boolean eqInstall = StrUtil.equals(oldInstallId, installId);
- //
- URL url = URLUtil.toUrlForHttp(AgentExtConfigBean.getInstance().getAgentUrl());
- String protocol = url.getProtocol();
-
- HttpRequest serverRequest = AgentExtConfigBean.getInstance().createServerRequest(ServerOpenApi.UPDATE_NODE_INFO);
- serverRequest.form("id", agentId);
- serverRequest.form("name", "节点:" + agentId);
- serverRequest.form("openStatus", 1);
- serverRequest.form("protocol", protocol);
- serverRequest.form("url", url.getHost() + ":" + url.getPort());
- serverRequest.form("loginName", AgentAuthorize.getInstance().getAgentName());
- serverRequest.form("loginPwd", AgentAuthorize.getInstance().getAgentPwd());
- serverRequest.form("type", eqInstall ? "update" : "add");
- String body = serverRequest.execute().body();
- DefaultSystemLog.getLog().info("自动注册Server:" + body);
- JsonMessage regJsonMessage = JSON.parseObject(body, JsonMessage.class);
- if (regJsonMessage.getCode() == HttpStatus.HTTP_OK) {
- if (serverJson == null) {
- serverJson = new JSONObject();
- }
- if (!eqInstall) {
- serverJson.put("installId", installId);
- serverJson.put("regTime", DateTime.now().toString());
- } else {
- serverJson.put("updateTime", DateTime.now().toString());
- }
- JsonFileUtil.saveJson(file.getAbsolutePath(), serverJson);
- } else {
- DefaultSystemLog.getLog().error("自动注册插件端失败:{}", body);
- }
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/system/init/AutoStartProject.java b/modules/agent/src/main/java/io/jpom/system/init/AutoStartProject.java
deleted file mode 100644
index 39ea35fc21..0000000000
--- a/modules/agent/src/main/java/io/jpom/system/init/AutoStartProject.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.system.init;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.thread.ThreadUtil;
-import cn.jiangzeyin.common.DefaultSystemLog;
-import cn.jiangzeyin.common.PreLoadClass;
-import cn.jiangzeyin.common.PreLoadMethod;
-import cn.jiangzeyin.common.spring.SpringUtil;
-import io.jpom.common.commander.AbstractProjectCommander;
-import io.jpom.model.data.NodeProjectInfoModel;
-import io.jpom.service.manage.ProjectInfoService;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * 自动启动项目
- *
- * @author bwcx_jzy
- * @since 2021/12/10
- */
-@PreLoadClass
-public class AutoStartProject {
-
- @PreLoadMethod
- private static void start() {
- ProjectInfoService projectInfoService = SpringUtil.getBean(ProjectInfoService.class);
- List list = projectInfoService.list();
- if (CollUtil.isEmpty(list)) {
- return;
- }
- list = list.stream().filter(nodeProjectInfoModel -> nodeProjectInfoModel.getAutoStart() != null && nodeProjectInfoModel.getAutoStart()).collect(Collectors.toList());
- List finalList = list;
- ThreadUtil.execute(() -> {
- AbstractProjectCommander instance = AbstractProjectCommander.getInstance();
- for (NodeProjectInfoModel nodeProjectInfoModel : finalList) {
- try {
- if (!instance.isRun(nodeProjectInfoModel, null)) {
- instance.start(nodeProjectInfoModel, null);
- }
- List javaCopyItemList = nodeProjectInfoModel.getJavaCopyItemList();
- if (javaCopyItemList != null) {
- for (NodeProjectInfoModel.JavaCopyItem javaCopyItem : javaCopyItemList) {
- if (!instance.isRun(nodeProjectInfoModel, javaCopyItem)) {
- instance.start(nodeProjectInfoModel, javaCopyItem);
- }
- }
- }
- } catch (Exception e) {
- DefaultSystemLog.getLog().warn("自动启动项目失败:{} {}", nodeProjectInfoModel.getId(), e.getMessage());
- }
- }
- });
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/system/init/CheckAuthorize.java b/modules/agent/src/main/java/io/jpom/system/init/CheckAuthorize.java
deleted file mode 100644
index 7438d10d85..0000000000
--- a/modules/agent/src/main/java/io/jpom/system/init/CheckAuthorize.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.system.init;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.jiangzeyin.common.PreLoadClass;
-import cn.jiangzeyin.common.PreLoadMethod;
-import io.jpom.common.JpomManifest;
-import io.jpom.system.AgentAuthorize;
-import io.jpom.system.AgentConfigBean;
-import io.jpom.system.ConfigBean;
-import io.jpom.system.ExtConfigBean;
-
-import java.io.File;
-
-/**
- * 检查授权信息
- *
- * @author jiangzeyin
- * @date 2019/4/17
- */
-@PreLoadClass
-public class CheckAuthorize {
-
- @PreLoadMethod
- private static void startAutoBackLog() {
- AgentAuthorize.getInstance();
- }
-
- /**
- * 修护脚本模板路径
- */
- @PreLoadMethod
- private static void repairScriptPath() {
- if (!JpomManifest.getInstance().isDebug()) {
- if (StrUtil.compareVersion(JpomManifest.getInstance().getVersion(), "2.4.2") < 0) {
- return;
- }
- }
- File oldDir = FileUtil.file(ExtConfigBean.getInstance().getPath(), AgentConfigBean.SCRIPT_DIRECTORY);
- if (!oldDir.exists()) {
- return;
- }
- File newDir = FileUtil.file(ConfigBean.getInstance().getDataPath(), AgentConfigBean.SCRIPT_DIRECTORY);
- FileUtil.move(oldDir, newDir, true);
- }
-}
diff --git a/modules/agent/src/main/java/io/jpom/util/CompressionFileUtil.java b/modules/agent/src/main/java/io/jpom/util/CompressionFileUtil.java
deleted file mode 100644
index b81d4217a8..0000000000
--- a/modules/agent/src/main/java/io/jpom/util/CompressionFileUtil.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.util;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.extra.compress.CompressUtil;
-import cn.hutool.extra.compress.extractor.Extractor;
-import org.apache.commons.compress.compressors.CompressorInputStream;
-import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
-import org.apache.commons.compress.compressors.bzip2.BZip2Utils;
-import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
-import org.apache.commons.compress.compressors.gzip.GzipUtils;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.nio.charset.Charset;
-
-/**
- * 压缩文件工具
- *
- * @author bwcx_jzy
- */
-public class CompressionFileUtil {
-
- /**
- * 解压文件
- *
- * @param compressFile 压缩文件
- * @param destDir 解压到的文件夹
- */
- public static void unCompress(File compressFile, File destDir) {
- Charset charset = CharsetUtil.CHARSET_GBK;
- charset = ObjectUtil.defaultIfNull(charset, CharsetUtil.defaultCharset());
- try {
- try (Extractor extractor = CompressUtil.createExtractor(charset, compressFile)) {
- extractor.extract(destDir);
- }
- } catch (Exception e) {
- CompressorInputStream compressUtilIn = null;
- FileInputStream fileInputStream = null;
- try {
- fileInputStream = new FileInputStream(compressFile);
- compressUtilIn = CompressUtil.getIn(null, fileInputStream);
- if (compressUtilIn instanceof BZip2CompressorInputStream) {
- File file = FileUtil.file(destDir, BZip2Utils.getUncompressedFilename(compressFile.getName()));
- IoUtil.copy(compressUtilIn, new FileOutputStream(file));
- } else if (compressUtilIn instanceof GzipCompressorInputStream) {
- File file = FileUtil.file(destDir, GzipUtils.getUncompressedFilename(compressFile.getName()));
- IoUtil.copy(compressUtilIn, new FileOutputStream(file));
- } else {
- try (Extractor extractor = CompressUtil.createExtractor(charset, compressUtilIn)) {
- extractor.extract(destDir);
- }
- }
- } catch (Exception e2) {
- //
- e2.addSuppressed(e);
- //
- throw new RuntimeException(e2);
- } finally {
- IoUtil.close(fileInputStream);
- IoUtil.close(compressUtilIn);
- }
- }
- }
-
-
-}
diff --git a/modules/agent/src/main/java/io/jpom/util/FileUtils.java b/modules/agent/src/main/java/io/jpom/util/FileUtils.java
deleted file mode 100644
index 09129c903c..0000000000
--- a/modules/agent/src/main/java/io/jpom/util/FileUtils.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 码之科技工作室
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-package io.jpom.util;
-
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.system.SystemUtil;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-
-import java.io.File;
-
-/**
- * 文件工具
- *
- * @author jiangzeyin
- * @date 2019/4/28
- */
-public class FileUtils {
-
- private static JSONObject fileToJson(File file) {
- JSONObject jsonObject = new JSONObject(6);
- if (file.isDirectory()) {
- jsonObject.put("isDirectory", true);
- long sizeFile = FileUtil.size(file);
- jsonObject.put("fileSize", FileUtil.readableFileSize(sizeFile));
- } else {
- jsonObject.put("fileSize", FileUtil.readableFileSize(file.length()));
- }
- jsonObject.put("filename", file.getName());
- long mTime = file.lastModified();
- jsonObject.put("modifyTimeLong", mTime);
- jsonObject.put("modifyTime", DateUtil.date(mTime).toString());
- return jsonObject;
- }
-
- /**
- * 对文件信息解析排序
- *
- * @param files 文件数组
- * @param time 是否安装时间排序
- * @param startPath 开始路径
- * @return 排序后的json
- */
- public static JSONArray parseInfo(File[] files, boolean time, String startPath) {
- if (files == null) {
- return new JSONArray();
- }
- int size = files.length;
- JSONArray arrayFile = new JSONArray(size);
- for (File file : files) {
- JSONObject jsonObject = FileUtils.fileToJson(file);
- //
- if (startPath != null) {
- String levelName = StringUtil.delStartPath(file, startPath, false);
- jsonObject.put("levelName", levelName);
- }
- //
- arrayFile.add(jsonObject);
- }
- arrayFile.sort((o1, o2) -> {
- JSONObject jsonObject1 = (JSONObject) o1;
- JSONObject jsonObject2 = (JSONObject) o2;
- if (time) {
- return jsonObject2.getLong("modifyTimeLong").compareTo(jsonObject1.getLong("modifyTimeLong"));
- }
- return jsonObject1.getString("filename").compareTo(jsonObject2.getString("filename"));
- });
- final int[] i = {0};
- arrayFile.forEach(o -> {
- JSONObject jsonObject = (JSONObject) o;
- jsonObject.put("index", ++i[0]);
- });
- return arrayFile;
- }
-
- /**
- * 判断路径是否满足jdk 条件
- *
- * @param path 路径
- * @return 判断存在java文件
- */
- public static boolean isJdkPath(String path) {
- String fileName = getJdkJavaPath(path, false);
- File newPath = new File(fileName);
- return newPath.exists() && newPath.isFile();
- }
-
- /**
- * 获取java 文件路径
- *
- * @param path path
- * @param w 是否使用javaw
- * @return 完整路径
- */
- public static String getJdkJavaPath(String path, boolean w) {
- String fileName;
- if (SystemUtil.getOsInfo().isWindows()) {
- fileName = w ? "javaw.exe" : "java.exe";
- } else {
- fileName = w ? "javaw" : "java";
- }
- File newPath = FileUtil.file(path, "bin", fileName);
- return FileUtil.getAbsolutePath(newPath);
- }
-
- /**
- * 获取jdk 版本
- *
- * @param path jdk 路径
- * @return 获取成功返回版本号
- */
- public static String getJdkVersion(String path) {
- String newPath = getJdkJavaPath(path, false);
- if (path.contains(StrUtil.SPACE)) {
- newPath = String.format("\"%s\"", newPath);
- }
- String command = CommandUtil.execSystemCommand(newPath + " -version");
- String[] split = StrUtil.splitToArray(command, StrUtil.LF);
- if (split == null || split.length <= 0) {
- return null;
- }
- String[] strings = StrUtil.splitToArray(split[0], "\"");
- if (strings == null || strings.length <= 1) {
- return null;
- }
- return strings[1];
- }
-}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/JpomAgentApplication.java b/modules/agent/src/main/java/org/dromara/jpom/JpomAgentApplication.java
new file mode 100644
index 0000000000..9a692d23f5
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/JpomAgentApplication.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom;
+
+import cn.hutool.core.date.BetweenFormatter;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.date.SystemClock;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.keepbx.jpom.JpomAppType;
+import cn.keepbx.jpom.Type;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.common.ServerOpenApi;
+import org.dromara.jpom.common.i18n.I18nMessageUtil;
+import org.dromara.jpom.system.AgentStartInit;
+import org.springframework.boot.Banner;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.ServletComponentScan;
+
+/**
+ * jpom 启动类
+ *
+ * @author bwcx_jzy
+ * @since 2017/9/14.
+ */
+@SpringBootApplication(scanBasePackages = {"org.dromara.jpom"})
+@ServletComponentScan(basePackages = {"org.dromara.jpom"})
+@Slf4j
+@JpomAppType(Type.Agent)
+public class JpomAgentApplication {
+
+ /**
+ * 启动执行
+ *
+ * @param args 参数
+ * @throws Exception 异常
+ */
+ public static void main(String[] args) throws Exception {
+ long time = SystemClock.now();
+ SpringApplicationBuilder springApplicationBuilder = new SpringApplicationBuilder(JpomAgentApplication.class);
+ springApplicationBuilder.bannerMode(Banner.Mode.LOG);
+ springApplicationBuilder.run(args);
+ // 自动向服务端推送
+ autoPushToServer(args);
+ log.info("Time-consuming to start this time:{}", DateUtil.formatBetween(SystemClock.now() - time, BetweenFormatter.Level.MILLISECOND));
+ }
+
+ /**
+ * 自动推送 插件端信息到服务端
+ *
+ * @param args 参数
+ */
+ private static void autoPushToServer(String[] args) {
+ int i = ArrayUtil.indexOf(args, ServerOpenApi.PUSH_NODE_KEY);
+ if (i == ArrayUtil.INDEX_NOT_FOUND) {
+ return;
+ }
+ String arg = ArrayUtil.get(args, i + 1);
+ if (StrUtil.isEmpty(arg)) {
+ log.error("not found auto-push-to-server url");
+ return;
+ }
+ try {
+ AgentStartInit autoRegSeverNode = SpringUtil.getBean(AgentStartInit.class);
+ autoRegSeverNode.autoPushToServer(arg);
+ } catch (Exception e) {
+ log.error(I18nMessageUtil.get("i18n.push_registration_to_server_failed.5949"), arg, e);
+ }
+ }
+
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/AgentConst.java b/modules/agent/src/main/java/org/dromara/jpom/common/AgentConst.java
new file mode 100644
index 0000000000..08af50067e
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/AgentConst.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common;
+
+/**
+ * 插件端配置
+ *
+ * @author bwcx_jzy
+ * @since 2019/4/16
+ */
+public class AgentConst {
+ /**
+ * 授权文件
+ */
+ public static final String WHITELIST_DIRECTORY = "whitelistDirectory.json";
+ /**
+ * 项目数据文件
+ */
+ public static final String PROJECT = "project.json";
+ /**
+ * 脚本管理数据文件
+ */
+ public static final String SCRIPT = "script.json";
+ /**
+ * 脚本管理执行记录数据文件
+ */
+ public static final String SCRIPT_LOG = "script_log.json";
+ /**
+ * 环境变量列表信息
+ */
+ public static final String WORKSPACE_ENV_VAR = "workspace_env_var.json";
+
+
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/AgentExceptionHandler.java b/modules/agent/src/main/java/org/dromara/jpom/common/AgentExceptionHandler.java
new file mode 100644
index 0000000000..313e24dfca
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/AgentExceptionHandler.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common;
+
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.exception.BaseExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * 全局异常处理
+ *
+ * @author bwcx_jzy
+ * @since 2019/04/17
+ */
+@RestControllerAdvice
+@Slf4j
+public class AgentExceptionHandler extends BaseExceptionHandler {
+
+
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/BaseAgentController.java b/modules/agent/src/main/java/org/dromara/jpom/common/BaseAgentController.java
new file mode 100644
index 0000000000..8e303628f8
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/BaseAgentController.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common;
+
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.URLUtil;
+import cn.hutool.extra.servlet.ServletUtil;
+import org.dromara.jpom.common.i18n.I18nMessageUtil;
+import org.dromara.jpom.model.data.NodeProjectInfoModel;
+import org.dromara.jpom.service.manage.ProjectInfoService;
+import org.springframework.util.Assert;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * agent 端
+ *
+ * @author bwcx_jzy
+ * @since 2019/4/17
+ */
+public abstract class BaseAgentController extends BaseJpomController {
+
+ @Resource
+ protected ProjectInfoService projectInfoService;
+
+
+ /**
+ * 获取server 端操作人
+ *
+ * @param request req
+ * @return name
+ */
+ private static String getUserName(HttpServletRequest request) {
+ String name = ServletUtil.getHeaderIgnoreCase(request, Const.JPOM_SERVER_USER_NAME);
+ name = CharsetUtil.convert(name, CharsetUtil.CHARSET_ISO_8859_1, CharsetUtil.CHARSET_UTF_8);
+ name = StrUtil.emptyToDefault(name, StrUtil.DASHED);
+ return URLUtil.decode(name, CharsetUtil.CHARSET_UTF_8);
+ }
+
+ /**
+ * 获取server 端操作人
+ *
+ * @return name
+ */
+ public static String getNowUserName() {
+ ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ if (servletRequestAttributes == null) {
+ return StrUtil.DASHED;
+ }
+ HttpServletRequest request = servletRequestAttributes.getRequest();
+ return getUserName(request);
+ }
+
+ protected String getWorkspaceId() {
+ return ServletUtil.getHeader(getRequest(), Const.WORKSPACE_ID_REQ_HEADER, CharsetUtil.CHARSET_UTF_8);
+ }
+
+ /**
+ * 获取拦截器中缓存的项目信息
+ *
+ * @return NodeProjectInfoModel
+ */
+ protected NodeProjectInfoModel getProjectInfoModel() {
+ String id = getParameter("id");
+ NodeProjectInfoModel nodeProjectInfoModel = tryGetProjectInfoModel(id);
+ Assert.notNull(nodeProjectInfoModel, I18nMessageUtil.get("i18n.get_project_info_failure.ddff") + id);
+ return nodeProjectInfoModel;
+ }
+
+ /**
+ * 根据 项目ID 获取项目信息
+ *
+ * @return NodeProjectInfoModel
+ */
+ protected NodeProjectInfoModel getProjectInfoModel(String id) {
+ NodeProjectInfoModel nodeProjectInfoModel = tryGetProjectInfoModel(id);
+ Assert.notNull(nodeProjectInfoModel, I18nMessageUtil.get("i18n.get_project_info_failure.ddff") + id);
+ return nodeProjectInfoModel;
+ }
+
+ protected NodeProjectInfoModel tryGetProjectInfoModel() {
+ String id = getParameter("id");
+ return tryGetProjectInfoModel(id);
+ }
+
+ protected NodeProjectInfoModel tryGetProjectInfoModel(String id) {
+ if (StrUtil.isNotEmpty(id)) {
+ return projectInfoService.getItem(id);
+ }
+ return null;
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/WebConfigurer.java b/modules/agent/src/main/java/org/dromara/jpom/common/WebConfigurer.java
new file mode 100644
index 0000000000..8089a8811e
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/WebConfigurer.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common;
+
+import org.dromara.jpom.common.interceptor.AuthorizeInterceptor;
+import org.dromara.jpom.common.validator.ParameterInterceptor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * @author bwcx_jzy
+ * @since 2022/12/8
+ */
+@Configuration
+public class WebConfigurer implements WebMvcConfigurer {
+
+ private final ParameterInterceptor parameterInterceptor;
+ private final AuthorizeInterceptor authorizeInterceptor;
+
+ public WebConfigurer(ParameterInterceptor parameterInterceptor,
+ AuthorizeInterceptor authorizeInterceptor) {
+ this.parameterInterceptor = parameterInterceptor;
+ this.authorizeInterceptor = authorizeInterceptor;
+ }
+
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+
+ registry.addInterceptor(parameterInterceptor).addPathPatterns("/**");
+ registry.addInterceptor(authorizeInterceptor).addPathPatterns("/**");
+ }
+
+
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/AbstractProjectCommander.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/AbstractProjectCommander.java
new file mode 100644
index 0000000000..e5b5a297c4
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/AbstractProjectCommander.java
@@ -0,0 +1,909 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.unit.DataSizeUtil;
+import cn.hutool.core.lang.JarClassLoader;
+import cn.hutool.core.lang.Opt;
+import cn.hutool.core.lang.Tuple;
+import cn.hutool.core.map.SafeConcurrentHashMap;
+import cn.hutool.core.text.StrPool;
+import cn.hutool.core.text.StrSplitter;
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.system.SystemUtil;
+import cn.keepbx.jpom.plugins.IPlugin;
+import lombok.Lombok;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.common.i18n.I18nMessageUtil;
+import org.dromara.jpom.common.i18n.I18nThreadUtil;
+import org.dromara.jpom.configuration.ProjectConfig;
+import org.dromara.jpom.configuration.ProjectLogConfig;
+import org.dromara.jpom.exception.IllegalArgument2Exception;
+import org.dromara.jpom.model.RunMode;
+import org.dromara.jpom.model.data.DslYmlDto;
+import org.dromara.jpom.model.data.NodeProjectInfoModel;
+import org.dromara.jpom.model.system.NetstatModel;
+import org.dromara.jpom.plugin.PluginFactory;
+import org.dromara.jpom.service.manage.ProjectInfoService;
+import org.dromara.jpom.service.script.DslScriptServer;
+import org.dromara.jpom.socket.AgentFileTailWatcher;
+import org.dromara.jpom.socket.ConsoleCommandOp;
+import org.dromara.jpom.util.CommandUtil;
+import org.dromara.jpom.util.JvmUtil;
+import org.dromara.jpom.webhook.DefaultWebhookPluginImpl;
+import org.springframework.util.Assert;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.stream.Collectors;
+
+/**
+ * 项目命令执行基类
+ *
+ * @author bwcx_jzy
+ */
+@Slf4j
+public abstract class AbstractProjectCommander implements ProjectCommander {
+
+ public static final String RUNNING_TAG = "running";
+ public static final String STOP_TAG = "stopped";
+
+ private static final long BACK_LOG_MIN_SIZE = DataSizeUtil.parse("100KB");
+
+
+ /**
+ * 进程Id 获取端口号
+ */
+ public static final Map> PID_PORT = new SafeConcurrentHashMap<>();
+
+ protected final Charset fileCharset;
+ protected final SystemCommander systemCommander;
+ protected final ProjectConfig projectConfig;
+ protected final ProjectLogConfig projectLogConfig;
+ protected final DslScriptServer dslScriptServer;
+ protected final ProjectInfoService projectInfoService;
+
+ public AbstractProjectCommander(Charset fileCharset,
+ SystemCommander systemCommander,
+ ProjectConfig projectConfig,
+ DslScriptServer dslScriptServer,
+ ProjectInfoService projectInfoService) {
+ this.fileCharset = fileCharset;
+ this.systemCommander = systemCommander;
+ this.projectConfig = projectConfig;
+ this.projectLogConfig = projectConfig.getLog();
+ this.dslScriptServer = dslScriptServer;
+ this.projectInfoService = projectInfoService;
+ }
+
+
+ //---------------------------------------------------- 基本操作----start
+
+ /**
+ * 生成可以执行的命令
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return null 是条件不足
+ */
+ public abstract String buildRunCommand(NodeProjectInfoModel nodeProjectInfoModel);
+
+ /**
+ * 生成可以执行的命令
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return null 是条件不足
+ */
+ public abstract String buildRunCommand(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel);
+
+ protected String getRunJavaPath(NodeProjectInfoModel nodeProjectInfoModel, boolean w) {
+// if (StrUtil.isEmpty(nodeProjectInfoModel.getJdkId())) {
+// return w ? "javaw" : "java";
+// }
+//
+// if (item == null) {
+ return w ? "javaw" : "java";
+// }
+// String jdkJavaPath = FileUtils.getJdkJavaPath(item.getPath(), w);
+// if (jdkJavaPath.contains(StrUtil.SPACE)) {
+// jdkJavaPath = String.format("\"%s\"", jdkJavaPath);
+// }
+// return jdkJavaPath;
+ }
+
+ /**
+ * 启动
+ *
+ * @param nodeProjectInfoModel 项目
+ * @param sync dsl 是否同步执行
+ * @return 结果
+ */
+ protected CommandOpResult start(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel, boolean sync) {
+ String msg = this.checkStart(nodeProjectInfoModel, originalModel);
+ if (msg != null) {
+ return CommandOpResult.of(false, msg);
+ }
+ RunMode runMode = originalModel.getRunMode();
+ if (runMode == RunMode.Dsl) {
+ //
+ DslYmlDto mustDslConfig = originalModel.mustDslConfig();
+ try {
+ dslScriptServer.run(mustDslConfig, ConsoleCommandOp.start, nodeProjectInfoModel, originalModel, sync);
+ } catch (Exception e) {
+ throw Lombok.sneakyThrow(e);
+ }
+
+ } else {
+ String command = this.buildRunCommand(nodeProjectInfoModel, originalModel);
+ if (command == null) {
+ return CommandOpResult.of(false, I18nMessageUtil.get("i18n.no_command_to_execute.340b"));
+ }
+ Map env = projectInfoService.getEnv(nodeProjectInfoModel.getWorkspaceId());
+ // 执行命令
+ I18nThreadUtil.execute(() -> {
+ try {
+ File file = projectInfoService.resolveLibFile(nodeProjectInfoModel);
+ if (SystemUtil.getOsInfo().isWindows()) {
+ CommandUtil.execSystemCommand(command, file, env);
+ } else {
+ CommandUtil.asyncExeLocalCommand(command, file, env);
+ }
+ } catch (Exception e) {
+ log.error(I18nMessageUtil.get("i18n.command_execution_failed.90ef"), e);
+ }
+ });
+ }
+ //
+ this.loopCheckRun(nodeProjectInfoModel, originalModel, true);
+ CommandOpResult status = this.status(nodeProjectInfoModel, originalModel);
+ this.asyncWebHooks(nodeProjectInfoModel, originalModel, "start", "result", status.msgStr());
+ return status;
+ }
+
+// private T runDsl(NodeProjectInfoModel nodeProjectInfoModel, String opt, BiFunction function) {
+// DslYmlDto mustDslConfig = nodeProjectInfoModel.mustDslConfig();
+// DslYmlDto.BaseProcess process = mustDslConfig.getDslProcess(opt);
+// return function.apply(process, mustDslConfig);
+// }
+
+ /**
+ * 查询出指定端口信息
+ *
+ * @param pid 进程id
+ * @param listening 是否只获取检查状态的
+ * @return 数组
+ */
+ protected abstract List listNetstat(int pid, boolean listening);
+
+
+ /**
+ * 停止
+ *
+ * @param nodeProjectInfoModel 项目
+ * @param sync dsl 是否同步执行
+ * @return 结果
+ */
+ protected CommandOpResult stop(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel, boolean sync) {
+ RunMode runMode = nodeProjectInfoModel.getRunMode();
+ if (runMode == RunMode.File) {
+ return CommandOpResult.of(true, I18nMessageUtil.get("i18n.file_type_no_stop.00ff"));
+ }
+
+ Tuple tuple = this.stopBefore(nodeProjectInfoModel, originalModel);
+ CommandOpResult status = tuple.get(1);
+ String webHook = tuple.get(0);
+ if (status.isSuccess()) {
+ // 运行中
+ if (runMode == RunMode.Dsl) {
+ //
+ DslYmlDto config = originalModel.mustDslConfig();
+ try {
+ dslScriptServer.run(config, ConsoleCommandOp.stop, nodeProjectInfoModel, originalModel, sync);
+ } catch (Exception e) {
+ throw Lombok.sneakyThrow(e);
+ }
+ boolean checkRun = this.loopCheckRun(nodeProjectInfoModel, originalModel, false);
+ return CommandOpResult.of(checkRun, checkRun ? "stop done" : "stop done,but unsuccessful")
+ .appendMsg(status.getMsgs())
+ .appendMsg(webHook);
+ } else {
+ //
+ return this.stopJava(nodeProjectInfoModel, originalModel, status.getPid()).appendMsg(status.getMsgs()).appendMsg(webHook);
+ }
+ }
+ return CommandOpResult.of(true).
+ appendMsg(status.getMsgs()).
+ appendMsg(webHook);
+ }
+
+ /**
+ * 停止
+ *
+ * @param nodeProjectInfoModel 项目
+ * @param pid 进程ID
+ * @return 结果
+ */
+ protected abstract CommandOpResult stopJava(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel, int pid);
+
+ /**
+ * 停止之前
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return 结果
+ */
+ private Tuple stopBefore(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel) {
+ String beforeStop = this.webHooks(nodeProjectInfoModel.token(), nodeProjectInfoModel, "beforeStop");
+ // 再次查看进程信息
+ CommandOpResult result = this.status(nodeProjectInfoModel, originalModel);
+ if (result.isSuccess()) {
+ // 端口号缓存
+ PID_PORT.remove(result.getPid());
+ }
+ this.asyncWebHooks(nodeProjectInfoModel, originalModel, "stop", "result", result);
+ return new Tuple(StrUtil.emptyToDefault(beforeStop, StrUtil.EMPTY), result);
+ }
+
+ /**
+ * 执行 webhooks 通知
+ *
+ * @param nodeProjectInfoModel 项目信息
+ * @param type 类型
+ * @param other 其他参数
+ */
+ public void asyncWebHooks(NodeProjectInfoModel nodeProjectInfoModel,
+
+ String type, Object... other) {
+ NodeProjectInfoModel infoModel = projectInfoService.resolveModel(nodeProjectInfoModel);
+ this.asyncWebHooks(nodeProjectInfoModel, infoModel, type, other);
+ }
+
+ /**
+ * 执行 webhooks 通知
+ *
+ * @param nodeProjectInfoModel 项目信息
+ * @param type 类型
+ * @param other 其他参数
+ */
+ public void asyncWebHooks(NodeProjectInfoModel nodeProjectInfoModel,
+ NodeProjectInfoModel originalModel,
+ String type, Object... other) {
+ // webhook 通知
+ Opt.ofBlankAble(nodeProjectInfoModel.token())
+ .ifPresent(s ->
+ I18nThreadUtil.execute(() -> {
+ try {
+ String result = this.webHooks(s, nodeProjectInfoModel, type, other);
+ Optional.ofNullable(result).ifPresent(s1 -> log.debug(I18nMessageUtil.get("i18n.trigger_result.364e"), nodeProjectInfoModel.getId(), type, s1));
+ } catch (Exception e) {
+ log.error("project webhook", e);
+ }
+ })
+ );
+ // 判断文件变动
+ if (StrUtil.equals(type, "fileChange")) {
+ RunMode runMode = originalModel.getRunMode();
+ if (runMode == RunMode.Dsl) {
+ DslYmlDto dslYmlDto = originalModel.mustDslConfig();
+ if (dslYmlDto.hasRunProcess(ConsoleCommandOp.reload.name())) {
+ DslYmlDto.Run run = dslYmlDto.getRun();
+ Boolean fileChangeReload = run.getFileChangeReload();
+ if (fileChangeReload != null && fileChangeReload) {
+ // 需要执行重载事件
+ I18nThreadUtil.execute(() -> {
+ try {
+ CommandOpResult reload = this.reload(nodeProjectInfoModel, originalModel);
+ log.info(I18nMessageUtil.get("i18n.trigger_project_reload_event.a7dc"), reload);
+ } catch (Exception e) {
+ log.error(I18nMessageUtil.get("i18n.reload_project_exception.b566"), e);
+ }
+ });
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 执行 webhooks 通知
+ *
+ * @param nodeProjectInfoModel 项目信息
+ * @param type 类型
+ * @param other 其他参数
+ * @return 结果
+ */
+ private String webHooks(String token, NodeProjectInfoModel nodeProjectInfoModel, String type, Object... other) {
+ if (StrUtil.isEmpty(token)) {
+ return null;
+ }
+ IPlugin plugin = PluginFactory.getPlugin("webhook");
+ Map map = new HashMap<>(10);
+ map.put("projectId", nodeProjectInfoModel.getId());
+ map.put("projectName", nodeProjectInfoModel.getName());
+ map.put("type", type);
+ map.put("JPOM_WEBHOOK_EVENT", DefaultWebhookPluginImpl.WebhookEvent.PROJECT);
+
+ for (int i = 0; i < other.length; i += 2) {
+ map.put(other[i].toString(), other[i + 1]);
+ }
+ try {
+ Object execute = plugin.execute(token, map);
+ return Convert.toStr(execute, StrUtil.EMPTY);
+ } catch (Exception e) {
+ throw Lombok.sneakyThrow(e);
+ }
+ }
+
+ /**
+ * 重启
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return 结果
+ */
+ protected CommandOpResult restart(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel) {
+ RunMode runMode = originalModel.getRunMode();
+ if (runMode == RunMode.File) {
+ return CommandOpResult.of(true, I18nMessageUtil.get("i18n.file_type_no_restart.0977"));
+ }
+ this.asyncWebHooks(nodeProjectInfoModel, originalModel, "beforeRestart");
+ if (runMode == RunMode.Dsl) {
+ DslYmlDto dslConfig = originalModel.mustDslConfig();
+ String opt = ConsoleCommandOp.restart.name();
+ DslYmlDto.BaseProcess dslProcess = dslConfig.tryDslProcess(opt);
+ if (dslProcess != null) {
+ // 如果存在自定义 restart 流程
+ try {
+ dslScriptServer.run(dslConfig, ConsoleCommandOp.restart, nodeProjectInfoModel, originalModel, false);
+ } catch (Exception e) {
+ throw Lombok.sneakyThrow(e);
+ }
+ // 等待 状态成功
+ boolean run = this.loopCheckRun(nodeProjectInfoModel, originalModel, true);
+ CommandOpResult result = CommandOpResult.of(run, run ? "restart done" : "restart done,but unsuccessful");
+ this.asyncWebHooks(nodeProjectInfoModel, originalModel, "restart", "result", result);
+ return result;
+
+ //return new Tuple(run ? "restart done,but unsuccessful" : "restart done", resultMsg);
+ }
+ }
+ boolean run = this.isRun(nodeProjectInfoModel, originalModel);
+ CommandOpResult stopMsg = null;
+ if (run) {
+ stopMsg = this.stop(nodeProjectInfoModel, originalModel, true);
+ }
+ CommandOpResult startMsg = this.start(nodeProjectInfoModel, originalModel, false);
+ if (stopMsg != null) {
+ startMsg.appendMsg(stopMsg.getMsgs());
+ }
+ return startMsg;
+ }
+
+ /**
+ * 启动项目前基本检查
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return null 检查一切正常
+ */
+ private String checkStart(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel) {
+ CommandOpResult status = this.status(nodeProjectInfoModel, originalModel);
+ if (status.isSuccess()) {
+ return I18nMessageUtil.get("i18n.program_already_running.96e1") + status.getPid();
+ }
+ File fileLib = projectInfoService.resolveLibFile(nodeProjectInfoModel);
+ File[] files = fileLib.listFiles();
+ if (files == null || files.length == 0) {
+ return I18nMessageUtil.get("i18n.no_files_in_project_directory.108e");
+ }
+ //
+
+ RunMode checkRunMode = originalModel.getRunMode();
+ if (checkRunMode == RunMode.Dsl) {
+ //
+ originalModel.mustDslConfig();
+ } else if (checkRunMode == RunMode.ClassPath || checkRunMode == RunMode.JavaExtDirsCp) {
+ // 判断主类
+ String mainClass = originalModel.mainClass();
+ try (JarClassLoader jarClassLoader = JarClassLoader.load(fileLib)) {
+ jarClassLoader.loadClass(mainClass);
+ } catch (ClassNotFoundException notFound) {
+ return I18nMessageUtil.get("i18n.no_main_class_found.b001") + mainClass;
+ } catch (IOException io) {
+ throw Lombok.sneakyThrow(io);
+ }
+ } else if (checkRunMode == RunMode.Jar || checkRunMode == RunMode.JarWar) {
+
+ List fileList = this.listJars(checkRunMode, fileLib);
+ if (fileList.isEmpty()) {
+ return String.format(I18nMessageUtil.get("i18n.missing_package_in_root_dir.8bab"), checkRunMode.name(), checkRunMode.name());
+ }
+ File jarFile = fileList.get(0);
+ String checkJar = checkJar(jarFile);
+ if (checkJar != null) {
+ return checkJar;
+ }
+ } else {
+ return I18nMessageUtil.get("i18n.project_type_not_supported_for_startup.7bd1");
+ }
+ // 备份日志
+ this.backLog(nodeProjectInfoModel, originalModel);
+ return null;
+ }
+
+ /**
+ * 校验jar包
+ *
+ * @param jarFile jar 文件
+ * @return mainClass
+ */
+ private static String checkJar(File jarFile) {
+ try (JarFile jarFile1 = new JarFile(jarFile)) {
+ Manifest manifest = jarFile1.getManifest();
+ Attributes attributes = manifest.getMainAttributes();
+ String mainClass = attributes.getValue(Attributes.Name.MAIN_CLASS);
+ if (mainClass == null) {
+ return jarFile.getAbsolutePath() + I18nMessageUtil.get("i18n.main_class_attribute_not_found.93e8");
+ }
+ try (JarClassLoader jarClassLoader = JarClassLoader.load(jarFile)) {
+ jarClassLoader.loadClass(mainClass);
+ } catch (ClassNotFoundException notFound) {
+ return jarFile.getAbsolutePath() + I18nMessageUtil.get("i18n.main_class_not_found.b4b7") + mainClass;
+ }
+ } catch (Exception e) {
+ log.error(I18nMessageUtil.get("i18n.parse_jar.a26e"), e);
+ return jarFile.getAbsolutePath() + I18nMessageUtil.get("i18n.parse_error.da6d") + e.getMessage();
+ }
+ return null;
+ }
+
+ /**
+ * 解析是否开启 日志备份功能
+ *
+ * @param nodeProjectInfoModel 项目实体
+ * @return true 开启日志备份
+ */
+ private boolean resolveOpenLogBack(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel) {
+ RunMode runMode = originalModel.getRunMode();
+ boolean autoBackToFile = projectLogConfig.isAutoBackupToFile();
+ if (runMode == RunMode.Dsl) {
+ return Optional.ofNullable(originalModel.dslConfig())
+ .map(DslYmlDto::getConfig)
+ .map(DslYmlDto.Config::getAutoBackToFile)
+ .orElse(autoBackToFile);
+ }
+ return autoBackToFile;
+ }
+
+ /**
+ * 清空日志信息
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return 结果
+ */
+ public String backLog(NodeProjectInfoModel nodeProjectInfoModel) {
+ NodeProjectInfoModel infoModel = projectInfoService.resolveModel(nodeProjectInfoModel);
+ return this.backLog(nodeProjectInfoModel, infoModel);
+ }
+
+ /**
+ * 清空日志信息
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return 结果
+ */
+ public String backLog(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel) {
+ File file = projectInfoService.resolveAbsoluteLogFile(nodeProjectInfoModel, originalModel);
+ if (!file.exists() || file.isDirectory()) {
+ return "not exists";
+ }
+ // 文件内容太少不处理
+
+ if (file.length() <= BACK_LOG_MIN_SIZE) {
+ return "ok";
+ }
+ boolean openLogBack = this.resolveOpenLogBack(nodeProjectInfoModel, originalModel);
+ if (openLogBack) {
+ // 开启日志备份才移动文件
+ File backPath = projectInfoService.resolveLogBack(nodeProjectInfoModel, originalModel);
+ String pathId = DateTime.now().toString(DatePattern.PURE_DATETIME_FORMAT) + ".log";
+ backPath = new File(backPath, pathId);
+ FileUtil.copy(file, backPath, true);
+ }
+ // 清空日志
+ String r = systemCommander.emptyLogFile(file);
+ if (StrUtil.isNotEmpty(r)) {
+ log.info(r);
+ }
+ // 重新监听
+ AgentFileTailWatcher.reWatcher(file);
+ return "ok";
+ }
+
+ /**
+ * 查询项目状态
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return 状态
+ */
+ protected CommandOpResult status(NodeProjectInfoModel nodeProjectInfoModel) {
+ NodeProjectInfoModel originalModel = projectInfoService.resolveModel(nodeProjectInfoModel);
+ return this.status(nodeProjectInfoModel, originalModel);
+ }
+
+ /**
+ * 查询项目状态
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return 状态
+ */
+ protected CommandOpResult status(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel) {
+ RunMode runMode = originalModel.getRunMode();
+ if (runMode == RunMode.File) {
+ return CommandOpResult.of(false, I18nMessageUtil.get("i18n.file_type_project_no_running_status.32a2"));
+ }
+ if (runMode == RunMode.Dsl) {
+ DslYmlDto config = originalModel.mustDslConfig();
+ List status;
+ // 提前判断脚本 id,避免填写错误在删除项目检测状态时候异常
+ try {
+ Tuple tuple = dslScriptServer.syncRun(config, ConsoleCommandOp.status, nodeProjectInfoModel, originalModel);
+ status = tuple.get(1);
+ } catch (IllegalArgument2Exception argument2Exception) {
+ log.warn(I18nMessageUtil.get("i18n.execute_dsl_script_exception.0882"), argument2Exception.getMessage());
+ status = CollUtil.newArrayList(argument2Exception.getMessage());
+ }
+
+ return Optional.ofNullable(status)
+ .map(strings -> {
+ File log = projectInfoService.resolveAbsoluteLogFile(nodeProjectInfoModel, originalModel);
+ FileUtil.appendLines(strings, log, fileCharset);
+ return strings;
+ })
+ .map(CollUtil::getLast)
+ // 此流程特意处理 系统日志标准格式 StrUtil.format("{} [{}] - {}", DateUtil.now(), this.action, line);
+ .map(s -> StrUtil.splitTrim(s, StrPool.DASHED))
+ .map(CollUtil::getLast)
+ .map(CommandOpResult::of)
+ .orElseGet(() -> CommandOpResult.of(false, STOP_TAG));
+ } else {
+ String tag = nodeProjectInfoModel.getId();
+ String statusResult = this.status(tag);
+ CommandOpResult of = CommandOpResult.of(statusResult);
+ if (!of.isSuccess()) {
+ // 只有 java 项目才判断 jps
+ Assert.state(JvmUtil.jpsNormal, JvmUtil.JPS_ERROR_MSG);
+ }
+ return of;
+ }
+ }
+
+ /**
+ * 重新加载
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return 结果
+ */
+ protected CommandOpResult reload(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel) {
+ RunMode runMode = originalModel.getRunMode();
+ Assert.state(runMode == RunMode.Dsl, I18nMessageUtil.get("i18n.non_dsl_project_unsupported_operation.5c09"));
+ DslYmlDto config = originalModel.mustDslConfig();
+ CommandOpResult commandOpResult;
+ // 提前判断脚本 id,避免填写错误在删除项目检测状态时候异常
+ try {
+ Tuple tuple = dslScriptServer.syncRun(config, ConsoleCommandOp.reload, nodeProjectInfoModel, originalModel);
+ int code = tuple.get(0);
+ List list = tuple.get(1);
+ // 如果退出码为 0 认为执行成功
+ commandOpResult = CommandOpResult.of(code == 0, list);
+ } catch (IllegalArgument2Exception argument2Exception) {
+ log.warn(I18nMessageUtil.get("i18n.execute_dsl_script_exception.0882"), argument2Exception.getMessage());
+ commandOpResult = CommandOpResult.of(false, argument2Exception.getMessage());
+ }
+ // 缓存执行结果
+ NodeProjectInfoModel update = new NodeProjectInfoModel();
+ update.setLastReloadResult(commandOpResult);
+ projectInfoService.updateById(update, nodeProjectInfoModel.getId());
+ this.asyncWebHooks(nodeProjectInfoModel, originalModel, "reload", "result", commandOpResult);
+ return commandOpResult;
+ }
+
+ /**
+ * 查看状态
+ *
+ * @param tag 运行标识
+ * @return 查询结果
+ */
+ protected String status(String tag) {
+ String jpsStatus = this.getJpsStatus(tag);
+ if (StrUtil.equals(AbstractProjectCommander.STOP_TAG, jpsStatus)) {
+ // 通过系统命令查询
+ return this.bySystemPs(tag);
+ }
+ return jpsStatus;
+ }
+
+ /**
+ * 通过系统命令查询进程是否存在
+ *
+ * @param tag 进程标识
+ * @return 是否存在
+ */
+ protected String bySystemPs(String tag) {
+ return AbstractProjectCommander.STOP_TAG;
+ }
+
+ /**
+ * 尝试jps 中查看进程id
+ *
+ * @param tag 进程标识
+ * @return 运行标识
+ */
+ private String getJpsStatus(String tag) {
+ Integer pid = JvmUtil.getPidByTag(tag);
+ if (pid == null || pid <= 0) {
+ return AbstractProjectCommander.STOP_TAG;
+ }
+ return StrUtil.format("{}:{}", AbstractProjectCommander.RUNNING_TAG, pid);
+ }
+
+//---------------------------------------------------- 基本操作----end
+
+ /**
+ * 获取进程占用的主要端口
+ *
+ * @param pid 进程id
+ * @return 端口
+ */
+ public String getMainPort(Integer pid) {
+ if (pid == null || pid <= 0) {
+ return StrUtil.DASHED;
+ }
+ String cachePort = CacheObject.get(PID_PORT, pid);
+ if (cachePort != null) {
+ return cachePort;
+ }
+ List list = this.listNetstat(pid, true);
+ if (list == null) {
+ return StrUtil.DASHED;
+ }
+ List ports = new ArrayList<>();
+ for (NetstatModel model : list) {
+ String local = model.getLocal();
+ String portStr = getPortFormLocalIp(local);
+ if (portStr == null) {
+ continue;
+ }
+ // 取最小的端口号
+ int minPort = Convert.toInt(portStr, Integer.MAX_VALUE);
+ if (minPort == Integer.MAX_VALUE) {
+ continue;
+ }
+ ports.add(minPort);
+ }
+ if (CollUtil.isEmpty(ports)) {
+ return StrUtil.DASHED;
+ }
+ String allPort = CollUtil.join(ports, StrUtil.COMMA);
+ // 缓存
+ CacheObject.put(PID_PORT, pid, allPort);
+ return allPort;
+ }
+
+ /**
+ * 判断ip 信息是否为本地ip
+ *
+ * @param local ip信息
+ * @return true 是本地ip
+ */
+ private String getPortFormLocalIp(String local) {
+ if (StrUtil.isEmpty(local)) {
+ return null;
+ }
+ List ipPort = StrSplitter.splitTrim(local, StrUtil.COLON, true);
+ if (ipPort.isEmpty()) {
+ return null;
+ }
+ String anObject = ipPort.get(0);
+ if (StrUtil.equalsAny(anObject, "0.0.0.0", "*") || ipPort.size() == 1) {
+ // 0.0.0.0:8084 || :::18000 || *:2123
+ return ipPort.get(ipPort.size() - 1);
+ }
+ return null;
+ }
+
+
+ /**
+ * 是否正在运行
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return true 正在运行
+ */
+ public boolean isRun(NodeProjectInfoModel nodeProjectInfoModel) {
+ NodeProjectInfoModel originalModel = projectInfoService.resolveModel(nodeProjectInfoModel);
+ return this.isRun(nodeProjectInfoModel, originalModel);
+ }
+
+ /**
+ * 是否正在运行
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return true 正在运行
+ */
+ public boolean isRun(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel) {
+ CommandOpResult result = this.status(nodeProjectInfoModel, originalModel);
+ return result.isSuccess();
+ }
+
+ /***
+ * 阻塞检查程序状态
+ * @param nodeProjectInfoModel 项目
+ * @param status 要检查的状态
+ *
+ * @return 和参数status相反
+ */
+ protected boolean loopCheckRun(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel, boolean status) {
+ int statusWaitTime = projectConfig.getStatusWaitTime();
+ return this.loopCheckRun(nodeProjectInfoModel, originalModel, statusWaitTime, status);
+ }
+
+ /***
+ * 阻塞检查程序状态
+ * @param nodeProjectInfoModel 项目
+ * @param status 要检查的状态
+ * @param waitTime 检查等待时间
+ *
+ * @return 如果和期望一致则返回 true,反之 false
+ */
+ protected boolean loopCheckRun(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel, int waitTime, boolean status) {
+ waitTime = Math.max(waitTime, 1);
+ int statusDetectionInterval = projectConfig.getStatusDetectionInterval();
+ statusDetectionInterval = Math.max(statusDetectionInterval, 1);
+ int loopCount = (int) (TimeUnit.SECONDS.toMillis(waitTime) / 500);
+ int count = 0;
+ do {
+ if (this.isRun(nodeProjectInfoModel, originalModel) == status) {
+ // 是期望的结果
+ return true;
+ }
+ ThreadUtil.sleep(statusDetectionInterval);
+ } while (count++ < loopCount);
+ return false;
+ }
+
+ /**
+ * 执行shell命令
+ *
+ * @param consoleCommandOp 执行的操作
+ * @param nodeProjectInfoModel 项目信息
+ * @return 执行结果
+ */
+ public CommandOpResult execCommand(ConsoleCommandOp consoleCommandOp, NodeProjectInfoModel nodeProjectInfoModel) {
+ NodeProjectInfoModel originalModel = projectInfoService.resolveModel(nodeProjectInfoModel);
+ CommandOpResult result;
+ // 执行命令
+ switch (consoleCommandOp) {
+ case restart:
+ result = this.restart(nodeProjectInfoModel, originalModel);
+ break;
+ case start:
+ result = this.start(nodeProjectInfoModel, originalModel, false);
+ break;
+ case stop:
+ result = this.stop(nodeProjectInfoModel, originalModel, false);
+ break;
+ case status: {
+ result = this.status(nodeProjectInfoModel, originalModel);
+ break;
+ }
+ case reload: {
+ result = this.reload(nodeProjectInfoModel, originalModel);
+ break;
+ }
+ case showlog:
+ default:
+ throw new IllegalArgumentException(consoleCommandOp + " error");
+ }
+ return result;
+ }
+
+ /**
+ * 获取项目文件中的所有jar 文件
+ *
+ * @param runMode 运行模式
+ * @param path 目录
+ * @return list
+ */
+ protected List listJars(RunMode runMode, String path) {
+ //File fileLib = projectInfoService.resolveLibFile(nodeProjectInfoModel);
+ return this.listJars(runMode, FileUtil.file(path));
+ }
+
+ /**
+ * 获取项目文件中的所有jar 文件
+ *
+ * @param runMode 运行模式
+ * @param path 目录
+ * @return list
+ */
+ protected List listJars(RunMode runMode, File path) {
+ File[] files = path.listFiles();
+ if (files == null) {
+ return new ArrayList<>();
+ }
+ return Arrays.stream(files)
+ .filter(File::isFile)
+ .filter(file -> {
+ if (runMode == RunMode.ClassPath || runMode == RunMode.Jar || runMode == RunMode.JavaExtDirsCp) {
+ return StrUtil.endWith(file.getName(), FileUtil.JAR_FILE_EXT, true);
+ } else if (runMode == RunMode.JarWar) {
+ return StrUtil.endWith(file.getName(), "war", true);
+ }
+ return false;
+ })
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * 拼接java 执行的jar路径
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return classpath 或者 jar
+ */
+ protected String getClassPathLib(NodeProjectInfoModel nodeProjectInfoModel, String lib) {
+ RunMode runMode = nodeProjectInfoModel.getRunMode();
+ List files = this.listJars(runMode, lib);
+ if (CollUtil.isEmpty(files)) {
+ return "";
+ }
+ // 获取lib下面的所有jar包
+ StringBuilder classPath = new StringBuilder();
+
+ int len = files.size();
+ if (runMode == RunMode.ClassPath) {
+ classPath.append("-classpath ");
+ } else if (runMode == RunMode.Jar || runMode == RunMode.JarWar) {
+ classPath.append("-jar ");
+ // 只取一个jar文件
+ len = 1;
+ } else if (runMode == RunMode.JavaExtDirsCp) {
+ classPath.append("-Djava.ext.dirs=");
+ String javaExtDirsCp = nodeProjectInfoModel.javaExtDirsCp();
+ String[] split = StrUtil.splitToArray(javaExtDirsCp, StrUtil.COLON);
+ if (ArrayUtil.isEmpty(split)) {
+ classPath.append(". -cp ");
+ } else {
+ classPath.append(split[0]).append(" -cp ");
+ if (split.length > 1) {
+ classPath.append(split[1]).append(FileUtil.PATH_SEPARATOR);
+ }
+ }
+ } else {
+ return StrUtil.EMPTY;
+ }
+ for (int i = 0; i < len; i++) {
+ File file = files.get(i);
+ classPath.append(file.getAbsolutePath());
+ if (i != len - 1) {
+ classPath.append(FileUtil.PATH_SEPARATOR);
+ }
+ }
+ return classPath.toString();
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/AbstractSystemCommander.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/AbstractSystemCommander.java
new file mode 100644
index 0000000000..6a9dc9a715
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/AbstractSystemCommander.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander;
+
+import org.dromara.jpom.util.CommandUtil;
+
+import java.io.File;
+
+/**
+ * 系统监控命令
+ *
+ * @author bwcx_jzy
+ * @since 2019/4/16
+ */
+public abstract class AbstractSystemCommander implements SystemCommander {
+
+
+ /**
+ * 清空文件内容
+ *
+ * @param file 文件
+ * @return 执行结果
+ */
+ public abstract String emptyLogFile(File file);
+
+// /**
+// * 查询服务状态
+// *
+// * @param serviceName 服务名称
+// * @return true 运行中
+// */
+// public abstract boolean getServiceStatus(String serviceName);
+//
+// /**
+// * 启动服务
+// *
+// * @param serviceName 服务名称
+// * @return 结果
+// */
+// public abstract String startService(String serviceName);
+//
+// /**
+// * 关闭服务
+// *
+// * @param serviceName 服务名称
+// * @return 结果
+// */
+// public abstract String stopService(String serviceName);
+
+ /**
+ * 构建kill 命令
+ *
+ * @param pid 进程编号
+ * @return 结束进程命令
+ */
+ public abstract String buildKill(int pid);
+
+ /**
+ * kill
+ *
+ * @param pid 进程编号
+ */
+ public String kill(File file, int pid) {
+ String kill = buildKill(pid);
+ return CommandUtil.execSystemCommand(kill, file);
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/BaseUnixProjectCommander.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/BaseUnixProjectCommander.java
new file mode 100644
index 0000000000..465aa4c769
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/BaseUnixProjectCommander.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander;
+
+import cn.hutool.core.text.StrSplitter;
+import cn.hutool.core.util.StrUtil;
+import lombok.Lombok;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.configuration.ProjectConfig;
+import org.dromara.jpom.model.data.NodeProjectInfoModel;
+import org.dromara.jpom.service.manage.ProjectInfoService;
+import org.dromara.jpom.service.script.DslScriptServer;
+import org.dromara.jpom.util.CommandUtil;
+import org.dromara.jpom.util.JvmUtil;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * unix
+ *
+ * @author bwcx_jzy
+ * @since 2021/12/17
+ */
+@Slf4j
+public abstract class BaseUnixProjectCommander extends AbstractProjectCommander {
+
+ public BaseUnixProjectCommander(Charset fileCharset,
+ SystemCommander systemCommander,
+ ProjectConfig projectConfig,
+ DslScriptServer dslScriptServer,
+ ProjectInfoService projectInfoService) {
+ super(fileCharset, systemCommander, projectConfig, dslScriptServer, projectInfoService);
+ }
+
+ @Override
+ public String buildRunCommand(NodeProjectInfoModel nodeProjectInfoModel) {
+ NodeProjectInfoModel infoModel = projectInfoService.resolveModel(nodeProjectInfoModel);
+ return this.buildRunCommand(nodeProjectInfoModel, infoModel);
+ }
+
+
+ @Override
+ public String buildRunCommand(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel) {
+ String lib = projectInfoService.resolveLibPath(originalModel);
+ String path = this.getClassPathLib(originalModel, lib);
+ if (StrUtil.isBlank(path)) {
+ return null;
+ }
+ String tag = nodeProjectInfoModel.getId();
+ String absoluteLog = projectInfoService.resolveAbsoluteLog(nodeProjectInfoModel, originalModel);
+ return StrUtil.format("nohup {} {} {} {} {} {} >> {} 2>&1 &",
+ getRunJavaPath(nodeProjectInfoModel, false),
+ Optional.ofNullable(nodeProjectInfoModel.getJvm()).orElse(StrUtil.EMPTY),
+ JvmUtil.getJpomPidTag(tag, lib),
+ path,
+ Optional.ofNullable(originalModel.mainClass()).orElse(StrUtil.EMPTY),
+ Optional.ofNullable(nodeProjectInfoModel.getArgs()).orElse(StrUtil.EMPTY),
+ absoluteLog);
+ }
+
+ @Override
+ public CommandOpResult stopJava(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel, int pid) {
+ File file = projectInfoService.resolveLibFile(originalModel);
+ List result = new ArrayList<>();
+ boolean success = false;
+ String kill = systemCommander.kill(file, pid);
+ result.add(kill);
+ if (this.loopCheckRun(nodeProjectInfoModel, originalModel, false)) {
+ success = true;
+ } else {
+ // 强制杀进程
+ result.add("Kill not completed, test kill -9");
+ String cmd = String.format("kill -9 %s", pid);
+ try {
+ CommandUtil.asyncExeLocalCommand(cmd, file, null, true);
+ } catch (Exception e) {
+ throw Lombok.sneakyThrow(e);
+ }
+ //
+ if (this.loopCheckRun(nodeProjectInfoModel, originalModel, 5, false)) {
+ success = true;
+ } else {
+ result.add("Kill -9 not completed, kill -9 failed ");
+ }
+ }
+ String tag = nodeProjectInfoModel.getId();
+ return CommandOpResult.of(success, status(tag)).appendMsg(result);
+// return status(tag) + StrUtil.SPACE + kill;
+ }
+
+ /**
+ * 尝试ps -ef | grep 中查看进程id
+ *
+ * @param tag 进程标识
+ * @return 运行标识
+ */
+ @Override
+ protected String bySystemPs(String tag) {
+ String execSystemCommand = CommandUtil.execSystemCommand("ps -ef | grep " + tag);
+ log.debug("getPsStatus {} {}", tag, execSystemCommand);
+ List list = StrSplitter.splitTrim(execSystemCommand, StrUtil.LF, true);
+ for (String item : list) {
+ if (JvmUtil.checkCommandLineIsJpom(item, tag)) {
+ String[] split = StrUtil.splitToArray(item, StrUtil.SPACE);
+ return StrUtil.format("{}:{}", AbstractProjectCommander.RUNNING_TAG, split[1]);
+ }
+ }
+ return AbstractProjectCommander.STOP_TAG;
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/CacheObject.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/CacheObject.java
new file mode 100644
index 0000000000..0316d19edb
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/CacheObject.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander;
+
+import cn.hutool.core.date.SystemClock;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author bwcx_jzy
+ * @since 2023/4/6
+ */
+public class CacheObject {
+
+ private final T value;
+
+ private final Long enterTime;
+
+ public CacheObject(T value) {
+ this.value = value;
+ this.enterTime = SystemClock.now();
+ }
+
+ private boolean isExpired() {
+ return (System.currentTimeMillis() - this.enterTime > TimeUnit.MINUTES.toMillis(10));
+ }
+
+ /**
+ * 添加到缓存对象中
+ *
+ * @param map map
+ * @param key 缓存的 key
+ * @param value 缓存的 value
+ * @param 缓存的 key
+ * @param 缓存的 value
+ */
+ public static void put(Map> map, K key, V value) {
+ map.put(key, new CacheObject<>(value));
+ int size = map.size();
+ if (size > 100) {
+ // 清空过期的数据
+ Iterator>> iterator = map.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry> next = iterator.next();
+ CacheObject nextValue = next.getValue();
+ if (nextValue.isExpired()) {
+ iterator.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * 获取缓存中的值
+ *
+ * @param map 缓存 map
+ * @param key 缓存的 key
+ * @param 缓存的 key
+ * @return value
+ */
+ public static V get(Map> map, K key) {
+ CacheObject cacheObject = map.get(key);
+ if (cacheObject == null || cacheObject.isExpired()) {
+ map.remove(key);
+ return null;
+ }
+ return cacheObject.value;
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/CommandOpResult.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/CommandOpResult.java
new file mode 100644
index 0000000000..ef3cf7ef05
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/CommandOpResult.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 命令操作执行结果
+ *
+ * @author bwcx_jzy
+ * @since 2022/11/30
+ */
+@Data
+public class CommandOpResult {
+
+ /**
+ * 是否成功
+ */
+ private Boolean success;
+ /**
+ * 进程id
+ */
+ private Integer pid;
+ /**
+ * 多个进程 id
+ */
+ private Integer[] pids;
+ /**
+ * 端口
+ */
+ private String ports;
+ /**
+ * 状态消息
+ */
+ private String statusMsg;
+ /**
+ * 执行结果
+ */
+ private final List msgs = new ArrayList<>();
+
+ /**
+ * 执行是否成功
+ *
+ * @return true 成功
+ */
+ public boolean isSuccess() {
+ return success != null && success;
+ }
+
+ /**
+ * 构建结构对象
+ *
+ * @param msg 结果消息
+ * @return result
+ */
+ public static CommandOpResult of(String msg) {
+ int[] pidsArray = null;
+ String ports = null;
+ if (StrUtil.startWith(msg, AbstractProjectCommander.RUNNING_TAG)) {
+ List list = StrUtil.splitTrim(msg, StrUtil.COLON);
+ String pids = CollUtil.get(list, 1);
+ pidsArray = StrUtil.splitToInt(pids, StrUtil.COMMA);
+ //
+ ports = CollUtil.get(list, 2);
+ }
+ int mainPid = ObjectUtil.defaultIfNull(ArrayUtil.get(pidsArray, 0), 0);
+ CommandOpResult result = of(mainPid > 0, msg);
+ if (ArrayUtil.length(pidsArray) > 1) {
+ // 仅有多个进程号,才返回 pids
+ result.pids = ArrayUtil.wrap(pidsArray);
+ }
+ result.pid = mainPid;
+ result.ports = ports;
+ result.statusMsg = msg;
+ return result;
+ }
+
+ public static CommandOpResult of(boolean success) {
+ return of(success, (List) null);
+ }
+
+ public static CommandOpResult of(boolean success, String msg) {
+ CommandOpResult commandOpResult = new CommandOpResult();
+ commandOpResult.success = success;
+ commandOpResult.appendMsg(msg);
+ return commandOpResult;
+ }
+
+ public static CommandOpResult of(boolean success, List msg) {
+ CommandOpResult commandOpResult = new CommandOpResult();
+ commandOpResult.success = success;
+ Optional.ofNullable(msg).ifPresent(commandOpResult.msgs::addAll);
+ return commandOpResult;
+ }
+
+ public CommandOpResult appendMsg(String msg) {
+ if (StrUtil.isEmpty(msg)) {
+ return this;
+ }
+ msgs.add(msg);
+ return this;
+ }
+
+ public CommandOpResult appendMsg(List msgs) {
+ for (String msg : msgs) {
+ this.appendMsg(msg);
+ }
+ return this;
+ }
+
+ public String msgStr() {
+ return CollUtil.join(msgs, StrUtil.COMMA);
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/Commander.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/Commander.java
new file mode 100644
index 0000000000..01ed46b3de
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/Commander.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander;
+
+import cn.hutool.system.OsInfo;
+import cn.hutool.system.SystemUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.common.i18n.I18nMessageUtil;
+import org.dromara.jpom.system.JpomRuntimeException;
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+/**
+ * @author bwcx_jzy
+ * @since 23/12/29 029
+ */
+@Configuration
+@Slf4j
+public class Commander {
+
+ public Commander() {
+ OsInfo osInfo = SystemUtil.getOsInfo();
+ if (osInfo.isLinux()) {
+ // Linux系统
+ log.debug(I18nMessageUtil.get("i18n.current_system_is_linux.e377"));
+ } else if (osInfo.isWindows()) {
+ // Windows系统
+ log.debug(I18nMessageUtil.get("i18n.current_system_is_windows.91d1"));
+ } else if (osInfo.isMac()) {
+ log.debug(I18nMessageUtil.get("i18n.current_system_is_mac.0139"));
+ } else {
+ throw new JpomRuntimeException(I18nMessageUtil.get("i18n.unsupported_item.bcf4") + osInfo.getName());
+ }
+ }
+
+ public static class Windows implements Condition {
+
+ @Override
+ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ return SystemUtil.getOsInfo().isWindows();
+ }
+ }
+
+ public static class Linux implements Condition {
+
+ @Override
+ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ return SystemUtil.getOsInfo().isLinux();
+ }
+ }
+
+ public static class Mac implements Condition {
+
+ @Override
+ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ return SystemUtil.getOsInfo().isMac();
+ }
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/ProjectCommander.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/ProjectCommander.java
new file mode 100644
index 0000000000..89e68e5ab0
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/ProjectCommander.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander;
+
+import org.dromara.jpom.model.data.NodeProjectInfoModel;
+import org.dromara.jpom.socket.ConsoleCommandOp;
+
+/**
+ * @author bwcx_jzy
+ * @since 23/12/29 029
+ */
+public interface ProjectCommander {
+
+ /**
+ * 生成可以执行的命令
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return null 是条件不足
+ */
+ String buildRunCommand(NodeProjectInfoModel nodeProjectInfoModel);
+
+ /**
+ * 执行 webhooks 通知
+ *
+ * @param nodeProjectInfoModel 项目信息
+ * @param type 类型
+ * @param other 其他参数
+ */
+ void asyncWebHooks(NodeProjectInfoModel nodeProjectInfoModel, String type, Object... other);
+
+
+ /**
+ * 清空日志信息
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return 结果
+ */
+ String backLog(NodeProjectInfoModel nodeProjectInfoModel);
+
+
+ /**
+ * 获取进程占用的主要端口
+ *
+ * @param pid 进程id
+ * @return 端口
+ */
+ String getMainPort(Integer pid);
+
+
+ /**
+ * 是否正在运行
+ *
+ * @param nodeProjectInfoModel 项目
+ * @return true 正在运行
+ */
+ boolean isRun(NodeProjectInfoModel nodeProjectInfoModel);
+
+
+ /**
+ * 执行shell命令
+ *
+ * @param consoleCommandOp 执行的操作
+ * @param nodeProjectInfoModel 项目信息
+ * @return 执行结果
+ */
+ CommandOpResult execCommand(ConsoleCommandOp consoleCommandOp, NodeProjectInfoModel nodeProjectInfoModel);
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/SystemCommander.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/SystemCommander.java
new file mode 100644
index 0000000000..d7468dec9a
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/SystemCommander.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander;
+
+import java.io.File;
+
+/**
+ * @author bwcx_jzy
+ * @since 23/12/29 029
+ */
+public interface SystemCommander {
+
+ /**
+ * 清空文件内容
+ *
+ * @param file 文件
+ * @return 执行结果
+ */
+ String emptyLogFile(File file);
+
+
+ /**
+ * kill 进程
+ *
+ * @param pid 进程编号
+ * @param file 指定文件夹执行
+ * @return 结束进程命令
+ */
+
+ String kill(File file, int pid);
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/LinuxProjectCommander.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/LinuxProjectCommander.java
new file mode 100644
index 0000000000..5d2283cc8b
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/LinuxProjectCommander.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.text.StrSplitter;
+import cn.hutool.core.util.StrUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.common.commander.BaseUnixProjectCommander;
+import org.dromara.jpom.common.commander.Commander;
+import org.dromara.jpom.common.commander.SystemCommander;
+import org.dromara.jpom.configuration.AgentConfig;
+import org.dromara.jpom.model.system.NetstatModel;
+import org.dromara.jpom.service.manage.ProjectInfoService;
+import org.dromara.jpom.service.script.DslScriptServer;
+import org.dromara.jpom.util.CommandUtil;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * linux
+ *
+ * @author bwcx_jzy
+ */
+@Conditional(Commander.Linux.class)
+@Service
+@Primary
+@Slf4j
+public class LinuxProjectCommander extends BaseUnixProjectCommander {
+
+ public LinuxProjectCommander(AgentConfig agentConfig,
+ SystemCommander systemCommander,
+ DslScriptServer dslScriptServer,
+ ProjectInfoService projectInfoService) {
+ super(agentConfig.getProject().getLog().getFileCharset(), systemCommander, agentConfig.getProject(), dslScriptServer, projectInfoService);
+ }
+
+ @Override
+ public List listNetstat(int pId, boolean listening) {
+ String cmd;
+ if (listening) {
+ cmd = "netstat -antup | grep " + pId + " |grep \"LISTEN\" | head -20";
+ } else {
+ cmd = "netstat -antup | grep " + pId + " |grep -v \"CLOSE_WAIT\" | head -20";
+ }
+ return this.listNetstat(cmd);
+ }
+
+ protected List listNetstat(String cmd) {
+ String result = CommandUtil.execSystemCommand(cmd);
+ List netList = StrSplitter.splitTrim(result, StrUtil.LF, true);
+ if (CollUtil.isEmpty(netList)) {
+ return null;
+ }
+ return netList.stream().map(str -> {
+ List list = StrSplitter.splitTrim(str, " ", true);
+ if (list.size() < 5) {
+ return null;
+ }
+ NetstatModel netstatModel = new NetstatModel();
+ netstatModel.setProtocol(list.get(0));
+ netstatModel.setReceive(list.get(1));
+ netstatModel.setSend(list.get(2));
+ netstatModel.setLocal(list.get(3));
+ netstatModel.setForeign(list.get(4));
+ if ("tcp".equalsIgnoreCase(netstatModel.getProtocol())) {
+ netstatModel.setStatus(CollUtil.get(list, 5));
+ netstatModel.setName(CollUtil.get(list, 6));
+ } else {
+ netstatModel.setStatus(StrUtil.DASHED);
+ netstatModel.setName(CollUtil.get(list, 5));
+ }
+
+ return netstatModel;
+ }).filter(Objects::nonNull).collect(Collectors.toList());
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/LinuxSystemCommander.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/LinuxSystemCommander.java
new file mode 100644
index 0000000000..4980c8deb3
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/LinuxSystemCommander.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander.impl;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.common.commander.AbstractSystemCommander;
+import org.dromara.jpom.common.commander.Commander;
+import org.dromara.jpom.util.CommandUtil;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+
+/**
+ * @author bwcx_jzy
+ * @since 2019/4/16
+ */
+@Slf4j
+@Conditional(Commander.Linux.class)
+@Service
+@Primary
+public class LinuxSystemCommander extends AbstractSystemCommander {
+
+
+ @Override
+ public String emptyLogFile(File file) {
+ return CommandUtil.execSystemCommand("cp /dev/null " + file.getAbsolutePath());
+ }
+
+
+// @Override
+// public boolean getServiceStatus(String serviceName) {
+// if (StrUtil.startWith(serviceName, StrUtil.SLASH)) {
+// String ps = getPs(serviceName);
+// return StrUtil.isNotEmpty(ps);
+// }
+// String format = StrUtil.format("service {} status", serviceName);
+// String result = CommandUtil.execSystemCommand(format);
+// return StrUtil.containsIgnoreCase(result, "RUNNING");
+// }
+//
+// @Override
+// public String startService(String serviceName) {
+// if (StrUtil.startWith(serviceName, StrUtil.SLASH)) {
+// try {
+// CommandUtil.asyncExeLocalCommand(FileUtil.file(SystemUtil.getUserInfo().getHomeDir()), serviceName);
+// return "ok";
+// } catch (Exception e) {
+// log.error("执行异常", e);
+// return "执行异常:" + e.getMessage();
+// }
+// }
+// String format = StrUtil.format("service {} start", serviceName);
+// return CommandUtil.execSystemCommand(format);
+// }
+//
+// @Override
+// public String stopService(String serviceName) {
+// if (StrUtil.startWith(serviceName, StrUtil.SLASH)) {
+// String ps = getPs(serviceName);
+// List list = StrUtil.splitTrim(ps, StrUtil.LF);
+// if (list == null || list.isEmpty()) {
+// return "stop";
+// }
+// String s = list.get(0);
+// list = StrUtil.splitTrim(s, StrUtil.SPACE);
+// if (list == null || list.size() < 2) {
+// return "stop";
+// }
+// File file = new File(SystemUtil.getUserInfo().getHomeDir());
+// int pid = Convert.toInt(list.get(1), 0);
+// if (pid <= 0) {
+// return "error stop";
+// }
+// return kill(file, pid);
+// }
+// String format = StrUtil.format("service {} stop", serviceName);
+// return CommandUtil.execSystemCommand(format);
+// }
+
+ @Override
+ public String buildKill(int pid) {
+ return String.format("kill %s", pid);
+ }
+
+ private String getPs(String serviceName) {
+ String ps = StrUtil.format("ps -ef | grep -v 'grep' | egrep {}", serviceName);
+ return CommandUtil.execSystemCommand(ps);
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/MacOsProjectCommander.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/MacOsProjectCommander.java
new file mode 100644
index 0000000000..1593fa6118
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/MacOsProjectCommander.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.text.StrSplitter;
+import cn.hutool.core.util.StrUtil;
+import org.dromara.jpom.common.commander.BaseUnixProjectCommander;
+import org.dromara.jpom.common.commander.Commander;
+import org.dromara.jpom.common.commander.SystemCommander;
+import org.dromara.jpom.configuration.AgentConfig;
+import org.dromara.jpom.model.system.NetstatModel;
+import org.dromara.jpom.service.manage.ProjectInfoService;
+import org.dromara.jpom.service.script.DslScriptServer;
+import org.dromara.jpom.util.CommandUtil;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * MacOSProjectCommander
+ *
+ * some commands cannot execute success on Mac OS
+ *
+ * @author Hotstrip
+ */
+@Conditional(Commander.Mac.class)
+@Service
+public class MacOsProjectCommander extends BaseUnixProjectCommander {
+
+ public MacOsProjectCommander(AgentConfig agentConfig,
+ SystemCommander systemCommander,
+ DslScriptServer dslScriptServer,
+ ProjectInfoService projectInfoService) {
+ super(agentConfig.getProject().getLog().getFileCharset(), systemCommander, agentConfig.getProject(), dslScriptServer, projectInfoService);
+ }
+
+ @Override
+ public List listNetstat(int pId, boolean listening) {
+ String cmd;
+ if (listening) {
+ cmd = "lsof -n -P -iTCP -sTCP:LISTEN |grep " + pId + " | head -20";
+ } else {
+ cmd = "lsof -n -P -iTCP -sTCP:CLOSE_WAIT |grep " + pId + " | head -20";
+ }
+ return this.listNetstat(cmd);
+ }
+
+ protected List listNetstat(String cmd) {
+ String result = CommandUtil.execSystemCommand(cmd);
+ List netList = StrSplitter.splitTrim(result, StrUtil.LF, true);
+ if (CollUtil.isEmpty(netList)) {
+ return null;
+ }
+ return netList.stream()
+ .map(str -> {
+ List list = StrSplitter.splitTrim(str, " ", true);
+ if (list.size() < 10) {
+ return null;
+ }
+ NetstatModel netstatModel = new NetstatModel();
+ netstatModel.setProtocol(list.get(7));
+ //netstatModel.setReceive(list.get(1));
+ //netstatModel.setSend(list.get(2));
+ netstatModel.setLocal(list.get(8));
+ netstatModel.setForeign(list.get(4));
+ if ("tcp".equalsIgnoreCase(netstatModel.getProtocol())) {
+ netstatModel.setStatus(CollUtil.get(list, 9));
+ netstatModel.setName(CollUtil.get(list, 0));
+ } else {
+ netstatModel.setStatus(StrUtil.DASHED);
+ netstatModel.setName(CollUtil.get(list, 5));
+ }
+
+ return netstatModel;
+ })
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/MacOsSystemCommander.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/MacOsSystemCommander.java
new file mode 100644
index 0000000000..289a2c07c0
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/MacOsSystemCommander.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.common.commander.AbstractSystemCommander;
+import org.dromara.jpom.common.commander.Commander;
+import org.dromara.jpom.util.CommandUtil;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+
+/**
+ * @author User
+ */
+@Slf4j
+@Conditional(Commander.Mac.class)
+@Service
+public class MacOsSystemCommander extends AbstractSystemCommander {
+
+
+ @Override
+ public String emptyLogFile(File file) {
+ return CommandUtil.execSystemCommand("cp /dev/null " + file.getAbsolutePath());
+ }
+
+
+// @Override
+// public boolean getServiceStatus(String serviceName) {
+// if (StrUtil.startWith(serviceName, StrUtil.SLASH)) {
+// String ps = getPs(serviceName);
+// return StrUtil.isNotEmpty(ps);
+// }
+// /**
+// * Mac OS 里面查询服务的命令是 launchctl list | grep serverName
+// * 第一个数字是进程的 PID,如果进程正在运行,如果它不在运行,则显示 "-"
+// * 第二个数字是进程的退出代码(如果已完成)。如果为负,则为终止信号的数量
+// * 第三列进程名称
+// */
+// String format = StrUtil.format("service {} status", serviceName);
+// String result = CommandUtil.execSystemCommand(format);
+// return StrUtil.containsIgnoreCase(result, "RUNNING");
+// }
+//
+// private String getPs(final String serviceName) {
+// String ps = StrUtil.format(" ps -ef |grep -w {} | grep -v grep", serviceName);
+// return CommandUtil.execSystemCommand(ps);
+// }
+//
+// @Override
+// public String startService(String serviceName) {
+// if (StrUtil.startWith(serviceName, StrUtil.SLASH)) {
+// try {
+// CommandUtil.asyncExeLocalCommand(FileUtil.file(SystemUtil.getUserInfo().getHomeDir()), serviceName);
+// return "ok";
+// } catch (Exception e) {
+// log.error("执行异常", e);
+// return "执行异常:" + e.getMessage();
+// }
+// }
+// /**
+// * Mac OS 里面启动服务命令是 launchctl start serverName
+// */
+// String format = StrUtil.format("service {} start", serviceName);
+// return CommandUtil.execSystemCommand(format);
+// }
+//
+// @Override
+// public String stopService(String serviceName) {
+// if (StrUtil.startWith(serviceName, StrUtil.SLASH)) {
+// String ps = getPs(serviceName);
+// List list = StrUtil.splitTrim(ps, StrUtil.LF);
+// if (list == null || list.isEmpty()) {
+// return "stop";
+// }
+// String s = list.get(0);
+// list = StrUtil.splitTrim(s, StrUtil.SPACE);
+// if (list == null || list.size() < 2) {
+// return "stop";
+// }
+// File file = new File(SystemUtil.getUserInfo().getHomeDir());
+// int pid = Convert.toInt(list.get(1), 0);
+// if (pid <= 0) {
+// return "error stop";
+// }
+// return kill(file, pid);
+// }
+// /**
+// * Mac OS 里面启动服务命令是 launchctl stop serverName
+// */
+// String format = StrUtil.format("service {} stop", serviceName);
+// return CommandUtil.execSystemCommand(format);
+// }
+
+ @Override
+ public String buildKill(int pid) {
+ return String.format("kill %s", pid);
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/WindowsProjectCommander.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/WindowsProjectCommander.java
new file mode 100644
index 0000000000..26990b2bd9
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/WindowsProjectCommander.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander.impl;
+
+import cn.hutool.core.text.StrSplitter;
+import cn.hutool.core.util.StrUtil;
+import org.dromara.jpom.common.commander.AbstractProjectCommander;
+import org.dromara.jpom.common.commander.CommandOpResult;
+import org.dromara.jpom.common.commander.Commander;
+import org.dromara.jpom.common.commander.SystemCommander;
+import org.dromara.jpom.configuration.AgentConfig;
+import org.dromara.jpom.model.data.NodeProjectInfoModel;
+import org.dromara.jpom.model.system.NetstatModel;
+import org.dromara.jpom.service.manage.ProjectInfoService;
+import org.dromara.jpom.service.script.DslScriptServer;
+import org.dromara.jpom.util.CommandUtil;
+import org.dromara.jpom.util.JvmUtil;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * windows 版
+ *
+ * @author bwcx_jzy
+ */
+@Conditional(Commander.Windows.class)
+@Service
+public class WindowsProjectCommander extends AbstractProjectCommander {
+
+ public WindowsProjectCommander(AgentConfig agentConfig,
+ SystemCommander systemCommander,
+ DslScriptServer dslScriptServer,
+ ProjectInfoService projectInfoService) {
+ super(agentConfig.getProject().getLog().getFileCharset(), systemCommander, agentConfig.getProject(), dslScriptServer, projectInfoService);
+ }
+
+ @Override
+ public String buildRunCommand(NodeProjectInfoModel nodeProjectInfoModel) {
+ NodeProjectInfoModel infoModel = projectInfoService.resolveModel(nodeProjectInfoModel);
+ return this.buildRunCommand(nodeProjectInfoModel, infoModel);
+ }
+
+ @Override
+ public String buildRunCommand(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel) {
+ String lib = projectInfoService.resolveLibPath(originalModel);
+ String classPath = this.getClassPathLib(originalModel, lib);
+ if (StrUtil.isBlank(classPath)) {
+ return null;
+ }
+ // 拼接命令
+ String jvm = nodeProjectInfoModel.getJvm();
+ String tag = nodeProjectInfoModel.getId();
+ String mainClass = originalModel.mainClass();
+ String args = nodeProjectInfoModel.getArgs();
+
+ String absoluteLog = projectInfoService.resolveAbsoluteLog(nodeProjectInfoModel, originalModel);
+ return StrUtil.format("{} {} {} {} {} {} >> {} &",
+ getRunJavaPath(nodeProjectInfoModel, true),
+ Optional.ofNullable(jvm).orElse(StrUtil.EMPTY),
+ JvmUtil.getJpomPidTag(tag, lib),
+ classPath,
+ Optional.ofNullable(mainClass).orElse(StrUtil.EMPTY),
+ Optional.ofNullable(args).orElse(StrUtil.EMPTY),
+ absoluteLog);
+ }
+
+ @Override
+ public CommandOpResult stopJava(NodeProjectInfoModel nodeProjectInfoModel, NodeProjectInfoModel originalModel, int pid) {
+ String tag = nodeProjectInfoModel.getId();
+ List result = new ArrayList<>();
+ boolean success = false;
+ // 如果正在运行,则执行杀进程命令
+ File file = projectInfoService.resolveLibFile(nodeProjectInfoModel);
+ String kill = systemCommander.kill(file, pid);
+ result.add(kill);
+ if (this.loopCheckRun(nodeProjectInfoModel, originalModel, false)) {
+ success = true;
+ } else {
+ result.add("Kill not completed");
+ }
+ return CommandOpResult.of(success, status(tag)).appendMsg(result);
+ // return status(tag) + StrUtil.SPACE + kill;
+ }
+
+ @Override
+ public List listNetstat(int pId, boolean listening) {
+ String cmd;
+ if (listening) {
+ cmd = "netstat -nao -p tcp | findstr \"LISTENING\" | findstr " + pId;
+ } else {
+ cmd = "netstat -nao -p tcp | findstr /V \"CLOSE_WAIT\" | findstr " + pId;
+ }
+ String result = CommandUtil.execSystemCommand(cmd);
+ List netList = StrSplitter.splitTrim(result, StrUtil.LF, true);
+ if (netList == null || netList.isEmpty()) {
+ return null;
+ }
+ List array = new ArrayList<>();
+ for (String str : netList) {
+ List list = StrSplitter.splitTrim(str, " ", true);
+ if (list.size() < 5) {
+ continue;
+ }
+ NetstatModel netstatModel = new NetstatModel();
+ netstatModel.setProtocol(list.get(0));
+ netstatModel.setLocal(list.get(1));
+ netstatModel.setForeign(list.get(2));
+ netstatModel.setStatus(list.get(3));
+ netstatModel.setName(list.get(4));
+ array.add(netstatModel);
+ }
+ return array;
+ }
+
+ // tasklist | findstr /s /i "java"
+ // wmic process where caption="javaw.exe" get processid,caption,commandline /value
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/WindowsSystemCommander.java b/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/WindowsSystemCommander.java
new file mode 100644
index 0000000000..a82e64be59
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/commander/impl/WindowsSystemCommander.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.commander.impl;
+
+import org.dromara.jpom.common.commander.AbstractSystemCommander;
+import org.dromara.jpom.common.commander.Commander;
+import org.dromara.jpom.util.CommandUtil;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+
+/**
+ * windows 系统查询命令
+ *
+ * @author bwcx_jzy
+ * @since 2019/4/16
+ */
+@Conditional(Commander.Windows.class)
+@Service
+public class WindowsSystemCommander extends AbstractSystemCommander {
+
+ @Override
+ public String emptyLogFile(File file) {
+ return CommandUtil.execSystemCommand("echo \"\" > " + file.getAbsolutePath());
+ }
+
+
+// @Override
+// public boolean getServiceStatus(String serviceName) {
+// String result = CommandUtil.execSystemCommand("sc query " + serviceName);
+// return StrUtil.containsIgnoreCase(result, "RUNNING");
+// }
+//
+// @Override
+// public String startService(String serviceName) {
+// String format = StrUtil.format("net start {}", serviceName);
+// return CommandUtil.execSystemCommand(format);
+// }
+//
+// @Override
+// public String stopService(String serviceName) {
+// String format = StrUtil.format("net stop {}", serviceName);
+// return CommandUtil.execSystemCommand(format);
+// }
+
+ @Override
+ public String buildKill(int pid) {
+ return String.format("taskkill /F /PID %s", pid);
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/interceptor/AuthorizeInterceptor.java b/modules/agent/src/main/java/org/dromara/jpom/common/interceptor/AuthorizeInterceptor.java
new file mode 100644
index 0000000000..226e28ff11
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/interceptor/AuthorizeInterceptor.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.interceptor;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.servlet.ServletUtil;
+import cn.keepbx.jpom.model.JsonMessage;
+import org.dromara.jpom.common.Const;
+import org.dromara.jpom.common.i18n.I18nMessageUtil;
+import org.dromara.jpom.configuration.AgentAuthorize;
+import org.dromara.jpom.configuration.AgentConfig;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.web.method.HandlerMethod;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 授权拦截
+ *
+ * @author bwcx_jzy
+ * @since 2019/4/17
+ */
+@Configuration
+public class AuthorizeInterceptor implements HandlerMethodInterceptor {
+
+ private final AgentAuthorize agentAuthorize;
+
+ public AuthorizeInterceptor(AgentConfig agentConfig) {
+ this.agentAuthorize = agentConfig.getAuthorize();
+ }
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
+ NotAuthorize notAuthorize = handlerMethod.getMethodAnnotation(NotAuthorize.class);
+ if (notAuthorize == null) {
+ String authorize = ServletUtil.getHeaderIgnoreCase(request, Const.JPOM_AGENT_AUTHORIZE);
+ if (StrUtil.isEmpty(authorize)) {
+ this.error(response);
+ return false;
+ }
+ if (!agentAuthorize.checkAuthorize(authorize)) {
+ this.error(response);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void error(HttpServletResponse response) {
+ ServletUtil.write(response, JsonMessage.getString(Const.AUTHORIZE_ERROR, I18nMessageUtil.get("i18n.auth_info_error.c184")), MediaType.APPLICATION_JSON_VALUE);
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/interceptor/DecryptionFilter.java b/modules/agent/src/main/java/org/dromara/jpom/common/interceptor/DecryptionFilter.java
new file mode 100644
index 0000000000..37843408b4
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/interceptor/DecryptionFilter.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.interceptor;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.servlet.ServletUtil;
+import cn.hutool.http.ContentType;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
+import org.dromara.jpom.common.i18n.I18nMessageUtil;
+import org.dromara.jpom.common.transport.BodyRewritingRequestWrapper;
+import org.dromara.jpom.common.transport.MultipartRequestWrapper;
+import org.dromara.jpom.common.transport.ParameterRequestWrapper;
+import org.dromara.jpom.encrypt.EncryptFactory;
+import org.dromara.jpom.encrypt.Encryptor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.MediaType;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * @author loyal.f
+ * @since 2023/3/13
+ */
+@Configuration
+@Slf4j
+@Order(1)
+public class DecryptionFilter implements Filter {
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ String transportEncryption = request.getHeader("transport-encryption");
+ // 兼容没有没有传入
+ Encryptor encryptor;
+ try {
+ encryptor = EncryptFactory.createEncryptor(Convert.toInt(transportEncryption, 0));
+ } catch (NoSuchAlgorithmException e) {
+ log.error(I18nMessageUtil.get("i18n.get_decrypt_distribution_failure.4feb"), e);
+ chain.doFilter(servletRequest, response);
+ return;
+ }
+ log.debug(I18nMessageUtil.get("i18n.request_needs_decoding.d4d7"), encryptor.name());
+ String contentType = request.getContentType();
+ if (ContentType.isDefault(contentType)) {
+ // 普通表单
+ HttpServletRequestWrapper wrapper = new ParameterRequestWrapper(request, encryptor);
+ chain.doFilter(wrapper, response);
+ } else if (StrUtil.startWithIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE)) {
+ String body = ServletUtil.getBody(request);
+ String temp;
+ try {
+ temp = encryptor.decrypt(body);
+ } catch (Exception e) {
+ log.error(I18nMessageUtil.get("i18n.decode_failure.822e"), e);
+ temp = body;
+ }
+ BodyRewritingRequestWrapper requestWrapper = new BodyRewritingRequestWrapper(request, temp.getBytes(StandardCharsets.UTF_8));
+ chain.doFilter(requestWrapper, response);
+ } else if (ServletFileUpload.isMultipartContent(request)) {
+ // 文件上传
+ HttpServletRequestWrapper wrapper = new MultipartRequestWrapper(request, encryptor);
+ chain.doFilter(wrapper, response);
+ } else {
+ log.warn(I18nMessageUtil.get("i18n.request_type_not_supported_for_decoding.ea2e"), contentType);
+ chain.doFilter(servletRequest, response);
+ }
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/common/interceptor/NotAuthorize.java b/modules/agent/src/main/java/org/dromara/jpom/common/interceptor/NotAuthorize.java
new file mode 100644
index 0000000000..65aef5229b
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/common/interceptor/NotAuthorize.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.common.interceptor;
+
+import java.lang.annotation.*;
+
+/**
+ * 不需要授权
+ *
+ * @author bwcx_jzy
+ * @since 2019/4/17
+ */
+@Documented
+@Target(ElementType.METHOD)
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NotAuthorize {
+}
+
diff --git a/modules/agent/src/main/java/org/dromara/jpom/configuration/AgentAuthorize.java b/modules/agent/src/main/java/org/dromara/jpom/configuration/AgentAuthorize.java
new file mode 100644
index 0000000000..239d3a7fbf
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/configuration/AgentAuthorize.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.configuration;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.SecureUtil;
+import com.alibaba.fastjson2.JSONObject;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.JpomApplication;
+import org.dromara.jpom.common.Const;
+import org.dromara.jpom.common.i18n.I18nMessageUtil;
+import org.dromara.jpom.model.system.AgentAutoUser;
+import org.dromara.jpom.system.JpomRuntimeException;
+import org.dromara.jpom.util.JsonFileUtil;
+import org.dromara.jpom.util.JvmUtil;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.io.File;
+
+/**
+ * agent 端授权账号信息
+ *
+ * @author bwcx_jzy
+ * @since 2019/4/17
+ */
+@Slf4j
+@Data
+@ConfigurationProperties("jpom.authorize")
+public class AgentAuthorize {
+ /**
+ * 账号
+ */
+ private String agentName;
+ /**
+ * 密码
+ */
+ private String agentPwd;
+ /**
+ * 授权加密字符串
+ */
+ private String authorize;
+
+ public void setAuthorize(String authorize) {
+ // 不能外部 set
+ }
+
+ public String getAuthorize() {
+ return null;
+ }
+
+
+ /**
+ * 判断授权是否正确
+ *
+ * @param authorize 授权
+ * @return true 正确
+ */
+ public boolean checkAuthorize(String authorize) {
+ return StrUtil.equals(authorize, this.authorize);
+ }
+
+ /**
+ * 检查是否配置密码
+ */
+ private void checkPwd(JpomApplication configBean) {
+ File path = FileUtil.file(configBean.getDataPath(), Const.AUTHORIZE);
+ if (StrUtil.isNotEmpty(agentPwd)) {
+ // 有指定密码 清除旧密码信息
+ FileUtil.del(path);
+ log.info("Authorization information has been customized,account:{}", this.agentName);
+ return;
+ }
+ if (FileUtil.exist(path)) {
+ // 读取旧密码
+ String json = FileUtil.readString(path, CharsetUtil.CHARSET_UTF_8);
+ AgentAutoUser autoUser = JSONObject.parseObject(json, AgentAutoUser.class);
+ if (!StrUtil.equals(autoUser.getAgentName(), this.agentName)) {
+ throw new JpomRuntimeException("The existing login name is inconsistent with the configured login name");
+ }
+ String oldAgentPwd = autoUser.getAgentPwd();
+ if (StrUtil.isNotEmpty(oldAgentPwd)) {
+ this.agentPwd = oldAgentPwd;
+ log.info("Already authorized account:{} password:{} Authorization information storage location:{}", this.agentName, this.agentPwd, FileUtil.getAbsolutePath(path));
+ return;
+ }
+ }
+ this.agentPwd = RandomUtil.randomString(10);
+ AgentAutoUser autoUser = new AgentAutoUser();
+ autoUser.setAgentName(this.agentName);
+ autoUser.setAgentPwd(this.agentPwd);
+ // 写入文件中
+ JsonFileUtil.saveJson(path, autoUser.toJson());
+ log.info("Automatically generate authorized account:{} password:{} Authorization information storage location:{}", this.agentName, this.agentPwd, FileUtil.getAbsolutePath(path));
+ }
+
+ public void init(JpomApplication configBean) {
+ if (StrUtil.isEmpty(this.agentName)) {
+ throw new JpomRuntimeException("The agent login name cannot be empty");
+ }
+ if (StrUtil.isEmpty(this.authorize)) {
+ this.checkPwd(configBean);
+ // 生成密码授权字符串
+ this.authorize = SecureUtil.sha1(this.agentName + "@" + this.agentPwd);
+ } else {
+ log.warn(I18nMessageUtil.get("i18n.authorized_cannot_be_reloaded.6ece"));
+ }
+ //
+ JvmUtil.checkJpsNormal();
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/configuration/AgentConfig.java b/modules/agent/src/main/java/org/dromara/jpom/configuration/AgentConfig.java
new file mode 100644
index 0000000000..6ea3042713
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/configuration/AgentConfig.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.configuration;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.Data;
+import org.dromara.jpom.JpomApplication;
+import org.dromara.jpom.common.ILoadEvent;
+import org.dromara.jpom.system.ExtConfigBean;
+import org.dromara.jpom.util.BaseFileTailWatcher;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Configuration;
+
+import java.io.File;
+import java.util.Optional;
+
+/**
+ * 插件端配置信息
+ *
+ * @author bwcx_jzy
+ * @since 2022/12/16
+ */
+
+@Configuration
+@ConfigurationProperties("jpom")
+@Data
+@EnableConfigurationProperties({ProjectConfig.class, ProjectLogConfig.class, SystemConfig.class, AgentAuthorize.class, MonitorConfig.class, MonitorConfig.NetworkConfig.class})
+public class AgentConfig implements ILoadEvent, InitializingBean {
+
+ private final JpomApplication jpomApplication;
+
+ public AgentConfig(JpomApplication jpomApplication) {
+ this.jpomApplication = jpomApplication;
+ }
+
+ /**
+ * 授权配置
+ */
+ private AgentAuthorize authorize;
+
+ /**
+ * 项目配置
+ */
+ private ProjectConfig project;
+ /**
+ * 系统配置参数
+ */
+ private SystemConfig system;
+ /**
+ * 监控配置
+ */
+ private MonitorConfig monitor;
+
+ /**
+ * 数据目录
+ */
+ private String path;
+
+ /**
+ * 初始读取日志文件行号
+ */
+ private int initReadLine = 10;
+
+ public AgentAuthorize getAuthorize() {
+ return Optional.ofNullable(this.authorize).orElseGet(() -> {
+ this.authorize = new AgentAuthorize();
+ return this.authorize;
+ });
+ }
+
+ public ProjectConfig getProject() {
+ return Optional.ofNullable(this.project).orElseGet(() -> {
+ this.project = new ProjectConfig();
+ return this.project;
+ });
+ }
+
+ public SystemConfig getSystem() {
+ return Optional.ofNullable(this.system).orElseGet(() -> {
+ this.system = new SystemConfig();
+ return this.system;
+ });
+ }
+
+ /**
+ * 获取临时文件存储路径,并添加一个随机字符串
+ *
+ * @return 文件夹
+ */
+ public String getTempPathName() {
+ File file = getTempPath();
+ // 生成随机的一个文件夹、避免同一个节点分发同一个文件,mv 失败
+ return FileUtil.getAbsolutePath(FileUtil.file(file, IdUtil.fastSimpleUUID()));
+ }
+
+ /**
+ * 获取临时文件存储路径
+ *
+ * @return 文件夹
+ */
+ public String getFixedTempPathName() {
+ File file = getTempPath();
+ return FileUtil.getAbsolutePath(file);
+ }
+
+
+ /**
+ * 获取临时文件存储路径
+ *
+ * @return file
+ */
+ public File getTempPath() {
+ File file = jpomApplication.getTempPath();
+ file = FileUtil.file(file, DateTime.now().toDateStr());
+ FileUtil.mkdir(file);
+ return file;
+ }
+
+
+ @Override
+ public void afterPropertiesSet(ApplicationContext applicationContext) throws Exception {
+ // 登录名不能为空
+ this.getAuthorize().init(jpomApplication);
+ }
+
+ @Override
+ public int getOrder() {
+ return HIGHEST_PRECEDENCE;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ int initReadLine = ObjectUtil.defaultIfNull(this.initReadLine, 10);
+ BaseFileTailWatcher.setInitReadLine(initReadLine);
+ ExtConfigBean.setPath(path);
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/configuration/MonitorConfig.java b/modules/agent/src/main/java/org/dromara/jpom/configuration/MonitorConfig.java
new file mode 100644
index 0000000000..6584f6f05f
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/configuration/MonitorConfig.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * @author bwcx_jzy
+ * @since 2024/4/24
+ */
+@Data
+@ConfigurationProperties("jpom.monitor")
+public class MonitorConfig {
+
+ private NetworkConfig network;
+
+ @Data
+ @ConfigurationProperties("jpom.monitor.network")
+ public static class NetworkConfig {
+ /**
+ * 忽略的网卡,多个使用逗号分隔
+ */
+ private String statExcludeNames;
+ /**
+ * 仅统计的网卡
+ * ,多个使用逗号分隔
+ */
+ private String statContainsOnlyNames;
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/configuration/ProjectConfig.java b/modules/agent/src/main/java/org/dromara/jpom/configuration/ProjectConfig.java
new file mode 100644
index 0000000000..15362a3b7d
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/configuration/ProjectConfig.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.Optional;
+
+/**
+ * @author bwcx_jzy
+ * @since 23/12/29 029
+ */
+@Data
+@ConfigurationProperties("jpom.project")
+public class ProjectConfig {
+ /**
+ * 项目日志配置
+ */
+ private ProjectLogConfig log;
+ /**
+ * 停止项目等待的时长 单位秒,最小为1秒
+ */
+ private int statusWaitTime = 10;
+
+ /**
+ * 项目状态检测间隔时间 单位毫秒,最小为1毫秒
+ */
+ private int statusDetectionInterval = 500;
+
+ /**
+ * 项目文件备份保留个数,大于 1 才会备份
+ */
+ private int fileBackupCount;
+
+ /**
+ * 限制备份指定文件后缀(支持正则)
+ * [ '.jar','.html','^.+\\.(?i)(txt)$' ]
+ */
+ private String[] fileBackupSuffix;
+
+ public ProjectLogConfig getLog() {
+ return Optional.ofNullable(this.log).orElseGet(() -> {
+ this.log = new ProjectLogConfig();
+ return this.log;
+ });
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/configuration/ProjectLogConfig.java b/modules/agent/src/main/java/org/dromara/jpom/configuration/ProjectLogConfig.java
new file mode 100644
index 0000000000..2542108417
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/configuration/ProjectLogConfig.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.configuration;
+
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.system.SystemUtil;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.util.unit.DataSize;
+
+import java.nio.charset.Charset;
+import java.util.Optional;
+
+/**
+ * @author bwcx_jzy
+ * @since 23/12/29 029
+ */
+@Data
+@ConfigurationProperties("jpom.project.log")
+public class ProjectLogConfig {
+ /**
+ * 检测控制台日志周期,防止日志文件过大,目前暂只支持linux 不停服备份
+ */
+ private String autoBackupConsoleCron = "0 0/10 * * * ?";
+ /**
+ * 当文件多大时自动备份
+ *
+ * @see ch.qos.logback.core.util.FileSize
+ */
+ private DataSize autoBackupSize = DataSize.ofMegabytes(50);
+ /**
+ * 是否自动将控制台日志文件备份
+ */
+ private boolean autoBackupToFile = true;
+
+ /**
+ * 控制台日志保存时长单位天
+ */
+ private int saveDays = 7;
+
+ public int getSaveDays() {
+ return Math.max(saveDays, 0);
+ }
+
+ /**
+ * 日志文件的编码格式
+ */
+ private Charset fileCharset;
+
+ public Charset getFileCharset() {
+ return Optional.ofNullable(this.fileCharset).orElseGet(() ->
+ SystemUtil.getOsInfo().isWindows() ?
+ CharsetUtil.CHARSET_GBK : CharsetUtil.CHARSET_UTF_8);
+ }
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/configuration/SystemConfig.java b/modules/agent/src/main/java/org/dromara/jpom/configuration/SystemConfig.java
new file mode 100644
index 0000000000..ce031f20c0
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/configuration/SystemConfig.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.configuration;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.jpom.system.BaseSystemConfig;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * @author bwcx_jzy
+ * @since 23/12/29 029
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@ConfigurationProperties("jpom.system")
+public class SystemConfig extends BaseSystemConfig {
+}
diff --git a/modules/agent/src/main/java/org/dromara/jpom/controller/IndexController.java b/modules/agent/src/main/java/org/dromara/jpom/controller/IndexController.java
new file mode 100644
index 0000000000..2a75feadb1
--- /dev/null
+++ b/modules/agent/src/main/java/org/dromara/jpom/controller/IndexController.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2019 Of Him Code Technology Studio
+ * Jpom is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+package org.dromara.jpom.controller;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.system.SystemUtil;
+import cn.keepbx.jpom.IJsonMessage;
+import cn.keepbx.jpom.model.JsonMessage;
+import com.alibaba.fastjson2.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.common.BaseAgentController;
+import org.dromara.jpom.common.JpomManifest;
+import org.dromara.jpom.common.RemoteVersion;
+import org.dromara.jpom.common.commander.ProjectCommander;
+import org.dromara.jpom.common.commander.SystemCommander;
+import org.dromara.jpom.common.i18n.I18nMessageUtil;
+import org.dromara.jpom.common.interceptor.NotAuthorize;
+import org.dromara.jpom.configuration.AgentConfig;
+import org.dromara.jpom.configuration.MonitorConfig;
+import org.dromara.jpom.model.data.NodeProjectInfoModel;
+import org.dromara.jpom.model.data.NodeScriptModel;
+import org.dromara.jpom.plugin.PluginFactory;
+import org.dromara.jpom.service.manage.ProjectInfoService;
+import org.dromara.jpom.service.script.NodeScriptServer;
+import org.dromara.jpom.util.JvmUtil;
+import org.springframework.http.MediaType;
+import org.springframework.util.Assert;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * 首页
+ *
+ * @author bwcx_jzy
+ * @since 2019/4/17
+ */
+@RestController
+@Slf4j
+public class IndexController extends BaseAgentController {
+
+ private final ProjectInfoService projectInfoService;
+ private final NodeScriptServer nodeScriptServer;
+ private final SystemCommander systemCommander;
+ private final ProjectCommander projectCommander;
+ private final AgentConfig agentConfig;
+
+ public IndexController(ProjectInfoService projectInfoService,
+ NodeScriptServer nodeScriptServer,
+ SystemCommander systemCommander,
+ ProjectCommander projectCommander,
+ AgentConfig agentConfig) {
+ this.projectInfoService = projectInfoService;
+ this.nodeScriptServer = nodeScriptServer;
+ this.systemCommander = systemCommander;
+ this.projectCommander = projectCommander;
+ this.agentConfig = agentConfig;
+ }
+
+ @RequestMapping(value = {"index", "", "index.html", "/"}, produces = MediaType.TEXT_PLAIN_VALUE)
+ @NotAuthorize
+ public String index() {
+ return "Jpom-Agent,Can't access directly,Please configure it to JPOM server";
+ }
+
+ @RequestMapping(value = "info", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
+ public IJsonMessage info() {
+
+ JpomManifest instance = JpomManifest.getInstance();
+ cn.keepbx.jpom.RemoteVersion remoteVersion = RemoteVersion.cacheInfo();
+ //
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("manifest", instance);
+ jsonObject.put("remoteVersion", remoteVersion);
+ jsonObject.put("pluginSize", PluginFactory.size());
+ jsonObject.put("joinBetaRelease", RemoteVersion.betaRelease());
+ jsonObject.put("monitor", agentConfig.getMonitor());
+ return JsonMessage.success("", jsonObject);
+ }
+
+ /**
+ * 获取节点统计信息
+ *
+ * @return json
+ */
+ @PostMapping(value = "get-stat-info", produces = MediaType.APPLICATION_JSON_VALUE)
+ public IJsonMessage getDirectTop() {
+ JSONObject jsonObject = new JSONObject();
+ try {
+ Optional monitorConfig = Optional.ofNullable(agentConfig).map(AgentConfig::getMonitor);
+
+ JSONObject topInfo = org.dromara.jpom.util.OshiUtils.getSimpleInfo(monitorConfig.orElse(null));
+ jsonObject.put("simpleStatus", topInfo);
+ // 系统固定休眠时间
+ jsonObject.put("systemSleep", org.dromara.jpom.util.OshiUtils.NET_STAT_SLEEP + org.dromara.jpom.util.OshiUtils.CPU_STAT_SLEEP);
+
+ JSONObject systemInfo = org.dromara.jpom.util.OshiUtils.getSystemInfo();
+ jsonObject.put("systemInfo", systemInfo);
+ //jsonObject.put("oshiError", "测试异常");
+ } catch (Throwable e) {
+ log.error(I18nMessageUtil.get("i18n.oshi_system_monitoring_exception.5c1c"), e);
+ jsonObject.put("oshiError", e.getMessage());
+ }
+
+ JSONObject jpomInfo = this.getJpomInfo();
+ jsonObject.put("jpomInfo", jpomInfo);
+ return JsonMessage.success("", jsonObject);
+ }
+
+ private JSONObject getJpomInfo() {
+ List nodeProjectInfoModels = projectInfoService.list();
+ List list = nodeScriptServer.list();
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("javaVirtualCount", JvmUtil.getJavaVirtualCount());
+ JpomManifest instance = JpomManifest.getInstance();
+ jsonObject.put("jpomManifest", instance);
+ jsonObject.put("javaVersion", SystemUtil.getJavaRuntimeInfo().getVersion());
+ // 获取JVM中内存总大小
+ jsonObject.put("totalMemory", SystemUtil.getTotalMemory());
+ //
+ jsonObject.put("freeMemory", SystemUtil.getFreeMemory());
+ Map workspaceMap = new HashMap<>(4);
+ //
+ {
+ for (NodeProjectInfoModel model : nodeProjectInfoModels) {
+ JSONObject jsonObject1 = workspaceMap.computeIfAbsent(model.getWorkspaceId(), s -> {
+ JSONObject jsonObject11 = new JSONObject();
+ jsonObject11.put("projectCount", 0);
+ jsonObject11.put("scriptCount", 0);
+ return jsonObject11;
+ });
+ jsonObject1.merge("projectCount", 1, (v1, v2) -> Integer.sum((Integer) v1, (Integer) v2));
+ }
+ jsonObject.put("projectCount", CollUtil.size(nodeProjectInfoModels));
+ }
+ {
+ for (NodeScriptModel model : list) {
+ JSONObject jsonObject1 = workspaceMap.computeIfAbsent(model.getWorkspaceId(), s -> {
+ JSONObject jsonObject11 = new JSONObject();
+ jsonObject11.put("projectCount", 0);
+ jsonObject11.put("scriptCount", 0);
+ return jsonObject11;
+ });
+ jsonObject1.merge("scriptCount", 1, (v1, v2) -> Integer.sum((Integer) v1, (Integer) v2));
+ }
+ jsonObject.put("scriptCount", CollUtil.size(list));
+ }
+ jsonObject.put("workspaceStat", workspaceMap);
+ return jsonObject;
+ }
+
+
+ @RequestMapping(value = "processList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
+ public IJsonMessage> getProcessList(String processName, Integer count) {
+ try {
+ processName = StrUtil.emptyToDefault(processName, "java");
+ List processes = org.dromara.jpom.util.OshiUtils.getProcesses(processName, Convert.toInt(count, 20));
+ processes = processes.stream()
+ .peek(jsonObject -> {
+ int processId = jsonObject.getIntValue("processId");
+ String port = projectCommander.getMainPort(processId);
+ jsonObject.put("port", port);
+ //
+ })
+ .collect(Collectors.toList());
+ return JsonMessage.success("", processes);
+ } catch (Throwable e) {
+ log.error(I18nMessageUtil.get("i18n.oshi_system_process_monitoring_exception.a4da"), e);
+ throw new IllegalStateException(I18nMessageUtil.get("i18n.system_process_monitoring_error.fe1d") + e.getMessage());
+ }
+ }
+
+
+ @PostMapping(value = "kill.json", produces = MediaType.APPLICATION_JSON_VALUE)
+ public IJsonMessage kill(int pid) {
+ long jpomAgentId = JpomManifest.getInstance().getPid();
+ Assert.state(!StrUtil.equals(StrUtil.toString(jpomAgentId), StrUtil.toString(pid)), I18nMessageUtil.get("i18n.online_agent_close_not_supported.d81d"));
+ String result = systemCommander.kill(null, pid);
+ if (StrUtil.isEmpty(result)) {
+ result = I18nMessageUtil.get("i18n.process_killed_successfully.a4c3");
+ }
+ return JsonMessage.success(result);
+ }
+
+ @PostMapping(value = "disk-info", produces = MediaType.APPLICATION_JSON_VALUE)
+ public IJsonMessage> diskInfo() {
+ try {
+ List list = org.dromara.jpom.util.OshiUtils.fileStores();
+ return JsonMessage.success("", list);
+ } catch (Throwable e) {
+ log.error(I18nMessageUtil.get("i18n.oshi_file_system_monitoring_exception.dc24"), e);
+ throw new IllegalStateException(I18nMessageUtil.get("i18n.file_system_monitoring_exception.d4c0") + e.getMessage());
+ }
+ }
+
+ @PostMapping(value = "hw-disk--info", produces = MediaType.APPLICATION_JSON_VALUE)
+ public IJsonMessage> hwDiskInfo() {
+ try {
+ List list = org.dromara.jpom.util.OshiUtils.diskStores();
+ return JsonMessage.success("", list);
+ } catch (Throwable e) {
+ log.error(I18nMessageUtil.get("i18n.oshi_hard_disk_monitoring_exception.c642"), e);
+ throw new IllegalStateException(I18nMessageUtil.get("i18n.hard_drive_monitoring_error.43e7") + e.getMessage());
+ }
+ }
+
+ @PostMapping(value = "network-interfaces", produces = MediaType.APPLICATION_JSON_VALUE)
+ public IJsonMessage> networkInterfaces() {
+ try {
+ List