diff --git a/.env.example b/.env.example index 27c174136d6baa403c1f6a3b12d2708f9aaf1f23..c5ec7e43ddd6a7b241fb4cf0fb1be7f9540d108f 100644 --- a/.env.example +++ b/.env.example @@ -26,9 +26,3 @@ API_BASE_URL=https://api.mycopilot.com ORIGIN_TRACKER_BASE_URL=https://origin-tracker.githubusercontent.com PROXY_BASE_URL=https://copilot-proxy.mycopilot.com TELEMETRY_BASE_URL=https://copilot-telemetry-service.mycopilot.com - -# redis配置 -REDIS_HOST=10.6.80.35 -REDIS_PORT=6379 -REDIS_PASSWORD=123456 - diff --git a/docker-compose.yml b/docker-compose.yml index 9182b1a958e5b36ee6fc49b561cfd7e8a38b642d..0d7854881a3bffd39a0893b78288df0701c81d5b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,8 +7,6 @@ services: ports: - "11110:11110" environment: # 更多环境变量配置查看 .env.example - - REDIS_HOST=copilot-redis - - REDIS_PASSWORD=yourpassword - COPILOT_DEBOUNCE=200 # 代码补全请求防抖时间,ms - CODEX_API_BASE=https://api.deepseek.com/beta/v1/completions # 代码补全API地址 - CODEX_API_KEY=yourapikey # 代码补全API密钥 @@ -18,18 +16,9 @@ services: - CHAT_API_MODEL_NAME=deepseek-chat # 聊天补全API模型名称 - CHAT_MAX_TOKENS=4096 # 聊天API最大返回token数 - CODEX_TEMPERATURE=1 # 代码补全API温度, 默认值为:-1, 表示跟随插件动态设置, 如果是deepseek模型,官方推荐设置为1 - depends_on: - - copilot-redis extra_hosts: - "host.docker.internal:host-gateway" - copilot-redis: - container_name: copilot-redis - image: registry.cn-hangzhou.aliyuncs.com/ripper/redis:latest - restart: always - command: redis-server --requirepass yourpassword - environment: - - REDIS_PASSWORD=yourpassword copilot-nginx: container_name: copilot-nginx diff --git a/internal/app/github_auth/code.go b/internal/app/github_auth/code.go index df380b5d19b28ca6f6e99d664f7de9d8ecf4e638..3dc08cde5d1f7a6771c243ea43070f5fb7069d11 100644 --- a/internal/app/github_auth/code.go +++ b/internal/app/github_auth/code.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/gofrs/uuid" "github.com/gomodule/redigo/redis" - redisPkg "ripper/internal/redis" + "ripper/internal/cache" "strings" ) @@ -21,7 +21,6 @@ type ClientAuthInfo struct { // exp 过期时间 // return 用户代码, 设备代码, 错误 func BindClientToCode(clientId string, exp int) (string, string, error) { - rc := redisPkg.GetCoon() genCode := func() string { newUUID, _ := uuid.NewV4() uuidStr := strings.Replace(newUUID.String(), "-", "", -1) @@ -30,14 +29,14 @@ func BindClientToCode(clientId string, exp int) (string, string, error) { formattedUUID := genCode() rep := 0 redisKey := fmt.Sprintf("copilot.proxy.%s", formattedUUID) - repeat, _ := redis.Bool(rc.Do("EXISTS", redisKey)) + repeat, _ := cache.Exist(redisKey) for repeat { if rep > 5 { return "", "", fmt.Errorf("gen code error") } formattedUUID = genCode() redisKey = fmt.Sprintf("copilot.proxy.%s", formattedUUID) - repeat, _ = redis.Bool(rc.Do("EXISTS", redisKey)) + repeat, _ = cache.Exist(redisKey) rep++ } devId := GenDevicesCode(40) @@ -47,25 +46,24 @@ func BindClientToCode(clientId string, exp int) (string, string, error) { UserCode: formattedUUID, } authInfoData, _ := json.Marshal(authInfo) - _, err := rc.Do("set", redisKey, authInfoData, "EX", exp) + err := cache.Set(redisKey, authInfoData, exp) if err != nil { return "", "", err } redisKey = fmt.Sprintf("copilot.proxy.map.%s", devId) - _, err = rc.Do("set", redisKey, formattedUUID, "EX", exp) + err = cache.Set(redisKey, formattedUUID, exp) return formattedUUID, devId, err } // GetClientAuthInfoByDeviceCode 通过设备代码获取客户端授权信息 func GetClientAuthInfoByDeviceCode(deviceCode string) (*ClientAuthInfo, error) { - rc := redisPkg.GetCoon() redisKey := fmt.Sprintf("copilot.proxy.map.%s", deviceCode) - userCode, err := rc.Do("get", redisKey) + userCode, err := cache.Get(redisKey) if err != nil { return nil, err } redisKey = fmt.Sprintf("copilot.proxy.%s", userCode) - authInfoData, err := redis.Bytes(rc.Do("get", redisKey)) + authInfoData, err := redis.Bytes(cache.Get(redisKey)) if err != nil { return nil, err } @@ -75,9 +73,8 @@ func GetClientAuthInfoByDeviceCode(deviceCode string) (*ClientAuthInfo, error) { } func GetClientAuthInfo(code string) (ClientAuthInfo, error) { - rc := redisPkg.GetCoon() redisKey := fmt.Sprintf("copilot.proxy.%s", code) - authInfoData, err := redis.Bytes(rc.Do("get", redisKey)) + authInfoData, err := redis.Bytes(cache.Get(redisKey)) if err != nil { return ClientAuthInfo{}, err } @@ -98,14 +95,13 @@ func GenDevicesCode(codeLen int) string { // UpdateClientAuthStatusByDeviceCode 更新客户端授权码通过设备代码 func UpdateClientAuthStatusByDeviceCode(deviceCode string, cardCode string) error { - rc := redisPkg.GetCoon() redisKey := fmt.Sprintf("copilot.proxy.map.%s", deviceCode) - uCode, err := rc.Do("get", redisKey) + uCode, err := cache.Get(redisKey) if err != nil { return err } redisKey = fmt.Sprintf("copilot.proxy.%s", uCode) - authInfoData, err := redis.Bytes(rc.Do("get", redisKey)) + authInfoData, err := redis.Bytes(cache.Get(redisKey)) if err != nil { return err } @@ -116,23 +112,22 @@ func UpdateClientAuthStatusByDeviceCode(deviceCode string, cardCode string) erro } authInfo.CardCode = cardCode authInfoData, _ = json.Marshal(authInfo) - _, err = rc.Do("set", redisKey, authInfoData) + err = cache.Set(redisKey, authInfoData, -1) return err } func RemoveClientAuthInfoByDeviceCode(deviceCode string) error { - rc := redisPkg.GetCoon() redisKey := fmt.Sprintf("copilot.proxy.map.%s", deviceCode) - uCode, err := rc.Do("get", redisKey) + uCode, err := cache.Get(redisKey) if err != nil { return err } redisKey = fmt.Sprintf("copilot.proxy.%s", uCode) - _, err = rc.Do("del", redisKey) + err = cache.Del(redisKey) if err != nil { return err } redisKey = fmt.Sprintf("copilot.proxy.map.%s", deviceCode) - _, err = rc.Do("del", redisKey) + err = cache.Del(redisKey) return err } diff --git a/internal/cache/cacheable.go b/internal/cache/cacheable.go new file mode 100644 index 0000000000000000000000000000000000000000..f839302520b55d75ecd6aaa89e41901f6f1c4a0b --- /dev/null +++ b/internal/cache/cacheable.go @@ -0,0 +1,8 @@ +package cache + +type Cacheable interface { + Set(key string, value interface{}, ttl int) error + Get(key string) (interface{}, error) + Exist(key string) (bool, error) + Del(key string) error +} diff --git a/internal/cache/memory.go b/internal/cache/memory.go new file mode 100644 index 0000000000000000000000000000000000000000..f721e4d8904beaaed9154081a3a36a13c41d8feb --- /dev/null +++ b/internal/cache/memory.go @@ -0,0 +1,100 @@ +package cache + +import ( + "fmt" + "sync" + "time" +) + +// MemoryMap 用于内存缓存 +type MemoryMap struct { + cache map[string]interface{} + expirations map[string]int64 + mu sync.Mutex +} + +func NewMemoryMap() *MemoryMap { + m := &MemoryMap{} + m.init() + return m +} + +// init 初始化 MemoryMap 的缓存 +func (m *MemoryMap) init() { + m.cache = make(map[string]interface{}) + m.expirations = make(map[string]int64) +} + +func (m *MemoryMap) Get(key string) (interface{}, error) { + m.mu.Lock() + defer m.mu.Unlock() + + expiration, exists := m.expirations[key] + currentTime := time.Now().UnixMilli() + if exists && currentTime > expiration { + // 键已过期,删除并返回 nil + fmt.Printf("Get: key=%s has expired, deleting...\n", key) + delete(m.cache, key) + delete(m.expirations, key) + return nil, nil + } + + value, ok := m.cache[key] + if !ok { + return nil, nil + } + return value, nil +} + +// Set 设置缓存中的值,并指定过期时间(秒) +func (m *MemoryMap) Set(key string, value interface{}, ttl int) error { + m.mu.Lock() + defer m.mu.Unlock() + + m.cache[key] = value + if ttl == 0 { + // 默认半小时 + ttl = 30 * 60 + } + + if ttl == -1 { + // -1 表示永久缓存,不设置过期时间 + delete(m.expirations, key) + } else { + expiration := time.Now().UnixMilli() + int64(ttl*1000) + m.expirations[key] = expiration + } + return nil +} + +func (m *MemoryMap) Exist(key string) (bool, error) { + m.mu.Lock() + defer m.mu.Unlock() + + expiration, exists := m.expirations[key] + currentTime := time.Now().UnixMilli() + if exists && currentTime > expiration { + // 键已过期,删除并返回 nil + fmt.Printf("Get: key=%s has expired, deleting...\n", key) + delete(m.cache, key) + delete(m.expirations, key) + } + + _, ok := m.cache[key] + return ok, nil +} + +func (m *MemoryMap) Del(key string) error { + m.mu.Lock() + defer m.mu.Unlock() + + if _, ok := m.cache[key]; !ok { + return nil + } + delete(m.cache, key) + delete(m.expirations, key) + return nil +} + +// 编译时检查 +var _ Cacheable = (*MemoryMap)(nil) diff --git a/internal/cache/operation.go b/internal/cache/operation.go new file mode 100644 index 0000000000000000000000000000000000000000..54c4618184997d251c556fb6fb72b3022e4f6665 --- /dev/null +++ b/internal/cache/operation.go @@ -0,0 +1,25 @@ +package cache + +var cache Cacheable + +func init() { + cache = NewMemoryMap() + + // 已废弃redis缓存实现 + /*host := os.Getenv("REDIS_HOST") + port := os.Getenv("REDIS_PORT") + psw := os.Getenv("REDIS_PASSWORD") + cache = NewRedisInstance(host, port, psw)*/ +} +func Set(key string, value interface{}, ttl int) error { + return cache.Set(key, value, ttl) +} +func Get(key string) (interface{}, error) { + return cache.Get(key) +} +func Exist(key string) (bool, error) { + return cache.Exist(key) +} +func Del(key string) error { + return cache.Del(key) +} diff --git a/internal/redis/init.go b/internal/cache/redis.go similarity index 57% rename from internal/redis/init.go rename to internal/cache/redis.go index 39dcd3620f986cbbbd5da5cce99f4ba4a13fc315..b48546939440639e646f1df51ab7fdb513f59f08 100644 --- a/internal/redis/init.go +++ b/internal/cache/redis.go @@ -1,17 +1,49 @@ -package redis +package cache import ( "fmt" "github.com/gomodule/redigo/redis" - "os" "strconv" "time" ) -var pool *redis.Pool +type Redis struct { + Host string + Port string + Psw string + Pool *redis.Pool +} + +func NewRedisInstance(host string, port string, psw string) *Redis { + r := &Redis{Host: host, Port: port, Psw: psw} + r.init() + return r +} + +func (r *Redis) Get(k string) (interface{}, error) { + return r.getConn().Do("get", k) +} + +func (r *Redis) Set(k string, v interface{}, ttl int) error { + _, err := r.getConn().Do("set", k, v, "EX", ttl) + return err +} + +func (r *Redis) Exist(k string) (bool, error) { + return redis.Bool(r.getConn().Do("EXISTS", k)) +} + +func (r *Redis) Del(k string) error { + _, err := r.getConn().Do("del", k) + return err +} + +func (r *Redis) getConn() redis.Conn { + return r.Pool.Get() +} -func InitRedis() { - pool = &redis.Pool{ +func (r *Redis) init() { + r.Pool = &redis.Pool{ // Maximum number of connections allocated by the pool at a given time. // When zero, there is no limit on the number of connections in the pool. //最大活跃连接数,0代表无限 @@ -31,12 +63,12 @@ func InitRedis() { // The connection returned from Dial must not be in a special state // (subscribed to pubsub channel, transaction started, ...). Dial: func() (redis.Conn, error) { - port, _ := strconv.Atoi(os.Getenv("REDIS_PORT")) - c, err := redis.Dial("tcp", fmt.Sprintf("%s:%d", os.Getenv("REDIS_HOST"), port)) + port, _ := strconv.Atoi(r.Port) + c, err := redis.Dial("tcp", fmt.Sprintf("%s:%d", r.Host, port)) if err != nil { return nil, err } - password := os.Getenv("REDIS_PASSWORD") + password := r.Psw if password != "" { if _, err := c.Do("AUTH", password); err != nil { c.Close() diff --git a/internal/redis/operation.go b/internal/redis/operation.go deleted file mode 100644 index ceefb190717b862e13c5ab86fabc6931a8476308..0000000000000000000000000000000000000000 --- a/internal/redis/operation.go +++ /dev/null @@ -1,42 +0,0 @@ -package redis - -import ( - "fmt" - "github.com/gomodule/redigo/redis" -) - -func GetCoon() redis.Conn { - return pool.Get() -} - -func GetOneString(key string) (string, error) { - redisconn := pool.Get() - defer redisconn.Close() - return redis.String(redisconn.Do("get", key)) -} - -func GetTokenVersion(db, key string) (int64, error) { - redisconn := pool.Get() - defer redisconn.Close() - return redis.Int64(redisconn.Do("get", fmt.Sprintf("Hzer:JWT:Version:%s:%s", db, key))) -} - -func SetTokenVersion(db, key string, value, expire int64, cover bool) (err error) { - redisconn := pool.Get() - defer redisconn.Close() - keys := fmt.Sprintf("Hzer:JWT:Version:%s:%s", db, key) - if !cover { - var exi bool - if exi, err = redis.Bool(redisconn.Do("EXISTS", keys)); err != nil { - return err - } - if exi { - return nil - } - } - if _, err = redisconn.Do("set", keys, value); err != nil { - return - } - _, err = redisconn.Do("expire", keys, expire) - return -} diff --git a/main.go b/main.go index 2aaf81804d81977482f8073b75ade545fbe093c6..04afc521be1faf2cee7e16ff5618a69d8e11d3f8 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,6 @@ import ( "github.com/joho/godotenv" "log" "os" - "ripper/internal/redis" "ripper/internal/router" "strconv" ) @@ -23,9 +22,6 @@ func main() { //初始化router router.NewHTTPRouter(r) - // 初始化redis - redis.InitRedis() - //开启服务器 port, _ := strconv.Atoi(os.Getenv("PORT")) ipAddr := fmt.Sprintf("%s:%d", os.Getenv("HOST"), port)