Support configuration file

Per default configuration file will be ignored or will be loaded from $HOME/.tty-share if this file exists. A non-default config file behaviour can be changed using -config flag to specify a config file name.
pull/13/head
Faruk Kasumovic 4 years ago
parent 6fc776b924
commit 732233ccad

@ -0,0 +1,72 @@
package main
import (
"flag"
"fmt"
"io/ioutil"
"os"
"path"
hcl "github.com/hashicorp/hcl"
)
// TTYShareConfig - configuration options for CLI flags or config file
type TTYShareConfig struct {
LogFileName string `json:"logFileName"`
UseTLS bool `json:"useTLS"`
Server string `json:"server"`
configFileName string
commandName string
commandArgs string
versionFlag bool
}
// Load - Load configuration from config file if available and parse CLI options
// CLI options override any config file settings, having config file is useful
// for changing default options
func (conf *TTYShareConfig) Load() {
defConfigFileName := os.Getenv("HOME") + "/." + path.Base(os.Args[0])
flag.StringVar(&conf.configFileName, "config", defConfigFileName, "Config file path")
flag.StringVar(&conf.commandName, "command", os.Getenv("SHELL"), "The command to run")
if conf.commandName == "" {
conf.commandName = "bash"
}
flag.StringVar(&conf.commandArgs, "args", "", "The command arguments")
flag.BoolVar(&conf.versionFlag, "version", false, "Print the tty-share version")
flag.StringVar(&config.LogFileName, "logfile", config.LogFileName, "The name of the file to log")
flag.BoolVar(&config.UseTLS, "useTLS", config.UseTLS, "Use TLS to connect to the server")
flag.StringVar(&config.Server, "server", config.Server, "tty-server address")
flag.Parse()
if conf.versionFlag {
fmt.Printf("%s\n", version)
os.Exit(0)
}
if fileInfo, err := os.Stat(conf.configFileName); os.IsNotExist(err) {
// Ignore if default config file does not exist
// but report error otherwise
if conf.configFileName != defConfigFileName {
fmt.Fprintf(os.Stderr, "Config failed: %s\n", err.Error())
os.Exit(1)
}
} else {
var data []byte
if fileInfo.Size() > 0x100000 {
// Config larger than 1MiB makes no sense for this little program, report and exit
fmt.Fprintf(os.Stderr, "Config failed: config file '%s' is too big\n", conf.configFileName)
os.Exit(3)
}
if data, err = ioutil.ReadFile(conf.configFileName); err != nil {
fmt.Fprintf(os.Stderr, "Config failed: %s\n", err.Error())
os.Exit(2)
}
if err = hcl.Decode(conf, string(data)); err != nil {
fmt.Fprintf(os.Stderr, "Config failed: %s\n", err.Error())
os.Exit(4)
}
fmt.Printf("Configuration loaded from '%s'\n\n", conf.configFileName)
}
// Override config file options with CLI / give priority to CLI
flag.Parse()
}

@ -4,6 +4,7 @@ go 1.13
require (
github.com/elisescu/pty v1.0.2
github.com/hashicorp/hcl v1.0.0
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/sirupsen/logrus v1.4.2
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876

@ -2,6 +2,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/elisescu/pty v1.0.2 h1:I/wkN5bnPyh00j/bnNAy8wll8yvd8wRLUjPnmcmYI+Q=
github.com/elisescu/pty v1.0.2/go.mod h1:tzLUboZf84k7sFZdd2cOvhr/fSxMABV0UTMxnF25R/Y=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=

@ -4,7 +4,6 @@ import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"flag"
"fmt"
"io"
"net"
@ -16,30 +15,20 @@ import (
var log = logrus.New()
var version string = "0.0.0"
var config = TTYShareConfig{ // default configuration options
LogFileName: "-",
Server: "go.tty-share.com:7654",
UseTLS: false,
}
func main() {
commandName := flag.String("command", os.Getenv("SHELL"), "The command to run")
if *commandName == "" {
*commandName = "bash"
}
commandArgs := flag.String("args", "", "The command arguments")
logFileName := flag.String("logfile", "-", "The name of the file to log")
useTLS := flag.Bool("useTLS", true, "Use TLS to connect to the server")
server := flag.String("server", "go.tty-share.com:7654", "tty-server address")
versionFlag := flag.Bool("version", false, "Print the tty-share version")
flag.Parse()
if *versionFlag {
fmt.Printf("%s\n", version)
return
}
config.Load()
log.Level = logrus.ErrorLevel
if *logFileName != "-" {
fmt.Printf("Writing logs to: %s\n", *logFileName)
logFile, err := os.Create(*logFileName)
if config.LogFileName != "-" {
fmt.Printf("Writing logs to: %s\n", config.LogFileName)
logFile, err := os.Create(config.LogFileName)
if err != nil {
fmt.Printf("Can't open %s for writing logs\n", *logFileName)
fmt.Printf("Can't open %s for writing logs\n", config.LogFileName)
}
log.Level = logrus.DebugLevel
log.Out = logFile
@ -51,22 +40,22 @@ func main() {
}
var rawConnection io.ReadWriteCloser
if *useTLS {
if config.UseTLS {
roots, err := x509.SystemCertPool()
if err != nil {
fmt.Printf("Cannot connect to the server (%s): %s", *server, err.Error())
fmt.Printf("Cannot connect to the server (%s): %s", config.Server, err.Error())
return
}
rawConnection, err = tls.Dial("tcp", *server, &tls.Config{RootCAs: roots})
rawConnection, err = tls.Dial("tcp", config.Server, &tls.Config{RootCAs: roots})
if err != nil {
fmt.Printf("Cannot connect (TLS) to the server (%s): %s", *server, err.Error())
fmt.Printf("Cannot connect (TLS) to the server (%s): %s", config.Server, err.Error())
return
}
} else {
var err error
rawConnection, err = net.Dial("tcp", *server)
rawConnection, err = net.Dial("tcp", config.Server)
if err != nil {
fmt.Printf("Cannot connect to the server (%s): %s", *server, err.Error())
fmt.Printf("Cannot connect to the server (%s): %s", config.Server, err.Error())
return
}
}
@ -91,7 +80,7 @@ func main() {
// tty sender, they will be delivered all at once, after Enter has been pressed. Fix that.
ptyMaster := ptyMasterNew()
ptyMaster.Start(*commandName, strings.Fields(*commandArgs), func(cols, rows int) {
ptyMaster.Start(config.commandName, strings.Fields(config.commandArgs), func(cols, rows int) {
log.Infof("New window size: %dx%d", cols, rows)
serverConnection.SetWinSize(cols, rows)
})

Loading…
Cancel
Save