diff --git a/Makefile b/Makefile index 1600281..c05d302 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ BUILD_OPTIONS = -ldflags "-X main.Version=$(VERSION) -X main.CommitID=$(GIT_COMM gotty: main.go server/*.go webtty/*.go backend/*.go Makefile mkdir -p builds go build -o builds/gotty ${BUILD_OPTIONS} + $(PWD)/builds/gotty .PHONY: asset asset: bindata/static/js/gotty-bundle.js bindata/static/index.html bindata/static/favicon.png bindata/static/css/index.css bindata/static/css/xterm.css bindata/static/css/xterm_customize.css diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..684ed37 --- /dev/null +++ b/go.sum @@ -0,0 +1,45 @@ +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= +github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= +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= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw= +github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/urfave/cli v1.22.17 h1:SYzXoiPfQjHBbkYxbew5prZHS1TOLT3ierW8SYLqtVQ= +github.com/urfave/cli v1.22.17/go.mod h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo= +github.com/yudai/hcl v0.0.0-20151013225006-5fa2393b3552 h1:tjsK9T2IA3d2FFNxzDP7AJf+EXhyuPd7PB4Z2HrtAoc= +github.com/yudai/hcl v0.0.0-20151013225006-5fa2393b3552/go.mod h1:hg0ZaCmQL3rze1cH8Fh2g0a9q8vQs0uN8ESpePEwSEw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gottyLib/gotty.go b/gottyLib/gotty.go new file mode 100644 index 0000000..61b4371 --- /dev/null +++ b/gottyLib/gotty.go @@ -0,0 +1,97 @@ +package gottyLib + +import ( + "context" + "fmt" + "github.com/kernel-punk/gotty/backend/localcommand" + "github.com/kernel-punk/gotty/server" + "github.com/kernel-punk/gotty/utils" + "os" + "os/signal" + "syscall" +) + +func Run(runParameters RunParameters) error { + + //runParameters := RunParameters{ + // + // cmd: "htop", + // args: []string{}, + // ssl: false, + //} + + hostname, _ := os.Hostname() + + appOptions := &server.Options{} + if err := utils.ApplyDefaultValues(appOptions); err != nil { + return err + } + + backendOptions := &localcommand.Options{} + if err := utils.ApplyDefaultValues(backendOptions); err != nil { + return err + } + + factory, err := localcommand.NewFactory(runParameters.Cmd, runParameters.Args, backendOptions) + if err != nil { + return err + } + + appOptions.TitleVariables = map[string]interface{}{ + "command": runParameters.Cmd, + "argv": runParameters.Args, + "hostname": hostname, + } + + srv, err := server.New(factory, appOptions) + if err != nil { + return err + } + + ctx, cancel := context.WithCancel(context.Background()) + gCtx, gCancel := context.WithCancel(context.Background()) + + errs := make(chan error, 1) + go func() { + errs <- srv.Run(ctx, server.WithGracefullContext(gCtx)) + }() + err = waitSignals(errs, cancel, gCancel) + + if err != nil && err != context.Canceled { + return err + } + + return nil +} + +func waitSignals(errs chan error, cancel context.CancelFunc, gracefullCancel context.CancelFunc) error { + sigChan := make(chan os.Signal, 1) + signal.Notify( + sigChan, + syscall.SIGINT, + syscall.SIGTERM, + ) + + select { + case err := <-errs: + return err + + case s := <-sigChan: + switch s { + case syscall.SIGINT: + gracefullCancel() + fmt.Println("C-C to force close") + select { + case err := <-errs: + return err + case <-sigChan: + fmt.Println("Force closing...") + cancel() + return <-errs + } + default: + cancel() + return <-errs + } + } +} diff --git a/gottyLib/types.go b/gottyLib/types.go new file mode 100644 index 0000000..87bdd5b --- /dev/null +++ b/gottyLib/types.go @@ -0,0 +1,7 @@ +package gottyLib + +type RunParameters struct { + Cmd string + Args []string + Ssl bool +} diff --git a/main.go b/main.go index b8f5dc2..b389d48 100644 --- a/main.go +++ b/main.go @@ -1,152 +1,19 @@ package main import ( - "context" - "fmt" + "github.com/kernel-punk/gotty/gottyLib" "log" - "os" - "os/signal" - "strings" - "syscall" - - "github.com/urfave/cli" - - "github.com/kernel-punk/gotty/backend/localcommand" - "github.com/kernel-punk/gotty/pkg/homedir" - "github.com/kernel-punk/gotty/server" - "github.com/kernel-punk/gotty/utils" ) func main() { - app := cli.NewApp() - app.Name = "gotty" - app.Version = Version + "+" + CommitID - app.Usage = "Share your terminal as a web application" - app.HideHelp = true - cli.AppHelpTemplate = helpTemplate - appOptions := &server.Options{} - if err := utils.ApplyDefaultValues(appOptions); err != nil { - exit(err, 1) - } - backendOptions := &localcommand.Options{} - if err := utils.ApplyDefaultValues(backendOptions); err != nil { - exit(err, 1) + if err := gottyLib.Run(gottyLib.RunParameters{ + + Cmd: "htop", + Args: []string{}, + Ssl: false, + }); err != nil { + log.Fatal(err) } - cliFlags, flagMappings, err := utils.GenerateFlags(appOptions, backendOptions) - if err != nil { - exit(err, 3) - } - - app.Flags = append( - cliFlags, - cli.StringFlag{ - Name: "config", - Value: "~/.gotty", - Usage: "Config file path", - EnvVar: "GOTTY_CONFIG", - }, - ) - - app.Action = func(c *cli.Context) { - if len(c.Args()) == 0 { - msg := "Error: No command given." - cli.ShowAppHelp(c) - exit(fmt.Errorf(msg), 1) - } - - configFile := c.String("config") - _, err := os.Stat(homedir.Expand(configFile)) - if configFile != "~/.gotty" || !os.IsNotExist(err) { - if err := utils.ApplyConfigFile(configFile, appOptions, backendOptions); err != nil { - exit(err, 2) - } - } - - utils.ApplyFlags(cliFlags, flagMappings, c, appOptions, backendOptions) - - appOptions.EnableBasicAuth = c.IsSet("credential") - appOptions.EnableTLSClientAuth = c.IsSet("tls-ca-crt") - - err = appOptions.Validate() - if err != nil { - exit(err, 6) - } - - args := c.Args() - factory, err := localcommand.NewFactory(args[0], args[1:], backendOptions) - if err != nil { - exit(err, 3) - } - - hostname, _ := os.Hostname() - appOptions.TitleVariables = map[string]interface{}{ - "command": args[0], - "argv": args[1:], - "hostname": hostname, - } - - srv, err := server.New(factory, appOptions) - if err != nil { - exit(err, 3) - } - - ctx, cancel := context.WithCancel(context.Background()) - gCtx, gCancel := context.WithCancel(context.Background()) - - log.Printf("GoTTY is starting with command: %s", strings.Join(args, " ")) - - errs := make(chan error, 1) - go func() { - errs <- srv.Run(ctx, server.WithGracefullContext(gCtx)) - }() - err = waitSignals(errs, cancel, gCancel) - - if err != nil && err != context.Canceled { - fmt.Printf("Error: %s\n", err) - exit(err, 8) - } - - } - app.Run(os.Args) -} - -func exit(err error, code int) { - if err != nil { - fmt.Println(err) - } - os.Exit(code) -} - -func waitSignals(errs chan error, cancel context.CancelFunc, gracefullCancel context.CancelFunc) error { - sigChan := make(chan os.Signal, 1) - signal.Notify( - sigChan, - syscall.SIGINT, - syscall.SIGTERM, - ) - - select { - case err := <-errs: - return err - - case s := <-sigChan: - switch s { - case syscall.SIGINT: - gracefullCancel() - fmt.Println("C-C to force close") - select { - case err := <-errs: - return err - case <-sigChan: - fmt.Println("Force closing...") - cancel() - return <-errs - } - default: - cancel() - return <-errs - } - } }