heroagent/pkg/servers/redisserver/factory.go
2025-04-23 04:18:28 +02:00

69 lines
1.6 KiB
Go

package redisserver
import (
"sync"
"time"
)
// entry represents a stored value. For strings, value is stored as a string.
// For hashes, value is stored as a map[string]string.
type entry struct {
value interface{}
expiration time.Time // zero means no expiration
}
// Server holds the in-memory datastore and provides thread-safe access.
// It implements a Redis-compatible server using redcon.
type Server struct {
mu sync.RWMutex
data map[string]*entry
}
type ServerConfig struct {
TCPPort string
UnixSocketPath string
}
// NewCustomServer creates a new server instance with custom TCP port and Unix socket path.
// It starts a cleanup goroutine and Redis-compatible servers on the specified addresses.
func NewServer(config ServerConfig) *Server {
if config.UnixSocketPath == "" {
config.UnixSocketPath = "/tmp/redis.sock"
}
s := &Server{
data: make(map[string]*entry),
}
go s.cleanupExpiredKeys()
// Start TCP server if port is provided
if config.TCPPort != "" {
tcpAddr := ":" + config.TCPPort
go s.startRedisServer(tcpAddr, "")
}
// Start Unix socket server if path is provided
if config.UnixSocketPath != "" {
go s.startRedisServer(config.UnixSocketPath, "unix")
}
return s
}
// cleanupExpiredKeys periodically removes expired keys.
func (s *Server) cleanupExpiredKeys() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for range ticker.C {
now := time.Now()
s.mu.Lock()
for k, ent := range s.data {
if !ent.expiration.IsZero() && now.After(ent.expiration) {
delete(s.data, k)
}
}
s.mu.Unlock()
}
}