// package mod_http -- http-движок для архитектуры package engine_http import ( "bytes" _ "embed" "fmt" "time" svg "github.com/ajstarks/svgo" "github.com/gofiber/fiber/v2" "gitp78su.ipnodns.ru/svi/kern/v3" "gitp78su.ipnodns.ru/svi/kern/v3/kc/log_buf" "gitp78su.ipnodns.ru/svi/kern/v3/krn/ktypes" "gopkg.in/yaml.v3" "gitp78su.ipnodns.ru/svi/goarch/lev0/alias" "gitp78su.ipnodns.ru/svi/goarch/lev0/cons" "gitp78su.ipnodns.ru/svi/goarch/lev0/types" "gitp78su.ipnodns.ru/svi/goarch/lev1/coord" "gitp78su.ipnodns.ru/svi/goarch/lev1/size" "gitp78su.ipnodns.ru/svi/goarch/pkg/elems/canvas" ) //go:embed index.html var indexHtml []byte // CanvasSize -- размер хоста type CanvasSize struct { SizeX_ int `form:"w"` SizeY_ int `form:"h"` } func (sf *CanvasSize) String() string { return fmt.Sprintf("w:%v; h:%v", sf.SizeX_, sf.SizeY_) } // EngineHttp -- http-движок для архитектуры type EngineHttp struct { // fibApp *fiber.App kCtx ktypes.IKernelCtx log ktypes.ILogBuf diaMode string // Режим диаграммы oldBinArch []byte // Кеш старой архитектуры canvSize CanvasSize // Размер холста size types.IViewSize // Размер холста в его координатах pos types.IViewCoord // Координаты холста mapDrawer types.IMapDrawer // Словарь отрисовщиков } // NewEngineHttp -- возвращает новый движок HTTP func NewEngineHttp() *EngineHttp { optTerm := log_buf.OptIsTerm(true) optPref := log_buf.OptPrefix("EngineHttp") log := log_buf.NewLogBuf(optTerm, optPref) sf := &EngineHttp{ kCtx: kern.GetKernelCtx(), log: log, diaMode: cons.ModeUseCase, size: size.NewSize(800, 600), pos: coord.NewCoord(0, 0), } sHttp := kern.GetKernelServerHttp() fibApp := sHttp.Fiber() fibApp.Static("/static", "./static", fiber.Static{ Compress: true, Browse: true, CacheDuration: time.Second * 10, }) fibApp.Get("/", sf.getIndex) fibApp.Get("/api/use_case", sf.postSetModeUseCase) fibApp.Post("/api/arch", sf.postArch) fibApp.Post("/api/canvas_size", sf.postSetCanvasSize) return sf } // FormArch -- извлекает данные из текстового поля для обновления type FormArch struct { StrData string `form:"text"` } // Устанавливает размер холста func (sf *EngineHttp) postSetCanvasSize(ctx *fiber.Ctx) error { err := ctx.BodyParser(&sf.canvSize) if err != nil { sf.log.Err("postSetCanvasSize(): on body parser, err=\n\t%v", err) } var ( w alias.SizeX h alias.SizeY ) if sf.canvSize.SizeX_ > 0 { w = alias.SizeX(sf.canvSize.SizeX_ - 10) } if sf.canvSize.SizeY_ > 0 { h = alias.SizeY(sf.canvSize.SizeY_ - 10) } sf.size = size.NewSize(w, h) return ctx.SendString(sf.size.String()) } // Возвращает новый холст func (sf *EngineHttp) canvas(wr *bytes.Buffer, lstElem []map[string]interface{}) (*svg.SVG, error) { var ( elem map[string]interface{} isFind, isOk bool _section interface{} ) for _, elem = range lstElem { _section, isOk = elem["type"] if !isOk { continue } section, isOk := _section.(string) if !isOk { return nil, fmt.Errorf("ServHttp.canvas(): in mapElem, type(%#+v) not string
%#+v", _section, elem) } if section == cons.SectionConfig { isFind = true break } } if !isFind { return nil, fmt.Errorf("ServHttp.canvas(): in mapElem, config not found") } confCanvas := canvas.NewCanvas(sf.diaMode, sf.size, sf.pos) sizeX, sizeY := confCanvas.Size().Int() canvas := svg.New(wr) canvas.Start(sizeX, sizeY) confCanvas.Draw(canvas) return canvas, nil } // По запросу парсит, что получилось -- обновляет архитектуру func (sf *EngineHttp) postArch(ctx *fiber.Ctx) error { form := &FormArch{} if err := ctx.BodyParser(form); err != nil { return ctx.SendString(fmt.Sprintf("ServHttp.archPost(): in BodyParser, err=
%v", err)) } binData := []byte(form.StrData) if len(binData) == len(sf.oldBinArch) { return ctx.Send(sf.oldBinArch) } mapElem := []map[string]interface{}{} err := yaml.Unmarshal(binData, &mapElem) if err != nil { return ctx.SendString(fmt.Sprintf("ServHttp.archPost(): in Decode JSON, err=
%v", err)) } wr := bytes.NewBuffer(nil) canvas, err := sf.canvas(wr, mapElem) if err != nil { return ctx.SendString(fmt.Sprintf("ServHttp.archPost(): in create canvas, err=
%v", err)) } switch sf.diaMode { case cons.ModeUseCase: // режим вариантов использования if err := sf.useCase(canvas); err != nil { return ctx.SendString(fmt.Sprintf("ServHttp.archPost(): in useCase, err=
%v", err)) } default: // неизвестный режим return ctx.SendString(fmt.Sprintf("ServHttp.archPost(): unknown mode=%q", sf.diaMode)) } canvas.End() binData = wr.Bytes() return ctx.Send(binData) } // Формирует варианты использования func (sf *EngineHttp) useCase(canvas *svg.SVG) error { for _, elem := range sf.mapDrawer.LstDrawers() { elem.Draw(canvas) } return nil } // Возвращает картинку архитектуры func (sf *EngineHttp) postSetModeUseCase(ctx *fiber.Ctx) error { sf.diaMode = cons.ModeUseCase return ctx.SendString("[mode='" + sf.diaMode + "']") } // Возвращает главную страницу сервиса func (sf *EngineHttp) getIndex(ctx *fiber.Ctx) error { ctx.Response().Header.Set("Content-Type", "text/html") return ctx.Send(indexHtml) }