From 938e8e31953deff1f90f240567e25235cbb248fe Mon Sep 17 00:00:00 2001 From: Trit0 Date: Sun, 29 Jun 2025 18:20:53 -0400 Subject: [PATCH] start game perchance? --- app.go | 46 +++++--- frontend/src/stores/app-store.ts | 9 ++ .../key-contexts/carousel-key-context.ts | 1 + frontend/wailsjs/go/main/App.d.ts | 4 +- frontend/wailsjs/go/main/App.js | 8 +- lib/provider/provider.go | 100 ++++++++++++++++++ 6 files changed, 147 insertions(+), 21 deletions(-) diff --git a/app.go b/app.go index 79c976f..337f1c2 100644 --- a/app.go +++ b/app.go @@ -1,16 +1,17 @@ package main import ( + "conjure-os/lib/inputs" "conjure-os/lib/models" + "conjure-os/lib/provider" "context" "fmt" - - "conjure-os/lib/inputs" - "conjure-os/lib/provider" - - "github.com/wailsapp/wails/v2/pkg/runtime" + "os" + "os/exec" ) +var games []models.Game + // App struct type App struct { ctx context.Context @@ -29,15 +30,36 @@ func (a *App) startup(ctx context.Context) { provider.Update() } -// Greet returns a greeting for the given name -func (a *App) Greet(name string) string { - runtime.LogInfo(a.ctx, "Test : "+name) - return fmt.Sprintf("Hello %s, It's show time!", name) -} +func (a *App) StartGame(id string) { + for _, game := range games { + if game.Id == id { + gamePath := provider.ExtractGame(game) + cmd := exec.Command(gamePath) -func (a *App) SelectGame(id string) { + // Optional: attach current terminal's std streams + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + + // Start the process + if err := cmd.Start(); err != nil { + fmt.Println("Failed to start:", err) + return + } + + fmt.Printf("Process started with PID %d\n", cmd.Process.Pid) + + // Optional: wait for it to finish + if err := cmd.Wait(); err != nil { + fmt.Println("Process exited with error:", err) + } else { + fmt.Println("Process exited successfully.") + } + } + } } func (a *App) LoadGames() []models.Game { - return provider.GetConjureGameInfo() + games = provider.GetConjureGameInfo() + return games } diff --git a/frontend/src/stores/app-store.ts b/frontend/src/stores/app-store.ts index b3c456d..18715bc 100644 --- a/frontend/src/stores/app-store.ts +++ b/frontend/src/stores/app-store.ts @@ -1,6 +1,7 @@ import { defineStore } from 'pinia'; import {models} from "../../wailsjs/go/models"; import Game = models.Game; +import { StartGame } from "../../wailsjs/go/main/App"; export const useAppStore = defineStore('app', { state: () => ({ @@ -48,6 +49,14 @@ export const useAppStore = defineStore('app', { }, showQr(link: string) { this.qrLink = link; + }, + startSelectedGame() { + if (this.selectedGame) { + StartGame(this.selectedGame.Id).then() + } + else { + console.log("No game selected") + } } } }); \ No newline at end of file diff --git a/frontend/src/utils/key-contexts/carousel-key-context.ts b/frontend/src/utils/key-contexts/carousel-key-context.ts index c0300ca..ef60030 100644 --- a/frontend/src/utils/key-contexts/carousel-key-context.ts +++ b/frontend/src/utils/key-contexts/carousel-key-context.ts @@ -35,5 +35,6 @@ export class CarouselKeyContext extends KeyContext { protected onEnter() { super.onEnter(); + this.store.startSelectedGame(); } } \ No newline at end of file diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts index 8cf3cd6..6deff79 100755 --- a/frontend/wailsjs/go/main/App.d.ts +++ b/frontend/wailsjs/go/main/App.d.ts @@ -2,8 +2,6 @@ // This file is automatically generated. DO NOT EDIT import {models} from '../models'; -export function Greet(arg1:string):Promise; - export function LoadGames():Promise>; -export function SelectGame(arg1:string):Promise; +export function StartGame(arg1:string):Promise; diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js index 813f75e..76e728c 100755 --- a/frontend/wailsjs/go/main/App.js +++ b/frontend/wailsjs/go/main/App.js @@ -2,14 +2,10 @@ // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT -export function Greet(arg1) { - return window['go']['main']['App']['Greet'](arg1); -} - export function LoadGames() { return window['go']['main']['App']['LoadGames'](); } -export function SelectGame(arg1) { - return window['go']['main']['App']['SelectGame'](arg1); +export function StartGame(arg1) { + return window['go']['main']['App']['StartGame'](arg1); } diff --git a/lib/provider/provider.go b/lib/provider/provider.go index 782ba4d..b7036da 100644 --- a/lib/provider/provider.go +++ b/lib/provider/provider.go @@ -70,6 +70,106 @@ func GetOrSetEnvKey(key string, defaultValue string) string { return defaultValue } +func extractZipToSiblingFolder(zipPath string) error { + // Determine destination folder name (same name as zip file, without .zip) + zipBase := strings.TrimSuffix(filepath.Base(zipPath), ".conj") + destDir := filepath.Join(filepath.Dir(zipPath), zipBase) + + // Delete destination folder if it exists + if _, err := os.Stat(destDir); err == nil { + err = os.RemoveAll(destDir) + if err != nil { + return fmt.Errorf("failed to remove existing folder: %v", err) + } + } + + // Open the zip archive + r, err := zip.OpenReader(zipPath) + if err != nil { + return err + } + defer r.Close() + + // Create the destination directory + err = os.MkdirAll(destDir, os.ModePerm) + if err != nil { + return err + } + + for _, f := range r.File { + destPath := filepath.Join(destDir, f.Name) + + // ZipSlip protection + if !strings.HasPrefix(destPath, filepath.Clean(destDir)+string(os.PathSeparator)) { + return fmt.Errorf("illegal file path: %s", destPath) + } + + if f.FileInfo().IsDir() { + if err := os.MkdirAll(destPath, os.ModePerm); err != nil { + return err + } + continue + } + + // Ensure parent directories exist + if err := os.MkdirAll(filepath.Dir(destPath), os.ModePerm); err != nil { + return err + } + + // Create and copy the file + srcFile, err := f.Open() + if err != nil { + return err + } + defer srcFile.Close() + + dstFile, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return err + } + defer dstFile.Close() + + if _, err := io.Copy(dstFile, srcFile); err != nil { + return err + } + } + + return nil +} + +func extractZipsInFolder(folder string) error { + entries, err := os.ReadDir(folder) + if err != nil { + return fmt.Errorf("reading directory failed: %w", err) + } + + for _, entry := range entries { + if entry.IsDir() { + continue + } + if strings.HasSuffix(strings.ToLower(entry.Name()), ".conj") { + zipPath := filepath.Join(folder, entry.Name()) + fmt.Println("Extracting:", zipPath) + if err := extractZipToSiblingFolder(zipPath); err != nil { + return fmt.Errorf("failed to extract %s: %w", zipPath, err) + } + } + } + + return nil +} + +func ExtractGame(game models.Game) string { + gamePath := filepath.Join(config.GetDefaultConjureGamesDirectory(), fmt.Sprintf("%s.conj", game.Id)) + err := extractZipToSiblingFolder(gamePath) + check(err) + gamePath = filepath.Join(config.GetDefaultConjureGamesDirectory(), game.Id) + err = extractZipsInFolder(gamePath) + check(err) + gamePath = filepath.Join(gamePath, game.Files) + return gamePath +} + func GetConjureGameInfo() []models.Game { gamePath := config.GetDefaultConjureGamesDirectory()