添加脚本调试

This commit is contained in:
huoxue1 2023-02-03 12:43:37 +08:00
parent 0366c23d26
commit d7c362d1cb
30 changed files with 441 additions and 116 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@
*.exe *.exe
*.log *.log
/dist/

View File

@ -20,8 +20,25 @@ func Api(group *gin.RouterGroup) {
group.PUT("/pin", pin()) group.PUT("/pin", pin())
group.PUT("/unpin", unpin()) group.PUT("/unpin", unpin())
group.GET("/:id/log", log1()) group.GET("/:id/log", log1())
group.GET("/:id", getById())
group.PUT("/run", run()) group.PUT("/run", run())
group.PUT("/stop", stop()) group.PUT("/stop", stop())
group.GET("/views", views())
}
func views() gin.HandlerFunc {
return func(ctx *gin.Context) {
ctx.JSON(200, res.Ok([]string{}))
}
}
func getById() gin.HandlerFunc {
return func(ctx *gin.Context) {
id, _ := strconv.Atoi(ctx.Param("id"))
c := cron.GetCron(id)
ctx.JSON(200, res.Ok(c))
}
} }
func get() gin.HandlerFunc { func get() gin.HandlerFunc {

View File

@ -14,9 +14,18 @@ func Api(group *gin.RouterGroup) {
group.GET("/:id", getDep()) group.GET("/:id", getDep())
} }
var (
typMap = map[string]int{
"nodejs": 0,
"python3": 1,
"linux": 2,
}
)
func get() gin.HandlerFunc { func get() gin.HandlerFunc {
return func(ctx *gin.Context) { return func(ctx *gin.Context) {
dependences, err := models.QueryDependences(ctx.Query("searchValue"))
dependences, err := models.QueryDependences(ctx.Query("searchValue"), typMap[ctx.Query("type")])
if err != nil { if err != nil {
ctx.JSON(503, res.Err(503, err)) ctx.JSON(503, res.Err(503, err))
return return

4
api/env/env.go vendored
View File

@ -43,7 +43,7 @@ func post() gin.HandlerFunc {
e.Createdat = time.Now() e.Createdat = time.Now()
e.Updatedat = time.Now() e.Updatedat = time.Now()
e.Timestamp = time.Now().Format("Mon Jan 02 2006 15:04:05 MST") e.Timestamp = time.Now().Format("Mon Jan 02 2006 15:04:05 MST")
e.Status = &status e.Status = status
id, err := env.AddEnv(e) id, err := env.AddEnv(e)
if err != nil { if err != nil {
ctx.JSON(200, res.Err(503, err)) ctx.JSON(200, res.Err(503, err))
@ -142,7 +142,7 @@ func upload() gin.HandlerFunc {
e.Createdat = time.Now() e.Createdat = time.Now()
e.Updatedat = time.Now() e.Updatedat = time.Now()
e.Timestamp = time.Now().Format("Mon Jan 02 2006 15:04:05 MST") e.Timestamp = time.Now().Format("Mon Jan 02 2006 15:04:05 MST")
e.Status = &status e.Status = status
id, err := env.AddEnv(e) id, err := env.AddEnv(e)
if err != nil { if err != nil {
ctx.JSON(200, res.Err(503, err)) ctx.JSON(200, res.Err(503, err))

View File

@ -15,8 +15,36 @@ func Api(group *gin.RouterGroup) {
group.POST("", post()) group.POST("", post())
group.DELETE("", del()) group.DELETE("", del())
group.GET("/:name", getFile()) group.GET("/:name", getFile())
group.GET("/log", log())
group.PUT("/run", run()) group.PUT("/run", run())
group.PUT("/stop", stop())
}
func stop() gin.HandlerFunc {
return func(ctx *gin.Context) {
type Req struct {
Path string `json:"path"`
FileName string `json:"filename"`
Pid string `json:"pid"`
}
r := new(Req)
err := ctx.ShouldBindJSON(r)
if err != nil {
ctx.JSON(503, res.Err(503, err))
return
}
scripts.Stop(r.Pid)
ctx.JSON(200, res.Ok(true))
}
}
func log() gin.HandlerFunc {
return func(ctx *gin.Context) {
pid := ctx.Query("pid")
value := scripts.Log(pid)
ctx.JSON(200, res.Ok(value))
}
} }
func run() gin.HandlerFunc { func run() gin.HandlerFunc {
@ -32,12 +60,12 @@ func run() gin.HandlerFunc {
ctx.JSON(503, res.Err(503, err)) ctx.JSON(503, res.Err(503, err))
return return
} }
err = scripts.Run(path2.Join(r.Path, "_"+r.FileName), r.Content) id, err := scripts.Run(path2.Join(r.Path, "_"+r.FileName), r.Content)
if err != nil { if err != nil {
ctx.JSON(503, res.Err(503, err)) ctx.JSON(503, res.Err(503, err))
return return
} }
ctx.JSON(200, res.Ok(true)) ctx.JSON(200, res.Ok(id))
} }
} }

View File

@ -66,7 +66,6 @@ func get() gin.HandlerFunc {
ctx.JSON(200, res.Ok(subs)) ctx.JSON(200, res.Ok(subs))
} }
} }
func post() gin.HandlerFunc { func post() gin.HandlerFunc {

View File

@ -22,7 +22,7 @@ func get() gin.HandlerFunc {
Version: config.GetVersion(), Version: config.GetVersion(),
LastCommitTime: "", LastCommitTime: "",
LastCommitId: "", LastCommitId: "",
Branch: "Main", Branch: "qinglong-go",
})) }))
} }
} }

View File

@ -69,6 +69,9 @@ TsCmd="ts-node-transpile-only"
# 运行以.sh结尾的文件时的命令 # 运行以.sh结尾的文件时的命令
ShCmd="bash" ShCmd="bash"
# 运行以python依赖的命令
PipCmd="pip"
## 通知环境变量 ## 通知环境变量
## 1. Server酱 ## 1. Server酱
## https://sct.ftqq.com ## https://sct.ftqq.com

View File

@ -57,6 +57,7 @@ func appInit() gin.HandlerFunc {
return return
} }
_ = os.MkdirAll(path.Join("data", "config"), 0666) _ = os.MkdirAll(path.Join("data", "config"), 0666)
_ = os.MkdirAll(path.Join("data", "deps"), 0666)
_ = os.MkdirAll(path.Join("data", "log"), 0666) _ = os.MkdirAll(path.Join("data", "log"), 0666)
_ = os.MkdirAll(path.Join("data", "repo"), 0666) _ = os.MkdirAll(path.Join("data", "repo"), 0666)
_ = os.MkdirAll(path.Join("data", "scripts"), 0666) _ = os.MkdirAll(path.Join("data", "scripts"), 0666)

View File

@ -1,10 +1,13 @@
package ws package ws
import ( import (
"context"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gobwas/ws"
"github.com/huoxue1/qinglong-go/service/client" "github.com/huoxue1/qinglong-go/service/client"
"github.com/huoxue1/qinglong-go/utils/res" "github.com/huoxue1/qinglong-go/utils/res"
"nhooyr.io/websocket"
"nhooyr.io/websocket/wsjson"
"time"
) )
func Api(group *gin.RouterGroup) { func Api(group *gin.RouterGroup) {
@ -20,12 +23,35 @@ func info() gin.HandlerFunc {
func wsHandle() gin.HandlerFunc { func wsHandle() gin.HandlerFunc {
return func(ctx *gin.Context) { return func(ctx *gin.Context) {
conn, _, _, err := ws.UpgradeHTTP(ctx.Request, ctx.Writer) conn, err := websocket.Accept(ctx.Writer, ctx.Request, &websocket.AcceptOptions{
Subprotocols: nil,
InsecureSkipVerify: false,
OriginPatterns: []string{"*"},
CompressionMode: 0,
CompressionThreshold: 0,
})
if err != nil { if err != nil {
ctx.JSON(502, res.Err(502, err)) ctx.JSON(502, res.Err(502, err))
return return
} }
client.AddWs(ctx.Param("id")+"_"+ctx.Param("name"), conn) wsjson.Write(context.Background(), conn, map[string]string{"123": "11"})
wsjson.Write(context.Background(), conn, map[string]string{"123": "11"})
wsjson.Write(context.Background(), conn, map[string]string{"123": "11"})
c := make(chan any, 100)
client.AddChan(c)
for true {
wsjson.Write(context.Background(), conn, map[string]string{"123": "11"})
time.Sleep(1000)
wsjson.Write(context.Background(), conn, map[string]string{"123": "11"})
data := <-c
err := wsjson.Write(context.Background(), conn, data)
if err != nil {
break
} }
}
}
} }

View File

@ -5,7 +5,8 @@ import (
"github.com/gin-contrib/static" "github.com/gin-contrib/static"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/huoxue1/qinglong-go/api" "github.com/huoxue1/qinglong-go/api"
"net/http" "io/ioutil"
"strings"
) )
func Router() *gin.Engine { func Router() *gin.Engine {
@ -15,11 +16,20 @@ func Router() *gin.Engine {
engine.Use(gzip.Gzip(gzip.DefaultCompression)) engine.Use(gzip.Gzip(gzip.DefaultCompression))
engine.Use(static.Serve("/", static.LocalFile("static/dist/", false))) engine.Use(static.Serve("/", static.LocalFile("static/dist/", false)))
engine.NoRoute(func(ctx *gin.Context) { engine.NoRoute(func(ctx *gin.Context) {
if ctx.Request.Method == http.MethodGet { accept := ctx.Request.Header.Get("Accept")
ctx.Redirect(301, "/") flag := strings.Contains(accept, "text/html")
if flag {
content, err := ioutil.ReadFile("static/dist/index.html")
if (err) != nil {
ctx.Writer.WriteHeader(404)
_, _ = ctx.Writer.WriteString("Not Found")
return return
} }
ctx.Next() ctx.Writer.WriteHeader(200)
ctx.Writer.Header().Add("Accept", "text/html")
_, _ = ctx.Writer.Write(content)
ctx.Writer.Flush()
}
}) })
api.Api(engine.Group("/api", api.Jwt())) api.Api(engine.Group("/api", api.Jwt()))
api.Open(engine.Group("/open", api.OpenJwt())) api.Open(engine.Group("/open", api.OpenJwt()))

8
go.mod
View File

@ -4,13 +4,16 @@ go 1.18
require ( require (
github.com/Lyrics-you/sail-logrus-formatter v1.3.1 github.com/Lyrics-you/sail-logrus-formatter v1.3.1
github.com/dablelv/go-huge-util v0.0.31
github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/gin-contrib/gzip v0.0.6
github.com/gin-contrib/static v0.0.1 github.com/gin-contrib/static v0.0.1
github.com/gin-gonic/gin v1.8.1 github.com/gin-gonic/gin v1.8.1
github.com/gobwas/ws v1.1.0 github.com/gobwas/ws v1.1.0
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
github.com/imroc/req/v3 v3.26.5 github.com/imroc/req/v3 v3.26.5
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
github.com/panjf2000/ants/v2 v2.7.1
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/sirupsen/logrus v1.9.0 github.com/sirupsen/logrus v1.9.0
github.com/tidwall/gjson v1.14.4 github.com/tidwall/gjson v1.14.4
@ -21,9 +24,7 @@ require (
require ( require (
github.com/cheekybits/genny v1.0.0 // indirect github.com/cheekybits/genny v1.0.0 // indirect
github.com/dablelv/go-huge-util v0.0.31 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gin-contrib/gzip v0.0.6 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect
@ -37,6 +38,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.10.3 // indirect
github.com/leodido/go-urn v1.2.1 // indirect github.com/leodido/go-urn v1.2.1 // indirect
github.com/lestrrat-go/strftime v1.0.6 // indirect github.com/lestrrat-go/strftime v1.0.6 // indirect
github.com/lucas-clemente/quic-go v0.28.1 // indirect github.com/lucas-clemente/quic-go v0.28.1 // indirect
@ -53,7 +55,6 @@ require (
github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/stretchr/testify v1.8.1 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/pretty v1.2.0 // indirect
@ -76,4 +77,5 @@ require (
modernc.org/opt v0.1.3 // indirect modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect modernc.org/token v1.0.1 // indirect
nhooyr.io/websocket v1.8.7 // indirect
) )

13
go.sum
View File

@ -122,10 +122,13 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA= github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
@ -151,6 +154,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@ -189,6 +193,7 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@ -288,6 +293,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eTO0Q8=
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@ -407,6 +414,8 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/panjf2000/ants/v2 v2.7.1 h1:qBy5lfSdbxvrR0yUnZfaEDjf0FlCw4ufsbcsxmE7r+M=
github.com/panjf2000/ants/v2 v2.7.1/go.mod h1:KIBmYG9QQX5U2qzFP/yQJaq/nSb6rahS9iEHkrCMgM8=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
@ -644,6 +653,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -965,6 +976,8 @@ modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY= modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY=
modernc.org/z v1.3.2 h1:4GWBVMa48UDC7KQ9tnaggN/yTlXg+CdCX9bhgHPQ9AM= modernc.org/z v1.3.2 h1:4GWBVMa48UDC7KQ9tnaggN/yTlXg+CdCX9bhgHPQ9AM=
modernc.org/z v1.3.2/go.mod h1:PEU2oK2OEA1CfzDTd+8E908qEXhC9s0MfyKp5LZsd+k= modernc.org/z v1.3.2/go.mod h1:PEU2oK2OEA1CfzDTd+8E908qEXhC9s0MfyKp5LZsd+k=
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=

10
main.go
View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"flag"
"fmt" "fmt"
nested "github.com/Lyrics-you/sail-logrus-formatter/sailor" nested "github.com/Lyrics-you/sail-logrus-formatter/sailor"
"github.com/dablelv/go-huge-util/zip" "github.com/dablelv/go-huge-util/zip"
@ -17,6 +18,10 @@ import (
"time" "time"
) )
var (
address string
)
func init() { func init() {
w, err := rotates.New(path.Join("data", "log", "qinglong-go", "%Y-%m-%d.log"), rotates.WithRotationTime(time.Hour*24)) w, err := rotates.New(path.Join("data", "log", "qinglong-go", "%Y-%m-%d.log"), rotates.WithRotationTime(time.Hour*24))
if err != nil { if err != nil {
@ -39,13 +44,16 @@ func init() {
CallerFirst: false, CallerFirst: false,
CustomCallerFormatter: nil, CustomCallerFormatter: nil,
}) })
flag.StringVar(&address, "add", "0.0.0.0:5700", "the ql listen address!")
flag.Parse()
config.SetAddress(address)
} }
func main() { func main() {
checkStatic() checkStatic()
service.AppInit() service.AppInit()
engine := controller.Router() engine := controller.Router()
_ = engine.Run(":5700") _ = engine.Run(address)
} }
func checkStatic() { func checkStatic() {

View File

@ -11,7 +11,7 @@ type Crontabs struct {
Command string `xorm:"VARCHAR(255)" json:"command"` Command string `xorm:"VARCHAR(255)" json:"command"`
Schedule string `xorm:"VARCHAR(255)" json:"schedule"` Schedule string `xorm:"VARCHAR(255)" json:"schedule"`
Timestamp string `xorm:"VARCHAR(255)" json:"timestamp"` Timestamp string `xorm:"VARCHAR(255)" json:"timestamp"`
Saved int `xorm:"TINYINT(1)" json:"saved"` Saved bool `xorm:"TINYINT(1)" json:"saved"`
Status int `xorm:"TINYINT(1)" json:"status"` Status int `xorm:"TINYINT(1)" json:"status"`
Issystem int `xorm:"TINYINT(1)" json:"isSystem"` Issystem int `xorm:"TINYINT(1)" json:"isSystem"`
Pid int `xorm:"TINYINT(1)" json:"pid"` Pid int `xorm:"TINYINT(1)" json:"pid"`

View File

@ -23,17 +23,16 @@ type Dependences struct {
Updatedat time.Time `xorm:"not null DATETIME updated" json:"updatedAt"` Updatedat time.Time `xorm:"not null DATETIME updated" json:"updatedAt"`
} }
func QueryDependences(searchValue string) ([]*Dependences, error) { func QueryDependences(searchValue string, typ int) ([]*Dependences, error) {
dep := make([]*Dependences, 0) dep := make([]*Dependences, 0)
session := engine.Table(new(Dependences)). session := engine.Table(new(Dependences)).
Where( Where(
builder.Like{"name", "%" + searchValue + "%"}) builder.Like{"name", "%" + searchValue + "%"})
err := session.Find(&dep) err := session.And("type=?", typ).Find(&dep)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return dep, err return dep, err
} }
func AddDependences(dep *Dependences) (int, error) { func AddDependences(dep *Dependences) (int, error) {

View File

@ -9,7 +9,7 @@ type Envs struct {
Id int `xorm:"pk autoincr INTEGER" json:"id,omitempty"` Id int `xorm:"pk autoincr INTEGER" json:"id,omitempty"`
Value string `xorm:"TEXT" json:"value,omitempty"` Value string `xorm:"TEXT" json:"value,omitempty"`
Timestamp string `xorm:"TEXT" json:"timestamp,omitempty"` Timestamp string `xorm:"TEXT" json:"timestamp,omitempty"`
Status *int `xorm:"TINYINT(1)" json:"status,omitempty"` Status int `xorm:"TINYINT(1)" json:"status,omitempty"`
Position string `xorm:"TINYINT(1)" json:"position,omitempty"` Position string `xorm:"TINYINT(1)" json:"position,omitempty"`
Name string `xorm:"TEXT" json:"name,omitempty"` Name string `xorm:"TEXT" json:"name,omitempty"`
Remarks string `xorm:"TEXT" json:"remarks,omitempty"` Remarks string `xorm:"TEXT" json:"remarks,omitempty"`

View File

@ -1,57 +1,30 @@
package client package client
import ( type client struct {
"encoding/json" channels []chan any
"github.com/gobwas/ws"
"github.com/gobwas/ws/wsutil"
"net"
"sync"
)
type Clients struct {
sync.Map
} }
func (c *Clients) Write(p []byte) (n int, err error) { func (c *client) Write(p []byte) (n int, err error) {
data := map[string]string{"type": "manuallyRunScript", "message": string(p)} data := map[string]string{"type": "manuallyRunScript", "message": string(p)}
content, _ := json.Marshal(data) for _, channel := range c.channels {
var deleSlince []string select {
c.Range(func(key, value any) bool { case channel <- data:
conn := value.(*Client).conn default:
writer := wsutil.NewWriter(conn, ws.StateServerSide, ws.OpText)
_, err := writer.Write(content)
if err != nil {
deleSlince = append(deleSlince, key.(string))
return true
} }
err = writer.Flush()
if err != nil {
deleSlince = append(deleSlince, key.(string))
return true
}
return true
})
for _, s := range deleSlince {
c.Delete(s)
} }
return len(p), nil return len(p), nil
} }
var ( var (
MyClient *Clients MyClient *client
) )
func init() { func init() {
MyClient = new(Clients) MyClient = new(client)
} }
type Client struct { func AddChan(c chan any) {
conn net.Conn MyClient.channels = append(MyClient.channels, c)
}
func AddWs(id string, conn net.Conn) {
MyClient.Store(id, &Client{
conn: conn,
})
} }

View File

@ -4,6 +4,8 @@ import (
"os" "os"
"path" "path"
"regexp" "regexp"
"strconv"
"strings"
) )
var VERSION = "v1.0.0" var VERSION = "v1.0.0"
@ -24,3 +26,15 @@ func GetKey(key, defaultValue string) string {
func GetVersion() string { func GetVersion() string {
return VERSION return VERSION
} }
var address string
func SetAddress(add string) {
address = add
}
func ListenPort() int {
split := strings.Split(address, ":")
port, _ := strconv.Atoi(split[1])
return port
}

View File

@ -2,7 +2,6 @@ package cron
import ( import (
"github.com/huoxue1/qinglong-go/models" "github.com/huoxue1/qinglong-go/models"
"github.com/robfig/cron/v3"
"time" "time"
) )
@ -12,17 +11,17 @@ func GetCrons(page, size int, searchValue string, sorter map[string]string, filt
} }
func AddCron(cron *models.Crontabs) (int, error) { func AddCron(cron *models.Crontabs) (int, error) {
AddTask(cron) err := AddTask(cron)
if err != nil {
return 0, err
}
return models.AddCron(cron) return models.AddCron(cron)
} }
func DeleteCron(ids []int) error { func DeleteCron(ids []int) error {
for _, id := range ids { for _, id := range ids {
c, _ := manager.Load(id) DeleteTask(id)
if c != nil {
c.(*cron.Cron).Stop()
}
err := models.DeleteCron(id) err := models.DeleteCron(id)
if err != nil { if err != nil {
@ -40,10 +39,7 @@ func UpdateCron(c1 *models.Crontabs) error {
crontabs.Schedule = c1.Schedule crontabs.Schedule = c1.Schedule
crontabs.Updatedat = time.Now().Format(time.RFC3339) crontabs.Updatedat = time.Now().Format(time.RFC3339)
c, _ := manager.Load(c1.Id) DeleteTask(c1.Id)
if c != nil {
c.(*cron.Cron).Stop()
}
AddTask(c1) AddTask(c1)
return models.UpdateCron(crontabs) return models.UpdateCron(crontabs)
@ -52,8 +48,7 @@ func UpdateCron(c1 *models.Crontabs) error {
func DisableCron(ids []int) error { func DisableCron(ids []int) error {
for _, id := range ids { for _, id := range ids {
c, _ := manager.Load(id) DeleteTask(id)
c.(*cron.Cron).Stop()
cron, err := models.GetCron(id) cron, err := models.GetCron(id)
if err != nil { if err != nil {
@ -120,7 +115,7 @@ func RunCron(ids []int) error {
if err != nil { if err != nil {
continue continue
} }
runCron(crontab) runCron(crontab, true)
} }
return nil return nil
} }

View File

@ -8,7 +8,7 @@ import (
"github.com/huoxue1/qinglong-go/service/config" "github.com/huoxue1/qinglong-go/service/config"
"github.com/huoxue1/qinglong-go/service/env" "github.com/huoxue1/qinglong-go/service/env"
"github.com/huoxue1/qinglong-go/utils" "github.com/huoxue1/qinglong-go/utils"
"github.com/robfig/cron/v3" cron_manager "github.com/huoxue1/qinglong-go/utils/cron-manager"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"io" "io"
"os" "os"
@ -22,7 +22,6 @@ import (
) )
var ( var (
manager sync.Map
execManager sync.Map execManager sync.Map
) )
@ -58,7 +57,7 @@ func stopCron(crontabs *models.Crontabs) {
cancel() cancel()
} }
func runCron(crontabs *models.Crontabs) { func runCron(crontabs *models.Crontabs, isNow bool) {
envFromDb := env.LoadEnvFromDb() envFromDb := env.LoadEnvFromDb()
envfromFile := env.LoadEnvFromFile("data/config/config.sh") envfromFile := env.LoadEnvFromFile("data/config/config.sh")
for s, s2 := range envfromFile { for s, s2 := range envfromFile {
@ -119,7 +118,8 @@ func runCron(crontabs *models.Crontabs) {
if strings.HasPrefix(ta.cmd, "go") { if strings.HasPrefix(ta.cmd, "go") {
cmdDir = ta.dir cmdDir = ta.dir
} }
go utils.RunWithOption(ctx, &utils.RunOption{ option := &utils.RunOption{
Ctx: ctx,
Command: ta.cmd, Command: ta.cmd,
Env: envFromDb, Env: envFromDb,
OnStart: func(ctx context.Context) { OnStart: func(ctx context.Context) {
@ -138,33 +138,29 @@ func runCron(crontabs *models.Crontabs) {
}, },
LogFile: file, LogFile: file,
CmdDir: cmdDir, CmdDir: cmdDir,
}) }
if isNow {
go utils.RunWithOption(ctx, option)
} else {
_ = run(option)
}
} }
} }
func AddTask(crontabs *models.Crontabs) { func AddTask(crontabs *models.Crontabs) error {
crons := strings.Split(crontabs.Schedule, " ") err := cron_manager.AddCron(fmt.Sprintf("cron_%d", crontabs.Id), crontabs.Schedule, func() {
var c *cron.Cron runCron(crontabs, false)
if len(crons) == 5 {
c = cron.New()
} else if len(crons) == 6 {
c = cron.New(cron.WithParser(
cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)))
} else {
log.Errorf("the task %s cron %s is error", crontabs.Name, crontabs.Command)
return
}
_, err := c.AddFunc(crontabs.Schedule, func() {
runCron(crontabs)
}) })
if err != nil { if err != nil {
log.Errorln("添加task错误" + crontabs.Schedule + err.Error()) log.Errorln("添加定时任务错误" + err.Error())
return return err
} }
c.Start() return nil
manager.Store(crontabs.Id, c) }
func DeleteTask(id int) error {
return cron_manager.DeleteCron(fmt.Sprintf("cron_%d", id))
} }
func handCommand(command string) *task { func handCommand(command string) *task {

34
service/cron/run.go Normal file
View File

@ -0,0 +1,34 @@
package cron
import (
"github.com/huoxue1/qinglong-go/utils"
"os"
"github.com/panjf2000/ants/v2"
log "github.com/sirupsen/logrus"
)
func init() {
initPool()
}
var (
pool *ants.PoolWithFunc
)
func run(task *utils.RunOption) error {
return pool.Invoke(task)
}
func initPool() {
pool1, err := ants.NewPoolWithFunc(5, func(i2 interface{}) {
option := i2.(*utils.RunOption)
utils.RunWithOption(option.Ctx, option)
})
if err != nil {
log.Errorln("创建定时任务协程池失败" + err.Error())
os.Exit(2)
}
pool = pool1
}

View File

@ -5,6 +5,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/huoxue1/qinglong-go/models" "github.com/huoxue1/qinglong-go/models"
"github.com/huoxue1/qinglong-go/service/config"
"github.com/huoxue1/qinglong-go/utils" "github.com/huoxue1/qinglong-go/utils"
"io" "io"
"strings" "strings"
@ -47,7 +48,8 @@ func addPythonDep(dep *models.Dependences) {
buffer := bytes.NewBufferString(log) buffer := bytes.NewBufferString(log)
ctx := context.WithValue(context.Background(), "cancel", make(chan int, 1)) ctx := context.WithValue(context.Background(), "cancel", make(chan int, 1))
now := time.Now() now := time.Now()
utils.RunTask(ctx, fmt.Sprintf("pip install %s", dep.Name), map[string]string{}, func(ctx context.Context) { pip := config.GetKey("PipCmd", "pip")
utils.RunTask(ctx, fmt.Sprintf(pip+" install %s", dep.Name), map[string]string{}, func(ctx context.Context) {
writer := ctx.Value("log").(io.Writer) writer := ctx.Value("log").(io.Writer)
writer.Write([]byte(fmt.Sprintf("##开始执行.. %s\n\n", now.Format("2006-01-02 15:04:05")))) writer.Write([]byte(fmt.Sprintf("##开始执行.. %s\n\n", now.Format("2006-01-02 15:04:05"))))
}, func(ctx context.Context) { }, func(ctx context.Context) {

7
service/env/env.go vendored
View File

@ -44,7 +44,7 @@ func DisableEnv(ids []int) error {
if err != nil { if err != nil {
continue continue
} }
env.Status = &DISABLESTATUS env.Status = DISABLESTATUS
err = models.UpdateEnv(env) err = models.UpdateEnv(env)
if err != nil { if err != nil {
return err return err
@ -59,7 +59,7 @@ func EnableEnv(ids []int) error {
if err != nil { if err != nil {
continue continue
} }
env.Status = &ENABLESTATUS env.Status = ENABLESTATUS
err = models.UpdateEnv(env) err = models.UpdateEnv(env)
if err != nil { if err != nil {
return err return err
@ -86,6 +86,9 @@ func LoadEnvFromDb() map[string]string {
return result return result
} }
for _, env := range envs { for _, env := range envs {
if env.Status == 1 {
continue
}
if _, ok := result[env.Name]; ok { if _, ok := result[env.Name]; ok {
result[env.Name] = result[env.Name] + "&" + env.Value result[env.Name] = result[env.Name] + "&" + env.Value
} else { } else {

View File

@ -4,7 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/huoxue1/qinglong-go/service/client" "github.com/google/uuid"
"github.com/huoxue1/qinglong-go/service/env" "github.com/huoxue1/qinglong-go/service/env"
"github.com/huoxue1/qinglong-go/utils" "github.com/huoxue1/qinglong-go/utils"
"io" "io"
@ -13,6 +13,7 @@ import (
"path/filepath" "path/filepath"
"sort" "sort"
"strings" "strings"
"sync"
"time" "time"
) )
@ -30,26 +31,71 @@ var (
"node_modules", "node_modules",
"__pycache__", "__pycache__",
} }
scriptRunPidMap sync.Map
) )
func Run(filePath, content string) error { 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) err := os.WriteFile(path.Join("data", "scripts", filePath), []byte(content), 0666)
if err != nil { if err != nil {
return err return "", err
} }
id := uuid.New().String()
logPath := "data/log/" + time.Now().Format("2006-01-02") + "/" + filepath.Base(filePath) + "_" + id + ".log"
cmd := getCmd(filePath) cmd := getCmd(filePath)
cancelChan := make(chan int, 1) cancelChan := make(chan int, 1)
ctx := context.WithValue(context.Background(), "cancel", cancelChan) ctx := context.WithValue(context.Background(), "cancel", cancelChan)
now := time.Now() now := time.Now()
utils.RunTask(ctx, cmd, env.GetALlEnv(), func(ctx context.Context) { file, _ := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE, 0666)
go utils.RunTask(ctx, cmd, env.GetALlEnv(), func(ctx context.Context) {
writer := ctx.Value("log").(io.Writer) writer := ctx.Value("log").(io.Writer)
_, _ = writer.Write([]byte(fmt.Sprintf("##开始执行.. %s\n\n", now.Format("2006-01-02 15:04:05")))) _, _ = writer.Write([]byte(fmt.Sprintf("##开始执行.. %s\n\n", now.Format("2006-01-02 15:04:05"))))
}, func(ctx context.Context) { }, func(ctx context.Context) {
writer := ctx.Value("log").(io.Writer) 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()))) _, _ = 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) _ = os.Remove(filePath)
}, client.MyClient) // 等待结束三分钟后再删除
return nil go func() {
time.Sleep(time.Minute * 3)
scriptRunPidMap.LoadAndDelete(id)
}()
}, file)
scriptRunPidMap.Store(id, &task{
id: id,
c: cancelChan,
logPath: logPath,
})
return id, nil
} }
func getCmd(filePath string) string { func getCmd(filePath string) string {
@ -59,7 +105,8 @@ func getCmd(filePath string) string {
return fmt.Sprintf("%s %s", "node", filePath) return fmt.Sprintf("%s %s", "node", filePath)
case ".py": case ".py":
return fmt.Sprintf("%s %s", "python", filePath) return fmt.Sprintf("%s %s", "python", filePath)
case ".go":
return fmt.Sprintf("go run %s", filePath)
} }
return "" return ""
} }

View File

@ -9,6 +9,7 @@ import (
"github.com/huoxue1/qinglong-go/service/config" "github.com/huoxue1/qinglong-go/service/config"
"github.com/huoxue1/qinglong-go/service/cron" "github.com/huoxue1/qinglong-go/service/cron"
"github.com/huoxue1/qinglong-go/utils" "github.com/huoxue1/qinglong-go/utils"
cron_manager "github.com/huoxue1/qinglong-go/utils/cron-manager"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"io" "io"
"os" "os"
@ -25,6 +26,34 @@ var (
manager sync.Map manager sync.Map
) )
func init() {
log.Infoln("开始初始化订阅任务定时!")
subscriptions, err := models.QuerySubscription("")
if err != nil {
return
}
for _, subscription := range subscriptions {
cron_manager.AddCron(fmt.Sprintf("sub_%d", subscription.Id), subscription.GetCron(), func() {
downloadFiles(subscription)
})
}
}
func getDepFiles() []string {
var files []string
dir, err := os.ReadDir(path.Join("data", "deps"))
if err != nil {
return []string{}
}
for _, entry := range dir {
if !entry.IsDir() {
files = append(files, entry.Name())
}
}
return files
}
func stopSubscription(sub *models.Subscriptions) { func stopSubscription(sub *models.Subscriptions) {
defer func() { defer func() {
_ = recover() _ = recover()
@ -41,12 +70,13 @@ func stopSubscription(sub *models.Subscriptions) {
func downloadFiles(subscriptions *models.Subscriptions) { func downloadFiles(subscriptions *models.Subscriptions) {
if subscriptions.Type == "public-repo" { if subscriptions.Type == "public-repo" {
os.RemoveAll(path.Join("data", "scripts", subscriptions.Alias))
os.RemoveAll(path.Join("data", "repo", subscriptions.Alias)) os.RemoveAll(path.Join("data", "repo", subscriptions.Alias))
err := downloadPublicRepo(subscriptions) err := downloadPublicRepo(subscriptions)
if err != nil { if err != nil {
return return
} }
os.RemoveAll(path.Join("data", "scripts", subscriptions.Alias))
if config.GetKey("AutoAddCron", "true") == "true" { if config.GetKey("AutoAddCron", "true") == "true" {
addScripts(subscriptions) addScripts(subscriptions)
} else { } else {
@ -58,6 +88,7 @@ func downloadFiles(subscriptions *models.Subscriptions) {
_ = file.Close() _ = file.Close()
subscriptions.Status = 1 subscriptions.Status = 1
models.UpdateSubscription(subscriptions) models.UpdateSubscription(subscriptions)
manager.LoadAndDelete(subscriptions.Id)
} else if subscriptions.Type == "file" { } else if subscriptions.Type == "file" {
addRawFiles(subscriptions) addRawFiles(subscriptions)
} }
@ -128,7 +159,7 @@ func downloadPublicRepo(subscriptions *models.Subscriptions) error {
manager.Store(subscriptions.Id, func() { manager.Store(subscriptions.Id, func() {
command.Process.Kill() command.Process.Kill()
}) })
defer manager.LoadAndDelete(subscriptions.Id)
go io.Copy(io.MultiWriter(file, os.Stdout), pipe) go io.Copy(io.MultiWriter(file, os.Stdout), pipe)
go io.Copy(file, stderrPipe) go io.Copy(file, stderrPipe)
command.Wait() command.Wait()
@ -136,6 +167,7 @@ func downloadPublicRepo(subscriptions *models.Subscriptions) error {
} }
func addScripts(subscriptions *models.Subscriptions) { func addScripts(subscriptions *models.Subscriptions) {
depFiles := getDepFiles()
file, _ := os.OpenFile(subscriptions.LogPath, os.O_RDWR|os.O_APPEND, 0666) file, _ := os.OpenFile(subscriptions.LogPath, os.O_RDWR|os.O_APPEND, 0666)
defer file.Close() defer file.Close()
var extensions []string var extensions []string
@ -175,8 +207,7 @@ func addScripts(subscriptions *models.Subscriptions) {
if c != "" { if c != "" {
command, err := models.GetCronByCommand(fmt.Sprintf("task %s", path.Join(subscriptions.Alias, entry.Name()))) command, err := models.GetCronByCommand(fmt.Sprintf("task %s", path.Join(subscriptions.Alias, entry.Name())))
if err != nil { if err != nil {
file.WriteString("已添加新的定时任务 " + name + "\n") _, err1 := cron.AddCron(&models.Crontabs{
_, _ = cron.AddCron(&models.Crontabs{
Name: name, Name: name,
Command: fmt.Sprintf("task %s", path.Join(subscriptions.Alias, entry.Name())), Command: fmt.Sprintf("task %s", path.Join(subscriptions.Alias, entry.Name())),
Schedule: c, Schedule: c,
@ -184,6 +215,12 @@ func addScripts(subscriptions *models.Subscriptions) {
Status: 1, Status: 1,
Labels: []string{}, Labels: []string{},
}) })
if err1 != nil {
file.WriteString("定时任务添加失败: " + name + " " + err1.Error())
err1 = nil
} else {
file.WriteString("已添加新的定时任务 " + name + "\n")
}
} else { } else {
command.Name = name command.Name = name
command.Schedule = c command.Schedule = c
@ -199,6 +236,10 @@ func addScripts(subscriptions *models.Subscriptions) {
utils.Copy(path.Join("data", "repo", subscriptions.Alias, entry.Name()), path.Join("data", "scripts", subscriptions.Alias, entry.Name())) utils.Copy(path.Join("data", "repo", subscriptions.Alias, entry.Name()), path.Join("data", "scripts", subscriptions.Alias, entry.Name()))
} }
} }
if utils.In(entry.Name(), depFiles) {
file.WriteString("已替换依赖文件: " + entry.Name() + "\n")
utils.Copy(path.Join("data", "deps", entry.Name()), path.Join("data", "scripts", subscriptions.Alias, entry.Name()))
}
} }
if config.GetKey("AutoDelCron", "true") == "true" { if config.GetKey("AutoDelCron", "true") == "true" {
for _, m := range cronMap { for _, m := range cronMap {
@ -223,6 +264,10 @@ func addScripts(subscriptions *models.Subscriptions) {
CmdDir: path.Join("data", "scripts", subscriptions.Alias), CmdDir: path.Join("data", "scripts", subscriptions.Alias),
}) })
} }
for _, depFile := range depFiles {
utils.Copy(path.Join("data", "deps", depFile), path.Join("data", "scripts", subscriptions.Alias, depFile))
}
} }
func getSubCron(filePath string) (name string, cron string, err error) { func getSubCron(filePath string) (name string, cron string, err error) {

View File

@ -0,0 +1,55 @@
package cron_manager
import (
"errors"
"github.com/huoxue1/qinglong-go/utils/log"
"github.com/robfig/cron/v3"
"strings"
"sync"
)
var (
manager sync.Map
defaultCron *cron.Cron
SixCron *cron.Cron
)
type mapValue struct {
en cron.EntryID
c *cron.Cron
}
func init() {
defaultCron = cron.New(cron.WithChain(cron.Recover(&log.CronLog{})))
SixCron = cron.New(cron.WithChain(cron.Recover(&log.CronLog{})), cron.WithParser(
cron.NewParser(cron.Second|cron.Minute|cron.Hour|cron.Dom|cron.Month|cron.Dow|cron.Descriptor)))
defaultCron.Start()
SixCron.Start()
}
func AddCron(id string, value string, task func()) error {
if value == "7 7 7 7 7" {
value = "7 7 7 7 6"
}
crons := strings.Split(value, " ")
cronCmd := defaultCron
if len(crons) == 6 {
cronCmd = SixCron
}
en, err := cronCmd.AddFunc(value, task)
if err != nil {
return err
}
manager.Store(id, &mapValue{en, cronCmd})
return nil
}
func DeleteCron(id string) error {
value, loaded := manager.LoadAndDelete(id)
if !loaded {
return errors.New("the cron " + id + " not found!")
}
v := value.(*mapValue)
v.c.Remove(v.en)
return nil
}

View File

@ -0,0 +1,17 @@
package cron_manager
import (
"fmt"
"testing"
"time"
)
func TestAddCron(t *testing.T) {
_ = AddCron("test1", "*/5 * * * * ?", func() {
fmt.Println(time.Now().Format("15:04:05"))
})
time.Sleep(time.Minute)
DeleteCron("test1")
fmt.Println("已停止")
time.Sleep(10 * time.Second)
}

View File

@ -74,3 +74,14 @@ func (l *LogWriter) Write(p []byte) (n int, err error) {
log.Debugln(string(p)) log.Debugln(string(p))
return len(p), nil return len(p), nil
} }
type CronLog struct {
}
func (c *CronLog) Info(msg string, keysAndValues ...interface{}) {
log.Infoln(msg, " ", keysAndValues)
}
func (c *CronLog) Error(err error, msg string, keysAndValues ...interface{}) {
log.Errorln(err)
}

View File

@ -2,6 +2,9 @@ package utils
import ( import (
"context" "context"
"fmt"
"github.com/huoxue1/qinglong-go/service/config"
log "github.com/sirupsen/logrus"
"io" "io"
"os" "os"
"os/exec" "os/exec"
@ -17,6 +20,10 @@ func RunTask(ctx context.Context, command string, env map[string]string, onStart
for s, s2 := range env { for s, s2 := range env {
cmd.Env = append(cmd.Env, s+"="+s2) cmd.Env = append(cmd.Env, s+"="+s2)
} }
environ := os.Environ()
dir, _ := os.Getwd()
port := config.ListenPort()
cmd.Env = append(append(cmd.Env, environ...), "QL_DIR="+dir, fmt.Sprintf("QL_PORT=%d", port))
stdoutPipe, _ := cmd.StdoutPipe() stdoutPipe, _ := cmd.StdoutPipe()
stderrPipe, _ := cmd.StderrPipe() stderrPipe, _ := cmd.StderrPipe()
cmd.Dir = "./data/scripts/" cmd.Dir = "./data/scripts/"
@ -53,6 +60,7 @@ func RunTask(ctx context.Context, command string, env map[string]string, onStart
} }
type RunOption struct { type RunOption struct {
Ctx context.Context
Command string Command string
Env map[string]string Env map[string]string
OnStart func(ctx context.Context) OnStart func(ctx context.Context)
@ -62,12 +70,21 @@ type RunOption struct {
} }
func RunWithOption(ctx context.Context, option *RunOption) { func RunWithOption(ctx context.Context, option *RunOption) {
defer func() {
err := recover()
if err != nil {
log.Errorln("执行command出现异常")
log.Errorln(err)
}
}()
cmd := exec.Command(strings.Split(option.Command, " ")[0], strings.Split(option.Command, " ")[1:]...) cmd := exec.Command(strings.Split(option.Command, " ")[0], strings.Split(option.Command, " ")[1:]...)
for s, s2 := range option.Env { for s, s2 := range option.Env {
cmd.Env = append(cmd.Env, s+"="+s2) cmd.Env = append(cmd.Env, s+"="+s2)
} }
environ := os.Environ() environ := os.Environ()
cmd.Env = append(cmd.Env, environ...) dir, _ := os.Getwd()
port := config.ListenPort()
cmd.Env = append(append(cmd.Env, environ...), "QL_DIR="+dir, fmt.Sprintf("QL_PORT=%d", port))
stdoutPipe, _ := cmd.StdoutPipe() stdoutPipe, _ := cmd.StdoutPipe()
stderrPipe, _ := cmd.StderrPipe() stderrPipe, _ := cmd.StderrPipe()
cmd.Dir = option.CmdDir cmd.Dir = option.CmdDir