Fix issues with account swutching

This commit is contained in:
Mukhtar Akere
2025-08-26 15:31:24 +01:00
parent eefe8a3901
commit 267cc2d32b
13 changed files with 149 additions and 115 deletions

View File

@@ -1,7 +1,9 @@
package types
import (
"fmt"
"github.com/sirrobot01/decypharr/internal/config"
"github.com/sirrobot01/decypharr/internal/utils"
"slices"
"sync"
"sync/atomic"
@@ -37,6 +39,7 @@ type Account struct {
Disabled bool
InUse bool
Token string `json:"token"`
MaskedToken string `json:"masked_token"`
links map[string]*DownloadLink
mu sync.RWMutex
TrafficUsed int64 `json:"traffic_used"` // Traffic used in bytes
@@ -95,13 +98,12 @@ func (a *Accounts) Current() *Account {
return current
}
current = activeAccounts[0]
a.setCurrent(current)
return current
return a.setCurrent(current)
}
func (a *Accounts) setCurrent(account *Account) {
func (a *Accounts) setCurrent(account *Account) *Account {
if account == nil {
return
return nil
}
// Set every account InUse to false
a.accounts.Range(func(key, value interface{}) bool {
@@ -114,25 +116,24 @@ func (a *Accounts) setCurrent(account *Account) {
})
account.InUse = true
a.current.Store(account)
return account
}
func (a *Accounts) Disable(account *Account) {
account.Disabled = true
account.InUse = false
a.accounts.Store(account.Token, account)
current := a.getCurrent()
if current.Equals(account) {
var newCurrent *Account
a.accounts.Range(func(key, value interface{}) bool {
acc, ok := value.(*Account)
if ok && !acc.Disabled {
newCurrent = acc
return false // Break the loop
}
return true // Continue the loop
})
activeAccounts := a.Active()
if len(activeAccounts) > 0 {
newCurrent = activeAccounts[0]
} else {
newCurrent = a.All()[0]
}
a.setCurrent(newCurrent)
}
}
@@ -155,19 +156,20 @@ func (a *Accounts) Reset() {
a.setCurrent(current)
}
func (a *Accounts) GetDownloadLink(fileLink string) (*DownloadLink, *Account, error) {
func (a *Accounts) GetDownloadLink(fileLink string) (*DownloadLink, error) {
current := a.Current()
if current == nil {
return nil, nil, NoActiveAccountsError
return nil, NoActiveAccountsError
}
dl, ok := current.getLink(fileLink)
dl, ok := current.GetDownloadLink(fileLink)
if !ok {
return nil, current, NoDownloadLinkError
return nil, NoDownloadLinkError
}
if err := dl.Valid(); err != nil {
return nil, current, err
if !dl.Valid() {
return nil, fmt.Errorf("invalid download link: %s", dl.Link)
}
return dl, current, nil
dl.Token = current.Token
return dl, nil
}
func (a *Accounts) GetAccountFromLink(fileLink string) (*Account, error) {
@@ -175,7 +177,7 @@ func (a *Accounts) GetAccountFromLink(fileLink string) (*Account, error) {
if currentAccount == nil {
return nil, NoActiveAccountsError
}
dl, ok := currentAccount.getLink(fileLink)
dl, ok := currentAccount.GetDownloadLink(fileLink)
if !ok {
return nil, NoDownloadLinkError
}
@@ -186,13 +188,22 @@ func (a *Accounts) GetAccountFromLink(fileLink string) (*Account, error) {
}
// SetDownloadLink sets the download link for the current account
func (a *Accounts) SetDownloadLink(account *Account, dl *DownloadLink) {
func (a *Accounts) SetDownloadLink(dl *DownloadLink) {
if dl == nil {
return
}
var account *Account
// Get account from link token
if dl.Token != "" {
if acc, ok := a.accounts.Load(dl.Token); ok {
account = acc.(*Account)
}
}
if account == nil {
account = a.getCurrent()
}
account.setLink(dl.Link, dl)
}
@@ -210,12 +221,11 @@ func (a *Accounts) GetLinksCount() int {
return a.Current().LinksCount()
}
func (a *Accounts) SetDownloadLinks(account *Account, links map[string]*DownloadLink) {
if account == nil {
account = a.Current()
func (a *Accounts) SetDownloadLinks(links map[string]*DownloadLink) {
if a.Current() == nil {
return
}
account.setLinks(links)
a.accounts.Store(account.Token, account)
a.Current().setLinks(links)
}
func (a *Accounts) Update(account *Account) {
@@ -227,10 +237,11 @@ func (a *Accounts) Update(account *Account) {
func newAccount(debridName, token string, index int) *Account {
return &Account{
Debrid: debridName,
Token: token,
Order: index,
links: make(map[string]*DownloadLink),
Debrid: debridName,
Token: token,
MaskedToken: utils.Mask(token),
Order: index,
links: make(map[string]*DownloadLink),
}
}
@@ -241,7 +252,7 @@ func (a *Account) Equals(other *Account) bool {
return a.Token == other.Token && a.Debrid == other.Debrid
}
func (a *Account) getLink(fileLink string) (*DownloadLink, bool) {
func (a *Account) GetDownloadLink(fileLink string) (*DownloadLink, bool) {
a.mu.RLock()
defer a.mu.RUnlock()
dl, ok := a.links[a.sliceFileLink(fileLink)]
@@ -273,7 +284,7 @@ func (a *Account) setLinks(links map[string]*DownloadLink) {
a.mu.Lock()
defer a.mu.Unlock()
for _, dl := range links {
if err := dl.Valid(); err != nil {
if !dl.Valid() {
continue
}
a.links[a.sliceFileLink(dl.Link)] = dl

View File

@@ -8,7 +8,7 @@ type Client interface {
SubmitMagnet(tr *Torrent) (*Torrent, error)
CheckStatus(tr *Torrent) (*Torrent, error)
GetFileDownloadLinks(tr *Torrent) error
GetDownloadLink(tr *Torrent, file *File) (*DownloadLink, *Account, error)
GetDownloadLink(tr *Torrent, file *File) (*DownloadLink, error)
DeleteTorrent(torrentId string) error
IsAvailable(infohashes []string) map[string]bool
GetDownloadUncached() bool

View File

@@ -176,17 +176,19 @@ type DownloadLink struct {
Generated time.Time `json:"generated"`
Size int64 `json:"size"`
Id string `json:"id"`
ExpiresAt time.Time
ExpiresAt time.Time `json:"expires_at"`
MaskedToken string `json:"masked_token"`
Token string `json:"token"` // The token or api key used to generate this link
}
func (dl *DownloadLink) Valid() error {
func (dl *DownloadLink) Valid() bool {
if dl.DownloadLink == "" {
return EmptyDownloadLinkError
return false
}
if dl.ExpiresAt.IsZero() || dl.ExpiresAt.Before(time.Now()) {
return DownloadLinkExpiredError
return false
}
return nil
return true
}
func (dl *DownloadLink) String() string {