Skip to content

Commit

Permalink
✨ feat: Add viper config and basic arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
wanjohiryan committed Jul 8, 2024
1 parent a0303bb commit 08597ce
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 233 deletions.
11 changes: 11 additions & 0 deletions .nestri.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: "0.1"

games:
CyberPunk2047:
directory: /path/to/game
executable: CyberPunk2047.exe
gpu: 1
vendor: GPUidhere #(ex: vendor:N) e.g. nvidia:0 or amd:1
resolution:
height: 1080
width: 1920
43 changes: 42 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ package cmd

import (
_ "embed"
"fmt"
"os"

"github.com/spf13/cobra"
"github.com/spf13/viper"
)

//go:embed nestri.ascii
var art string

var cfgFile string

type GameConfig struct {
Directory string
Executable string
Expand Down Expand Up @@ -44,12 +48,49 @@ func Execute() {
}

func init() {
cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cli.yaml)")
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.nestri.yaml)")

// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
// rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Search for config in the current directory
viper.AddConfigPath(".")
viper.SetConfigName(".nestri")
viper.SetConfigType("yaml")

// If not found in current directory, check in $HOME/.nestri/
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Find home directory.
home, err := os.UserHomeDir()
cobra.CheckErr(err)

// Search config in home directory with name ".nestri" (without extension).
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".nestri")
}
}

}

viper.AutomaticEnv() // read in environment variables that match

// If a config file is found, read it in.
if err := viper.ReadInConfig(); err != nil {
fmt.Fprintln(os.Stderr, "Could not find a config file in local directory or in $HOME directory:")
}
}
279 changes: 47 additions & 232 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import (
"runtime"

"github.com/spf13/cobra"
"github.com/spf13/viper"
)

