From 27bb52737304eb713464a97534f608f737bfef96 Mon Sep 17 00:00:00 2001 From: yanghao05 Date: Mon, 30 Jan 2023 16:57:48 +0800 Subject: [PATCH] add some utils --- config.toml | 60 +++++++++++++++ providers/config/loader.go | 3 +- providers/config/section_database.go | 24 +++++- providers/config/section_http.go | 30 +++++++- providers/config/section_storage.go | 29 +++++++ utils/fs/dir.go | 40 ++++++++++ utils/fs/file.go | 65 ++++++++++++++++ utils/hash/bcrypt.go | 17 +++++ utils/hash/md5.go | 12 +++ utils/zip.go | 110 +++++++++++++++++++++++++++ 10 files changed, 384 insertions(+), 6 deletions(-) create mode 100644 providers/config/section_storage.go create mode 100644 utils/fs/dir.go create mode 100644 utils/fs/file.go create mode 100644 utils/hash/bcrypt.go create mode 100644 utils/hash/md5.go create mode 100644 utils/zip.go diff --git a/config.toml b/config.toml index 782ad35..27e658d 100644 --- a/config.toml +++ b/config.toml @@ -1,6 +1,33 @@ [App] Mode = "debug" +[Storage] +Driver = "local" + +[Storage.Local] +Path="./storage" + +[Storage.AwsS3] +Bucket = "bucket" +Region = "region" +Endpoint = "endpoint" +DisableSSL = false +SecretID = "" +SecretKey = "" +BaseURL = "" +Path = "" +S3ForcePathStyle = false + +[Storage.AliYunOSS] +Bucket = "bucket" +Region = "region" +Endpoint = "endpoint" +AccessKeyID = "" +AccessKeySecret = "" +BaseURL = "" +Path = "" + + [Http] Static = "./dist" Https = false @@ -8,6 +35,19 @@ HttpsCert = "" HttpKey = "" Port = 8088 +[Http.Captcha] +KeyLong= 6 +Width= 240 +Height= 80 +OpenCaptcha= 0 +OpenCaptchaTimeout= 3600 + +[Http.JWT] +SigningKey="f3a0ed18-3eea-4bc9-b440-d56c3bb77bd8" +ExpiresTime= "168h" # 7 days +BufferTime= "24h" +Issuer="AtomFramework" + [Http.Cors] # 跨域配置 # 需要配合 server/initialize/router.go#L32 使用 @@ -28,9 +68,22 @@ ExposeHeaders = "Content-Length, Access-Control-Allow-Origin, Access-Control-All AllowCredentials = true [Log] +Driver = "zap" Level = "debug" +[Log.Zap] +Prefix = "[github.com/flipped-aurora/gin-vue-admin/server]" +Format = "console" +Director = "log" +EncodeLevel= "LowercaseColorLevelEncoder" +StacktraceKey= "stacktrace" +MaxAge= 0 +ShowLine= true +LogInConsole= true + + [Database] +Driver = "mysql" [Database.MySQL] Host = "localhost" @@ -38,3 +91,10 @@ Port = 3306 Database = "demos" Username = "root" Password = "root" + +[Database.Redis] +Host = "localhost" +Port = 3306 +Database = 0 +Username = "" +Password = "" diff --git a/providers/config/loader.go b/providers/config/loader.go index fc4cde8..8a84757 100644 --- a/providers/config/loader.go +++ b/providers/config/loader.go @@ -10,13 +10,12 @@ import ( "github.com/spf13/viper" ) -var c *Config - type Config struct { App App Http Http Log Log Database Database + Storage Storage } func init() { diff --git a/providers/config/section_database.go b/providers/config/section_database.go index 018c245..1d54f66 100755 --- a/providers/config/section_database.go +++ b/providers/config/section_database.go @@ -1,10 +1,14 @@ package config -import "fmt" +import ( + "fmt" +) // Database database config type Database struct { + Driver string MySQL MySQL + Redis Redis PostgreSQL PostgreSQL } @@ -17,7 +21,7 @@ type MySQL struct { Password string } -// DSN is the mysql connection dsn +// DSN connection dsn func (m *MySQL) DSN() string { dsnTpl := "%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local" @@ -41,8 +45,22 @@ type PostgreSQL struct { TimeZone string } -// DSN is the mysql connection dsn +// DSN connection dsn func (m *PostgreSQL) DSN() string { dsnTpl := "host=%s user=%s password=%s dbname=%s port=%d sslmode=%s TimeZone=%s" return fmt.Sprintf(dsnTpl, m.Host, m.User, m.Password, m.Database, m.Port, m.SslMode, m.TimeZone) } + +type Redis struct { + Host string + Port uint + Database uint + Username string + Password string +} + +// DSN connection dsn +func (m *Redis) DSN() string { + dsnTpl := "%s:%d" + return fmt.Sprintf(dsnTpl, m.Host, m.Port) +} diff --git a/providers/config/section_http.go b/providers/config/section_http.go index 95b0c5b..f87a5e8 100644 --- a/providers/config/section_http.go +++ b/providers/config/section_http.go @@ -1,6 +1,10 @@ package config -import "fmt" +import ( + "fmt" + "log" + "time" +) type Http struct { Static string @@ -13,6 +17,30 @@ type Http struct { Mode string Whitelist []Whitelist } + JWT JWT +} + +type JWT struct { + SigningKey string // jwt签名 + ExpiresTime string // 过期时间 + BufferTime string // 缓冲时间 + Issuer string // 签发者 +} + +func (j JWT) ExpiresTimeDuration() time.Duration { + d, err := time.ParseDuration(j.ExpiresTime) + if err != nil { + log.Fatal(err) + } + return d +} + +func (j JWT) BufferTimeDuration() time.Duration { + d, err := time.ParseDuration(j.BufferTime) + if err != nil { + log.Fatal(err) + } + return d } type Whitelist struct { diff --git a/providers/config/section_storage.go b/providers/config/section_storage.go new file mode 100644 index 0000000..6c0b3c9 --- /dev/null +++ b/providers/config/section_storage.go @@ -0,0 +1,29 @@ +package config + +type Storage struct { + Driver string + AliYunOSS AliYunOSS + AwsS3 AwsS3 +} + +type AliYunOSS struct { + Bucket string + Region string + Endpoint string + AccessKeyID string + AccessKeySecret string + BaseURL string + Path string +} + +type AwsS3 struct { + Bucket string + Region string + Endpoint string + DisableSSL bool + SecretID string + SecretKey string + BaseURL string + Path string + S3ForcePathStyle bool +} diff --git a/utils/fs/dir.go b/utils/fs/dir.go new file mode 100644 index 0000000..6099aff --- /dev/null +++ b/utils/fs/dir.go @@ -0,0 +1,40 @@ +package fs + +import ( + "atom/providers/log" + "errors" + "os" + + "go.uber.org/zap" +) + +func PathExists(path string) (bool, error) { + fi, err := os.Stat(path) + if err == nil { + if fi.IsDir() { + return true, nil + } + return false, errors.New("存在同名文件") + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +} + +func CreateDir(dirs ...string) (err error) { + for _, v := range dirs { + exist, err := PathExists(v) + if err != nil { + return err + } + if !exist { + log.Debug("create directory" + v) + if err := os.MkdirAll(v, os.ModePerm); err != nil { + log.Error("create directory"+v, zap.Any(" error:", err)) + return err + } + } + } + return err +} diff --git a/utils/fs/file.go b/utils/fs/file.go new file mode 100644 index 0000000..11aa76d --- /dev/null +++ b/utils/fs/file.go @@ -0,0 +1,65 @@ +package fs + +import ( + "os" + "path/filepath" + "reflect" + "strings" +) + +func Move(src string, dst string) (err error) { + if dst == "" { + return nil + } + src, err = filepath.Abs(src) + if err != nil { + return err + } + dst, err = filepath.Abs(dst) + if err != nil { + return err + } + revoke := false + dir := filepath.Dir(dst) +Redirect: + _, err = os.Stat(dir) + if err != nil { + err = os.MkdirAll(dir, 0o755) + if err != nil { + return err + } + if !revoke { + revoke = true + goto Redirect + } + } + return os.Rename(src, dst) +} + +func Delete(filePath string) error { + return os.RemoveAll(filePath) +} + +func TrimSpace(target interface{}) { + t := reflect.TypeOf(target) + if t.Kind() != reflect.Ptr { + return + } + t = t.Elem() + v := reflect.ValueOf(target).Elem() + for i := 0; i < t.NumField(); i++ { + switch v.Field(i).Kind() { + case reflect.String: + v.Field(i).SetString(strings.TrimSpace(v.Field(i).String())) + } + } +} + +// FileExist 判断文件是否存在 +func FileExist(path string) bool { + fi, err := os.Lstat(path) + if err == nil { + return !fi.IsDir() + } + return !os.IsNotExist(err) +} diff --git a/utils/hash/bcrypt.go b/utils/hash/bcrypt.go new file mode 100644 index 0000000..b9ff3db --- /dev/null +++ b/utils/hash/bcrypt.go @@ -0,0 +1,17 @@ +package hash + +import ( + "golang.org/x/crypto/bcrypt" +) + +// BcryptHash 使用 bcrypt 对密码进行加密 +func BcryptHash(password string) string { + bytes, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + return string(bytes) +} + +// BcryptCheck 对比明文密码和数据库的哈希值 +func BcryptCheck(password, hash string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) + return err == nil +} diff --git a/utils/hash/md5.go b/utils/hash/md5.go new file mode 100644 index 0000000..60612bb --- /dev/null +++ b/utils/hash/md5.go @@ -0,0 +1,12 @@ +package hash + +import ( + "crypto/md5" + "encoding/hex" +) + +func MD5(str []byte, b ...byte) string { + h := md5.New() + h.Write(str) + return hex.EncodeToString(h.Sum(b)) +} diff --git a/utils/zip.go b/utils/zip.go new file mode 100644 index 0000000..e0075f4 --- /dev/null +++ b/utils/zip.go @@ -0,0 +1,110 @@ +package utils + +import ( + "archive/zip" + "fmt" + "io" + "os" + "path/filepath" + "strings" +) + +// 解压 +func Unzip(zipFile string, destDir string) ([]string, error) { + zipReader, err := zip.OpenReader(zipFile) + var paths []string + if err != nil { + return []string{}, err + } + defer zipReader.Close() + + for _, f := range zipReader.File { + if strings.Index(f.Name, "..") > -1 { + return []string{}, fmt.Errorf("%s 文件名不合法", f.Name) + } + fpath := filepath.Join(destDir, f.Name) + paths = append(paths, fpath) + if f.FileInfo().IsDir() { + os.MkdirAll(fpath, os.ModePerm) + } else { + if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { + return []string{}, err + } + + inFile, err := f.Open() + if err != nil { + return []string{}, err + } + defer inFile.Close() + + outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return []string{}, err + } + defer outFile.Close() + + _, err = io.Copy(outFile, inFile) + if err != nil { + return []string{}, err + } + } + } + return paths, nil +} + +func ZipFiles(filename string, files []string, oldForm, newForm string) error { + newZipFile, err := os.Create(filename) + if err != nil { + return err + } + defer func() { + _ = newZipFile.Close() + }() + + zipWriter := zip.NewWriter(newZipFile) + defer func() { + _ = zipWriter.Close() + }() + + // 把files添加到zip中 + for _, file := range files { + + err = func(file string) error { + zipFile, err := os.Open(file) + if err != nil { + return err + } + defer zipFile.Close() + // 获取file的基础信息 + info, err := zipFile.Stat() + if err != nil { + return err + } + + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + + // 使用上面的FileInforHeader() 就可以把文件保存的路径替换成我们自己想要的了,如下面 + header.Name = strings.Replace(file, oldForm, newForm, -1) + + // 优化压缩 + // 更多参考see http://golang.org/pkg/archive/zip/#pkg-constants + header.Method = zip.Deflate + + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return err + } + if _, err = io.Copy(writer, zipFile); err != nil { + return err + } + return nil + }(file) + if err != nil { + return err + } + } + return nil +}