Squashed commit of the following:

commit a394259f0a
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 19 15:10:08 2024 +0800

    done

commit af9d966376
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 19 13:52:33 2024 +0800

    debug done.

commit 47335ca5e9
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 19 12:47:00 2024 +0800

    swagger done

commit 34fb2a478b
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 19 10:05:19 2024 +0800

    stage 2, not completed

commit 88b2255f8b
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 19 09:44:37 2024 +0800

    test stage 1

commit b583720223
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 15 21:53:09 2024 +0800

    Squashed commit of the following:

    commit 1e92328a0fc570fe9419ad5dbaaef77f7dc9ad2e
    Author: Sense T <me@sense-t.eu.org>
    Date:   Mon Apr 15 21:52:44 2024 +0800

        yes, react it!

    commit 09fffff6139b4cecb81cb1444139f225e95e8917
    Author: Sense T <me@sense-t.eu.org>
    Date:   Mon Apr 15 17:33:26 2024 +0800

        actions to be done

    commit 1611b0b338cfd965d15f43fb10308bc56015895f
    Author: Sense T <me@sense-t.eu.org>
    Date:   Mon Apr 15 15:22:08 2024 +0800

        modal needed.

    commit 88453e7382618fb6774ff1cc4c0f7045d4dfcf46
    Author: Sense T <me@sense-t.eu.org>
    Date:   Mon Apr 15 10:52:13 2024 +0800

        Domain View done

    commit 8cedca27c79ca2ba69c8777dfcb6019799875e31
    Author: Sense T <me@sense-t.eu.org>
    Date:   Sun Apr 14 21:24:14 2024 +0800

        domain delete modal done

    commit 60cd00c0cad0774bae5b57bcfc4723a29d28d221
    Author: Sense T <me@sense-t.eu.org>
    Date:   Sun Apr 14 07:55:11 2024 +0800

        1

    commit 285853e988db6e6a6371135869da0129fd73afd7
    Author: Sense T <me@sense-t.eu.org>
    Date:   Sat Apr 13 17:29:43 2024 +0800

        eslint

    commit 8f0ffbf744fd85a612daacd7bd6cbc45d58907d3
    Author: Sense T <me@sense-t.eu.org>
    Date:   Sat Apr 13 17:20:50 2024 +0800

        f

    commit 9762b632225f185d83388e58d93ed49f62fe6b3f
    Author: Sense T <me@sense-t.eu.org>
    Date:   Sat Apr 13 17:08:37 2024 +0800

        views, components to be done

    commit 321e5255f2b1e705844179dd910d5f5a1ae58298
    Author: Sense T <me@sense-t.eu.org>
    Date:   Sat Apr 13 14:29:04 2024 +0800

        prepare for react

commit 3305d8d618
Author: Sense T <me@sense-t.eu.org>
Date:   Sat Apr 13 10:30:02 2024 +0800

    swagger to be done

commit 2c754e7eec
Author: Sense T <me@sense-t.eu.org>
Date:   Sat Apr 13 10:14:45 2024 +0800

    validate 'em !

commit 7b529ad8f6
Author: Sense T <me@sense-t.eu.org>
Date:   Sat Apr 13 09:22:27 2024 +0800

    try to avoid nil point panic

commit 0012a697cb
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 12 22:26:35 2024 +0800

    fix some bug

commit a098d3056c
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 12 20:03:34 2024 +0800

    web debug done

commit 01765c4e7f
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 12 15:16:52 2024 +0800

    all tsx used, no vue SFC

commit 731504ae82
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 22:05:58 2024 +0800

    tsx used - stage 2

commit b669a3e68e
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 16:18:11 2024 +0800

    use tsx for compoents stage 1

commit 2ab1b0bf1b
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 12:10:57 2024 +0800

    rr validation

commit 58c66fc3a8
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 11:41:33 2024 +0800

    stage 1

commit 7a5fcf1972
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 10:51:50 2024 +0800

    long options supported

