First prototype

This commit is contained in:
Felix Niederwanger 2022-02-08 11:25:22 +01:00
parent cd9aabb92b
commit 1b63df4e4e
Signed by: phoenix
GPG key ID: 31860289A704FB3C
6 changed files with 165 additions and 2 deletions

View file

@ -1,5 +1,5 @@
default: all
all: weblug
weblug: cmd/weblug/weblug.go
weblug: cmd/weblug/weblug.go cmd/weblug/config.go
go build -o $@ $^

35
cmd/weblug/config.go Normal file
View file

@ -0,0 +1,35 @@
package main
import (
"io/ioutil"
"gopkg.in/yaml.v2"
)
type Config struct {
Settings ConfigSettings `yaml:"settings"`
Hooks []Hook `yaml:"hooks"`
}
type ConfigSettings struct {
BindAddress string // Bind address for the webserver
}
type Hook struct {
Name string
Route string
Command string
Background bool
}
func (cf *Config) SetDefaults() {
cf.Settings.BindAddress = ":2088"
}
func (cf *Config) LoadYAML(filename string) error {
content, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
return yaml.Unmarshal(content, cf)
}

View file

@ -5,8 +5,108 @@ package main
import (
"fmt"
"log"
"net/http"
"os"
"os/exec"
"strings"
)
var cf Config
var hooks []Hook
type Handler func(http.ResponseWriter, *http.Request)
func main() {
fmt.Println("weblug")
cf.SetDefaults()
if err := cf.LoadYAML(("../../weblug.yaml")); err != nil {
fmt.Fprintf(os.Stderr, "yaml error: %s\n", err)
os.Exit(1)
}
if len(cf.Hooks) == 0 {
fmt.Fprintf(os.Stderr, "error: no webhooks defined\n")
os.Exit(2)
}
// Create default handlers
http.HandleFunc("/health", createHealthHandler())
http.HandleFunc("/health.json", createHealthHandler())
http.HandleFunc("/index", createDefaultHandler())
http.HandleFunc("/index.htm", createDefaultHandler())
http.HandleFunc("/index.html", createDefaultHandler())
http.HandleFunc("/robots.txt", createRobotsHandler())
// Register hooks
for i, hook := range cf.Hooks {
if hook.Route == "" {
fmt.Fprintf(os.Stderr, "Invalid hook %s: No route defined\n", hook.Name)
}
log.Printf("Webhook %d: '%s' [%s] \"%s\"\n", i, hook.Name, hook.Route, hook.Command)
http.HandleFunc(hook.Route, createHandler(hook))
}
// TODO: Await termination signal
log.Printf("Launching webserver on %s", cf.Settings.BindAddress)
log.Fatal(http.ListenAndServe(cf.Settings.BindAddress, nil))
}
// Execute the given command and return it's return code
func execute(command string) error {
split := strings.Split(command, " ")
args := make([]string, 0)
if len(split) > 1 {
args = split[1:]
}
cmd := exec.Command(split[0], args...)
return cmd.Run()
}
// create a http handler function from the given hook
func createHandler(hook Hook) Handler {
return func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s", r.RemoteAddr, hook.Name)
if hook.Background { // Execute command in background
w.WriteHeader(200)
fmt.Fprintf(w, "{\"status\":\"ok\"}")
go func() {
if err := execute(hook.Command); err != nil {
log.Printf("Hook %s failed: %s", hook.Name, err)
} else {
log.Printf("Hook %s completed", hook.Name)
}
}()
} else {
if err := execute(hook.Command); err != nil {
log.Printf("Hook %s failed: %s", hook.Name, err)
w.WriteHeader(500)
fmt.Fprintf(w, "{\"status\":\"fail\"}")
} else {
w.WriteHeader(200)
fmt.Fprintf(w, "{\"status\":\"ok\"}")
}
}
}
}
func createHealthHandler() Handler {
return func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
fmt.Fprintf(w, "{\"status\":\"ok\"}")
}
}
func createDefaultHandler() Handler {
return func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
fmt.Fprintf(w, "weblug")
}
}
func createRobotsHandler() Handler {
return func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
fmt.Fprintf(w, "User-agent: *\nDisallow: /")
}
}

5
go.mod Normal file
View file

@ -0,0 +1,5 @@
module weblug/m/v2
go 1.17
require gopkg.in/yaml.v2 v2.4.0

4
go.sum Normal file
View file

@ -0,0 +1,4 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

19
weblug.yaml Normal file
View file

@ -0,0 +1,19 @@
---
## Weblug example config
settings:
bind: ":2088"
# hook definition. A hook needs to define the HTTP endpoint ("route") and the
# command that will be executed, once this route is executed
hooks:
- name: 'hook one'
route: "/webhooks/1"
command: "sleep 5"
background: True # Terminate http request immediately
- name: 'hook two'
route: "/webhooks/2"
command: "sleep 2"
- name: 'hook 3'
route: "/webhooks/data/3"
command: "/srv/fetch-new-data.sh"