Skip to content

Commit

Permalink
Implemented expiry & max origins.
Browse files Browse the repository at this point in the history
refactored constants to utils/constants.
  • Loading branch information
JasonLovesDoggo committed Mar 19, 2024
1 parent 851c569 commit 325846b
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 23 deletions.
22 changes: 22 additions & 0 deletions docs/benchmarks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
All Benchmarks are conducted with go run locally, and the redis being ran on the same host as prod.

These numbers were taken using tests/avg.py

## /hit with different TTL implementations (in relation to the data return)
### With expire before

AVG: 66.62284ms, MIN: 53.67ms, MAX: 311.721ms, COUNT: 100

### With expire after

AVG: 64.50046999999999ms, MIN: 53.162ms, MAX: 193.546ms, COUNT: 100

### With expire as a go routine

AVG: 43.408190000000005ms, MIN: 28.913999999999998ms, MAX: 167.731ms, COUNT: 100

### With no expire

AVG: 38.95288ms, MIN: 22.008ms, MAX: 165.397ms, COUNT: 100


9 changes: 6 additions & 3 deletions routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ func HitView(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get data. Try again later."})
return
}
go func() {
Client.Expire(context.Background(), dbKey, utils.BaseTTLPeriod)
}()

c.JSON(http.StatusOK, gin.H{"value": val})
}
Expand Down Expand Up @@ -78,7 +81,7 @@ func CreateView(c *gin.Context) {
return
}
// Get data from Redis
created := Client.SetNX(context.Background(), dbKey, initialValue, 0)
created := Client.SetNX(context.Background(), dbKey, initialValue, utils.BaseTTLPeriod)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to set data. Try again later."})
return
Expand All @@ -87,8 +90,8 @@ func CreateView(c *gin.Context) {
c.JSON(http.StatusConflict, gin.H{"error": "Key already exists, please use a different key."})
return
}
AdminKey := uuid.New().String() // Create a new admin key used for deletion and control
Client.Set(context.Background(), utils.CreateAdminKey(dbKey), AdminKey, 0)
AdminKey := uuid.New().String() // Create a new admin key used for deletion and control
Client.Set(context.Background(), utils.CreateAdminKey(dbKey), AdminKey, 0) // todo: figure out how to handle admin keys (handle alongside admin orrrrrrr separately as in a routine once a month that deletes all admin keys with no corresponding key)
c.JSON(http.StatusCreated, gin.H{"key": key, "namespace": namespace, "admin_key": AdminKey, "value": initialValue})
}

Expand Down
13 changes: 13 additions & 0 deletions tests/avg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import requests

COUNT = 100
TIMEOUT = 0.5 #(500ms)
url = 'http://localhost:8080/hit/jasoncameron.dev/'
times = []

for _ in range(COUNT):

response = requests.get(url, timeout=TIMEOUT)
times.append(response.elapsed.total_seconds() * 1000)

print(f"AVG: {sum(times)/COUNT}ms, MIN: {min(times)}ms, MAX: {max(times)}ms, COUNT: {len(times)}")
8 changes: 8 additions & 0 deletions utils/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package utils

import "time"

const BaseTTLPeriod = time.Hour * 24 * 7 * 4 * 6 // 6 months

const MinLength = 3
const MaxLength = 64
47 changes: 27 additions & 20 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,46 @@ import (
"github.com/gin-gonic/gin"
)

func truncateString(s string, length int) string {
if len(s) <= length {
return s
// truncateString truncates the string to a maximum of 64 characters. If the string is less than 3 characters, it will be padded with dots.
func truncateString(s string) string {

strLen := len(s)
if strLen < MinLength {
return strings.Repeat(".", MinLength-strLen) + s
}
return s[:length]
}
func getHostPath(c *gin.Context) (string, string) {
path := truncateString(strings.ReplaceAll(c.Request.URL.Path, "/", ""), 64)
// Extract domain and path // todo fix path logic
return "", path
if strLen > MaxLength {
return s[:MaxLength]
}
return s

}

func convertReserved(c *gin.Context, input string) (string, bool) {
func convertReserved(c *gin.Context, input string) string {
input = strings.Trim(input, "/")
if input == ":HOST:" {
origin := c.Request.Header.Get("Origin")
if origin == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Origin header is required if :HOST: is used"})
return "", false
return ""
}
return origin, true
return truncateString(origin)
} else if input == ":PATH:" {
_, path := getHostPath(c)
return path, true
path := c.Request.Header.Get("Referer")
if path == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Referer header is required if :PATH: is used"})
return ""
}

return truncateString(path)

}
host, path := getHostPath(c)
fmt.Println(host, path)
return input, true

return input
}
func CreateKey(c *gin.Context, namespace, key string, skipValidation bool) string {
namespace, continueOn := convertReserved(c, namespace)
key, continueOn2 := convertReserved(c, key)
if !(continueOn && continueOn2) {
namespace = convertReserved(c, namespace)
key = convertReserved(c, key)
if key == "" || namespace == "" {
return ""
}
if skipValidation == false {
Expand Down

0 comments on commit 325846b

Please sign in to comment.