starting sqlite rewrite

- adding db connector
- starting rewrite of commands
- WIP
This commit is contained in:
2025-06-16 19:17:52 -04:00
parent 58ece42142
commit 77bb3166c4
14 changed files with 421 additions and 152 deletions

View File

@@ -5,36 +5,25 @@ package cmd
import (
"fmt"
"os"
"code.jakeyoungdev.com/jake/mctl/models"
"code.jakeyoungdev.com/jake/mctl/database"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// clearCmd represents the clear command
var clearCmd = &cobra.Command{
Use: "clear",
Short: "Clear config file",
Long: `Clears all configuration values for mctl, all server configuration will be lost`,
Long: `Clears all configuration values for mctl. [WARNING] all server configuration will be lost`,
Run: func(cmd *cobra.Command, args []string) {
home, err := os.UserHomeDir()
db, err := database.New()
cobra.CheckErr(err)
defer db.Close()
err = db.Destroy()
cobra.CheckErr(err)
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".mctl")
err = viper.ReadInConfig()
if err == nil {
//clear values if file exists
for _, v := range models.ConfigFields {
viper.Set(v, "")
}
err := viper.WriteConfig()
cobra.CheckErr(err)
fmt.Println("Config file cleared, use 'config' command to re-populate it")
}
fmt.Println("Configuration is cleared, the 'config' command must be run again.")
},
}

View File

