parent
95e9383138
commit
8432135f3d
6
Makefile
6
Makefile
|
@ -8,6 +8,12 @@ LDFLAGS=-ldflags "-X main.Version=${VERSION} -X main.Build=${BUILD} -w"
|
||||||
|
|
||||||
default: build
|
default: build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf dist
|
||||||
|
|
||||||
|
run: build
|
||||||
|
$(shell cd dist; ./${PROJ} -log configui.log)
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build:
|
build:
|
||||||
go build ${LDFLAGS} -o dist/${PROJ}
|
go build ${LDFLAGS} -o dist/${PROJ}
|
35
README.md
35
README.md
|
@ -2,6 +2,41 @@
|
||||||
|
|
||||||
a web app to edit and action on update
|
a web app to edit and action on update
|
||||||
|
|
||||||
|
```
|
||||||
|
Usage: configui [options]
|
||||||
|
-bind string
|
||||||
|
address to bind (default "localhost:8000")
|
||||||
|
-c string
|
||||||
|
cmd to apply
|
||||||
|
-f string
|
||||||
|
path to config file
|
||||||
|
-log string
|
||||||
|
log to file
|
||||||
|
-n string
|
||||||
|
alias of file
|
||||||
|
-p string
|
||||||
|
path to file, precedence over config
|
||||||
|
-v show version
|
||||||
|
```
|
||||||
|
|
||||||
|
## Config
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "configui.log",
|
||||||
|
"ro": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "etc/test.ini",
|
||||||
|
"name": "test",
|
||||||
|
"action": "myip local -P"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
`configui -f PATH/TO/CONFIG`
|
||||||
|
|
||||||
## Api
|
## Api
|
||||||
|
|
||||||
### Files
|
### Files
|
||||||
|
|
59
api.go
59
api.go
|
@ -11,8 +11,7 @@ import (
|
||||||
func ListFiles(w http.ResponseWriter, r *http.Request) {
|
func ListFiles(w http.ResponseWriter, r *http.Request) {
|
||||||
data, err := json.Marshal(files)
|
data, err := json.Marshal(files)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
HttpWriter(w, 500, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Write(data)
|
w.Write(data)
|
||||||
|
@ -22,14 +21,12 @@ func GetFile(w http.ResponseWriter, r *http.Request) {
|
||||||
name := r.URL.Query().Get("name")
|
name := r.URL.Query().Get("name")
|
||||||
file, ok := files[name]
|
file, ok := files[name]
|
||||||
if name == "" || !ok {
|
if name == "" || !ok {
|
||||||
w.WriteHeader(404)
|
HttpWriter(w, 404, "file not found")
|
||||||
w.Write([]byte("file not found"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data, err := file.Read()
|
data, err := file.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
HttpWriter(w, 500, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response, err := json.Marshal(map[string]string{
|
response, err := json.Marshal(map[string]string{
|
||||||
|
@ -39,8 +36,7 @@ func GetFile(w http.ResponseWriter, r *http.Request) {
|
||||||
"data": string(data),
|
"data": string(data),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
HttpWriter(w, 500, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
@ -51,25 +47,21 @@ func PostFile(w http.ResponseWriter, r *http.Request) {
|
||||||
data, err := ioutil.ReadAll(r.Body)
|
data, err := ioutil.ReadAll(r.Body)
|
||||||
r.Body.Close()
|
r.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
HttpWriter(w, 500, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f := configui.File{}
|
f := configui.File{}
|
||||||
if err := json.Unmarshal(data, &f); err != nil {
|
if err := json.Unmarshal(data, &f); err != nil {
|
||||||
w.WriteHeader(500)
|
HttpWriter(w, 500, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
file, ok := files[f.Alias]
|
file, ok := files[f.Alias]
|
||||||
if !ok {
|
if !ok {
|
||||||
w.WriteHeader(404)
|
HttpWriter(w, 404, "file not found")
|
||||||
w.Write([]byte("file not found"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := file.Write([]byte(f.Data)); err != nil {
|
if err := file.Write([]byte(f.Data)); err != nil {
|
||||||
w.WriteHeader(500)
|
HttpWriter(w, 500, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Write([]byte("ok"))
|
w.Write([]byte("ok"))
|
||||||
|
@ -79,14 +71,12 @@ func Apply(w http.ResponseWriter, r *http.Request) {
|
||||||
name := r.URL.Query().Get("name")
|
name := r.URL.Query().Get("name")
|
||||||
file, ok := files[name]
|
file, ok := files[name]
|
||||||
if name == "" || !ok {
|
if name == "" || !ok {
|
||||||
w.WriteHeader(404)
|
HttpWriter(w, 404, "file not found")
|
||||||
w.Write([]byte("file not found"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
result, err := file.Do()
|
result, err := file.Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
HttpWriter(w, 500, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Write([]byte(result))
|
w.Write([]byte(result))
|
||||||
|
@ -100,3 +90,32 @@ func Download(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Disposition", `attachment; filename="export.tar.gz"`)
|
w.Header().Set("Content-Disposition", `attachment; filename="export.tar.gz"`)
|
||||||
bundle(w, fs, false)
|
bundle(w, fs, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoadConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
|
data, err := ioutil.ReadAll(r.Body)
|
||||||
|
r.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
HttpWriter(w, 500, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ftmp, err := configui.ReadConfig(string(data))
|
||||||
|
if err != nil {
|
||||||
|
HttpWriter(w, 500, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
files = configui.GetFileMap(ftmp)
|
||||||
|
w.Write([]byte("ok"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
|
config := []configui.File{}
|
||||||
|
for _, f := range files {
|
||||||
|
config = append(config, *f)
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
HttpWriter(w, 500, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Write(data)
|
||||||
|
}
|
||||||
|
|
|
@ -70,6 +70,11 @@ func ReadConfig(confstr string) ([]File, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
for i := range conf {
|
||||||
|
if conf[i].Alias == "" {
|
||||||
|
conf[i].Alias = conf[i].Path
|
||||||
|
}
|
||||||
|
}
|
||||||
return conf, nil
|
return conf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
21
main.go
21
main.go
|
@ -3,7 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"embed"
|
"embed"
|
||||||
"errors"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
@ -28,8 +27,11 @@ var (
|
||||||
|
|
||||||
flagBind string
|
flagBind string
|
||||||
flagLogFile string
|
flagLogFile string
|
||||||
|
flagVer bool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var Version = "0.0.0"
|
||||||
|
var Build = "alpha"
|
||||||
var files = map[string]*configui.File{}
|
var files = map[string]*configui.File{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -41,6 +43,7 @@ func init() {
|
||||||
flag.StringVar(&flagAction, "c", "", "cmd to apply")
|
flag.StringVar(&flagAction, "c", "", "cmd to apply")
|
||||||
flag.StringVar(&flagLogFile, "log", "", "log to file")
|
flag.StringVar(&flagLogFile, "log", "", "log to file")
|
||||||
flag.StringVar(&flagBind, "bind", "localhost:8000", "address to bind")
|
flag.StringVar(&flagBind, "bind", "localhost:8000", "address to bind")
|
||||||
|
flag.BoolVar(&flagVer, "v", false, "show version")
|
||||||
flag.Usage = func() {
|
flag.Usage = func() {
|
||||||
fmt.Fprintf(os.Stderr, "Usage: configui [options]\n")
|
fmt.Fprintf(os.Stderr, "Usage: configui [options]\n")
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
|
@ -50,6 +53,10 @@ func init() {
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
if flagVer {
|
||||||
|
fmt.Printf("%v - %v\n", Version, Build)
|
||||||
|
}
|
||||||
|
|
||||||
// setup logging
|
// setup logging
|
||||||
if flagLogFile != "" {
|
if flagLogFile != "" {
|
||||||
f, err := os.OpenFile(flagLogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
f, err := os.OpenFile(flagLogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
@ -72,7 +79,7 @@ func main() {
|
||||||
Action: flagAction,
|
Action: flagAction,
|
||||||
}
|
}
|
||||||
} else if flagConfigPath == "" {
|
} else if flagConfigPath == "" {
|
||||||
log.Fatalln(errors.New("no config found"))
|
log.Println("no config found")
|
||||||
} else {
|
} else {
|
||||||
conf, err := os.ReadFile(flagConfigPath)
|
conf, err := os.ReadFile(flagConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -87,7 +94,15 @@ func main() {
|
||||||
|
|
||||||
// setup routes
|
// setup routes
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
// mux.
|
mux.HandleFunc("/api/conf", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method == "GET" {
|
||||||
|
GetConfig(w, r)
|
||||||
|
} else if r.Method == "POST" {
|
||||||
|
LoadConfig(w, r)
|
||||||
|
} else {
|
||||||
|
w.WriteHeader(404)
|
||||||
|
}
|
||||||
|
})
|
||||||
mux.HandleFunc("/api/files", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/api/files", func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method == "GET" {
|
if r.Method == "GET" {
|
||||||
ListFiles(w, r)
|
ListFiles(w, r)
|
||||||
|
|
18
util.go
18
util.go
|
@ -7,11 +7,19 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func LogMiddleware(next http.Handler) http.Handler {
|
func LogMiddleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(
|
return http.HandlerFunc(
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer func() {
|
||||||
|
r := recover()
|
||||||
|
if r != nil {
|
||||||
|
log.Println("panic", r)
|
||||||
|
w.WriteHeader(500)
|
||||||
|
}
|
||||||
|
}()
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
log.Printf("%s %s %s %s\n", r.RemoteAddr, r.Method, r.URL, r.Header.Get("User-Agent"))
|
log.Printf("%s %s %s %s\n", r.RemoteAddr, r.Method, r.URL, r.Header.Get("User-Agent"))
|
||||||
},
|
},
|
||||||
|
@ -47,6 +55,11 @@ func bundle(buf io.Writer, paths []string, flat bool) error {
|
||||||
// not be preserved
|
// not be preserved
|
||||||
// https://golang.org/src/archive/tar/common.go?#L626
|
// https://golang.org/src/archive/tar/common.go?#L626
|
||||||
if !flat {
|
if !flat {
|
||||||
|
if !strings.HasPrefix(file, "/") {
|
||||||
|
file = "configui/" + file
|
||||||
|
} else {
|
||||||
|
file = "configui" + file
|
||||||
|
}
|
||||||
header.Name = file
|
header.Name = file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,3 +83,8 @@ func bundle(buf io.Writer, paths []string, flat bool) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HttpWriter(w http.ResponseWriter, status int, errStr string) {
|
||||||
|
w.WriteHeader(status)
|
||||||
|
w.Write([]byte(errStr))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue