模块化上传驱动,使用泛型优化工具库降低冗余

This commit is contained in:
孟帅
2023-06-02 20:29:08 +08:00
parent fdc48b9335
commit 62ecbb7f26
96 changed files with 1276 additions and 1483 deletions

View File

@@ -9,41 +9,11 @@ import (
"crypto/rand"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/utility/convert"
r "math/rand"
"strings"
"time"
)
// SplitMemberIds 从截取字串符中读取用户ID
func SplitMemberIds(str, pos string) (memberIds []int64) {
receiver := strings.Split(strings.TrimSpace(str), pos)
if len(receiver) == 0 {
return memberIds
}
if len(receiver) == 1 && strings.TrimSpace(receiver[0]) == "" {
return memberIds
}
for _, memberId := range receiver {
memberIds = append(memberIds, gconv.Int64(strings.TrimSpace(memberId)))
}
return convert.UniqueSliceInt64(memberIds)
}
// GetMapKeysByString 获取map的所有key字串符类型
func GetMapKeysByString(m map[string]string) []string {
// 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率很高
j := 0
keys := make([]string, len(m))
for k := range m {
keys[j] = k
j++
}
return keys
}
// RandomCreateBytes 生成随机字串符
func RandomCreateBytes(n int, alphabets ...byte) []byte {
if len(alphabets) == 0 {
@@ -51,13 +21,12 @@ func RandomCreateBytes(n int, alphabets ...byte) []byte {
}
var bytes = make([]byte, n)
var randBy bool
r.Seed(time.Now().UnixNano())
if num, err := rand.Read(bytes); num != n || err != nil {
randBy = true
}
for i, b := range bytes {
if randBy {
bytes[i] = alphabets[r.Intn(len(alphabets))]
bytes[i] = alphabets[r.New(r.NewSource(time.Now().UnixNano())).Intn(len(alphabets))]
} else {
bytes[i] = alphabets[b%byte(len(alphabets))]
}

View File

@@ -17,23 +17,21 @@ var (
fieldTags = []string{"json"} // 实体字段名称映射
)
// UniqueSliceInt64 切片去重
func UniqueSliceInt64(languages []int64) []int64 {
result := make([]int64, 0, len(languages))
temp := map[int64]struct{}{}
for _, item := range languages {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
result = append(result, item)
}
// GetMapKeys 获取map的所有key
func GetMapKeys[K comparable](m map[K]any) []K {
j := 0
keys := make([]K, len(m))
for k := range m {
keys[j] = k
j++
}
return result
return keys
}
// UniqueSliceString 切片去重
func UniqueSliceString(languages []string) []string {
result := make([]string, 0, len(languages))
temp := map[string]struct{}{}
// UniqueSlice 切片去重
func UniqueSlice[K comparable](languages []K) []K {
result := make([]K, 0, len(languages))
temp := map[K]struct{}{}
for _, item := range languages {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
@@ -121,19 +119,19 @@ func reflectTag(reflectType reflect.Type, filterTags []string, tags []string) ([
// reflectTagName 解析实体中的描述标签优先级description > dc > json > Name
func reflectTagName(field reflect.StructField, filterTags []string, isDef bool) string {
if validate.InSliceString(filterTags, "description") {
if validate.InSlice(filterTags, "description") {
if description, ok := field.Tag.Lookup("description"); ok && description != "" {
return description
}
}
if validate.InSliceString(filterTags, "dc") {
if validate.InSlice(filterTags, "dc") {
if dc, ok := field.Tag.Lookup("dc"); ok && dc != "" {
return dc
}
}
if validate.InSliceString(filterTags, "json") {
if validate.InSlice(filterTags, "json") {
if jsonName, ok := field.Tag.Lookup("json"); ok && jsonName != "" {
return jsonName
}

View File

@@ -12,12 +12,6 @@ import (
"path/filepath"
)
const ( //文件大小单位
_ = iota
KB = 1 << (10 * iota)
MB
)
type fileInfo struct { //文件信息
name string
size int64

View File

@@ -1,142 +0,0 @@
// Package file
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package file
import (
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/text/gstr"
"io"
"path"
)
// 文件分类
const (
KindImg = "images" // 图片
KindDoc = "document" // 文档
KindAudio = "audio" // 音频
KindVideo = "video" // 视频
KindOther = "other" // 其他
)
var (
// 图片类型
imgType = g.MapStrStr{
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"png": "image/png",
"gif": "image/gif",
"webp": "image/webp",
"cr2": "image/x-canon-cr2",
"tif": "image/tiff",
"bmp": "image/bmp",
"heif": "image/heif",
"jxr": "image/vnd.ms-photo",
"psd": "image/vnd.adobe.photoshop",
"ico": "image/vnd.microsoft.icon",
"dwg": "image/vnd.dwg",
}
// 文档类型
docType = g.MapStrStr{
"doc": "application/msword",
"docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"xls": "application/vnd.ms-excel",
"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"ppt": "application/vnd.ms-powerpoint",
"pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
}
// 音频类型
audioType = g.MapStrStr{
"mid": "audio/midi",
"mp3": "audio/mpeg",
"m4a": "audio/mp4",
"ogg": "audio/ogg",
"flac": "audio/x-flac",
"wav": "audio/x-wav",
"amr": "audio/amr",
"aac": "audio/aac",
"aiff": "audio/x-aiff",
}
// 视频类型
videoType = g.MapStrStr{
"mp4": "video/mp4",
"m4v": "video/x-m4v",
"mkv": "video/x-matroska",
"webm": "video/webm",
"mov": "video/quicktime",
"avi": "video/x-msvideo",
"wmv": "video/x-ms-wmv",
"mpg": "video/mpeg",
"flv": "video/x-flv",
"3gp": "video/3gpp",
}
)
// IsImgType 判断是否为图片
func IsImgType(ext string) bool {
_, ok := imgType[ext]
return ok
}
// GetImgType 获取图片类型
func GetImgType(ext string) (string, error) {
if mime, ok := imgType[ext]; ok {
return mime, nil
}
return "", gerror.New("Invalid image type")
}
// GetFileType 获取文件类型
func GetFileType(ext string) (string, error) {
if mime, ok := imgType[ext]; ok {
return mime, nil
}
if mime, ok := docType[ext]; ok {
return mime, nil
}
if mime, ok := audioType[ext]; ok {
return mime, nil
}
if mime, ok := videoType[ext]; ok {
return mime, nil
}
return "", gerror.Newf("Invalid file type:%v", ext)
}
// GetFileKind 获取文件所属分类
func GetFileKind(ext string) string {
if _, ok := imgType[ext]; ok {
return KindImg
}
if _, ok := docType[ext]; ok {
return KindDoc
}
if _, ok := audioType[ext]; ok {
return KindAudio
}
if _, ok := videoType[ext]; ok {
return KindVideo
}
return KindOther
}
// Ext 获取文件后缀
func Ext(baseName string) string {
return gstr.StrEx(path.Ext(baseName), ".")
}
// UploadFileByte 获取上传文件的byte
func UploadFileByte(file *ghttp.UploadFile) ([]byte, error) {
open, err := file.Open()
if err != nil {
return nil, err
}
return io.ReadAll(open)
}

View File

@@ -7,40 +7,67 @@ package format
import (
"fmt"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"strconv"
)
// Round2String 四舍五入保留小数默认2位
func Round2String(value float64, args ...interface{}) (v string) {
func Round2String(value float64, args ...interface{}) string {
var places = 2
if len(args) > 0 {
places = gconv.Int(args[0])
}
cDig := strconv.Itoa(places)
val := fmt.Sprintf("%0."+cDig+"f", value)
return val
return fmt.Sprintf("%0."+strconv.Itoa(places)+"f", value)
}
// Round2Float64 四舍五入保留小数默认2位
func Round2Float64(value float64, args ...interface{}) (v float64) {
func Round2Float64(value float64, args ...interface{}) float64 {
return gconv.Float64(Round2String(value, args...))
}
// FileSize 字节的单位转换 保留两位小数
func FileSize(fileSize int64) (size string) {
if fileSize < 1024 {
return fmt.Sprintf("%.2fB", float64(fileSize)/float64(1))
} else if fileSize < (1024 * 1024) {
return fmt.Sprintf("%.2fKB", float64(fileSize)/float64(1024))
} else if fileSize < (1024 * 1024 * 1024) {
return fmt.Sprintf("%.2fMB", float64(fileSize)/float64(1024*1024))
} else if fileSize < (1024 * 1024 * 1024 * 1024) {
return fmt.Sprintf("%.2fGB", float64(fileSize)/float64(1024*1024*1024))
} else if fileSize < (1024 * 1024 * 1024 * 1024 * 1024) {
return fmt.Sprintf("%.2fTB", float64(fileSize)/float64(1024*1024*1024*1024))
} else {
return fmt.Sprintf("%.2fEB", float64(fileSize)/float64(1024*1024*1024*1024*1024))
func FileSize(data int64) string {
var factor float64 = 1024
res := float64(data)
for _, unit := range []string{"", "K", "M", "G", "T", "P"} {
if res < factor {
return fmt.Sprintf("%.2f%sB", res, unit)
}
res /= factor
}
return fmt.Sprintf("%.2f%sB", res, "P")
}
// AgoTime 多久以前
func AgoTime(gt *gtime.Time) string {
if gt == nil {
return ""
}
n := gtime.Now().Timestamp()
t := gt.Timestamp()
var ys int64 = 31536000
var ds int64 = 86400
var hs int64 = 3600
var ms int64 = 60
var ss int64 = 1
var rs string
d := n - t
switch {
case d > ys:
rs = fmt.Sprintf("%d年前", int(d/ys))
case d > ds:
rs = fmt.Sprintf("%d天前", int(d/ds))
case d > hs:
rs = fmt.Sprintf("%d小时前", int(d/hs))
case d > ms:
rs = fmt.Sprintf("%d分钟前", int(d/ms))
case d > ss:
rs = fmt.Sprintf("%d秒前", int(d/ss))
default:
rs = "刚刚"
}
return rs
}

View File

@@ -1,56 +0,0 @@
// Package signal
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package signal
import (
"sync"
)
type StopSignal int32
type exitWait struct {
mutex sync.Mutex
wg *sync.WaitGroup
deferFuns []func()
stopSignList []chan StopSignal
}
var exitWaitHandler *exitWait
func init() {
exitWaitHandler = &exitWait{
wg: &sync.WaitGroup{},
}
}
// ExitWaitFunDo 退出后等待处理完成
func ExitWaitFunDo(doFun func()) {
exitWaitHandler.wg.Add(1)
defer exitWaitHandler.wg.Done()
if doFun != nil {
doFun()
}
}
// AppDefer 应用退出后置操作
func AppDefer(deferFun ...func()) {
exitWaitHandler.mutex.Lock()
defer exitWaitHandler.mutex.Unlock()
for _, funcItem := range deferFun {
if funcItem != nil {
exitWaitHandler.deferFuns = append(exitWaitHandler.deferFuns, funcItem)
}
}
}
// ListenStop 订阅app退出信号
func ListenStop(stopSig chan StopSignal) {
exitWaitHandler.mutex.Lock()
defer exitWaitHandler.mutex.Unlock()
exitWaitHandler.stopSignList = append(exitWaitHandler.stopSignList, stopSig)
}

View File

@@ -0,0 +1,51 @@
package simple
import (
"context"
"sync"
)
type EventFunc func(ctx context.Context, args ...interface{})
type sEvent struct {
sync.Mutex
list map[string][]EventFunc // 所有事件的列表
}
var event *sEvent
// InstanceEvent 事件实例
func InstanceEvent() *sEvent {
if event == nil {
event = &sEvent{
list: make(map[string][]EventFunc),
}
}
return event
}
// Register 往一个分组中注册事件
func (e *sEvent) Register(group string, callback EventFunc) {
e.Lock()
defer e.Unlock()
e.list[group] = append(e.list[group], callback)
}
// Call 回调一个分组的事件
func (e *sEvent) Call(group string, ctx context.Context, args ...interface{}) {
if events, ok := e.list[group]; ok {
for _, f := range events {
f(ctx, args...)
}
}
}
// Remove 移动一个分组的事件
func (e *sEvent) Remove(group string) {
delete(e.list, group)
}
// Clear 清空事件列表
func (e *sEvent) Clear() {
e.list = make(map[string][]EventFunc)
}

View File

@@ -8,35 +8,40 @@ package useragent
import (
"fmt"
"github.com/gogf/gf/v2/text/gstr"
"hotgo/internal/consts"
"regexp"
"strings"
)
// GetOs 获取OS名称
func GetOs(userAgent string) string {
osName := "Unknown"
osName := consts.Unknown
if userAgent == "" {
return osName
}
strRe, _ := regexp.Compile(`(?i:\((.*?)\))`)
userAgent = strRe.FindString(userAgent)
var (
strRe, _ = regexp.Compile(`(?i:\((.*?)\))`)
levelNames = ":micromessenger:dart:Windows NT:Windows Mobile:Windows Phone:Windows Phone OS:Macintosh|Macintosh:Mac OS:CrOS|CrOS:iPhone OS:iPad|iPad:OS:Android:Linux:blackberry:hpwOS:Series:Symbian:PalmOS:SymbianOS:J2ME:Sailfish:Bada:MeeGo:webOS|hpwOS:Maemo:"
namesArr = strings.Split(strings.Trim(levelNames, ":"), ":")
regStrArr = make([]string, len(namesArr))
)
levelNames := ":micromessenger:dart:Windows NT:Windows Mobile:Windows Phone:Windows Phone OS:Macintosh|Macintosh:Mac OS:CrOS|CrOS:iPhone OS:iPad|iPad:OS:Android:Linux:blackberry:hpwOS:Series:Symbian:PalmOS:SymbianOS:J2ME:Sailfish:Bada:MeeGo:webOS|hpwOS:Maemo:"
var regStrArr []string
namesArr := strings.Split(strings.Trim(levelNames, ":"), ":")
for _, name := range namesArr {
regStrArr = append(regStrArr, fmt.Sprintf("(%s[\\s?\\/XxSs0-9_.]+)", name))
for k, name := range namesArr {
regStrArr[k] = fmt.Sprintf("(%s[\\s?\\/XxSs0-9_.]+)", name)
}
regexpStr := fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|"))
nameRe, _ := regexp.Compile(regexpStr)
names := nameRe.FindAllString(userAgent, -1)
name := ""
userAgent = strRe.FindString(userAgent)
var (
nameRe, _ = regexp.Compile(fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|")))
names = nameRe.FindAllString(userAgent, -1)
name = ""
)
for _, s := range names {
if name == "" {
if len(name) == 0 {
name = strings.TrimSpace(s)
} else if len(name) > 0 {
} else {
if strings.Contains(name, "Macintosh") && s != "" {
name = strings.TrimSpace(s)
} else if strings.Contains(name, s) {
@@ -62,30 +67,32 @@ func GetOs(userAgent string) string {
if name != "" {
osName = name
}
return osName
}
// GetBrowser 获取浏览器名称
func GetBrowser(userAgent string) string {
deviceName := "Unknown"
var (
deviceName = consts.Unknown
levelNames = ":VivoBrowser:QQDownload:QQBrowser:QQ:MQQBrowser:MicroMessenger:TencentTraveler:LBBROWSER:TaoBrowser:BrowserNG:UCWEB:TwonkyBeamBrowser:NokiaBrowser:OviBrowser:NF-Browser:OneBrowser:Obigo:DiigoBrowser:baidubrowser:baiduboxapp:xiaomi:Redmi:MI:Lumia:Micromax:MSIEMobile:IEMobile:EdgiOS:Yandex:Mercury:Openwave:TouchPad:UBrowser:Presto:Maxthon:MetaSr:Trident:Opera:IEMobile:Edge:Chrome:Chromium:OPR:CriOS:Firefox:FxiOS:fennec:CrMo:Safari:Nexus One:Nexus S:Nexus:Blazer:teashark:bolt:HTC:Dell:Motorola:Samsung:LG:Sony:SonyST:SonyLT:SonyEricsson:Asus:Palm:Vertu:Pantech:Fly:Wiko:i-mobile:Alcatel:Nintendo:Amoi:INQ:ONEPLUS:Tapatalk:PDA:Novarra-Vision:NetFront:Minimo:FlyFlow:Dolfin:Nokia:Series:AppleWebKit:Mobile:Mozilla:Version:"
namesArr = strings.Split(strings.Trim(levelNames, ":"), ":")
regStrArr []string
)
levelNames := ":VivoBrowser:QQDownload:QQBrowser:QQ:MQQBrowser:MicroMessenger:TencentTraveler:LBBROWSER:TaoBrowser:BrowserNG:UCWEB:TwonkyBeamBrowser:NokiaBrowser:OviBrowser:NF-Browser:OneBrowser:Obigo:DiigoBrowser:baidubrowser:baiduboxapp:xiaomi:Redmi:MI:Lumia:Micromax:MSIEMobile:IEMobile:EdgiOS:Yandex:Mercury:Openwave:TouchPad:UBrowser:Presto:Maxthon:MetaSr:Trident:Opera:IEMobile:Edge:Chrome:Chromium:OPR:CriOS:Firefox:FxiOS:fennec:CrMo:Safari:Nexus One:Nexus S:Nexus:Blazer:teashark:bolt:HTC:Dell:Motorola:Samsung:LG:Sony:SonyST:SonyLT:SonyEricsson:Asus:Palm:Vertu:Pantech:Fly:Wiko:i-mobile:Alcatel:Nintendo:Amoi:INQ:ONEPLUS:Tapatalk:PDA:Novarra-Vision:NetFront:Minimo:FlyFlow:Dolfin:Nokia:Series:AppleWebKit:Mobile:Mozilla:Version:"
var regStrArr []string
namesArr := strings.Split(strings.Trim(levelNames, ":"), ":")
for _, name := range namesArr {
regStrArr = append(regStrArr, fmt.Sprintf("(%s[\\s?\\/0-9.]+)", name))
}
regexpStr := fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|"))
nameRe, _ := regexp.Compile(regexpStr)
names := nameRe.FindAllString(userAgent, -1)
level := 0
var (
regexpStr = fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|"))
nameRe, _ = regexp.Compile(regexpStr)
names = nameRe.FindAllString(userAgent, -1)
level = 0
)
for _, name := range names {
replaceRe, _ := regexp.Compile(`(?i:[\s?\/0-9.]+)`)
n := replaceRe.ReplaceAllString(name, "")
l := strings.Index(levelNames, fmt.Sprintf(":%s:", n))
l := strings.Index(levelNames, fmt.Sprintf(":%s:", replaceRe.ReplaceAllString(name, "")))
if level == 0 {
deviceName = strings.TrimSpace(name)
}
@@ -95,7 +102,6 @@ func GetBrowser(userAgent string) string {
deviceName = strings.TrimSpace(name)
}
}
return deviceName
}
@@ -119,6 +125,5 @@ func getWinOsNameWithWinNT(sName string) string {
break
}
}
return osName
}

View File

@@ -3,18 +3,16 @@
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package validate
import (
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
// 包含判断
// InSliceExistStr 判断字符或切片字符是否存在指定字符
func InSliceExistStr(elems interface{}, search string) bool {
func InSliceExistStr(elems any, search string) bool {
switch elems.(type) {
case []string:
elem := gconv.Strings(elems)
@@ -26,35 +24,15 @@ func InSliceExistStr(elems interface{}, search string) bool {
default:
return gconv.String(elems) == search
}
return false
}
// InSliceInt64 元素是否存在于切片中
func InSliceInt64(slice []int64, key int64) bool {
if len(slice) == 0 {
return false
}
for i := 0; i < len(slice); i++ {
if slice[i] == key {
// InSlice 元素是否存在于切片中
func InSlice[K comparable](slice []K, key K) bool {
for _, v := range slice {
if v == key {
return true
}
}
return false
}
func InSliceInt(slice []int, key int) bool {
if len(slice) == 0 {
return false
}
for i := 0; i < len(slice); i++ {
if slice[i] == key {
return true
}
}
return false
}
func InSliceString(slice []string, key string) bool {
return gstr.InArray(slice, key)
}