| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- package main
- import (
- "encoding/json"
- "fmt"
- "io"
- "net/http"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
- "time"
- "hnyfkj.com.cn/rtu/linux/baseapp"
- )
- const maxUploadSize = 1 << 30 // 1GB
- func downloadAppInstallLog(w http.ResponseWriter, r *http.Request) {
- if r.Method != http.MethodGet {
- http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
- return
- }
- filename := fmt.Sprintf("app-install.log.%s.tar.gz", time.Now().Format("20060102150405"))
- tmpFile := fmt.Sprintf("/tmp/%d.tar.gz", time.Now().UnixNano())
- defer os.Remove(tmpFile)
- cmd := exec.Command(
- "tar",
- "--warning=no-file-changed",
- "-czf",
- tmpFile,
- "-C",
- "/opt/yfkj/app-install.service/log",
- ".",
- )
- out, err := cmd.CombinedOutput()
- if err != nil {
- if exitErr, ok := err.(*exec.ExitError); !ok || exitErr.ExitCode() != 1 {
- http.Error(w, string(out), http.StatusInternalServerError)
- return
- }
- }
- w.Header().Set("Content-Type", "application/gzip")
- w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename))
- http.ServeFile(w, r, tmpFile)
- }
- func restartAppInstallService(w http.ResponseWriter, r *http.Request) {
- if r.Method != http.MethodPost {
- http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
- return
- }
- cmd := exec.Command("systemctl", "restart", "yfkj-app-install.service")
- if out, err := cmd.CombinedOutput(); err != nil {
- http.Error(w, string(out)+err.Error(), http.StatusInternalServerError)
- return
- }
- w.Header().Set("Content-Type", "application/json")
- w.Write([]byte(`{"status":"ok"}`))
- }
- func getUserAppStatus() (string, string) {
- status := noValue
- pid := noValue
- out, err := exec.Command("systemctl", "show", "yfkj-user-app.service",
- "-p", "LoadState",
- "-p", "ActiveState",
- "-p", "SubState",
- "-p", "MainPID").Output()
- if err != nil {
- return status, pid
- }
- v := string(out)
- switch {
- case strings.Contains(v, "ActiveState=active") &&
- strings.Contains(v, "SubState=running"):
- status = "🟢运行中"
- case strings.Contains(v, "ActiveState=active") &&
- strings.Contains(v, "SubState=exited"):
- status = "🔵已完成"
- case strings.Contains(v, "LoadState=loaded") &&
- strings.Contains(v, "ActiveState=inactive"):
- status = "🟡已停止"
- }
- for _, line := range strings.Split(v, "\n") {
- if after, ok := strings.CutPrefix(line, "MainPID="); ok {
- if after != "" && after != "0" {
- pid = after
- }
- break
- }
- }
- return status, pid
- }
- func appInstallStatusHandler(w http.ResponseWriter, r *http.Request) {
- var info *struct {
- Pkg struct {
- FileName string `json:"fileName"`
- FileSize int64 `json:"fileSize"`
- FileMD5 string `json:"fileMD5"`
- UploadTime string `json:"uploadTime"`
- } `json:"pkg"`
- App struct {
- Name string `json:"name"`
- Version string `json:"version"`
- Executable string `json:"executable"`
- Description string `json:"description"`
- ReadmeFile string `json:"readmeFile"`
- } `json:"app"`
- Ins struct {
- Installed bool `json:"installed"`
- InstallTime string `json:"installTime"`
- } `json:"ins"`
- }
- callErr := callRPCResult(r.Context(), 7004, "core.getInstallInfo", nil, &info)
- data := map[string]string{
- "state": "0",
- "avar1": noValue,
- "avar2": noValue,
- "avar3": noValue,
- "avar4": noValue,
- "bvar1": noValue,
- "bvar2": noValue,
- "bvar3": noValue,
- "bvar4": noValue,
- "bvar5": noValue,
- "cvar1": noValue,
- "cvar2": noValue,
- "cvar3": noValue,
- "cvar4": noValue,
- "cvar5": noValue,
- }
- if callErr == nil {
- data["avar1"] = "🟢正常"
- if info != nil {
- data["bvar1"] = info.Pkg.FileName
- data["bvar2"] = fmt.Sprintf("%d 字节", info.Pkg.FileSize)
- data["bvar3"] = info.Pkg.FileMD5
- data["bvar4"] = info.Pkg.UploadTime
- data["cvar1"] = info.App.Name
- data["cvar2"] = info.App.Version
- data["cvar3"] = info.App.Executable
- data["cvar4"] = info.Ins.InstallTime
- data["cvar5"] = info.App.ReadmeFile
- if info.Ins.Installed {
- data["state"] = "2"
- data["avar2"] = info.App.Name
- data["avar3"], data["avar4"] = getUserAppStatus()
- data["bvar5"] = "已安装"
- } else {
- data["state"] = "1"
- data["bvar5"] = "未安装"
- }
- }
- }
- w.Header().Set("Content-Type", "application/json; charset=utf-8")
- json.NewEncoder(w).Encode(data)
- }
- func uploadUserAPP(w http.ResponseWriter, r *http.Request) {
- if r.Method != http.MethodPost {
- http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
- return
- }
- r.Body = http.MaxBytesReader(w, r.Body, maxUploadSize)
- err := r.ParseMultipartForm(maxUploadSize)
- if err != nil {
- http.Error(w, "解析上传文件失败: "+err.Error(), http.StatusBadRequest)
- return
- }
- file, header, err := r.FormFile("file")
- if err != nil {
- http.Error(w, "获取上传文件失败: "+err.Error(), http.StatusBadRequest)
- return
- }
- defer file.Close()
- if !strings.HasSuffix(strings.ToLower(header.Filename), ".tar.gz") {
- http.Error(w, "只允许上传 tar.gz 类型的文件", http.StatusBadRequest)
- return
- }
- path := filepath.Join("/tmp", filepath.Base(header.Filename))
- err = saveUploadFile(file, path)
- if err != nil {
- http.Error(w, "保存上传文件失败: "+err.Error(), http.StatusInternalServerError)
- return
- }
- baseapp.Logger.Infof(
- "[上传文件成功] 上传文件名: %s, 上传文件大小: %d 字节, 本地存储路径: %s",
- header.Filename, header.Size, path)
- w.WriteHeader(http.StatusOK)
- }
- func saveUploadFile(src io.Reader, path string) error {
- dst, err := os.Create(path)
- if err != nil {
- return err
- }
- defer dst.Close()
- _, err = io.Copy(dst, src)
- if err != nil {
- os.Remove(path)
- return err
- }
- return nil
- }
|