refact: use klog and ksrv
continuous-integration/drone/tag Build is passing
Details
continuous-integration/drone/tag Build is passing
Details
parent
cff4c13b78
commit
239be22094
|
@ -3,11 +3,11 @@ package main
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
log "kumoly.io/lib/klog"
|
||||||
|
|
||||||
"kumoly.io/tools/configui"
|
"kumoly.io/tools/configui"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -55,17 +55,6 @@ func main() {
|
||||||
|
|
||||||
cui := configui.New()
|
cui := configui.New()
|
||||||
|
|
||||||
// setup logging
|
|
||||||
if flagLogFile != "" {
|
|
||||||
f, err := os.OpenFile(flagLogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error opening file: %v", err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
mwriter := io.MultiWriter(f, os.Stderr)
|
|
||||||
log.SetOutput(mwriter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup values
|
// setup values
|
||||||
if flagPath != "" {
|
if flagPath != "" {
|
||||||
if flagName == "" {
|
if flagName == "" {
|
||||||
|
@ -77,18 +66,21 @@ func main() {
|
||||||
Action: flagAction,
|
Action: flagAction,
|
||||||
}
|
}
|
||||||
if err := cui.AppendFile(file); err != nil {
|
if err := cui.AppendFile(file); err != nil {
|
||||||
log.Fatalln(err)
|
log.Error(err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else if flagConfigPath == "" {
|
} else if flagConfigPath == "" {
|
||||||
log.Println("no config specified")
|
log.Error("no config specified")
|
||||||
} else {
|
} else {
|
||||||
conf, err := os.ReadFile(flagConfigPath)
|
conf, err := os.ReadFile(flagConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Error(err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
cui.LoadConfig(string(conf))
|
cui.LoadConfig(string(conf))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Error(err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +106,10 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// start server
|
// start server
|
||||||
log.Println("Listening on", flagBind)
|
log.Info("Listening on ", flagBind)
|
||||||
log.Fatal(server.ListenAndServe())
|
err := server.ListenAndServe()
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
71
configui.go
71
configui.go
|
@ -1,13 +1,17 @@
|
||||||
package configui
|
package configui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"embed"
|
"embed"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"kumoly.io/lib/klog"
|
||||||
"kumoly.io/tools/configui/public"
|
"kumoly.io/tools/configui/public"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,6 +34,7 @@ var Ext2Mode map[string]string = map[string]string{
|
||||||
|
|
||||||
type ConfigUI struct {
|
type ConfigUI struct {
|
||||||
AppName string `json:"app_name"`
|
AppName string `json:"app_name"`
|
||||||
|
Prod bool `json:"production"`
|
||||||
BaseUrl string `json:"base_url"`
|
BaseUrl string `json:"base_url"`
|
||||||
ConfigPath string `json:"config_path"`
|
ConfigPath string `json:"config_path"`
|
||||||
|
|
||||||
|
@ -46,11 +51,14 @@ type ConfigUI struct {
|
||||||
|
|
||||||
// Should be in main app
|
// Should be in main app
|
||||||
LogPath string `json:"log_path"`
|
LogPath string `json:"log_path"`
|
||||||
SilentSysOut bool `json:"silent_sys_out"`
|
LogLevel int `json:"log_level"`
|
||||||
|
|
||||||
TmplFS embed.FS `json:"-"`
|
TmplFS embed.FS `json:"-"`
|
||||||
tmpl *template.Template
|
tmpl *template.Template
|
||||||
PublicFS embed.FS `json:"-"`
|
PublicFS embed.FS `json:"-"`
|
||||||
|
log *klog.Logger `json:"-"`
|
||||||
|
ksrv_log *klog.Logger `json:"-"`
|
||||||
|
f *os.File `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *ConfigUI {
|
func New() *ConfigUI {
|
||||||
|
@ -65,6 +73,7 @@ func New() *ConfigUI {
|
||||||
}).ParseFS(tmplFS, "templates/*.tmpl", "templates/**/*.tmpl"))
|
}).ParseFS(tmplFS, "templates/*.tmpl", "templates/**/*.tmpl"))
|
||||||
return &ConfigUI{
|
return &ConfigUI{
|
||||||
fileIndex: map[string]int{},
|
fileIndex: map[string]int{},
|
||||||
|
Prod: true,
|
||||||
AppName: "ConfigUI",
|
AppName: "ConfigUI",
|
||||||
BaseUrl: "/",
|
BaseUrl: "/",
|
||||||
PublicFS: public.FS,
|
PublicFS: public.FS,
|
||||||
|
@ -72,6 +81,8 @@ func New() *ConfigUI {
|
||||||
tmpl: tmpl,
|
tmpl: tmpl,
|
||||||
CmdTimeout: "10s",
|
CmdTimeout: "10s",
|
||||||
cmdTimeout: time.Second * 10,
|
cmdTimeout: time.Second * 10,
|
||||||
|
LogLevel: klog.Lerror | klog.Linfo,
|
||||||
|
log: klog.Sub("ConfigUI"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +92,7 @@ func (cui *ConfigUI) File(file_name string) (*File, error) {
|
||||||
Path: cui.ConfigPath,
|
Path: cui.ConfigPath,
|
||||||
Name: cui.AppName,
|
Name: cui.AppName,
|
||||||
Lang: "json",
|
Lang: "json",
|
||||||
|
owner: cui,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
index, ok := cui.fileIndex[file_name]
|
index, ok := cui.fileIndex[file_name]
|
||||||
|
@ -103,6 +115,7 @@ func (cui *ConfigUI) LoadConfig(confstr string) error {
|
||||||
if f.Name == "" {
|
if f.Name == "" {
|
||||||
f.Name = f.Path
|
f.Name = f.Path
|
||||||
}
|
}
|
||||||
|
f.owner = cui
|
||||||
tmpIndex[f.Name] = i
|
tmpIndex[f.Name] = i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,15 +123,21 @@ func (cui *ConfigUI) LoadConfig(confstr string) error {
|
||||||
cui.fileIndex = tmpIndex
|
cui.fileIndex = tmpIndex
|
||||||
cui.Files = tmpConf.Files
|
cui.Files = tmpConf.Files
|
||||||
cui.AllowIP = tmpConf.AllowIP
|
cui.AllowIP = tmpConf.AllowIP
|
||||||
|
cui.Prod = tmpConf.Prod
|
||||||
cui.ConfigPath = tmpConf.ConfigPath
|
cui.ConfigPath = tmpConf.ConfigPath
|
||||||
cui.HideConfig = tmpConf.HideConfig
|
cui.HideConfig = tmpConf.HideConfig
|
||||||
cui.LogPath = tmpConf.LogPath
|
|
||||||
cui.NoReconfig = tmpConf.NoReconfig
|
cui.NoReconfig = tmpConf.NoReconfig
|
||||||
|
|
||||||
cui.AppName = tmpConf.AppName
|
cui.AppName = tmpConf.AppName
|
||||||
|
if cui.AppName == "" {
|
||||||
|
cui.AppName = "ConfigUI"
|
||||||
|
}
|
||||||
|
|
||||||
cui.BaseUrl = tmpConf.BaseUrl
|
cui.BaseUrl = tmpConf.BaseUrl
|
||||||
if cui.BaseUrl == "" {
|
if cui.BaseUrl == "" {
|
||||||
cui.BaseUrl = "/"
|
cui.BaseUrl = "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
ct, err := time.ParseDuration(tmpConf.CmdTimeout)
|
ct, err := time.ParseDuration(tmpConf.CmdTimeout)
|
||||||
if err != nil || cui.CmdTimeout == "" {
|
if err != nil || cui.CmdTimeout == "" {
|
||||||
cui.CmdTimeout = "10s"
|
cui.CmdTimeout = "10s"
|
||||||
|
@ -128,13 +147,48 @@ func (cui *ConfigUI) LoadConfig(confstr string) error {
|
||||||
cui.cmdTimeout = ct
|
cui.cmdTimeout = ct
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cui.log = klog.Sub(cui.AppName)
|
||||||
|
|
||||||
// NOT implemented
|
// NOT implemented
|
||||||
cui.ResultBellow = tmpConf.ResultBellow
|
cui.ResultBellow = tmpConf.ResultBellow
|
||||||
cui.SilentSysOut = tmpConf.SilentSysOut
|
|
||||||
|
cui.LogLevel = tmpConf.LogLevel
|
||||||
|
cui.LogPath = tmpConf.LogPath
|
||||||
|
cui.setLog()
|
||||||
// fmt.Printf("%+v", cui)
|
// fmt.Printf("%+v", cui)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cui *ConfigUI) setLog() {
|
||||||
|
var err error
|
||||||
|
if cui.f != nil {
|
||||||
|
cui.f.Close()
|
||||||
|
}
|
||||||
|
if cui.LogPath != "" {
|
||||||
|
cui.f, err = os.OpenFile(cui.LogPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
cui.log.Error(err)
|
||||||
|
}
|
||||||
|
cui.log.SetErrOutput(cui.f)
|
||||||
|
cui.log.SetOutput(cui.f)
|
||||||
|
cui.log.Reload()
|
||||||
|
if cui.ksrv_log != nil {
|
||||||
|
cui.ksrv_log.SetErrOutput(cui.f)
|
||||||
|
cui.ksrv_log.SetOutput(cui.f)
|
||||||
|
cui.ksrv_log.Reload()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cui.log.SetErrOutput(os.Stderr)
|
||||||
|
cui.log.SetOutput(os.Stderr)
|
||||||
|
cui.log.Reload()
|
||||||
|
if cui.ksrv_log != nil {
|
||||||
|
cui.ksrv_log.SetErrOutput(os.Stderr)
|
||||||
|
cui.ksrv_log.SetOutput(os.Stderr)
|
||||||
|
cui.ksrv_log.Reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (cui *ConfigUI) Config() ([]byte, error) {
|
func (cui *ConfigUI) Config() ([]byte, error) {
|
||||||
return json.MarshalIndent(cui, "", " ")
|
return json.MarshalIndent(cui, "", " ")
|
||||||
}
|
}
|
||||||
|
@ -143,6 +197,7 @@ func (cui *ConfigUI) AppendFile(file *File) error {
|
||||||
if file.Name == "" {
|
if file.Name == "" {
|
||||||
file.Name = file.Path
|
file.Name = file.Path
|
||||||
}
|
}
|
||||||
|
file.owner = cui
|
||||||
i, ok := cui.fileIndex[file.Name]
|
i, ok := cui.fileIndex[file.Name]
|
||||||
if ok {
|
if ok {
|
||||||
return fmt.Errorf("%v already exists at %d", file.Name, i)
|
return fmt.Errorf("%v already exists at %d", file.Name, i)
|
||||||
|
@ -151,3 +206,13 @@ func (cui *ConfigUI) AppendFile(file *File) error {
|
||||||
cui.Files = append(cui.Files, file)
|
cui.Files = append(cui.Files, file)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cui *ConfigUI) Parse(w http.ResponseWriter, name string, data interface{}) error {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
err := cui.tmpl.ExecuteTemplate(buf, "home", data)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_, err = w.Write(buf.Bytes())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
33
file.go
33
file.go
|
@ -1,9 +1,7 @@
|
||||||
package configui
|
package configui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -26,6 +24,7 @@ type File struct {
|
||||||
Data string `json:"data"`
|
Data string `json:"data"`
|
||||||
|
|
||||||
lock sync.RWMutex `json:"-"`
|
lock sync.RWMutex `json:"-"`
|
||||||
|
owner *ConfigUI `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) Read() ([]byte, error) {
|
func (f *File) Read() ([]byte, error) {
|
||||||
|
@ -33,7 +32,7 @@ func (f *File) Read() ([]byte, error) {
|
||||||
defer f.lock.RUnlock()
|
defer f.lock.RUnlock()
|
||||||
data, err := os.ReadFile(f.Path)
|
data, err := os.ReadFile(f.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
f.owner.log.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return data, nil
|
return data, nil
|
||||||
|
@ -64,7 +63,7 @@ func (f *File) Do(CmdTimeout time.Duration) (string, error) {
|
||||||
} else {
|
} else {
|
||||||
cmd = exec.Command(UNIX_SHELL, "-c", f.Action)
|
cmd = exec.Command(UNIX_SHELL, "-c", f.Action)
|
||||||
}
|
}
|
||||||
log.Println("DO: ", f.Action)
|
f.owner.log.Info("DO: ", f.Action)
|
||||||
done := make(chan string, 1)
|
done := make(chan string, 1)
|
||||||
go func() {
|
go func() {
|
||||||
out, _ := cmd.CombinedOutput()
|
out, _ := cmd.CombinedOutput()
|
||||||
|
@ -77,32 +76,10 @@ func (f *File) Do(CmdTimeout time.Duration) (string, error) {
|
||||||
select {
|
select {
|
||||||
case <-time.After(CmdTimeout):
|
case <-time.After(CmdTimeout):
|
||||||
cmd.Process.Kill()
|
cmd.Process.Kill()
|
||||||
log.Println("timeout")
|
f.owner.log.Error("timeout")
|
||||||
return "", errors.New("command timeout")
|
return "", errors.New("command timeout")
|
||||||
case out := <-done:
|
case out := <-done:
|
||||||
log.Printf("\n%v", out)
|
f.owner.log.Info("\n", out)
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadConfig(confstr string) ([]File, error) {
|
|
||||||
conf := []File{}
|
|
||||||
err := json.Unmarshal([]byte(confstr), &conf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for i := range conf {
|
|
||||||
if conf[i].Name == "" {
|
|
||||||
conf[i].Name = conf[i].Path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return conf, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetFileMap(files []File) map[string]*File {
|
|
||||||
fileMap := map[string]*File{}
|
|
||||||
for i := range files {
|
|
||||||
fileMap[files[i].Name] = &files[i]
|
|
||||||
}
|
|
||||||
return fileMap
|
|
||||||
}
|
|
||||||
|
|
10
go.mod
10
go.mod
|
@ -1,3 +1,13 @@
|
||||||
module kumoly.io/tools/configui
|
module kumoly.io/tools/configui
|
||||||
|
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
|
require (
|
||||||
|
kumoly.io/lib/klog v0.1.9
|
||||||
|
kumoly.io/lib/ksrv v0.1.4
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
kumoly.io/lib/klog v0.1.9 h1:rS9PPqfyBIIfeQlPSuMv+7StGPiFVuAdp04HDwwDY3E=
|
||||||
|
kumoly.io/lib/klog v0.1.9/go.mod h1:Snm+c1xRrh/RbXsxQf7UGYbAJGPcIa6bEEN+CmzJh7M=
|
||||||
|
kumoly.io/lib/ksrv v0.1.4 h1:8zbslRwdNWHw5Wm1PiyDLr6Mu4xxjz0FTW4u8dZ6ZeI=
|
||||||
|
kumoly.io/lib/ksrv v0.1.4/go.mod h1:eKfhJR5mOqlQZAy5EUI+Avfxirx2/nNW79r+Ki2C18k=
|
12
handler.go
12
handler.go
|
@ -8,6 +8,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"kumoly.io/lib/ksrv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cui *ConfigUI) ListFiles(w http.ResponseWriter, r *http.Request) {
|
func (cui *ConfigUI) ListFiles(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -22,7 +24,7 @@ func (cui *ConfigUI) GetFile(w http.ResponseWriter, r *http.Request) {
|
||||||
name := r.URL.Query().Get("name")
|
name := r.URL.Query().Get("name")
|
||||||
file, err := cui.File(name)
|
file, err := cui.File(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response(w, 404, []byte("file not found"))
|
ksrv.Response(w, 404, []byte("file not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data, err := file.Read()
|
data, err := file.Read()
|
||||||
|
@ -55,7 +57,7 @@ func (cui *ConfigUI) GetDelta(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
file, err := cui.File(name)
|
file, err := cui.File(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response(w, 404, []byte("file not found"))
|
ksrv.Response(w, 404, []byte("file not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f, err := os.Open(file.Path)
|
f, err := os.Open(file.Path)
|
||||||
|
@ -106,7 +108,7 @@ func (cui *ConfigUI) PostFile(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
file, err := cui.File(f.Name)
|
file, err := cui.File(f.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response(w, 404, []byte("file not found"))
|
ksrv.Response(w, 404, []byte("file not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := file.Write([]byte(f.Data)); err != nil {
|
if err := file.Write([]byte(f.Data)); err != nil {
|
||||||
|
@ -119,7 +121,7 @@ func (cui *ConfigUI) Apply(w http.ResponseWriter, r *http.Request) {
|
||||||
name := r.URL.Query().Get("name")
|
name := r.URL.Query().Get("name")
|
||||||
file, err := cui.File(name)
|
file, err := cui.File(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response(w, 404, []byte("file not found"))
|
ksrv.Response(w, 404, []byte("file not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
result, err := file.Do(cui.cmdTimeout)
|
result, err := file.Do(cui.cmdTimeout)
|
||||||
|
@ -145,7 +147,7 @@ func (cui *ConfigUI) Download(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
file, err := cui.File(name)
|
file, err := cui.File(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response(w, 404, []byte("file not found"))
|
ksrv.Response(w, 404, []byte("file not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data, err := file.Read()
|
data, err := file.Read()
|
||||||
|
|
69
netutil.go
69
netutil.go
|
@ -1,69 +0,0 @@
|
||||||
package configui
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CuiResponseWriter struct {
|
|
||||||
http.ResponseWriter
|
|
||||||
StatueCode int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *CuiResponseWriter) WriteHeader(statusCode int) {
|
|
||||||
if w.StatueCode != 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.StatueCode = statusCode
|
|
||||||
w.ResponseWriter.WriteHeader(statusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *CuiResponseWriter) Write(body []byte) (int, error) {
|
|
||||||
if w.StatueCode == 0 {
|
|
||||||
w.WriteHeader(200)
|
|
||||||
}
|
|
||||||
return w.ResponseWriter.Write(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
func response(w http.ResponseWriter, status int, body []byte) (int, error) {
|
|
||||||
w.WriteHeader(status)
|
|
||||||
return w.Write(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
func abort(w http.ResponseWriter, err interface{}) (int, error) {
|
|
||||||
log.Println(err)
|
|
||||||
switch v := err.(type) {
|
|
||||||
case int:
|
|
||||||
w.WriteHeader(v)
|
|
||||||
return w.Write([]byte(strconv.Itoa(v)))
|
|
||||||
case string:
|
|
||||||
w.WriteHeader(500)
|
|
||||||
return w.Write([]byte(v))
|
|
||||||
case error:
|
|
||||||
w.WriteHeader(500)
|
|
||||||
return w.Write([]byte(v.Error()))
|
|
||||||
default:
|
|
||||||
w.WriteHeader(500)
|
|
||||||
return w.Write([]byte(strconv.Itoa(500)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func catch(rw *CuiResponseWriter, r *http.Request) {
|
|
||||||
ex := recover()
|
|
||||||
if ex != nil {
|
|
||||||
abort(rw, ex)
|
|
||||||
log.Printf("%s %s %d %s %s\n", GetIP(r), r.Method, rw.StatueCode, r.URL, r.Header.Get("User-Agent"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cui *ConfigUI) Parse(w http.ResponseWriter, name string, data interface{}) error {
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
err := cui.tmpl.ExecuteTemplate(buf, "home", data)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
_, err = w.Write(buf.Bytes())
|
|
||||||
return err
|
|
||||||
}
|
|
30
server.go
30
server.go
|
@ -1,9 +1,10 @@
|
||||||
package configui
|
package configui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"kumoly.io/lib/ksrv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cui *ConfigUI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (cui *ConfigUI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -11,25 +12,28 @@ func (cui *ConfigUI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cui *ConfigUI) middleware(next http.Handler) http.Handler {
|
func (cui *ConfigUI) middleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(
|
k := ksrv.New()
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
cui.ksrv_log = k.GetLogger()
|
||||||
// log.Println(r.URL)
|
cui.setLog()
|
||||||
rw := &CuiResponseWriter{w, 0}
|
k.SetNoLogCondition(func(r *http.Request) bool {
|
||||||
defer catch(rw, r)
|
if strings.HasPrefix(r.URL.Path, "/public") || r.URL.Query().Get("f") == "true" {
|
||||||
ip := GetIP(r)
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
return k.Middleware(
|
||||||
|
http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
if cui.AllowIP != "" {
|
if cui.AllowIP != "" {
|
||||||
if !matchIPGlob(ip, cui.AllowIP) {
|
ip := ksrv.GetIP(r)
|
||||||
|
if !ksrv.MatchIPGlob(ip, cui.AllowIP) {
|
||||||
rw.WriteHeader(403)
|
rw.WriteHeader(403)
|
||||||
panic("permission denied")
|
panic("permission denied")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
next.ServeHTTP(rw, r)
|
next.ServeHTTP(rw, r)
|
||||||
//logging
|
}),
|
||||||
if !strings.HasPrefix(r.URL.Path, "/public") && r.URL.Query().Get("f") != "true" {
|
|
||||||
log.Printf("%s %s %d %s %s\n", ip, r.Method, rw.StatueCode, r.URL, r.Header.Get("User-Agent"))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cui *ConfigUI) mux() *http.ServeMux {
|
func (cui *ConfigUI) mux() *http.ServeMux {
|
||||||
|
|
62
util.go
62
util.go
|
@ -4,55 +4,10 @@ import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func matchIPGlob(ip, pattern string) bool {
|
|
||||||
parts := strings.Split(pattern, ".")
|
|
||||||
seg := strings.Split(ip, ".")
|
|
||||||
for i, part := range parts {
|
|
||||||
|
|
||||||
// normalize pattern to 3 digits
|
|
||||||
switch len(part) {
|
|
||||||
case 1:
|
|
||||||
if part == "*" {
|
|
||||||
part = "***"
|
|
||||||
} else {
|
|
||||||
part = "00" + part
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
if strings.HasPrefix(part, "*") {
|
|
||||||
part = "*" + part
|
|
||||||
} else if strings.HasSuffix(part, "*") {
|
|
||||||
part = part + "*"
|
|
||||||
} else {
|
|
||||||
part = "0" + part
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// normalize ip to 3 digits
|
|
||||||
switch len(seg[i]) {
|
|
||||||
case 1:
|
|
||||||
seg[i] = "00" + seg[i]
|
|
||||||
case 2:
|
|
||||||
seg[i] = "0" + seg[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
for j := range part {
|
|
||||||
if string(part[j]) == "*" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if part[j] != seg[i][j] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func bundle(buf io.Writer, paths []string, rootDir string, flat bool) error {
|
func bundle(buf io.Writer, paths []string, rootDir string, flat bool) error {
|
||||||
gw := gzip.NewWriter(buf)
|
gw := gzip.NewWriter(buf)
|
||||||
defer gw.Close()
|
defer gw.Close()
|
||||||
|
@ -110,20 +65,3 @@ func bundle(buf io.Writer, paths []string, rootDir string, flat bool) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetIP(r *http.Request) string {
|
|
||||||
ip := r.Header.Get("X-Real-Ip")
|
|
||||||
if ip == "" {
|
|
||||||
ips := r.Header.Get("X-Forwarded-For")
|
|
||||||
ipArr := strings.Split(ips, ",")
|
|
||||||
ip = strings.Trim(ipArr[len(ipArr)-1], " ")
|
|
||||||
}
|
|
||||||
if ip == "" {
|
|
||||||
var err error
|
|
||||||
ip, _, err = net.SplitHostPort(r.RemoteAddr)
|
|
||||||
if err != nil {
|
|
||||||
ip = r.RemoteAddr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ip
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue