181 lines
4.0 KiB
Go
181 lines
4.0 KiB
Go
package scripts
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"fmt"
|
||
"github.com/google/uuid"
|
||
"github.com/huoxue1/qinglong-go/service/env"
|
||
"github.com/huoxue1/qinglong-go/utils"
|
||
"io"
|
||
"os"
|
||
"path"
|
||
"path/filepath"
|
||
"sort"
|
||
"strings"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
type File struct {
|
||
Key string `json:"key"`
|
||
Parent string `json:"parent"`
|
||
Title string `json:"title"`
|
||
Type string `json:"type"`
|
||
IsLeaf bool `json:"is_leaf"`
|
||
Children []*File `json:"children"`
|
||
}
|
||
|
||
var (
|
||
excludedFiles = []string{
|
||
"node_modules",
|
||
"__pycache__",
|
||
}
|
||
|
||
scriptRunPidMap sync.Map
|
||
)
|
||
|
||
type task struct {
|
||
id string
|
||
c chan int
|
||
logPath string
|
||
}
|
||
|
||
func Stop(id string) {
|
||
value, loaded := scriptRunPidMap.Load(id)
|
||
if !loaded || value == nil {
|
||
return
|
||
}
|
||
t := value.(*task)
|
||
t.c <- 1
|
||
}
|
||
|
||
func Log(id string) string {
|
||
value, ok := scriptRunPidMap.Load(id)
|
||
if !ok || value == nil {
|
||
return ""
|
||
}
|
||
t := value.(*task)
|
||
file, err := os.ReadFile(t.logPath)
|
||
if err != nil {
|
||
return ""
|
||
}
|
||
return string(file)
|
||
|
||
}
|
||
|
||
func Run(filePath, content string) (string, error) {
|
||
err := os.WriteFile(path.Join("data", "scripts", filePath), []byte(content), 0666)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
id := uuid.New().String()
|
||
logPath := "data/log/" + time.Now().Format("2006-01-02") + "/" + filepath.Base(filePath) + "_" + id + ".log"
|
||
os.Mkdir(filepath.Dir(logPath), 0666)
|
||
dir, cmd := getCmd(filePath)
|
||
cancelChan := make(chan int, 1)
|
||
ctx := context.WithValue(context.Background(), "cancel", cancelChan)
|
||
now := time.Now()
|
||
file, _ := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE, 0666)
|
||
go utils.RunWithOption(ctx, &utils.RunOption{
|
||
Ctx: ctx,
|
||
Command: cmd,
|
||
Env: env.GetALlEnv(),
|
||
OnStart: func(ctx context.Context) {
|
||
writer := ctx.Value("log").(io.Writer)
|
||
_, _ = writer.Write([]byte(fmt.Sprintf("##开始执行.. %s\n\n", now.Format("2006-01-02 15:04:05"))))
|
||
},
|
||
OnEnd: func(ctx context.Context) {
|
||
writer := ctx.Value("log").(io.Writer)
|
||
_, _ = writer.Write([]byte(fmt.Sprintf("\n##执行结束.. %s,耗时%.1f秒\n\n", time.Now().Format("2006-01-02 15:04:05"), time.Now().Sub(now).Seconds())))
|
||
_ = os.Remove(filePath)
|
||
// 等待结束三分钟后再删除
|
||
go func() {
|
||
time.Sleep(time.Minute * 3)
|
||
scriptRunPidMap.LoadAndDelete(id)
|
||
}()
|
||
|
||
},
|
||
LogFile: file,
|
||
CmdDir: dir,
|
||
})
|
||
scriptRunPidMap.Store(id, &task{
|
||
id: id,
|
||
c: cancelChan,
|
||
logPath: logPath,
|
||
})
|
||
return id, nil
|
||
}
|
||
|
||
func getCmd(filePath string) (dir string, cmd string) {
|
||
ext := filepath.Ext(filePath)
|
||
switch ext {
|
||
case ".js":
|
||
return "./data/scripts/", fmt.Sprintf("%s %s", "node", filePath)
|
||
case ".py":
|
||
return "./data/scripts/", fmt.Sprintf("%s %s", "python", filePath)
|
||
case ".go":
|
||
return path.Join("./data/scripts/", filepath.Dir(filePath)), fmt.Sprintf("go run %s", filepath.Base(filePath))
|
||
}
|
||
return "./data/scripts/", ""
|
||
}
|
||
|
||
func GetFiles(base, p string) []*File {
|
||
var files Files
|
||
dir, err := os.ReadDir(path.Join(base, p))
|
||
if err != nil {
|
||
return []*File{}
|
||
}
|
||
for _, entry := range dir {
|
||
if utils.In(entry.Name(), excludedFiles) {
|
||
continue
|
||
}
|
||
if entry.IsDir() {
|
||
f := &File{
|
||
Key: path.Join(p, entry.Name()),
|
||
Parent: p,
|
||
Title: entry.Name(),
|
||
Type: "directory",
|
||
IsLeaf: true,
|
||
Children: GetFiles(base, path.Join(p, entry.Name())),
|
||
}
|
||
files = append(files, f)
|
||
|
||
} else {
|
||
if strings.HasPrefix(entry.Name(), "_") {
|
||
continue
|
||
}
|
||
files = append(files, &File{
|
||
Key: path.Join(p, entry.Name()),
|
||
Parent: p,
|
||
Title: entry.Name(),
|
||
Type: "file",
|
||
IsLeaf: true,
|
||
Children: []*File{},
|
||
})
|
||
}
|
||
}
|
||
sort.Sort(files)
|
||
return files
|
||
}
|
||
|
||
type Files []*File
|
||
|
||
func (a Files) Len() int { // 重写 Len() 方法
|
||
return len(a)
|
||
}
|
||
func (a Files) Swap(i, j int) { // 重写 Swap() 方法
|
||
a[i], a[j] = a[j], a[i]
|
||
}
|
||
func (a Files) Less(i, j int) bool { // 重写 Less() 方法, 从大到小排序
|
||
if a[i].Type != a[j].Type {
|
||
if a[i].Type == "file" {
|
||
return false
|
||
} else {
|
||
return true
|
||
}
|
||
} else {
|
||
return bytes.Compare([]byte(a[i].Title), []byte(a[j].Title)) > 0
|
||
}
|
||
}
|