Compare commits
No commits in common. "master" and "fd5c5b570090fe9dfd286a7df869cae604f4be61" have entirely different histories.
master
...
fd5c5b5700
3 changed files with 37 additions and 86 deletions
21
LICENSE
21
LICENSE
|
@ -1,21 +0,0 @@
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2022 Augusto Dwenger
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
49
README.md
49
README.md
|
@ -1,57 +1,32 @@
|
||||||
# whook
|
# whook
|
||||||
|
|
||||||
A simple and naive implementation of a web server for the usage with webhooks.
|
Simple Server for Webhook usage.
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
**Requirements:**
|
|
||||||
|
|
||||||
- Go >= 1.17
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git clone https://git.hhhammer.de/hamburghammer/whook.git
|
|
||||||
cd whook
|
|
||||||
go build
|
|
||||||
```
|
|
||||||
|
|
||||||
You should now have a `whook` executable in the directory.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
The server is build to run behind a proxy that provides `https` and some kind of
|
|
||||||
`auth` and it is not designed for long running processes.
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./whook -c ./test.sh
|
./whook -c ./test.sh -d $(pwd)
|
||||||
```
|
```
|
||||||
|
|
||||||
The `test.sh` script contains only `echo "hellow"` so that the output after
|
The `test.sh` script contains only `echo "hellow"` so that the output after starting
|
||||||
starting the application and opening the given URL in side the browser we see
|
the application and opening the given URL in side the browser we see following output:
|
||||||
following output:
|
|
||||||
|
|
||||||
```plain
|
```plain
|
||||||
2022/01/17 21:48:43 The HTTP server is running: http://localhost:8080/
|
2022/01/17 19:14:28 The HTTP server is running: http://localhost:8080/
|
||||||
2022/01/17 21:48:49 Executing a command...
|
Executing a command...
|
||||||
2022/01/17 21:48:49 hellow
|
hallow
|
||||||
```
|
```
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
```plain
|
```plain
|
||||||
A small server to listen for requests to execute some particular code.
|
A small server to listen for requests to execute some particular code.
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
whook [FLAGS] --cmd [COMMAND [--args [ARGS]]]
|
whook [FLAGS]
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-a, --args strings Arguments for the command. Can be provided multiple times or as comma-separated string.
|
-c, --cmd string REQUIRED: The command to execute.
|
||||||
-c, --cmd string REQUIRED: The command to execute.
|
-d, --dir string REQUIRED: The Directory to execute the command.
|
||||||
-d, --dir string The Directory to execute the command.
|
-h, --help Prints this help message and exits.
|
||||||
Defaults to the directory the tool was called on.
|
-p, --port string Port to listen for incoming connections. (default "8080")
|
||||||
-h, --help Prints this help message and exits.
|
|
||||||
-p, --port string Port to listen for incoming connections. (default "8080")
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
This project is licensed under the [MIT](LICENSE) license.
|
|
||||||
|
|
53
main.go
53
main.go
|
@ -19,8 +19,7 @@ import (
|
||||||
var (
|
var (
|
||||||
servePort string
|
servePort string
|
||||||
isHelp bool
|
isHelp bool
|
||||||
cmd string
|
cmdPath string
|
||||||
cmdArgs []string
|
|
||||||
commandExecDir string
|
commandExecDir string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,41 +28,35 @@ func init() {
|
||||||
flags.StringVarP(&servePort, "port", "p", "8080", "Port to listen for incoming connections.")
|
flags.StringVarP(&servePort, "port", "p", "8080", "Port to listen for incoming connections.")
|
||||||
flags.BoolVarP(&isHelp, "help", "h", false, "Prints this help message and exits.")
|
flags.BoolVarP(&isHelp, "help", "h", false, "Prints this help message and exits.")
|
||||||
|
|
||||||
flags.StringVarP(&cmd, "cmd", "c", "", "REQUIRED: The command to execute.")
|
flags.StringVarP(&cmdPath, "cmd", "c", "", "REQUIRED: The command to execute.")
|
||||||
flags.StringSliceVarP(&cmdArgs, "args", "a", []string{}, "Arguments for the command. Can be provided multiple times or as comma-separated string.")
|
flags.StringVarP(&commandExecDir, "dir", "d", "", "REQUIRED: The Directory to execute the command.")
|
||||||
flags.StringVarP(&commandExecDir, "dir", "d", "", "The Directory to execute the command.\nDefaults to the directory the tool was called on.")
|
|
||||||
flags.Parse()
|
flags.Parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
// handles the webhook requests
|
// handles the webhook requests
|
||||||
func handler(w http.ResponseWriter, r *http.Request) {
|
func handler(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close() // so I don't forget to close it -> eventhough it's not read.
|
defer r.Body.Close()
|
||||||
|
|
||||||
cmd := exec.CommandContext(r.Context(), cmd, cmdArgs...)
|
fmt.Println("Executing a command...")
|
||||||
// set directory only if it's present.
|
cmd := exec.Command(cmdPath)
|
||||||
if commandExecDir != "" {
|
cmd.Dir = commandExecDir
|
||||||
cmd.Dir = commandExecDir
|
out, err := cmd.Output()
|
||||||
}
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
fmt.Fprint(w, err.Error())
|
|
||||||
w.WriteHeader(http.StatusBadGateway)
|
w.WriteHeader(http.StatusBadGateway)
|
||||||
}
|
}
|
||||||
output := string(out)
|
fmt.Println(string(out))
|
||||||
log.Println("Command output:\n" + output)
|
|
||||||
fmt.Fprint(w, output)
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if isHelp {
|
if isHelp {
|
||||||
printHelp()
|
printHelp()
|
||||||
// printing help is treated as a successful execution.
|
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := validateParams()
|
err := validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
@ -71,7 +64,7 @@ func main() {
|
||||||
// use the default mux because it implements the Handler interface
|
// use the default mux because it implements the Handler interface
|
||||||
// which we need for the server struct.
|
// which we need for the server struct.
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.HandleFunc("/", handler) // only add one handler on root path
|
mux.HandleFunc("/", handler) // only add out handler on root path
|
||||||
|
|
||||||
// custom server struct to set custom timeouts for better performance.
|
// custom server struct to set custom timeouts for better performance.
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
|
@ -98,19 +91,20 @@ func startHTTPServer(server *http.Server, wg *sync.WaitGroup) {
|
||||||
log.Println("Shutting down the server...")
|
log.Println("Shutting down the server...")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Fatalf("An unexpected error happened while running the HTTP server: %v\n", err)
|
log.Fatalf("An unexpected error happend while running the HTTP server: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func listenToStopHTTPServer(server *http.Server, wg *sync.WaitGroup) {
|
func listenToStopHTTPServer(server *http.Server, wg *sync.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
stop := make(chan os.Signal, 1)
|
stop := make(chan os.Signal, 1)
|
||||||
signal.Notify(stop, os.Interrupt)
|
signal.Notify(stop, os.Interrupt, os.Kill)
|
||||||
<-stop // block til signal is captured.
|
|
||||||
|
<-stop
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := server.Shutdown(ctx); err != nil {
|
if err := server.Shutdown(ctx); err != nil {
|
||||||
log.Fatalf("An error happened on the shutdown of the server: %v", err)
|
log.Fatalf("An error happened on the shutdown of the server: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -120,16 +114,19 @@ func printHelp() {
|
||||||
fmt.Println(`A small server to listen for requests to execute some particular code.
|
fmt.Println(`A small server to listen for requests to execute some particular code.
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
whook [FLAGS] --cmd [COMMAND [--args [ARGS]]
|
whook [FLAGS]
|
||||||
|
|
||||||
FLAGS:`)
|
FLAGS:`)
|
||||||
flags.PrintDefaults()
|
flags.PrintDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateParams if required params are present.
|
// validate if required params are presend.
|
||||||
func validateParams() error {
|
func validate() error {
|
||||||
if cmd == "" {
|
if cmdPath == "" {
|
||||||
return errors.New("missing required 'cmd' parameter")
|
return errors.New("Missing required 'cmd' parameter")
|
||||||
|
}
|
||||||
|
if commandExecDir == "" {
|
||||||
|
return errors.New("Missing required 'dir' parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Reference in a new issue