Evan Chen 2021-10-21 21:49:15 +08:00
parent a2c16da520
commit bc443cc320
13 changed files with 275 additions and 128 deletions

View File

118
bak/util.go Normal file
View File

@ -0,0 +1,118 @@
package main
import (
"archive/tar"
"compress/gzip"
"io"
"os"
"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, flat bool) error {
gw := gzip.NewWriter(buf)
defer gw.Close()
tw := tar.NewWriter(gw)
defer tw.Close()
for _, file := range paths {
if err := func(file string) error {
f, err := os.Open(file)
if err != nil {
return err
}
defer f.Close()
info, err := f.Stat()
if err != nil {
return err
}
header, err := tar.FileInfoHeader(info, info.Name())
if err != nil {
return err
}
// Use full path as name (FileInfoHeader only takes the basename)
// If we don't do this the directory strucuture would
// not be preserved
// https://golang.org/src/archive/tar/common.go?#L626
if !flat {
if !strings.HasPrefix(file, "/") {
file = "configui/" + file
} else {
file = "configui" + file
}
header.Name = file
}
// Write file header to the tar archive
err = tw.WriteHeader(header)
if err != nil {
return err
}
// Copy file content to tar archive
_, err = io.Copy(tw, f)
if err != nil {
return err
}
return nil
}(file); err != nil {
return err
}
}
return nil
}
var ext2mode map[string]string = map[string]string{
"go": "golang",
"log": "sh",
"txt": "text",
"yml": "yaml",
"conf": "ini",
}

1
cmd/configui/main.go Normal file
View File

@ -0,0 +1 @@
package main

42
configui.go Normal file
View File

@ -0,0 +1,42 @@
package configui
var APP_NAME = "ConfigUI"
var UNIX_SHELL = "sh"
var WIN_SHELL = "cmd"
type ConfigUI struct {
ConfigPath string `json:"config_path"`
NoReconfig bool `json:"no_reconfig"`
LogPath string `json:"log_path"`
SilentSysOut bool `json:"silent_sys_out"`
AllowIP string `json:"allow_ip"`
Files []*File `json:"files"`
fileIndex map[string]int
// TODO
ResultBellow bool `json:"result_bellow"`
HideConfig bool `json:"hide_config"`
}
func New() *ConfigUI {
return &ConfigUI{
fileIndex: map[string]int{},
}
}
func (cui *ConfigUI) Get(file_name string) (*File, error) {
if file_name == APP_NAME {
}
return nil, nil
}
func (cui *ConfigUI) LoadConfig(confstr string) {
// construct fileIndex
}
func (cui *ConfigUI) GetConfig() []byte {
return nil
}

101
file.go Normal file
View File

@ -0,0 +1,101 @@
package configui
import (
"encoding/json"
"errors"
"log"
"os"
"os/exec"
"runtime"
"sync"
"time"
)
type File struct {
Path string `json:"path"`
Name string `json:"name"`
Action string `json:"action"`
RO bool `json:"ro"`
Lang string `json:"lang"`
// used for parsing post data
Data string `json:"data"`
lock sync.RWMutex `json:"-"`
}
func (f *File) Read() ([]byte, error) {
f.lock.RLock()
defer f.lock.RUnlock()
data, err := os.ReadFile(f.Path)
if err != nil {
log.Println(err)
return nil, err
}
return data, nil
}
func (f *File) Write(data []byte) error {
if f.RO {
return errors.New("this file has readonly set")
}
f.lock.Lock()
defer f.lock.Unlock()
info, err := os.Stat(f.Path)
if err != nil {
return err
}
return os.WriteFile(f.Path, data, info.Mode())
}
func (f *File) Do() (string, error) {
if f.Action == "" {
return "", nil
}
timeout := time.After(2 * time.Second)
cmd := &exec.Cmd{}
if runtime.GOOS == "windows" {
cmd = exec.Command(WIN_SHELL, "/c", f.Action)
} else {
exec.Command(UNIX_SHELL, "-c", f.Action)
}
var out []byte
done := make(chan struct{}, 1)
go func() {
out, _ = cmd.CombinedOutput()
// real cmd err is only pass down
// if err != nil {
// return string(out), err
// }
done <- struct{}{}
}()
select {
case <-timeout:
cmd.Process.Kill()
return "", errors.New("command timeout")
case <-done:
return string(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
}

1
handler.go Normal file
View File

@ -0,0 +1 @@
package configui

1
server.go Normal file
View File

@ -0,0 +1 @@
package configui

View File

@ -11,16 +11,6 @@
</span></span>
</button>
</p>
<p class="control">
<div class="select is-small">
<select onchange="SetTabstop(this)">
<option value="0">Tabstop</option>
<option value="4">Tabstop 4</option>
<option value="2">Tabstop 2</option>
<option value="-1">Tab</option>
</select>
</div>
</p>
<p class="control">
<button class="button is-small has-tooltip-arrow" id="toolFollow"
data-tooltip="Follow file change (1s)" onclick="toolFollow()">
@ -47,6 +37,16 @@
</span></span>
</button>
</p>
<p class="control">
<div class="select is-small">
<select onchange="SetTabstop(this)">
<option value="0">Tabstop</option>
<option value="4">Tabstop 4</option>
<option value="2">Tabstop 2</option>
<option value="-1">Tab</option>
</select>
</div>
</p>
</div>
</div>

119
util.go
View File

@ -1,118 +1 @@
package main
import (
"archive/tar"
"compress/gzip"
"io"
"os"
"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, flat bool) error {
gw := gzip.NewWriter(buf)
defer gw.Close()
tw := tar.NewWriter(gw)
defer tw.Close()
for _, file := range paths {
if err := func(file string) error {
f, err := os.Open(file)
if err != nil {
return err
}
defer f.Close()
info, err := f.Stat()
if err != nil {
return err
}
header, err := tar.FileInfoHeader(info, info.Name())
if err != nil {
return err
}
// Use full path as name (FileInfoHeader only takes the basename)
// If we don't do this the directory strucuture would
// not be preserved
// https://golang.org/src/archive/tar/common.go?#L626
if !flat {
if !strings.HasPrefix(file, "/") {
file = "configui/" + file
} else {
file = "configui" + file
}
header.Name = file
}
// Write file header to the tar archive
err = tw.WriteHeader(header)
if err != nil {
return err
}
// Copy file content to tar archive
_, err = io.Copy(tw, f)
if err != nil {
return err
}
return nil
}(file); err != nil {
return err
}
}
return nil
}
var ext2mode map[string]string = map[string]string{
"go": "golang",
"log": "sh",
"txt": "text",
"yml": "yaml",
"conf": "ini",
}
package configui