web.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "git.swzry.com/zry/GoHiedaLogger/hieda_ginutil"
  6. "git.swzry.com/zry/GoHiedaLogger/hiedalog"
  7. "git.swzry.com/zry/ran-proc/rpcore"
  8. "github.com/gin-gonic/gin"
  9. "github.com/hashicorp/go-uuid"
  10. "github.com/liushuochen/gotable"
  11. "net/http"
  12. "os"
  13. "time"
  14. )
  15. type WebServerClass struct {
  16. engine *gin.Engine
  17. httpServer *http.Server
  18. apiGroup *gin.RouterGroup
  19. wsGroup *gin.RouterGroup
  20. }
  21. func NewWebServer() *WebServerClass {
  22. web := &WebServerClass{
  23. engine: gin.New(),
  24. }
  25. glf := hieda_ginutil.GinLoggerWithComplexLogger(hieda_ginutil.GinLoggerConfig{
  26. Logger: Logger,
  27. ModuleName: "web",
  28. LevelMapFunc: hieda_ginutil.GetDefaultLevelMapFunc(),
  29. })
  30. web.engine.Use(glf, gin.Recovery())
  31. web.httpServer = &http.Server{
  32. Addr: "0.0.0.0:9198",
  33. Handler: web.engine,
  34. }
  35. return web
  36. }
  37. func (s *WebServerClass) Run() error {
  38. s.defineRoutes()
  39. return s.httpServer.ListenAndServe()
  40. }
  41. func (s *WebServerClass) Stop(_ error) {
  42. ctx, cncl := context.WithTimeout(context.Background(), 10*time.Second)
  43. defer cncl()
  44. err := s.httpServer.Shutdown(ctx)
  45. if err != nil {
  46. Logger.LogPrint("main", hiedalog.DLN_ERROR, "error in shutting down web server: ", err)
  47. }
  48. }
  49. func (s *WebServerClass) defineRoutes() {
  50. s.engine.GET("/", s.wh_ListAllStatus)
  51. s.apiGroup = s.engine.Group("/api/")
  52. s.wsGroup = s.engine.Group("/ws/")
  53. s.wsGroup.GET("/get-cmd-output.satori", s.wh_ReadCmdOutput)
  54. s.apiGroup.POST("/new-task.satori", s.wh_NewTask)
  55. }
  56. func (s *WebServerClass) wh_ListAllStatus(ctx *gin.Context) {
  57. st, err := PM.ListAllStatus()
  58. if err != nil {
  59. ctx.String(500, "500 Internal Server Error")
  60. Logger.LogPrint("web-api", hiedalog.DLN_WARN, "failed list status: ", err)
  61. return
  62. }
  63. tb, err := gotable.Create("CPID", "Name", "Status", "PID", "Last Start Time")
  64. if err != nil {
  65. ctx.String(500, "500 Internal Server Error")
  66. Logger.LogPrint("web-api", hiedalog.DLN_WARN, "failed create table: ", err)
  67. return
  68. }
  69. for _, v := range st {
  70. err = tb.AddRow(v.ToPrintableTableData())
  71. if err != nil {
  72. Logger.LogPrint("debug", hiedalog.DLN_INFO, "Failed Print Table:", err)
  73. }
  74. }
  75. ctx.String(200, tb.String())
  76. }
  77. func (s *WebServerClass) ApiChecker(ctx *gin.Context, BindObj interface{}) bool {
  78. key := ctx.GetHeader("AuthKey")
  79. if key != AccessKey {
  80. ctx.JSON(403, &gin.H{
  81. "status": "403",
  82. "errMsg": "auth failed",
  83. })
  84. Logger.LogPrintf("web-api", hiedalog.DLN_VERBOSE, "client %s auth failed", ctx.Request.RemoteAddr)
  85. return false
  86. }
  87. err := ctx.BindJSON(BindObj)
  88. if err != nil {
  89. ctx.JSON(400, &gin.H{
  90. "status": "400",
  91. "errMsg": "bad request json format",
  92. })
  93. Logger.LogPrintf("web-api", hiedalog.DLN_VERBOSE, "client %s request json invalid: %v", ctx.Request.RemoteAddr, err)
  94. return false
  95. }
  96. return true
  97. }
  98. func (s *WebServerClass) wh_ReadCmdOutput(ctx *gin.Context) {
  99. key := ctx.Query("auth-key")
  100. if key != AccessKey {
  101. ctx.JSON(403, &gin.H{
  102. "status": "403",
  103. "errMsg": "auth failed",
  104. })
  105. Logger.LogPrintf("web-api", hiedalog.DLN_VERBOSE, "client %s auth failed", ctx.Request.RemoteAddr)
  106. return
  107. }
  108. WsLogDistr.HandleNewConnections(ctx)
  109. }
  110. func (s *WebServerClass) wh_NewTask(ctx *gin.Context) {
  111. var input ApiJsonDef_NewTask
  112. if !s.ApiChecker(ctx, &input) {
  113. return
  114. }
  115. taskName := input.TaskName
  116. if taskName == "" {
  117. ustr, _ := uuid.GenerateUUID()
  118. taskName = fmt.Sprintf("task-%s", ustr)
  119. }
  120. cpid, err := PM.CreateTask(&rpcore.NewTaskConfig{
  121. Name: taskName,
  122. CmdInfo: &rpcore.CmdInfoClass{
  123. Name: input.ExecutablePath,
  124. Args: append([]string{input.ExecutablePath}, input.Args...),
  125. Env: os.Environ(),
  126. Dir: input.WorkDir,
  127. Stdin: nil,
  128. Stdout: WsLogDistr,
  129. Stderr: WsLogDistr,
  130. },
  131. DoneCallback: func(cpid int64, name string) {
  132. Logger.LogPrintf("task-done", hiedalog.DLN_INFO, "task (cpid=%16X, name='%s') done.", cpid, name)
  133. },
  134. ExecTimeout: time.Duration(input.ExecTimeout) * time.Millisecond,
  135. ShutdownTimeout: 10 * time.Second,
  136. ShutdownActor: GracefulShutdownActorForThis,
  137. })
  138. if err != nil {
  139. ctx.JSON(500, &gin.H{
  140. "status": "500",
  141. "errMsg": "failed create task: internal error",
  142. })
  143. Logger.LogPrint("web-api", hiedalog.DLN_WARN, "failed create task: ", err)
  144. return
  145. }
  146. ctx.JSON(200, &gin.H{
  147. "status": "200",
  148. "infoMsg": "task created",
  149. "cpid": fmt.Sprintf("%16X", cpid),
  150. "name": taskName,
  151. })
  152. }
  153. func (s *WebServerClass) wh_NewDaemon(ctx *gin.Context) {
  154. var input ApiJsonDef_NewDaemon
  155. if !s.ApiChecker(ctx, &input) {
  156. return
  157. }
  158. daemonName := input.DaemonName
  159. if daemonName == "" {
  160. ctx.JSON(500, &gin.H{
  161. "status": "400",
  162. "errMsg": "failed create daemon: daemonName should not be empty",
  163. })
  164. Logger.LogPrint("web-api", hiedalog.DLN_WARN, "failed create task: daemonName should not be empty")
  165. return
  166. }
  167. cpid, err := PM.CreateDaemon(&rpcore.NewDaemonConfig{
  168. Name: daemonName,
  169. CmdInfo: &rpcore.CmdInfoClass{
  170. Name: input.ExecutablePath,
  171. Args: append([]string{input.ExecutablePath}, input.Args...),
  172. Env: os.Environ(),
  173. Dir: input.WorkDir,
  174. Stdin: nil,
  175. Stdout: WsLogDistr,
  176. Stderr: WsLogDistr,
  177. },
  178. ShutdownTimeout: 10 * time.Second,
  179. ShutdownActor: GracefulShutdownActorForThis,
  180. EnableAfterCreate: input.EnableAfterCreate,
  181. })
  182. if err != nil {
  183. ctx.JSON(500, &gin.H{
  184. "status": "500",
  185. "errMsg": "failed create daemon: internal error",
  186. })
  187. Logger.LogPrint("web-api", hiedalog.DLN_WARN, "failed create daemon: ", err)
  188. return
  189. }
  190. ctx.JSON(200, &gin.H{
  191. "status": "200",
  192. "infoMsg": "task created",
  193. "cpid": fmt.Sprintf("%16X", cpid),
  194. "name": daemonName,
  195. })
  196. }