2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 12:40:25 +08:00

feat: 更新说明

This commit is contained in:
耗子
2024-08-25 02:12:25 +08:00
parent 6e9a4963af
commit b82bc21d1b
19 changed files with 57 additions and 201 deletions

View File

@@ -20,6 +20,10 @@
交流QQ群[12370907](https://jq.qq.com/?_wv=1027&k=I1oJKSTH) | 论坛:[tom.moe](https://tom.moe) | 赞助:[爱发电](https://afdian.com/a/TheTNB)
## 项目现状
**目前我在着手使用新的「自研」框架重构本项目,由于更改非常大需要一定时间,预期 8 月底会带来新的更新。**
## 优势
1. **极低占用:** 在 Debian 12 下部署面板 + LNMP 环境,内存占用不到 500 MB遥遥领先于使用容器化的其他面板。

View File

@@ -1,187 +0,0 @@
package plugins
import (
"fmt"
"regexp"
"time"
"github.com/go-resty/resty/v2"
"github.com/goravel/framework/contracts/http"
"github.com/spf13/cast"
"github.com/TheTNB/panel/v2/pkg/h"
"github.com/TheTNB/panel/v2/pkg/io"
"github.com/TheTNB/panel/v2/pkg/shell"
"github.com/TheTNB/panel/v2/pkg/str"
"github.com/TheTNB/panel/v2/pkg/systemctl"
"github.com/TheTNB/panel/v2/pkg/types"
)
type OpenRestyController struct {
// Dependent services
}
func NewOpenrestyController() *OpenRestyController {
return &OpenRestyController{}
}
// GetConfig
//
// @Summary 获取配置
// @Tags 插件-OpenResty
// @Produce json
// @Security BearerToken
// @Success 200 {object} controllers.SuccessResponse
// @Router /plugins/openresty/config [get]
func (r *OpenRestyController) GetConfig(ctx http.Context) http.Response {
config, err := io.Read("/www/server/openresty/conf/nginx.conf")
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, "获取配置失败")
}
return h.Success(ctx, config)
}
// SaveConfig
//
// @Summary 保存配置
// @Tags 插件-OpenResty
// @Produce json
// @Security BearerToken
// @Param config body string true "配置"
// @Success 200 {object} controllers.SuccessResponse
// @Router /plugins/openresty/config [post]
func (r *OpenRestyController) SaveConfig(ctx http.Context) http.Response {
config := ctx.Request().Input("config")
if len(config) == 0 {
return h.Error(ctx, http.StatusInternalServerError, "配置不能为空")
}
if err := io.Write("/www/server/openresty/conf/nginx.conf", config, 0644); err != nil {
return h.Error(ctx, http.StatusInternalServerError, "保存配置失败")
}
if err := systemctl.Reload("openresty"); err != nil {
_, err = shell.Execf("openresty -t")
return h.Error(ctx, http.StatusInternalServerError, fmt.Sprintf("重载服务失败: %v", err))
}
return h.Success(ctx, nil)
}
// ErrorLog
//
// @Summary 获取错误日志
// @Tags 插件-OpenResty
// @Produce json
// @Security BearerToken
// @Success 200 {object} controllers.SuccessResponse
// @Router /plugins/openresty/errorLog [get]
func (r *OpenRestyController) ErrorLog(ctx http.Context) http.Response {
if !io.Exists("/www/wwwlogs/nginx_error.log") {
return h.Success(ctx, "")
}
out, err := shell.Execf("tail -n 100 /www/wwwlogs/openresty_error.log")
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
return h.Success(ctx, out)
}
// ClearErrorLog
//
// @Summary 清空错误日志
// @Tags 插件-OpenResty
// @Produce json
// @Security BearerToken
// @Success 200 {object} controllers.SuccessResponse
// @Router /plugins/openresty/clearErrorLog [post]
func (r *OpenRestyController) ClearErrorLog(ctx http.Context) http.Response {
if out, err := shell.Execf("echo '' > /www/wwwlogs/openresty_error.log"); err != nil {
return h.Error(ctx, http.StatusInternalServerError, out)
}
return h.Success(ctx, nil)
}
// Load
//
// @Summary 获取负载状态
// @Tags 插件-OpenResty
// @Produce json
// @Security BearerToken
// @Success 200 {object} controllers.SuccessResponse
// @Router /plugins/openresty/load [get]
func (r *OpenRestyController) Load(ctx http.Context) http.Response {
client := resty.New().SetTimeout(10 * time.Second)
resp, err := client.R().Get("http://127.0.0.1/nginx_status")
if err != nil || !resp.IsSuccess() {
return h.Success(ctx, []types.NV{})
}
raw := resp.String()
var data []types.NV
workers, err := shell.Execf("ps aux | grep nginx | grep 'worker process' | wc -l")
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, "获取负载失败")
}
data = append(data, types.NV{
Name: "工作进程",
Value: workers,
})
out, err := shell.Execf("ps aux | grep nginx | grep 'worker process' | awk '{memsum+=$6};END {print memsum}'")
if err != nil {
return h.Error(ctx, http.StatusInternalServerError, "获取负载失败")
}
mem := str.FormatBytes(cast.ToFloat64(out))
data = append(data, types.NV{
Name: "内存占用",
Value: mem,
})
match := regexp.MustCompile(`Active connections:\s+(\d+)`).FindStringSubmatch(raw)
if len(match) == 2 {
data = append(data, types.NV{
Name: "活跃连接数",
Value: match[1],
})
}
match = regexp.MustCompile(`server accepts handled requests\s+(\d+)\s+(\d+)\s+(\d+)`).FindStringSubmatch(raw)
if len(match) == 4 {
data = append(data, types.NV{
Name: "总连接次数",
Value: match[1],
})
data = append(data, types.NV{
Name: "总握手次数",
Value: match[2],
})
data = append(data, types.NV{
Name: "总请求次数",
Value: match[3],
})
}
match = regexp.MustCompile(`Reading:\s+(\d+)\s+Writing:\s+(\d+)\s+Waiting:\s+(\d+)`).FindStringSubmatch(raw)
if len(match) == 4 {
data = append(data, types.NV{
Name: "请求数",
Value: match[1],
})
data = append(data, types.NV{
Name: "响应数",
Value: match[2],
})
data = append(data, types.NV{
Name: "驻留进程",
Value: match[3],
})
}
return h.Success(ctx, data)
}

