feat: run.sh四模式(dev/docker/build/binary) + CLI flags + Redka内嵌Redis + Agent复制修复 + 服务器编辑IP字段 + 安装Agent按钮

This commit is contained in:
attacker committed 2026-06-18 03:36:04 +00:00
1 parent d0b94d39c0
commit 2354959811
14 files changed
+1355 -575

No files matched your search

+66
View File
@@ -0,0 +1,66 @@
// go-redis 外部 Redis 服务器实现
// 用于 Docker Compose / 生产环境部署 // Logan.Li
package redis
import (
"context"
"fmt"
"time"
goredis "github.com/redis/go-redis/v9"
)
// goRedisCache 基于 go-redis 的缓存实现 // Logan.Li
type goRedisCache struct {
client *goredis.Client
}
func newGoRedis(cfg Config) (Cache, error) {
client := goredis.NewClient(&goredis.Options{
Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
Password: cfg.Password,
DB: cfg.DB,
})
// 连接测试
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := client.Ping(ctx).Err(); err != nil {
return nil, fmt.Errorf("redis: 连接失败 %s:%d: %w", cfg.Host, cfg.Port, err)
}
return &goRedisCache{client: client}, nil
}
func (r *goRedisCache) Get(ctx context.Context, key string) (string, error) {
val, err := r.client.Get(ctx, key).Result()
if err == goredis.Nil {
return "", nil
}
return val, err
}
func (r *goRedisCache) Set(ctx context.Context, key string, value string, expiration time.Duration) error {
return r.client.Set(ctx, key, value, expiration).Err()
}
func (r *goRedisCache) Del(ctx context.Context, keys ...string) error {
return r.client.Del(ctx, keys...).Err()
}
func (r *goRedisCache) Exists(ctx context.Context, keys ...string) (int64, error) {
return r.client.Exists(ctx, keys...).Result()
}
func (r *goRedisCache) Expire(ctx context.Context, key string, expiration time.Duration) error {
return r.client.Expire(ctx, key, expiration).Err()
}
func (r *goRedisCache) Ping(ctx context.Context) error {
return r.client.Ping(ctx).Err()
}
func (r *goRedisCache) Close() error {
return r.client.Close()
}
+58
View File
@@ -0,0 +1,58 @@
// Package redis 提供统一的 Redis 缓存抽象层
// 支持两种后端:
// - redka: 内嵌 Redis 兼容存储(零依赖,独立二进制模式)// Logan.Li
// - redis: 外部 Redis 服务器(Docker / 生产环境)
//
// 使用方式:
//
// cache, err := redis.New(redis.Config{
// Driver: "redka", // 或 "redis"
// Host: "localhost",
// Port: 6379,
// Password: "",
// DB: 0,
// DataDir: "data/redka", // redka 数据目录(仅 redka 驱动使用)
// })
//
// cache.Set(ctx, "key", "value", 0)
// val, _ := cache.Get(ctx, "key")
package redis
import (
"context"
"fmt"
"time"
)
// Config Redis 配置 // Logan.Li
type Config struct {
Driver string // "redka" 或 "redis"
Host string
Port int
Password string
DB int
DataDir string // redka 数据目录
}
// Cache Redis 缓存接口 // Logan.Li
type Cache interface {
Get(ctx context.Context, key string) (string, error)
Set(ctx context.Context, key string, value string, expiration time.Duration) error
Del(ctx context.Context, keys ...string) error
Exists(ctx context.Context, keys ...string) (int64, error)
Expire(ctx context.Context, key string, expiration time.Duration) error
Ping(ctx context.Context) error
Close() error
}
// New 创建缓存实例(根据驱动自动选择后端)// Logan.Li
func New(cfg Config) (Cache, error) {
switch cfg.Driver {
case "redka", "":
return newRedka(cfg)
case "redis":
return newGoRedis(cfg)
default:
return nil, fmt.Errorf("redis: 不支持的驱动: %s (支持: redka, redis)", cfg.Driver)
}
}
+98
View File
@@ -0,0 +1,98 @@
// redka 内嵌 Redis 兼容存储实现(v0.2.x API)
// 使用 github.com/nalgeon/redka — 基于 SQLite 的 Redis 替代方案 // Logan.Li
// 零外部依赖,数据存在本地文件中,非常适合独立二进制部署
package redis
import (
"context"
"time"
"github.com/nalgeon/redka"
)
// redkaCache 基于 Redka v0.2.x 的缓存实现 // Logan.Li
type redkaCache struct {
db *redka.DB
}
func newRedka(cfg Config) (Cache, error) {
dataDir := cfg.DataDir
if dataDir == "" {
dataDir = "data/redka"
}
// Redka v0.2.x: Open(path, opts) // Logan.Li
db, err := redka.Open(dataDir+"/redka.db", nil)
if err != nil {
return nil, err
}
return &redkaCache{db: db}, nil
}
func (r *redkaCache) Get(ctx context.Context, key string) (string, error) {
// Redka v0.2.x: Str().Get() 返回 core.Value // Logan.Li
val, err := r.db.Str().Get(key)
if err == redka.ErrNotFound {
return "", nil
}
if err != nil {
return "", err
}
return val.String(), nil
}
func (r *redkaCache) Set(ctx context.Context, key string, value string, expiration time.Duration) error {
// Redka v0.2.x: Str().Set() 返回 error // Logan.Li
if err := r.db.Str().Set(key, value); err != nil {
return err
}
if expiration > 0 {
_, err := r.db.Key().Expire(key, expiration)
return err
}
return nil
}
func (r *redkaCache) Del(ctx context.Context, keys ...string) error {
for _, key := range keys {
if _, err := r.db.Key().Delete(key); err != nil {
return err
}
}
return nil
}
func (r *redkaCache) Exists(ctx context.Context, keys ...string) (int64, error) {
var count int64
for _, key := range keys {
ok, err := r.db.Key().Exists(key)
if err != nil {
return 0, err
}
if ok {
count++
}
}
return count, nil
}
func (r *redkaCache) Expire(ctx context.Context, key string, expiration time.Duration) error {
ok, err := r.db.Key().Expire(key, expiration)
if err != nil {
return err
}
if !ok {
return redka.ErrNotFound
}
return nil
}
func (r *redkaCache) Ping(ctx context.Context) error {
// Redka 始终可用(内嵌数据库)// Logan.Li
return nil
}
func (r *redkaCache) Close() error {
return r.db.Close()
}