Skip to content

Commit

Permalink
feat(cache): remove segment specific caching
Browse files Browse the repository at this point in the history
  • Loading branch information
JanDeDobbeleer committed Nov 4, 2024
1 parent a45fb39 commit 4fe6efc
Show file tree
Hide file tree
Showing 44 changed files with 289 additions and 982 deletions.
13 changes: 4 additions & 9 deletions src/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ type Cache interface {
Close()
// Gets the value for a given key.
// Returns the value and a boolean indicating if the key was found.
// In case the ttl expired, the function returns false.
// In case the duration expired, the function returns false.
Get(key string) (string, bool)
// Sets a value for a given key.
// The ttl indicates how many minutes to cache the value.
Set(key, value string, ttl int)
// The duration indicates how many minutes to cache the value.
Set(key, value string, duration Duration)
// Deletes a key from the cache.
Delete(key string)
}
Expand All @@ -45,11 +45,6 @@ const (
PROMPTCOUNTCACHE = "prompt_count_cache"
ENGINECACHE = "engine_cache"
FONTLISTCACHE = "font_list_cache"

ONEDAY = 1440
ONEWEEK = 10080
ONEMONTH = 43200
INFINITE = -1
)

type Entry struct {
Expand All @@ -63,5 +58,5 @@ func (c *Entry) Expired() bool {
return false
}

return time.Now().Unix() >= (c.Timestamp + int64(c.TTL)*60)
return time.Now().Unix() >= (c.Timestamp + int64(c.TTL))
}
86 changes: 86 additions & 0 deletions src/cache/duration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package cache

import (
"strconv"

"github.com/jandedobbeleer/oh-my-posh/src/regex"
)

type Duration string

const INFINITE = Duration("infinite")

func (d Duration) Seconds() int {
if d == INFINITE {
return -1
}

re := `(?P<AMOUNT>[0-9]*)(?P<UNIT>.*)`
match := regex.FindNamedRegexMatch(re, string(d))
if len(match) < 2 {
return 0
}

amount := match["AMOUNT"]
unit := match["UNIT"]

if len(amount) == 0 {
return 0
}

amountInt, err := strconv.Atoi(amount)
if err != nil {
return 0
}

var multiplier int

switch unit {
case "second", "seconds":
multiplier = 1
case "minute", "minutes":
multiplier = 60
case "hour", "hours":
multiplier = 3600
case "day", "days":
multiplier = 86400
case "week", "weeks":
multiplier = 604800
case "month", "months":
multiplier = 2592000
}

return amountInt * multiplier
}

func (d Duration) IsEmpty() bool {
return len(d) == 0
}

func ToDuration(seconds int) Duration {
if seconds == 0 {
return ""
}

if seconds == -1 {
return "infinite"
}

if seconds%604800 == 0 {
return Duration(strconv.Itoa(seconds/604800) + "weeks")
}

if seconds%86400 == 0 {
return Duration(strconv.Itoa(seconds/86400) + "days")
}

if seconds%3600 == 0 {
return Duration(strconv.Itoa(seconds/3600) + "hours")
}

if seconds%60 == 0 {
return Duration(strconv.Itoa(seconds/60) + "minutes")
}

return Duration(strconv.Itoa(seconds) + "seconds")
}
95 changes: 95 additions & 0 deletions src/cache/duration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package cache

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestSeconds(t *testing.T) {
cases := []struct {
Case string
Duration Duration
Expected int
}{
{
Case: "1 second",
Duration: "1second",
Expected: 1,
},
{
Case: "2 seconds",
Duration: "2seconds",
Expected: 2,
},
{
Case: "1 minute",
Duration: "1minute",
Expected: 60,
},
{
Case: "2 minutes",
Duration: "2minutes",
Expected: 120,
},
{
Case: "1 hour",
Duration: "1hour",
Expected: 3600,
},
{
Case: "2 hours",
Duration: "2hours",
Expected: 7200,
},
{
Case: "1 day",
Duration: "1day",
Expected: 86400,
},
{
Case: "2 days",
Duration: "2days",
Expected: 172800,
},
{
Case: "1 week",
Duration: "1week",
Expected: 604800,
},
{
Case: "2 weeks",
Duration: "2weeks",
Expected: 1209600,
},
{
Case: "1 month",
Duration: "1month",
Expected: 2592000,
},
{
Case: "2 months",
Duration: "2month",
Expected: 5184000,
},
{
Case: "invalid",
Duration: "foo",
Expected: 0,
},
{
Case: "1 fortnight",
Duration: "1fortnight",
Expected: 0,
},
{
Case: "infinite",
Duration: "infinite",
Expected: -1,
},
}
for _, tc := range cases {
got := tc.Duration.Seconds()
assert.Equal(t, tc.Expected, got, tc.Case)
}
}
8 changes: 4 additions & 4 deletions src/cache/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (fc *File) Close() {
}

