aboutsummaryrefslogtreecommitdiff
path: root/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'main.go')
-rw-r--r--main.go161
1 files changed, 107 insertions, 54 deletions
diff --git a/main.go b/main.go
index 551f5da..96d4b8a 100644
--- a/main.go
+++ b/main.go
@@ -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"))
}