初步实现文件上传与下载

This commit is contained in:
suguo.yao 2022-04-01 16:58:03 +08:00
parent 794bd74337
commit d6f618888d
13 changed files with 361 additions and 31 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
data/* data/*
go.sum go.sum
*.exe *.exe
leveldb-demo leveldb-demo
upload/

0
Dockerfile Normal file
View File

0
Makefile Normal file
View File

84
gin/auth-filter.go Normal file
View File

@ -0,0 +1,84 @@
package gin
import (
"encoding/json"
"github.com/gin-gonic/gin"
"myschools.me/yyjishu/yy-base/redis"
)
//从redis中认证用户
func AuthUser() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
claims := cacheGet(&token)
if claims == nil {
c.Abort()
return
}
c.Set("user", claims)
c.Next()
}
}
//从redis中获取用户信息最佳实践经验建议把此代码放service层
func cacheGet(token *string) interface{} {
var user interface{}
b, err := redis.GetBytes(token)
if err != nil {
return nil
}
if err := json.Unmarshal(*b, &user); err != nil {
return nil
}
return &user
}
// gin拦截基于微服务的拦截
// func AuthUserBS() gin.HandlerFunc {
// return func(c *gin.Context) {
// token := c.GetHeader("Authorization")
// claims := userAuthWithGrpc(&token)
// if claims == nil {
// yy.RespUnauth(c, "token无效或过期请重新登录", nil, nil)
// c.Abort()
// }
// c.Set("user", claims)
// c.Next()
// }
// }
// func userAuthWithGrpc(token *string) *yy.UserClaims {
// srv, err := consul.FindService("oauth", "v1")
// if err != nil {
// logrus.WithFields(logrus.Fields{
// "func": "userAuthWithGrpc",
// }).Errorf("consul.FindServer: %s", err.Error())
// return nil
// }
// defer srv.Close()
// client := pb.NewCertificationClient(srv)
// resp, err := client.Auth(context.Background(), &pb.CertificationAuthRequest{
// Token: *token,
// })
// if err != nil {
// logrus.WithFields(logrus.Fields{
// "func": "userAuthWithGrpc",
// }).Errorf("client.Auth: %s", err.Error())
// return nil
// }
// if resp.Result == "ok" {
// r := &yy.UserClaims{}
// if err := json.Unmarshal(resp.Data.Value, r); err != nil {
// logrus.WithFields(logrus.Fields{
// "func": "userAuthWithGrpc",
// }).Errorf("json.Unmarshal: %s", err.Error())
// return nil
// }
// return r
// }
// logrus.WithFields(logrus.Fields{
// "func": "userAuthWithGrpc",
// }).Warnln("nil")
// return nil
// }

8
gin/config.go Normal file
View File

@ -0,0 +1,8 @@
package gin
//GIN 配置
type Config struct {
RootPath string
Addr string
Port int
}

33
gin/gin.go Normal file
View File

@ -0,0 +1,33 @@
package gin
import (
"fmt"
"log"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func Service(conf *Config) {
if conf == nil {
conf = &Config{
RootPath: "/",
Addr: "0.0.0.0",
Port: 80,
}
}
go func() {
router := gin.New()
routerSetup(router, &conf.RootPath)
s := &http.Server{
Addr: fmt.Sprintf("%s:%d", conf.Addr, conf.Port),
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Printf("start service on %s", fmt.Sprintf("%s:%d", conf.Addr, conf.Port))
log.Fatal(s.ListenAndServe())
}()
}

21
gin/router.go Normal file
View File

@ -0,0 +1,21 @@
package gin
import (
"fmt"
"github.com/gin-gonic/gin"
"myschools.me/suguo/leveldb-demo/handler"
)
//路由配置
func routerSetup(router *gin.Engine, rootpath *string) {
router.Use(gin.Recovery())
r := router.Group(fmt.Sprintf("/%s", *rootpath))
{
r.POST(`/upload`, handler.FileUpload)
r.POST(`/update`, handler.FileUpdate)
r.POST(`/delete`, handler.FileDelete)
r.GET(`/get/:id`, handler.FileGet)
}
}

31
go.mod
View File

@ -1,8 +1,33 @@
module myschools.me/suguo/leveldb-demo module myschools.me/suguo/leveldb-demo
go 1.18 go 1.17
require ( require (
github.com/golang/snappy v0.0.4 // indirect github.com/gin-gonic/gin v1.7.4
github.com/syndtr/goleveldb v1.0.0 // indirect github.com/gofrs/uuid v4.2.0+incompatible
github.com/sirupsen/logrus v1.8.1
github.com/syndtr/goleveldb v1.0.0
myschools.me/yyjishu/yy-base v0.16.133
)
require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.9.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gomodule/redigo v1.8.5 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/ugorji/go/codec v1.2.6 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
) )

57
handler/file-handler.go Normal file
View File

@ -0,0 +1,57 @@
package handler
import (
"io/ioutil"
"github.com/gin-gonic/gin"
"myschools.me/suguo/leveldb-demo/service"
"myschools.me/yyjishu/yy-base/yy"
)
func FileUpload(c *gin.Context) {
reqid := yy.NewRequestID()
fs, fh, err := c.Request.FormFile("file")
if err != nil {
yy.RespBadRequest(c, "上传文件获取失败", err, &reqid)
return
}
defer fs.Close()
payload, err := ioutil.ReadAll(fs)
if err != nil {
yy.RespBadRequest(c, "上传文件中断", err, &reqid)
return
}
if fh.Header.Get("Content-Type") != "image/png" {
yy.RespBadRequest(c, "文件类型不支持", nil, &reqid)
return
}
ret, err := service.FileUpload(&payload)
if err != nil {
yy.RespInternalServerError(c, "上传失败", err, &reqid)
return
}
yy.RespSuccess(c, "ok", gin.H{
"id": *ret,
}, &reqid)
}
func FileGet(c *gin.Context) {
reqid := yy.NewRequestID()
id := c.Param("id")
data, err := service.FileGet(&id)
if err != nil {
yy.RespInternalServerError(c, "获取文件失败", err, &reqid)
return
}
c.Writer.Write(*data)
c.Writer.Flush()
}
func FileUpdate(c *gin.Context) {
}
func FileDelete(c *gin.Context) {
}

20
leveldb-demo.http Normal file
View File

@ -0,0 +1,20 @@
@url=http://127.0.0.1:8080/assets/file
@createdAt = {{$datetime iso8601}}
###
POST {{url}}/upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="text"
title
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="1.png"
Content-Type: image/png
< /home/suguo/Pictures/kindeditor_201907201649420191.jpg
------WebKitFormBoundary7MA4YWxkTrZu0gW--
###
GET {{url}}/get/1ecb19989cd76cf69cdae53c0efeef79 HTTP/1.1

45
main.go
View File

@ -1,37 +1,28 @@
package main package main
import ( import (
"fmt" "context"
"log" "os"
"os/signal"
"time"
"github.com/syndtr/goleveldb/leveldb" "github.com/sirupsen/logrus"
"github.com/syndtr/goleveldb/leveldb/opt" "myschools.me/suguo/leveldb-demo/gin"
) )
func main() { func main() {
db, err := leveldb.OpenFile("./data", nil) gin.Service(&gin.Config{
if err != nil { RootPath: "assets/file",
log.Fatal(err) Addr: "0.0.0.0",
} Port: 8080,
defer db.Close()
for i := 0; i < 50; i++ {
if err := db.Put([]byte(fmt.Sprintf("hello %d", i)), []byte("a hello world."), nil); err != nil {
log.Fatal(err)
}
}
ret, err := db.Has([]byte("hello 49"), &opt.ReadOptions{
DontFillCache: false,
Strict: 0,
}) })
if err != nil {
log.Fatal(err)
}
fmt.Println(ret)
val, err := db.Get([]byte("hello 4"), nil) // 服务停止相应
if err != nil { c := make(chan os.Signal, 1)
log.Fatal(err) signal.Notify(c, os.Interrupt)
} <-c
fmt.Println(string(val)) _, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
logrus.Println("file storage service shutting down")
os.Exit(0)
} }

4
readme.md Normal file
View File

@ -0,0 +1,4 @@
# 本地文件存储系统
#### 概述
使用leveldb进行简单文件存储修改、删除等操作

86
service/file-service.go Normal file
View File

@ -0,0 +1,86 @@
package service
import (
"errors"
"fmt"
"log"
"os"
"strings"
"github.com/gofrs/uuid"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/opt"
)
var (
storagepath string = "./upload"
)
func init() {
sp := os.Getenv("p")
if sp != "" {
storagepath = sp
}
}
func FileGet(id *string) (*[]byte, error) {
db, err := leveldb.OpenFile(storagepath, nil)
if err != nil {
return nil, err
}
defer db.Close()
ret, err := db.Has([]byte(*id), &opt.ReadOptions{
DontFillCache: false,
Strict: 0,
})
if err != nil {
return nil, errors.New("文件不存在")
}
if !ret {
return nil, errors.New("文件不存在")
}
val, err := db.Get([]byte(*id), nil)
if err != nil {
return nil, err
}
return &val, nil
}
func FileUpload(payload *[]byte) (*string, error) {
db, err := leveldb.OpenFile(storagepath, nil)
if err != nil {
return nil, err
}
defer db.Close()
key := strings.ReplaceAll(uuid.Must(uuid.NewV6()).String(), "-", "")
if err := db.Put([]byte(key), *payload, nil); err != nil {
return nil, err
}
return &key, nil
}
func FileUpdate() {
db, err := leveldb.OpenFile(storagepath, nil)
if err != nil {
return
}
defer db.Close()
ret, err := db.Has([]byte("hello 49"), &opt.ReadOptions{
DontFillCache: false,
Strict: 0,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(ret)
val, err := db.Get([]byte("hello 4"), nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(val))
}