mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-08-02 09:08:35 +02:00
perf(go): cut redundant signed-session writes, progress-callback churn, tombstone growth
This commit is contained in:
@@ -292,6 +292,7 @@ func (r *extensionRuntime) fileDownload(call goja.FunctionCall) goja.Value {
|
||||
}
|
||||
|
||||
var written int64
|
||||
var lastProgressNotify int64
|
||||
buf := make([]byte, 32*1024)
|
||||
|
||||
// copyBody streams resp into progressWriter. fatal is a terminal JS error
|
||||
@@ -321,7 +322,11 @@ func (r *extensionRuntime) fileDownload(call goja.FunctionCall) goja.Value {
|
||||
return r.jsError("short write"), nil
|
||||
}
|
||||
|
||||
if onProgress != nil && contentLength > 0 {
|
||||
// Throttle the JS callback like the native progress writer:
|
||||
// per-read invocation is interpreter work inside the copy loop.
|
||||
if onProgress != nil && contentLength > 0 &&
|
||||
(written-lastProgressNotify >= progressUpdateThreshold || written >= contentLength) {
|
||||
lastProgressNotify = written
|
||||
_, _ = onProgress(goja.Undefined(), r.vm.ToValue(written), r.vm.ToValue(contentLength))
|
||||
}
|
||||
}
|
||||
@@ -535,6 +540,7 @@ func (r *extensionRuntime) fileDownloadChunked(client *http.Client, urlStr, full
|
||||
}
|
||||
|
||||
var totalWritten int64
|
||||
var lastProgressNotify int64
|
||||
buf := make([]byte, 32*1024)
|
||||
maxRetries := 3
|
||||
|
||||
@@ -616,7 +622,9 @@ func (r *extensionRuntime) fileDownloadChunked(client *http.Client, urlStr, full
|
||||
return r.jsError("short write")
|
||||
}
|
||||
|
||||
if onProgress != nil && totalSize > 0 {
|
||||
if onProgress != nil && totalSize > 0 &&
|
||||
(totalWritten-lastProgressNotify >= progressUpdateThreshold || totalWritten >= totalSize) {
|
||||
lastProgressNotify = totalWritten
|
||||
_, _ = onProgress(goja.Undefined(), r.vm.ToValue(totalWritten), r.vm.ToValue(totalSize))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,9 +95,6 @@ func (r *extensionRuntime) signedSessionFilePath(config SignedSessionConfig) (st
|
||||
baseDir = r.dataDir
|
||||
}
|
||||
dir := filepath.Join(baseDir, "signed_sessions")
|
||||
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||
return "", err
|
||||
}
|
||||
scope := strings.Join([]string{
|
||||
namespace,
|
||||
strings.TrimSpace(strings.ToLower(config.BaseURL)),
|
||||
@@ -128,32 +125,41 @@ func (r *extensionRuntime) loadSignedSession(config SignedSessionConfig) (*signe
|
||||
if data, err := os.ReadFile(path); err == nil {
|
||||
_ = json.Unmarshal(data, record)
|
||||
}
|
||||
changed := false
|
||||
if strings.TrimSpace(record.InstallID) == "" {
|
||||
record.InstallID = randomHex(16)
|
||||
changed = true
|
||||
}
|
||||
normalizeSignedSessionRecordScope(config, record)
|
||||
if err := r.saveSignedSession(config, record); err != nil {
|
||||
return nil, err
|
||||
if normalizeSignedSessionRecordScope(config, record) {
|
||||
changed = true
|
||||
}
|
||||
// Only rewrite the file when the record actually changed; loads happen on
|
||||
// every signed request and preflight.
|
||||
if changed {
|
||||
if err := r.saveSignedSession(config, record); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return record, nil
|
||||
}
|
||||
|
||||
func normalizeSignedSessionRecordScope(config SignedSessionConfig, record *signedSessionRecord) {
|
||||
// normalizeSignedSessionRecordScope stamps the config scope onto the record,
|
||||
// resetting the session when the scope changed. Returns whether the record
|
||||
// was modified.
|
||||
func normalizeSignedSessionRecordScope(config SignedSessionConfig, record *signedSessionRecord) bool {
|
||||
namespace := sanitizeSignedSessionNamespace(config.Namespace)
|
||||
baseURL := strings.TrimSpace(config.BaseURL)
|
||||
appVersion := strings.TrimSpace(config.AppVersion)
|
||||
platform := strings.TrimSpace(config.Platform)
|
||||
if record.Namespace == "" && record.BaseURL == "" && record.AppVersion == "" && record.Platform == "" {
|
||||
record.Namespace = namespace
|
||||
record.BaseURL = baseURL
|
||||
record.AppVersion = appVersion
|
||||
record.Platform = platform
|
||||
return
|
||||
if record.Namespace == namespace &&
|
||||
record.BaseURL == baseURL &&
|
||||
record.AppVersion == appVersion &&
|
||||
record.Platform == platform {
|
||||
return false
|
||||
}
|
||||
if record.Namespace != namespace ||
|
||||
record.BaseURL != baseURL ||
|
||||
record.AppVersion != appVersion ||
|
||||
record.Platform != platform {
|
||||
blankScope := record.Namespace == "" && record.BaseURL == "" &&
|
||||
record.AppVersion == "" && record.Platform == ""
|
||||
if !blankScope {
|
||||
record.SessionID = ""
|
||||
record.SessionSecret = ""
|
||||
record.ExpiresAt = ""
|
||||
@@ -162,6 +168,7 @@ func normalizeSignedSessionRecordScope(config SignedSessionConfig, record *signe
|
||||
record.BaseURL = baseURL
|
||||
record.AppVersion = appVersion
|
||||
record.Platform = platform
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *extensionRuntime) saveSignedSession(config SignedSessionConfig, record *signedSessionRecord) error {
|
||||
@@ -169,6 +176,9 @@ func (r *extensionRuntime) saveSignedSession(config SignedSessionConfig, record
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.MarshalIndent(record, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -3,6 +3,7 @@ package gobackend
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -334,6 +335,11 @@ func SetItemFinalizing(itemID string) {
|
||||
}
|
||||
}
|
||||
|
||||
// maxRemovedProgressEntries bounds the removal tombstones a long batch session
|
||||
// can accumulate; pruning bumps multiProgressReset so lagging delta clients
|
||||
// fall back to a full resync instead of missing removals.
|
||||
const maxRemovedProgressEntries = 512
|
||||
|
||||
func RemoveItemProgress(itemID string) {
|
||||
multiMu.Lock()
|
||||
defer multiMu.Unlock()
|
||||
@@ -341,10 +347,30 @@ func RemoveItemProgress(itemID string) {
|
||||
if _, ok := multiProgress.Items[itemID]; ok {
|
||||
delete(multiProgress.Items, itemID)
|
||||
removedProgressSeq[itemID] = nextMultiProgressSeqLocked()
|
||||
if len(removedProgressSeq) > maxRemovedProgressEntries {
|
||||
pruneRemovedProgressLocked()
|
||||
}
|
||||
}
|
||||
markMultiProgressDirtyLocked()
|
||||
}
|
||||
|
||||
func pruneRemovedProgressLocked() {
|
||||
revisions := make([]int64, 0, len(removedProgressSeq))
|
||||
for _, revision := range removedProgressSeq {
|
||||
revisions = append(revisions, revision)
|
||||
}
|
||||
sort.Slice(revisions, func(i, j int) bool { return revisions[i] < revisions[j] })
|
||||
cutoff := revisions[len(revisions)/2]
|
||||
for id, revision := range removedProgressSeq {
|
||||
if revision <= cutoff {
|
||||
delete(removedProgressSeq, id)
|
||||
}
|
||||
}
|
||||
if cutoff > multiProgressReset {
|
||||
multiProgressReset = cutoff
|
||||
}
|
||||
}
|
||||
|
||||
func GetItemProgress(itemID string) string {
|
||||
multiMu.RLock()
|
||||
defer multiMu.RUnlock()
|
||||
|
||||
Reference in New Issue
Block a user