239 lines
6.5 KiB
Go
239 lines
6.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/freeflowuniverse/heroagent/pkg/servers/redisserver"
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
func main() {
|
|
// Parse command line flags
|
|
tcpPort := flag.String("tcp-port", "7777", "Redis server TCP port")
|
|
unixSocket := flag.String("unix-socket", "/tmp/redis-test.sock", "Redis server Unix domain socket path")
|
|
username := flag.String("user", "jan", "Username to check")
|
|
mailbox := flag.String("mailbox", "inbox", "Mailbox to check")
|
|
debug := flag.Bool("debug", true, "Enable debug output")
|
|
dbNum := flag.Int("db", 0, "Redis database number")
|
|
flag.Parse()
|
|
|
|
// Start Redis server in a goroutine
|
|
log.Printf("Starting Redis server on TCP port %s and Unix socket %s", *tcpPort, *unixSocket)
|
|
|
|
// Create a wait group to ensure the server is started before testing
|
|
var wg sync.WaitGroup
|
|
wg.Add(1)
|
|
|
|
// Remove the Unix socket file if it already exists
|
|
if *unixSocket != "" {
|
|
if _, err := os.Stat(*unixSocket); err == nil {
|
|
log.Printf("Removing existing Unix socket file: %s", *unixSocket)
|
|
if err := os.Remove(*unixSocket); err != nil {
|
|
log.Printf("Warning: Failed to remove existing Unix socket file: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Start the Redis server in a goroutine
|
|
go func() {
|
|
// Create a new server instance
|
|
_ = redisserver.NewServer(redisserver.ServerConfig{TCPPort: *tcpPort, UnixSocketPath: *unixSocket})
|
|
|
|
// Signal that the server is ready
|
|
wg.Done()
|
|
|
|
// Keep the server running
|
|
select {}
|
|
}()
|
|
|
|
// Wait for the server to start
|
|
wg.Wait()
|
|
|
|
// Give the server a moment to initialize, especially for Unix socket
|
|
time.Sleep(1 * time.Second)
|
|
|
|
// Test TCP connection
|
|
log.Println("Testing TCP connection")
|
|
tcpAddr := fmt.Sprintf("localhost:%s", *tcpPort)
|
|
testRedisConnection(tcpAddr, username, mailbox, debug, dbNum)
|
|
|
|
// Test Unix socket connection if supported
|
|
log.Println("Testing Unix socket connection")
|
|
testRedisConnection(*unixSocket, username, mailbox, debug, dbNum)
|
|
}
|
|
|
|
func testRedisConnection(addr string, username *string, mailbox *string, debug *bool, dbNum *int) {
|
|
// Connect to Redis
|
|
redisClient := redis.NewClient(&redis.Options{
|
|
Network: getNetworkType(addr),
|
|
Addr: addr,
|
|
DB: *dbNum,
|
|
DialTimeout: 5 * time.Second,
|
|
ReadTimeout: 5 * time.Second,
|
|
WriteTimeout: 5 * time.Second,
|
|
})
|
|
defer redisClient.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Check connection
|
|
pong, err := redisClient.Ping(ctx).Result()
|
|
if err != nil {
|
|
log.Fatalf("Failed to connect to Redis: %v", err)
|
|
}
|
|
log.Printf("Connected to Redis: %s", pong)
|
|
|
|
// Try to get a specific key that we know exists
|
|
specificKey := "mail:in:jan:inbox:17419716651"
|
|
val, err := redisClient.Get(ctx, specificKey).Result()
|
|
if err == redis.Nil {
|
|
log.Printf("Key '%s' does not exist", specificKey)
|
|
} else if err != nil {
|
|
log.Printf("Error getting key '%s': %v", specificKey, err)
|
|
} else {
|
|
log.Printf("Found key '%s' with value length: %d", specificKey, len(val))
|
|
}
|
|
|
|
if *debug {
|
|
log.Println("Listing keys in Redis using SCAN:")
|
|
var cursor uint64
|
|
var allKeys []string
|
|
var err error
|
|
var keys []string
|
|
|
|
for {
|
|
keys, cursor, err = redisClient.Scan(ctx, cursor, "*", 10).Result()
|
|
if err != nil {
|
|
log.Printf("Error scanning keys: %v", err)
|
|
break
|
|
}
|
|
|
|
allKeys = append(allKeys, keys...)
|
|
if cursor == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
log.Printf("Found %d total keys using SCAN", len(allKeys))
|
|
for i, k := range allKeys {
|
|
if i < 20 { // Limit output to first 20 keys
|
|
log.Printf("Key[%d]: %s", i, k)
|
|
}
|
|
}
|
|
if len(allKeys) > 20 {
|
|
log.Printf("... and %d more keys", len(allKeys)-20)
|
|
}
|
|
}
|
|
|
|
// Test different pattern formats using SCAN and KEYS
|
|
patterns := []string{
|
|
fmt.Sprintf("mail:in:%s:%s*", *username, strings.ToLower(*mailbox)),
|
|
fmt.Sprintf("mail:in:%s:%s:*", *username, strings.ToLower(*mailbox)),
|
|
fmt.Sprintf("mail:in:%s:%s/*", *username, strings.ToLower(*mailbox)),
|
|
fmt.Sprintf("mail:in:%s:%s*", *username, *mailbox),
|
|
}
|
|
|
|
for _, pattern := range patterns {
|
|
// Test with SCAN
|
|
log.Printf("Trying pattern with SCAN: %s", pattern)
|
|
var cursor uint64
|
|
var keys []string
|
|
var allKeys []string
|
|
|
|
for {
|
|
keys, cursor, err = redisClient.Scan(ctx, cursor, pattern, 10).Result()
|
|
if err != nil {
|
|
log.Printf("Error scanning with pattern %s: %v", pattern, err)
|
|
break
|
|
}
|
|
|
|
allKeys = append(allKeys, keys...)
|
|
if cursor == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
log.Printf("Found %d keys with pattern %s using SCAN", len(allKeys), pattern)
|
|
for i, key := range allKeys {
|
|
log.Printf(" Key[%d]: %s", i, key)
|
|
}
|
|
|
|
// Test with the standard KEYS command
|
|
log.Printf("Trying pattern with KEYS: %s", pattern)
|
|
keysResult, err := redisClient.Keys(ctx, pattern).Result()
|
|
if err != nil {
|
|
log.Printf("Error with KEYS command for pattern %s: %v", pattern, err)
|
|
} else {
|
|
log.Printf("Found %d keys with pattern %s using KEYS", len(keysResult), pattern)
|
|
for i, key := range keysResult {
|
|
log.Printf(" Key[%d]: %s", i, key)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Find all keys for the specified user using SCAN
|
|
userPattern := fmt.Sprintf("mail:in:%s:*", *username)
|
|
log.Printf("Checking all keys for user with pattern: %s using SCAN", userPattern)
|
|
var cursor uint64
|
|
var keys []string
|
|
var userKeys []string
|
|
|
|
for {
|
|
keys, cursor, err = redisClient.Scan(ctx, cursor, userPattern, 10).Result()
|
|
if err != nil {
|
|
log.Printf("Error scanning user keys: %v", err)
|
|
break
|
|
}
|
|
|
|
userKeys = append(userKeys, keys...)
|
|
if cursor == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
log.Printf("Found %d total keys for user %s using SCAN", len(userKeys), *username)
|
|
|
|
// Extract unique mailbox names
|
|
mailboxMap := make(map[string]bool)
|
|
for _, key := range userKeys {
|
|
parts := strings.Split(key, ":")
|
|
if len(parts) >= 4 {
|
|
mailboxName := parts[3]
|
|
|
|
// Handle mailbox/uid format
|
|
if strings.Contains(mailboxName, "/") {
|
|
mailboxParts := strings.Split(mailboxName, "/")
|
|
mailboxName = mailboxParts[0]
|
|
}
|
|
|
|
mailboxMap[mailboxName] = true
|
|
}
|
|
}
|
|
|
|
log.Printf("Found %d unique mailboxes for user %s:", len(mailboxMap), *username)
|
|
for mailbox := range mailboxMap {
|
|
log.Printf(" Mailbox: %s", mailbox)
|
|
}
|
|
}
|
|
|
|
// getNetworkType determines if the address is a TCP or Unix socket
|
|
func getNetworkType(addr string) string {
|
|
if strings.HasPrefix(addr, "/") {
|
|
// For Unix sockets, always return unix regardless of file existence
|
|
// The file might not exist yet when we're setting up the connection
|
|
// Check if the socket file exists
|
|
if _, err := os.Stat(addr); err != nil && !os.IsNotExist(err) {
|
|
log.Printf("Warning: Error checking Unix socket file: %v", err)
|
|
}
|
|
return "unix"
|
|
}
|
|
return "tcp"
|
|
}
|