Compare commits
No commits in common. "ef76eff2289cbbdda810577d620ea3918ad36e75" and "091c026a46714af377b49b32447b672da8fea763" have entirely different histories.
ef76eff228
...
091c026a46
4
app.go
4
app.go
|
@ -12,7 +12,7 @@ type ActiveFile struct {
|
|||
RO bool
|
||||
Path string
|
||||
Name string
|
||||
Cmd string
|
||||
Action string
|
||||
Content string
|
||||
Order int
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ func (cui *ConfigUI) App(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
} else {
|
||||
tmp, err = file.Read()
|
||||
data.File.Cmd = file.Cmd
|
||||
data.File.Action = file.Action
|
||||
data.File.Name = file.Name
|
||||
if file.Lang != "" {
|
||||
data.Editor.Lang = file.Lang
|
||||
|
|
15
configui.go
15
configui.go
|
@ -19,7 +19,7 @@ import (
|
|||
var UNIX_SHELL = "sh"
|
||||
var WIN_SHELL = "cmd"
|
||||
|
||||
const version = "v0.1.11"
|
||||
const version = "v0.1.10"
|
||||
|
||||
//go:embed templates
|
||||
var tmplFS embed.FS
|
||||
|
@ -34,17 +34,14 @@ var Ext2Mode map[string]string = map[string]string{
|
|||
}
|
||||
|
||||
type Action struct {
|
||||
Name string `json:"name"`
|
||||
Cmd string `json:"cmd"`
|
||||
run chan struct{} `json:"-"`
|
||||
pid int `json:"-"`
|
||||
Name string `json:"name"`
|
||||
Cmd string `json:"cmd"`
|
||||
}
|
||||
|
||||
type Integration struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Cmd func() (string, error) `json:"-"`
|
||||
run chan struct{} `json:"-"`
|
||||
}
|
||||
|
||||
type ConfigUI struct {
|
||||
|
@ -139,12 +136,6 @@ func (cui *ConfigUI) LoadConfig(confstr string) error {
|
|||
}
|
||||
f.owner = cui
|
||||
tmpIndex[f.Name] = i
|
||||
|
||||
// deprecated fix
|
||||
if f.Cmd == "" && f.Action != "" {
|
||||
f.Cmd = f.Action
|
||||
f.Action = ""
|
||||
}
|
||||
}
|
||||
|
||||
// copy
|
||||
|
|
53
file.go
53
file.go
|
@ -1,9 +1,7 @@
|
|||
package configui
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
|
@ -12,9 +10,9 @@ import (
|
|||
)
|
||||
|
||||
type File struct {
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Cmd string `json:"cmd"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Action string `json:"action"`
|
||||
// RO is readonly
|
||||
RO bool `json:"ro"`
|
||||
Lang string `json:"lang"`
|
||||
|
@ -25,13 +23,8 @@ type File struct {
|
|||
// used for parsing post data
|
||||
Data string `json:"data,omitempty"`
|
||||
|
||||
lock sync.RWMutex `json:"-"`
|
||||
owner *ConfigUI `json:"-"`
|
||||
run chan struct{} `json:"-"`
|
||||
pid int `json:"-"`
|
||||
|
||||
// deprecated
|
||||
Action string `json:"action,omitempty"`
|
||||
lock sync.RWMutex `json:"-"`
|
||||
owner *ConfigUI `json:"-"`
|
||||
}
|
||||
|
||||
func (f *File) Read() ([]byte, error) {
|
||||
|
@ -59,42 +52,26 @@ func (f *File) Write(data []byte) error {
|
|||
}
|
||||
|
||||
func (f *File) Do(CmdTimeout time.Duration) (string, error) {
|
||||
if f.Cmd == "" {
|
||||
if f.Action == "" {
|
||||
return "", nil
|
||||
}
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
// limit running instance to 1
|
||||
if cap(f.run) == 0 {
|
||||
f.run = make(chan struct{}, 1)
|
||||
}
|
||||
select {
|
||||
case f.run <- struct{}{}:
|
||||
defer func() { <-f.run }()
|
||||
default:
|
||||
f.owner.log.Error("task is running: ", f.Name)
|
||||
return "", fmt.Errorf("another task of %s is running with pid: %d", f.Name, f.pid)
|
||||
}
|
||||
|
||||
// prepare cmd
|
||||
cmd := &exec.Cmd{}
|
||||
if runtime.GOOS == "windows" {
|
||||
cmd = exec.Command(WIN_SHELL, "/c", f.Cmd)
|
||||
cmd = exec.Command(WIN_SHELL, "/c", f.Action)
|
||||
} else {
|
||||
cmd = exec.Command(UNIX_SHELL, "-c", f.Cmd)
|
||||
cmd = exec.Command(UNIX_SHELL, "-c", f.Action)
|
||||
}
|
||||
f.owner.log.Info("DO: ", f.Cmd)
|
||||
f.owner.log.Info("DO: ", f.Action)
|
||||
done := make(chan string, 1)
|
||||
go func() {
|
||||
|
||||
var b bytes.Buffer
|
||||
cmd.Stdout = &b
|
||||
cmd.Stderr = &b
|
||||
cmd.Start()
|
||||
f.pid = cmd.Process.Pid
|
||||
cmd.Wait()
|
||||
done <- b.String()
|
||||
out, _ := cmd.CombinedOutput()
|
||||
// real cmd err is unhandled, but passed to client
|
||||
// if err != nil {
|
||||
// return string(out), err
|
||||
// }
|
||||
done <- string(out)
|
||||
}()
|
||||
select {
|
||||
case <-time.After(CmdTimeout):
|
||||
|
|
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module kumoly.io/tools/configui
|
|||
go 1.17
|
||||
|
||||
require (
|
||||
kumoly.io/lib/klog v0.0.8
|
||||
kumoly.io/lib/klog v0.0.5
|
||||
kumoly.io/lib/ksrv v0.0.1
|
||||
)
|
||||
|
||||
|
|
5
go.sum
5
go.sum
|
@ -3,8 +3,9 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
|||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
kumoly.io/lib/klog v0.0.4 h1:Ev9G/zvLt/C8Q1yWfYoUcXVJWgPMjpqHPat2WKyOPIM=
|
||||
kumoly.io/lib/klog v0.0.4/go.mod h1:Snm+c1xRrh/RbXsxQf7UGYbAJGPcIa6bEEN+CmzJh7M=
|
||||
kumoly.io/lib/klog v0.0.8 h1:6hTfDlZh7KGnPrd2tUrauCKRImSnyyN9DHXpey3Czn8=
|
||||
kumoly.io/lib/klog v0.0.8/go.mod h1:Snm+c1xRrh/RbXsxQf7UGYbAJGPcIa6bEEN+CmzJh7M=
|
||||
kumoly.io/lib/klog v0.0.5 h1:8Z2FYpW01gxt2gbRJNag8f8KSsfd1pRleQTPJvoR8Zc=
|
||||
kumoly.io/lib/klog v0.0.5/go.mod h1:Snm+c1xRrh/RbXsxQf7UGYbAJGPcIa6bEEN+CmzJh7M=
|
||||
kumoly.io/lib/ksrv v0.0.1 h1:JfWwJ9GeiTtDfGoeG7YxJwsckralbhsLKEPLQb20Uzo=
|
||||
kumoly.io/lib/ksrv v0.0.1/go.mod h1:ykHXeAPjNvA5jEZo5rp32edzkugLf0e+2pspct3FOFQ=
|
||||
|
|
53
handler.go
53
handler.go
|
@ -8,7 +8,6 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"kumoly.io/lib/ksrv"
|
||||
)
|
||||
|
@ -37,11 +36,11 @@ func (cui *ConfigUI) GetFile(w http.ResponseWriter, r *http.Request) {
|
|||
panic(err)
|
||||
}
|
||||
response, err := json.Marshal(map[string]string{
|
||||
"path": file.Path,
|
||||
"name": file.Name,
|
||||
"cmd": file.Cmd,
|
||||
"data": string(data),
|
||||
"delta": strconv.Itoa(int(stat.Size())),
|
||||
"path": file.Path,
|
||||
"name": file.Name,
|
||||
"action": file.Action,
|
||||
"data": string(data),
|
||||
"delta": strconv.Itoa(int(stat.Size())),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -81,11 +80,11 @@ func (cui *ConfigUI) GetDelta(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
response, err := json.Marshal(map[string]string{
|
||||
"path": file.Path,
|
||||
"name": file.Name,
|
||||
"cmd": file.Cmd,
|
||||
"data": string(buf),
|
||||
"delta": strconv.Itoa(int(stat.Size())),
|
||||
"path": file.Path,
|
||||
"name": file.Name,
|
||||
"action": file.Action,
|
||||
"data": string(buf),
|
||||
"delta": strconv.Itoa(int(stat.Size())),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -131,25 +130,9 @@ func (cui *ConfigUI) Apply(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func (cui *ConfigUI) DoAction(w http.ResponseWriter, r *http.Request) {
|
||||
name := r.URL.Query().Get("name")
|
||||
for i, v := range cui.Actions {
|
||||
for _, v := range cui.Actions {
|
||||
if v.Name == name {
|
||||
|
||||
// limit running instance to one
|
||||
if cap(cui.Actions[i].run) != 1 {
|
||||
cui.Actions[i].run = make(chan struct{}, 1)
|
||||
}
|
||||
select {
|
||||
case cui.Actions[i].run <- struct{}{}:
|
||||
defer func() { <-cui.Actions[i].run }()
|
||||
default:
|
||||
panic(fmt.Errorf("another task of %s is running with pid: %d", name, v.pid))
|
||||
}
|
||||
|
||||
file := &File{Name: name, Action: v.Cmd, owner: cui}
|
||||
go func() {
|
||||
<-time.After(time.Millisecond * 10)
|
||||
cui.Actions[i].pid = file.pid
|
||||
}()
|
||||
result, err := file.Do(cui.cmdTimeout)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -163,20 +146,8 @@ func (cui *ConfigUI) DoAction(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func (cui *ConfigUI) DoIntegration(w http.ResponseWriter, r *http.Request) {
|
||||
name := r.URL.Query().Get("name")
|
||||
for i, v := range cui.Integrations {
|
||||
for _, v := range cui.Integrations {
|
||||
if v.Name == name {
|
||||
|
||||
// limit running instance to one
|
||||
if cap(cui.Integrations[i].run) != 1 {
|
||||
cui.Integrations[i].run = make(chan struct{}, 1)
|
||||
}
|
||||
select {
|
||||
case cui.Integrations[i].run <- struct{}{}:
|
||||
defer func() { <-cui.Integrations[i].run }()
|
||||
default:
|
||||
panic(fmt.Errorf("another task of %s is running", name))
|
||||
}
|
||||
|
||||
result, err := v.Cmd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{define "components/error"}}
|
||||
<div class="notification is-danger {{if not .Error}}is-hidden{{end}}" id="error_view">
|
||||
<button class="delete" onclick="ErrorClose()"></button>
|
||||
<button class="delete" onclick="ErrorTog()"></button>
|
||||
<p id="err_msg">{{.Error}}</p>
|
||||
</div>
|
||||
<script>
|
||||
|
@ -8,18 +8,10 @@ function ErrorTog(){
|
|||
let el = document.getElementById('error_view');
|
||||
el.classList.toggle('is-hidden');
|
||||
}
|
||||
function ErrorOpen(){
|
||||
let el = document.getElementById('error_view');
|
||||
el.classList.remove('is-hidden');
|
||||
}
|
||||
function ErrorClose(){
|
||||
let el = document.getElementById('error_view');
|
||||
el.classList.add('is-hidden');
|
||||
}
|
||||
function ShowError(msg){
|
||||
let el = document.getElementById('err_msg');
|
||||
el.innerHTML = msg;
|
||||
ErrorOpen();
|
||||
ErrorTog();
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
|
@ -21,7 +21,7 @@
|
|||
<ul class="menu-list">
|
||||
<li>
|
||||
<a class="has-tooltip-arrow {{if eq .File.Name .AppName }}is-active{{end}}"
|
||||
data-tooltip="Configuration"
|
||||
data-tooltip="{{$.File.Path}}"
|
||||
href="{{.BaseUrl}}"
|
||||
>Config</a></li>
|
||||
</ul>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<button class="delete" aria-label="close" onclick="ResultViewTog()"></button>
|
||||
</header>
|
||||
<section class="modal-card-body">
|
||||
<p class="title">{{.File.Cmd}}</p>
|
||||
<p class="title">{{.File.Action}}</p>
|
||||
<p class="subtitle">{{.File.Path}}</p>
|
||||
<div id="result_editor"></div>
|
||||
</section>
|
||||
|
|
|
@ -91,10 +91,10 @@
|
|||
{{end}}
|
||||
</p>
|
||||
{{end}}
|
||||
{{if .File.Cmd}}
|
||||
{{if .File.Action}}
|
||||
<p class="control">
|
||||
<button class="button is-small has-tooltip-arrow"
|
||||
data-tooltip="{{.File.Cmd}}"
|
||||
data-tooltip="{{.File.Action}}"
|
||||
onclick="toolApply()">
|
||||
<span class="icon is-small"><span class="material-icons"id="toolApplyIco">
|
||||
play_arrow
|
||||
|
|
Loading…
Reference in New Issue