init
This commit is contained in:
0
app/http/.gitkeep
Normal file
0
app/http/.gitkeep
Normal file
0
app/http/.help.md
Normal file
0
app/http/.help.md
Normal file
18
app/http/medias.go
Normal file
18
app/http/medias.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"quyun/app/models"
|
||||
"quyun/app/requests"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
// @provider
|
||||
type medias struct{}
|
||||
|
||||
// List medias
|
||||
// @Router /v1/medias [get]
|
||||
// @Bind pagination query
|
||||
func (ctl *medias) List(ctx fiber.Ctx, pagination *requests.Pagination) (*requests.Pager, error) {
|
||||
return models.Medias.List(ctx.Context(), pagination)
|
||||
}
|
||||
48
app/http/provider.gen.go
Executable file
48
app/http/provider.gen.go
Executable file
@@ -0,0 +1,48 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"quyun/providers/app"
|
||||
|
||||
"go.ipao.vip/atom"
|
||||
"go.ipao.vip/atom/container"
|
||||
"go.ipao.vip/atom/contracts"
|
||||
"go.ipao.vip/atom/opt"
|
||||
)
|
||||
|
||||
func Provide(opts ...opt.Option) error {
|
||||
if err := container.Container.Provide(func() (*medias, error) {
|
||||
obj := &medias{}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func(
|
||||
medias *medias,
|
||||
uploads *uploads,
|
||||
) (contracts.HttpRoute, error) {
|
||||
obj := &Routes{
|
||||
medias: medias,
|
||||
uploads: uploads,
|
||||
}
|
||||
if err := obj.Prepare(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
}, atom.GroupRoutes); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func(
|
||||
app *app.Config,
|
||||
) (*uploads, error) {
|
||||
obj := &uploads{
|
||||
app: app,
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
52
app/http/routes.gen.go
Normal file
52
app/http/routes.gen.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// Code generated by the atomctl ; DO NOT EDIT.
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v3"
|
||||
log "github.com/sirupsen/logrus"
|
||||
_ "go.ipao.vip/atom"
|
||||
_ "go.ipao.vip/atom/contracts"
|
||||
. "go.ipao.vip/atom/fen"
|
||||
"mime/multipart"
|
||||
"quyun/app/requests"
|
||||
)
|
||||
|
||||
// @provider contracts.HttpRoute atom.GroupRoutes
|
||||
type Routes struct {
|
||||
log *log.Entry `inject:"false"`
|
||||
medias *medias
|
||||
uploads *uploads
|
||||
}
|
||||
|
||||
func (r *Routes) Prepare() error {
|
||||
r.log = log.WithField("module", "routes.http")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Routes) Name() string {
|
||||
return "http"
|
||||
}
|
||||
|
||||
func (r *Routes) Register(router fiber.Router) {
|
||||
// 注册路由组: medias
|
||||
router.Get("/v1/medias", DataFunc1(
|
||||
r.medias.List,
|
||||
Query[requests.Pagination]("pagination"),
|
||||
))
|
||||
|
||||
// 注册路由组: uploads
|
||||
router.Post("/v1/uploads/:md5/chunks/:idx", Func3(
|
||||
r.uploads.Chunks,
|
||||
PathParam[string]("md5"),
|
||||
PathParam[string]("idx"),
|
||||
File[multipart.FileHeader]("file"),
|
||||
))
|
||||
|
||||
router.Post("/v1/uploads/:md5/complete", Func2(
|
||||
r.uploads.Complete,
|
||||
PathParam[string]("md5"),
|
||||
Body[UploadFileInfo]("body"),
|
||||
))
|
||||
|
||||
}
|
||||
119
app/http/uploads.go
Normal file
119
app/http/uploads.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"quyun/pkg/utils"
|
||||
"quyun/providers/app"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// @provider
|
||||
type uploads struct {
|
||||
app *app.Config
|
||||
}
|
||||
|
||||
func (up *uploads) storagePath() string {
|
||||
return filepath.Join(up.app.StoragePath, "uploads/tmp")
|
||||
}
|
||||
|
||||
type UploadChunk struct {
|
||||
Chunk int `query:"chunk"`
|
||||
Md5 string `query:"md5"`
|
||||
}
|
||||
|
||||
type UploadFileInfo struct {
|
||||
Md5 string `json:"md5"`
|
||||
Filename string `json:"filename"`
|
||||
Mime string `json:"mime"`
|
||||
Size int64 `json:"size"`
|
||||
Chunks int `json:"chunks"`
|
||||
}
|
||||
|
||||
// Upload chunks
|
||||
// @Router /v1/uploads/:md5/chunks/:idx [post]
|
||||
// @Bind md5 path
|
||||
// @Bind idx path
|
||||
// @Bind file file
|
||||
func (up *uploads) Chunks(ctx fiber.Ctx, md5, idx string, file *multipart.FileHeader) error {
|
||||
tmpPath := filepath.Join(up.storagePath(), md5, idx)
|
||||
|
||||
// if tmpPath not exists, create it
|
||||
if _, err := os.Stat(tmpPath); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(filepath.Dir(tmpPath), os.ModePerm); err != nil {
|
||||
log.WithError(err).Errorf("create tmpPath failed %s", tmpPath)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// save file to tmpPath
|
||||
if err := ctx.SaveFile(file, tmpPath); err != nil {
|
||||
log.WithError(err).Errorf("save file to tmpPath failed %s", tmpPath)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Complete uploads
|
||||
// @Router /v1/uploads/:md5/complete [post]
|
||||
// @Bind md5 path
|
||||
// @Bind body body
|
||||
func (up *uploads) Complete(ctx fiber.Ctx, md5 string, body *UploadFileInfo) error {
|
||||
// merge chunks
|
||||
path := filepath.Join(up.storagePath(), md5)
|
||||
defer os.RemoveAll(path)
|
||||
|
||||
targetFile := filepath.Join(up.storagePath(), md5, body.Filename)
|
||||
|
||||
// if targetFile not exists, create it
|
||||
tf, err := os.Create(targetFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < body.Chunks; i++ {
|
||||
tmpPath := filepath.Join(up.storagePath(), md5, fmt.Sprintf("%d", i))
|
||||
|
||||
// open chunk file
|
||||
chunkFile, err := os.Open(tmpPath)
|
||||
if err != nil {
|
||||
tf.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
// copy chunk file to target file
|
||||
if _, err := tf.ReadFrom(chunkFile); err != nil {
|
||||
chunkFile.Close()
|
||||
tf.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
chunkFile.Close()
|
||||
}
|
||||
tf.Close()
|
||||
|
||||
// validate md5
|
||||
ok, err := utils.CompareFileMd5(targetFile, md5)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return errors.New("md5 not match")
|
||||
}
|
||||
|
||||
// save file to target path
|
||||
targetPath := filepath.Join(up.storagePath(), body.Filename)
|
||||
|
||||
if err := os.Rename(targetFile, targetPath); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: save file to database
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user