mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-08-27 19:53:50 +08:00
v2.0
This commit is contained in:
0
server/utility/.gitkeep
Normal file
0
server/utility/.gitkeep
Normal file
45
server/utility/auth/auth.go
Normal file
45
server/utility/auth/auth.go
Normal file
@@ -0,0 +1,45 @@
|
||||
// Package auth
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"hotgo/utility/validate"
|
||||
)
|
||||
|
||||
// IsExceptAuth 是否是不需要验证权限的路由地址
|
||||
func IsExceptAuth(ctx context.Context, path string) bool {
|
||||
var pathList []string
|
||||
|
||||
except, _ := g.Cfg().Get(ctx, "router.admin.exceptAuth")
|
||||
pathList = except.Strings()
|
||||
|
||||
for i := 0; i < len(pathList); i++ {
|
||||
if validate.InSliceExistStr(pathList[i], path) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsExceptLogin 是否是不需要登录的路由地址
|
||||
func IsExceptLogin(ctx context.Context, path string) bool {
|
||||
var pathList []string
|
||||
|
||||
except, _ := g.Cfg().Get(ctx, "router.admin.exceptLogin")
|
||||
pathList = except.Strings()
|
||||
|
||||
for i := 0; i < len(pathList); i++ {
|
||||
if validate.InSliceExistStr(pathList[i], path) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
91
server/utility/charset/charset.go
Normal file
91
server/utility/charset/charset.go
Normal file
@@ -0,0 +1,91 @@
|
||||
// Package charset
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package charset
|
||||
|
||||
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 {
|
||||
alphabets = []byte(`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`)
|
||||
}
|
||||
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))]
|
||||
} else {
|
||||
bytes[i] = alphabets[b%byte(len(alphabets))]
|
||||
}
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
// GetStack 格式化错误的堆栈信息
|
||||
func GetStack(err error) []string {
|
||||
stackList := gstr.Split(gerror.Stack(err), "\n")
|
||||
for i := 0; i < len(stackList); i++ {
|
||||
stackList[i] = gstr.Replace(stackList[i], "\t", "--> ")
|
||||
}
|
||||
|
||||
return stackList
|
||||
}
|
||||
|
||||
// SubstrAfter 截取指定字符后的内容
|
||||
func SubstrAfter(str string, symbol string) string {
|
||||
comma := strings.Index(str, symbol)
|
||||
if comma < 0 { // -1 不存在
|
||||
return ""
|
||||
}
|
||||
pos := strings.Index(str[comma:], symbol)
|
||||
if comma+pos+1 > len(str) {
|
||||
return ""
|
||||
}
|
||||
return str[comma+pos+1:]
|
||||
}
|
46
server/utility/convert/convert.go
Normal file
46
server/utility/convert/convert.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// Package convert
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package convert
|
||||
|
||||
// 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 { //如果字典中找不到元素,ok=false,!ok为true,就往切片中append元素。
|
||||
temp[item] = struct{}{}
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InSliceInt 元素是否存在于切片中
|
||||
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
|
||||
}
|
24
server/utility/encrypt/encrypt.go
Normal file
24
server/utility/encrypt/encrypt.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// Package encrypt
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package encrypt
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
)
|
||||
|
||||
// Md5ToString 生成md5
|
||||
func Md5ToString(str string) string {
|
||||
return fmt.Sprintf("%x", md5.Sum([]byte(str)))
|
||||
}
|
||||
|
||||
func Hash32(b []byte) uint32 {
|
||||
h := fnv.New32a()
|
||||
h.Write(b)
|
||||
return h.Sum32()
|
||||
}
|
82
server/utility/excel/excel.go
Normal file
82
server/utility/excel/excel.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// Package excel
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package excel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/xuri/excelize/v2"
|
||||
"net/url"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func ExportByStruct(w *ghttp.ResponseWriter, titleList []string, data []interface{}, fileName string, sheetName string) error {
|
||||
|
||||
f := excelize.NewFile()
|
||||
f.SetSheetName("Sheet1", sheetName)
|
||||
header := make([]string, 0)
|
||||
for _, v := range titleList {
|
||||
header = append(header, v)
|
||||
}
|
||||
|
||||
rowStyleID, _ := f.NewStyle(`{"font":{"color":"#666666","size":13,"family":"arial"},"alignment":{"vertical":"center","horizontal":"center"}}`)
|
||||
_ = f.SetSheetRow(sheetName, "A1", &header)
|
||||
_ = f.SetRowHeight("Sheet1", 1, 30)
|
||||
length := len(titleList)
|
||||
headStyle := letter(length)
|
||||
var lastRow string
|
||||
var widthRow string
|
||||
for k, v := range headStyle {
|
||||
if k == length-1 {
|
||||
lastRow = fmt.Sprintf("%s1", v)
|
||||
widthRow = v
|
||||
}
|
||||
}
|
||||
if err := f.SetColWidth(sheetName, "A", widthRow, 30); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rowNum := 1
|
||||
for _, v := range data {
|
||||
t := reflect.TypeOf(v)
|
||||
value := reflect.ValueOf(v)
|
||||
row := make([]interface{}, 0)
|
||||
for l := 0; l < t.NumField(); l++ {
|
||||
val := value.Field(l).Interface()
|
||||
row = append(row, val)
|
||||
}
|
||||
rowNum++
|
||||
err := f.SetSheetRow(sheetName, "A"+gconv.String(rowNum), &row)
|
||||
_ = f.SetCellStyle(sheetName, fmt.Sprintf("A%d", rowNum), fmt.Sprintf("%s", lastRow), rowStyleID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
disposition := fmt.Sprintf("attachment; filename=%s.xlsx", url.QueryEscape(fileName))
|
||||
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", disposition)
|
||||
w.Header().Set("Content-Transfer-Encoding", "binary")
|
||||
w.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
|
||||
|
||||
err := f.Write(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Letter 遍历a-z
|
||||
func letter(length int) []string {
|
||||
var str []string
|
||||
for i := 0; i < length; i++ {
|
||||
str = append(str, string(rune('A'+i)))
|
||||
}
|
||||
return str
|
||||
}
|
113
server/utility/file/file.go
Normal file
113
server/utility/file/file.go
Normal file
@@ -0,0 +1,113 @@
|
||||
// Package file
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package file
|
||||
|
||||
import (
|
||||
"hotgo/utility/format"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const ( //文件大小单位
|
||||
_ = iota
|
||||
KB = 1 << (10 * iota)
|
||||
MB
|
||||
)
|
||||
|
||||
type fileInfo struct { //文件信息
|
||||
name string
|
||||
size int64
|
||||
}
|
||||
|
||||
func PathExists(path string) (bool, error) {
|
||||
info, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return info.IsDir(), nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
func FileExists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
// HasDir 判断文件夹是否存在
|
||||
func HasDir(path string) (bool, error) {
|
||||
_, _err := os.Stat(path)
|
||||
if _err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if os.IsNotExist(_err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, _err
|
||||
}
|
||||
|
||||
// CreateDir 创建文件夹
|
||||
func CreateDir(path string) (err error) {
|
||||
_exist, err := HasDir(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !_exist {
|
||||
err = os.Mkdir(path, os.ModePerm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// WalkDir 递归获取目录下文件的名称和大小
|
||||
func WalkDir(dirname string) (error, []fileInfo) {
|
||||
op, err := filepath.Abs(dirname) //获取目录的绝对路径
|
||||
if nil != err {
|
||||
return err, nil
|
||||
}
|
||||
files, err := ioutil.ReadDir(op) //获取目录下所有文件的信息,包括文件和文件夹
|
||||
if nil != err {
|
||||
return err, nil
|
||||
}
|
||||
|
||||
var fileInfos []fileInfo //返回值,存储读取的文件信息
|
||||
for _, f := range files {
|
||||
if f.IsDir() { // 如果是目录,那么就递归调用
|
||||
err, fs := WalkDir(op + `/` + f.Name()) //路径分隔符,linux 和 windows 不同
|
||||
if nil != err {
|
||||
return err, nil
|
||||
}
|
||||
fileInfos = append(fileInfos, fs...) //将 slice 添加到 slice
|
||||
} else {
|
||||
fi := fileInfo{op + `/` + f.Name(), f.Size()}
|
||||
fileInfos = append(fileInfos, fi) //slice 中添加成员
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fileInfos
|
||||
}
|
||||
|
||||
// DirSize 获取目录下所有文件大小
|
||||
func DirSize(dirname string) string {
|
||||
var (
|
||||
ss int64
|
||||
_, files = WalkDir(dirname)
|
||||
)
|
||||
for _, n := range files {
|
||||
ss += n.size
|
||||
}
|
||||
|
||||
return format.FileSize(ss)
|
||||
}
|
147
server/utility/file/mime.go
Normal file
147
server/utility/file/mime.go
Normal file
@@ -0,0 +1,147 @@
|
||||
// Package file
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 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/ioutil"
|
||||
"path"
|
||||
)
|
||||
|
||||
// 文件分类
|
||||
const (
|
||||
KindImg = "images" // 图片
|
||||
KindDoc = "document" // 文档
|
||||
KindAudio = "audio" // 音频
|
||||
KindVideo = "video" // 视频
|
||||
KindOther = "other" // 其他
|
||||
)
|
||||
|
||||
var (
|
||||
// 图片类型
|
||||
imgType = g.MapStrStr{
|
||||
"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.New("Invalid file type")
|
||||
}
|
||||
|
||||
// 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) (b []byte, err error) {
|
||||
open, err := file.Open()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
all, err := ioutil.ReadAll(open)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return all, nil
|
||||
}
|
55
server/utility/format/format.go
Normal file
55
server/utility/format/format.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// Package format
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package format
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/shopspring/decimal"
|
||||
"math"
|
||||
)
|
||||
|
||||
// RoundInt64 四舍五入
|
||||
func RoundInt64(x float64) int64 {
|
||||
return int64(math.Floor(x + 0/5))
|
||||
}
|
||||
|
||||
// Round2String 四舍五入保留小数,默认2位
|
||||
func Round2String(value float64, args ...interface{}) (v string) {
|
||||
var places int32 = 2
|
||||
if len(args) > 0 {
|
||||
places = args[0].(int32)
|
||||
}
|
||||
|
||||
return decimal.NewFromFloat(value).Round(places).String()
|
||||
}
|
||||
|
||||
// Round2Float64 四舍五入保留小数,默认2位
|
||||
func Round2Float64(value float64, args ...interface{}) (v float64) {
|
||||
var places int32 = 2
|
||||
if len(args) > 0 {
|
||||
places = args[0].(int32)
|
||||
}
|
||||
|
||||
return decimal.NewFromFloat(value).Round(places).InexactFloat64()
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
56
server/utility/signal/signal.go
Normal file
56
server/utility/signal/signal.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// Package signal
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 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)
|
||||
}
|
59
server/utility/tree/tree.go
Normal file
59
server/utility/tree/tree.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// Package tree
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package tree
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var pidName = "pid"
|
||||
|
||||
// GenTree 生成关系树 参考:https://blog.csdn.net/weixin_51546892/article/details/122876793
|
||||
func GenTree(menus []map[string]interface{}) (realMenu []map[string]interface{}) {
|
||||
if len(menus) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
minPid := GetMinPid(menus)
|
||||
formatMenu := make(map[int]map[string]interface{})
|
||||
for _, m := range menus {
|
||||
formatMenu[gconv.Int(m["id"])] = m
|
||||
if gconv.Int(m[pidName]) == minPid {
|
||||
realMenu = append(realMenu, m) // 需要返回的顶级菜单
|
||||
}
|
||||
}
|
||||
// 得益于都是地址操作,可以直接往父级塞
|
||||
for _, m := range formatMenu {
|
||||
if formatMenu[gconv.Int(m[pidName])] == nil {
|
||||
continue
|
||||
}
|
||||
if formatMenu[gconv.Int(m[pidName])]["children"] == nil {
|
||||
formatMenu[gconv.Int(m[pidName])]["children"] = []map[string]interface{}{}
|
||||
}
|
||||
|
||||
formatMenu[gconv.Int(m[pidName])]["children"] = append(formatMenu[gconv.Int(m[pidName])]["children"].([]map[string]interface{}), m)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetMinPid(menus []map[string]interface{}) int {
|
||||
index := -1
|
||||
for _, m := range menus {
|
||||
if index == -1 {
|
||||
index = gconv.Int(m[pidName])
|
||||
continue
|
||||
}
|
||||
if gconv.Int(m[pidName]) < index {
|
||||
index = gconv.Int(m[pidName])
|
||||
}
|
||||
}
|
||||
|
||||
if index == -1 {
|
||||
return 0
|
||||
}
|
||||
return index
|
||||
}
|
125
server/utility/useragent/useragent.go
Normal file
125
server/utility/useragent/useragent.go
Normal file
@@ -0,0 +1,125 @@
|
||||
// Package useragent
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package useragent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetOs 获取OS名称
|
||||
func GetOs(userAgent string) string {
|
||||
osName := "Unknown"
|
||||
if userAgent == "" {
|
||||
return osName
|
||||
}
|
||||
|
||||
strRe, _ := regexp.Compile("(?i:\\((.*?)\\))")
|
||||
userAgent = strRe.FindString(userAgent)
|
||||
|
||||
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))
|
||||
}
|
||||
regexpStr := fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|"))
|
||||
nameRe, _ := regexp.Compile(regexpStr)
|
||||
|
||||
names := nameRe.FindAllString(userAgent, -1)
|
||||
name := ""
|
||||
for _, s := range names {
|
||||
if name == "" {
|
||||
name = strings.TrimSpace(s)
|
||||
} else if len(name) > 0 {
|
||||
if strings.Contains(name, "Macintosh") && s != "" {
|
||||
name = strings.TrimSpace(s)
|
||||
} else if strings.Contains(name, s) {
|
||||
name = strings.TrimSpace(s)
|
||||
} else if !strings.Contains(s, name) {
|
||||
if strings.Contains(name, "iPhone") ||
|
||||
strings.Contains(name, "iPad") {
|
||||
s = strings.Trim(s, "Mac OS X")
|
||||
}
|
||||
|
||||
if s != "" {
|
||||
name += " " + strings.TrimSpace(s)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if strings.Contains(name, "Windows NT") {
|
||||
name = getWinOsNameWithWinNT(name)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if name != "" {
|
||||
osName = name
|
||||
}
|
||||
|
||||
return osName
|
||||
}
|
||||
|
||||
// GetBrowser 获取浏览器名称
|
||||
func GetBrowser(userAgent string) string {
|
||||
deviceName := "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:"
|
||||
|
||||
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
|
||||
for _, name := range names {
|
||||
replaceRe, _ := regexp.Compile("(?i:[\\s?\\/0-9.]+)")
|
||||
n := replaceRe.ReplaceAllString(name, "")
|
||||
l := strings.Index(levelNames, fmt.Sprintf(":%s:", n))
|
||||
if level == 0 {
|
||||
deviceName = strings.TrimSpace(name)
|
||||
}
|
||||
|
||||
if l >= 0 && (level == 0 || level > l) {
|
||||
level = l
|
||||
deviceName = strings.TrimSpace(name)
|
||||
}
|
||||
}
|
||||
|
||||
return deviceName
|
||||
}
|
||||
|
||||
func getWinOsNameWithWinNT(sName string) string {
|
||||
osName := "Windows"
|
||||
types := map[string]string{
|
||||
"Windows NT 10": "Windows 10",
|
||||
"Windows NT 6.3": "Windows 8",
|
||||
"Windows NT 6.2": "Windows 8",
|
||||
"Windows NT 6.1": "Windows 7",
|
||||
"Windows NT 6.0": "Windows Vista/Server 2008",
|
||||
"Windows NT 5.2": "Windows Server 2003",
|
||||
"Windows NT 5.1": "Windows XP",
|
||||
"Windows NT 5": "Windows 2000",
|
||||
"Windows NT 4": "Windows NT4",
|
||||
}
|
||||
|
||||
for keyWord, name := range types {
|
||||
if strings.Contains(sName, keyWord) {
|
||||
osName = name
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return osName
|
||||
}
|
78
server/utility/validate/validate.go
Normal file
78
server/utility/validate/validate.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// Package validate
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package validate
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"net"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IsIp 是否为ipv4
|
||||
func IsIp(ip string) bool {
|
||||
if net.ParseIP(ip) != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsEmail 是否为邮箱地址
|
||||
func IsEmail(email string) bool {
|
||||
//pattern := `\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*` //匹配电子邮箱
|
||||
pattern := `^[0-9a-z][_.0-9a-z-]{0,31}@([0-9a-z][0-9a-z-]{0,30}[0-9a-z].){1,4}[a-z]{2,4}$`
|
||||
|
||||
reg := regexp.MustCompile(pattern)
|
||||
return reg.MatchString(email)
|
||||
}
|
||||
|
||||
// InSameDay 是否为同一天
|
||||
func InSameDay(t1, t2 int64) bool {
|
||||
y1, m1, d1 := time.Unix(t1, 0).Date()
|
||||
y2, m2, d2 := time.Unix(t2, 0).Date()
|
||||
|
||||
return y1 == y2 && m1 == m2 && d1 == d2
|
||||
}
|
||||
|
||||
// InSameMinute 是否为同一分钟
|
||||
func InSameMinute(t1, t2 int64) bool {
|
||||
d1 := time.Unix(t1, 0).Format("2006-01-02 15:04")
|
||||
d2 := time.Unix(t2, 0).Format("2006-01-02 15:04")
|
||||
|
||||
return d1 == d2
|
||||
}
|
||||
|
||||
// InSliceExistStr 判断字符或切片字符是否存在指定字符
|
||||
func InSliceExistStr(elems interface{}, search string) bool {
|
||||
switch elems.(type) {
|
||||
case []string:
|
||||
elem := gconv.Strings(elems)
|
||||
for i := 0; i < len(elem); i++ {
|
||||
if gconv.String(elem[i]) == search {
|
||||
return true
|
||||
}
|
||||
}
|
||||
default:
|
||||
return gconv.String(elems) == search
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsURL 是否是url地址
|
||||
func IsURL(u string) bool {
|
||||
_, err := url.ParseRequestURI(u)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
URL, err := url.Parse(u)
|
||||
if err != nil || URL.Scheme == "" || URL.Host == "" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
Reference in New Issue
Block a user