Skip to content

Commit

Permalink
feat: update v2.0.7
Browse files Browse the repository at this point in the history
  • Loading branch information
devhaozi committed Jul 21, 2023
1 parent 915403e commit 594dfea
Show file tree
Hide file tree
Showing 42 changed files with 2,315 additions and 881 deletions.
8 changes: 4 additions & 4 deletions app/console/commands/monitoring.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import (
"github.com/goravel/framework/contracts/console/command"
"github.com/goravel/framework/facades"
"github.com/goravel/framework/support/carbon"
"github.com/spf13/cast"

"panel/app/models"
"panel/app/services"
"panel/pkg/tools"
)

Expand All @@ -36,10 +38,8 @@ func (receiver *Monitoring) Extend() command.Extend {
// Handle Execute the console command.
func (receiver *Monitoring) Handle(ctx console.Context) error {
var setting models.Setting
if err := facades.Orm().Query().Where("key", "monitor").First(&setting); err != nil {
return nil
}
if setting.Value == "0" || len(setting.Value) == 0 {
monitor := services.NewSettingImpl().Get(models.SettingKeyMonitor)
if !cast.ToBool(monitor) {
return nil
}

Expand Down
5 changes: 4 additions & 1 deletion app/console/kernel.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package console
import (
"github.com/goravel/framework/contracts/console"
"github.com/goravel/framework/contracts/schedule"
"github.com/goravel/framework/facades"

"panel/app/console/commands"
)
Expand All @@ -11,7 +12,9 @@ type Kernel struct {
}

func (kernel *Kernel) Schedule() []schedule.Event {
return []schedule.Event{}
return []schedule.Event{
facades.Schedule().Command("panel:monitoring").EveryMinute().SkipIfStillRunning(),
}
}

func (kernel *Kernel) Commands() []console.Command {
Expand Down
57 changes: 56 additions & 1 deletion app/http/controllers/helpers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package controllers

import "github.com/goravel/framework/contracts/http"
import (
"sync"

"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"

"panel/app/services"
)

func Success(ctx http.Context, data any) {
ctx.Response().Success().Json(http.Json{
Expand All @@ -16,3 +23,51 @@ func Error(ctx http.Context, code int, message any) {
"message": message,
})
}

// Check 检查插件是否可用
func Check(ctx http.Context, slug string) bool {
plugin := services.NewPluginImpl().GetBySlug(slug)
installedPlugin := services.NewPluginImpl().GetInstalledBySlug(slug)
installedPlugins, err := services.NewPluginImpl().AllInstalled()
if err != nil {
facades.Log().Error("[面板][插件] 获取已安装插件失败")
Error(ctx, http.StatusInternalServerError, "系统内部错误")
return false
}

if installedPlugin.Version != plugin.Version || installedPlugin.Slug != plugin.Slug {
Error(ctx, http.StatusForbidden, "插件 "+slug+" 需要更新至 "+plugin.Version+" 版本")
return false
}

var lock sync.RWMutex
pluginsMap := make(map[string]bool)

for _, p := range installedPlugins {
lock.Lock()
pluginsMap[p.Slug] = true
lock.Unlock()
}

for _, require := range plugin.Requires {
lock.RLock()
_, requireFound := pluginsMap[require]
lock.RUnlock()
if !requireFound {
Error(ctx, http.StatusForbidden, "插件 "+slug+" 需要依赖 "+require+" 插件")
return false
}
}

for _, exclude := range plugin.Excludes {
lock.RLock()
_, excludeFound := pluginsMap[exclude]
lock.RUnlock()
if excludeFound {
Error(ctx, http.StatusForbidden, "插件 "+slug+" 不兼容 "+exclude+" 插件")
return false
}
}

return true
}
33 changes: 22 additions & 11 deletions app/http/controllers/info_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package controllers

import (
"fmt"
"strings"

"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
Expand All @@ -19,16 +20,16 @@ type MenuItem struct {
}

type InfoController struct {
// Dependent services
plugin services.Plugin
}

func NewInfoController() *InfoController {
return &InfoController{
// Inject services
plugin: services.NewPluginImpl(),
}
}

func (r *InfoController) Name(ctx http.Context) {
func (c *InfoController) Name(ctx http.Context) {
var setting models.Setting
err := facades.Orm().Query().Where("key", "name").First(&setting)
if err != nil {
Expand All @@ -42,7 +43,7 @@ func (r *InfoController) Name(ctx http.Context) {
})
}

func (r *InfoController) Menu(ctx http.Context) {
func (c *InfoController) Menu(ctx http.Context) {
Success(ctx, []MenuItem{
{Name: "home", Title: "主页", Icon: "layui-icon-home", Jump: "/"},
{Name: "website", Title: "网站管理", Icon: "layui-icon-website", Jump: "website/list"},
Expand All @@ -55,7 +56,7 @@ func (r *InfoController) Menu(ctx http.Context) {
})
}

func (r *InfoController) HomePlugins(ctx http.Context) {
func (c *InfoController) HomePlugins(ctx http.Context) {
var plugins []models.Plugin
err := facades.Orm().Query().Where("show", 1).Find(&plugins)
if err != nil {
Expand All @@ -80,11 +81,11 @@ func (r *InfoController) HomePlugins(ctx http.Context) {
Success(ctx, pluginsJson)
}

func (r *InfoController) NowMonitor(ctx http.Context) {
func (c *InfoController) NowMonitor(ctx http.Context) {
Success(ctx, tools.GetMonitoringInfo())
}

func (r *InfoController) SystemInfo(ctx http.Context) {
func (c *InfoController) SystemInfo(ctx http.Context) {
monitorInfo := tools.GetMonitoringInfo()

Success(ctx, http.Json{
Expand All @@ -94,7 +95,7 @@ func (r *InfoController) SystemInfo(ctx http.Context) {
})
}

func (r *InfoController) InstalledDbAndPhp(ctx http.Context) {
func (c *InfoController) InstalledDbAndPhp(ctx http.Context) {
var php []models.Plugin
err := facades.Orm().Query().Where("slug like ?", "php%").Find(&php)
if err != nil {
Expand All @@ -116,14 +117,24 @@ func (r *InfoController) InstalledDbAndPhp(ctx http.Context) {
postgresqlInstalled = false
}

type data struct {
Slug string `json:"slug"`
Name string `json:"name"`
}
var phpData []data
phpData = append(phpData, data{Slug: "0", Name: "不使用"})
for _, p := range php {
phpData = append(phpData, data{Slug: strings.ReplaceAll(p.Slug, "php", ""), Name: c.plugin.GetBySlug(p.Slug).Name})
}

Success(ctx, http.Json{
"php": php,
"php": phpData,
"mysql": mysqlInstalled,
"postgresql": postgresqlInstalled,
})
}

func (r *InfoController) CheckUpdate(ctx http.Context) {
func (c *InfoController) CheckUpdate(ctx http.Context) {
version := facades.Config().GetString("panel.version")
remote, err := tools.GetLatestPanelVersion()
if err != nil {
Expand Down Expand Up @@ -151,7 +162,7 @@ func (r *InfoController) CheckUpdate(ctx http.Context) {
})
}

func (r *InfoController) Update(ctx http.Context) {
func (c *InfoController) Update(ctx http.Context) {
proxy := ctx.Request().InputBool("proxy")
err := tools.UpdatePanel(proxy)
if err != nil {
Expand Down
107 changes: 99 additions & 8 deletions app/http/controllers/monitor_controller.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package controllers

import (
"fmt"

"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
"github.com/goravel/framework/support/carbon"
"github.com/spf13/cast"
"panel/app/models"

"panel/app/services"
)

Expand Down Expand Up @@ -46,9 +47,20 @@ func (r *MonitorController) SaveDays(ctx http.Context) {
Success(ctx, nil)
}

// SwitchAndDays 监控开关和监控天数
func (r *MonitorController) SwitchAndDays(ctx http.Context) {
monitor := r.setting.Get(models.SettingKeyMonitor)
monitorDays := r.setting.Get(models.SettingKeyMonitorDays)

Success(ctx, http.Json{
"switch": cast.ToBool(monitor),
"days": cast.ToInt(monitorDays),
})
}

// Clear 清空监控数据
func (r *MonitorController) Clear(ctx http.Context) {
_, err := facades.Orm().Query().Delete(&models.Monitor{})
_, err := facades.Orm().Query().Where("1 = 1").Delete(&models.Monitor{})
if err != nil {
facades.Log().Error("[面板][MonitorController] 清空监控数据失败 ", err)
Error(ctx, http.StatusInternalServerError, "系统内部错误")
Expand All @@ -60,18 +72,97 @@ func (r *MonitorController) Clear(ctx http.Context) {

// List 监控数据列表
func (r *MonitorController) List(ctx http.Context) {
start := ctx.Request().Input("start")
end := ctx.Request().Input("end")
startTime := carbon.Parse(start)
endTime := carbon.Parse(end)
start := ctx.Request().InputInt64("start")
end := ctx.Request().InputInt64("end")
startTime := carbon.FromTimestampMilli(start)
endTime := carbon.FromTimestampMilli(end)

var monitors []models.Monitor
err := facades.Orm().Query().Where("created_at", ">=", startTime).Where("created_at", "<=", endTime).Get(&monitors)
err := facades.Orm().Query().Where("created_at >= ?", startTime.ToDateTimeString()).Where("created_at <= ?", endTime.ToDateTimeString()).Get(&monitors)
if err != nil {
facades.Log().Error("[面板][MonitorController] 查询监控数据失败 ", err)
Error(ctx, http.StatusInternalServerError, "系统内部错误")
return
}

Success(ctx, monitors)
if len(monitors) == 0 {
Error(ctx, http.StatusNotFound, "监控数据为空")
return
}

type load struct {
Load1 []float64 `json:"load1"`
Load5 []float64 `json:"load5"`
Load15 []float64 `json:"load15"`
}
type cpu struct {
Percent []string `json:"percent"`
}
type mem struct {
Total string `json:"total"`
Available []string `json:"available"`
Used []string `json:"used"`
}
type swap struct {
Total string `json:"total"`
Used []string `json:"used"`
Free []string `json:"free"`
}
type network struct {
Sent []string `json:"sent"`
Recv []string `json:"recv"`
Tx []string `json:"tx"`
Rx []string `json:"rx"`
}
type monitorData struct {
Times []string `json:"times"`
Load load `json:"load"`
Cpu cpu `json:"cpu"`
Mem mem `json:"mem"`
Swap swap `json:"swap"`
Net network `json:"net"`
}

var data monitorData
var bytesSent uint64
var bytesRecv uint64
var bytesSent2 uint64
var bytesRecv2 uint64
for _, net := range monitors[0].Info.Net {
bytesSent += net.BytesSent
bytesRecv += net.BytesRecv
}
for i, monitor := range monitors {
// 跳过第一条数据,因为第一条数据的流量为 0
if i == 0 {
// MB
data.Mem.Total = fmt.Sprintf("%.2f", float64(monitor.Info.Mem.Total)/1024/1024)
data.Swap.Total = fmt.Sprintf("%.2f", float64(monitor.Info.Swap.Total)/1024/1024)
continue
}
for _, net := range monitor.Info.Net {
bytesSent2 += net.BytesSent
bytesRecv2 += net.BytesRecv
}
data.Times = append(data.Times, monitor.CreatedAt.ToDateTimeString())
data.Load.Load1 = append(data.Load.Load1, monitor.Info.Load.Load1)
data.Load.Load5 = append(data.Load.Load5, monitor.Info.Load.Load5)
data.Load.Load15 = append(data.Load.Load15, monitor.Info.Load.Load15)
data.Cpu.Percent = append(data.Cpu.Percent, fmt.Sprintf("%.2f", monitor.Info.Percent[0]))
data.Mem.Available = append(data.Mem.Available, fmt.Sprintf("%.2f", float64(monitor.Info.Mem.Available)/1024/1024))
data.Mem.Used = append(data.Mem.Used, fmt.Sprintf("%.2f", float64(monitor.Info.Mem.Used)/1024/1024))
data.Swap.Used = append(data.Swap.Used, fmt.Sprintf("%.2f", float64(monitor.Info.Swap.Used)/1024/1024))
data.Swap.Free = append(data.Swap.Free, fmt.Sprintf("%.2f", float64(monitor.Info.Swap.Free)/1024/1024))
data.Net.Sent = append(data.Net.Sent, fmt.Sprintf("%.2f", float64(bytesSent2/1024)))
data.Net.Recv = append(data.Net.Recv, fmt.Sprintf("%.2f", float64(bytesRecv2/1024)))

// 监控频率为 1 分钟,所以这里除以 60 即可得到每秒的流量
data.Net.Tx = append(data.Net.Tx, fmt.Sprintf("%.2f", float64(bytesSent2-bytesSent)/60/1024))
data.Net.Rx = append(data.Net.Rx, fmt.Sprintf("%.2f", float64(bytesRecv2-bytesRecv)/60/1024))

bytesSent = bytesSent2
bytesRecv = bytesRecv2
}

Success(ctx, data)
}
Loading

0 comments on commit 594dfea

Please sign in to comment.