diff --git a/README.md b/README.md
index fbd3f07..b93815c 100644
--- a/README.md
+++ b/README.md
@@ -119,4 +119,11 @@ mctl utilizes [govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck
# Development
-this repo is currently in development and may encounter breaking changes, use a tag to prevent any surprises
\ No newline at end of file
+this repo is currently in development and may encounter breaking changes, use a tag to prevent any surprises
+
+# TODO
+1. continue sqlite update
+2. migrate the credentials to sqlite as well
+3. login too
+4. MCR client also has viper stuff, gut it
+5. Since we are now using sqlite should we just encode the pwd and insert
\ No newline at end of file
diff --git a/client/mcr.go b/client/mcr.go
index 292c687..e58db39 100644
--- a/client/mcr.go
+++ b/client/mcr.go
@@ -1,11 +1,11 @@
package client
import (
+ "encoding/base64"
"fmt"
- "code.jakeyoungdev.com/jake/mctl/cryptography"
+ "code.jakeyoungdev.com/jake/mctl/database"
"github.com/jake-young-dev/mcr"
- "github.com/spf13/viper"
)
/*
@@ -23,22 +23,25 @@ type IClient interface {
}
// creates a new mcr client using saved credentials and decrypted password
-func New() (*Client, error) {
- //grab saved credentials
- server := viper.Get("server").(string)
- password := viper.Get("password").(string)
- port := viper.Get("port").(int)
- fmt.Printf("Logging into %s on port %d\n", server, port)
-
- //decrypt password
- pt, err := cryptography.DecryptPassword([]byte(password))
+func New(name string) (*Client, error) {
+ db, err := database.New()
if err != nil {
return nil, err
}
+ defer db.Close()
+
+ srv, err := db.GetServer(name)
+ if err != nil {
+ return nil, err
+ }
+ fmt.Printf("Logging into %s on port %d\n", srv.Server, srv.Port)
+
+ var p []byte
+ _, err = base64.StdEncoding.Decode(p, []byte(srv.Password))
//connect to game server
- cli := mcr.NewClient(server, mcr.WithPort(port))
- err = cli.Connect(string(pt))
+ cli := mcr.NewClient(srv.Server, mcr.WithPort(srv.Port))
+ err = cli.Connect(string(p))
if err != nil {
return nil, err
}
diff --git a/cmd/clear.go b/cmd/clear.go
index 5dd05de..692dc2e 100644
--- a/cmd/clear.go
+++ b/cmd/clear.go
@@ -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.")
},
}
diff --git a/cmd/config.go b/cmd/config.go
index 25f500c..d299d13 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -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)
- }
-}
diff --git a/cmd/delete.go b/cmd/delete.go
index dcee881..0944d79 100644
--- a/cmd/delete.go
+++ b/cmd/delete.go
@@ -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 {
diff --git a/cmd/login.go b/cmd/login.go
index 84e22f9..33e78ea 100644
--- a/cmd/login.go
+++ b/cmd/login.go
@@ -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 ",
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
diff --git a/cmd/run.go b/cmd/run.go
index bf749c6..4c33e2d 100644
--- a/cmd/run.go
+++ b/cmd/run.go
@@ -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
diff --git a/cmd/save.go b/cmd/save.go
index 2f5e6fb..0cbc4d3 100644
--- a/cmd/save.go
+++ b/cmd/save.go
@@ -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 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!")
}
diff --git a/cmd/view.go b/cmd/view.go
index 1c95609..929bed5 100644
--- a/cmd/view.go
+++ b/cmd/view.go
@@ -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 {
diff --git a/database/commands.go b/database/commands.go
new file mode 100644
index 0000000..80cc041
--- /dev/null
+++ b/database/commands.go
@@ -0,0 +1,250 @@
+package database
+
+import (
+ "fmt"
+ "os"
+
+ "code.jakeyoungdev.com/jake/mctl/model"
+ "github.com/jmoiron/sqlx"
+ _ "github.com/ncruces/go-sqlite3/driver"
+ _ "github.com/ncruces/go-sqlite3/embed"
+)
+
+type database struct {
+ *sqlx.DB
+}
+
+type Database interface {
+ Init() error
+ Destroy() error
+ Close() error
+ //command methods
+ GetCmd(name string) (string, error)
+ GetAllCmds() ([]model.Command, error)
+ SaveCmd(name, cmd string) error
+ UpdateCmd(name, cmd string) error
+ DeleteCmd(name string) error
+ //server methods
+ GetServer(name string) (model.Server, error)
+ GetAllServers() ([]model.Server, error)
+ SaveServer(srv model.Server) error
+ UpdateServer(name, password string) error
+ DeleteServer(name string) error
+}
+
+func New() (Database, error) {
+ home, err := os.UserHomeDir()
+ if err != nil {
+ return nil, err
+ }
+ db, err := sqlx.Open("sqlite3", fmt.Sprintf("file:%s/.mctl", home))
+ if err != nil {
+ return nil, err
+ }
+
+ return &database{
+ db,
+ }, nil
+}
+
+func (d *database) Init() error {
+ query := `
+ CREATE TABLE IF NOT EXISTS commands(
+ name TEXT PRIMARY KEY,
+ command TEXT
+ )
+
+ CREATE TABLE IF NOT EXISTS servers(
+ name TEXT PRIMARY KEY,
+ server TEXT,
+ password TEXT,
+ port NUMBER
+ )
+ `
+
+ _, err := d.Exec(query)
+ return err
+}
+
+func (d *database) Destroy() error {
+ query := `
+ DROP TABLE commands
+ DROP TABLE servers
+ `
+
+ _, err := d.Exec(query)
+ return err
+}
+
+func (d *database) Close() error {
+ return d.Close()
+}
+
+func (d *database) GetCmd(name string) (string, error) {
+ query := `
+ SELECT
+ command
+ FROM
+ commands
+ WHERE
+ name = ?
+ `
+
+ var cmd string
+ err := d.QueryRowx(query, name).Scan(&cmd)
+ if err != nil {
+ return "", err
+ }
+
+ return name, nil
+}
+
+func (d *database) GetAllCmds() ([]model.Command, error) {
+ query := `
+ SELECT
+ name,
+ command
+ FROM
+ commands
+ `
+
+ rows, err := d.Queryx(query)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ var res []model.Command
+ for rows.Next() {
+ var r model.Command
+ err := rows.StructScan(&r)
+ if err != nil {
+ return nil, err
+ }
+
+ res = append(res, r)
+ }
+
+ return res, nil
+}
+
+func (d *database) SaveCmd(name, cmd string) error {
+ query := `
+ INSERT INTO commands(name, command)
+ VALUES(?, ?)
+ `
+
+ _, err := d.Exec(query, name, cmd)
+ return err
+}
+
+func (d *database) UpdateCmd(name, cmd string) error {
+ query := `
+ UPDATE
+ commands
+ SET
+ cmd = ?
+ WHERE
+ name = ?
+ `
+
+ _, err := d.Exec(query, cmd, name)
+ return err
+}
+
+func (d *database) DeleteCmd(name string) error {
+ query := `
+ DELETE FROM commands
+ WHERE name = ?
+ `
+
+ _, err := d.Exec(query, name)
+ return err
+}
+
+func (d *database) GetServer(name string) (model.Server, error) {
+ query := `
+ SELECT
+ name,
+ server,
+ password,
+ port
+ FROM
+ servers
+ WHERE
+ name = ?
+ `
+
+ var s model.Server
+ err := d.QueryRowx(query, name).StructScan(&s)
+ if err != nil {
+ return model.Server{}, err
+ }
+ return s, nil
+}
+
+func (d *database) GetAllServers() ([]model.Server, error) {
+ query := `
+ SELECT
+ name,
+ server,
+ password,
+ port
+ FROM
+ servers
+ `
+
+ rows, err := d.Queryx(query)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ var res []model.Server
+ for rows.Next() {
+ var r model.Server
+ err := rows.StructScan(&r)
+ if err != nil {
+ return nil, err
+ }
+
+ res = append(res, r)
+ }
+
+ return res, nil
+}
+
+func (d *database) SaveServer(srv model.Server) error {
+ query := `
+ INSERT INTO servers(name, server, password, port)
+ VALUES(?, ?, ?, ?)
+ `
+
+ _, err := d.Exec(query, srv.Name, srv.Server, srv.Password, srv.Port)
+ return err
+}
+
+// updates server password, if anymore fields need updated the entry should be deleted and recreated
+func (d *database) UpdateServer(name, password string) error {
+ query := `
+ UPDATE servers
+ SET
+ password = ?
+ WHERE
+ name = ?
+ `
+
+ _, err := d.Exec(query, password, name)
+ return err
+}
+
+func (d *database) DeleteServer(name string) error {
+ query := `
+ DELETE FROM servers
+ WHERE
+ name = ?
+ `
+
+ _, err := d.Exec(query, name)
+ return err
+}
diff --git a/go.mod b/go.mod
index fed923e..68fac98 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,8 @@ go 1.24.2
require (
github.com/jake-young-dev/mcr v1.4.0
+ github.com/jmoiron/sqlx v1.4.0
+ github.com/ncruces/go-sqlite3 v0.26.1
github.com/spf13/cobra v1.9.1
github.com/spf13/viper v1.20.1
golang.org/x/term v0.31.0
@@ -13,6 +15,7 @@ require (
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/ncruces/julianday v1.0.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
@@ -20,9 +23,10 @@ require (
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
+ github.com/tetratelabs/wazero v1.9.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
- golang.org/x/sys v0.32.0 // indirect
- golang.org/x/text v0.21.0 // indirect
+ golang.org/x/sys v0.33.0 // indirect
+ golang.org/x/text v0.26.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 4c6f616..6fee408 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,5 @@
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -6,20 +8,30 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/jake-young-dev/mcr v1.3.1 h1:ELJsrJHwQsMiM09o+q8auUaiGXXX3DWIgh/TfZQc0B0=
-github.com/jake-young-dev/mcr v1.3.1/go.mod h1:74yZHGf9h3tLUDUpInA17grKLrNp9lVesWvisCFCXKY=
github.com/jake-young-dev/mcr v1.4.0 h1:cXZImkfI8aNIiVPrONE6qP+nfblTGsD2iXpPKTcA25U=
github.com/jake-young-dev/mcr v1.4.0/go.mod h1:74yZHGf9h3tLUDUpInA17grKLrNp9lVesWvisCFCXKY=
+github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
+github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
+github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
+github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
+github.com/ncruces/go-sqlite3 v0.26.1 h1:lBXmbmucH1Bsj57NUQR6T84UoMN7jnNImhF+ibEITJU=
+github.com/ncruces/go-sqlite3 v0.26.1/go.mod h1:XFTPtFIo1DmGCh+XVP8KGn9b/o2f+z0WZuT09x2N6eo=
+github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
+github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -47,16 +59,18 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
+github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
+github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
-golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
-golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
-golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
+golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/model/data.go b/model/data.go
new file mode 100644
index 0000000..38841a6
--- /dev/null
+++ b/model/data.go
@@ -0,0 +1,16 @@
+package model
+
+//list of all fields kept in config file
+// var ConfigFields = [6]string{"customcmd", "device", "nonce", "port", "server", "password"}
+
+type Command struct {
+ Name string `db:"name"`
+ Command string `db:"command"`
+}
+
+type Server struct {
+ Name string `db:"name"`
+ Server string `db:"server"`
+ Password string `db:"password"`
+ Port int `db:"port"`
+}
diff --git a/models/data.go b/models/data.go
deleted file mode 100644
index e282c91..0000000
--- a/models/data.go
+++ /dev/null
@@ -1,4 +0,0 @@
-package models
-
-//list of all fields kept in config file
-var ConfigFields = [6]string{"customcmd", "device", "nonce", "port", "server", "password"}