diff --git a/go.mod b/go.mod index 4431611..61d65dc 100644 --- a/go.mod +++ b/go.mod @@ -178,7 +178,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - lukechampine.com/blake3 v1.2.1 // indirect + lukechampine.com/blake3 v1.3.0 // indirect ) require ( @@ -231,7 +231,7 @@ require ( github.com/xaionaro-go/kickcom v0.0.0-20241022142825-25a234cc8628 github.com/xaionaro-go/lockmap v0.0.0-20240901172806-e17aea364748 github.com/xaionaro-go/mediamtx v0.0.0-20241009124606-94c22c603970 - github.com/xaionaro-go/object v0.0.0-20241024025057-382352276e7b + github.com/xaionaro-go/object v0.0.0-20241026212449-753ce10ec94c github.com/xaionaro-go/obs-grpc-proxy v0.0.0-20241018162120-5faf4e7a684a github.com/xaionaro-go/timeapiio v0.0.0-20240915203246-b907cf699af3 github.com/xaionaro-go/typing v0.0.0-20221123235249-2229101d38ba diff --git a/go.sum b/go.sum index c3fa9fc..cb37786 100644 --- a/go.sum +++ b/go.sum @@ -697,6 +697,8 @@ github.com/xaionaro-go/mediamtx v0.0.0-20241009124606-94c22c603970 h1:QmbvVR2Jt+ github.com/xaionaro-go/mediamtx v0.0.0-20241009124606-94c22c603970/go.mod h1:3J9s+wGt6CV4MDnoXApKEdY3kdc5sd6AYEndLJSAIYI= github.com/xaionaro-go/object v0.0.0-20241024025057-382352276e7b h1:tAZ8x7bEoxhv2/o73ykCvuI/cR7ifcuH6dUxiEZLTqw= github.com/xaionaro-go/object v0.0.0-20241024025057-382352276e7b/go.mod h1:kiXodA4gThh6NpkPWRlgdqbtel8/F7zj4xIBAhDPygM= +github.com/xaionaro-go/object v0.0.0-20241026212449-753ce10ec94c h1:2CIIxTRox9auImHyfbfrqSyrvPaWrw5w2Yw5TkOioZw= +github.com/xaionaro-go/object v0.0.0-20241026212449-753ce10ec94c/go.mod h1:vRcA12NWsR0IrS75eqnPBs5aVfCYmJy4bR+6DbJpBCg= github.com/xaionaro-go/obs-grpc-proxy v0.0.0-20241018162120-5faf4e7a684a h1:PyX7XpLkj+eAwrPMFMGpvZIG4zBfzAfwNhwTtbORqN0= github.com/xaionaro-go/obs-grpc-proxy v0.0.0-20241018162120-5faf4e7a684a/go.mod h1:exSKIlCibB0ww+ABDwH+YG/iNdqVfdzXBBg5LYxkxGw= github.com/xaionaro-go/pulse v0.0.0-20241023202712-7151fa00d4bb h1:9iHPI27CYbmJDhzEuCABQthE/DGVNvT60ybWvv3BV8w= @@ -1256,6 +1258,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= +lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/pkg/streamcontrol/kick/cache.go b/pkg/streamcontrol/kick/cache.go new file mode 100644 index 0000000..4947421 --- /dev/null +++ b/pkg/streamcontrol/kick/cache.go @@ -0,0 +1,39 @@ +package kick + +import ( + "context" + "sync/atomic" + "unsafe" + + "github.com/xaionaro-go/kickcom" +) + +type Cache struct { + ChanInfo *kickcom.ChannelV1 +} + +type ctxKeyCacheT struct{} + +var ctxKeyCache ctxKeyCacheT + +func CtxWithCache(ctx context.Context, cache *Cache) context.Context { + return context.WithValue(ctx, ctxKeyCache, cache) +} + +func CacheFromCtx(ctx context.Context) *Cache { + cacheIface := ctx.Value(ctxKeyCache) + cache, _ := cacheIface.(*Cache) + return cache +} + +func (cache *Cache) GetChanInfo() *kickcom.ChannelV1 { + if cache == nil { + return nil + } + + return (*kickcom.ChannelV1)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&cache.ChanInfo)))) +} + +func (cache *Cache) SetChanInfo(chanInfo *kickcom.ChannelV1) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&cache.ChanInfo)), unsafe.Pointer(chanInfo)) +} diff --git a/pkg/streamcontrol/kick/kick.go b/pkg/streamcontrol/kick/kick.go index 79e681f..043af4a 100644 --- a/pkg/streamcontrol/kick/kick.go +++ b/pkg/streamcontrol/kick/kick.go @@ -45,27 +45,31 @@ func New( return nil, fmt.Errorf("channel is not set") } - var err error - var client *kickcom.Kick - var channel *kickcom.ChannelV1 - for i := 0; i < 10; i++ { + client, err := kickcom.New() + if err != nil { + return nil, fmt.Errorf("unable to initialize a client to Kick: %w", err) + } - client, err = kickcom.New() - if err != nil { - err = fmt.Errorf("unable to initialize a client to Kick: %w", err) - time.Sleep(time.Second) - continue + var channel *kickcom.ChannelV1 + cache := CacheFromCtx(ctx) + if chanInfo := cache.GetChanInfo(); chanInfo != nil && chanInfo.Slug == cfg.Config.Channel { + channel = cache.ChanInfo + logger.Debugf(ctx, "reuse the cache, instead of querying channel info") + } else { + for i := 0; i < 10; i++ { + channel, err = client.GetChannelV1(ctx, cfg.Config.Channel) + if err != nil { + err = fmt.Errorf("unable to obtain channel info: %w", err) + time.Sleep(time.Second) + continue + } } - - channel, err = client.GetChannelV1(ctx, cfg.Config.Channel) if err != nil { - err = fmt.Errorf("unable to obtain channel info: %w", err) - time.Sleep(time.Second) - continue + return nil, err + } + if cache != nil { + cache.SetChanInfo(channel) } - } - if err != nil { - return nil, err } ctx, closeFn := context.WithCancel(ctx) diff --git a/pkg/streamd/api/streamd.go b/pkg/streamd/api/streamd.go index 4ed82d0..bf23368 100644 --- a/pkg/streamd/api/streamd.go +++ b/pkg/streamd/api/streamd.go @@ -307,6 +307,7 @@ type BackendDataTwitch struct { } type BackendDataKick struct { + Cache cache.Kick } type BackendDataYouTube struct { diff --git a/pkg/streamd/cache/cache.go b/pkg/streamd/cache/cache.go index 558c9b0..0b7dae0 100644 --- a/pkg/streamd/cache/cache.go +++ b/pkg/streamd/cache/cache.go @@ -10,9 +10,12 @@ import ( "github.com/facebookincubator/go-belt/tool/logger" "github.com/goccy/go-yaml" "github.com/nicklaw5/helix/v2" + "github.com/xaionaro-go/streamctl/pkg/streamcontrol/kick" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube" ) +type Kick = kick.Cache + type Twitch struct { Categories []helix.Game } @@ -22,6 +25,7 @@ type YouTube struct { } type Cache struct { + Kick Kick Twitch Twitch Youtube YouTube } diff --git a/pkg/streamd/stream_controller.go b/pkg/streamd/stream_controller.go index c6ce51c..4d829d7 100644 --- a/pkg/streamd/stream_controller.go +++ b/pkg/streamd/stream_controller.go @@ -12,6 +12,7 @@ import ( "github.com/andreykaipov/goobs/api/events/subscriptions" "github.com/facebookincubator/go-belt/tool/logger" "github.com/hashicorp/go-multierror" + "github.com/xaionaro-go/object" "github.com/xaionaro-go/streamctl/pkg/streamcontrol" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/kick" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/obs" @@ -345,8 +346,9 @@ func (d *StreamD) initTwitchBackend(ctx context.Context) error { } func (d *StreamD) initKickBackend(ctx context.Context) error { + cacheHashBeforeInit, _ := object.CalcCryptoHash(d.Cache.Kick) kick, err := newKick( - ctx, + kick.CtxWithCache(ctx, &d.Cache.Kick), d.Config.Backends[kick.ID], func(cfg *streamcontrol.AbstractPlatformConfig) error { return d.setPlatformConfig(ctx, kick.ID, cfg) @@ -357,6 +359,13 @@ func (d *StreamD) initKickBackend(ctx context.Context) error { if err != nil { return err } + cacheHashAfterInit, _ := object.CalcCryptoHash(d.Cache.Kick) + if len(cacheHashAfterInit) == 0 || !cacheHashAfterInit.Equals(cacheHashBeforeInit) { + err := d.writeCache(ctx) + if err != nil { + logger.Errorf(ctx, "unable to write cache: %w", err) + } + } d.StreamControllers.Kick = kick return nil } diff --git a/pkg/streamd/streamd.go b/pkg/streamd/streamd.go index bac9ba2..53fd328 100644 --- a/pkg/streamd/streamd.go +++ b/pkg/streamd/streamd.go @@ -455,8 +455,7 @@ func (d *StreamD) saveConfig(ctx context.Context) error { } func (d *StreamD) ResetCache(ctx context.Context) error { - d.Cache.Twitch = cache.Twitch{} - d.Cache.Youtube = cache.YouTube{} + d.Cache = &cache.Cache{} return nil } @@ -718,7 +717,7 @@ func (d *StreamD) getBackendData( case twitch.ID: return api.BackendDataTwitch{Cache: d.Cache.Twitch}, nil case kick.ID: - return api.BackendDataKick{}, nil + return api.BackendDataKick{Cache: d.Cache.Kick}, nil case youtube.ID: return api.BackendDataYouTube{Cache: d.Cache.Youtube}, nil default: diff --git a/pkg/streampanel/panel.go b/pkg/streampanel/panel.go index 0009e10..73e6529 100644 --- a/pkg/streampanel/panel.go +++ b/pkg/streampanel/panel.go @@ -2418,6 +2418,7 @@ func (p *Panel) initMainWindow( p.statusPanel = widget.NewLabel("") p.statusPanel.Wrapping = fyne.TextWrapWord + p.statusPanel.Truncation = fyne.TextTruncateEllipsis w.SetContent(container.NewBorder( container.NewVBox(