diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d37bab4..8666eb3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,7 @@ jobs: if [ $GOOS = "windows" ]; then export BINARY_SUFFIX="$BINARY_SUFFIX.exe"; fi if $IS_PR ; then echo $PR_PROMPT; fi export BINARY_NAME="$BINARY_PREFIX$GOOS_$GOARCH$BINARY_SUFFIX" - export LD_FLAGS="-w -s -X github.com/huoxue1/qinglong-go/api/system.VERSION=$COMMIT_ID" + export LD_FLAGS="-w -s -X github.com/huoxue1/qinglong-go/service/config.VERSION=$COMMIT_ID" go mod tidy go build -o "output/$BINARY_NAME" -trimpath -ldflags "$LD_FLAGS" ./ - name: Upload artifact diff --git a/.github/workflows/push-to-docker.yml b/.github/workflows/push-to-docker.yml index e250198..9b1b0b4 100644 --- a/.github/workflows/push-to-docker.yml +++ b/.github/workflows/push-to-docker.yml @@ -82,9 +82,8 @@ jobs: with: context: . push: ${{ github.event_name != 'pull_request' }} - platforms: linux/amd64,linux/arm64 + platforms: linux/amd64,linux/arm64,linux/386,linux/arm tags: ${{ steps.meta.outputs.tags }} cache-from: type=gha cache-to: type=gha,mode=max - shm-size: 2g ulimit: core=0:0 diff --git a/.goreleaser.yml b/.goreleaser.yml index f6d578d..c9f7ea8 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -30,7 +30,7 @@ builds: flags: - -trimpath ldflags: - - -s -w -X main.VERSION=v{{.Version}} + - -s -w -X github.com/huoxue1/qinglong-go/service/config.VERSION=v{{.Version}} - id: win env: - CGO_ENABLED=0 @@ -46,7 +46,7 @@ builds: flags: - -trimpath ldflags: - - -s -w -X main.VERSION=v{{.Version}} + - -s -w -X github.com/huoxue1/qinglong-go/service/config.VERSION.VERSION=v{{.Version}} - id: docker env: - CGO_ENABLED=0 @@ -54,13 +54,17 @@ builds: goos: - linux goarch: + - 386 - amd64 + - arm - arm64 + goarm: + - 7 mod_timestamp: "{{ .CommitTimestamp }}" flags: - -trimpath ldflags: - - -s -w -X main.VERSION=v{{.Version}} + - -s -w -X github.com/huoxue1/qinglong-go/service/config.VERSION.VERSION=v{{.Version}} checksum: name_template: "{{ .ProjectName }}_checksums.txt" diff --git a/Dockerfile b/Dockerfile index 0b1f34d..6aa26bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,9 +31,6 @@ RUN set -x \ openssh \ npm \ && rm -rf /var/cache/apk/* \ - && wget https://studygolang.com/dl/golang/go1.19.4.linux-${TARGETARCH}.tar.gz \ - && tar -C /usr/local -xzf go1.19.4.linux-${TARGETARCH}.tar.gz \ - && rm -rf go1.19.4.linux-${TARGETARCH}.tar.gz \ && apk update \ && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone \ diff --git a/api/api.go b/api/api.go index 0216e77..bcf6685 100644 --- a/api/api.go +++ b/api/api.go @@ -8,6 +8,7 @@ import ( "github.com/huoxue1/qinglong-go/api/env" "github.com/huoxue1/qinglong-go/api/logs" "github.com/huoxue1/qinglong-go/api/open" + "github.com/huoxue1/qinglong-go/api/public" "github.com/huoxue1/qinglong-go/api/scripts" "github.com/huoxue1/qinglong-go/api/subscription" "github.com/huoxue1/qinglong-go/api/system" @@ -27,4 +28,5 @@ func Api(group *gin.RouterGroup) { logs.APi(group.Group("/logs")) dependencies.Api(group.Group("/dependencies")) ws.Api(group.Group("/ws")) + public.Api(group.Group("/public")) } diff --git a/api/cron/cron.go b/api/cron/cron.go index 714dcbe..fd1d3b4 100644 --- a/api/cron/cron.go +++ b/api/cron/cron.go @@ -33,6 +33,9 @@ func get() gin.HandlerFunc { filters := ctx.QueryMap("queryString")["filters"] page, _ := strconv.Atoi(ctx.Query("page")) size, _ := strconv.Atoi(ctx.Query("size")) + if size == 0 { + size = 1000 + } crons, err := cron.GetCrons(page, size, ctx.Query("searchValue"), sorter, filters) if err != nil { ctx.JSON(503, res.Err(503, err)) diff --git a/api/midware.go b/api/midware.go index d25aa67..f1cc69c 100644 --- a/api/midware.go +++ b/api/midware.go @@ -19,6 +19,7 @@ var ( "/api/system", "/api/user/login", "/api/user/init", + "api/public/panel/log", } ) diff --git a/api/public/public.go b/api/public/public.go new file mode 100644 index 0000000..f7b4de6 --- /dev/null +++ b/api/public/public.go @@ -0,0 +1,16 @@ +package public + +import ( + "github.com/gin-gonic/gin" + "path" + "time" +) + +func Api(group *gin.RouterGroup) { + group.GET("/panel/log", log()) +} +func log() gin.HandlerFunc { + return func(ctx *gin.Context) { + ctx.File(path.Join("data", "log", "qinglong-go", time.Now().Format("2006-01-02")+".log")) + } +} diff --git a/api/scripts/scripts.go b/api/scripts/scripts.go index 60cd39b..759f47e 100644 --- a/api/scripts/scripts.go +++ b/api/scripts/scripts.go @@ -15,6 +15,30 @@ func Api(group *gin.RouterGroup) { group.POST("", post()) group.DELETE("", del()) group.GET("/:name", getFile()) + + group.PUT("/run", run()) +} + +func run() gin.HandlerFunc { + return func(ctx *gin.Context) { + type Req struct { + Path string `json:"path"` + FileName string `json:"filename"` + Content string `json:"content"` + } + r := new(Req) + err := ctx.ShouldBindJSON(r) + if err != nil { + ctx.JSON(503, res.Err(503, err)) + return + } + err = scripts.Run(path2.Join(r.Path, "_"+r.FileName), r.Content) + if err != nil { + ctx.JSON(503, res.Err(503, err)) + return + } + ctx.JSON(200, res.Ok(true)) + } } func get() gin.HandlerFunc { diff --git a/api/system/system.go b/api/system/system.go index 719a6ec..581a79a 100644 --- a/api/system/system.go +++ b/api/system/system.go @@ -2,16 +2,13 @@ package system import ( "github.com/gin-gonic/gin" + "github.com/huoxue1/qinglong-go/service/config" "github.com/huoxue1/qinglong-go/service/system" "github.com/huoxue1/qinglong-go/utils/res" "os" "path" ) -var ( - VERSION = "UNKNOWN" -) - func Api(group *gin.RouterGroup) { group.GET("", get()) } @@ -22,10 +19,10 @@ func get() gin.HandlerFunc { exist := os.IsNotExist(err) ctx.JSON(200, res.Ok(system.System{ IsInitialized: !exist, - Version: VERSION, + Version: config.GetVersion(), LastCommitTime: "", LastCommitId: "", - Branch: "master", + Branch: "Main", })) } } diff --git a/api/user/user.go b/api/user/user.go index 7a7cb9f..212ac39 100644 --- a/api/user/user.go +++ b/api/user/user.go @@ -111,6 +111,11 @@ func login() gin.HandlerFunc { ctx.JSON(503, res.Err(503, err)) return } + ip, err := user.GetNetIp(ctx.RemoteIP()) + if err != nil { + ip = new(user.Ip) + err = nil + } mobile := utils.IsMobile(ctx.GetHeader("User-Agent")) if mobile { auth.Tokens.Mobile = token @@ -126,8 +131,8 @@ func login() gin.HandlerFunc { "token": token, "platform": "mobile", "retries": 0, - "lastip": "", - "lastaddr": "", + "lastip": ctx.RemoteIP(), + "lastaddr": ip.Addr, "lastlogon": time.Now().UnixNano(), })) } else { @@ -144,9 +149,9 @@ func login() gin.HandlerFunc { "token": token, "platform": "desktop", "retries": 0, - "lastip": "", - "lastaddr": "", - "lastlogon": time.Now().UnixNano(), + "lastip": ctx.RemoteIP(), + "lastaddr": ip.Addr, + "lastlogon": time.Now().Unix(), })) } } else { diff --git a/api/ws/ws.go b/api/ws/ws.go index 5932317..df64fcf 100644 --- a/api/ws/ws.go +++ b/api/ws/ws.go @@ -3,7 +3,7 @@ package ws import ( "github.com/gin-gonic/gin" "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" + "github.com/huoxue1/qinglong-go/service/client" "github.com/huoxue1/qinglong-go/utils/res" ) @@ -25,8 +25,7 @@ func wsHandle() gin.HandlerFunc { ctx.JSON(502, res.Err(502, err)) return } - writer := wsutil.NewWriter(conn, ws.StateServerSide, ws.OpText) - writer.Write([]byte("pong")) - writer.Flush() + + client.AddWs(ctx.Param("id")+"_"+ctx.Param("name"), conn) } } diff --git a/main.go b/main.go index 9a92fdb..424459c 100644 --- a/main.go +++ b/main.go @@ -39,5 +39,5 @@ func init() { func main() { service.AppInit() engine := controller.Router() - _ = engine.Run(":8080") + _ = engine.Run(":5700") } diff --git a/service/client/client.go b/service/client/client.go new file mode 100644 index 0000000..0ee63fa --- /dev/null +++ b/service/client/client.go @@ -0,0 +1,57 @@ +package client + +import ( + "encoding/json" + "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) { + data := map[string]string{"type": "manuallyRunScript", "message": string(p)} + content, _ := json.Marshal(data) + var deleSlince []string + c.Range(func(key, value any) bool { + conn := value.(*Client).conn + 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 +} + +var ( + MyClient *Clients +) + +func init() { + MyClient = new(Clients) +} + +type Client struct { + conn net.Conn +} + +func AddWs(id string, conn net.Conn) { + MyClient.Store(id, &Client{ + conn: conn, + }) + +} diff --git a/service/config/config.go b/service/config/config.go index 943bdbc..a5fa5c2 100644 --- a/service/config/config.go +++ b/service/config/config.go @@ -6,6 +6,8 @@ import ( "regexp" ) +var VERSION = "test" + func GetKey(key string) string { file, err := os.ReadFile(path.Join("data", "config", "config.sh")) if err != nil { @@ -18,3 +20,7 @@ func GetKey(key string) string { datas := compile.FindAllStringSubmatch(string(file), 1) return datas[0][1] } + +func GetVersion() string { + return VERSION +} diff --git a/service/cron/cron.go b/service/cron/cron.go index 4f4df08..56cae17 100644 --- a/service/cron/cron.go +++ b/service/cron/cron.go @@ -20,7 +20,9 @@ func DeleteCron(ids []int) error { for _, id := range ids { c, _ := manager.Load(id) - c.(*cron.Cron).Stop() + if c != nil { + c.(*cron.Cron).Stop() + } err := models.DeleteCron(id) if err != nil { diff --git a/service/dependencies/dependencies.go b/service/dependencies/dependencies.go index 556fbc3..9d59533 100644 --- a/service/dependencies/dependencies.go +++ b/service/dependencies/dependencies.go @@ -16,6 +16,8 @@ func AddDep(dep *models.Dependences) { addNodeDep(dep) } else if dep.Type == models.PYTHON { addPythonDep(dep) + } else { + addLinuxDep(dep) } } @@ -60,3 +62,24 @@ func addPythonDep(dep *models.Dependences) { models.AddDependences(dep) }, buffer) } + +func addLinuxDep(dep *models.Dependences) { + log := "" + buffer := bytes.NewBufferString(log) + ctx := context.WithValue(context.Background(), "cancel", make(chan int, 1)) + now := time.Now() + utils.RunTask(ctx, fmt.Sprintf("apk add %s", dep.Name), map[string]string{}, 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")))) + }, 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()))) + dep.Status = 1 + var logs []string + for _, i2 := range strings.Split(buffer.String(), "\n") { + logs = append(logs, i2+"\n\n") + } + dep.Log = logs + models.AddDependences(dep) + }, buffer) +} diff --git a/service/env/env.go b/service/env/env.go index ff68465..8953ed3 100644 --- a/service/env/env.go +++ b/service/env/env.go @@ -109,3 +109,16 @@ func LoadEnvFromFile(file string) map[string]string { } return result } + +func GetALlEnv() map[string]string { + envFromDb := LoadEnvFromDb() + envfromFile := LoadEnvFromFile("data/config/config.sh") + for s, s2 := range envfromFile { + if _, ok := envFromDb[s]; ok { + envFromDb[s] = envFromDb[s] + "&" + s2 + } else { + envFromDb[s] = s2 + } + } + return envFromDb +} diff --git a/service/scripts/scripts.go b/service/scripts/scripts.go index 76ff601..3d0dc1f 100644 --- a/service/scripts/scripts.go +++ b/service/scripts/scripts.go @@ -2,10 +2,18 @@ package scripts import ( "bytes" + "context" + "fmt" + "github.com/huoxue1/qinglong-go/service/client" + "github.com/huoxue1/qinglong-go/service/env" "github.com/huoxue1/qinglong-go/utils" + "io" "os" "path" + "path/filepath" "sort" + "strings" + "time" ) type File struct { @@ -24,6 +32,38 @@ var ( } ) +func Run(filePath, content string) error { + err := os.WriteFile(path.Join("data", "scripts", filePath), []byte(content), 0666) + if err != nil { + return err + } + cmd := getCmd(filePath) + cancelChan := make(chan int, 1) + ctx := context.WithValue(context.Background(), "cancel", cancelChan) + now := time.Now() + utils.RunTask(ctx, cmd, env.GetALlEnv(), 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")))) + }, 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) + }, client.MyClient) + return nil +} + +func getCmd(filePath string) string { + ext := filepath.Ext(filePath) + switch ext { + case ".js": + return fmt.Sprintf("%s %s", "node", filePath) + case ".py": + return fmt.Sprintf("%s %s", "python", filePath) + + } + return "" +} + func GetFiles(base, p string) []*File { var files Files dir, err := os.ReadDir(path.Join(base, p)) @@ -46,6 +86,9 @@ func GetFiles(base, p string) []*File { files = append(files, f) } else { + if strings.HasPrefix(entry.Name(), "_") { + continue + } files = append(files, &File{ Key: path.Join(p, entry.Name()), Parent: p, diff --git a/service/user/user.go b/service/user/user.go index ca9b81b..1d8ddc3 100644 --- a/service/user/user.go +++ b/service/user/user.go @@ -2,6 +2,7 @@ package user import ( "encoding/json" + "github.com/huoxue1/qinglong-go/utils" "os" ) @@ -31,3 +32,25 @@ func GetUserInfo() (*Info, error) { return i, err } + +type Ip struct { + Ip string `json:"ip"` + Pro string `json:"pro"` + ProCode string `json:"proCode"` + City string `json:"city"` + CityCode string `json:"cityCode"` + Region string `json:"region"` + RegionCode string `json:"regionCode"` + Addr string `json:"addr"` + RegionNames string `json:"regionNames"` + Err string `json:"err"` +} + +func GetNetIp(ip string) (*Ip, error) { + i := new(Ip) + _, err := utils.GetClient().R().SetQueryParams(map[string]string{"ip": ip, "json": "true"}).SetResult(i).Get("https://whois.pconline.com.cn/ipJson.jsp") + if err != nil { + return nil, err + } + return i, nil +} diff --git a/utils/client.go b/utils/client.go new file mode 100644 index 0000000..aa17fa4 --- /dev/null +++ b/utils/client.go @@ -0,0 +1,18 @@ +package utils + +import ( + "github.com/imroc/req/v3" + "net/http" +) + +var ( + client *req.Client +) + +func init() { + client = req.C().SetProxy(http.ProxyFromEnvironment) +} + +func GetClient() *req.Client { + return client +}