Skip to content

Commit

Permalink
Resolved the merge issues
Browse files Browse the repository at this point in the history
  • Loading branch information
tanbirali committed Oct 7, 2024
2 parents e14ab31 + d373641 commit a23bf92
Show file tree
Hide file tree
Showing 19 changed files with 659 additions and 295 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
.vscode/
.env
/playground-mono
__debug_bin*
59 changes: 49 additions & 10 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
package config

import (
"fmt"
"os"
"strconv"
"strings"

"github.com/joho/godotenv"
)

// Config holds the application configuration
type Config struct {
DiceAddr string
ServerPort string
RequestLimit int // Field for the request limit
RequestWindow int // Field for the time window in seconds
DiceDBAddr string
ServerPort string
RequestLimitPerMin int64 // Field for the request limit
RequestWindowSec float64 // Field for the time window in float64
AllowedOrigins []string // Field for the allowed origins
}

// LoadConfig loads the application configuration from environment variables or defaults
func LoadConfig() *Config {
err := godotenv.Load()
if err != nil {
fmt.Println("Warning: .env file not found, falling back to system environment variables.")
}

return &Config{
DiceAddr: getEnv("DICE_ADDR", "localhost:7379"), // Default Dice address
ServerPort: getEnv("SERVER_PORT", ":8080"), // Default server port
RequestLimit: getEnvInt("REQUEST_LIMIT", 1000), // Default request limit
RequestWindow: getEnvInt("REQUEST_WINDOW", 60), // Default request window in seconds
DiceDBAddr: getEnv("DICEDB_ADDR", "localhost:7379"), // Default DiceDB address
ServerPort: getEnv("SERVER_PORT", ":8080"), // Default server port
RequestLimitPerMin: getEnvInt("REQUEST_LIMIT_PER_MIN", 1000), // Default request limit
RequestWindowSec: getEnvFloat64("REQUEST_WINDOW_SEC", 60), // Default request window in float64
AllowedOrigins: getEnvArray("ALLOWED_ORIGINS", []string{"http://localhost:3000"}), // Default allowed origins
}
}

Expand All @@ -32,11 +43,39 @@ func getEnv(key, fallback string) string {
}

