Make backend and frontend independent

This commit is contained in:
Xpl0itU 2023-08-29 20:55:43 +02:00
parent 08505c9eec
commit 99597834ce
8 changed files with 148 additions and 123 deletions

View file

@ -13,9 +13,6 @@ import (
"time"
"github.com/cavaliergopher/grab/v3"
"github.com/dustin/go-humanize"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
)
const (
@ -24,70 +21,14 @@ const (
bufferSize = 1048576
)
type ProgressWindow struct {
Window *gtk.Window
box *gtk.Box
gameLabel *gtk.Label
bar *gtk.ProgressBar
cancelButton *gtk.Button
cancelled bool
type ProgressReporter interface {
SetGameTitle(title string)
UpdateDownloadProgress(resp *grab.Response, filePath string)
UpdateDecryptionProgress(progress float64)
Cancelled() bool
}
func CreateProgressWindow(parent *gtk.ApplicationWindow) (ProgressWindow, error) {
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
if err != nil {
return ProgressWindow{}, err
}
win.SetTitle("WiiUDownloader - Downloading")
win.SetTransientFor(parent)
box, err := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
if err != nil {
return ProgressWindow{}, err
}
win.Add(box)
gameLabel, err := gtk.LabelNew("")
if err != nil {
return ProgressWindow{}, err
}
box.PackStart(gameLabel, false, false, 0)
progressBar, err := gtk.ProgressBarNew()
if err != nil {
return ProgressWindow{}, err
}
progressBar.SetShowText(true)
box.PackStart(progressBar, false, false, 0)
cancelButton, err := gtk.ButtonNewWithLabel("Cancel")
if err != nil {
return ProgressWindow{}, err
}
bottomhBox, err := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
if err != nil {
return ProgressWindow{}, err
}
bottomhBox.PackEnd(cancelButton, false, false, 0)
box.SetMarginBottom(5)
box.SetMarginEnd(5)
box.SetMarginStart(5)
box.SetMarginTop(5)
box.PackEnd(bottomhBox, false, false, 0)
return ProgressWindow{
Window: win,
box: box,
gameLabel: gameLabel,
bar: progressBar,
cancelButton: cancelButton,
cancelled: false,
}, nil
}
func downloadFile(progressWindow *ProgressWindow, client *grab.Client, downloadURL string, dstPath string, doRetries bool) error {
func downloadFile(progressWindow ProgressReporter, client *grab.Client, downloadURL string, dstPath string, doRetries bool) error {
filePath := filepath.Base(dstPath)
for attempt := 1; attempt <= maxRetries; attempt++ {
@ -98,7 +39,7 @@ func downloadFile(progressWindow *ProgressWindow, client *grab.Client, downloadU
req.BufferSize = bufferSize
resp := client.Do(req)
updateProgressWindow(progressWindow, resp, filePath)
progressWindow.UpdateDownloadProgress(resp, filePath)
t := time.NewTicker(500 * time.Millisecond)
defer t.Stop()
@ -107,13 +48,12 @@ func downloadFile(progressWindow *ProgressWindow, client *grab.Client, downloadU
for {
select {
case <-t.C:
updateProgressWindow(progressWindow, resp, filePath)
if progressWindow.cancelled {
progressWindow.UpdateDownloadProgress(resp, filePath)
if progressWindow.Cancelled() {
resp.Cancel()
break Loop
}
case <-resp.Done:
forceUpdateUI()
if err := resp.Err(); err != nil {
if doRetries && attempt < maxRetries {
time.Sleep(retryDelay)
@ -129,30 +69,11 @@ func downloadFile(progressWindow *ProgressWindow, client *grab.Client, downloadU
return nil
}
func forceUpdateUI() {
for gtk.EventsPending() {
gtk.MainIteration()
}
}
func updateProgressWindow(progressWindow *ProgressWindow, resp *grab.Response, filePath string) {
glib.IdleAdd(func() {
progressWindow.bar.SetFraction(resp.Progress())
progressWindow.bar.SetText(fmt.Sprintf("Downloading %s (%s/%s) (%s/s)", filePath, humanize.Bytes(uint64(resp.BytesComplete())), humanize.Bytes(uint64(resp.Size())), humanize.Bytes(uint64(resp.BytesPerSecond()))))
})
forceUpdateUI()
}
func DownloadTitle(titleID string, outputDirectory string, doDecryption bool, progressWindow *ProgressWindow, deleteEncryptedContents bool, logger *Logger) error {
progressWindow.cancelButton.Connect("clicked", func() {
progressWindow.cancelled = true
})
func DownloadTitle(titleID string, outputDirectory string, doDecryption bool, progressReporter ProgressReporter, deleteEncryptedContents bool, logger *Logger) error {
titleEntry := getTitleEntryFromTid(titleID)
glib.IdleAdd(func() {
progressWindow.gameLabel.SetText(titleEntry.Name)
})
progressReporter.SetGameTitle(titleEntry.Name)
outputDir := strings.TrimRight(outputDirectory, "/\\")
baseURL := fmt.Sprintf("http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/%s", titleID)
titleIDBytes, err := hex.DecodeString(titleID)
@ -167,7 +88,7 @@ func DownloadTitle(titleID string, outputDirectory string, doDecryption bool, pr
client := grab.NewClient()
client.BufferSize = bufferSize
tmdPath := filepath.Join(outputDir, "title.tmd")
if err := downloadFile(progressWindow, client, fmt.Sprintf("%s/%s", baseURL, "tmd"), tmdPath, true); err != nil {
if err := downloadFile(progressReporter, client, fmt.Sprintf("%s/%s", baseURL, "tmd"), tmdPath, true); err != nil {
return err
}
@ -182,7 +103,7 @@ func DownloadTitle(titleID string, outputDirectory string, doDecryption bool, pr
}
tikPath := filepath.Join(outputDir, "title.tik")
if err := downloadFile(progressWindow, client, fmt.Sprintf("%s/%s", baseURL, "cetk"), tikPath, false); err != nil {
if err := downloadFile(progressReporter, client, fmt.Sprintf("%s/%s", baseURL, "cetk"), tikPath, false); err != nil {
titleKey, err := GenerateKey(titleID)
if err != nil {
return err
@ -202,7 +123,7 @@ func DownloadTitle(titleID string, outputDirectory string, doDecryption bool, pr
return err
}
cert, err := GenerateCert(tmdData, contentCount, progressWindow, client)
cert, err := GenerateCert(tmdData, contentCount, progressReporter, client)
if err != nil {
return err
}
@ -243,13 +164,13 @@ func DownloadTitle(titleID string, outputDirectory string, doDecryption bool, pr
return err
}
filePath := filepath.Join(outputDir, fmt.Sprintf("%08X.app", id))
if err := downloadFile(progressWindow, client, fmt.Sprintf("%s/%08X", baseURL, id), filePath, true); err != nil {
if err := downloadFile(progressReporter, client, fmt.Sprintf("%s/%08X", baseURL, id), filePath, true); err != nil {
return err
}
if tmdData[offset+7]&0x2 == 2 {
filePath = filepath.Join(outputDir, fmt.Sprintf("%08X.h3", id))
if err := downloadFile(progressWindow, client, fmt.Sprintf("%s/%08X.h3", baseURL, id), filePath, true); err != nil {
if err := downloadFile(progressReporter, client, fmt.Sprintf("%s/%08X.h3", baseURL, id), filePath, true); err != nil {
return err
}
content.Hash = tmdData[offset+16 : offset+0x14]
@ -259,19 +180,19 @@ func DownloadTitle(titleID string, outputDirectory string, doDecryption bool, pr
return err
}
if err := checkContentHashes(outputDirectory, content, &cipherHashTree); err != nil {
if progressWindow.cancelled {
if progressReporter.Cancelled() {
break
}
return err
}
}
if progressWindow.cancelled {
if progressReporter.Cancelled() {
break
}
}
if doDecryption && !progressWindow.cancelled {
if err := DecryptContents(outputDir, progressWindow, deleteEncryptedContents); err != nil {
if doDecryption && !progressReporter.Cancelled() {
if err := DecryptContents(outputDir, progressReporter, deleteEncryptedContents); err != nil {
return err
}
}