commit c3b80093d2
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 10:51:33 2024 +0800

    for develop use

commit 7f52707323
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 10:51:24 2024 +0800

    fix typo

commit 9cc2696bbe
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 10 16:53:03 2024 +0800

    record data validate done

commit 5e2ae637a0
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 10 14:56:15 2024 +0800

    end with dot.

commit ed4fee935d
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 10 13:41:32 2024 +0800

    content safety

commit 29f75938bb
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 10 13:24:01 2024 +0800

    cmd is ok

commit 9465bb885d
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 10 11:00:47 2024 +0800

    web done

commit 65bf461d44
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 10 11:00:38 2024 +0800

    use tokei for stat

commit 61395ab61b
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 21:53:12 2024 +0800

    errors handler

commit 9752e7d9ae
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 21:16:19 2024 +0800

    model with generics done

commit 7dd3af3707
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 16:28:18 2024 +0800

    use DAO

commit 2369734230
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 13:06:31 2024 +0800

    dao for future

commit e18781ba25
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 11:36:34 2024 +0800

    DotEnd

commit 613ef7fdd9
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 10:16:06 2024 +0800

    record should endwith .

commit c93e8107dc
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 10:06:47 2024 +0800

    update regexp

commit 84e9961f4b
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 08:30:32 2024 +0800

    error log

commit db77b0fdb2
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 08:25:25 2024 +0800

    no console log

commit 0c197820a0
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 08:25:01 2024 +0800

    use flags for validate

commit 33c9050653
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 07:58:27 2024 +0800

    SOA Email Format

commit fb9c78efed
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 00:19:03 2024 +0800

    no debug

commit 1a7bf83cb9
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 00:18:18 2024 +0800

    1

commit e72de14797
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 8 17:30:25 2024 +0800

    last modal

commit e884840b7d
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 8 15:56:03 2024 +0800

    add

commit 36b0384319
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 8 15:02:55 2024 +0800

    delete domain modal done

commit 753e950fae
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 8 13:49:11 2024 +0800

    add domainRemovemodal

commit 69613f9b6e
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 8 13:32:01 2024 +0800

    modal needed for edit

commit 8c0b79066f
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 8 09:37:32 2024 +0800

    base UI

commit a67b2d7724
Author: Sense T <me@sense-t.eu.org>
Date:   Sun Apr 7 21:07:20 2024 +0800

    route update

commit 5a266e9e6c
Author: Sense T <me@sense-t.eu.org>
Date:   Sun Apr 7 14:36:55 2024 +0800

    ui base data struct

commit 3449df913c
Author: Sense T <me@sense-t.eu.org>
Date:   Sun Apr 7 13:08:45 2024 +0800

    web store for dev

commit 156bf651dd
Author: Sense T <me@sense-t.eu.org>
Date:   Sun Apr 7 13:08:30 2024 +0800

    store friendly

commit d90e949472
Author: Sense T <me@sense-t.eu.org>
Date:   Sun Apr 7 10:08:02 2024 +0800

    base code update

commit 0a20b5a670
Author: Sense T <me@sense-t.eu.org>
Date:   Sun Apr 7 10:07:26 2024 +0800

    metrics

commit bdd4866c10
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 3 22:37:15 2024 +0800

    all api done

commit 8a8ea59b71
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 3 17:05:12 2024 +0800

    1
This commit is contained in:
Sense T
2024-04-19 15:16:24 +08:00
parent 94a126086e
commit 021ec9c8f6
72 changed files with 11469 additions and 89 deletions

1
server/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
dist/

129
server/handlers_domains.go Normal file
View File

@@ -0,0 +1,129 @@
package server
import (
"net/http"
"reCoreD-UI/controllers"
"reCoreD-UI/models"
"github.com/gin-gonic/gin"
_ "reCoreD-UI/docs"
)
// GetDomains godoc
//
// @Router /domains/ [get]
// @Summary List all domains
// @Description List all domains
// @Tags domains
// @Accept json
// @Product json
// @Success 200 {object} Response{data=[]models.Domain}
// @Failure 401 {object} Response{data=nil}
// @Failure 500 {object} Response{data=nil}
func getDomains(c *gin.Context) {
domains, err := controllers.GetDomains("")
if err != nil {
errorHandler(c, err)
return
}
c.JSON(http.StatusOK, Response{
Succeed: true,
Data: domains,
})
}
// CreateDomain godoc
//
// @Router /domains/ [post]
// @Summary Create a domain
// @Description Create a domain
// @Tags domains
// @Product json
// @Param object body models.Domain true "content"
// @Success 201 {object} Response{data=models.Domain}
// @Failure 400 {object} Response{data=nil}
// @Failure 401 {object} Response{data=nil}
// @Failure 500 {object} Response{data=nil}
func createDomain(c *gin.Context) {
domain := &models.Domain{}
if err := c.BindJSON(domain); err != nil {
c.JSON(http.StatusBadRequest, Response{
Succeed: false,
Message: err.Error(),
})
return
}
domain, err := controllers.CreateDomain(domain)
if err != nil {
errorHandler(c, err)
return
}
c.JSON(http.StatusCreated, Response{
Succeed: true,
Data: domain,
})
}
// UpdateDomain godoc
//
// @Router /domains/ [put]
// @Summary Update a domain
// @Description Update a domain
// @Tags domains
// @Accept json
// @Product json
// @Param object body models.Domain true "content"
// @Success 200 {object} Response{data=models.Domain}
// @Failure 400 {object} Response{data=nil}
// @Failure 401 {object} Response{data=nil}
// @Failure 404 {object} Response{data=nil}
// @Failure 500 {object} Response{data=nil}
func updateDomain(c *gin.Context) {
domain := &models.Domain{}
if err := c.BindJSON(domain); err != nil {
c.JSON(http.StatusBadRequest, Response{
Succeed: false,
Message: err.Error(),
})
return
}
if err := controllers.UpdateDomain(domain); err != nil {
errorHandler(c, err)
return
}
c.JSON(http.StatusOK, Response{
Succeed: true,
})
}
// DeleteDomain godoc
//
// @Router /domains/{id} [delete]
// @Summary Delete a domain
// @Description Delete a domain
// @Tags domains
// @Product json
// @Param id path int true "Domain ID"
// @Success 204 {object} Response{data=nil}
// @Failure 401 {object} Response{data=nil}
// @Failure 404 {object} Response{data=nil}
// @Failure 500 {object} Response{data=nil}
func deleteDomain(c *gin.Context) {
id := c.Param("id")
if err := controllers.DeleteDomain(id); err != nil {
errorHandler(c, err)
return
}
c.JSON(http.StatusNoContent, Response{
Succeed: true,
})
}

281
server/handlers_records.go Normal file
View File

@@ -0,0 +1,281 @@
package server
import (
"fmt"
"net/http"
"reCoreD-UI/controllers"
"reCoreD-UI/models"
"github.com/gin-gonic/gin"
)
func validateRecord(r models.IRecord) error {
switch r.GetType() {
case models.RecordTypeA:
record := &models.Record[models.ARecord]{}
if err := record.FromEntity(r); err != nil {
return err
}
return record.Content.Validate()
case models.RecordTypeAAAA:
record := &models.Record[models.AAAARecord]{}
if err := record.FromEntity(r); err != nil {
return err
}
return record.Content.Validate()
case models.RecordTypeCNAME:
record := &models.Record[models.CNAMERecord]{}
if err := record.FromEntity(r); err != nil {
return err
}
return record.Content.Validate()
case models.RecordTypeCAA:
record := &models.Record[models.CAARecord]{}
if err := record.FromEntity(r); err != nil {
return err
}
return record.Content.Validate()
case models.RecordTypeMX:
record := &models.Record[models.MXRecord]{}
if err := record.FromEntity(r); err != nil {
return err
}
return record.Content.Validate()
case models.RecordTypeNS:
record := &models.Record[models.NSRecord]{}
if err := record.FromEntity(r); err != nil {
return err
}
return record.Content.Validate()
case models.RecordTypeSOA:
record := &models.Record[models.SOARecord]{}
if err := record.FromEntity(r); err != nil {
return err
}
return record.Content.Validate()
case models.RecordTypeSRV:
record := &models.Record[models.SRVRecord]{}
if err := record.FromEntity(r); err != nil {
return err
}
return record.Content.Validate()
case models.RecordTypeTXT:
record := &models.Record[models.TXTRecord]{}
if err := record.FromEntity(r); err != nil {
return err
}
return record.Content.Validate()
default:
return models.ErrInvalidType
}
}
// GetRecords godoc
//
// @Router /records/{domain} [get]
// @Summary List all records of a domain
// @Description List all records of a domain
// @Tags records
// @Product json
// @Param domain path string true "domain"
// @Success 200 {object} Response{data=[]models.Record[models.RecordContentDefault]}
// @Failure 401 {object} Response{data=nil}
// @Failure 404 {object} Response{data=nil}
// @Failure 500 {object} Response{data=nil}
func getRecords(c *gin.Context) {
query := &models.Record[models.RecordContentDefault]{Content: make(models.RecordContentDefault)}
if err := c.BindQuery(query); err != nil {
c.JSON(http.StatusBadRequest, Response{
Succeed: false,
Message: err.Error(),
})
return
}
domain := c.Param("domain")
query.Zone = fmt.Sprintf("%s.", domain)
records, err := controllers.GetRecords(query)
if err != nil {
errorHandler(c, err)
return
}
c.JSON(http.StatusOK, Response{
Succeed: true,
Data: records,
})
}
// CreateRecord godoc
//
// @Router /records/{domain} [post]
// @Summary Create a record of a domain
// @Description Create a record of a domain
// @Tags records
// @Accept json
// @Product json
// @Param domain path string true "domain"
// @Param object body models.Record[models.RecordContentDefault] true "content"
// @Success 201 {object} Response{data=models.Record[models.RecordContentDefault]}
// @Failure 400 {object} Response{data=nil}
// @Failure 401 {object} Response{data=nil}
// @Failure 404 {object} Response{data=nil}
// @Failure 500 {object} Response{data=nil}
func createRecord(c *gin.Context) {
record := &models.Record[models.RecordContentDefault]{Content: make(models.RecordContentDefault)}
if err := c.BindJSON(record); err != nil {
c.JSON(http.StatusBadRequest, Response{
Succeed: false,
Message: err.Error(),
})
return
}
domain := c.Param("domain")
if domain != record.WithOutDotTail() {
c.JSON(http.StatusBadRequest, Response{
Succeed: false,
Message: "request body doesn't match URI",
})
return
}
if err := validateRecord(record); err != nil {
c.JSON(http.StatusBadRequest, Response{
Succeed: false,
Message: err.Error(),
})
return
}
irecord, err := controllers.CreateRecord(record)
if err != nil {
errorHandler(c, err)
return
}
c.JSON(http.StatusCreated, Response{
Succeed: true,
Data: irecord,
})
}
// CreateRecords godoc
//
// @Router /records/{domain}/bulk [post]
// @Summary Create some records of a domain
// @Description Create some records of a domain
// @Tags records
// @Accept json
// @Product json
// @Param domain path string true "domain"
// @Param object body []models.Record[models.RecordContentDefault] true "content"
// @Success 201 {object} Response{data=models.Record[models.RecordContentDefault]}
// @Failure 400 {object} Response{data=nil}
// @Failure 401 {object} Response{data=nil}
// @Failure 404 {object} Response{data=nil}
// @Failure 500 {object} Response{data=nil}
func createRecords(c *gin.Context) {
var records []models.Record[models.RecordContentDefault]
if err := c.BindJSON(&records); err != nil {
c.JSON(http.StatusBadRequest, Response{
Succeed: false,
Message: err.Error(),
})
return
}
var iRecords []models.IRecord
for _, v := range records {
iRecords = append(iRecords, &v)
}
if err := controllers.CreateRecords(iRecords); err != nil {
errorHandler(c, err)
return
}
c.JSON(http.StatusCreated, Response{
Succeed: true,
})
}
// UpdateRecord godoc
//
// @Router /records/{domain} [put]
// @Summary Update a record of a domain
// @Description Update a record of a domain
// @Tags records
// @Accept json
// @Product json
// @Param domain path string true "domain"
// @Param object body models.Record[models.RecordContentDefault] true "content"
// @Success 200 {object} Response{data=models.Record[models.RecordContentDefault]}
// @Failure 400 {object} Response{data=nil}
// @Failure 401 {object} Response{data=nil}
// @Failure 404 {object} Response{data=nil}
// @Failure 500 {object} Response{data=nil}
func updateRecord(c *gin.Context) {
record := &models.Record[models.RecordContentDefault]{Content: make(models.RecordContentDefault)}
if err := c.BindJSON(record); err != nil {
c.JSON(http.StatusBadRequest, Response{
Succeed: false,
Message: err.Error(),
})
return
}
if err := validateRecord(record); err != nil {
c.JSON(http.StatusBadRequest, Response{
Succeed: false,
Message: err.Error(),
})
return
}
domain := c.Param("domain")
if domain != record.WithOutDotTail() {
c.JSON(http.StatusBadRequest, Response{
Succeed: false,
Message: "request body doesn't match URI",
})
return
}
if err := controllers.UpdateRecord(record); err != nil {
errorHandler(c, err)
return
}
c.JSON(http.StatusOK, Response{
Succeed: true,
})
}
// DeleteRecord godoc
//
// @Router /records/{domain}/{id} [delete]
// @Summary Delete a record of a domain
// @Description Delete a record of a domain, except SOA record.
// @Tags records
// @Product json
// @Param domain path string true "domain"
// @Param id path int true "Record ID"
// @Success 204 {object} Response{data=nil}
// @Failure 400 {object} Response{data=nil}
// @Failure 401 {object} Response{data=nil}
// @Failure 404 {object} Response{data=nil}
// @Failure 500 {object} Response{data=nil}
func deleteRecord(c *gin.Context) {
domain := c.Param("domain")
id := c.Param("id")
if err := controllers.DeleteRecord(domain, id); err != nil {
errorHandler(c, err)
return
}
c.JSON(http.StatusNoContent, Response{
Succeed: true,
})
}

44
server/response.go Normal file
View File

@@ -0,0 +1,44 @@
package server
import (
"errors"
"net/http"
"reCoreD-UI/models"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
// Response common http response
type Response struct {
// `true` for 2xx, else `false`
Succeed bool `json:"succeed"`
// error message
Message string `json:"message"`
// payload here
Data interface{} `json:"data"`
}
func errorHandler(c *gin.Context, err error) {
logrus.Error(err)
switch {
case errors.Is(err, gorm.ErrRecordNotFound):
c.JSON(http.StatusNotFound, Response{
Succeed: false,
Message: err.Error(),
})
case errors.Is(err, models.ErrorZoneNotEndWithDot):
c.JSON(http.StatusBadRequest, Response{
Succeed: false,
Message: err.Error(),
})
default:
c.JSON(http.StatusInternalServerError, Response{
Succeed: false,
Message: err.Error(),
})
}
}

99
server/route.go Normal file
View File

@@ -0,0 +1,99 @@
package server
import (
"net/http"
"path"
"reCoreD-UI/controllers"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sirupsen/logrus"
swaggerfiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
)
const (
apiPrefix = "/api"
metricPrefix = "/metrics"
swaggerPrefix = "/swagger"
)
func (s *Server) setupRoute() {
username, password, err := controllers.GetAdmin()
if err != nil {
logrus.Fatal(err)
}
logrus.Debugf("got %s:%s", username, password)
server := s.webServer.Group(s.prefix)
swaggerHandler := server
if s.debug {
swaggerHandler.GET(path.Join(swaggerPrefix, "*any"), ginSwagger.WrapHandler(swaggerfiles.Handler))
} else {
swaggerHandler.GET(path.Join(swaggerPrefix, "*any"), func(ctx *gin.Context) {
ctx.HTML(http.StatusNotFound, "", nil)
})
}
controllers.RegisterMetrics()
metricHandler := server
metricHandler.GET(metricPrefix, func(ctx *gin.Context) {
if err := controllers.RefreshMetrics(); err != nil {
logrus.Error(err)
}
promhttp.Handler().ServeHTTP(ctx.Writer, ctx.Request)
})
apiHandler := server
groupV1 := apiHandler.Group(apiPrefix, gin.BasicAuth(gin.Accounts{
username: password,
}), func(ctx *gin.Context) {
_, ok := ctx.Get(gin.AuthUserKey)
if !ok {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, Response{
Succeed: false,
})
}
}).Group("/v1")
domains := groupV1.Group("/domains")
domains.
GET("/", getDomains).
POST("/", createDomain).
PUT("/", updateDomain).
DELETE("/:id", deleteDomain)
records := groupV1.Group("/records")
records.
GET("/:domain", getRecords).
POST("/:domain", createRecord).
POST("/:domain/bulk", createRecords).
PUT("/:domain", updateRecord).
DELETE("/:domain/:id", deleteRecord)
/*server := s.webServer.Group(s.prefix)
server.Use(apiHandler.HandleContext, metricHandler.HandleContext, func(ctx *gin.Context) {
uri := ctx.Request.RequestURI
logrus.Debug(uri)
switch {
case strings.HasPrefix(uri, path.Join(s.prefix, apiPrefix)):
//apiHandler.HandleContext(ctx)
case strings.HasPrefix(uri, path.Join(s.prefix, metricPrefix)):
//metricHandler.HandleContext(ctx)
case strings.HasPrefix(uri, path.Join(s.prefix, swaggerPrefix)):
if s.debug {
swaggerHandler.HandleContext(ctx)
} else {
ctx.HTML(http.StatusNotFound, "", nil)
}
default:
staticFileHandler()(ctx)
}
})*/
server.GET("/", staticFileHandler())
server.GET("/assets/*any", staticFileHandler())
}

