2024-10-24 13:31:01 -06:00
package main
import (
2024-11-26 20:54:30 -07:00
"bytes"
2024-10-24 13:31:01 -06:00
"context"
2024-10-30 16:41:03 -06:00
"encoding/json"
2024-10-24 13:31:01 -06:00
"fmt"
2024-10-30 16:41:03 -06:00
"io"
2024-11-26 11:50:33 -07:00
"log"
2024-10-30 16:41:03 -06:00
"os"
2024-11-26 11:50:33 -07:00
"os/exec"
2024-10-30 16:41:03 -06:00
"path/filepath"
2024-11-26 11:50:33 -07:00
"runtime"
2024-10-24 19:48:19 -06:00
2024-11-26 20:54:30 -07:00
"github.com/inconshreveable/go-update"
2024-11-26 11:50:33 -07:00
wruntime "github.com/wailsapp/wails/v2/pkg/runtime"
2024-10-24 13:31:01 -06:00
)
2024-10-30 15:39:11 -06:00
const client_id string = "9305aeb8-5ecb-4e7a-b28f-c33aefcfbd8d"
2024-11-26 21:42:06 -07:00
const client_version string = "0.0.3"
2024-11-26 20:54:30 -07:00
type LauncherMetadata struct {
Schema_Version string
Version string
Desc string
Downloads map [ string ] string
}
2024-10-30 15:39:11 -06:00
2024-10-24 13:31:01 -06:00
// App struct
type App struct {
2024-10-31 21:20:20 -06:00
Ctx context . Context
2024-10-26 14:00:53 -06:00
PrismLauncher Prism
2024-10-31 21:20:20 -06:00
Java JavaManager
Instance InstanceManager
Modpacks ModpackManager
Auth authenticationResp
2024-10-24 13:31:01 -06:00
}
// NewApp creates a new App application struct
func NewApp ( ) * App {
2024-10-26 14:00:53 -06:00
a := & App { }
a . Java = JavaManager { app : a }
a . Instance = InstanceManager { app : a }
a . Modpacks = ModpackManager { app : a }
return a
2024-10-24 13:31:01 -06:00
}
// 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 ) {
2024-10-26 14:00:53 -06:00
a . Ctx = ctx
2024-10-24 13:31:01 -06:00
}
// Greet returns a greeting for the given name
2024-11-26 11:50:33 -07:00
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 )
}
}
2024-10-24 15:46:17 -06:00
func ( a * App ) CheckPrerequisites ( ) {
2024-11-26 20:54:30 -07:00
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 )
}
}
}
2024-10-26 14:00:53 -06:00
a . Status ( "Querrying Existing Instances" )
a . Instance . SearchInstances ( )
a . Status ( "Pulling Modpacks" )
a . Modpacks . QuerryModpacks ( )
2024-10-30 17:16:10 -06:00
a . Status ( "Logging in with Microsoft" )
2024-10-31 21:20:20 -06:00
dir , _ := os . UserConfigDir ( )
2024-10-30 16:41:03 -06:00
authenticated := false
2024-10-31 21:20:20 -06:00
if _ , err := os . Stat ( filepath . Join ( dir , "FCLauncher" , "authentication.json" ) ) ; err == nil {
2024-10-30 16:41:03 -06:00
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
2024-11-01 08:05:12 -06:00
} else {
fmt . Printf ( "token reauth failed, requesting device code: %s\n" , err )
2024-10-30 16:41:03 -06:00
}
}
if ! authenticated {
var err error
a . Auth , err = AuthCode ( * a )
if err != nil {
fmt . Printf ( "Authentication Error: %s\n" , err )
return
}
}
2024-11-26 20:54:30 -07:00
err = os . Remove ( filepath . Join ( dir , "FCLauncher" , "authentication.json" ) )
if err != nil {
fmt . Printf ( "Unable to delete auth file\n" )
}
2024-10-30 16:41:03 -06:00
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 )
2024-10-29 21:48:59 -06:00
}
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
2024-10-24 15:46:17 -06:00
}
2024-10-24 19:48:19 -06:00
2024-10-26 14:00:53 -06:00
func ( a * App ) Status ( status string ) {
2024-10-24 19:48:19 -06:00
fmt . Printf ( "LOG: %s\n" , status )
2024-11-26 11:50:33 -07:00
wruntime . EventsEmit ( a . Ctx , "status" , status )
2024-10-24 19:48:19 -06:00
}