Убраны файлы и добавлен лог файл

This commit is contained in:
Anatoly Prohacky 2023-04-25 20:06:02 +10:00
parent 2592598ce3
commit 20d0a2bddd
11 changed files with 247 additions and 130 deletions

4
.gitignore vendored
View File

@ -8,9 +8,7 @@
# Local History for Visual Studio Code
.history/
convert/*
upload/*
log/*
# Built Visual Studio Code Extensions
*.vsix

View File

@ -1,24 +1,25 @@
package main
import (
"os"
"flag"
"fmt"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
"gitstore.ru/tolikproh/sirius/internal/model"
"gitstore.ru/tolikproh/sirius/internal/server"
)
func main() {
log.SetFormatter(&log.JSONFormatter{})
log.SetOutput(os.Stdout)
log.SetLevel(log.WarnLevel)
flag.Parse()
if err := model.Init(); err != nil {
log.Fatalf("%s", err.Error())
cfg, err := initConfig()
if err != nil {
fmt.Printf("Error initializing configs file (configs set default): %s\n", err.Error())
}
app := server.NewApp(viper.GetString("port"))
log := NewLogger(cfg)
app := server.New(cfg, log)
fmt.Printf("Start server on lister port: %s\n", cfg.Srv.Port)
if err := app.Run(); err != nil {
log.Fatalf("%s", err.Error())

View File

@ -1 +0,0 @@
port: 8188

17
configs/config.yml Normal file
View File

@ -0,0 +1,17 @@
srv:
hostname: "gitstore.ru"
port: 8188
mode: release #Running in "release, debug, test" mode Switch to "release" mode in production.
# Logger log level:
# PanicLevel = 0
# FatalLevel = 1
# ErrorLevel = 2
# WarnLevel = 3
# InfoLevel = 4
# DebugLevel = 5
# TraceLevel = 6
loglevel: 6
logpath: "./log"
maxsizefile: 1 # Max size file for upload [MegaByte]

3
go.mod
View File

@ -35,6 +35,7 @@ require (
golang.org/x/sys v0.7.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
@ -45,7 +46,9 @@ require (
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.3 // indirect
github.com/sirupsen/logrus v1.9.0
github.com/snowzach/rotatefilehook v0.0.0-20220211133110-53752135082d
github.com/spf13/viper v1.15.0
github.com/toorop/gin-logrus v0.0.0-20210225092905-2c785434f26f
github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
golang.org/x/crypto v0.8.0 // indirect

6
go.sum
View File

@ -201,6 +201,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/snowzach/rotatefilehook v0.0.0-20220211133110-53752135082d h1:4660u5vJtsyrn3QwJNfESwCws+TM1CMhRn123xjVyQ8=
github.com/snowzach/rotatefilehook v0.0.0-20220211133110-53752135082d/go.mod h1:ZLVe3VfhAuMYLYWliGEydMBoRnfib8EFSqkBYu1ck9E=
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
@ -226,6 +228,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/toorop/gin-logrus v0.0.0-20210225092905-2c785434f26f h1:oqdnd6OGlOUu1InG37hWcCB3a+Jy3fwjylyVboaNMwY=
github.com/toorop/gin-logrus v0.0.0-20210225092905-2c785434f26f/go.mod h1:X3Dd1SB8Gt1V968NTzpKFjMM6O8ccta2NPC6MprOxZQ=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
@ -568,6 +572,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -0,0 +1,103 @@
package handler
import (
"bytes"
"encoding/json"
"errors"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/xuri/excelize/v2"
"gitstore.ru/tolikproh/sirius/internal/model"
)
var (
TEXT_TYPES = map[string]interface{}{
"text/plain; charset=utf-8": nil,
}
)
func (s *Handler) GinConvert(c *gin.Context) {
s.log.Debug("start convert")
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, s.cfg.Srv.MaxSizeFile<<20)
file, fileHeader, err := c.Request.FormFile("file")
if err != nil {
s.log.Errorf("error code: 001. %s", err.Error())
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
defer file.Close()
buffer := make([]byte, fileHeader.Size)
file.Read(buffer)
buffer = bytes.TrimPrefix(buffer, []byte("\xef\xbb\xbf"))
fileType := http.DetectContentType(buffer)
// Validate File Type
if _, ex := TEXT_TYPES[fileType]; !ex {
s.log.Errorf("error code: 002. formated data not text/plain")
c.JSON(http.StatusBadRequest, gin.H{
"error": errors.New("formated data not text/plain").Error(),
})
return
}
if !json.Valid(buffer) {
s.log.Errorf("error code: 003. formated data not json")
c.JSON(http.StatusBadRequest, gin.H{
"error": errors.New("formated data not json").Error(),
})
return
}
var sirius model.Sirius
err = json.Unmarshal(buffer, &sirius)
if err != nil {
s.log.Errorf("error code: 004. %s", err.Error())
c.JSON(http.StatusBadRequest, gin.H{
"error": errors.New("Error unmarshal file").Error(),
})
return
}
buff, err := SaveToExel(sirius.NewBolid().ZoneInfo())
if err != nil {
s.log.Errorf("error code: 005. %s", err.Error())
c.JSON(http.StatusBadRequest, gin.H{
"error": errors.New("Error create file").Error(),
})
return
}
c.Data(200, "application/vnd.ms-excel", buff.Bytes())
s.log.Printf("converted: ok. filename: %s; file size: %d bytes", fileHeader.Filename, fileHeader.Size)
}
func SaveToExel(data []model.ZoneInfo) (*bytes.Buffer, error) {
f := excelize.NewFile()
defer f.Close()
// Create a new sheet.
f.SetCellValue("Sheet1", "A2", "№ зоны")
f.SetCellValue("Sheet1", "B2", "Описание зоны")
f.SetCellValue("Sheet1", "C2", "Адреса в зоне")
i := 3
for _, d := range data {
f.SetCellValue("Sheet1", "A"+strconv.Itoa(i), d.ZoneNum)
f.SetCellValue("Sheet1", "B"+strconv.Itoa(i), d.ZoneName)
f.SetCellValue("Sheet1", "C"+strconv.Itoa(i), d.InputString())
i++
}
return f.WriteToBuffer()
}

View File

@ -1,104 +1,16 @@
package handler
import (
"bytes"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/xuri/excelize/v2"
"github.com/sirupsen/logrus"
"gitstore.ru/tolikproh/sirius/internal/model"
)
func GinConvert(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
}
fileUuid := uuid.New().String()
fileUpload := "./upload/" + fileUuid + "_" + file.Filename
// сохраняем загруженный файл в /tmp
err = c.SaveUploadedFile(file, fileUpload)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
var sirius model.Sirius
siriusJson, err := ioutil.ReadFile(fileUpload)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": errors.New("No read file").Error(),
})
return
}
siriusJson = bytes.TrimPrefix(siriusJson, []byte("\xef\xbb\xbf"))
if !json.Valid(siriusJson) {
c.JSON(http.StatusBadRequest, gin.H{
"error": errors.New("Formated file not supported").Error(),
})
return
}
err = json.Unmarshal(siriusJson, &sirius)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": errors.New("Error unmarshal file").Error(),
})
return
}
fileConverted := "./convert/" + fileUuid + ".xlsx"
if err := SaveToExel(fileConverted, sirius.NewBolid().ZoneInfo()); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": errors.New("Error create file").Error(),
})
return
}
siriusExel, err := ioutil.ReadFile(fileConverted)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": errors.New("No read file exel").Error(),
})
return
}
c.Data(200, "application/vnd.ms-excel", siriusExel)
type Handler struct {
log *logrus.Logger
cfg *model.Config
}
func SaveToExel(filename string, data []model.ZoneInfo) error {
f := excelize.NewFile()
defer func() {
if err := f.Close(); err != nil {
return
}
}()
// Create a new sheet.
f.SetCellValue("Sheet1", "A2", "№ зоны")
f.SetCellValue("Sheet1", "B2", "Описание зоны")
f.SetCellValue("Sheet1", "C2", "Адреса в зоне")
i := 3
for _, d := range data {
f.SetCellValue("Sheet1", "A"+strconv.Itoa(i), d.ZoneNum)
f.SetCellValue("Sheet1", "B"+strconv.Itoa(i), d.ZoneName)
f.SetCellValue("Sheet1", "C"+strconv.Itoa(i), d.InputString())
i++
}
// Save spreadsheet by the given path.
if err := f.SaveAs(filename); err != nil {
return err
}
return nil
func New(cfg *model.Config, log *logrus.Logger) *Handler {
// HTTP Server
return &Handler{cfg: cfg, log: log}
}

View File

@ -1,12 +1,57 @@
package model
import (
"github.com/spf13/viper"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
func Init() error {
viper.AddConfigPath("./config")
viper.SetConfigName("config")
return viper.ReadInConfig()
type Config struct {
Srv struct {
HostName string `yaml:"hostname"`
Port string `yaml:"port"`
Mode string `yaml:"mode"`
LogLevel int `yaml:"loglevel"`
LogPath string `yaml:"logpath"`
MaxSizeFile int64 `yaml:"maxsizefile"`
} `yaml:"srv"`
}
// NewConfig Set Default
func NewConfig() *Config {
var cnf Config
cnf.Srv.HostName = "example.com"
cnf.Srv.Port = "8080"
cnf.Srv.Mode = gin.DebugMode
cnf.Srv.LogLevel = int(logrus.DebugLevel)
cnf.Srv.LogPath = "./log"
cnf.Srv.MaxSizeFile = 2 //2 Mb
return &cnf
}
func ValidLogLevel(cnf *Config) logrus.Level {
switch cnf.Srv.LogLevel {
case int(logrus.PanicLevel):
return logrus.PanicLevel //PanicLevel = 0
case int(logrus.FatalLevel):
return logrus.FatalLevel //FatalLevel = 1
case int(logrus.ErrorLevel):
return logrus.ErrorLevel //ErrorLevel = 2
case int(logrus.WarnLevel):
return logrus.WarnLevel //WarnLevel = 3
case int(logrus.InfoLevel):
return logrus.InfoLevel //InfoLevel = 4
case int(logrus.DebugLevel):
return logrus.DebugLevel //DebugLevel = 5
case int(logrus.TraceLevel):
return logrus.TraceLevel //TraceLevel = 6
}
return logrus.DebugLevel
}

View File

@ -4,36 +4,44 @@ import (
"context"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
ginlogrus "github.com/toorop/gin-logrus"
"github.com/gin-contrib/cors"
"gitstore.ru/tolikproh/sirius/internal/controller/handler"
"gitstore.ru/tolikproh/sirius/internal/model"
"log"
"net/http"
"os"
"os/signal"
"time"
)
type App struct {
type Server struct {
httpServer *http.Server
log *logrus.Logger
cfg *model.Config
}
func NewApp(port string) *App {
func New(cfg *model.Config, log *logrus.Logger) *Server {
// Initiate an S3 compatible client
return &App{
return &Server{
httpServer: &http.Server{
Addr: ":" + port,
Addr: ":" + cfg.Srv.Port,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}}
},
cfg: cfg, log: log}
}
func (a *App) Run() error {
// Init gin handler
router := gin.Default()
func (a *Server) Run() error {
a.log.Debug("start server")
gin.SetMode(validMode(a.cfg.Srv.Mode))
router := gin.New()
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"*"},
@ -45,19 +53,22 @@ func (a *App) Run() error {
router.Use(
gin.Recovery(),
gin.Logger(),
ginlogrus.Logger(a.log),
)
h := handler.New(a.cfg, a.log)
// API endpoints
api := router.Group("/api")
api.POST("/sirius", handler.GinConvert)
api.POST("/sirius", h.GinConvert)
// HTTP Server
a.httpServer.Handler = router
go func() {
if err := a.httpServer.ListenAndServe(); err != nil {
log.Fatalf("Failed to listen and serve: %+v", err)
a.log.Fatalf("Failed to listen and serve: %+v", err)
return
}
}()
@ -65,9 +76,31 @@ func (a *App) Run() error {
signal.Notify(quit, os.Interrupt, os.Interrupt)
<-quit
a.log.Println("Shutdown Server ...")
ctx, shutdown := context.WithTimeout(context.Background(), 5*time.Second)
defer shutdown()
ctx, cansel := context.WithTimeout(context.Background(), 5*time.Second)
defer cansel()
select {
case <-ctx.Done():
a.log.Println("timeout of 5 seconds.")
}
return a.httpServer.Shutdown(ctx)
}
func validMode(mode string) string {
switch mode {
case gin.ReleaseMode:
return gin.ReleaseMode
case gin.DebugMode:
return gin.DebugMode
case gin.TestMode:
return gin.TestMode
}
return gin.TestMode
}

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Конвертор ППКУП Сириус</title>
<title>Конвертер ППКУП Сириус</title>
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="description" content="Онлайн конвертер конфураций ППКУП Сириус v1.03.022 (Болид)">