@@ -4,26 +4,26 @@ Copyright © 2025 Jake jake.young.dev@gmail.com
package cmd
import (
"crypto/rand"
"encoding/base64"
"fmt"
"io"
"os"
"code.jakeyoungdev.com/jake/mctl/cryptography"
"code.jakeyoungdev.com/jake/mctl/database"
"code.jakeyoungdev.com/jake/mctl/model"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"golang.org/x/term"
)
var (
cfgserver string
cfgport int
cfgname string
)
// configCmd represents the config command
var configCmd = &cobra.Command{
Use: "config",
Example: "mctl config -s x.x.x.x -p 61695",
Example: "mctl config -n serverAlias -s x.x.x.x -p 61695",
Short: "Create and populate config file",
Long: `Creates the .mctl file in the user home directory
populating it with the server address, rcon password, and
@@ -34,68 +34,32 @@ var configCmd = &cobra.Command{
ps, err := term.ReadPassword(int(os.Stdin.Fd()))
cobra.CheckErr(err)
//generate and apply random nonce
nonce := make([]byte, 12)
_, err = io.ReadFull(rand.Reader, nonce)
db, err := database.New()
cobra.CheckErr(err)
viper.Set("nonce", string(nonce))
defer db.Close()
//encrypt password
ciphert, err := cryptography.EncryptPassword(ps)
err = db.Init()
cobra.CheckErr(err)
//update config file with new values
viper.Set("server", cfgserver)
viper.Set("password", string(ciphert))
viper.Set("port", cfgport)
err = viper.WriteConfig()
err = db.SaveServer(model.Server{
Name: cfgname,
Server: cfgserver,
Port: cfgport,
Password: base64.StdEncoding.EncodeToString(ps),
})
cobra.CheckErr(err)
fmt.Println()
fmt.Println("Config file updated!")
},
}
func init() {
initConfig()
configCmd.Flags().StringVarP(&cfgserver, "server", "s", "", "server address")
err := configCmd.MarkFlagRequired("server")
cobra.CheckErr(err)
configCmd.Flags().IntVarP(&cfgport, "port", "p", 0, "server rcon port")
err = configCmd.MarkFlagRequired("port")
cobra.CheckErr(err)
configCmd.Flags().StringVarP(&cfgname, "name", "n", "", "server alias")
err = configCmd.MarkFlagRequired("name")
cobra.CheckErr(err)
rootCmd.AddCommand(configCmd)
}
// init config sets viper config and checks for config file, creating it if it doesn't exist
func initConfig() {
home, err := os.UserHomeDir()
cobra.CheckErr(err)
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".mctl")
viper.AutomaticEnv()
err = viper.ReadInConfig()
if err != nil {
//file does not exist, create it
viper.Set("server", cfgserver)
viper.Set("password", "")
viper.Set("port", cfgport)
viper.Set("nonce", "")
//generate psuedo-random key
uu := make([]byte, 32)
_, err := rand.Read(uu)
cobra.CheckErr(err)
//create custom command map
cmdMap := make(map[string]any, 0)
//write config
viper.Set("customcmd", cmdMap)
viper.Set("device", string(uu))
err = viper.SafeWriteConfig()
cobra.CheckErr(err)
}
}

View File

@@ -5,9 +5,10 @@ package cmd
import (
"errors"
"fmt"
"code.jakeyoungdev.com/jake/mctl/database"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// deleteCmd represents the delete command
@@ -17,13 +18,13 @@ var deleteCmd = &cobra.Command{
Short: "Delete a saved command",
Long: `Deletes a command stored using the save command`,
Run: func(cmd *cobra.Command, args []string) {
if viper.IsSet("customcmd") {
cmdMap := viper.Get("customcmd").(map[string]any)
delete(cmdMap, args[0])
viper.Set("customcmd", cmdMap)
err := viper.WriteConfig()
cobra.CheckErr(err)
}
db, err := database.New()
cobra.CheckErr(err)
defer db.Close()
err = db.DeleteCmd(args[0])
cobra.CheckErr(err)
fmt.Println("Command deleted")
},
PreRunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {

View File

@@ -10,28 +10,36 @@ import (
"os"
"code.jakeyoungdev.com/jake/mctl/client"
"code.jakeyoungdev.com/jake/mctl/database"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
name string
)
// loginCmd represents the login command
var loginCmd = &cobra.Command{
Use: "login",
Example: "mctl login",
Example: "mctl login <name>",
SilenceUsage: true,
Short: "Login to server and send commands",
Long: `Login to server using saved config and enter command loop
sending commands to server and printing the response.`,
Run: func(cmd *cobra.Command, args []string) {
//grab saved credentials
server := viper.Get("server").(string)
cli, err := client.New()
server := args[0]
cli, err := client.New(server)
cobra.CheckErr(err)
defer cli.Close()
//start command loop
fmt.Println("Connected! Type 'mctl' to close")
scanner := bufio.NewScanner(os.Stdin)
db, err := database.New()
cobra.CheckErr(err)
defer db.Close()
var runningCmd string
for runningCmd != "mctl" {
fmt.Printf("RCON@%s /> ", server)
@@ -48,6 +56,11 @@ var loginCmd = &cobra.Command{
break
}
if runningCmd == ".run" {
}
//hmm this gets weird af tbh
dbcmd, err := db.GetCmd(runningCmd)
res, err := cli.Command(runningCmd)
cobra.CheckErr(err)
fmt.Printf("\n%s\n", res)
@@ -57,9 +70,24 @@ var loginCmd = &cobra.Command{
fmt.Printf("Disconnected from %s\n", server)
},
PreRunE: func(cmd *cobra.Command, args []string) error {
//ensure config command has been run
if !viper.IsSet("server") || !viper.IsSet("password") || !viper.IsSet("port") {
return errors.New("the 'config' command must be run before you can interact with servers")
if len(args) == 0 {
return errors.New("must specify which server to login to")
}
srv := args[0]
db, err := database.New()
if err != nil {
return err
}
defer db.Close()
server, err := db.GetServer(srv)
if err != nil {
return err
}
if server.Name == "" {
return fmt.Errorf("server %s not found", server.Name)
}
return nil

View File

@@ -4,11 +4,13 @@ Copyright © 2025 Jake jake.young.dev@gmail.com
package cmd
import (
"database/sql"
"errors"
"fmt"
"strings"
"code.jakeyoungdev.com/jake/mctl/client"
"code.jakeyoungdev.com/jake/mctl/database"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
@@ -22,13 +24,16 @@ var runCmd = &cobra.Command{
Long: `Loads a saved command, injects the supplied arguments into the command, and sends the command to the remove server
printing the response`,
Run: func(cmd *cobra.Command, args []string) {
cm := viper.Get("customcmd").(map[string]any)
//is this an existing command
cmdRun, ok := cm[args[0]]
if !ok {
db, err := database.New()
cobra.CheckErr(err)
defer db.Close()
sc, err := db.GetCmd(args[0])
if err == sql.ErrNoRows {
fmt.Printf("command %s not found", args[0])
return
}
cobra.CheckErr(err)
//convert arguments to interface
var nargs []any
@@ -37,7 +42,7 @@ var runCmd = &cobra.Command{
}
//inject arguments
fixed := fmt.Sprintf(cmdRun.(string), nargs...)
fixed := fmt.Sprintf(sc, nargs...)
fmt.Printf("Running saved command %s\n", fixed)
//create client and send command

View File

@@ -9,8 +9,8 @@ import (
"fmt"
"os"
"code.jakeyoungdev.com/jake/mctl/database"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// saveCmd represents the save command
@@ -21,22 +21,17 @@ var saveCmd = &cobra.Command{
Long: `Saves supplied command using alias <name> to allow the command to be executed using the run command. The %s placeholder can be
used as a wildcard to be injected when running the command`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Use %s as a wildcard in your command\n", "%s") //this is ugly, have to use printf to stop issues with compiler
fmt.Printf("Use %s as a wildcard in your command\n", "%s") //this is ugly
fmt.Printf("Command: ")
sc := bufio.NewScanner(os.Stdin)
if sc.Scan() {
txt := sc.Text()
if txt != "" {
var cmdMap map[string]any
cm := viper.Get("customcmd")
if cmdMap == nil {
cmdMap = make(map[string]any, 0)
} else {
cmdMap = cm.(map[string]any)
}
cmdMap[args[0]] = txt
viper.Set("customcmd", cmdMap)
err := viper.WriteConfig()
db, err := database.New()
cobra.CheckErr(err)
defer db.Close()
err = db.SaveCmd(args[0], txt)
cobra.CheckErr(err)
fmt.Println("\nSaved!")
}

View File

@@ -8,8 +8,8 @@ import (
"fmt"
"strings"
"code.jakeyoungdev.com/jake/mctl/database"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// viewCmd represents the view command
@@ -19,32 +19,29 @@ var viewCmd = &cobra.Command{
Short: "View saved commands",
Long: `Load command using the supplied name and displays it in the terminal, 'all' will list every saved command`,
Run: func(cmd *cobra.Command, args []string) {
var cm map[string]any
cmdMap := viper.Get("customcmd")
if cmdMap == nil {
fmt.Println("no custom commands found")
return
}
cm = cmdMap.(map[string]any)
db, err := database.New()
cobra.CheckErr(err)
defer db.Close()
if strings.EqualFold(args[0], "all") {
//show all commands
cmds, err := db.GetAllCmds()
cobra.CheckErr(err)
fmt.Println("\nCommands: ")
for k, v := range cm {
fmt.Printf("%s - %s\n", k, v)
for _, c := range cmds {
fmt.Printf("%s - %s\n", c.Name, c.Command)
}
fmt.Println()
return
}
} else {
cmds, err := db.GetCmd(args[0])
cobra.CheckErr(err)
custom, ok := cm[args[0]]
if !ok {
fmt.Println("command not found")
return
}
if cmds == "" {
fmt.Println("Command not found")
return
}
fmt.Printf("Command: %s\n", custom.(string))
fmt.Printf("Command: %s\n", cmds)
}
},
PreRunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {