-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Olric provider embedded mode support (#80)
* Implement Olric support as embedded mode * Remove useless code * Fix test env containers * Update embeddedOlricProvider_test.go * Support the JSON configuration * Fix tests * Support struct to Olric config * Fix review * Use UUID for dynamic Olric configuration temp storage * Fix TTL recovery
- Loading branch information
Showing
356 changed files
with
8,910 additions
and
44,252 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
package providers | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"github.com/buraksezer/olric" | ||
"github.com/buraksezer/olric/config" | ||
"github.com/darkweak/souin/cache/keysaver" | ||
t "github.com/darkweak/souin/configurationtypes" | ||
"github.com/google/uuid" | ||
"go.uber.org/zap" | ||
"gopkg.in/yaml.v3" | ||
"io/ioutil" | ||
"os" | ||
"time" | ||
) | ||
|
||
// EmbeddedOlric provider type | ||
type EmbeddedOlric struct { | ||
dm *olric.DMap | ||
db *olric.Olric | ||
keySaver *keysaver.ClearKey | ||
} | ||
|
||
func tryToLoadConfiguration(olricInstance *config.Config, olricConfiguration t.CacheProvider, logger *zap.Logger) (*config.Config, bool) { | ||
var e error | ||
isAlreadyLoaded := false | ||
if olricConfiguration.Configuration == nil && olricConfiguration.Path != "" { | ||
if olricInstance, e = config.Load(olricConfiguration.Path); e == nil { | ||
isAlreadyLoaded = true | ||
} | ||
} else if olricConfiguration.Configuration != nil { | ||
tmpFile := "/tmp/" + uuid.NewString() + ".yml" | ||
yamlConfig, e := yaml.Marshal(olricConfiguration.Configuration) | ||
defer func() { | ||
if e = os.RemoveAll(tmpFile); e != nil { | ||
logger.Error("Impossible to remove the temporary file") | ||
} | ||
}() | ||
if e = ioutil.WriteFile( | ||
tmpFile, | ||
yamlConfig, | ||
0644, | ||
); e != nil { | ||
logger.Error("Impossible to create the embedded Olric config from the given one") | ||
} | ||
|
||
if olricInstance, e = config.Load(tmpFile); e == nil { | ||
isAlreadyLoaded = true | ||
} else { | ||
logger.Error("Impossible to create the embedded Olric config from the given one") | ||
} | ||
} | ||
|
||
return olricInstance, isAlreadyLoaded | ||
} | ||
|
||
// EmbeddedOlricConnectionFactory function create new EmbeddedOlric instance | ||
func EmbeddedOlricConnectionFactory(configuration t.AbstractConfigurationInterface) (*EmbeddedOlric, error) { | ||
var keySaver *keysaver.ClearKey | ||
if configuration.GetAPI().Souin.Enable { | ||
keySaver = keysaver.NewClearKey() | ||
} | ||
|
||
var olricInstance *config.Config | ||
loaded := false | ||
|
||
if olricInstance, loaded = tryToLoadConfiguration(olricInstance, configuration.GetDefaultCache().GetOlric(), configuration.GetLogger()); !loaded { | ||
olricInstance = config.New("local") | ||
olricInstance.Cache.MaxInuse = 512 << 20 | ||
} | ||
|
||
started, cancel := context.WithCancel(context.Background()) | ||
olricInstance.Started = func() { | ||
defer cancel() | ||
configuration.GetLogger().Info("Embedded Olric is ready") | ||
} | ||
|
||
db, err := olric.New(olricInstance) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
ch := make(chan error, 1) | ||
go func() { | ||
if err = db.Start(); err != nil { | ||
fmt.Println(fmt.Sprintf("Impossible to start the embedded Olric instance: %v", err)) | ||
ch <- err | ||
} | ||
}() | ||
|
||
select { | ||
case err = <-ch: | ||
return nil, err | ||
case <-started.Done(): | ||
} | ||
dm, e := db.NewDMap("souin-map") | ||
|
||
return &EmbeddedOlric{ | ||
dm, | ||
db, | ||
keySaver, | ||
}, e | ||
} | ||
|
||
// ListKeys method returns the list of existing keys | ||
func (provider *EmbeddedOlric) ListKeys() []string { | ||
if nil != provider.keySaver { | ||
return provider.keySaver.ListKeys() | ||
} | ||
return []string{} | ||
} | ||
|
||
// Get method returns the populated response if exists, empty response then | ||
func (provider *EmbeddedOlric) Get(key string) []byte { | ||
val2, err := provider.dm.Get(key) | ||
|
||
if err != nil { | ||
return []byte{} | ||
} | ||
|
||
return val2.([]byte) | ||
} | ||
|
||
// Set method will store the response in EmbeddedOlric provider | ||
func (provider *EmbeddedOlric) Set(key string, value []byte, url t.URL, duration time.Duration) { | ||
if duration == 0 { | ||
ttl, err := time.ParseDuration(url.TTL) | ||
if err != nil { | ||
ttl = 0 | ||
fmt.Println(err) | ||
} | ||
duration = ttl | ||
} | ||
|
||
err := provider.dm.PutEx(key, value, duration) | ||
if err != nil { | ||
panic(err) | ||
} else { | ||
go func() { | ||
if nil != provider.keySaver { | ||
provider.keySaver.AddKey(key) | ||
} | ||
}() | ||
} | ||
} | ||
|
||
// Delete method will delete the response in EmbeddedOlric provider if exists corresponding to key param | ||
func (provider *EmbeddedOlric) Delete(key string) { | ||
go func() { | ||
err := provider.dm.Delete(key) | ||
if err != nil { | ||
panic(err) | ||
} else { | ||
go func() { | ||
if nil != provider.keySaver { | ||
provider.keySaver.DelKey(key, 0) | ||
} | ||
}() | ||
} | ||
}() | ||
} | ||
|
||
// Init method will initialize EmbeddedOlric provider if needed | ||
func (provider *EmbeddedOlric) Init() error { | ||
return nil | ||
} | ||
|
||
// Reset method will reset or close provider | ||
func (provider *EmbeddedOlric) Reset() { | ||
_ = provider.db.Shutdown(context.Background()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package providers | ||
|
||
import ( | ||
"fmt" | ||
"github.com/darkweak/souin/cache/types" | ||
"github.com/darkweak/souin/configurationtypes" | ||
"github.com/darkweak/souin/errors" | ||
"github.com/darkweak/souin/tests" | ||
"testing" | ||
"time" | ||
) | ||
|
||
const EMBEDDEDOLRICVALUE = "My first data" | ||
|
||
func mockEmbeddedConfiguration(c func() string, key string) (types.AbstractProviderInterface, configurationtypes.URL) { | ||
return tests.GetCacheProviderClientAndMatchedURL( | ||
key, | ||
func() configurationtypes.AbstractConfigurationInterface { | ||
return tests.MockConfiguration(c) | ||
}, | ||
func(config configurationtypes.AbstractConfigurationInterface) (types.AbstractProviderInterface, error) { | ||
provider, _ := EmbeddedOlricConnectionFactory(config) | ||
_ = provider.Init() | ||
|
||
return provider, nil | ||
}, | ||
) | ||
} | ||
|
||
func getEmbeddedOlricClientAndMatchedURL(key string) (types.AbstractProviderInterface, configurationtypes.URL) { | ||
return mockEmbeddedConfiguration(tests.EmbeddedOlricConfiguration, key) | ||
} | ||
|
||
func getEmbeddedOlricWithoutYAML(key string) (types.AbstractProviderInterface, configurationtypes.URL) { | ||
return mockEmbeddedConfiguration(tests.EmbeddedOlricPlainConfigurationWithoutAdditionalYAML, key) | ||
} | ||
|
||
func TestIShouldBeAbleToReadAndWriteDataInEmbeddedOlric(t *testing.T) { | ||
client, u := getEmbeddedOlricClientAndMatchedURL("Test") | ||
defer client.Reset() | ||
client.Set("Test", []byte(EMBEDDEDOLRICVALUE), u, time.Duration(10)*time.Second) | ||
time.Sleep(3 * time.Second) | ||
res := client.Get("Test") | ||
if EMBEDDEDOLRICVALUE != string(res) { | ||
errors.GenerateError(t, fmt.Sprintf("%s not corresponding to %s", res, EMBEDDEDOLRICVALUE)) | ||
} | ||
} | ||
|
||
func TestIShouldBeAbleToReadAndWriteDataInEmbeddedOlricWithoutYAML(t *testing.T) { | ||
client, u := getEmbeddedOlricWithoutYAML("Test") | ||
defer client.Reset() | ||
client.Set("Test", []byte(EMBEDDEDOLRICVALUE), u, time.Duration(10)*time.Second) | ||
time.Sleep(3 * time.Second) | ||
res := client.Get("Test") | ||
if EMBEDDEDOLRICVALUE != string(res) { | ||
errors.GenerateError(t, fmt.Sprintf("%s not corresponding to %s", res, EMBEDDEDOLRICVALUE)) | ||
} | ||
} | ||
|
||
func TestEmbeddedOlric_GetRequestInCache(t *testing.T) { | ||
client, _ := getEmbeddedOlricClientAndMatchedURL(NONEXISTENTKEY) | ||
defer client.Reset() | ||
res := client.Get(NONEXISTENTKEY) | ||
if string(res) != "" { | ||
errors.GenerateError(t, fmt.Sprintf("Key %s should not exist", NONEXISTENTKEY)) | ||
} | ||
} | ||
|
||
func TestEmbeddedOlric_SetRequestInCache_OneByte(t *testing.T) { | ||
client, u := getEmbeddedOlricClientAndMatchedURL(BYTEKEY) | ||
defer client.Reset() | ||
client.Set(BYTEKEY, []byte{65}, u, time.Duration(20)*time.Second) | ||
} | ||
|
||
func TestEmbeddedOlric_SetRequestInCache_TTL(t *testing.T) { | ||
key := "MyEmptyKey" | ||
client, matchedURL := getEmbeddedOlricClientAndMatchedURL(key) | ||
defer client.Reset() | ||
nv := []byte("Hello world") | ||
setValueThenVerify(client, key, nv, matchedURL, time.Duration(20)*time.Second, t) | ||
} | ||
|
||
func TestEmbeddedOlric_SetRequestInCache_NoTTL(t *testing.T) { | ||
client, matchedURL := getEmbeddedOlricClientAndMatchedURL(BYTEKEY) | ||
defer client.Reset() | ||
nv := []byte("New value") | ||
setValueThenVerify(client, BYTEKEY, nv, matchedURL, 0, t) | ||
} | ||
|
||
func TestEmbeddedOlric_DeleteRequestInCache(t *testing.T) { | ||
client, _ := getEmbeddedOlricClientAndMatchedURL(BYTEKEY) | ||
defer client.Reset() | ||
client.Delete(BYTEKEY) | ||
time.Sleep(1 * time.Second) | ||
if 0 < len(client.Get(BYTEKEY)) { | ||
errors.GenerateError(t, fmt.Sprintf("Key %s should not exist", BYTEKEY)) | ||
} | ||
} | ||
|
||
func TestEmbeddedOlric_Init(t *testing.T) { | ||
client, _ := EmbeddedOlricConnectionFactory(tests.MockConfiguration(tests.EmbeddedOlricConfiguration)) | ||
err := client.Init() | ||
defer client.Reset() | ||
|
||
if nil != err { | ||
errors.GenerateError(t, "Impossible to init EmbeddedOlric provider") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,8 @@ services: | |
build: | ||
context: . | ||
target: souin | ||
depends_on: | ||
- olric | ||
ports: | ||
- 80:80 | ||
- 443:443 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.