2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 06:47:20 +08:00

feat: 移除工具箱和跑分应用

This commit is contained in:
2025-05-19 00:09:29 +08:00
parent d43090b84f
commit bc4fcfe6ed
11 changed files with 155 additions and 163 deletions

View File

@@ -3,7 +3,6 @@ package apps
import (
"github.com/google/wire"
"github.com/tnb-labs/panel/internal/apps/benchmark"
"github.com/tnb-labs/panel/internal/apps/codeserver"
"github.com/tnb-labs/panel/internal/apps/docker"
"github.com/tnb-labs/panel/internal/apps/fail2ban"
@@ -27,11 +26,9 @@ import (
"github.com/tnb-labs/panel/internal/apps/rsync"
"github.com/tnb-labs/panel/internal/apps/s3fs"
"github.com/tnb-labs/panel/internal/apps/supervisor"
"github.com/tnb-labs/panel/internal/apps/toolbox"
)
var ProviderSet = wire.NewSet(
benchmark.NewApp,
codeserver.NewApp,
docker.NewApp,
fail2ban.NewApp,
@@ -55,5 +52,4 @@ var ProviderSet = wire.NewSet(
rsync.NewApp,
s3fs.NewApp,
supervisor.NewApp,
toolbox.NewApp,
)

View File

@@ -1,7 +1,6 @@
package bootstrap
import (
"github.com/tnb-labs/panel/internal/apps/benchmark"
"github.com/tnb-labs/panel/internal/apps/codeserver"
"github.com/tnb-labs/panel/internal/apps/docker"
"github.com/tnb-labs/panel/internal/apps/fail2ban"
@@ -25,12 +24,10 @@ import (
"github.com/tnb-labs/panel/internal/apps/rsync"
"github.com/tnb-labs/panel/internal/apps/s3fs"
"github.com/tnb-labs/panel/internal/apps/supervisor"
"github.com/tnb-labs/panel/internal/apps/toolbox"
"github.com/tnb-labs/panel/pkg/apploader"
)
func NewLoader(
benchmark *benchmark.App,
codeserver *codeserver.App,
docker *docker.App,
fail2ban *fail2ban.App,
@@ -54,9 +51,8 @@ func NewLoader(
rsync *rsync.App,
s3fs *s3fs.App,
supervisor *supervisor.App,
toolbox *toolbox.App,
) *apploader.Loader {
loader := new(apploader.Loader)
loader.Add(benchmark, codeserver, docker, fail2ban, frp, gitea, memcached, minio, mysql, nginx, php74, php80, php81, php82, php83, php84, phpmyadmin, podman, postgresql, pureftpd, redis, rsync, s3fs, supervisor, toolbox)
loader.Add(codeserver, docker, fail2ban, frp, gitea, memcached, minio, mysql, nginx, php74, php80, php81, php82, php83, php84, phpmyadmin, podman, postgresql, pureftpd, redis, rsync, s3fs, supervisor)
return loader
}

View File

@@ -1,12 +1,12 @@
package middleware
import (
"github.com/go-chi/chi/v5"
"net"
"net/http"
"slices"
"strings"
"github.com/go-chi/chi/v5"
"github.com/go-rat/chix"
"github.com/go-rat/sessions"
"github.com/knadh/koanf/v2"

View File

@@ -1,6 +1,6 @@
package benchmark
package request
type Test struct {
type ToolboxBenchmarkTest struct {
Name string `json:"name" validate:"required|in:image,machine,compile,encryption,compression,physics,json,memory,disk"`
Multi bool `json:"multi"`
}

View File

@@ -1,32 +1,32 @@
package toolbox
package request
import "time"
type DNS struct {
type ToolboxSystemDNS struct {
DNS1 string `form:"dns1" json:"dns1" validate:"required"`
DNS2 string `form:"dns2" json:"dns2" validate:"required"`
}
type SWAP struct {
type ToolboxSystemSWAP struct {
Size int64 `form:"size" json:"size" validate:"min:0"`
}
type Timezone struct {
type ToolboxSystemTimezone struct {
Timezone string `form:"timezone" json:"timezone" validate:"required"`
}
type Time struct {
type ToolboxSystemTime struct {
Time time.Time `form:"time" json:"time" validate:"required"`
}
type Hostname struct {
type ToolboxSystemHostname struct {
Hostname string `form:"hostname" json:"hostname" validate:"required|regex:^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$"`
}
type Hosts struct {
type ToolboxSystemHosts struct {
Hosts string `form:"hosts" json:"hosts"`
}
type Password struct {
type ToolboxSystemPassword struct {
Password string `form:"password" json:"password" validate:"required|password"`
}

View File

@@ -42,6 +42,8 @@ type Http struct {
monitor *service.MonitorService
setting *service.SettingService
systemctl *service.SystemctlService
toolboxSystem *service.ToolboxSystemService
toolboxBenchmark *service.ToolboxBenchmarkService
apps *apploader.Loader
}
@@ -73,6 +75,8 @@ func NewHttp(
monitor *service.MonitorService,
setting *service.SettingService,
systemctl *service.SystemctlService,
toolboxSystem *service.ToolboxSystemService,
toolboxBenchmark *service.ToolboxBenchmarkService,
apps *apploader.Loader,
) *Http {
return &Http{
@@ -103,6 +107,8 @@ func NewHttp(
monitor: monitor,
setting: setting,
systemctl: systemctl,
toolboxSystem: toolboxSystem,
toolboxBenchmark: toolboxBenchmark,
apps: apps,
}
}
@@ -381,6 +387,26 @@ func (route *Http) Register(r *chi.Mux) {
r.Post("/stop", route.systemctl.Stop)
})
r.Route("/toolbox_system", func(r chi.Router) {
r.Get("/dns", route.toolboxSystem.GetDNS)
r.Post("/dns", route.toolboxSystem.UpdateDNS)
r.Get("/swap", route.toolboxSystem.GetSWAP)
r.Post("/swap", route.toolboxSystem.UpdateSWAP)
r.Get("/timezone", route.toolboxSystem.GetTimezone)
r.Post("/timezone", route.toolboxSystem.UpdateTimezone)
r.Post("/time", route.toolboxSystem.UpdateTime)
r.Post("/sync_time", route.toolboxSystem.SyncTime)
r.Get("/hostname", route.toolboxSystem.GetHostname)
r.Post("/hostname", route.toolboxSystem.UpdateHostname)
r.Get("/hosts", route.toolboxSystem.GetHosts)
r.Post("/hosts", route.toolboxSystem.UpdateHosts)
r.Post("/root_password", route.toolboxSystem.UpdateRootPassword)
})
r.Route("/toolbox_benchmark", func(r chi.Router) {
r.Post("/test", route.toolboxBenchmark.Test)
})
r.Route("/apps", func(r chi.Router) {
route.apps.Register(r)
})

View File

@@ -32,5 +32,7 @@ var ProviderSet = wire.NewSet(
NewUserService,
NewUserTokenService,
NewWebsiteService,
NewToolboxSystemService,
NewToolboxBenchmarkService,
NewWsService,
)

View File

@@ -1,4 +1,4 @@
package benchmark
package service
import (
"bytes"
@@ -21,69 +21,64 @@ import (
"sync"
"time"
"github.com/go-chi/chi/v5"
"github.com/leonelquinteros/gotext"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/internal/http/request"
)
type App struct {
type ToolboxBenchmarkService struct {
t *gotext.Locale
}
func NewApp(t *gotext.Locale) *App {
return &App{
func NewToolboxBenchmarkService(t *gotext.Locale) *ToolboxBenchmarkService {
return &ToolboxBenchmarkService{
t: t,
}
}
func (s *App) Route(r chi.Router) {
r.Post("/test", s.Test)
}
// Test 运行测试
func (s *App) Test(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Test](r)
func (s *ToolboxBenchmarkService) Test(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ToolboxBenchmarkTest](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
switch req.Name {
case "image":
result := s.imageProcessing(req.Multi)
service.Success(w, result)
Success(w, result)
case "machine":
result := s.machineLearning(req.Multi)
service.Success(w, result)
Success(w, result)
case "compile":
result := s.compileSimulationSingle(req.Multi)
service.Success(w, result)
Success(w, result)
case "encryption":
result := s.encryptionTest(req.Multi)
service.Success(w, result)
Success(w, result)
case "compression":
result := s.compressionTest(req.Multi)
service.Success(w, result)
Success(w, result)
case "physics":
result := s.physicsSimulation(req.Multi)
service.Success(w, result)
Success(w, result)
case "json":
result := s.jsonProcessing(req.Multi)
service.Success(w, result)
Success(w, result)
case "disk":
result := s.diskTestTask()
service.Success(w, result)
Success(w, result)
case "memory":
result := s.memoryTestTask()
service.Success(w, result)
Success(w, result)
default:
service.Error(w, http.StatusUnprocessableEntity, s.t.Get("unknown test type"))
Error(w, http.StatusUnprocessableEntity, s.t.Get("unknown test type"))
}
}
// calculateCpuScore 计算CPU成绩
func (s *App) calculateCpuScore(duration time.Duration) int {
func (s *ToolboxBenchmarkService) calculateCpuScore(duration time.Duration) int {
score := int((10 / duration.Seconds()) * float64(3000))
if score < 0 {
@@ -93,7 +88,7 @@ func (s *App) calculateCpuScore(duration time.Duration) int {
}
// calculateScore 计算内存/硬盘成绩
func (s *App) calculateScore(duration time.Duration) int {
func (s *ToolboxBenchmarkService) calculateScore(duration time.Duration) int {
score := int((20 / duration.Seconds()) * float64(30000))
if score < 0 {
@@ -104,7 +99,7 @@ func (s *App) calculateScore(duration time.Duration) int {
// 图像处理
func (s *App) imageProcessing(multi bool) int {
func (s *ToolboxBenchmarkService) imageProcessing(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -117,7 +112,7 @@ func (s *App) imageProcessing(multi bool) int {
return s.calculateCpuScore(duration)
}
func (s *App) imageProcessingTask(numThreads int) error {
func (s *ToolboxBenchmarkService) imageProcessingTask(numThreads int) error {
img := image.NewRGBA(image.Rect(0, 0, 4000, 4000))
for x := 0; x < 4000; x++ {
for y := 0; y < 4000; y++ {
@@ -166,7 +161,7 @@ func (s *App) imageProcessingTask(numThreads int) error {
// 机器学习(矩阵乘法)
func (s *App) machineLearning(multi bool) int {
func (s *ToolboxBenchmarkService) machineLearning(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -177,7 +172,7 @@ func (s *App) machineLearning(multi bool) int {
return s.calculateCpuScore(duration)
}
func (s *App) machineLearningTask(numThreads int) {
func (s *ToolboxBenchmarkService) machineLearningTask(numThreads int) {
size := 900
a := make([][]float64, size)
b := make([][]float64, size)
@@ -224,7 +219,7 @@ func (s *App) machineLearningTask(numThreads int) {
// 数学问题(计算斐波那契数)
func (s *App) compileSimulationSingle(multi bool) int {
func (s *ToolboxBenchmarkService) compileSimulationSingle(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -258,7 +253,7 @@ func (s *App) compileSimulationSingle(multi bool) int {
}
// 斐波那契函数
func (s *App) fib(n int) *big.Int {
func (s *ToolboxBenchmarkService) fib(n int) *big.Int {
if n < 2 {
return big.NewInt(int64(n))
}
@@ -275,7 +270,7 @@ func (s *App) fib(n int) *big.Int {
// AES加密
func (s *App) encryptionTest(multi bool) int {
func (s *ToolboxBenchmarkService) encryptionTest(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -288,7 +283,7 @@ func (s *App) encryptionTest(multi bool) int {
return s.calculateCpuScore(duration)
}
func (s *App) encryptionTestTask(numThreads int) error {
func (s *ToolboxBenchmarkService) encryptionTestTask(numThreads int) error {
key := []byte("abcdefghijklmnopqrstuvwxyz123456")
dataSize := 1024 * 1024 * 512 // 512 MB
plaintext := []byte(strings.Repeat("A", dataSize))
@@ -330,7 +325,7 @@ func (s *App) encryptionTestTask(numThreads int) error {
// 压缩/解压缩
func (s *App) compressionTest(multi bool) int {
func (s *ToolboxBenchmarkService) compressionTest(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -341,7 +336,7 @@ func (s *App) compressionTest(multi bool) int {
return s.calculateCpuScore(duration)
}
func (s *App) compressionTestTask(numThreads int) {
func (s *ToolboxBenchmarkService) compressionTestTask(numThreads int) {
data := []byte(strings.Repeat("耗子面板", 50000000))
chunkSize := len(data) / numThreads
@@ -391,7 +386,7 @@ func (s *App) compressionTestTask(numThreads int) {
// 物理仿真N体问题
func (s *App) physicsSimulation(multi bool) int {
func (s *ToolboxBenchmarkService) physicsSimulation(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -402,7 +397,7 @@ func (s *App) physicsSimulation(multi bool) int {
return s.calculateCpuScore(duration)
}
func (s *App) physicsSimulationTask(numThreads int) {
func (s *ToolboxBenchmarkService) physicsSimulationTask(numThreads int) {
const (
numBodies = 4000
steps = 30
@@ -489,7 +484,7 @@ func (s *App) physicsSimulationTask(numThreads int) {
// JSON解析
func (s *App) jsonProcessing(multi bool) int {
func (s *ToolboxBenchmarkService) jsonProcessing(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -500,7 +495,7 @@ func (s *App) jsonProcessing(multi bool) int {
return s.calculateCpuScore(duration)
}
func (s *App) jsonProcessingTask(numThreads int) {
func (s *ToolboxBenchmarkService) jsonProcessingTask(numThreads int) {
numElements := 1000000
elementsPerThread := numElements / numThreads
@@ -541,7 +536,7 @@ func (s *App) jsonProcessingTask(numThreads int) {
// 内存性能
func (s *App) memoryTestTask() map[string]any {
func (s *ToolboxBenchmarkService) memoryTestTask() map[string]any {
results := make(map[string]any)
dataSize := 500 * 1024 * 1024 // 500 MB
data := make([]byte, dataSize)
@@ -559,7 +554,7 @@ func (s *App) memoryTestTask() map[string]any {
return results
}
func (s *App) memoryBandwidthTest(data []byte) string {
func (s *ToolboxBenchmarkService) memoryBandwidthTest(data []byte) string {
dataSize := len(data)
startTime := time.Now()
@@ -576,7 +571,7 @@ func (s *App) memoryBandwidthTest(data []byte) string {
return fmt.Sprintf("%.2f MB/s", speed)
}
func (s *App) memoryLatencyTest(data []byte) string {
func (s *ToolboxBenchmarkService) memoryLatencyTest(data []byte) string {
dataSize := len(data)
indices := rand.Perm(dataSize)
@@ -595,7 +590,7 @@ func (s *App) memoryLatencyTest(data []byte) string {
// 硬盘IO
func (s *App) diskTestTask() map[string]any {
func (s *ToolboxBenchmarkService) diskTestTask() map[string]any {
results := make(map[string]any)
blockSizes := []int64{4 * 1024, 64 * 1024, 512 * 1024, 1 * 1024 * 1024} // 4K, 64K, 512K, 1M
fileSize := int64(100 * 1024 * 1024) // 100MB 文件
@@ -611,7 +606,7 @@ func (s *App) diskTestTask() map[string]any {
return results
}
func (s *App) diskIOTest(blockSize int64, fileSize int64) map[string]any {
func (s *ToolboxBenchmarkService) diskIOTest(blockSize int64, fileSize int64) map[string]any {
result := make(map[string]any)
tempFile := fmt.Sprintf("tempfile_%d", blockSize)
defer func(name string) {
@@ -631,7 +626,7 @@ func (s *App) diskIOTest(blockSize int64, fileSize int64) map[string]any {
return result
}
func (s *App) diskWriteTest(fileName string, blockSize int64, fileSize int64) (float64, float64) {
func (s *ToolboxBenchmarkService) diskWriteTest(fileName string, blockSize int64, fileSize int64) (float64, float64) {
totalBlocks := fileSize / blockSize
data := make([]byte, blockSize)
@@ -667,7 +662,7 @@ func (s *App) diskWriteTest(fileName string, blockSize int64, fileSize int64) (f
return speed, iops
}
func (s *App) diskReadTest(fileName string, blockSize int64, fileSize int64) (float64, float64) {
func (s *ToolboxBenchmarkService) diskReadTest(fileName string, blockSize int64, fileSize int64) (float64, float64) {
totalBlocks := fileSize / blockSize
data := make([]byte, blockSize)

View File

@@ -1,4 +1,4 @@
package toolbox
package service
import (
"net/http"
@@ -7,13 +7,12 @@ import (
"regexp"
"strings"
"github.com/go-chi/chi/v5"
"github.com/go-rat/chix"
"github.com/leonelquinteros/gotext"
"github.com/spf13/cast"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/internal/http/request"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/ntp"
"github.com/tnb-labs/panel/pkg/shell"
@@ -21,37 +20,21 @@ import (
"github.com/tnb-labs/panel/pkg/types"
)
type App struct {
type ToolboxSystemService struct {
t *gotext.Locale
}
func NewApp(t *gotext.Locale) *App {
return &App{
func NewToolboxSystemService(t *gotext.Locale) *ToolboxSystemService {
return &ToolboxSystemService{
t: t,
}
}
func (s *App) Route(r chi.Router) {
r.Get("/dns", s.GetDNS)
r.Post("/dns", s.UpdateDNS)
r.Get("/swap", s.GetSWAP)
r.Post("/swap", s.UpdateSWAP)
r.Get("/timezone", s.GetTimezone)
r.Post("/timezone", s.UpdateTimezone)
r.Post("/time", s.UpdateTime)
r.Post("/sync_time", s.SyncTime)
r.Get("/hostname", s.GetHostname)
r.Post("/hostname", s.UpdateHostname)
r.Get("/hosts", s.GetHosts)
r.Post("/hosts", s.UpdateHosts)
r.Post("/root_password", s.UpdateRootPassword)
}
// GetDNS 获取 DNS 信息
func (s *App) GetDNS(w http.ResponseWriter, r *http.Request) {
func (s *ToolboxSystemService) GetDNS(w http.ResponseWriter, r *http.Request) {
raw, err := io.Read("/etc/resolv.conf")
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
@@ -61,14 +44,14 @@ func (s *App) GetDNS(w http.ResponseWriter, r *http.Request) {
dns = append(dns, m[1])
}
service.Success(w, dns)
Success(w, dns)
}
// UpdateDNS 设置 DNS 信息
func (s *App) UpdateDNS(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[DNS](r)
func (s *ToolboxSystemService) UpdateDNS(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ToolboxSystemDNS](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
@@ -77,21 +60,21 @@ func (s *App) UpdateDNS(w http.ResponseWriter, r *http.Request) {
dns += "nameserver " + req.DNS2 + "\n"
if err := io.Write("/etc/resolv.conf", dns, 0644); err != nil {
service.Error(w, http.StatusInternalServerError, s.t.Get("failed to update DNS: %v", err))
Error(w, http.StatusInternalServerError, s.t.Get("failed to update DNS: %v", err))
return
}
service.Success(w, nil)
Success(w, nil)
}
// GetSWAP 获取 SWAP 信息
func (s *App) GetSWAP(w http.ResponseWriter, r *http.Request) {
func (s *ToolboxSystemService) GetSWAP(w http.ResponseWriter, r *http.Request) {
var total, used, free string
var size int64
if io.Exists(filepath.Join(app.Root, "swap")) {
file, err := os.Stat(filepath.Join(app.Root, "swap"))
if err != nil {
service.Error(w, http.StatusInternalServerError, s.t.Get("failed to get SWAP: %v", err))
Error(w, http.StatusInternalServerError, s.t.Get("failed to get SWAP: %v", err))
return
}
@@ -104,7 +87,7 @@ func (s *App) GetSWAP(w http.ResponseWriter, r *http.Request) {
raw, err := shell.Execf("free | grep Swap")
if err != nil {
service.Error(w, http.StatusInternalServerError, s.t.Get("failed to get SWAP: %v", err))
Error(w, http.StatusInternalServerError, s.t.Get("failed to get SWAP: %v", err))
return
}
@@ -114,7 +97,7 @@ func (s *App) GetSWAP(w http.ResponseWriter, r *http.Request) {
free = tools.FormatBytes(cast.ToFloat64(match[3]) * 1024)
}
service.Success(w, chix.M{
Success(w, chix.M{
"total": total,
"size": size,
"used": used,
@@ -123,24 +106,24 @@ func (s *App) GetSWAP(w http.ResponseWriter, r *http.Request) {
}
// UpdateSWAP 设置 SWAP 信息
func (s *App) UpdateSWAP(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[SWAP](r)
func (s *ToolboxSystemService) UpdateSWAP(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ToolboxSystemSWAP](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
if io.Exists(filepath.Join(app.Root, "swap")) {
if _, err = shell.Execf("swapoff '%s'", filepath.Join(app.Root, "swap")); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
if _, err = shell.Execf("rm -f '%s'", filepath.Join(app.Root, "swap")); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
if _, err = shell.Execf(`sed -i "\|^%s|d" /etc/fstab`, filepath.Join(app.Root, "swap")); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
}
@@ -149,52 +132,52 @@ func (s *App) UpdateSWAP(w http.ResponseWriter, r *http.Request) {
var free string
free, err = shell.Execf("df -k %s | awk '{print $4}' | tail -n 1", app.Root)
if err != nil {
service.Error(w, http.StatusInternalServerError, s.t.Get("failed to get disk space: %v", err))
Error(w, http.StatusInternalServerError, s.t.Get("failed to get disk space: %v", err))
return
}
if cast.ToInt64(free)*1024 < req.Size*1024*1024 {
service.Error(w, http.StatusInternalServerError, s.t.Get("disk space is insufficient, current free %s", tools.FormatBytes(cast.ToFloat64(free))))
Error(w, http.StatusInternalServerError, s.t.Get("disk space is insufficient, current free %s", tools.FormatBytes(cast.ToFloat64(free))))
return
}
btrfsCheck, _ := shell.Execf("df -T %s | awk '{print $2}' | tail -n 1", app.Root)
if strings.Contains(btrfsCheck, "btrfs") {
if _, err = shell.Execf("btrfs filesystem mkswapfile --size %dM --uuid clear %s", req.Size, filepath.Join(app.Root, "swap")); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
} else {
if _, err = shell.Execf("dd if=/dev/zero of=%s bs=1M count=%d", filepath.Join(app.Root, "swap"), req.Size); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
if _, err = shell.Execf("mkswap -f '%s'", filepath.Join(app.Root, "swap")); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
if err = io.Chmod(filepath.Join(app.Root, "swap"), 0600); err != nil {
service.Error(w, http.StatusInternalServerError, s.t.Get("failed to set SWAP permission: %v", err))
Error(w, http.StatusInternalServerError, s.t.Get("failed to set SWAP permission: %v", err))
return
}
}
if _, err = shell.Execf("swapon '%s'", filepath.Join(app.Root, "swap")); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
if _, err = shell.Execf("echo '%s swap swap defaults 0 0' >> /etc/fstab", filepath.Join(app.Root, "swap")); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
}
service.Success(w, nil)
Success(w, nil)
}
// GetTimezone 获取时区
func (s *App) GetTimezone(w http.ResponseWriter, r *http.Request) {
func (s *ToolboxSystemService) GetTimezone(w http.ResponseWriter, r *http.Request) {
raw, err := shell.Execf("timedatectl | grep zone")
if err != nil {
service.Error(w, http.StatusInternalServerError, s.t.Get("failed to get timezone: %v", err))
Error(w, http.StatusInternalServerError, s.t.Get("failed to get timezone: %v", err))
return
}
@@ -205,7 +188,7 @@ func (s *App) GetTimezone(w http.ResponseWriter, r *http.Request) {
zonesRaw, err := shell.Execf("timedatectl list-timezones")
if err != nil {
service.Error(w, http.StatusInternalServerError, s.t.Get("failed to get available timezones: %v", err))
Error(w, http.StatusInternalServerError, s.t.Get("failed to get available timezones: %v", err))
return
}
zones := strings.Split(zonesRaw, "\n")
@@ -218,121 +201,121 @@ func (s *App) GetTimezone(w http.ResponseWriter, r *http.Request) {
})
}
service.Success(w, chix.M{
Success(w, chix.M{
"timezone": match[1],
"timezones": zonesList,
})
}
// UpdateTimezone 设置时区
func (s *App) UpdateTimezone(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Timezone](r)
func (s *ToolboxSystemService) UpdateTimezone(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ToolboxSystemTimezone](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
if _, err = shell.Execf("timedatectl set-timezone '%s'", req.Timezone); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
service.Success(w, nil)
Success(w, nil)
}
// UpdateTime 设置时间
func (s *App) UpdateTime(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Time](r)
func (s *ToolboxSystemService) UpdateTime(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ToolboxSystemTime](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
if err = ntp.UpdateSystemTime(req.Time); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
service.Success(w, nil)
Success(w, nil)
}
// SyncTime 同步时间
func (s *App) SyncTime(w http.ResponseWriter, r *http.Request) {
func (s *ToolboxSystemService) SyncTime(w http.ResponseWriter, r *http.Request) {
now, err := ntp.Now()
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
if err = ntp.UpdateSystemTime(now); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
Error(w, http.StatusInternalServerError, "%v", err)
return
}
service.Success(w, nil)
Success(w, nil)
}
// GetHostname 获取主机名
func (s *App) GetHostname(w http.ResponseWriter, r *http.Request) {
func (s *ToolboxSystemService) GetHostname(w http.ResponseWriter, r *http.Request) {
hostname, _ := io.Read("/etc/hostname")
service.Success(w, strings.TrimSpace(hostname))
Success(w, strings.TrimSpace(hostname))
}
// UpdateHostname 设置主机名
func (s *App) UpdateHostname(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Hostname](r)
func (s *ToolboxSystemService) UpdateHostname(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ToolboxSystemHostname](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
if _, err = shell.Execf("hostnamectl set-hostname '%s'", req.Hostname); err != nil {
// 直接写 /etc/hostname
if err = io.Write("/etc/hostname", req.Hostname, 0644); err != nil {
service.Error(w, http.StatusInternalServerError, s.t.Get("failed to set hostname: %v", err))
Error(w, http.StatusInternalServerError, s.t.Get("failed to set hostname: %v", err))
return
}
}
service.Success(w, nil)
Success(w, nil)
}
// GetHosts 获取 hosts 信息
func (s *App) GetHosts(w http.ResponseWriter, r *http.Request) {
func (s *ToolboxSystemService) GetHosts(w http.ResponseWriter, r *http.Request) {
hosts, _ := io.Read("/etc/hosts")
service.Success(w, hosts)
Success(w, hosts)
}
// UpdateHosts 设置 hosts 信息
func (s *App) UpdateHosts(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Hosts](r)
func (s *ToolboxSystemService) UpdateHosts(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ToolboxSystemHosts](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
if err = io.Write("/etc/hosts", req.Hosts, 0644); err != nil {
service.Error(w, http.StatusInternalServerError, s.t.Get("failed to set hosts: %v", err))
Error(w, http.StatusInternalServerError, s.t.Get("failed to set hosts: %v", err))
return
}
service.Success(w, nil)
Success(w, nil)
}
// UpdateRootPassword 设置 root 密码
func (s *App) UpdateRootPassword(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Password](r)
func (s *ToolboxSystemService) UpdateRootPassword(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ToolboxSystemPassword](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
req.Password = strings.ReplaceAll(req.Password, `'`, `\'`)
if _, err = shell.Execf(`yes '%s' | passwd root`, req.Password); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", s.t.Get("failed to set root password: %v", err))
Error(w, http.StatusInternalServerError, "%v", s.t.Get("failed to set root password: %v", err))
return
}
service.Success(w, nil)
Success(w, nil)
}