国展报名

wp
workabee 8 months ago
parent 0772e8d0da
commit e45f0591ab

@ -0,0 +1,56 @@
package main
import (
"fmt"
appConfig "github.com/exhibition-main/internal/config"
"github.com/exhibition-main/pkg/router"
"github.com/exhibition-main/pkg/service"
"github.com/exhibition-main/pkg/tracing"
"github.com/exhibition-main/pkg/utils"
"github.com/go-redis/redis"
"github.com/robfig/cron/v3"
"github.com/streadway/amqp"
"go.uber.org/zap"
)
type App struct {
lg *zap.Logger
RedisClient *redis.Client
JaegerTracer *tracing.JaegerProvider
RabbitMqLink *amqp.Connection
}
func NewApp(lg *zap.Logger, RedisClient *redis.Client, JaegerTracer *tracing.JaegerProvider) *App {
return &App{
lg: lg,
RedisClient: RedisClient,
JaegerTracer: JaegerTracer,
}
}
func main() {
_, err := InitApp()
if err != nil {
panic(err)
}
modules()
r := router.NewRouter()
if appConfig.Data.System.IsHttps {
_ = r.RunTLS(fmt.Sprintf(":%d", appConfig.Data.System.Port), appConfig.Data.System.CertPath, appConfig.Data.System.KeyPath)
} else {
_ = r.Run(fmt.Sprintf(":%d", appConfig.Data.System.Port))
}
select {}
}
func modules() {
if err := utils.InitTrans("zh"); err != nil {
panic(err)
}
if appConfig.Data.System.Cron {
c := cron.New()
service.Task(c)
c.Start()
}
}

@ -0,0 +1,17 @@
// go:build wireinject
//go:build wireinject
// +build wireinject
package main
import (
"github.com/exhibition-main/pkg/cache"
"github.com/exhibition-main/pkg/logger"
"github.com/exhibition-main/pkg/tracing"
"github.com/google/wire"
)
func InitApp() (*App, error) {
wire.Build(logger.Provider, cache.RedisProvider, tracing.Provider, NewApp)
return &App{}, nil
}

@ -0,0 +1,23 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
import (
"github.com/exhibition-main/pkg/cache"
"github.com/exhibition-main/pkg/logger"
"github.com/exhibition-main/pkg/tracing"
)
// Injectors from wire.go:
func InitApp() (*App, error) {
zapLogger := logger.ZapInit()
client := cache.NewRedis()
jaegerProvider := tracing.NewTracing()
app := NewApp(zapLogger, client, jaegerProvider)
return app, nil
}

@ -11,7 +11,10 @@ dubbo:
max-call-send-msg-size: 8000000 max-call-send-msg-size: 8000000
max-call-recv-msg-size: 8000000 max-call-recv-msg-size: 8000000
references: references:
ExhibitionClientImpl:
protocol: tri
filter: tps
interface: com.fontree.microservices.common.Exhibition
logger: logger:
zap-config: zap-config:
level: error # 日志级别 level: error # 日志级别

@ -11,7 +11,10 @@ dubbo:
max-call-send-msg-size: 8000000 max-call-send-msg-size: 8000000
max-call-recv-msg-size: 8000000 max-call-recv-msg-size: 8000000
references: references:
ExhibitionClientImpl:
protocol: tri
filter: tps
interface: com.fontree.microservices.common.Exhibition
logger: logger:
zap-config: zap-config:
level: error # 日志级别 level: error # 日志级别

@ -11,7 +11,10 @@ dubbo:
max-call-send-msg-size: 8000000 max-call-send-msg-size: 8000000
max-call-recv-msg-size: 8000000 max-call-recv-msg-size: 8000000
references: references:
ExhibitionClientImpl:
protocol: tri
filter: tps
interface: com.fontree.microservices.common.Exhibition
logger: logger:
zap-config: zap-config:
level: error # 日志级别 level: error # 日志级别