48
server/server.go Normal file
View File

@@ -0,0 +1,48 @@
package server
import (
"net"
"reCoreD-UI/database"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
type Server struct {
webServer *gin.Engine
listen string
prefix string
debug bool
}
func NewServer(c *cli.Context) (*Server, error) {
if err := database.Connect(c.String("mysql-dsn")); err != nil {
return nil, err
}
if c.Bool("debug") {
database.Client = database.Client.Debug()
gin.SetMode(gin.DebugMode)
} else {
gin.SetMode(gin.ReleaseMode)
}
return &Server{
webServer: gin.New(),
listen: net.JoinHostPort(
c.String("listen"),
c.String("port"),
),
prefix: c.String("prefix"),
debug: c.Bool("debug"),
}, nil
}
func (s *Server) Run() error {
logrus.Debug("server running")
defer logrus.Debug("server exit")
s.setupRoute()
return s.webServer.Run(s.listen)
}

35
server/static.go Normal file
View File

@@ -0,0 +1,35 @@
package server
import (
"embed"
"io/fs"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
//go:generate cp -r ../web/dist ./
//go:embed dist
var staticFiles embed.FS
func staticFileHandler() gin.HandlerFunc {
sf, err := fs.Sub(staticFiles, "dist")
if err != nil {
logrus.Fatal("compile error: ", err)
}
fs := http.FileServer(http.FS(sf))
return func(ctx *gin.Context) {
defer ctx.Abort()
filename := strings.TrimLeft(ctx.Request.RequestURI, "/")
if filename == "" {
filename = "index.html"
}
fs.ServeHTTP(ctx.Writer, ctx.Request)
}
}