From 778cf630a244eb0d5e432267bdfb25419c270a40 Mon Sep 17 00:00:00 2001 From: Mustafa CEVIK Date: Sun, 10 Oct 2021 15:12:41 +0300 Subject: [PATCH 1/6] refactor(proxy): edited map operations (made thread safe) --- 103-http/proxy/cache.go | 7 ++++++- 103-http/proxy/limit.go | 43 +++++++++++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/103-http/proxy/cache.go b/103-http/proxy/cache.go index b65f275..889ef52 100644 --- a/103-http/proxy/cache.go +++ b/103-http/proxy/cache.go @@ -9,7 +9,7 @@ import ( "github.com/gofiber/fiber/v2/middleware/proxy" ) -// TODO: Burada ki mapi thread safe hale getirebilirsiniz. +// DONE: Buradaki mapi thread safe hale getirebilirsiniz. // 102-concurrency egitimindeki mutex orneklerine bakabilirsiniz. // Ref: https://pmihaylov.com/thread-safety-concerns-go/ // Ref: https://medium.com/@deckarep/the-new-kid-in-town-gos-sync-map-de24a6bf7c2c @@ -67,7 +67,12 @@ func (p CacheProxy) Proxy(c *fiber.Ctx) error { body: c.Response().Body(), } + //cache[path] = ch + + // thread safe version + mutex.Lock() cache[path] = ch + mutex.Unlock() c.Response().Header.Del(fiber.HeaderServer) return nil diff --git a/103-http/proxy/limit.go b/103-http/proxy/limit.go index df5cc56..ac950a5 100644 --- a/103-http/proxy/limit.go +++ b/103-http/proxy/limit.go @@ -2,15 +2,17 @@ package main import ( "fmt" + "sync" "time" "github.com/gofiber/fiber/v2" ) -// TODO: Burada ki mapi thread safe hale getirebilirsiniz. +// DONE: Buradaki mapi thread safe hale getirebilirsiniz. // 102-concurrency egitimindeki mutex orneklerine bakabilirsiniz. // Ref: https://pmihaylov.com/thread-safety-concerns-go/ // Ref: https://medium.com/@deckarep/the-new-kid-in-town-gos-sync-map-de24a6bf7c2c +var mutex sync.Mutex var counter = map[string]*Limit{} type Limit struct { @@ -55,21 +57,42 @@ func (p LimitProxy) Proxy(c *fiber.Ctx) error { } else { fmt.Printf("resetting counter values \n") - counter[path] = &Limit{ - count: 0, - ttl: time.Now().Add(p.ttl), - } + //counter[path] = &Limit{ + // count: 0, + // ttl: time.Now().Add(p.ttl), + //} + + // thread safe version + defineCounter(path, p.ttl) } } else if !ok { - counter[path] = &Limit{ - count: 0, - ttl: time.Now().Add(p.ttl), - } + //counter[path] = &Limit{ + // count: 0, + // ttl: time.Now().Add(p.ttl), + //} + + // thread safe version + defineCounter(path, p.ttl) } c.SendString("Go Turkiye - 103 Http Package") - counter[path].count++ + //counter[path].count++ + + // thread safe version + incrementCounter(path) return nil } + +func defineCounter(path string, ttl time.Duration) { + mutex.Lock() + counter[path] = &Limit{count: 0, ttl: time.Now().Add(ttl)} + mutex.Unlock() +} + +func incrementCounter(path string) { + mutex.Lock() + counter[path].count++ + mutex.Unlock() +} From a9b7a8176d7fc3353eb277fb0476c19ac0bd6e9c Mon Sep 17 00:00:00 2001 From: Mustafa CEVIK Date: Sun, 10 Oct 2021 15:48:08 +0300 Subject: [PATCH 2/6] refactor(proxy): edited response & error for reached limit, added error handling --- 103-http/proxy/limit.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/103-http/proxy/limit.go b/103-http/proxy/limit.go index ac950a5..74738ca 100644 --- a/103-http/proxy/limit.go +++ b/103-http/proxy/limit.go @@ -49,11 +49,11 @@ func (p LimitProxy) Proxy(c *fiber.Ctx) error { if r, ok := counter[path]; ok && r.count >= p.limit { if r.ttl.After(time.Now()) { - c.Response().SetStatusCode(429) + c.Response().SetStatusCode(fiber.StatusTooManyRequests) fmt.Printf("request limit reached for %s \n", path) - return nil + return fiber.ErrTooManyRequests } else { fmt.Printf("resetting counter values \n") @@ -75,7 +75,9 @@ func (p LimitProxy) Proxy(c *fiber.Ctx) error { defineCounter(path, p.ttl) } - c.SendString("Go Turkiye - 103 Http Package") + if err := c.SendString("Go Turkiye - 103 Http Package"); err != nil { + return err + } //counter[path].count++ From 74cc93e46845619665ab461ac7cd856cb22f673c Mon Sep 17 00:00:00 2001 From: Mustafa CEVIK Date: Sun, 10 Oct 2021 17:34:53 +0300 Subject: [PATCH 3/6] refactor(proxy): edited response header for cached values, checked response status code --- 103-http/proxy/cache.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/103-http/proxy/cache.go b/103-http/proxy/cache.go index 889ef52..c62d694 100644 --- a/103-http/proxy/cache.go +++ b/103-http/proxy/cache.go @@ -48,13 +48,14 @@ func (p CacheProxy) Proxy(c *fiber.Ctx) error { if r, ok := cache[path]; ok && r.ttl.After(time.Now()) { c.Response().SetBody(r.body) - c.Response().Header.Add("cache-control", fmt.Sprintf("max-age:%d", p.ttl/time.Second)) + c.Response().Header.Add(fiber.HeaderContentType, fiber.MIMEApplicationJSON) + c.Response().Header.Add(fiber.HeaderCacheControl, fmt.Sprintf("max-age:%d", p.ttl/time.Second)) return nil } // https://mocki.io/v1/d4d63bce-1809-4250-91ac-0470aa392ca5 - url := "https://mocki.io/" + strings.TrimPrefix(path, "/"+key+"/") + url := "https://mocki.io" + strings.TrimPrefix(path, "/"+key) fmt.Printf("http request redirecting to %s \n", url) @@ -62,6 +63,12 @@ func (p CacheProxy) Proxy(c *fiber.Ctx) error { return err } + respStatusCode := c.Response().StatusCode() + + if respStatusCode != fiber.StatusOK { + return fiber.NewError(respStatusCode, "Check your request") + } + ch := Cache{ ttl: time.Now().Add(p.ttl), body: c.Response().Body(), From 2df80c9e484413634a7a1821fab8625a44e33321 Mon Sep 17 00:00:00 2001 From: Mustafa CEVIK Date: Mon, 11 Oct 2021 20:57:15 +0300 Subject: [PATCH 4/6] feat(proxy): implemented reset limit handler --- 103-http/proxy/limit.go | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/103-http/proxy/limit.go b/103-http/proxy/limit.go index 74738ca..9a64899 100644 --- a/103-http/proxy/limit.go +++ b/103-http/proxy/limit.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "strings" "sync" "time" @@ -26,12 +27,6 @@ type LimitProxy struct { ttl time.Duration } -func ResetLimitHandler(c *fiber.Ctx) error { - // TODO: [DELETE] /limit/:key/* pathine istek atildiginda limiti sifirlayan handleri implement edebilirsiniz. - // TODO: implement me! - return nil -} - func NewLimitProxy(key string, limit int, ttl time.Duration) LimitProxy { return LimitProxy{ key: key, @@ -40,6 +35,24 @@ func NewLimitProxy(key string, limit int, ttl time.Duration) LimitProxy { } } +func ResetLimitHandler(c *fiber.Ctx) error { + // DONE: [DELETE] /limit/:key/* pathine istek atildiginda limiti sifirlayan handleri implement edebilirsiniz. + // DONE: implement me! + + key := strings.TrimPrefix(c.Path(), "/limit") + + if _, ok := counter[key]; !ok { + return fiber.ErrNotFound + } + + mutex.Lock() + delete(counter, key) + mutex.Unlock() + + c.Response().SetStatusCode(fiber.StatusNoContent) + return nil +} + func (p LimitProxy) Accept(key string) bool { return p.key == key } From d040701792d94d180b62865752f18f27fe7535fc Mon Sep 17 00:00:00 2001 From: Mustafa CEVIK Date: Mon, 11 Oct 2021 21:23:37 +0300 Subject: [PATCH 5/6] feat(proxy): implemented evict cache handler --- 103-http/proxy/cache.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/103-http/proxy/cache.go b/103-http/proxy/cache.go index c62d694..8d8ee97 100644 --- a/103-http/proxy/cache.go +++ b/103-http/proxy/cache.go @@ -25,12 +25,6 @@ type CacheProxy struct { ttl time.Duration } -func EvictCacheHandler(c *fiber.Ctx) error { - // TODO: [DELETE] /cache/:key/* pathine istek atildiginda memorydeki cachei temizleyen handleri implement edebilirsiniz. - // TODO: implement me! - return nil -} - func NewCacheProxy(key string, ttl time.Duration) CacheProxy { return CacheProxy{ key: key, @@ -38,6 +32,24 @@ func NewCacheProxy(key string, ttl time.Duration) CacheProxy { } } +func EvictCacheHandler(c *fiber.Ctx) error { + // DONE: [DELETE] /cache/:key/* pathine istek atildiginda memorydeki cachei temizleyen handleri implement edebilirsiniz. + // DONE: implement me! + + key := strings.TrimPrefix(c.Path(), "/cache") + + if _, ok := cache[key]; !ok { + return fiber.ErrNotFound + } + + mutex.Lock() + delete(cache, key) + mutex.Unlock() + + c.Response().SetStatusCode(fiber.StatusNoContent) + return nil +} + func (p CacheProxy) Accept(key string) bool { return p.key == key } From ae25deafc9f5b6af1316200dcce2c9831049abab Mon Sep 17 00:00:00 2001 From: Mustafa CEVIK Date: Thu, 14 Oct 2021 17:14:54 +0300 Subject: [PATCH 6/6] refactor(proxy): added new structs (maps converted to custom structs), refactored map functions (edited as receiver method) --- 103-http/proxy/cache.go | 33 +++++++++++++++++++++--------- 103-http/proxy/limit.go | 45 ++++++++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/103-http/proxy/cache.go b/103-http/proxy/cache.go index 8d8ee97..9ec15cb 100644 --- a/103-http/proxy/cache.go +++ b/103-http/proxy/cache.go @@ -3,6 +3,7 @@ package main import ( "fmt" "strings" + "sync" "time" "github.com/gofiber/fiber/v2" @@ -13,7 +14,13 @@ import ( // 102-concurrency egitimindeki mutex orneklerine bakabilirsiniz. // Ref: https://pmihaylov.com/thread-safety-concerns-go/ // Ref: https://medium.com/@deckarep/the-new-kid-in-town-gos-sync-map-de24a6bf7c2c -var cache = map[string]Cache{} + +var cache = &CacheStore{v: map[string]Cache{}} + +type CacheStore struct { + sync.Mutex + v map[string]Cache +} type Cache struct { body []byte @@ -38,13 +45,11 @@ func EvictCacheHandler(c *fiber.Ctx) error { key := strings.TrimPrefix(c.Path(), "/cache") - if _, ok := cache[key]; !ok { + if _, ok := cache.v[key]; !ok { return fiber.ErrNotFound } - mutex.Lock() - delete(cache, key) - mutex.Unlock() + cache.Delete(key) c.Response().SetStatusCode(fiber.StatusNoContent) return nil @@ -58,7 +63,7 @@ func (p CacheProxy) Proxy(c *fiber.Ctx) error { path := c.Path() key := c.Params("key") - if r, ok := cache[path]; ok && r.ttl.After(time.Now()) { + if r, ok := cache.v[path]; ok && r.ttl.After(time.Now()) { c.Response().SetBody(r.body) c.Response().Header.Add(fiber.HeaderContentType, fiber.MIMEApplicationJSON) c.Response().Header.Add(fiber.HeaderCacheControl, fmt.Sprintf("max-age:%d", p.ttl/time.Second)) @@ -89,10 +94,20 @@ func (p CacheProxy) Proxy(c *fiber.Ctx) error { //cache[path] = ch // thread safe version - mutex.Lock() - cache[path] = ch - mutex.Unlock() + cache.Set(path, ch) c.Response().Header.Del(fiber.HeaderServer) return nil } + +func (c *CacheStore) Set(key string, cache Cache) { + c.Lock() + c.v[key] = cache + c.Unlock() +} + +func (c *CacheStore) Delete(key string) { + c.Lock() + delete(c.v, key) + c.Unlock() +} diff --git a/103-http/proxy/limit.go b/103-http/proxy/limit.go index 9a64899..5236e5e 100644 --- a/103-http/proxy/limit.go +++ b/103-http/proxy/limit.go @@ -13,8 +13,13 @@ import ( // 102-concurrency egitimindeki mutex orneklerine bakabilirsiniz. // Ref: https://pmihaylov.com/thread-safety-concerns-go/ // Ref: https://medium.com/@deckarep/the-new-kid-in-town-gos-sync-map-de24a6bf7c2c -var mutex sync.Mutex -var counter = map[string]*Limit{} + +var counter = &LimitCounter{v: map[string]*Limit{}} + +type LimitCounter struct { + sync.Mutex + v map[string]*Limit +} type Limit struct { count int @@ -41,13 +46,11 @@ func ResetLimitHandler(c *fiber.Ctx) error { key := strings.TrimPrefix(c.Path(), "/limit") - if _, ok := counter[key]; !ok { + if _, ok := counter.v[key]; !ok { return fiber.ErrNotFound } - mutex.Lock() - delete(counter, key) - mutex.Unlock() + counter.Delete(key) c.Response().SetStatusCode(fiber.StatusNoContent) return nil @@ -60,7 +63,7 @@ func (p LimitProxy) Accept(key string) bool { func (p LimitProxy) Proxy(c *fiber.Ctx) error { path := c.Path() - if r, ok := counter[path]; ok && r.count >= p.limit { + if r, ok := counter.v[path]; ok && r.count >= p.limit { if r.ttl.After(time.Now()) { c.Response().SetStatusCode(fiber.StatusTooManyRequests) @@ -76,7 +79,7 @@ func (p LimitProxy) Proxy(c *fiber.Ctx) error { //} // thread safe version - defineCounter(path, p.ttl) + counter.Set(path, p.ttl) } } else if !ok { //counter[path] = &Limit{ @@ -85,7 +88,7 @@ func (p LimitProxy) Proxy(c *fiber.Ctx) error { //} // thread safe version - defineCounter(path, p.ttl) + counter.Set(path, p.ttl) } if err := c.SendString("Go Turkiye - 103 Http Package"); err != nil { @@ -95,19 +98,25 @@ func (p LimitProxy) Proxy(c *fiber.Ctx) error { //counter[path].count++ // thread safe version - incrementCounter(path) + counter.Increment(path) return nil } -func defineCounter(path string, ttl time.Duration) { - mutex.Lock() - counter[path] = &Limit{count: 0, ttl: time.Now().Add(ttl)} - mutex.Unlock() +func (l *LimitCounter) Set(key string, ttl time.Duration) { + l.Lock() + l.v[key] = &Limit{count: 0, ttl: time.Now().Add(ttl)} + l.Unlock() +} + +func (l *LimitCounter) Increment(key string) { + l.Lock() + l.v[key].count++ + l.Unlock() } -func incrementCounter(path string) { - mutex.Lock() - counter[path].count++ - mutex.Unlock() +func (l *LimitCounter) Delete(key string) { + l.Lock() + delete(l.v, key) + l.Unlock() }