serv_http.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // package mod_http -- http-движок для архитектуры
  2. package engine_http
  3. import (
  4. "bytes"
  5. _ "embed"
  6. "fmt"
  7. "time"
  8. svg "github.com/ajstarks/svgo"
  9. "github.com/gofiber/fiber/v2"
  10. "gitp78su.ipnodns.ru/svi/kern/v3"
  11. "gitp78su.ipnodns.ru/svi/kern/v3/kc/log_buf"
  12. "gitp78su.ipnodns.ru/svi/kern/v3/krn/ktypes"
  13. "gopkg.in/yaml.v3"
  14. "gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
  15. "gitp78su.ipnodns.ru/svi/goarch/lev0/cons"
  16. "gitp78su.ipnodns.ru/svi/goarch/lev0/types"
  17. "gitp78su.ipnodns.ru/svi/goarch/lev1/coord"
  18. "gitp78su.ipnodns.ru/svi/goarch/lev1/size"
  19. "gitp78su.ipnodns.ru/svi/goarch/pkg/elems/canvas"
  20. )
  21. //go:embed index.html
  22. var indexHtml []byte
  23. // CanvasSize -- размер хоста
  24. type CanvasSize struct {
  25. SizeX_ int `form:"w"`
  26. SizeY_ int `form:"h"`
  27. }
  28. func (sf *CanvasSize) String() string {
  29. return fmt.Sprintf("w:%v; h:%v", sf.SizeX_, sf.SizeY_)
  30. }
  31. // EngineHttp -- http-движок для архитектуры
  32. type EngineHttp struct {
  33. // fibApp *fiber.App
  34. kCtx ktypes.IKernelCtx
  35. log ktypes.ILogBuf
  36. diaMode string // Режим диаграммы
  37. oldBinArch []byte // Кеш старой архитектуры
  38. canvSize CanvasSize // Размер холста
  39. size types.IViewSize // Размер холста в его координатах
  40. pos types.IViewCoord // Координаты холста
  41. mapDrawer types.IMapDrawer // Словарь отрисовщиков
  42. }
  43. // NewEngineHttp -- возвращает новый движок HTTP
  44. func NewEngineHttp() *EngineHttp {
  45. optTerm := log_buf.OptIsTerm(true)
  46. optPref := log_buf.OptPrefix("EngineHttp")
  47. log := log_buf.NewLogBuf(optTerm, optPref)
  48. sf := &EngineHttp{
  49. kCtx: kern.GetKernelCtx(),
  50. log: log,
  51. diaMode: cons.ModeUseCase,
  52. size: size.NewSize(800, 600),
  53. pos: coord.NewCoord(0, 0),
  54. }
  55. sHttp := kern.GetKernelServerHttp()
  56. fibApp := sHttp.Fiber()
  57. fibApp.Static("/static", "./static", fiber.Static{
  58. Compress: true,
  59. Browse: true,
  60. CacheDuration: time.Second * 10,
  61. })
  62. fibApp.Get("/", sf.getIndex)
  63. fibApp.Get("/api/use_case", sf.postSetModeUseCase)
  64. fibApp.Post("/api/arch", sf.postArch)
  65. fibApp.Post("/api/canvas_size", sf.postSetCanvasSize)
  66. return sf
  67. }
  68. // FormArch -- извлекает данные из текстового поля для обновления
  69. type FormArch struct {
  70. StrData string `form:"text"`
  71. }
  72. // Устанавливает размер холста
  73. func (sf *EngineHttp) postSetCanvasSize(ctx *fiber.Ctx) error {
  74. err := ctx.BodyParser(&sf.canvSize)
  75. if err != nil {
  76. sf.log.Err("postSetCanvasSize(): on body parser, err=\n\t%v", err)
  77. }
  78. var (
  79. w alias.SizeX
  80. h alias.SizeY
  81. )
  82. if sf.canvSize.SizeX_ > 0 {
  83. w = alias.SizeX(sf.canvSize.SizeX_ - 10)
  84. }
  85. if sf.canvSize.SizeY_ > 0 {
  86. h = alias.SizeY(sf.canvSize.SizeY_ - 10)
  87. }
  88. sf.size = size.NewSize(w, h)
  89. return ctx.SendString(sf.size.String())
  90. }
  91. // Возвращает новый холст
  92. func (sf *EngineHttp) canvas(wr *bytes.Buffer, lstElem []map[string]interface{}) (*svg.SVG, error) {
  93. var (
  94. elem map[string]interface{}
  95. isFind, isOk bool
  96. _section interface{}
  97. )
  98. for _, elem = range lstElem {
  99. _section, isOk = elem["type"]
  100. if !isOk {
  101. continue
  102. }
  103. section, isOk := _section.(string)
  104. if !isOk {
  105. return nil, fmt.Errorf("ServHttp.canvas(): in mapElem, type(%#+v) not string<br>%#+v", _section, elem)
  106. }
  107. if section == cons.SectionConfig {
  108. isFind = true
  109. break
  110. }
  111. }
  112. if !isFind {
  113. return nil, fmt.Errorf("ServHttp.canvas(): in mapElem, config not found")
  114. }
  115. confCanvas := canvas.NewCanvas(sf.diaMode, sf.size, sf.pos)
  116. sizeX, sizeY := confCanvas.Size().Int()
  117. canvas := svg.New(wr)
  118. canvas.Start(sizeX, sizeY)
  119. confCanvas.Draw(canvas)
  120. return canvas, nil
  121. }
  122. // По запросу парсит, что получилось -- обновляет архитектуру
  123. func (sf *EngineHttp) postArch(ctx *fiber.Ctx) error {
  124. form := &FormArch{}
  125. if err := ctx.BodyParser(form); err != nil {
  126. return ctx.SendString(fmt.Sprintf("ServHttp.archPost(): in BodyParser, err=<br>%v", err))
  127. }
  128. binData := []byte(form.StrData)
  129. if len(binData) == len(sf.oldBinArch) {
  130. return ctx.Send(sf.oldBinArch)
  131. }
  132. mapElem := []map[string]interface{}{}
  133. err := yaml.Unmarshal(binData, &mapElem)
  134. if err != nil {
  135. return ctx.SendString(fmt.Sprintf("ServHttp.archPost(): in Decode JSON, err=<br>%v", err))
  136. }
  137. wr := bytes.NewBuffer(nil)
  138. canvas, err := sf.canvas(wr, mapElem)
  139. if err != nil {
  140. return ctx.SendString(fmt.Sprintf("ServHttp.archPost(): in create canvas, err=<br>%v", err))
  141. }
  142. switch sf.diaMode {
  143. case cons.ModeUseCase: // режим вариантов использования
  144. if err := sf.useCase(canvas); err != nil {
  145. return ctx.SendString(fmt.Sprintf("ServHttp.archPost(): in useCase, err=<br>%v", err))
  146. }
  147. default: // неизвестный режим
  148. return ctx.SendString(fmt.Sprintf("ServHttp.archPost(): unknown mode=%q", sf.diaMode))
  149. }
  150. canvas.End()
  151. binData = wr.Bytes()
  152. return ctx.Send(binData)
  153. }
  154. // Формирует варианты использования
  155. func (sf *EngineHttp) useCase(canvas *svg.SVG) error {
  156. for _, elem := range sf.mapDrawer.LstDrawers() {
  157. elem.Draw(canvas)
  158. }
  159. return nil
  160. }
  161. // Возвращает картинку архитектуры
  162. func (sf *EngineHttp) postSetModeUseCase(ctx *fiber.Ctx) error {
  163. sf.diaMode = cons.ModeUseCase
  164. return ctx.SendString("[mode='" + sf.diaMode + "']")
  165. }
  166. // Возвращает главную страницу сервиса
  167. func (sf *EngineHttp) getIndex(ctx *fiber.Ctx) error {
  168. ctx.Response().Header.Set("Content-Type", "text/html")
  169. return ctx.Send(indexHtml)
  170. }