// getEnvInt retrieves an environment variable as an integer or returns a default value
func getEnvInt(key string, fallback int) int {
func getEnvInt(key string, fallback int) int64 {
if value, exists := os.LookupEnv(key); exists {
if intValue, err := strconv.Atoi(value); err == nil {
return intValue
return int64(intValue)
}
}
return int64(fallback)
}

// added for miliseconds request window controls
func getEnvFloat64(key string, fallback float64) float64 {
if value, exists := os.LookupEnv(key); exists {
if floatValue, err := strconv.ParseFloat(value, 64); err == nil {
return floatValue
}
}
return fallback
}

func getEnvArray(key string, fallback []string) []string {
if value, exists := os.LookupEnv(key); exists {
if arrayValue := splitString(value); len(arrayValue) > 0 {
return arrayValue
}
}
return fallback
}

// splitString splits a string by comma and returns a slice of strings
func splitString(s string) []string {
var array []string
for _, v := range strings.Split(s, ",") {
array = append(array, strings.TrimSpace(v))
}
return array
}
10 changes: 9 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@ module server

go 1.22.5

require (
github.com/dicedb/go-dice v0.0.0-20240820180649-d97f15fca831
github.com/joho/godotenv v1.5.1
github.com/stretchr/testify v1.9.0
)

require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dicedb/go-dice v0.0.0-20240820180649-d97f15fca831 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
18 changes: 16 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dicedb/go-dice v0.0.0-20240820180649-d97f15fca831 h1:Cqyj9WCtoobN6++bFbDSe27q94SPwJD9Z0wmu+SDRuk=
github.com/dicedb/go-dice v0.0.0-20240820180649-d97f15fca831/go.mod h1:8+VZrr14c2LW8fW4tWZ8Bv3P2lfvlg+PpsSn5cWWuiQ=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
6 changes: 0 additions & 6 deletions internal/cmds/cmds.go

This file was deleted.

16 changes: 0 additions & 16 deletions internal/db/commands.go

This file was deleted.

93 changes: 52 additions & 41 deletions internal/db/dicedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@ import (
"log/slog"
"os"
"server/config"
"server/internal/cmds"
"server/util/cmds"
"strings"
"time"

dice "github.com/dicedb/go-dice"
dicedb "github.com/dicedb/go-dice"
)

const (
RespOK = "OK"
)
const RespNil = "(nil)"

type DiceDB struct {
Client *dice.Client
Client *dicedb.Client
Ctx context.Context
}

Expand All @@ -36,13 +35,13 @@ func (db *DiceDB) CloseDiceDB() {
}

func InitDiceClient(configValue *config.Config) (*DiceDB, error) {
diceClient := dice.NewClient(&dice.Options{
Addr: configValue.DiceAddr,
diceClient := dicedb.NewClient(&dicedb.Options{
Addr: configValue.DiceDBAddr,
DialTimeout: 10 * time.Second,
MaxRetries: 10,
})

// Ping the dice client to verify the connection
// Ping the dicedb client to verify the connection
err := diceClient.Ping(context.Background()).Err()
if err != nil {
return nil, err
Expand All @@ -56,47 +55,59 @@ func InitDiceClient(configValue *config.Config) (*DiceDB, error) {

// ExecuteCommand executes a command based on the input
func (db *DiceDB) ExecuteCommand(command *cmds.CommandRequest) (interface{}, error) {
switch command.Cmd {
case "GET":
if len(command.Args) != 1 {
return nil, errors.New("invalid args")
}
args := make([]interface{}, 0, len(command.Args)+1)
args = append(args, command.Cmd)
for _, arg := range command.Args {
args = append(args, arg)
}

val, err := db.getKey(command.Args[0])
switch {
case errors.Is(err, dice.Nil):
return nil, errors.New("key does not exist")
case err != nil:
return nil, fmt.Errorf("get failed %v", err)
}
res, err := db.Client.Do(db.Ctx, args...).Result()
if errors.Is(err, dicedb.Nil) {
return RespNil, nil
}

return val, nil
if err != nil {
return nil, fmt.Errorf("(error) %v", err)
}

case "SET":
if len(command.Args) < 2 {
return nil, errors.New("key is required")
}
// Print the result based on its type
switch v := res.(type) {
case string:
return v, nil
case []byte:
return string(v), nil
case []interface{}:
return renderListResponse(v)
case int64:
return fmt.Sprintf("%v", v), nil
case nil:
return RespNil, nil
default:
return fmt.Sprintf("%v", v), nil
}
}

err := db.setKey(command.Args[0], command.Args[1])
if err != nil {
return nil, errors.New("failed to set key")
}
func renderListResponse(items []interface{}) (string, error) {
if len(items)%2 != 0 {
return "", fmt.Errorf("(error) invalid result format")
}

return RespOK, nil
var builder strings.Builder
for i := 0; i < len(items); i += 2 {
field, ok1 := items[i].(string)
value, ok2 := items[i+1].(string)

case "DEL":
if len(command.Args) == 0 {
return nil, errors.New("at least one key is required")
// Check if both field and value are valid strings
if !ok1 || !ok2 {
return "", fmt.Errorf("(error) invalid result type")
}

err := db.deleteKeys(command.Args)
// Append the formatted field and value
_, err := fmt.Fprintf(&builder, "%d) \"%s\"\n%d) \"%s\"\n", i+1, field, i+2, value)
if err != nil {
return nil, errors.New("failed to delete keys")
return "", err
}

return RespOK, nil

default:
return nil, errors.New("unknown command")
}

return builder.String(), nil
}
41 changes: 41 additions & 0 deletions internal/middleware/cors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package middleware

import (
"net/http"
"server/config"
)

// Updated enableCors function to return a boolean indicating if OPTIONS was handled
func handleCors(w http.ResponseWriter, r *http.Request) bool {
configValue := config.LoadConfig()
allAllowedOrigins := configValue.AllowedOrigins
origin := r.Header.Get("Origin")
allowed := false

for _, allowedOrigin := range allAllowedOrigins {
if origin == allowedOrigin || allowedOrigin == "*" || origin == "" {
allowed = true
break
}
}

if !allowed {
http.Error(w, "CORS: origin not allowed", http.StatusForbidden)
return true
}

w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE, PATCH")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, Content-Length")

// If the request is an OPTIONS request, handle it and stop further processing
if r.Method == http.MethodOptions {
w.Header().Set("Access-Control-Max-Age", "86400")
w.WriteHeader(http.StatusOK)
return true
}

// Continue processing other requests
w.Header().Set("Content-Type", "application/json")
return false
}
Loading

0 comments on commit a23bf92

Please sign in to comment.