@ -2,12 +2,25 @@ module github.com/exhibition-main
go 1.20 go 1.20
replace (
github.com/fonchain_enterprise/utils/aes => ../utils/aes
github.com/fonchain_enterprise/utils/chain => ../utils/chain
github.com/fonchain_enterprise/utils/feie => ../utils/feie
github.com/fonchain_enterprise/utils/ipAddrQuery => ../utils/ipAddrQuery
github.com/fonchain_enterprise/utils/jwt => ../utils/jwt
github.com/fonchain_enterprise/utils/logger => ../utils/logger
github.com/fonchain_enterprise/utils/objstorage => ../utils/objstorage
github.com/fonchain_enterprise/utils/rand => ../utils/rand
github.com/fonchain_enterprise/utils/utils => ../utils/utils
)
require ( require (
dubbo.apache.org/dubbo-go/v3 v3.0.5 dubbo.apache.org/dubbo-go/v3 v3.0.5
github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/dubbogo/gost v1.13.2 github.com/dubbogo/gost v1.13.2
github.com/dubbogo/grpc-go v1.42.10 github.com/dubbogo/grpc-go v1.42.10
github.com/dubbogo/triple v1.2.2-rc2 github.com/dubbogo/triple v1.2.2-rc2
github.com/fonchain_enterprise/utils/objstorage v0.0.0-00010101000000-000000000000
github.com/gin-contrib/gzip v0.0.6 github.com/gin-contrib/gzip v0.0.6
github.com/gin-contrib/pprof v1.4.0 github.com/gin-contrib/pprof v1.4.0
github.com/gin-gonic/gin v1.9.0 github.com/gin-gonic/gin v1.9.0
@ -19,12 +32,17 @@ require (
github.com/google/wire v0.5.0 github.com/google/wire v0.5.0
github.com/mwitkow/go-proto-validators v0.3.2 github.com/mwitkow/go-proto-validators v0.3.2
github.com/natefinch/lumberjack v2.0.0+incompatible github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/opentracing/opentracing-go v1.2.0 github.com/opentracing/opentracing-go v1.2.0
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd
github.com/satori/go.uuid v1.2.0
github.com/spf13/viper v1.7.0 github.com/spf13/viper v1.7.0
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271
github.com/u2takey/ffmpeg-go v0.5.0
github.com/uber/jaeger-client-go v2.30.0+incompatible github.com/uber/jaeger-client-go v2.30.0+incompatible
go.uber.org/zap v1.21.0 go.uber.org/zap v1.21.0
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
google.golang.org/protobuf v1.28.1 google.golang.org/protobuf v1.28.1
) )
@ -36,8 +54,12 @@ require (
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 // indirect github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 // indirect
github.com/alibaba/sentinel-golang v1.0.4 // indirect github.com/alibaba/sentinel-golang v1.0.4 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 // indirect github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 // indirect
github.com/aliyun/aliyun-oss-go-sdk v2.2.4+incompatible // indirect
github.com/apache/dubbo-getty v1.4.9-0.20221022181821-4dc6252ce98c // indirect github.com/apache/dubbo-getty v1.4.9-0.20221022181821-4dc6252ce98c // indirect
github.com/apache/dubbo-go-hessian2 v1.11.5 // indirect github.com/apache/dubbo-go-hessian2 v1.11.5 // indirect
github.com/aws/aws-sdk-go v1.38.20 // indirect
github.com/baidubce/bce-sdk-go v0.9.123 // indirect
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect github.com/buger/jsonparser v1.1.1 // indirect
@ -112,7 +134,7 @@ require (
github.com/prometheus/statsd_exporter v0.21.0 // indirect github.com/prometheus/statsd_exporter v0.21.0 // indirect
github.com/shirou/gopsutil/v3 v3.22.2 // indirect github.com/shirou/gopsutil/v3 v3.22.2 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.1.2 // indirect github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.3.0 // indirect github.com/spf13/cast v1.3.0 // indirect
github.com/spf13/jwalterweatherman v1.0.0 // indirect github.com/spf13/jwalterweatherman v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
@ -120,6 +142,7 @@ require (
github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect github.com/tklauser/numcpus v0.4.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/u2takey/go-utils v0.3.1 // indirect
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
github.com/ugorji/go/codec v1.2.9 // indirect github.com/ugorji/go/codec v1.2.9 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
@ -138,6 +161,7 @@ require (
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
golang.org/x/sys v0.5.0 // indirect golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect golang.org/x/text v0.7.0 // indirect
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
google.golang.org/appengine v1.6.6 // indirect google.golang.org/appengine v1.6.6 // indirect
google.golang.org/genproto v0.0.0-20220504150022-98cd25cafc72 // indirect google.golang.org/genproto v0.0.0-20220504150022-98cd25cafc72 // indirect
google.golang.org/grpc v1.51.0 // indirect google.golang.org/grpc v1.51.0 // indirect

@ -10,6 +10,79 @@ import (
var Data = new(AppConfig) var Data = new(AppConfig)
var (
AppMode string
HttpPort string
Key string
Cert string
IsHttps bool
RunHttps bool
Domain string
OssDomain string
ServerDM string
Env string
DriverUrl string
AppointUrl string
MaterialHost string
BosAk string
BosSk string
BosBucketName string
BosBaseDir string
BosUrl string
BosHttp string
BosDomain string
ProjectMapDir string
JaegerHost string
JaegerOpen bool
Cron bool
DingAccessToken string
DingUrl string
HolidayID string
HolidaySecret string
HolidaySingleUrl string
HolidayMultiUrl string
ErpAk string
ErpSk string
// rabbitmq
RabbitmqUser string
RabbitmqPassword string
RabbitmqHost string
RabbitmqPort int
RabbitmqVhost string
RabbitmqVhostArtwork string
RedisDB int
RedisAddr string
RedisPw string
//shop配置
ShopHost string
//ShopDetail string
// 地图
MapAppCode string
// es
ElasticHost string
SendIndexesUrl string
ChatGptHost string
ApiHost string
Level string
Filename string
MaxSize string
MaxAge string
MaxBackups string
YearGiftCheckHost string
Aliyun struct {
AccessKeyId string
AccessKeySecret string
}
)
type AppConfig struct { type AppConfig struct {
System struct { System struct {
Domain string Domain string
@ -42,6 +115,15 @@ type AppConfig struct {
Key string Key string
Expire int32 Expire int32
} }
Bos struct {
AccessKeyId string
AccessKeySecret string
Endpoint string
Host string
BucketName string
BosBaseDir string
CdnHost string
}
} }
func GetConf() (iniConf string, err error) { func GetConf() (iniConf string, err error) {

@ -0,0 +1,12 @@
package model
type BaiduAccessToken struct {
Refresh_token string `json:"refresh_token"`
Expires_in uint64 `json:"expires_in"`
Scope string `json:"scope"`
Session_key string `json:"session_key"`
Access_token string `json:"access_token"`
Session_secret string `json:"session_secret"`
Error string `json:"error"`
Error_description string `json:"error_description"`
}

@ -6,10 +6,28 @@ const (
MODE_ENV = "MODE_ENV" MODE_ENV = "MODE_ENV"
) )
const (
HttpType = "http://"
HttpsType = "https://"
TmpArtworkDir = "./runtime/tmp/artworks"
TmpArtistDir = "./runtime/tmp/artists"
MediaPath = "./runtime/"
TplPath = "./data/"
ImgActionRotate = "rotate" //旋转
MediaTypeVideo = "video"
MediaTypeImage = "video"
)
type Response struct { type Response struct {
Status int `json:"status"` Status int `json:"status"`
Data interface{} `json:"data"` Data interface{} `json:"data"`
Msg string `json:"msg"` Msg string `json:"msg"`
Code int `json:"code"`
Error error `json:"error"`
Err string `json:"err"`
Keys []string `json:"keys"`
Mark string `json:"mark,omitempty"`
Page *PageInfo `json:"page,omitempty"`
} }
type PageInfo struct { type PageInfo struct {

@ -25,4 +25,11 @@ const (
NEED_LOGIN = "请先登录" NEED_LOGIN = "请先登录"
INVALID_TOKEN = "token不合法" INVALID_TOKEN = "token不合法"
INVALID_PARAMS = "参数错误"
JSON_UNMARSHAL = "Json解析错误"
ERROR_BAIDU_IMAGE = "图片审核不通过"
ERROR_BAIDU_FAIL = "图片审核失败"
ErrorUploadBos
) )

@ -1,9 +1,12 @@
package response package response
import ( import (
"fmt"
"github.com/exhibition-main/internal/model" "github.com/exhibition-main/internal/model"
"github.com/exhibition-main/internal/msg"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"net/http" "net/http"
"reflect"
) )
func ResponseMsg(c *gin.Context, httpCode int, Resp model.Response) { func ResponseMsg(c *gin.Context, httpCode int, Resp model.Response) {
@ -25,3 +28,158 @@ func ResponseQuickMsg(c *gin.Context, Status uint8, Msg string, Data interface{}
Data: Data, Data: Data,
}) })
} }
func Success(c *gin.Context, datas ...interface{}) {
var data any
if datas != nil {
data = datas[0]
}
dataFieldStr, _ := c.Get("dataField")
key := []string{"*"}
if dataFieldStr != "" && dataFieldStr != nil {
dataField := dataFieldStr.([]string)
key = dataField
if len(dataField) == 1 && dataField[0] == "*" { //不做处理
} else if len(dataField) >= 1 {
isList := isList(reflect.TypeOf(data).Elem())
// 是列表返回
if isList == false {
ChangeFromReflect(data, dataField)
} else {
ChangeRawFromReflect(data, dataField)
}
}
}
c.JSON(http.StatusOK, model.Response{
Status: msg.Ok,
Code: msg.StatusOK,
Data: data,
// Keys: dataField,
Keys: key,
})
c.Abort()
}
func IsContainString(items []string, item string) bool {
for _, eachItem := range items {
if eachItem == item {
return true
}
}
return false
}
func ChangeFromReflect(data interface{}, dataField []string) {
m := reflect.TypeOf(data).Elem()
for i := 0; i < m.NumField(); i++ {
fieldType := m.Field(i)
if IsContainString(dataField, fieldType.Name) == false {
field := reflect.ValueOf(data).Elem().FieldByName(fieldType.Name)
switch m.Field(i).Type.Name() {
case "int":
if field.CanSet() {
field.SetInt(0)
}
case "uint":
if field.CanSet() {
field.SetUint(0)
}
case "uint64":
if field.CanSet() {
field.SetUint(0)
}
case "string":
if field.CanSet() {
field.SetString("")
}
default:
if reflect.ValueOf(data).Elem().FieldByName(fieldType.Name).CanAddr() {
if reflect.ValueOf(data).Elem().FieldByName(fieldType.Name).Kind() == reflect.Slice {
field := reflect.ValueOf(data).Elem().FieldByName(fieldType.Name)
if field.CanSet() {
field.Set(reflect.MakeSlice(field.Type(), 0, 0))
}
}
if reflect.ValueOf(data).Elem().FieldByName(fieldType.Name).Kind() == reflect.Struct {
}
if reflect.ValueOf(data).Elem().FieldByName(fieldType.Name).Kind() == reflect.Ptr {
field := reflect.ValueOf(data).Elem().FieldByName(fieldType.Name)
if !reflect.ValueOf(data).Elem().FieldByName(fieldType.Name).IsNil() {
fieldType := reflect.ValueOf(data).Elem().FieldByName(fieldType.Name).Elem().Type()
if field.CanSet() {
field.Set(reflect.New(fieldType))
}
}
}
}
}
}
}
}
func ChangeRawFromReflect(data interface{}, dataField []string) {
sliceContent := reflect.ValueOf(data).Elem().FieldByName("Data")
for i := 0; i < sliceContent.Len(); i++ {
sliceContent.Index(i)
ChangeFromReflect(sliceContent.Index(i).Interface(), dataField)
}
}
func isList(m reflect.Type) bool {
dataExist := false
for i := 0; i < m.NumField(); i++ {
fieldType := m.Field(i)
if fieldType.Name == "Data" {
getValue := reflect.ValueOf(fieldType)
if getValue.Kind() != reflect.Slice {
dataExist = true
}
break
}
}
return dataExist
}
// Error 统一错误返回
func Error(c *gin.Context, code int, err error, message ...string) {
fmt.Println("err:", err)
status := msg.Fail
if code == msg.StatusUnauthorized {
status = msg.StatusUnauthorized
}
var msgStr string
if message != nil {
msgStr = message[0]
} else if err != nil {
msgStr = err.Error()
}
c.JSON(msg.StatusOK, model.Response{
Status: status,
Msg: msgStr,
Data: nil,
})
c.Abort()
}

@ -0,0 +1,58 @@
package logic
import (
"encoding/json"
"errors"
"fmt"
"github.com/dubbogo/gost/log/logger"
"github.com/exhibition-main/internal/model"
"github.com/exhibition-main/pkg/utils"
"time"
)
const (
grantType = "client_credentials"
clientId = "SjscdLEybzyxiV7lXKA5iSvZ"
clientSecret = "22fCduMdCarO6WWOi4WiSmt9rIeez3FW"
)
var accessToken string
var expiresIn uint64
func GetImageAccessToken() (string, error) {
var (
resObj model.BaiduAccessToken
err error
// daoAccessToken entity.AccessToken
)
if expiresIn == 0 || expiresIn < uint64(time.Now().Unix()) {
fmt.Println(1)
if resObj, err = getAccessTokenWithApi(); err != nil { //从链上获取
return "", err
}
accessToken = resObj.Access_token
expiresIn = resObj.Expires_in
}
return accessToken, nil
}
func getAccessTokenWithApi() (model.BaiduAccessToken, error) {
var (
resObj model.BaiduAccessToken
err error
)
url := "https://aip.baidubce.com/oauth/2.0/token"
urlReq := "?grant_type=" + grantType + "&client_id=" + clientId + "&client_secret=" + clientSecret
res := utils.Get(url + urlReq)
if err = json.Unmarshal([]byte(res), &resObj); err != nil {
logger.Error("getAccessTokenWithApi json err", err)
return resObj, err
}
if resObj.Error != "" {
logger.Error("getAccessTokenWithApi err", err)
return resObj, errors.New(resObj.Error_description)
}
return resObj, err
}

@ -0,0 +1,119 @@
package logic
import (
"github.com/dubbogo/gost/log/logger"
"github.com/rwcarlsen/goexif/exif"
"golang.org/x/image/bmp"
"image"
"image/jpeg"
"image/png"
"os"
"path"
"strings"
)
// ReadOrientation 方向判断
func ReadOrientation(filename string) (direct int, err error) {
file, err := os.Open(filename)
defer file.Close()
if err != nil {
logger.Error("failed to open file, err: ", err)
return
}
x, err := exif.Decode(file)
if err != nil {
logger.Error("failed to decode file, err: ", err)
return
}
orientation, err := x.Get(exif.Orientation)
if err != nil {
logger.Error("failed to orientation file, err: ", err)
return
}
direct, err = orientation.Int(0)
if err != nil {
logger.Error("failed to convert type file, err: ", err)
return
}
return
}
// 旋转90度
func rotate90(m image.Image) image.Image {
rotate90 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dy(), m.Bounds().Dx()))
// 矩阵旋转
for x := m.Bounds().Min.Y; x < m.Bounds().Max.Y; x++ {
for y := m.Bounds().Max.X - 1; y >= m.Bounds().Min.X; y-- {
// 设置像素点
rotate90.Set(m.Bounds().Max.Y-x, y, m.At(y, x))
}
}
return rotate90
}
// 旋转180度
func rotate180(m image.Image) image.Image {
rotate180 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dx(), m.Bounds().Dy()))
// 矩阵旋转
for x := m.Bounds().Min.X; x < m.Bounds().Max.X; x++ {
for y := m.Bounds().Min.Y; y < m.Bounds().Max.Y; y++ {
// 设置像素点
rotate180.Set(m.Bounds().Max.X-x, m.Bounds().Max.Y-y, m.At(x, y))
}
}
return rotate180
}
// 旋转270度
func rotate270(m image.Image) image.Image {
rotate270 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dy(), m.Bounds().Dx()))
// 矩阵旋转
for x := m.Bounds().Min.Y; x < m.Bounds().Max.Y; x++ {
for y := m.Bounds().Max.X - 1; y >= m.Bounds().Min.X; y-- {
// 设置像素点
rotate270.Set(x, m.Bounds().Max.X-y, m.At(y, x))
}
}
return rotate270
}
func MakeThumbnail(imagePath, savePath string) error {
prefix := strings.ToLower(path.Ext("./2.jpg"))
ori, err := ReadOrientation(imagePath)
if err != nil {
return err
}
file, _ := os.Open(imagePath)
defer file.Close()
img, _, err := image.Decode(file)
if err != nil {
return err
}
//苹果手机拍照的图片会有方向属性Orientation
//经过Decode和Encode编码处理后方向属性会丢失导致图片被旋转
switch ori {
case 6: //90度图片旋转
img = rotate90(img)
case 3:
img = rotate180(img)
case 8:
img = rotate270(img)
}
newImg, _ := os.Create(savePath)
defer newImg.Close()
switch prefix {
case ".jpg", ".jpeg":
err = jpeg.Encode(newImg, img, &jpeg.Options{Quality: 100})
case "png":
err = png.Encode(newImg, img)
case "bmp":
err = bmp.Encode(newImg, img)
default:
err = jpeg.Encode(newImg, img, &jpeg.Options{Quality: 100})
}
if err != nil {
logger.Error("Encode err", err)
return err
}
return nil
}