View File

@@ -1,4 +1,4 @@
package plugins
package openresty
import (
"regexp"
@@ -19,18 +19,18 @@ import (
"github.com/TheTNB/panel/v2/pkg/types"
)
type Fail2banController struct {
type Controller struct {
website internal.Website
}
func NewFail2banController() *Fail2banController {
return &Fail2banController{
func NewController() *Controller {
return &Controller{
website: services.NewWebsiteImpl(),
}
}
// List 所有 Fail2ban 规则
func (r *Fail2banController) List(ctx http.Context) http.Response {
func (r *Controller) List(ctx http.Context) http.Response {
raw, err := io.Read("/etc/fail2ban/jail.local")
if err != nil {
return h.Error(ctx, http.StatusUnprocessableEntity, err.Error())
@@ -77,7 +77,7 @@ func (r *Fail2banController) List(ctx http.Context) http.Response {
}
// Add 添加 Fail2ban 规则
func (r *Fail2banController) Add(ctx http.Context) http.Response {
func (r *Controller) Add(ctx http.Context) http.Response {
if sanitize := h.Sanitize(ctx, map[string]string{
"name": "required",
"type": "required|in:website,service",
@@ -217,7 +217,7 @@ logpath = ` + logPath + `
}
// Delete 删除规则
func (r *Fail2banController) Delete(ctx http.Context) http.Response {
func (r *Controller) Delete(ctx http.Context) http.Response {
jailName := ctx.Request().Input("name")
raw, err := io.Read("/etc/fail2ban/jail.local")
if err != nil {
@@ -242,7 +242,7 @@ func (r *Fail2banController) Delete(ctx http.Context) http.Response {
}
// BanList 获取封禁列表
func (r *Fail2banController) BanList(ctx http.Context) http.Response {
func (r *Controller) BanList(ctx http.Context) http.Response {
name := ctx.Request().Input("name")
if len(name) == 0 {
return h.Error(ctx, http.StatusUnprocessableEntity, "缺少参数")
@@ -283,7 +283,7 @@ func (r *Fail2banController) BanList(ctx http.Context) http.Response {
}
// Unban 解封
func (r *Fail2banController) Unban(ctx http.Context) http.Response {
func (r *Controller) Unban(ctx http.Context) http.Response {
name := ctx.Request().Input("name")
ip := ctx.Request().Input("ip")
if len(name) == 0 || len(ip) == 0 {
@@ -298,7 +298,7 @@ func (r *Fail2banController) Unban(ctx http.Context) http.Response {
}
// SetWhiteList 设置白名单
func (r *Fail2banController) SetWhiteList(ctx http.Context) http.Response {
func (r *Controller) SetWhiteList(ctx http.Context) http.Response {
ip := ctx.Request().Input("ip")
if len(ip) == 0 {
return h.Error(ctx, http.StatusUnprocessableEntity, "缺少参数")
@@ -327,7 +327,7 @@ func (r *Fail2banController) SetWhiteList(ctx http.Context) http.Response {
}
// GetWhiteList 获取白名单
func (r *Fail2banController) GetWhiteList(ctx http.Context) http.Response {
func (r *Controller) GetWhiteList(ctx http.Context) http.Response {
raw, err := io.Read("/etc/fail2ban/jail.local")
if err != nil {
return h.Error(ctx, http.StatusUnprocessableEntity, err.Error())

View File

@@ -0,0 +1,39 @@
package openresty
import (
"github.com/goravel/framework/contracts/foundation"
"github.com/goravel/framework/contracts/route"
"github.com/TheTNB/panel/v2/app/http/middleware"
"github.com/TheTNB/panel/v2/app/plugins/loader"
"github.com/TheTNB/panel/v2/pkg/types"
)
func init() {
loader.Register(&types.Plugin{
Name: "Fail2ban",
Description: "Fail2ban 扫描系统日志文件并从中找出多次尝试失败的IP地址将该IP地址加入防火墙的拒绝访问列表中",
Slug: "fail2ban",
Version: "1.0.2",
Requires: []string{},
Excludes: []string{},
Install: `bash /www/panel/scripts/fail2ban/install.sh`,
Uninstall: `bash /www/panel/scripts/fail2ban/uninstall.sh`,
Update: `bash /www/panel/scripts/fail2ban/update.sh`,
Boot: func(app foundation.Application) {
RouteFacade := app.MakeRoute()
RouteFacade.Prefix("api/plugins/fail2ban").Middleware(middleware.Session(), middleware.MustInstall()).Group(func(r route.Router) {
r.Prefix("openresty").Group(func(route route.Router) {
controller := NewController()
route.Get("jails", controller.List)
route.Post("jails", controller.Add)
route.Delete("jails", controller.Delete)
route.Get("jails/{name}", controller.BanList)
route.Post("unban", controller.Unban)
route.Post("whiteList", controller.SetWhiteList)
route.Get("whiteList", controller.GetWhiteList)
})
})
},
})
}

View File

@@ -11,7 +11,7 @@ func All() []*types.Plugin {
return data
}
// New 新注册插件
func New(plugin *types.Plugin) {
// Register 注册插件
func Register(plugin *types.Plugin) {
data = append(data, plugin)
}

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
loader.New(&types.Plugin{
loader.Register(&types.Plugin{
Name: "OpenResty",
Description: "OpenResty® 是一款基于 NGINX 和 LuaJIT 的 Web 平台",
Slug: "openresty",