// this is the "nestri run" subcommand, takes no arguments for now
var runCmd = &cobra.Command{
Use: "run [options] [game]",
Use: "run",
Short: "Run a game using nestri",
Args: cobra.MaximumNArgs(1),
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if runtime.GOOS != "linux" {
//make sure os is linux
Expand All @@ -31,230 +32,33 @@ var runCmd = &cobra.Command{
game := args[len(args)-1]

// Load game configuration
// var gameConfig GameConfig
// if err := viper.UnmarshalKey(fmt.Sprintf("games.%s", game), &gameConfig); err != nil {
// return fmt.Errorf("error parsing game configuration: %w", err)
// }

// // Override config with command-line flags
// cmd.Flags().Visit(func(f *pflag.Flag) {
// switch f.Name {
// case "directory":
// gameConfig.Directory = viper.GetString(f.Name)
// case "executable":
// gameConfig.Executable = viper.GetString(f.Name)
// case "gpu":
// gameConfig.GPU = viper.GetInt(f.Name)
// case "vendor":
// gameConfig.Vendor = viper.GetString(f.Name)
// case "resolution-height":
// gameConfig.Resolution.Height = viper.GetInt(f.Name)
// case "resolution-width":
// gameConfig.Resolution.Width = viper.GetInt(f.Name)
// }
// })

fmt.Printf("Running game: %s\n\n", game)

// cli, err := client.NewClientWithOpts(client.FromEnv)
// if err != nil {
// return fmt.Errorf("error creating Docker client: %w", err)
// }

// ctx := context.Background()

// var game string
// if len(args) > 0 {
// game = args[0]
// viper.Set("game", game)
// viper.WriteConfig()
// } else {
// game = viper.GetString("game")
// if filepath.Ext(game) != ".exe" {
// return fmt.Errorf("Make sure the game is a .exe")
// }
// if game == "" {
// return fmt.Errorf("no game specified and no previous game selected")
// }
// }

// fmt.Printf("Running game: %s\n\n", game)

// cli, err := client.NewClientWithOpts()
// if err != nil {
// panic(err)
// }

// ctx := context.Background()
// resp, err := cli.ContainerCreate(ctx, &container.Config{
// Image: "hello-world",
// }, nil, nil, nil, "hello-world")

// if err != nil {
// panic(err)
// }

// if err := cli.ContainerStart(ctx, resp.ID, container.StartOptions{}); err != nil {
// panic(err)
// }

// // Attach to the container to get logs
// out, err := cli.ContainerLogs(ctx, resp.ID, container.LogsOptions{ShowStdout: true, ShowStderr: true, Follow: true})
// if err != nil {
// fmt.Printf("Error attaching to container logs: %s\n", err)
// }
// defer out.Close()

// // Copy the logs to stdout and stderr
// stdcopy.StdCopy(os.Stdout, os.Stderr, out)

// // Wait for the container to finish
// statusCh, errCh := cli.ContainerWait(ctx, resp.ID, container.WaitConditionNotRunning)
// select {
// case err := <-errCh:
// if err != nil {
// fmt.Printf("Error waiting for container: %s\n", err)
// }
// case <-statusCh:
// fmt.Println("Container finished")
// }
// // Clean up the container
// if err := cli.ContainerRemove(ctx, resp.ID, container.RemoveOptions{}); err != nil {
// fmt.Printf("Error removing container: %s\n", err)
// }
// if gpu > 0 {
// fmt.Print("Using gpu %s\n", gpu)
// }
// if hdr {
// fmt.Println("Enabling HDR mode")
// }

//get linux version
// versionCmd := exec.Command("grep", "VERSION", "/etc/os-release")
// versionOutput, err := versionCmd.CombinedOutput()
// if err != nil {
// return fmt.Errorf("error getting linux version:")
// }
// fmt.Printf("Linux version:\n%s\n", string(versionOutput))

// //Step 1: change to games dir
// fmt.Println("changing to game dir.") //this is a temp command for debug as well as leads to a hardcoded dir

// HomeDir, err := os.UserHomeDir()
// if err != nil {
// return fmt.Errorf("error getting home directory %v\n", err)
// }

// err = os.Chdir(fmt.Sprintf("%s/game", HomeDir))
// if err != nil {
// return fmt.Errorf("error changing directory: %v\n", err)
// }
// //verify we are in game dir
// dir, err := os.Getwd()
// if err != nil {
// return fmt.Errorf("error getting current directory: %v\n", err)
// }
// fmt.Printf("Current directory: %s\n\n", dir)

// //list games dir
// listDir := exec.Command("ls", "-la", ".")
// listDirOutput, err := listDir.CombinedOutput()
// if err != nil {
// fmt.Errorf("error listing games: %v\n")
// }
// fmt.Printf("List of Games: \n%s\n", listDirOutput)

// //step 2: Generate a Session ID
// //generate id
// SID := exec.Command("bash", "-c", "head /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | head -c 16")

// //save output to variable
// output, err := SID.Output()
// if err != nil {
// fmt.Errorf("Error generating Session ID: %v\n", err)
// }
// sessionID := strings.TrimSpace(string(output))
// fmt.Printf("Your Session ID is: %s\n\n", sessionID)

// //step 3: Launch netris server
// fmt.Println("Installing Netris/Launching Netris Server")
// checkRunning := exec.Command("sudo", "docker", "ps", "-q", "-f", "name=netris")
// containerId, err := checkRunning.Output()
// if err != nil {
// return fmt.Errorf("error checking running Docker container: %v", err)
// }

// if len(containerId) == 0 {
// checkExisting := exec.Command("sudo", "docker", "ps", "-aq", "-f", "name=netris")
// containerId, err = checkExisting.Output()
// if err != nil {
// return fmt.Errorf("error checking for existing docker container: %v", err)
// }

// if len(containerId) == 0 {
// installCmd := exec.Command(
// "sudo", "docker", "run", "-d", "--gpus", "all", "--device=/dev/dri",
// "--name", "netris", "-it", "--entrypoint", "/bin/bash",
// "-e", fmt.Sprintf("SESSION_ID=%s", sessionID),
// "-v", fmt.Sprintf("%s:/game", dir), "-p", "8080:8080/udp",
// "--cap-add=SYS_NICE", "--cap-add=SYS_ADMIN", "ghcr.io/netrisdotme/netris/server:nightly",
// )
// installCmd.Stdout = os.Stdout
// installCmd.Stderr = os.Stderr

// if err := installCmd.Run(); err != nil {
// return fmt.Errorf("error running docker command: %v", err)
// }
// } else {
// startContainer := exec.Command("sudo", "docker", "start", "netris")
// startContainer.Stdout = os.Stdout
// startContainer.Stderr = os.Stderr

// if err := startContainer.Run(); err != nil {
// return fmt.Errorf("error starting existing Docker container: %v", err)
// }
// }
// }

// //main part of step 4:
// //start netris server

// fmt.Println("starting netris server\n\n")
// checkFileCmd := exec.Command("sudo", "docker", "exec", "netris", "ls", "-la", "/tmp")
// output, err = checkFileCmd.Output()
// if err != nil {
// return fmt.Errorf("error checking /tmp dir in docker container: %v\n", err)
// }

// if !strings.Contains(string(output), ".X11-unix") {
// startupCmd := exec.Command("sudo", "docker", "exec", "netris", "/etc/startup.sh", ">", "/dev/null", "&")
// startupCmd.Stdout = os.Stdout
// startupCmd.Stderr = os.Stderr

// if err := startupCmd.Run(); err != nil {
// return fmt.Errorf("error running startup command: %v\n", err)
// }
var gameConfig GameConfig
if err := viper.UnmarshalKey(fmt.Sprintf("games.%s", game), &gameConfig); err != nil {
return fmt.Errorf("error parsing game configuration: %w", err)
}

// for {
// time.Sleep(7 * time.Minute)
// output, err := checkFileCmd.Output()
// if err != nil {
// return fmt.Errorf("error checking /tmp directory in container: %v\n", err)
// }
// if strings.Contains(string(output), ".X11-unix") {
// break
// }
// }
// }
flags := cmd.Flags()

// gameCmd := fmt.Sprintf("netris-proton -pr %s", game)
// execCmd := exec.Command("sudo", "docker", "exec", "netris", gameCmd)
// execCmd.Stdout = os.Stdout
// execCmd.Stderr = os.Stderr
if flags.Changed("directory") || flags.Changed("d") {
gameConfig.Directory, _ = flags.GetString("directory")
}
if flags.Changed("executable") || flags.Changed("x") {
gameConfig.Executable, _ = flags.GetString("executable")
}
if flags.Changed("gpu") {
gameConfig.GPU, _ = flags.GetInt("gpu")
}
if flags.Changed("vendor") || flags.Changed("v") {
gameConfig.Vendor, _ = flags.GetString("vendor")
}
if flags.Changed("height") || flags.Changed("H") {
gameConfig.Resolution.Height, _ = flags.GetInt("height")
}
if flags.Changed("width") || flags.Changed("W") {
gameConfig.Resolution.Width, _ = flags.GetInt("width")
}

// if err := execCmd.Run(); err != nil {
// return fmt.Errorf("error executing game command in docker container: %v\n", err)
// }
fmt.Println("Game config:", gameConfig)

return nil
},
Expand All @@ -263,13 +67,24 @@ var runCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(runCmd)

// Here you will define your flags and configuration settings.

// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// runCmd.PersistentFlags().String("foo", "", "A help for foo")

// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// runCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
runCmd.Flags().StringP("directory", "d", "", "Game directory")
runCmd.Flags().StringP("executable", "x", "", "Game executable")
runCmd.Flags().Int("gpu", 0, "GPU number")
runCmd.Flags().StringP("vendor", "v", "", "GPU vendor")
runCmd.Flags().IntP("height", "H", 1080, "Screen height")
runCmd.Flags().IntP("width", "W", 1920, "Screen width")

// viper.BindPFlag("directory", runCmd.Flags().Lookup("directory"))
// viper.BindPFlag("executable", runCmd.Flags().Lookup("executable"))
// viper.BindPFlag("gpu", runCmd.Flags().Lookup("gpu"))
// viper.BindPFlag("vendor", runCmd.Flags().Lookup("vendor"))
// viper.BindPFlag("resolution.height", runCmd.Flags().Lookup("height"))
// viper.BindPFlag("resolution.width", runCmd.Flags().Lookup("width"))

viper.BindPFlag("games.*.directory", runCmd.Flags().Lookup("directory"))
viper.BindPFlag("games.*.executable", runCmd.Flags().Lookup("executable"))
viper.BindPFlag("games.*.gpu", runCmd.Flags().Lookup("gpu"))
viper.BindPFlag("games.*.vendor", runCmd.Flags().Lookup("vendor"))
viper.BindPFlag("games.*.resolution.height", runCmd.Flags().Lookup("height"))
viper.BindPFlag("games.*.resolution.width", runCmd.Flags().Lookup("width"))
}

0 comments on commit 08597ce

Please sign in to comment.