@ -2,6 +2,8 @@ package router
import ( import (
"github.com/exhibition-main/internal/middleware" "github.com/exhibition-main/internal/middleware"
"github.com/exhibition-main/pkg/service"
"github.com/exhibition-main/pkg/service/common"
"net/http" "net/http"
"github.com/gin-contrib/gzip" "github.com/gin-contrib/gzip"
@ -16,49 +18,20 @@ func NewRouter() *gin.Engine {
r.Use(gzip.Gzip(gzip.DefaultCompression)) r.Use(gzip.Gzip(gzip.DefaultCompression))
//加入日志中间件,跨域中间件 //加入日志中间件,跨域中间件
r.Use(middleware.NewLogger(), middleware.Cors(), middleware.GinRecovery(true)) r.Use(middleware.NewLogger(), middleware.Cors(), middleware.GinRecovery(true))
//noAuth := r.Group("")
auth := r.Group("") auth := r.Group("")
auth.Use(middleware.JWTAuthMiddleware()) auth.Use(middleware.JWTAuthMiddleware())
//userAuth := auth.Group("user") // 上传
//{ upload := auth.Group("upload")
// userAuth.POST("info", api.UserInfo) {
// userAuth.POST("tickets", api.Tickets) upload.POST("img", common.UploadImg)
// userAuth.POST("login-out", api.LoginOut) }
// userAuth.POST("destroy", api.Destroy)
//} registerAuth := auth.Group("register")
//userNoAuth := noAuth.Group("user") {
//{ registerAuth.POST("register_record_list", service.RegisterRecordList)
// userNoAuth.POST("login", api.Login) registerAuth.POST("check_by_phone", service.CheckPhone)
//} registerAuth.POST("save_register_info", service.SaveRegisterRecord)
//goodsAuth := auth.Group("goods") }
//{
// goodsAuth.POST("drink-list", api.DrinkList)
// goodsAuth.POST("ticket-list", api.TickerList)
// goodsAuth.POST("set-meal-list", api.SetMealList)
//}
//
//orderAuth := auth.Group("order")
//{
// orderAuth.POST("buy-goods", api.BuyGoods)
// orderAuth.POST("buy-tickets", api.BuyTicket)
// orderAuth.POST("buy-balance", api.BuyBalance)
// orderAuth.POST("buy-set-meal", api.BuySetMeal)
// orderAuth.POST("history-goods", api.HistoryGoods)
// orderAuth.POST("history-tickets", api.HistoryTickets)
// orderAuth.POST("history-balance", api.HistoryBalance)
//}
//
//orderNoAuth := noAuth.Group("order")
//{
// orderNoAuth.POST("wx_callback", api.WxCallback)
// orderAuth.POST("order-data-h5", api.OrderDataH5)
// orderAuth.POST("update-h5-order", api.UpdateH5Order)
//}
//
//miniNoAuth := noAuth.Group("mini")
//{
// miniNoAuth.POST("url-scheme", api.UrlScheme)
//}
//静态文件 //静态文件
r.StaticFS("/static", http.Dir("./runtime")) r.StaticFS("/static", http.Dir("./runtime"))

@ -0,0 +1,309 @@
package common
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/disintegration/imaging"
"github.com/dubbogo/gost/log/logger"
"github.com/exhibition-main/internal/config"
"github.com/exhibition-main/internal/model"
"github.com/exhibition-main/internal/msg"
"github.com/exhibition-main/internal/response"
"github.com/exhibition-main/pkg/logic"
"github.com/exhibition-main/pkg/utils"
"github.com/fonchain_enterprise/utils/objstorage"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
ffmpeg "github.com/u2takey/ffmpeg-go"
"go.uber.org/zap"
"io/ioutil"
"mime/multipart"
"net/url"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"sync"
)
var (
wg sync.WaitGroup
)
const (
MediaPath = "./runtime/"
RouteType = "static/"
VideoType = "video"
ImageType = "image"
PngType = "png"
ArtworkFilePath = "artwork"
ArtworkChunkBasePath = "./runtime/tmp/artworks"
)
func UploadImg(c *gin.Context) {
var err error
source := c.PostForm("source")
mask := c.PostForm("mask")
action := c.PostForm("action")
if mask == "" {
mask = "default"
}
mediaType := c.PostForm("type")
logger.Errorf("UploadImg 1 %+v", mask)
var BasePath string
if mediaType == "" || mediaType == ImageType {
mediaType = ImageType
}
BasePath = fmt.Sprintf("%s%s", MediaPath, mediaType)
//BaseRoute = fmt.Sprintf("%s%s", RouteType, mediaType)
var isCompress int
if cStr, ok := c.GetPostForm("is_compress"); ok {
var errS error
isCompress, errS = strconv.Atoi(cStr)
if errS != nil {
response.ResponseQuickMsg(c, msg.Fail, errS.Error(), nil)
return
}
}
logger.Errorf("UploadImg 2 %+v", mask)
// 检验参数
if mask == "" || source == "" {
response.ResponseQuickMsg(c, msg.Fail, msg.INVALID_PARAMS, nil)
return
}
file, err := c.FormFile("file")
// 检验文件
if err != nil {
logger.Errorf("Upload FormFile err", err)
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
logger.Errorf("UploadImg 3 %+v", mask)
// 判断是不是视频或者需要压缩
var oriUrl string
if isCompress != 1 && mediaType != "video" && action == "" {
oriUrl, err = quickBos(file, mediaType, mask, source)
if err != nil {
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
response.ResponseQuickMsg(c, msg.Ok, msg.SUCCESS, map[string]interface{}{
"ori_url": oriUrl,
})
return
}
logger.Errorf("UploadImg 4 %+v", mask)
//创建文件名
fileExt := strings.ToLower(path.Ext(file.Filename))
filename := uuid.NewV4()
if err != nil {
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
fileFullName := fmt.Sprintf("%s%s", filename, fileExt)
//检测文件夹 不存在就创建
imgPath := fmt.Sprintf("%s/%s/%s", BasePath, source, mask)
_, err = utils.CheckDirPath(imgPath, true)
if err != nil {
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
dst := fmt.Sprintf("%s/%s", imgPath, fileFullName)
logger.Errorf("UploadImg 5 %+v", mask)
// 保存文件至指定路径
err = c.SaveUploadedFile(file, dst)
if err != nil {
logger.Errorf("Upload FormFile err", err)
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
logger.Errorf("UploadImg 6 %+v", mask)
if action == model.ImgActionRotate {
fileFullName = fmt.Sprintf("%s%s", filename, fileExt)
newDst := fmt.Sprintf("%s/%s_rotate%v", imgPath, filename, fileExt)
if err = logic.MakeThumbnail(dst, newDst); err != nil {
//ResponseQuickMsg(c, e.Failed, e.GetMsg(e.ERROR_ROTATE_IMG), nil)
//return
} else {
_ = os.Remove(dst)
dst = newDst
}
}
//localUrl := fmt.Sprintf("%s/%s/%s/%s/%s", config.ServerDM, BaseRoute, source, mask, fileFullName)
var data map[string]string = make(map[string]string, 2)
//data["ori_url"] = localUrl
if int32(isCompress) == 1 {
//压缩图片并存储在原图路径命名格式xx.jpg_small.jpg
fileFullName = fmt.Sprintf("%s_small%s", filename, fileExt)
newDst := fmt.Sprintf("%s/%s", imgPath, fileFullName)
//compressUrl := fmt.Sprintf("%s/%s/%s/%s/%s", config.ServerDM, BaseRoute, source, mask, fileFullName)
err = utils.CompressJPG(dst, newDst)
compressUrl, err := PutBos(newDst, mediaType, true)
if err != nil {
logger.Errorf("Upload compress err", err)
response.ResponseQuickMsg(c, msg.Fail, err.Error(), data)
return
}
data["compress_url"] = compressUrl
}
logger.Errorf("UploadImg 7 %+v", mask)
// 如果是视频需要截图图片做封面
if mediaType == VideoType {
videoCover := fmt.Sprintf("%s/%s", imgPath, filename)
_, err = GetSnapshot(dst, videoCover, 1)
if err != nil {
logger.Errorf("GetSnapshot err %+v", err.Error())
response.ResponseQuickMsg(c, msg.Fail, "获取封面失败", err.Error())
return
}
logger.Errorf("UploadImg 8 %+v", mask)
logger.Errorf("UploadImg 8.1 videoCover %+v", videoCover)
//data["cover_url"] = fmt.Sprintf("%s/%s/%s/%s/%s", config.ServerDM, BaseRoute, source, mask, fmt.Sprintf("%s.%s", filename, PngType))
coverUrl, err := PutBos(videoCover+"."+PngType, mediaType, true)
data["cover_url"] = coverUrl
if err != nil {
logger.Errorf("Upload GetSnapshot err", zap.Error(err))
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
}
ossUrl, err := PutBos(dst, mediaType, true)
if err != nil {
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
data["ori_url"] = ossUrl
response.ResponseQuickMsg(c, msg.Ok, msg.SUCCESS, data)
return
}
func GetSnapshot(videoPath, snapshotPath string, frameNum int) (snapshotName string, err error) {
buf := bytes.NewBuffer(nil)
err = ffmpeg.Input(videoPath).
Filter("select", ffmpeg.Args{fmt.Sprintf("gte(n,%d)", frameNum)}).
Output("pipe:", ffmpeg.KwArgs{"vframes": 1, "format": "image2", "vcodec": "mjpeg"}).
WithOutput(buf, os.Stdout).
Run()
if err != nil {
logger.Errorf("GetSnapshot Input err:", zap.Error(err))
return "", err
}
img, err := imaging.Decode(buf)
if err != nil {
logger.Errorf("GetSnapshot Decode err:", zap.Error(err))
return "", err
}
err = imaging.Save(img, snapshotPath+"."+PngType)
if err != nil {
logger.Errorf("GetSnapshot Save err:", zap.Error(err))
return "", err
}
names := strings.Split(snapshotPath, "\\")
snapshotName = names[len(names)-1] + "." + PngType
return
}
func PutBos(filePath string, mediaType string, needRemove bool) (url string, err error) {
BOSClient, err := objstorage.NewBOS(config.BosAk, config.BosSk, objstorage.BOS_BJ)
if err != nil {
logger.Errorf("PutBos NewBOS err ", err)
err = errors.New(msg.ErrorUploadBos)
return
}
f, err := os.Open(filePath)
if err != nil {
logger.Errorf("PutBos Open err %+v", err.Error())
return
}
fileBytes, _ := ioutil.ReadAll(f)
f.Close()
//删除本地文件
if needRemove {
os.Remove(filePath)
}
if mediaType == "image" {
if err = BaiduCheckImage(fileBytes); err != nil {
return
}
}
filePath = strings.Replace(filePath, "./runtime", "", 1)
var objectName string = fmt.Sprintf("%s/%s%s", config.BosBaseDir, config.Env, filePath)
_, err = BOSClient.PutObjectFromBytes(config.BosBucketName, objectName, fileBytes)
if err != nil {
logger.Errorf("PutBos PutObject err %+v", err.Error())
err = errors.New(msg.ErrorUploadBos)
return
}
//url = fmt.Sprintf("%s%s%s/%s", config.BosHttp, config.BosBucketName, config.BosUrl, objectName)
url = fmt.Sprintf("%s%s/%s", config.BosHttp, config.BosDomain, objectName)
return
}
func quickBos(file *multipart.FileHeader, mediaType string, mask string, source string) (url string, err error) {
newFile, _ := file.Open()
defer newFile.Close()
uuids := uuid.NewV4()
filePath := fmt.Sprintf("%s/%s/%s/%s%s", mediaType, mask, source, uuids, filepath.Ext(file.Filename))
fileBytes, _ := ioutil.ReadAll(newFile)
if mediaType == "image" {
if err = BaiduCheckImage(fileBytes); err != nil {
return
}
}
var objectName string = fmt.Sprintf("%s/%s/%s", config.BosBaseDir, config.Env, filePath)
BOSClient, _ := objstorage.NewBOS(config.BosAk, config.BosSk, objstorage.BOS_BJ)
_, err = BOSClient.PutObjectFromBytes(config.BosBucketName, objectName, fileBytes)
if err != nil {
logger.Errorf("quickBos err", err)
return
}
//url = fmt.Sprintf("%s%s%s/%s", config.BosHttp, config.BosBucketName, config.BosUrl, objectName)
url = fmt.Sprintf("%s%s/%s", config.BosHttp, config.BosDomain, objectName)
return
}
// BaiduCheckImage 图片鉴黄
func BaiduCheckImage(imageByte []byte) (err error) {
return
var (
accesstoken string
response string
)
sourcestring := base64.StdEncoding.EncodeToString(imageByte)
if accesstoken, err = logic.GetImageAccessToken(); err != nil {
return err
}
host := "https://aip.baidubce.com/rest/2.0/solution/v1/img_censor/v2/user_defined?access_token=[" + accesstoken + "]"
if response, err = utils.PostForm(host, url.Values{"image": {sourcestring}}); err != nil {
logger.Error("user_defined PostForm err", err)
return err
}
var res struct {
ErrorCode int64 `json:"error_code"`
ErrorMsg string `json:"error_msg"`
Conclusion string `json:"conclusion"`
Log_id uint64 `json:"log_id"`
IsHitMd5 bool `json:"isHitMd5"`
ConclusionType int64 `json:"conclusionType"`
}
if err = json.Unmarshal([]byte(response), &res); err != nil {
err = errors.New(msg.JSON_UNMARSHAL)
return
}
logger.Error("user_defined res", res)
if res.ErrorCode != 0 || res.ErrorMsg != "" {
return errors.New(msg.ERROR_BAIDU_FAIL)
}
if res.Conclusion != "合规" && res.Conclusion != "疑似" {
return errors.New(msg.ERROR_BAIDU_IMAGE)
}
return nil
}

@ -0,0 +1,14 @@
package service
import (
"dubbo.apache.org/dubbo-go/v3/config"
"github.com/robfig/cron/v3"
)
func Task(c *cron.Cron) {
if config.GetConsumerService("ArtworkClientImpl") != nil {
_, _ = c.AddFunc("@every 5m", func() {
})
}
}

@ -3,13 +3,14 @@ package service
import ( import (
"dubbo.apache.org/dubbo-go/v3/config" "dubbo.apache.org/dubbo-go/v3/config"
_ "dubbo.apache.org/dubbo-go/v3/imports" _ "dubbo.apache.org/dubbo-go/v3/imports"
"github.com/exhibition-main/api/exhibition"
appConfig "github.com/exhibition-main/internal/config" appConfig "github.com/exhibition-main/internal/config"
) )
//var GrpcAccountClientImpl = new(account.AccountClientImpl) var GrpcExhibitionClientImpl = new(exhibition.ExhibitionClientImpl)
func init() { func init() {
//config.SetConsumerService(GrpcAccountClientImpl) config.SetConsumerService(GrpcExhibitionClientImpl)
appConfig.GetOptions() appConfig.GetOptions()
if err := config.Load(); err != nil { if err := config.Load(); err != nil {
panic(err) panic(err)

@ -1 +1,61 @@
package service package service
import (
"context"
"github.com/dubbogo/gost/log/logger"
"github.com/exhibition-main/api/exhibition"
"github.com/exhibition-main/internal/msg"
"github.com/exhibition-main/internal/response"
"github.com/gin-gonic/gin"
)
func RegisterRecordList(c *gin.Context) {
var recordListReq exhibition.RecordListReq
if err := c.ShouldBind(&recordListReq); err != nil {
logger.Errorf("RegisterRecordList ShouldBind err", err)
response.ResponseQuickMsg(c, msg.Fail, msg.INVALID_PARAMS, nil)
return
}
resp, err := GrpcExhibitionClientImpl.RegisterRecordList(context.Background(), &recordListReq)
if err != nil {
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
response.ResponseQuickMsg(c, msg.Ok, resp.Msg, resp)
return
}
func CheckPhone(c *gin.Context) {
var registerInfo exhibition.RegisterInfo
if err := c.ShouldBind(&registerInfo); err != nil {
logger.Errorf("CheckPhone ShouldBind err", err)
response.ResponseQuickMsg(c, msg.Fail, msg.INVALID_PARAMS, nil)
return
}
resp, err := GrpcExhibitionClientImpl.CheckPhone(context.Background(), &registerInfo)
if err != nil {
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
response.ResponseQuickMsg(c, msg.Ok, resp.Msg, resp)
return
}
func SaveRegisterRecord(c *gin.Context) {
var registerInfo exhibition.RegisterInfo
if err := c.ShouldBind(&registerInfo); err != nil {
logger.Errorf("SaveRegisterRecord ShouldBind err", err)
response.ResponseQuickMsg(c, msg.Fail, msg.INVALID_PARAMS, nil)
return
}
resp, err := GrpcExhibitionClientImpl.SaveRegisterRecord(context.Background(), &registerInfo)
if err != nil {
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
response.ResponseQuickMsg(c, msg.Ok, resp.Msg, resp)
return
}

@ -0,0 +1,82 @@
package utils
import (
"bytes"
"errors"
"fmt"
"github.com/exhibition-main/internal/msg"
"github.com/nfnt/resize"
"go.uber.org/zap"
"image"
"image/jpeg"
"os"
)
const (
CompressLimit = 1024 * 1024 * 1
MaxHeight uint = 600
)
func CheckDirPath(path string, create bool) (exists bool, err error) {
exists = false
if path == "" {
err = errors.New(msg.INVALID_PARAMS)
return
}
if _, err = os.Stat(path); os.IsNotExist(err) {
if !create {
return
}
if err = os.MkdirAll(path, os.ModePerm); err != nil {
return
}
}
exists = true
return
}
// CompressJPG 压缩图片,并返回缩略图路径
func CompressJPG(dst string, newDst string) (err error) {
filebytes, err := os.ReadFile(dst)
if err != nil {
return err
}
compressbytes := compressImageResource(filebytes)
fo, err := os.Create(newDst)
defer fo.Close()
if err != nil {
return err
}
_, err = fo.Write(compressbytes)
if err != nil {
return err
}
return nil
}
func compressImageResource(data []byte) []byte {
if len(data) < CompressLimit {
return data
}
img, _, err := image.Decode(bytes.NewReader(data))
if err != nil {
return data
}
m := resize.Resize(0, MaxHeight, img, resize.Lanczos3)
buf := bytes.Buffer{}
err = jpeg.Encode(&buf, m, &jpeg.Options{Quality: 100})
if err != nil {
zap.L().Error("compressImageResource Encode err", zap.Error(err))
return data
}
if buf.Len() > len(data) {
return data
}
fmt.Println(buf.Len())
if buf.Len() >= CompressLimit {
bytes := compressImageResource(buf.Bytes())
return bytes
}
return buf.Bytes()
}

@ -0,0 +1,47 @@
package utils
import (
"bytes"
"io"
"io/ioutil"
"net/http"
"net/url"
"time"
)
// PostForm 发送post请求
func PostForm(urlStr string, data url.Values) (string, error) {
resp, err := http.PostForm(urlStr, data)
if err != nil {
// handle error
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
// handle error
}
return string(body), err
}
func Get(url string) string {
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var buffer [512]byte
result := bytes.NewBuffer(nil)
for {
n, err := resp.Body.Read(buffer[0:])
result.Write(buffer[0:n])
if err != nil && err == io.EOF {
break
} else if err != nil {
panic(err)
}
}
return result.String()
}
Loading…
Cancel
Save