package main import ( "errors" "net" "strconv" "time" ) func handleGet(conn net.Conn, args []string) { db.mu.Lock() defer db.mu.Unlock() if len(args) != 2 { err := errors.New("wrong number of arguments for 'GET'") conn.Write(serializeRESP(err)) return } key := args[1] item, exists := db.data[key] if !exists { conn.Write(serializeRESP(nil)) return } if item.ExpiresAt != nil && time.Now().After(*item.ExpiresAt) { delete(db.data, key) conn.Write(serializeRESP(nil)) return } strValue, ok := item.Value.(string) if !ok { err := errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") conn.Write(serializeRESP(err)) return } conn.Write(serializeRESP(strValue)) } func handleExists(conn net.Conn, args []string) { db.mu.Lock() defer db.mu.Unlock() if len(args) != 2 { err := errors.New("wrong number of arguments for 'EXISTS'") conn.Write(serializeRESP(err)) return } key := args[1] _, exists := db.data[key] if exists { conn.Write(serializeRESP(1)) } else { conn.Write(serializeRESP(0)) } } func handleSet(conn net.Conn, args []string) { db.mu.Lock() defer db.mu.Unlock() if len(args) != 3 { err := errors.New("wrong number of arguments for 'SET'") conn.Write(serializeRESP(err)) return } key := args[1] item := Item{Value: args[2]} db.data[key] = item conn.Write(serializeRESP(SimpleString("OK"))) } func handleDel(conn net.Conn, args []string) { db.mu.Lock() defer db.mu.Unlock() if len(args) != 2 { err := errors.New("wrong number of arguments for 'DEL'") conn.Write(serializeRESP(err)) return } key := args[1] _, exists := db.data[key] if exists { delete(db.data, key) conn.Write(serializeRESP(1)) } else { conn.Write(serializeRESP(0)) } } func handleIncr(conn net.Conn, args []string) { db.mu.Lock() defer db.mu.Unlock() if len(args) != 2 { err := errors.New("wrong number of arguments for 'INCR'") conn.Write(serializeRESP(err)) return } key := args[1] item, exists := db.data[key] if exists { strValue, ok := item.Value.(string) if !ok { err := errors.New("value is not an integer or out of range") conn.Write(serializeRESP(err)) return } currentInt, err := strconv.Atoi(strValue) if err != nil { err := errors.New("value is not an integer or out of range") conn.Write(serializeRESP(err)) return } newValueStr := strconv.Itoa(currentInt + 1) db.data[key] = Item{Value: newValueStr} conn.Write(serializeRESP(currentInt + 1)) } else { db.data[key] = Item{Value: "1"} conn.Write(serializeRESP(1)) } } func handleDecr(conn net.Conn, args []string) { db.mu.Lock() defer db.mu.Unlock() if len(args) != 2 { err := errors.New("wrong number of arguments for 'DECR'") conn.Write(serializeRESP(err)) return } key := args[1] item, exists := db.data[key] if exists { strValue, ok := item.Value.(string) if !ok { err := errors.New("value is not an integer or out of range") conn.Write(serializeRESP(err)) return } currentInt, err := strconv.Atoi(strValue) if err != nil { err := errors.New("value is not an integer or out of range") conn.Write(serializeRESP(err)) return } newValueStr := strconv.Itoa(currentInt - 1) db.data[key] = Item{Value:newValueStr} conn.Write(serializeRESP(currentInt - 1)) } else { db.data[key] = Item{Value: "-1"} conn.Write(serializeRESP(-1)) } } func handlePing(conn net.Conn, args []string) { if len(args) != 1 { err := errors.New("wrong number of arguments for 'PING'") conn.Write(serializeRESP(err)) return } conn.Write(serializeRESP(SimpleString("PONG"))) } func handleFlushall(conn net.Conn, args []string) { db.mu.Lock() defer db.mu.Unlock() if len(args) != 1 { err := errors.New("wrong number of arguments for 'FLUSHALL'") conn.Write(serializeRESP(err)) return } db.data = make(map[string]Item) conn.Write(serializeRESP(SimpleString("OK"))) } func handleRpush(conn net.Conn, args []string) { key := args[1] newItems := args[2:] if len(args) < 3 { err := errors.New("wrong number of arguments for 'RPUSH'") conn.Write(serializeRESP(err)) return } db.mu.Lock() defer db.mu.Unlock() var list []string existingItem, exists := db.data[key] if exists { var ok bool list, ok = existingItem.Value.([]string) if !ok { err := errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") conn.Write(serializeRESP(err)) return } } else { list = []string{} } list = append(list, newItems...) db.data[key] = Item{Value: list} conn.Write(serializeRESP(len(list))) } func handleLpush(conn net.Conn, args []string) { key := args[1] newItems := args[2:] if len(args) < 3 { err := errors.New("wrong number of arguments for 'LPUSH'") conn.Write(serializeRESP(err)) return } db.mu.Lock() defer db.mu.Unlock() var list []string existingItem, exists := db.data[key] if exists { var ok bool list, ok = existingItem.Value.([]string) if !ok { err := errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") conn.Write(serializeRESP(err)) return } } else { list = []string{} } list = append(newItems, list...) db.data[key] = Item{Value: list} conn.Write(serializeRESP(len(list))) } func handleLrange(conn net.Conn, args []string) { db.mu.Lock() defer db.mu.Unlock() if len(args) != 4 { err := errors.New("wrong number of arguments for 'LRANGE'") conn.Write(serializeRESP(err)) return } start, err1 := strconv.Atoi(args[2]) stop, err2 := strconv.Atoi(args[3]) if err1 != nil || err2 != nil { err := errors.New("value is not an integer or out of range") conn.Write(serializeRESP(err)) return } key := args[1] item, exists := db.data[key] if !exists { conn.Write(serializeRESP([]string{})) return } if item.ExpiresAt != nil && time.Now().After(*item.ExpiresAt) { delete(db.data, key) conn.Write(serializeRESP(nil)) return } typedList, ok := item.Value.([]string) if !ok { err := errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") conn.Write(serializeRESP(err)) return } size := len(typedList) if start < 0 { start += size if start < 0 { start = 0 } } if stop < 0 { stop += size if stop < 0 { stop = 0 } } if stop >= size { stop = size - 1 } if start > stop || start >= size { conn.Write(serializeRESP([]string{})) return } resultList := typedList[start : stop+1] conn.Write(serializeRESP(resultList)) } func handleLpop(conn net.Conn, args []string){ db.mu.Lock() defer db.mu.Unlock() if len(args) != 2 { err := errors.New("wrong number of arguments for 'LPOP'") conn.Write(serializeRESP(err)) return } key := args[1] item, exists := db.data[key] if !exists { conn.Write(serializeRESP(nil)) return } typedList, ok := item.Value.([]string) if !ok { err := errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") conn.Write(serializeRESP(err)) return } if len(typedList) == 0 { conn.Write(serializeRESP(nil)) return } newItem := typedList[0] newList := typedList[1:] if len(newList) <= 0 { delete(db.data, key) }else{ db.data[key] = Item{Value: newList} } conn.Write(serializeRESP(newItem)) } func handleRpop(conn net.Conn, args []string){ db.mu.Lock() defer db.mu.Unlock() if len(args) != 2 { err := errors.New("wrong number of arguments for 'RPOOP'") conn.Write(serializeRESP(err)) return } key := args[1] item, exists := db.data[key] if !exists { conn.Write(serializeRESP(nil)) return } typedList, ok := item.Value.([]string) if !ok { err := errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") conn.Write(serializeRESP(err)) return } if len(typedList) == 0 { conn.Write(serializeRESP(nil)) return } newItem := typedList[len(typedList)-1] newList := typedList[:len(typedList)-1] if len(newList) <= 0 { delete(db.data, key) }else{ db.data[key] = Item{Value: newList} } conn.Write(serializeRESP(newItem)) } func handleExpire(conn net.Conn, args []string){ if len(args) != 3 { conn.Write(serializeRESP(errors.New("wrong number of arguments for 'EXPIRE'"))) return } key := args[1] seconds, err := strconv.Atoi(args[2]) if err != nil { conn.Write(serializeRESP(errors.New("ERR value is not an integer"))) return } db.mu.Lock() defer db.mu.Unlock() item, exists := db.data[key] if !exists { conn.Write(serializeRESP(0)) // Key doesn't exist return } expiry := time.Now().Add(time.Duration(seconds) * time.Second) item.ExpiresAt = &expiry db.data[key] = item conn.Write(serializeRESP(1)) } func handleHset(conn net.Conn, args []string){ if len(args) < 4 || (len(args)-2)%2 != 0 { err := errors.New("wrong number of arguments for 'HSET'") conn.Write(serializeRESP(err)) return } key := args[1] db.mu.Lock() defer db.mu.Unlock() item, exists := db.data[key] var hash map[string]string if exists { var ok bool hash, ok = item.Value.(map[string]string) if !ok { conn.Write(serializeRESP(errors.New("WRONGTYPE Operation against a key holding the wrong kind of value"))) return } } else { hash = make(map[string]string) } count := 0 for i := 2; i < len(args); i += 2 { hash[args[i]] = args[i+1] count += 1 } db.data[key] = Item{Value: hash} conn.Write(serializeRESP(count)) } func handleHget(conn net.Conn, args []string) { if len(args) != 3 { conn.Write(serializeRESP(errors.New("ERR wrong number of arguments for 'HGET'"))) return } key := args[1] field := args[2] db.mu.Lock() defer db.mu.Unlock() item, exists := db.data[key] if !exists { conn.Write(serializeRESP(nil)) return } hash, ok := item.Value.(map[string]string) if !ok { conn.Write(serializeRESP(errors.New("WRONGTYPE Operation against a key holding the wrong kind of value"))) return } val, found := hash[field] if !found { conn.Write(serializeRESP(nil)) return } conn.Write(serializeRESP(val)) } func handleHgetall(conn net.Conn, args []string){ if len(args) != 2 { conn.Write(serializeRESP(errors.New("ERR wrong number of arguments for 'HGETALL'"))) return } key := args[1] db.mu.Lock() defer db.mu.Unlock() item, exists := db.data[key] if !exists { conn.Write(serializeRESP(nil)) return } hash, ok := item.Value.(map[string]string) if !ok { conn.Write(serializeRESP(errors.New("WRONGTYPE Operation against a key holding the wrong kind of value"))) return } conn.Write(serializeRESP(hash)) } func handleHkeys(conn net.Conn, args []string){ if len(args) != 2 { conn.Write(serializeRESP(errors.New("ERR wrong number of arguments for 'HKEYS'"))) return } key := args[1] db.mu.Lock() defer db.mu.Unlock() item, exists := db.data[key] if !exists { conn.Write(serializeRESP(nil)) return } hash, ok := item.Value.(map[string]string) if !ok { conn.Write(serializeRESP(errors.New("WRONGTYPE Operation against a key holding the wrong kind of value"))) return } result := make([]string, 0, len(hash)) for key := range hash { result = append(result, key) } conn.Write(serializeRESP(result)) } func handleHvalues(conn net.Conn, args []string){ if len(args) != 2 { conn.Write(serializeRESP(errors.New("ERR wrong number of arguments for 'HVALUES'"))) return } key := args[1] db.mu.Lock() defer db.mu.Unlock() item, exists := db.data[key] if !exists { conn.Write(serializeRESP(nil)) return } hash, ok := item.Value.(map[string]string) if !ok { conn.Write(serializeRESP(errors.New("WRONGTYPE Operation against a key holding the wrong kind of value"))) return } result := make([]string, 0, len(hash)) for _, value := range hash { result = append(result, value) } conn.Write(serializeRESP(result)) } func handleType(conn net.Conn, args []string){ if len(args) != 2 { conn.Write(serializeRESP(errors.New("ERR wrong number of arguments for 'TYPE'"))) return } key := args[1] db.mu.Lock() defer db.mu.Unlock() item, exists := db.data[key] if !exists { conn.Write(serializeRESP(SimpleString("none"))) return } switch item.Value.(type) { case string: conn.Write(serializeRESP(SimpleString("string"))) case []string: conn.Write(serializeRESP(SimpleString("list"))) case map[string]string: conn.Write(serializeRESP(SimpleString("hash"))) default: conn.Write(serializeRESP(SimpleString("unknown"))) } }