page6_handler.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "net/http"
  7. "os"
  8. "os/exec"
  9. "path/filepath"
  10. "strings"
  11. "time"
  12. "hnyfkj.com.cn/rtu/linux/baseapp"
  13. )
  14. const maxUploadSize = 1 << 30 // 1GB
  15. func downloadAppInstallLog(w http.ResponseWriter, r *http.Request) {
  16. if r.Method != http.MethodGet {
  17. http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
  18. return
  19. }
  20. filename := fmt.Sprintf("app-install.log.%s.tar.gz", time.Now().Format("20060102150405"))
  21. tmpFile := fmt.Sprintf("/tmp/%d.tar.gz", time.Now().UnixNano())
  22. defer os.Remove(tmpFile)
  23. cmd := exec.Command(
  24. "tar",
  25. "--warning=no-file-changed",
  26. "-czf",
  27. tmpFile,
  28. "-C",
  29. "/opt/yfkj/app-install.service/log",
  30. ".",
  31. )
  32. out, err := cmd.CombinedOutput()
  33. if err != nil {
  34. if exitErr, ok := err.(*exec.ExitError); !ok || exitErr.ExitCode() != 1 {
  35. http.Error(w, string(out), http.StatusInternalServerError)
  36. return
  37. }
  38. }
  39. w.Header().Set("Content-Type", "application/gzip")
  40. w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename))
  41. http.ServeFile(w, r, tmpFile)
  42. }
  43. func restartAppInstallService(w http.ResponseWriter, r *http.Request) {
  44. if r.Method != http.MethodPost {
  45. http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
  46. return
  47. }
  48. cmd := exec.Command("systemctl", "restart", "yfkj-app-install.service")
  49. if out, err := cmd.CombinedOutput(); err != nil {
  50. http.Error(w, string(out)+err.Error(), http.StatusInternalServerError)
  51. return
  52. }
  53. w.Header().Set("Content-Type", "application/json")
  54. w.Write([]byte(`{"status":"ok"}`))
  55. }
  56. func getUserAppStatus() (string, string) {
  57. status := noValue
  58. pid := noValue
  59. out, err := exec.Command("systemctl", "show", "yfkj-user-app.service",
  60. "-p", "LoadState",
  61. "-p", "ActiveState",
  62. "-p", "SubState",
  63. "-p", "MainPID").Output()
  64. if err != nil {
  65. return status, pid
  66. }
  67. v := string(out)
  68. switch {
  69. case strings.Contains(v, "ActiveState=active") &&
  70. strings.Contains(v, "SubState=running"):
  71. status = "🟢运行中"
  72. case strings.Contains(v, "ActiveState=active") &&
  73. strings.Contains(v, "SubState=exited"):
  74. status = "🔵已完成"
  75. case strings.Contains(v, "LoadState=loaded") &&
  76. strings.Contains(v, "ActiveState=inactive"):
  77. status = "🟡已停止"
  78. }
  79. for _, line := range strings.Split(v, "\n") {
  80. if after, ok := strings.CutPrefix(line, "MainPID="); ok {
  81. if after != "" && after != "0" {
  82. pid = after
  83. }
  84. break
  85. }
  86. }
  87. return status, pid
  88. }
  89. func appInstallStatusHandler(w http.ResponseWriter, r *http.Request) {
  90. var info *struct {
  91. Pkg struct {
  92. FileName string `json:"fileName"`
  93. FileSize int64 `json:"fileSize"`
  94. FileMD5 string `json:"fileMD5"`
  95. UploadTime string `json:"uploadTime"`
  96. } `json:"pkg"`
  97. App struct {
  98. Name string `json:"name"`
  99. Version string `json:"version"`
  100. Executable string `json:"executable"`
  101. Description string `json:"description"`
  102. ReadmeFile string `json:"readmeFile"`
  103. } `json:"app"`
  104. Ins struct {
  105. Installed bool `json:"installed"`
  106. InstallTime string `json:"installTime"`
  107. } `json:"ins"`
  108. }
  109. callErr := callRPCResult(r.Context(), 7004, "core.getInstallInfo", nil, &info)
  110. data := map[string]string{
  111. "state": "0",
  112. "avar1": noValue,
  113. "avar2": noValue,
  114. "avar3": noValue,
  115. "avar4": noValue,
  116. "bvar1": noValue,
  117. "bvar2": noValue,
  118. "bvar3": noValue,
  119. "bvar4": noValue,
  120. "bvar5": noValue,
  121. "cvar1": noValue,
  122. "cvar2": noValue,
  123. "cvar3": noValue,
  124. "cvar4": noValue,
  125. "cvar5": noValue,
  126. }
  127. if callErr == nil {
  128. data["avar1"] = "🟢正常"
  129. if info != nil {
  130. data["bvar1"] = info.Pkg.FileName
  131. data["bvar2"] = fmt.Sprintf("%d 字节", info.Pkg.FileSize)
  132. data["bvar3"] = info.Pkg.FileMD5
  133. data["bvar4"] = info.Pkg.UploadTime
  134. data["cvar1"] = info.App.Name
  135. data["cvar2"] = info.App.Version
  136. data["cvar3"] = info.App.Executable
  137. data["cvar4"] = info.Ins.InstallTime
  138. data["cvar5"] = info.App.ReadmeFile
  139. if info.Ins.Installed {
  140. data["state"] = "2"
  141. data["avar2"] = info.App.Name
  142. data["avar3"], data["avar4"] = getUserAppStatus()
  143. data["bvar5"] = "已安装"
  144. } else {
  145. data["state"] = "1"
  146. data["bvar5"] = "未安装"
  147. }
  148. }
  149. }
  150. w.Header().Set("Content-Type", "application/json; charset=utf-8")
  151. json.NewEncoder(w).Encode(data)
  152. }
  153. func uploadUserAPP(w http.ResponseWriter, r *http.Request) {
  154. if r.Method != http.MethodPost {
  155. http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
  156. return
  157. }
  158. r.Body = http.MaxBytesReader(w, r.Body, maxUploadSize)
  159. err := r.ParseMultipartForm(maxUploadSize)
  160. if err != nil {
  161. http.Error(w, "解析上传文件失败: "+err.Error(), http.StatusBadRequest)
  162. return
  163. }
  164. file, header, err := r.FormFile("file")
  165. if err != nil {
  166. http.Error(w, "获取上传文件失败: "+err.Error(), http.StatusBadRequest)
  167. return
  168. }
  169. defer file.Close()
  170. if !strings.HasSuffix(strings.ToLower(header.Filename), ".tar.gz") {
  171. http.Error(w, "只允许上传 tar.gz 类型的文件", http.StatusBadRequest)
  172. return
  173. }
  174. path := filepath.Join("/tmp", filepath.Base(header.Filename))
  175. err = saveUploadFile(file, path)
  176. if err != nil {
  177. http.Error(w, "保存上传文件失败: "+err.Error(), http.StatusInternalServerError)
  178. return
  179. }
  180. baseapp.Logger.Infof(
  181. "[上传文件成功] 上传文件名: %s, 上传文件大小: %d 字节, 本地存储路径: %s",
  182. header.Filename, header.Size, path)
  183. w.WriteHeader(http.StatusOK)
  184. }
  185. func saveUploadFile(src io.Reader, path string) error {
  186. dst, err := os.Create(path)
  187. if err != nil {
  188. return err
  189. }
  190. defer dst.Close()
  191. _, err = io.Copy(dst, src)
  192. if err != nil {
  193. os.Remove(path)
  194. return err
  195. }
  196. return nil
  197. }