// returns the value for the given key as long as
// the TTL (minutes) is not expired
// the duration is not expired
func (fc *File) Get(key string) (string, bool) {
val, found := fc.cache.Get(key)
if !found {
Expand All @@ -73,12 +73,12 @@ func (fc *File) Get(key string) (string, bool) {
return "", false
}

// sets the value for the given key with a TTL (minutes)
func (fc *File) Set(key, value string, ttl int) {
// sets the value for the given key with a duration
func (fc *File) Set(key, value string, duration Duration) {
fc.cache.Set(key, &Entry{
Value: value,
Timestamp: time.Now().Unix(),
TTL: ttl,
TTL: duration.Seconds(),
})

fc.dirty = true
Expand Down
10 changes: 7 additions & 3 deletions src/cache/mock/cache.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package mock

import mock "github.com/stretchr/testify/mock"
import (
"github.com/jandedobbeleer/oh-my-posh/src/cache"
mock "github.com/stretchr/testify/mock"
)

type Cache struct {
mock.Mock
Expand Down Expand Up @@ -34,8 +37,9 @@ func (_m *Cache) Get(key string) (string, bool) {
return r0, r1
}

func (_m *Cache) Set(key, value string, ttl int) {
_m.Called(key, value, ttl)
// set provides a mock function with given fields: key, value, ttl
func (_m *Cache) Set(key, value string, duration cache.Duration) {
_m.Called(key, value, duration)
}

func (_m *Cache) Delete(key string) {
Expand Down
2 changes: 1 addition & 1 deletion src/cli/toggle.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ var toggleCmd = &cobra.Command{
newToggles = append(newToggles, segment)
}

env.Session().Set(cache.TOGGLECACHE, strings.Join(newToggles, ","), 1440)
env.Session().Set(cache.TOGGLECACHE, strings.Join(newToggles, ","), "1day")
},
}

Expand Down
10 changes: 5 additions & 5 deletions src/config/segment.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ type Segment struct {
Background color.Ansi `json:"background,omitempty" toml:"background,omitempty"`
Foreground color.Ansi `json:"foreground,omitempty" toml:"foreground,omitempty"`
Newline bool `json:"newline,omitempty" toml:"newline,omitempty"`
CacheDuration int `json:"cache_duration,omitempty" toml:"cache_duration,omitempty"`
CacheDuration cache.Duration `json:"cache_duration,omitempty" toml:"cache_duration,omitempty"`

Enabled bool `json:"-" toml:"-"`

Expand Down Expand Up @@ -153,7 +153,7 @@ func (segment *Segment) isToggled() bool {
}

func (segment *Segment) restoreCache() bool {
if segment.CacheDuration <= 0 {
if segment.CacheDuration.IsEmpty() {
return false
}

Expand Down Expand Up @@ -182,7 +182,7 @@ func (segment *Segment) restoreCache() bool {
}

func (segment *Segment) setCache() {
if segment.CacheDuration <= 0 {
if segment.CacheDuration.IsEmpty() {
return
}

Expand All @@ -198,11 +198,11 @@ func (segment *Segment) setCache() {
}

func (segment *Segment) cacheKey() string {
return fmt.Sprintf("segment_cache_%s", segment.Name())
return fmt.Sprintf("segment_cache_%s_%s", segment.Name(), segment.env.Pwd())
}

func (segment *Segment) writerCacheKey() string {
return fmt.Sprintf("segment_cache_writer_%s", segment.Name())
return fmt.Sprintf("segment_cache_writer_%s_%s", segment.Name(), segment.env.Pwd())
}

func (segment *Segment) setText() {
Expand Down
2 changes: 1 addition & 1 deletion src/font/fonts.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func setCachedFontData(assets []*Asset) {
return
}

environment.Cache().Set(cache.FONTLISTCACHE, string(data), cache.ONEDAY)
environment.Cache().Set(cache.FONTLISTCACHE, string(data), "1day")
}

func CascadiaCode() ([]*Asset, error) {
Expand Down
14 changes: 7 additions & 7 deletions src/runtime/http/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"fmt"
"io"
httplib "net/http"

"github.com/jandedobbeleer/oh-my-posh/src/cache"
)

const (
Expand Down Expand Up @@ -80,24 +82,22 @@ func (o *OAuthRequest) refreshToken(refreshToken string) (string, error) {
message: Timeout,
}
}

tokens := &tokenExchange{}
err = json.Unmarshal(body, &tokens)
if err != nil {
return "", &OAuthError{
message: TokenRefreshFailed,
}
}

// add tokens to cache
o.Env.Cache().Set(o.AccessTokenKey, tokens.AccessToken, tokens.ExpiresIn/60)
o.Env.Cache().Set(o.RefreshTokenKey, tokens.RefreshToken, 2*525960) // it should never expire unless revoked, default to 2 year
o.Env.Cache().Set(o.AccessTokenKey, tokens.AccessToken, cache.ToDuration(tokens.ExpiresIn))
o.Env.Cache().Set(o.RefreshTokenKey, tokens.RefreshToken, "2years")
return tokens.AccessToken, nil
}

func OauthResult[a any](o *OAuthRequest, url string, body io.Reader, requestModifiers ...RequestModifier) (a, error) {
if data, err := getCacheValue[a](&o.Request, url); err == nil {
return data, nil
}

accessToken, err := o.getAccessToken()
if err != nil {
var data a
Expand All @@ -115,5 +115,5 @@ func OauthResult[a any](o *OAuthRequest, url string, body io.Reader, requestModi

requestModifiers = append(requestModifiers, addAuthHeader)

return do[a](&o.Request, url, body, requestModifiers...)
return Do[a](&o.Request, url, body, requestModifiers...)
}
Loading

0 comments on commit 4fe6efc

Please sign in to comment.