Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions app.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"fmt"
"os"
"os/exec"
Expand All @@ -12,6 +13,7 @@ import (
rlbot "github.com/RLBot/go-interface"
"github.com/RLBot/go-interface/flat"
"github.com/ncruces/zenity"
"github.com/wailsapp/wails/v3/pkg/application"
)

type RawReleaseInfo struct {
Expand All @@ -21,6 +23,7 @@ type RawReleaseInfo struct {

// App struct
type App struct {
app *application.App
latestReleaseJson []RawReleaseInfo
rlbotAddress string
}
Expand Down Expand Up @@ -70,18 +73,24 @@ func (a *App) DownloadBotpack(repo string, installPath string) (string, error) {
}
}

err = DownloadExtractArchive(downloadUrl, installPath)
if downloadUrl == "" {
return "", fmt.Errorf("Failed to find %s in latest release for %s", fileName, repo)
}

err = DownloadExtractArchive(a.app.Event, downloadUrl, installPath)
if err != nil {
return "", err
}

return latestRelease.TagName, nil
}

func (a *App) RepairBotpack(repo string, installPath string) (string, error) {
err := os.RemoveAll(installPath)
if err != nil {
return "", err
func (a *App) RepairBotpack(repo string, installPath string, clearInstallPath bool) (string, error) {
if clearInstallPath {
err := os.RemoveAll(installPath)
if err != nil {
return "", err
}
}

return a.DownloadBotpack(repo, installPath)
Expand All @@ -103,11 +112,19 @@ func NewApp() *App {

var latest_release_json []RawReleaseInfo
return &App{
nil,
latest_release_json,
rlbot_address,
}
}

func (a *App) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
// You can access the application instance via ctx
a.app = application.Get()

return nil
}

func recursiveTomlSearch(root, tomlType string) ([]string, error) {
var matches []string
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
Expand Down
199 changes: 158 additions & 41 deletions frontend/src/components/PathsViewer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import closeIcon from "../assets/close.svg";
import repairIcon from "../assets/repair.svg";
import Modal from "./Modal.svelte";
import Switch from "./Switch.svelte";
import ProgressBar from "./ProgressBar.svelte";
import { Events } from "@wailsio/runtime";

const OFFICIAL_BOTPACK_REPO = "VirxEC/botpack-test";
const OFFICIAL_BOTPACK_REPOS = [
"VirxEC/botpack-test",
"VirxEC/pytorch-archive",
];

let {
visible = $bindable(false),
Expand All @@ -18,6 +23,7 @@ let {
repo: string | null;
installPath: string;
visible: boolean;
isDependency: boolean;
}[];
} = $props();

Expand All @@ -34,24 +40,74 @@ async function setDefaultPath() {
setDefaultPath();

function removePath(index: number) {
paths.splice(index, 1);
const [removedItem] = paths.splice(index, 1);

const dependency = paths.findIndex(
(item) => item.installPath === removedItem.installPath,
);
if (dependency !== -1) removePath(dependency);
}

function repairBotpack(index: number) {
const id = toast.loading("Re-downloading botpack...");
let downloadModalTitle = $state("Downloading & extracting repo/owner");
let downloadModalVisible = $state(false);
let downloadProgress = $state(0);
let downloadCurrentStep = $state(0);
let downloadTotalSteps = $state(0);

// @ts-ignore
App.RepairBotpack(paths[index].repo, paths[index].installPath)
.then((tagName) => {
paths[index].tagName = tagName;
toast.success("Botpack download successfully!", { id });
})
.catch((err) => {
Events.On("monitor:download-progress", (event) => {
const { status, done } = event.data.at(-1);

if (done) {
downloadProgress = 0;
downloadCurrentStep += 1;
} else {
downloadProgress = status;
}
});

async function repairBotpack(index: number) {
const info = paths[index];
if (!info.repo) {
return; // can't update something that doesn't have a repo
}

downloadProgress = 0;
downloadCurrentStep = 0;
downloadTotalSteps = 0;

for (const item of paths) {
if (!item.repo || item.installPath !== info.installPath) continue;
downloadTotalSteps += 2;
}

let clearInstallPath = true;
for (const item of paths) {
if (!item.repo || item.installPath !== info.installPath) continue;

downloadModalTitle = `Redownloading & extracting ${item.repo}`;
visible = false;
downloadModalVisible = true;

let tagName = await App.RepairBotpack(
item.repo,
item.installPath,
clearInstallPath,
).catch((err) => {
toast.error(`Failed to download botpack: ${err}`, {
duration: 10000,
id,
});

return null;
});
if (!tagName) break;

clearInstallPath = false;
downloadProgress = 0;
downloadCurrentStep += 1;
}

downloadModalVisible = false;
visible = true;
}

function openAddBotpackModal() {
Expand All @@ -60,6 +116,7 @@ function openAddBotpackModal() {
}

function closeAddBotpackModal() {
downloadModalVisible = false;
addBotpackVisible = false;
visible = true;
selectedBotpackType = "official";
Expand All @@ -78,6 +135,7 @@ function addInstallPath(installPath: string) {
visible: true,
tagName: null,
repo: null,
isDependency: false,
});
}

Expand All @@ -100,20 +158,21 @@ function addFile() {

addInstallPath(result);
})
.catch((error) => {
.catch((_) => {
toast.error(
"Failed to add file: Only bot.toml or script.toml files are allowed",
);
});
}

function confirmAddBotpack() {
async function confirmAddBotpack() {
if (!installPath) {
toast.error("Install path cannot be blank");
return;
}

let repo = OFFICIAL_BOTPACK_REPO;
let repo: string, dep: string | null;

if (selectedBotpackType === "custom") {
if (!customRepo) {
toast.error("URL cannot be blank");
Expand All @@ -126,32 +185,80 @@ function confirmAddBotpack() {
}

repo = customRepo;
dep = null;
} else {
[repo, dep] = OFFICIAL_BOTPACK_REPOS;
}

if (paths.some((x) => x.installPath === installPath)) {
toast.error(`Install path "${installPath}" already in use for ${repo}`);
return;
}

if (paths.some((x) => x.repo === repo)) {
toast.error("Botpack already added");
toast.error(`Botpack ${repo} already added`);
return;
}

if (paths.some((x) => x.installPath === installPath)) {
toast.error("Install path already in use");
downloadModalTitle = `Downloading & extracting ${repo}`;
downloadProgress = 0;
addBotpackVisible = false;
downloadModalVisible = true;
downloadCurrentStep = 0;
downloadTotalSteps = dep ? 4 : 2;

const tagName = await App.DownloadBotpack(repo, installPath).catch((err) => {
toast.error(`Failed to download botpack: ${err}`, {
duration: 10000,
});

return null;
});
if (!tagName) {
downloadModalVisible = false;
addBotpackVisible = true;
return;
}

const id = toast.loading("Downloading botpack...");
App.DownloadBotpack(repo, installPath)
.then((tagName) => {
toast.success("Botpack downloaded successfully!", { id });
if (dep) {
downloadModalTitle = `Downloading & extracting ${dep}`;
downloadProgress = 0;
downloadCurrentStep += 1;

paths.push({ installPath, repo, tagName, visible: true });
closeAddBotpackModal();
})
.catch((err) => {
toast.error(`Failed to download botpack: ${err}`, {
// Download possible dependency of the given botpack
const tagName = await App.DownloadBotpack(dep, installPath).catch((err) => {
toast.error(`Failed to download botpack dependency: ${err}`, {
duration: 10000,
id,
});

return null;
});
if (!tagName) {
downloadModalVisible = false;
addBotpackVisible = true;
return;
}
}

paths.push({
installPath,
repo,
tagName,
visible: true,
isDependency: false,
});
if (dep) {
paths.push({
installPath,
repo: dep,
tagName,
visible: false,
isDependency: true,
});
}

toast.success("Botpack downloaded successfully!");
closeAddBotpackModal();
}
</script>

Expand All @@ -164,20 +271,26 @@ function confirmAddBotpack() {
</div>

{#each paths as path, i}
<div class="path">
<pre>{path.repo ? `${path.repo} @ ${path.installPath}` : path.installPath}</pre>
{#if path.repo}
<button class="no-left-margin repair" onclick={() => repairBotpack(i)}>
<img src={repairIcon} alt="repair" />
{#if path.isDependency}
<div class="path" style="margin-left: 50px;">
<pre>{path.repo}</pre>
</div>
{:else}
<div class="path">
<pre>{path.repo ? `${path.repo} @ ${path.installPath}` : path.installPath}</pre>
{#if path.repo}
<button class="no-left-margin repair" onclick={() => repairBotpack(i)}>
<img src={repairIcon} alt="repair" />
</button>
<div><Switch bind:checked={path.visible} /></div>
{:else}
<div class="no-left-margin"><Switch bind:checked={path.visible} /></div>
{/if}
<button class="close" onclick={() => removePath(i)}>
<img src={closeIcon} alt="X" />
</button>
<div><Switch bind:checked={path.visible} /></div>
{:else}
<div class="no-left-margin"><Switch bind:checked={path.visible} /></div>
{/if}
<button class="close" onclick={() => removePath(i)}>
<img src={closeIcon} alt="X" />
</button>
</div>
</div>
{/if}
{/each}
</div>
</Modal>
Expand Down Expand Up @@ -206,6 +319,10 @@ function confirmAddBotpack() {
</div>
</Modal>

<Modal title={downloadModalTitle} bind:visible={downloadModalVisible} closeable={false}>
<ProgressBar percentComplete={downloadProgress} currentStep={downloadCurrentStep} totalSteps={downloadTotalSteps} />
</Modal>

<style>
.paths {
display: flex;
Expand Down
Loading