diff --git a/app/http/controllers/plugins/redis/redis_controller.go b/app/http/controllers/plugins/redis/redis_controller.go
new file mode 100644
index 00000000..257b700c
--- /dev/null
+++ b/app/http/controllers/plugins/redis/redis_controller.go
@@ -0,0 +1,206 @@
+package redis
+
+import (
+ "strings"
+
+ "github.com/goravel/framework/contracts/http"
+
+ "panel/app/http/controllers"
+ "panel/pkg/tools"
+)
+
+type RedisController struct {
+}
+
+type Info struct {
+ Name string `json:"name"`
+ Value string `json:"value"`
+}
+
+func NewRedisController() *RedisController {
+ return &RedisController{}
+}
+
+// Status 获取运行状态
+func (c *RedisController) Status(ctx http.Context) {
+ if !controllers.Check(ctx, "redis") {
+ return
+ }
+
+ status := tools.ExecShell("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'")
+ if len(status) == 0 {
+ controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败")
+ return
+ }
+
+ if status == "active" {
+ controllers.Success(ctx, true)
+ } else {
+ controllers.Success(ctx, false)
+ }
+}
+
+// Reload 重载配置
+func (c *RedisController) Reload(ctx http.Context) {
+ if !controllers.Check(ctx, "redis") {
+ return
+ }
+
+ tools.ExecShell("systemctl reload redis")
+ status := tools.ExecShell("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'")
+ if len(status) == 0 {
+ controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败")
+ return
+ }
+
+ if status == "active" {
+ controllers.Success(ctx, true)
+ } else {
+ controllers.Success(ctx, false)
+ }
+}
+
+// Restart 重启服务
+func (c *RedisController) Restart(ctx http.Context) {
+ if !controllers.Check(ctx, "redis") {
+ return
+ }
+
+ tools.ExecShell("systemctl restart redis")
+ status := tools.ExecShell("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'")
+ if len(status) == 0 {
+ controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败")
+ return
+ }
+
+ if status == "active" {
+ controllers.Success(ctx, true)
+ } else {
+ controllers.Success(ctx, false)
+ }
+}
+
+// Start 启动服务
+func (c *RedisController) Start(ctx http.Context) {
+ if !controllers.Check(ctx, "redis") {
+ return
+ }
+
+ tools.ExecShell("systemctl start redis")
+ status := tools.ExecShell("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'")
+ if len(status) == 0 {
+ controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败")
+ return
+ }
+
+ if status == "active" {
+ controllers.Success(ctx, true)
+ } else {
+ controllers.Success(ctx, false)
+ }
+}
+
+// Stop 停止服务
+func (c *RedisController) Stop(ctx http.Context) {
+ if !controllers.Check(ctx, "redis") {
+ return
+ }
+
+ tools.ExecShell("systemctl stop redis")
+ status := tools.ExecShell("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'")
+ if len(status) == 0 {
+ controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败")
+ return
+ }
+
+ if status != "active" {
+ controllers.Success(ctx, true)
+ } else {
+ controllers.Success(ctx, false)
+ }
+}
+
+// GetConfig 获取配置
+func (c *RedisController) GetConfig(ctx http.Context) {
+ if !controllers.Check(ctx, "redis") {
+ return
+ }
+
+ // 获取配置
+ config := tools.ReadFile("/www/server/redis/redis.conf")
+ if len(config) == 0 {
+ controllers.Error(ctx, http.StatusInternalServerError, "获取Redis配置失败")
+ return
+ }
+
+ controllers.Success(ctx, config)
+}
+
+// SaveConfig 保存配置
+func (c *RedisController) SaveConfig(ctx http.Context) {
+ if !controllers.Check(ctx, "redis") {
+ return
+ }
+
+ config := ctx.Request().Input("config")
+ if len(config) == 0 {
+ controllers.Error(ctx, http.StatusBadRequest, "配置不能为空")
+ return
+ }
+
+ if !tools.WriteFile("/www/server/redis/redis.conf", config, 0644) {
+ controllers.Error(ctx, http.StatusInternalServerError, "写入Redis配置失败")
+ return
+ }
+
+ tools.ExecShell("systemctl restart redis")
+
+ controllers.Success(ctx, nil)
+}
+
+// Load 获取负载
+func (c *RedisController) Load(ctx http.Context) {
+ if !controllers.Check(ctx, "redis") {
+ return
+ }
+
+ status := tools.ExecShell("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'")
+ if status != "active" {
+ controllers.Error(ctx, http.StatusInternalServerError, "Redis 已停止运行")
+ return
+ }
+
+ raw := tools.ExecShell("redis-cli info")
+ if len(raw) == 0 {
+ controllers.Error(ctx, http.StatusInternalServerError, "获取Redis负载失败")
+ return
+ }
+
+ infoLines := strings.Split(raw, "\n")
+ dataRaw := make(map[string]string)
+
+ for _, item := range infoLines {
+ parts := strings.Split(item, ":")
+ if len(parts) == 2 {
+ dataRaw[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
+ }
+ }
+
+ data := []Info{
+ {"TCP 端口", dataRaw["tcp_port"]},
+ {"已运行天数", dataRaw["uptime_in_days"]},
+ {"连接的客户端数", dataRaw["connected_clients"]},
+ {"已分配的内存总量", dataRaw["used_memory_human"]},
+ {"占用内存总量", dataRaw["used_memory_rss_human"]},
+ {"占用内存峰值", dataRaw["used_memory_peak_human"]},
+ {"内存碎片比率", dataRaw["mem_fragmentation_ratio"]},
+ {"运行以来连接过的客户端的总数", dataRaw["total_connections_received"]},
+ {"运行以来执行过的命令的总数", dataRaw["total_commands_processed"]},
+ {"每秒执行的命令数", dataRaw["instantaneous_ops_per_sec"]},
+ {"查找数据库键成功次数", dataRaw["keyspace_hits"]},
+ {"查找数据库键失败次数", dataRaw["keyspace_misses"]},
+ {"最近一次 fork() 操作耗费的毫秒数", dataRaw["latest_fork_usec"]},
+ }
+
+ controllers.Success(ctx, data)
+}
diff --git a/app/plugins/redis/redis.go b/app/plugins/redis/redis.go
new file mode 100644
index 00000000..1b86d6b4
--- /dev/null
+++ b/app/plugins/redis/redis.go
@@ -0,0 +1,13 @@
+package redis
+
+var (
+ Name = "Redis"
+ Description = "Redis 是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。"
+ Slug = "redis"
+ Version = "7.0.12"
+ Requires = []string{}
+ Excludes = []string{}
+ Install = `bash /www/panel/scripts/redis/install.sh`
+ Uninstall = `bash /www/panel/scripts/redis/uninstall.sh`
+ Update = `bash /www/panel/scripts/redis/update.sh`
+)
diff --git a/app/services/plugin.go b/app/services/plugin.go
index 7e2522a2..9d8d38c7 100644
--- a/app/services/plugin.go
+++ b/app/services/plugin.go
@@ -15,6 +15,7 @@ import (
"panel/app/plugins/php82"
"panel/app/plugins/phpmyadmin"
"panel/app/plugins/pureftpd"
+ "panel/app/plugins/redis"
"panel/app/plugins/s3fs"
"panel/app/plugins/supervisor"
)
@@ -159,6 +160,17 @@ func (r *PluginImpl) All() []PanelPlugin {
Uninstall: pureftpd.Uninstall,
Update: pureftpd.Update,
})
+ p = append(p, PanelPlugin{
+ Name: redis.Name,
+ Description: redis.Description,
+ Slug: redis.Slug,
+ Version: redis.Version,
+ Requires: redis.Requires,
+ Excludes: redis.Excludes,
+ Install: redis.Install,
+ Uninstall: redis.Uninstall,
+ Update: redis.Update,
+ })
p = append(p, PanelPlugin{
Name: s3fs.Name,
Description: s3fs.Description,
diff --git a/public/panel/views/plugins/redis.html b/public/panel/views/plugins/redis.html
new file mode 100644
index 00000000..77bb13b7
--- /dev/null
+++ b/public/panel/views/plugins/redis.html
@@ -0,0 +1,190 @@
+
+
Redis
+
+
+
+
+
+
+
+
+
+
+
当前状态:获取中
+
+
+
+
+
+
+
+
+
此处修改的是Redis主配置文件,如果你不了解各参数的含义,请不要随意修改!
+ 提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/routes/plugin.go b/routes/plugin.go
index 1ede94a1..5b06b3de 100644
--- a/routes/plugin.go
+++ b/routes/plugin.go
@@ -14,6 +14,7 @@ import (
"panel/app/http/controllers/plugins/php82"
"panel/app/http/controllers/plugins/phpmyadmin"
"panel/app/http/controllers/plugins/pureftpd"
+ "panel/app/http/controllers/plugins/redis"
"panel/app/http/controllers/plugins/s3fs"
"panel/app/http/controllers/plugins/supervisor"
"panel/app/http/middleware"
@@ -185,6 +186,17 @@ func Plugin() {
route.Get("port", pureFtpdController.GetPort)
route.Post("port", pureFtpdController.SetPort)
})
+ facades.Route().Prefix("api/plugins/redis").Middleware(middleware.Jwt()).Group(func(route route.Route) {
+ redisController := redis.NewRedisController()
+ route.Get("status", redisController.Status)
+ route.Post("reload", redisController.Reload)
+ route.Post("start", redisController.Start)
+ route.Post("stop", redisController.Stop)
+ route.Post("restart", redisController.Restart)
+ route.Get("load", redisController.Load)
+ route.Get("config", redisController.GetConfig)
+ route.Post("config", redisController.SaveConfig)
+ })
facades.Route().Prefix("api/plugins/s3fs").Middleware(middleware.Jwt()).Group(func(route route.Route) {
s3fsController := s3fs.NewS3fsController()
route.Get("list", s3fsController.List)
diff --git a/scripts/redis/install.sh b/scripts/redis/install.sh
new file mode 100644
index 00000000..f1ebbf32
--- /dev/null
+++ b/scripts/redis/install.sh
@@ -0,0 +1,116 @@
+#!/bin/bash
+export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
+
+: '
+Copyright 2022 HaoZi Technology Co., Ltd.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+'
+
+HR="+----------------------------------------------------"
+ARCH=$(uname -m)
+OS=$(source /etc/os-release && { [[ "$ID" == "debian" ]] && echo "debian"; } || { [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]] || [[ "$ID" == "rocky" ]] || [[ "$ID" == "almalinux" ]] && echo "centos"; } || echo "unknown")
+downloadUrl="https://dl.cdn.haozi.net/panel/redis"
+setupPath="/www"
+redisPath="${setupPath}/server/redis"
+redisVersion="7.0.12"
+cpuCore=$(cat /proc/cpuinfo | grep "processor" | wc -l)
+
+if ! id -u "redis" > /dev/null 2>&1; then
+ groupadd redis
+ useradd -s /sbin/nologin -g redis redis
+fi
+
+# 安装依赖
+if [ "${OS}" == "centos" ]; then
+ dnf makecache -y
+ dnf groupinstall "Development Tools" -y
+ dnf install systemd-devel openssl-devel -y
+elif [ "${OS}" == "debian" ]; then
+ apt update
+ apt install build-essential libsystemd-dev libssl-dev -y
+else
+ echo -e $HR
+ echo "错误:耗子Linux面板不支持该系统"
+ exit 1
+fi
+
+# 准备目录
+rm -rf ${redisPath}
+mkdir -p ${redisPath}
+cd ${redisPath}
+
+# 下载源码
+wget -T 120 -O ${redisPath}/redis-${redisVersion}.tar.gz ${downloadUrl}/redis-${redisVersion}.tar.gz
+tar -zxvf redis-${redisVersion}.tar.gz
+rm -f redis-${redisVersion}.tar.gz
+mv redis-${redisVersion}/* ./ && rm -rf redis-${redisVersion}
+mkdir -p ${redisPath}/bin
+
+make BUILD_TLS=yes USE_SYSTEMD=yes -j${cpuCore}
+if [ "$?" != "0" ]; then
+ echo -e $HR
+ echo "错误:Redis编译失败,请截图错误信息寻求帮助。"
+ rm -rf ${redisPath}
+ exit 1
+fi
+make PREFIX=${redisPath} install
+if [ ! -f "${redisPath}/bin/redis-server" ]; then
+ echo -e $HR
+ echo "错误:Redis安装失败,请截图错误信息寻求帮助。"
+ rm -rf ${redisPath}
+ exit 1
+fi
+
+# 设置软链接
+ln -sf ${redisPath}/bin/redis-cli /usr/bin/redis-cli
+ln -sf ${redisPath}/bin/redis-server /usr/bin/redis-server
+ln -sf ${redisPath}/bin/redis-sentinel /usr/bin/redis-sentinel
+ln -sf ${redisPath}/bin/redis-benchmark /usr/bin/redis-benchmark
+ln -sf ${redisPath}/bin/redis-check-aof /usr/bin/redis-check-aof
+ln -sf ${redisPath}/bin/redis-check-rdb /usr/bin/redis-check-rdb
+
+# 设置配置文件
+VM_OVERCOMMIT_MEMORY=$(cat /etc/sysctl.conf|grep vm.overcommit_memory)
+NET_CORE_SOMAXCONN=$(cat /etc/sysctl.conf|grep net.core.somaxconn)
+if [ -z "${VM_OVERCOMMIT_MEMORY}" ] && [ -z "${NET_CORE_SOMAXCONN}" ];then
+ echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf
+ echo "net.core.somaxconn = 1024" >> /etc/sysctl.conf
+ sysctl -p
+fi
+
+sed -i 's/dir .\//dir \/www\/server\/redis\//g' ${redisPath}/redis.conf
+sed -i 's/# supervised.*/supervised systemd/g' ${redisPath}/redis.conf
+sed -i 's/daemonize.*/daemonize no/g' ${redisPath}/redis.conf
+
+if [ "${ARCH}" == "aarch64" ]; then
+ echo "ignore-warnings ARM64-COW-BUG" >> ${redisPath}/redis.conf
+fi
+
+chown -R redis:redis ${redisPath}
+chmod -R 755 ${redisPath}
+
+# 设置服务
+cp -r utils/systemd-redis_server.service /etc/systemd/system/redis.service
+sed -i "s!ExecStart=.*!ExecStart=${redisPath}/bin/redis-server ${redisPath}/redis.conf!g" /etc/systemd/system/redis.service
+sed -i "s!#User=.*!User=redis!g" /etc/systemd/system/redis.service
+sed -i "s!#Group=.*!Group=redis!g" /etc/systemd/system/redis.service
+sed -i "s!#WorkingDirectory=.*!WorkingDirectory=${redisPath}!g" /etc/systemd/system/redis.service
+
+systemctl daemon-reload
+systemctl enable redis
+systemctl start redis
+
+panel writePlugin redis ${redisVersion}
+
+echo -e "${HR}\nRedis 安装完成\n${HR}"
diff --git a/scripts/redis/uninstall.sh b/scripts/redis/uninstall.sh
new file mode 100644
index 00000000..c9e42e0f
--- /dev/null
+++ b/scripts/redis/uninstall.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
+
+: '
+Copyright 2022 HaoZi Technology Co., Ltd.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+'
+
+HR="+----------------------------------------------------"
+
+systemctl stop redis
+systemctl disable redis
+rm -rf /etc/systemd/system/redis.service
+systemctl daemon-reload
+pkill -9 redis
+rm -rf /www/server/redis
+
+rm -rf /usr/bin/redis-cli
+rm -rf /usr/bin/redis-server
+rm -rf /usr/bin/redis-benchmark
+rm -rf /usr/bin/redis-check-aof
+rm -rf /usr/bin/redis-check-rdb
+rm -rf /usr/bin/redis-sentinel
+
+panel deletePlugin redis
+
+echo -e "${HR}\nRedis 卸载完成\n${HR}"
diff --git a/scripts/redis/update.sh b/scripts/redis/update.sh
new file mode 100644
index 00000000..8558b37c
--- /dev/null
+++ b/scripts/redis/update.sh
@@ -0,0 +1,86 @@
+#!/bin/bash
+export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
+
+: '
+Copyright 2022 HaoZi Technology Co., Ltd.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+'
+
+HR="+----------------------------------------------------"
+ARCH=$(uname -m)
+OS=$(source /etc/os-release && { [[ "$ID" == "debian" ]] && echo "debian"; } || { [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]] || [[ "$ID" == "rocky" ]] || [[ "$ID" == "almalinux" ]] && echo "centos"; } || echo "unknown")
+downloadUrl="https://dl.cdn.haozi.net/panel/redis"
+setupPath="/www"
+redisPath="${setupPath}/server/redis"
+redisVersion="7.0.12"
+cpuCore=$(cat /proc/cpuinfo | grep "processor" | wc -l)
+
+# 准备目录
+cd ${redisPath}
+
+# 下载源码
+wget -T 120 -O ${redisPath}/redis-${redisVersion}.tar.gz ${downloadUrl}/redis-${redisVersion}.tar.gz
+tar -zxvf redis-${redisVersion}.tar.gz
+rm -f redis-${redisVersion}.tar.gz
+mv redis-${redisVersion}/* ./ && rm -rf redis-${redisVersion}
+mkdir -p ${redisPath}/bin
+
+make BUILD_TLS=yes USE_SYSTEMD=yes -j${cpuCore}
+if [ "$?" != "0" ]; then
+ echo -e $HR
+ echo "错误:Redis编译失败,请截图错误信息寻求帮助。"
+ rm -rf ${redisPath}
+ exit 1
+fi
+make PREFIX=${redisPath} install
+if [ ! -f "${redisPath}/bin/redis-server" ]; then
+ echo -e $HR
+ echo "错误:Redis安装失败,请截图错误信息寻求帮助。"
+ rm -rf ${redisPath}
+ exit 1
+fi
+
+# 设置软链接
+ln -sf ${redisPath}/bin/redis-cli /usr/bin/redis-cli
+ln -sf ${redisPath}/bin/redis-server /usr/bin/redis-server
+ln -sf ${redisPath}/bin/redis-sentinel /usr/bin/redis-sentinel
+ln -sf ${redisPath}/bin/redis-benchmark /usr/bin/redis-benchmark
+ln -sf ${redisPath}/bin/redis-check-aof /usr/bin/redis-check-aof
+ln -sf ${redisPath}/bin/redis-check-rdb /usr/bin/redis-check-rdb
+
+# 设置配置文件
+sed -i 's/dir .\//dir \/www\/server\/redis\//g' ${redisPath}/redis.conf
+sed -i 's/# supervised.*/supervised systemd/g' ${redisPath}/redis.conf
+sed -i 's/daemonize.*/daemonize no/g' ${redisPath}/redis.conf
+
+if [ "${ARCH}" == "aarch64" ]; then
+ echo "ignore-warnings ARM64-COW-BUG" >> ${redisPath}/redis.conf
+fi
+
+chown -R redis:redis ${redisPath}
+chmod -R 755 ${redisPath}
+
+# 设置服务
+cp -r utils/systemd-redis_server.service /etc/systemd/system/redis.service
+sed -i "s!ExecStart=.*!ExecStart=${redisPath}/bin/redis-server ${redisPath}/redis.conf!g" /etc/systemd/system/redis.service
+sed -i "s!#User=.*!User=redis!g" /etc/systemd/system/redis.service
+sed -i "s!#Group=.*!Group=redis!g" /etc/systemd/system/redis.service
+sed -i "s!#WorkingDirectory=.*!WorkingDirectory=${redisPath}!g" /etc/systemd/system/redis.service
+
+systemctl daemon-reload
+systemctl restart redis
+
+panel writePlugin redis ${redisVersion}
+
+echo -e "${HR}\nRedis 升级完成\n${HR}"