diff options
Diffstat (limited to 'main.go')
| -rw-r--r-- | main.go | 161 |
1 files changed, 107 insertions, 54 deletions
@@ -3,23 +3,23 @@ package main import ( "bufio" "fmt" + "io" "net" "os" + "strconv" "strings" "sync" - "strconv" - "io" ) type RedisDB struct { - mu sync.Mutex - data map[string]string + mu sync.Mutex + data map[string]any } var db RedisDB func main() { - db = RedisDB{data: make(map[string]string)} + db = RedisDB{data: make(map[string]any)} listener, err := net.Listen("tcp", ":6379") if err != nil { @@ -41,19 +41,28 @@ func main() { func handleGet(conn net.Conn, key string) { db.mu.Lock() + defer db.mu.Unlock() + value, exists := db.data[key] - db.mu.Unlock() - if exists { - conn.Write([]byte("+" + value + "\r\n")) - } else { + if !exists { conn.Write([]byte("$-1\r\n")) + return + } + + strValue, ok := value.(string) + if !ok { + conn.Write([]byte("-WRONGTYPE Operation against a key holding the wrong kind of value\r\n")) + return } + + conn.Write([]byte("+" + strValue + "\r\n")) } -func handleExists(conn net.Conn, key string){ +func handleExists(conn net.Conn, key string) { db.mu.Lock() + defer db.mu.Unlock() + _, exists := db.data[key] - db.mu.Unlock() if exists { conn.Write([]byte(":1\r\n")) } else { @@ -63,61 +72,74 @@ func handleExists(conn net.Conn, key string){ func handleSet(conn net.Conn, key, value string) { db.mu.Lock() + defer db.mu.Unlock() + db.data[key] = value - db.mu.Unlock() conn.Write([]byte("+OK\r\n")) } -func handleDel(conn net.Conn, key string){ +func handleDel(conn net.Conn, key string) { db.mu.Lock() + defer db.mu.Unlock() + _, exists := db.data[key] - if exists { delete(db.data, key) conn.Write([]byte(":1\r\n")) } else { conn.Write([]byte(":0\r\n")) } - db.mu.Unlock() } -func handleIncr(conn net.Conn, key string){ +func handleIncr(conn net.Conn, key string) { db.mu.Lock() defer db.mu.Unlock() value, exists := db.data[key] if exists { - currentInt, err := strconv.Atoi(value) + strValue, ok := value.(string) + if !ok { + conn.Write([]byte("-ERR value is not an integer or out of range\r\n")) + return + } + + currentInt, err := strconv.Atoi(strValue) if err != nil { conn.Write([]byte("-ERR value is not an integer or out of range\r\n")) return } - newValueStr := strconv.Itoa(currentInt+1) + newValueStr := strconv.Itoa(currentInt + 1) db.data[key] = newValueStr conn.Write([]byte(":" + newValueStr + "\r\n")) - }else{ + } else { db.data[key] = "1" conn.Write([]byte(":1\r\n")) } } -func handleDecr(conn net.Conn, key string){ +func handleDecr(conn net.Conn, key string) { db.mu.Lock() defer db.mu.Unlock() value, exists := db.data[key] if exists { - currentInt, err := strconv.Atoi(value) + strValue, ok := value.(string) + if !ok { + conn.Write([]byte("-ERR value is not an integer or out of range\r\n")) + return + } + + currentInt, err := strconv.Atoi(strValue) if err != nil { conn.Write([]byte("-ERR value is not an integer or out of range\r\n")) return } - newValueStr := strconv.Itoa(currentInt-1) + newValueStr := strconv.Itoa(currentInt - 1) db.data[key] = newValueStr conn.Write([]byte(":" + newValueStr + "\r\n")) - }else{ + } else { db.data[key] = "-1" conn.Write([]byte(":-1\r\n")) } @@ -126,66 +148,95 @@ func handleDecr(conn net.Conn, key string){ func handlePing(conn net.Conn) { conn.Write([]byte("+PONG\r\n")) } -func handleFlushall(conn net.Conn){ + +func handleFlushall(conn net.Conn) { db.mu.Lock() - db.data = make(map[string]string) + defer db.mu.Unlock() + + db.data = make(map[string]any) conn.Write([]byte("+OK\r\n")) - db.mu.Unlock() +} + +func handleRpush(conn net.Conn, args []string) { + key := args[1] + newItems := args[2:] + + db.mu.Lock() + defer db.mu.Unlock() + + var list []string + existingValue, exists := db.data[key] + + if exists { + var ok bool + list, ok = existingValue.([]string) + if !ok { + conn.Write([]byte("-WRONGTYPE Operation against a key holding the wrong kind of value\r\n")) + return + } + } else { + list = []string{} + } + list = append(list, newItems...) + db.data[key] = list + + conn.Write([]byte(":" + strconv.Itoa(len(list)) + "\r\n")) } func parseRESP(reader *bufio.Reader) ([]string, error) { line, err := reader.ReadString('\n') - if err != nil { - return nil, err - } + if err != nil { + return nil, err + } if len(line) == 0 { - return nil, fmt.Errorf("empty line") - } + return nil, fmt.Errorf("empty line") + } switch line[0] { - case '*': + case '*': var args []string argC, _ := strconv.Atoi(strings.TrimSpace(line[1:])) for i := 0; i < argC; i++ { - nestedArgs, err := parseRESP(reader) - if err != nil { - return nil, err - } - - args = append(args, nestedArgs...) - } + nestedArgs, err := parseRESP(reader) + if err != nil { + return nil, err + } + + args = append(args, nestedArgs...) + } return args, nil case '$': strLen, _ := strconv.Atoi(strings.TrimSpace(line[1:])) if strLen == -1 { - return []string{""}, nil - } + return []string{""}, nil + } buf := make([]byte, strLen) _, err = io.ReadFull(reader, buf) - if err != nil { - return nil, err - } + if err != nil { + return nil, err + } _, err = reader.Discard(2) - if err != nil { - return nil, err - } + if err != nil { + return nil, err + } return []string{string(buf)}, nil - case '+': - cleanStr := strings.TrimSpace(line[1:]) - return []string{cleanStr}, nil + case '+': + cleanStr := strings.TrimSpace(line[1:]) + return []string{cleanStr}, nil case ':': return []string{strings.TrimSpace(line[1:])}, nil - default: - return nil, fmt.Errorf("unknown command type: %c", line[0]) - } + default: + return nil, fmt.Errorf("unknown command type: %c", line[0]) + } } + func handleConnection(conn net.Conn) { defer conn.Close() fmt.Println("Client connected:", conn.RemoteAddr()) @@ -195,7 +246,7 @@ func handleConnection(conn net.Conn) { args, err := parseRESP(reader) if err != nil { fmt.Println("Client disconnected or error parsing:", conn.RemoteAddr(), err) - return + return } if len(args) == 0 { @@ -223,6 +274,8 @@ func handleConnection(conn net.Conn) { handlePing(conn) case command == "FLUSHALL" && len(args) == 1: handleFlushall(conn) + case command == "RPUSH" && len(args) >= 3: + handleRpush(conn, args) default: conn.Write([]byte("-ERR unknown command or wrong arguments\r\n")) } |
