package main import ( "bytes" "context" "encoding/json" "fmt" "io" "log" "os" "os/exec" "path/filepath" "runtime" "github.com/inconshreveable/go-update" wruntime "github.com/wailsapp/wails/v2/pkg/runtime" ) const client_id string = "9305aeb8-5ecb-4e7a-b28f-c33aefcfbd8d" const client_version string = "0.0.2" type LauncherMetadata struct { Schema_Version string Version string Desc string Downloads map[string]string } // App struct type App struct { Ctx context.Context PrismLauncher Prism Java JavaManager Instance InstanceManager Modpacks ModpackManager Auth authenticationResp } // NewApp creates a new App application struct func NewApp() *App { a := &App{} a.Java = JavaManager{app: a} a.Instance = InstanceManager{app: a} a.Modpacks = ModpackManager{app: a} return a } // startup is called when the app starts. The context is saved // so we can call the runtime methods func (a *App) startup(ctx context.Context) { a.Ctx = ctx } // Greet returns a greeting for the given name func openbrowser(url string) { var err error switch runtime.GOOS { case "linux": err = exec.Command("xdg-open", url).Start() case "windows": err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() case "darwin": err = exec.Command("open", url).Start() default: err = fmt.Errorf("unsupported platform") } if err != nil { log.Fatal(err) } } func (a *App) CheckPrerequisites() { buff := new(bytes.Buffer) err := HttpDownload("launcher.json", buff, nil) fmt.Printf("Starting\n") if err == nil { data, _ := io.ReadAll(buff) meta := LauncherMetadata{} json.Unmarshal(data, &meta) if client_version != meta.Version { //Update available! val, _ := wruntime.MessageDialog(a.Ctx, wruntime.MessageDialogOptions{Type: wruntime.QuestionDialog, Title: "Update!", Message: fmt.Sprintf("There is an update available:\n\n%s -> %s\n\nUpdate Description:\n\n%s\n\nWould you like to update?\n", client_version, meta.Version, meta.Desc)}) if val == "Yes" { //run the update fmt.Printf("Updating\n") buff := new(bytes.Buffer) HttpDownload(meta.Downloads[runtime.GOOS], buff, nil) executable, _ := os.Executable() err := update.Apply(buff, update.Options{}) if err != nil { fmt.Printf("Error!") } child := exec.Command(executable) err = child.Start() if err != nil { fmt.Printf("Unable to launch: %s\n", err) } wruntime.Quit(a.Ctx) } } } a.Status("Querrying Existing Instances") a.Instance.SearchInstances() a.Status("Pulling Modpacks") a.Modpacks.QuerryModpacks() a.Status("Logging in with Microsoft") dir, _ := os.UserConfigDir() authenticated := false if _, err := os.Stat(filepath.Join(dir, "FCLauncher", "authentication.json")); err == nil { f, _ := os.OpenFile(filepath.Join(dir, "FCLauncher", "authentication.json"), os.O_RDONLY, 0755) defer f.Close() data, _ := io.ReadAll(f) json.Unmarshal(data, &a.Auth) a.Auth, err = TokenRefresh(*a, a.Auth) if err == nil { authenticated = true } else { fmt.Printf("token reauth failed, requesting device code: %s\n", err) } } if !authenticated { var err error a.Auth, err = AuthCode(*a) if err != nil { fmt.Printf("Authentication Error: %s\n", err) return } } err = os.Remove(filepath.Join(dir, "FCLauncher", "authentication.json")) if err != nil { fmt.Printf("Unable to delete auth file\n") } os.MkdirAll(filepath.Join(dir, "FCLauncher"), 0755) f, _ := os.OpenFile(filepath.Join(dir, "FCLauncher", "authentication.json"), os.O_CREATE|os.O_RDWR, 0755) defer f.Close() data, _ := json.Marshal(a.Auth) f.Write(data) } func (App) GetVersions() ([]string, error) { manifest, err := GetVersionManifest() if err != nil { fmt.Printf("Manifest Error: %s\n", err) return []string{}, err } versions := []string{} for _, version := range manifest.Versions { versions = append(versions, version.Id) } return versions, nil } func (a *App) Status(status string) { fmt.Printf("LOG: %s\n", status) wruntime.EventsEmit(a.Ctx, "status", status) }