Skip to content

Commit

Permalink
feat: add expired time for stored value
Browse files Browse the repository at this point in the history
  • Loading branch information
agungdwiprasetyo authored and wuriyanto48 committed Mar 6, 2019
1 parent 8d07bf8 commit aa26bc3
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 35 deletions.
59 changes: 47 additions & 12 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package kece
import (
"bytes"
"errors"
"fmt"
"math"
"net"
"strconv"
"strings"
"time"
)

// Client struct
Expand All @@ -26,31 +30,52 @@ type ClientMessage struct {
Cmd []byte
Key []byte
Value []byte
Exp time.Duration
}

func isValidValue(val string) (bool, string) {
func processingValue(val string) (value string, expiredValue int, err error) {
var pair = map[string]string{"{": "}", `"`: `"`, "'": "'"}
if _, ok := pair[val]; ok {
return false, val
err = errors.New(ErrorInvalidArgument)
return
}

lastChar := string(val[len(val)-1])
// calculate if arguments has expired value (suffix is integer)
decimal := 0
for i := len(val) - 1; i >= 0; i-- {
k := string(val[i])
a, errConv := strconv.Atoi(k)
if errConv != nil {
break
}
expiredValue += a * int(math.Pow10(decimal))
decimal++
}

if expiredValue != 0 && fmt.Sprint(expiredValue) != val {
val = strings.TrimRight(val, fmt.Sprint(expiredValue)) // trim argument with expired value
val = strings.TrimSpace(val)
}

lastChar := string(val[len(val)-1])
value = val
if res, ok := pair[string(val[0])]; ok {
if res == lastChar {
if res == `"` || res == "'" {
val = val[1 : len(val)-1] // remove prefix & suffix string => ex: "test" -> test
value = val[1 : len(val)-1] // remove prefix & suffix string => ex: "test" -> test
}
return true, val
return
}
return false, val
err = errors.New(ErrorInvalidArgument)
return
}

if len(strings.Fields(val)) <= 1 { // single string without space and list from pair
return true, val
return
}

return false, val
err = errors.New(ErrorInvalidArgument)
return
}

// ValidateMessage function
Expand Down Expand Up @@ -78,12 +103,22 @@ func (c *ClientMessage) ValidateMessage() error {
return errors.New(ErrorInvalidOperation)
}

messValue := strings.TrimSpace(strings.TrimLeft(string(message), strings.Join(messages[:2], " ")))
isValidVal, value := isValidValue(messValue)
if !isValidVal {
mess := strings.TrimLeft(string(message), command)
idx := strings.Index(mess, messages[1])
if idx < 0 {
return errors.New(ErrorInvalidArgument)
}
c.Value = []byte(value)

value := strings.TrimSpace(mess[idx+len(messages[1]):])
val, expired, err := processingValue(value)
if err != nil {
return err
}

c.Value = []byte(val)
if expired != 0 {
c.Exp = time.Second * time.Duration(expired)
}
}

c.Message = nil // garbage
Expand Down
59 changes: 36 additions & 23 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,43 +106,56 @@ func TestClient(t *testing.T) {

func TestIsValidValue(t *testing.T) {
tests := []struct {
name string
args string
wantValid bool
wantResult string
name string
args string
wantValue string
wantExpired int
wantError bool
}{
{
name: "Testcase #1: Positive (store json string)",
args: `{"field": "this is value from field a"}`,
wantValid: true,
wantResult: `{"field": "this is value from field a"}`,
name: "Testcase #1: Positive (store json string)",
args: `{"field": "this is value from field a"}`,
wantError: false,
wantValue: `{"field": "this is value from field a"}`,
},
{
name: "Testcase #2: Positive (store a string with spaces)",
args: `"this is value"`,
wantValid: true,
wantResult: `this is value`,
name: "Testcase #2: Positive (store a string with spaces)",
args: `"this is value"`,
wantError: false,
wantValue: `this is value`,
},
{
name: "Testcase #3: Positive (store a string with spaces)",
args: `'this is value'`,
wantValid: true,
wantResult: `this is value`,
name: "Testcase #3: Positive (store a string with spaces)",
args: `'this is value'`,
wantError: false,
wantValue: `this is value`,
},
{
name: "Testcase #4: Negative (invalid sign)",
name: "Testcase #4: Positive (store a string with expired value)",
args: `'this is value with lifetime 20 seconds' 20`,
wantError: false,
wantValue: `this is value with lifetime 20 seconds`,
wantExpired: 20,
},
{
name: "Testcase #5: Negative (invalid sign)",
args: `"this is value'`,
wantValid: false,
wantError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
isValid, res := isValidValue(tt.args)
if isValid != tt.wantValid {
t.Errorf("isValidValue() = %v, want %v", isValid, tt.wantValid)
value, expired, err := processingValue(tt.args)
if (err != nil) != tt.wantError {
t.Errorf("error: processingValue() = %v, want %v", err, tt.wantError)
}
if isValid && res != tt.wantResult {
t.Errorf("isValidValue() = %v, want %v", res, tt.wantResult)

if err == nil && value != tt.wantValue {
t.Errorf("value: processingValue() = %v, want %v", value, tt.wantValue)
}

if err == nil && expired != tt.wantExpired {
t.Errorf("expired: processingValue() = %v, want %v", expired, tt.wantExpired)
}
})
}
Expand Down
16 changes: 16 additions & 0 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package kece
import (
"bufio"
"bytes"
"context"
"errors"
"fmt"
"log"
Expand Down Expand Up @@ -159,6 +160,17 @@ func writeMessage(cm *ClientMessage, message []byte) {
log.Printf("Failed to write response. Err: %v", err)
}
}

func processExpired(ctx context.Context, cm *ClientMessage, commander Commander) {
c, cancel := context.WithTimeout(ctx, cm.Exp)
defer cancel()

select {
case <-c.Done():
commander.Delete([]byte("DEL"), cm.Key)
}
}

func processMessage(cm *ClientMessage, commander Commander, auth string) {
for {
if err := cm.ValidateMessage(); err != nil {
Expand Down Expand Up @@ -212,6 +224,10 @@ func processMessage(cm *ClientMessage, commander Commander, auth string) {
return
}

if cm.Exp != 0 {
go processExpired(context.Background(), cm, commander)
}

reply := replies["OK"]
writeMessage(cm, []byte(reply))
return
Expand Down

0 comments on commit aa26bc3

Please sign in to comment.