init
This commit is contained in:
commit
754e1ae43c
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
.idea
|
||||
.vscode
|
||||
*.log
|
||||
*.exe
|
||||
/go.sum
|
||||
yaml
|
||||
.DS_Store
|
75
go.mod
Normal file
75
go.mod
Normal file
@ -0,0 +1,75 @@
|
||||
module code.zhecent.com/gopkg/light-core
|
||||
|
||||
go 1.23.1
|
||||
|
||||
require (
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.63.68
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/go-pay/gopay v1.5.106
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/redis/go-redis/v9 v9.7.0
|
||||
github.com/shopspring/decimal v1.4.0
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
golang.org/x/crypto v0.31.0
|
||||
google.golang.org/protobuf v1.36.0
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/gorm v1.25.12
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.11.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-pay/crypto v0.0.1 // indirect
|
||||
github.com/go-pay/errgroup v0.0.2 // indirect
|
||||
github.com/go-pay/util v0.0.4 // indirect
|
||||
github.com/go-pay/xlog v0.0.3 // indirect
|
||||
github.com/go-pay/xtime v0.0.2 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
85
impl/int64Array.go
Normal file
85
impl/int64Array.go
Normal file
@ -0,0 +1,85 @@
|
||||
package impl
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type Int64Array []int64
|
||||
|
||||
func (v *Int64Array) Scan(value interface{}) error {
|
||||
//判断类型
|
||||
switch data := value.(type) {
|
||||
case []byte:
|
||||
return json.Unmarshal(data, v)
|
||||
case string:
|
||||
return json.Unmarshal([]byte(data), v)
|
||||
case nil:
|
||||
return nil
|
||||
}
|
||||
return json.Unmarshal(value.([]byte), v)
|
||||
}
|
||||
|
||||
func (v Int64Array) Value() (driver.Value, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
func (v Int64Array) RemoveDuplicates() Int64Array {
|
||||
newArr := make([]int64, 0)
|
||||
for i := 0; i < len(v); i++ {
|
||||
repeat := false
|
||||
for j := i + 1; j < len(v); j++ {
|
||||
if v[i] == v[j] {
|
||||
repeat = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !repeat {
|
||||
newArr = append(newArr, v[i])
|
||||
}
|
||||
}
|
||||
return newArr
|
||||
}
|
||||
func (v Int64Array) RemoveEmpty() Int64Array {
|
||||
return v.RemoveValue(0)
|
||||
}
|
||||
|
||||
func (v Int64Array) RemoveValue(value int64) Int64Array {
|
||||
newArr := make([]int64, 0)
|
||||
for i := 0; i < len(v); i++ {
|
||||
if v[i] != value {
|
||||
newArr = append(newArr, v[i])
|
||||
}
|
||||
}
|
||||
return newArr
|
||||
}
|
||||
|
||||
func (v Int64Array) Contains(id int64) bool {
|
||||
for _, i := range v {
|
||||
if i == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (v Int64Array) Eq(arr []int64) bool {
|
||||
if len(v) != len(arr) {
|
||||
return false
|
||||
}
|
||||
for _, i := range arr {
|
||||
//只要有一个不包含就是不一样的
|
||||
if v.Contains(i) == false {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (v Int64Array) ToIntSlice() []int {
|
||||
out := make([]int, 0)
|
||||
for _, i := range v {
|
||||
out = append(out, int(i))
|
||||
}
|
||||
return out
|
||||
}
|
86
impl/intArray.go
Normal file
86
impl/intArray.go
Normal file
@ -0,0 +1,86 @@
|
||||
package impl
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type IntArray []int
|
||||
|
||||
func (v *IntArray) Scan(value interface{}) error {
|
||||
//判断类型
|
||||
switch data := value.(type) {
|
||||
case []byte:
|
||||
return json.Unmarshal(data, v)
|
||||
case string:
|
||||
return json.Unmarshal([]byte(data), v)
|
||||
case nil:
|
||||
return nil
|
||||
}
|
||||
return json.Unmarshal(value.([]byte), v)
|
||||
}
|
||||
|
||||
func (v IntArray) Value() (driver.Value, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
func (v IntArray) RemoveDuplicates() IntArray {
|
||||
newArr := make([]int, 0)
|
||||
for i := 0; i < len(v); i++ {
|
||||
repeat := false
|
||||
for j := i + 1; j < len(v); j++ {
|
||||
if v[i] == v[j] {
|
||||
repeat = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !repeat {
|
||||
newArr = append(newArr, v[i])
|
||||
}
|
||||
}
|
||||
return newArr
|
||||
}
|
||||
|
||||
func (v IntArray) RemoveEmpty() IntArray {
|
||||
return v.RemoveValue(0)
|
||||
}
|
||||
|
||||
func (v IntArray) RemoveValue(value int) IntArray {
|
||||
newArr := make([]int, 0)
|
||||
for i := 0; i < len(v); i++ {
|
||||
if v[i] != value {
|
||||
newArr = append(newArr, v[i])
|
||||
}
|
||||
}
|
||||
return newArr
|
||||
}
|
||||
|
||||
func (v IntArray) Contains(id int) bool {
|
||||
for _, i := range v {
|
||||
if i == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (v IntArray) Eq(arr []int) bool {
|
||||
if len(v) != len(arr) {
|
||||
return false
|
||||
}
|
||||
for _, i := range arr {
|
||||
//只要有一个不包含就是不一样的
|
||||
if v.Contains(i) == false {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (v IntArray) ToIntSlice() []int {
|
||||
out := make([]int, 0)
|
||||
for _, i := range v {
|
||||
out = append(out, int(i))
|
||||
}
|
||||
return out
|
||||
}
|
87
impl/stringArray.go
Normal file
87
impl/stringArray.go
Normal file
@ -0,0 +1,87 @@
|
||||
package impl
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type StringArray []string
|
||||
|
||||
func (v *StringArray) Scan(value interface{}) error {
|
||||
//判断类型
|
||||
switch data := value.(type) {
|
||||
case []byte:
|
||||
return json.Unmarshal(data, v)
|
||||
case string:
|
||||
return json.Unmarshal([]byte(data), v)
|
||||
case nil:
|
||||
return nil
|
||||
}
|
||||
return json.Unmarshal(value.([]byte), v)
|
||||
}
|
||||
|
||||
func (v StringArray) Value() (driver.Value, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
func (v StringArray) RemoveDuplicates() StringArray {
|
||||
newArr := make([]string, 0)
|
||||
for i := 0; i < len(v); i++ {
|
||||
repeat := false
|
||||
for j := i + 1; j < len(v); j++ {
|
||||
if v[i] == v[j] {
|
||||
repeat = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !repeat {
|
||||
newArr = append(newArr, v[i])
|
||||
}
|
||||
}
|
||||
return newArr
|
||||
}
|
||||
|
||||
func (v StringArray) RemoveEmpty() StringArray {
|
||||
return v.RemoveValue("")
|
||||
}
|
||||
|
||||
func (v StringArray) RemoveValue(value string) StringArray {
|
||||
newArr := make([]string, 0)
|
||||
for i := 0; i < len(v); i++ {
|
||||
if !strings.EqualFold(v[i], value) {
|
||||
newArr = append(newArr, v[i])
|
||||
}
|
||||
}
|
||||
return newArr
|
||||
}
|
||||
|
||||
func (v StringArray) Contains(str string) bool {
|
||||
for _, i := range v {
|
||||
if i == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (v StringArray) Eq(strArr []string) bool {
|
||||
if len(v) != len(strArr) {
|
||||
return false
|
||||
}
|
||||
for _, i := range strArr {
|
||||
//只要有一个不包含就是不一样的
|
||||
if v.Contains(i) == false {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (v StringArray) ToStringSlice() []string {
|
||||
out := make([]string, 0)
|
||||
for _, i := range v {
|
||||
out = append(out, i)
|
||||
}
|
||||
return out
|
||||
}
|
52
lightCore/Config.go
Normal file
52
lightCore/Config.go
Normal file
@ -0,0 +1,52 @@
|
||||
package lightCore
|
||||
|
||||
var ConfigValue = &Config{}
|
||||
|
||||
type Config struct {
|
||||
App AppConfigModel `mapstructure:"app" yaml:"app"`
|
||||
Server ServerConfigModel `mapstructure:"server" yaml:"server"`
|
||||
Database DatabaseConfigModel `mapstructure:"database" yaml:"database"`
|
||||
Redis RedisConfigModel `mapstructure:"redis" yaml:"redis"`
|
||||
Admin AdminConfigModel `mapstructure:"admin" yaml:"admin"`
|
||||
}
|
||||
|
||||
func (t *Config) IsRelease() bool {
|
||||
return t.Server.RunMode == "release"
|
||||
}
|
||||
|
||||
type AppConfigModel struct {
|
||||
JwtSecret string `mapstructure:"jwt_secret" yaml:"jwt_secret"`
|
||||
AliOssSign string `mapstructure:"ali_oss_sign" yaml:"ali_oss_sign"`
|
||||
}
|
||||
|
||||
type AdminConfigModel struct {
|
||||
JwtSecret string `mapstructure:"jwt_secret" yaml:"jwt_secret"`
|
||||
JwtExpires int `mapstructure:"jwt_expires" yaml:"jwt_expires"`
|
||||
ApiPath string `mapstructure:"api_path" yaml:"api_path"`
|
||||
}
|
||||
|
||||
type ServerConfigModel struct {
|
||||
RunMode string `mapstructure:"run_mode" yaml:"run_mode"`
|
||||
HttpPort int `mapstructure:"http_port" yaml:"http_port"`
|
||||
ReadTimeout int `mapstructure:"read_timeout" yaml:"read_timeout"`
|
||||
WriteTimeout int `mapstructure:"write_timeout" yaml:"write_timeout"`
|
||||
}
|
||||
|
||||
type DatabaseConfigModel struct {
|
||||
Type string `mapstructure:"type" yaml:"type"`
|
||||
User string `mapstructure:"user" yaml:"user"`
|
||||
Password string `mapstructure:"password" yaml:"password"`
|
||||
Host string `mapstructure:"host" yaml:"host"`
|
||||
Name string `mapstructure:"name" yaml:"name"`
|
||||
Charset string `mapstructure:"charset" yaml:"charset"`
|
||||
TablePrefix string `mapstructure:"table_prefix" yaml:"table_prefix"`
|
||||
LogLevel string `mapstructure:"log_level" yaml:"log_level"`
|
||||
}
|
||||
|
||||
type RedisConfigModel struct {
|
||||
Host string `mapstructure:"host" yaml:"host"`
|
||||
Password string `mapstructure:"password" yaml:"password"`
|
||||
MaxIdle string `mapstructure:"max_idle" yaml:"max_idle"`
|
||||
MaxActive string `mapstructure:"max_active" yaml:"max_active"`
|
||||
IdleTimeout string `mapstructure:"idle_timeout" yaml:"idle_timeout"`
|
||||
}
|
21
lightCore/Db.go
Normal file
21
lightCore/Db.go
Normal file
@ -0,0 +1,21 @@
|
||||
package lightCore
|
||||
|
||||
import (
|
||||
"code.zhecent.com/gopkg/light-core/pkg/myGorm"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var DBEngine *gorm.DB
|
||||
|
||||
func InitDB() {
|
||||
orm := myGorm.NewSimpleORM(
|
||||
ConfigValue.Database.User,
|
||||
ConfigValue.Database.Password,
|
||||
ConfigValue.Database.Host,
|
||||
ConfigValue.Database.Name,
|
||||
ConfigValue.Database.Charset,
|
||||
ConfigValue.Server.RunMode,
|
||||
)
|
||||
orm.SetLoggerLevel(ConfigValue.Database.LogLevel)
|
||||
DBEngine = orm.ConnectMysql()
|
||||
}
|
7
lightCore/Fairing.go
Normal file
7
lightCore/Fairing.go
Normal file
@ -0,0 +1,7 @@
|
||||
package lightCore
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
type Fairing interface {
|
||||
OnRequest(c *gin.Context) error
|
||||
}
|
11
lightCore/GromAdapter.go
Normal file
11
lightCore/GromAdapter.go
Normal file
@ -0,0 +1,11 @@
|
||||
package lightCore
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type GormAdapter struct {
|
||||
*gorm.DB
|
||||
}
|
||||
|
||||
func NewGormAdapter(db *gorm.DB) *GormAdapter {
|
||||
return &GormAdapter{DB: db}
|
||||
}
|
24
lightCore/IClass.go
Normal file
24
lightCore/IClass.go
Normal file
@ -0,0 +1,24 @@
|
||||
package lightCore
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
type IClass interface {
|
||||
Build(core *LightCore)
|
||||
}
|
||||
|
||||
type ClassMounts struct {
|
||||
handles []IClass
|
||||
errorHandler []gin.HandlerFunc
|
||||
}
|
||||
|
||||
func NewClassMounts(handles []IClass, errorHandler []gin.HandlerFunc) *ClassMounts {
|
||||
return &ClassMounts{handles: handles, errorHandler: errorHandler}
|
||||
}
|
||||
|
||||
func (t *ClassMounts) Handles() []IClass {
|
||||
return t.handles
|
||||
}
|
||||
|
||||
func (t *ClassMounts) ErrorHandler() []gin.HandlerFunc {
|
||||
return t.errorHandler
|
||||
}
|
10
lightCore/IRouters.go
Normal file
10
lightCore/IRouters.go
Normal file
@ -0,0 +1,10 @@
|
||||
package lightCore
|
||||
|
||||
type Routers struct {
|
||||
groupPath string
|
||||
cs *ClassMounts
|
||||
}
|
||||
|
||||
func NewRouters(groupPath string, cs *ClassMounts) *Routers {
|
||||
return &Routers{groupPath: groupPath, cs: cs}
|
||||
}
|
135
lightCore/LightCore.go
Normal file
135
lightCore/LightCore.go
Normal file
@ -0,0 +1,135 @@
|
||||
package lightCore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type LightCore struct {
|
||||
gin *gin.Engine
|
||||
g *gin.RouterGroup
|
||||
props []interface{}
|
||||
}
|
||||
|
||||
func StartEngine() *LightCore {
|
||||
gin.SetMode(ConfigValue.Server.RunMode)
|
||||
g := &LightCore{gin: gin.New(), props: make([]interface{}, 0)}
|
||||
g.gin.Use(gin.Logger(), gin.Recovery())
|
||||
return g
|
||||
}
|
||||
func (t *LightCore) GetGin() *gin.Engine {
|
||||
return t.gin
|
||||
}
|
||||
|
||||
func (t *LightCore) Launch() {
|
||||
err := t.gin.Run(fmt.Sprintf(":%d", ConfigValue.Server.HttpPort))
|
||||
if err != nil {
|
||||
panic("Gin Launch Error")
|
||||
}
|
||||
|
||||
//server := &http.Server{
|
||||
// Addr: fmt.Sprintf(":%d", addr),
|
||||
// Handler: t,
|
||||
// MaxHeaderBytes: 1 << 20,
|
||||
//}
|
||||
//err := server.ListenAndServe()
|
||||
//if err != nil {
|
||||
// panic("Gin Launch Error")
|
||||
//}
|
||||
}
|
||||
|
||||
func (t *LightCore) Attach(f Fairing) *LightCore {
|
||||
t.gin.Use(func(context *gin.Context) {
|
||||
err := f.OnRequest(context)
|
||||
if err != nil {
|
||||
context.AbortWithStatusJSON(http.StatusOK, gin.H{"error": "onRequest"})
|
||||
} else {
|
||||
context.Next()
|
||||
}
|
||||
})
|
||||
return t
|
||||
}
|
||||
func (t *LightCore) LoadHtml(path string) *LightCore {
|
||||
t.gin.LoadHTMLGlob(path)
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *LightCore) StaticFS(path string, fs http.FileSystem) *LightCore {
|
||||
t.gin.StaticFS(path, fs)
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *LightCore) Beans(beans ...interface{}) *LightCore {
|
||||
t.props = append(t.props, beans...)
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *LightCore) Handle(httpMethod, relativePath string, handler interface{}, mids ...gin.HandlerFunc) *LightCore {
|
||||
if h := Convert(handler); h != nil {
|
||||
if len(mids) > 0 {
|
||||
mids = append(mids, h)
|
||||
t.g.Handle(httpMethod, relativePath, mids...)
|
||||
} else {
|
||||
t.g.Handle(httpMethod, relativePath, h)
|
||||
}
|
||||
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *LightCore) MountRaw(f func(s *gin.Engine)) *LightCore {
|
||||
f(t.GetGin())
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *LightCore) Mount(group string, errorHandlerFunc []gin.HandlerFunc, classes ...IClass) *LightCore {
|
||||
t.g = t.gin.Group(group)
|
||||
if len(errorHandlerFunc) > 0 {
|
||||
t.g.Use(errorHandlerFunc...)
|
||||
}
|
||||
for _, class := range classes {
|
||||
class.Build(t)
|
||||
//其实就是找到相同类型的数据就赋值上去
|
||||
t.setProp(class)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *LightCore) Mounts(routers []*Routers) *LightCore {
|
||||
for _, router := range routers {
|
||||
t.Mount(router.groupPath, router.cs.errorHandler, router.cs.Handles()...)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *LightCore) SetNoRoute(f func(context *gin.Context)) *LightCore {
|
||||
t.gin.NoRoute(f)
|
||||
return t
|
||||
}
|
||||
|
||||
// 查找对应名字的属性
|
||||
func (t *LightCore) getProp(tp reflect.Type) interface{} {
|
||||
for _, p := range t.props {
|
||||
if tp == reflect.TypeOf(p) {
|
||||
return p
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *LightCore) setProp(class IClass) {
|
||||
vClass := reflect.ValueOf(class).Elem()
|
||||
for i := 0; i < vClass.NumField(); i++ {
|
||||
f := vClass.Field(i)
|
||||
if !f.IsNil() || f.Kind() != reflect.Ptr {
|
||||
//已经赋值了,不需要初始化了。
|
||||
continue
|
||||
}
|
||||
if p := t.getProp(f.Type()); p != nil {
|
||||
f.Set(reflect.New(f.Type().Elem()))
|
||||
f.Elem().Set(reflect.ValueOf(p).Elem())
|
||||
}
|
||||
}
|
||||
}
|
5
lightCore/Model.go
Normal file
5
lightCore/Model.go
Normal file
@ -0,0 +1,5 @@
|
||||
package lightCore
|
||||
|
||||
type Model interface {
|
||||
IsLightModel()
|
||||
}
|
162
lightCore/Responder.go
Normal file
162
lightCore/Responder.go
Normal file
@ -0,0 +1,162 @@
|
||||
package lightCore
|
||||
|
||||
import (
|
||||
"code.zhecent.com/gopkg/light-core/pkg/myAes"
|
||||
"github.com/gin-gonic/gin"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"net/http"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var RespondList []Responder
|
||||
|
||||
func init() {
|
||||
RespondList = []Responder{
|
||||
new(EmptyResponder),
|
||||
new(StringResponder),
|
||||
new(ModelResponder),
|
||||
new(SuccessResponder),
|
||||
new(JsonErrorResponder),
|
||||
new(ViewResponder),
|
||||
new(ProtobufResponder),
|
||||
new(ProtobufAesResponder),
|
||||
new(RedirectResponder),
|
||||
}
|
||||
}
|
||||
|
||||
type Responder interface {
|
||||
RespondTo() gin.HandlerFunc
|
||||
}
|
||||
|
||||
func Convert(handler interface{}) gin.HandlerFunc {
|
||||
hRef := reflect.ValueOf(handler)
|
||||
for _, r := range RespondList {
|
||||
rRef := reflect.ValueOf(r).Elem()
|
||||
if hRef.Type().ConvertibleTo(rRef.Type()) {
|
||||
rRef.Set(hRef)
|
||||
return rRef.Interface().(Responder).RespondTo()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type StringResponder func(*gin.Context) string
|
||||
|
||||
func (t StringResponder) RespondTo() gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
context.String(http.StatusOK, t(context))
|
||||
}
|
||||
}
|
||||
|
||||
type ModelResponder func(*gin.Context) Model
|
||||
|
||||
func (t ModelResponder) RespondTo() gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
context.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"msg": "",
|
||||
"data": t(context),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type JsonSuccess string
|
||||
|
||||
type SuccessResponder func(*gin.Context) JsonSuccess
|
||||
|
||||
func (t SuccessResponder) RespondTo() gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
context.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"msg": string(t(context)),
|
||||
"data": []int{},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type JsonError error
|
||||
|
||||
type JsonErrorResponder func(*gin.Context) JsonError
|
||||
|
||||
func (t JsonErrorResponder) RespondTo() gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
err := t(context)
|
||||
if err != nil {
|
||||
context.JSON(http.StatusOK, gin.H{
|
||||
"code": 400,
|
||||
"msg": err.Error(),
|
||||
"data": []int{},
|
||||
})
|
||||
} else {
|
||||
context.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": []int{},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type EmptyResponder func(*gin.Context)
|
||||
|
||||
func (t EmptyResponder) RespondTo() gin.HandlerFunc {
|
||||
//func(c *gin.Context)其实就是reply
|
||||
//t,提示就是方法本身,其实就是reply
|
||||
return func(context *gin.Context) {
|
||||
//context是gin给的,全新的,没有任何资料的
|
||||
//t(context)其实就是运行reply
|
||||
t(context)
|
||||
//fmt.Println("========================")
|
||||
//fmt.Println(context.Writer)
|
||||
//fmt.Println("========================")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type View string
|
||||
|
||||
type ViewResponder func(*gin.Context) View
|
||||
|
||||
func (t ViewResponder) RespondTo() gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
context.HTML(http.StatusOK, string(t(context))+".html", context.Keys)
|
||||
}
|
||||
}
|
||||
|
||||
type Protobuf proto.Message
|
||||
type ProtobufResponder func(*gin.Context) Protobuf
|
||||
|
||||
func (t ProtobufResponder) RespondTo() gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
context.ProtoBuf(http.StatusOK, t(context))
|
||||
}
|
||||
}
|
||||
|
||||
type ProtobufAes proto.Message
|
||||
type ProtobufAesResponder func(*gin.Context) ProtobufAes
|
||||
|
||||
func (t ProtobufAesResponder) RespondTo() gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
str, err := proto.Marshal(t(context))
|
||||
if err != nil {
|
||||
context.String(http.StatusBadRequest, err.Error())
|
||||
} else {
|
||||
decrypt, err := myAes.AesTool(context.GetString("LightAppKey"), context.GetString("LightAppIv")).Encrypt(string(str))
|
||||
if err != nil {
|
||||
context.String(http.StatusBadRequest, err.Error())
|
||||
} else {
|
||||
context.String(http.StatusOK, string(decrypt))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Redirect string
|
||||
|
||||
type RedirectResponder func(*gin.Context) Redirect
|
||||
|
||||
func (t RedirectResponder) RespondTo() gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
context.Redirect(http.StatusFound, string(t(context)))
|
||||
}
|
||||
}
|
33
lightCore/Start.go
Normal file
33
lightCore/Start.go
Normal file
@ -0,0 +1,33 @@
|
||||
package lightCore
|
||||
|
||||
import "code.zhecent.com/gopkg/light-core/pkg/myViper"
|
||||
|
||||
type Start struct {
|
||||
config *Config
|
||||
}
|
||||
|
||||
func NewByConfig(config *Config) *Start {
|
||||
return &Start{config: config}
|
||||
}
|
||||
|
||||
func NewByYAML(fileName string, path string) *Start {
|
||||
c := &Config{}
|
||||
myViper.NewSimpleViper(c, "yaml", fileName, path).Apply()
|
||||
return &Start{config: c}
|
||||
}
|
||||
|
||||
func (t *Start) Start() {
|
||||
//校验配置
|
||||
if t.config.App.JwtSecret == "" {
|
||||
panic("App JwtSecret Empty")
|
||||
}
|
||||
|
||||
if t.config.Server.RunMode == "" || t.config.Server.HttpPort == 0 {
|
||||
panic("Server Config Error")
|
||||
}
|
||||
|
||||
ConfigValue = t.config
|
||||
|
||||
//初始化数据库
|
||||
InitDB()
|
||||
}
|
76
lightCore/Task.go
Normal file
76
lightCore/Task.go
Normal file
@ -0,0 +1,76 @@
|
||||
package lightCore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type TaskFunc func()
|
||||
|
||||
var taskList chan *TaskExecutor //任务列表
|
||||
var once sync.Once
|
||||
|
||||
func getTaskList() chan *TaskExecutor {
|
||||
once.Do(func() {
|
||||
taskList = make(chan *TaskExecutor, 0)
|
||||
})
|
||||
return taskList
|
||||
}
|
||||
|
||||
func init() {
|
||||
chList := getTaskList() //得到任务列表
|
||||
go func() {
|
||||
for t := range chList {
|
||||
doTask(t)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func doTask(t *TaskExecutor) {
|
||||
go func() {
|
||||
defer func() {
|
||||
if t.callback != nil {
|
||||
t.callback()
|
||||
}
|
||||
}()
|
||||
t.Exec()
|
||||
}()
|
||||
}
|
||||
|
||||
type TaskExecutor struct {
|
||||
f TaskFunc
|
||||
callback func()
|
||||
}
|
||||
|
||||
func NewTaskExecutor(f TaskFunc, callback func()) *TaskExecutor {
|
||||
return &TaskExecutor{f: f, callback: callback}
|
||||
}
|
||||
|
||||
func (t *TaskExecutor) Exec() {
|
||||
t.f()
|
||||
}
|
||||
|
||||
func Task(f TaskFunc, callBack func()) {
|
||||
if f == nil {
|
||||
return
|
||||
}
|
||||
newF := func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
if err, ok := e.(string); ok {
|
||||
fmt.Println("===================================")
|
||||
fmt.Println(fmt.Sprintf("协程运行错误:%s", err))
|
||||
fmt.Println("===================================")
|
||||
} else {
|
||||
fmt.Println("===================================")
|
||||
fmt.Println(fmt.Sprintf("协程运行错误:%s", "未知"))
|
||||
fmt.Println("===================================")
|
||||
}
|
||||
}
|
||||
}()
|
||||
f()
|
||||
}
|
||||
go func() {
|
||||
getTaskList() <- NewTaskExecutor(newF, callBack) //添加任务队列
|
||||
}()
|
||||
}
|
83
pkg/myAes/aes.go
Normal file
83
pkg/myAes/aes.go
Normal file
@ -0,0 +1,83 @@
|
||||
package myAes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
basicAES "crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
type Aes struct {
|
||||
securityKey []byte
|
||||
iv []byte
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*/
|
||||
func AesTool(securityKey string, iv string) *Aes {
|
||||
return &Aes{[]byte(securityKey), []byte(iv)}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
* @param string $plainText 明文
|
||||
* @return bool|string
|
||||
*/
|
||||
func (a Aes) Encrypt(plainText string) (string, error) {
|
||||
block, err := basicAES.NewCipher(a.securityKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
plainTextByte := []byte(plainText)
|
||||
blockSize := block.BlockSize()
|
||||
plainTextByte = addPKCS7Padding(plainTextByte, blockSize)
|
||||
cipherText := make([]byte, len(plainTextByte))
|
||||
mode := cipher.NewCBCEncrypter(block, a.iv)
|
||||
mode.CryptBlocks(cipherText, plainTextByte)
|
||||
return base64.StdEncoding.EncodeToString(cipherText), nil
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密
|
||||
* @param string $cipherText 密文
|
||||
* @return bool|string
|
||||
*/
|
||||
func (a Aes) Decrypt(cipherText string) ([]byte, error) {
|
||||
block, err := basicAES.NewCipher(a.securityKey)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
cipherDecodeText, decodeErr := base64.StdEncoding.DecodeString(cipherText)
|
||||
if decodeErr != nil {
|
||||
return []byte{}, decodeErr
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCDecrypter(block, a.iv)
|
||||
originCipherText := make([]byte, len(cipherDecodeText))
|
||||
mode.CryptBlocks(originCipherText, cipherDecodeText)
|
||||
originCipherText = stripPKSC7Padding(originCipherText)
|
||||
return originCipherText, nil
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充算法
|
||||
* @param string $source
|
||||
* @return string
|
||||
*/
|
||||
func addPKCS7Padding(ciphertext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
paddingText := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(ciphertext, paddingText...)
|
||||
}
|
||||
|
||||
/**
|
||||
* 移去填充算法
|
||||
* @param string $source
|
||||
* @return string
|
||||
*/
|
||||
func stripPKSC7Padding(cipherText []byte) []byte {
|
||||
length := len(cipherText)
|
||||
unpadding := int(cipherText[length-1])
|
||||
return cipherText[:(length - unpadding)]
|
||||
}
|
90
pkg/myAliMarket/index.go
Normal file
90
pkg/myAliMarket/index.go
Normal file
@ -0,0 +1,90 @@
|
||||
package myAliMarket
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
url string
|
||||
appCode string
|
||||
param map[string]string
|
||||
fullUrl string
|
||||
response string
|
||||
}
|
||||
|
||||
func New(url string, appCode string) *Client {
|
||||
return &Client{
|
||||
url: url,
|
||||
appCode: appCode,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Client) SetParam(param map[string]string) {
|
||||
t.param = param
|
||||
}
|
||||
|
||||
func (t *Client) getFullUrl() (string, error) {
|
||||
u, err := url.Parse(t.url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
q := u.Query()
|
||||
for k, v := range t.param {
|
||||
q.Add(k, v)
|
||||
}
|
||||
u.RawQuery = q.Encode()
|
||||
t.fullUrl = u.String()
|
||||
return t.fullUrl, nil
|
||||
}
|
||||
|
||||
func (t *Client) GetFullUrl() string {
|
||||
return t.fullUrl
|
||||
}
|
||||
|
||||
func (t *Client) GetResponse() string {
|
||||
return t.response
|
||||
}
|
||||
|
||||
func (t *Client) GetRequest(respData interface{}) error {
|
||||
fullUrl, err := t.getFullUrl()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
request, err := http.NewRequest("GET", fullUrl, nil)
|
||||
if err != nil {
|
||||
return errors.New("http客户端初始化失败")
|
||||
}
|
||||
request.Header.Add("Authorization", fmt.Sprintf("APPCODE %s", t.appCode))
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
return errors.New("认证服务器连接失败1")
|
||||
}
|
||||
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New("认证服务器连接失败2")
|
||||
}
|
||||
|
||||
var response2 []byte
|
||||
response2, err = ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return errors.New("数据解析失败")
|
||||
}
|
||||
|
||||
t.response = string(response2)
|
||||
|
||||
err = json.Unmarshal(response2, respData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
61
pkg/myAliSms/index.go
Normal file
61
pkg/myAliSms/index.go
Normal file
@ -0,0 +1,61 @@
|
||||
package myAliSms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
accessKeyId string
|
||||
accessSecret string
|
||||
signName string
|
||||
templateCode string
|
||||
}
|
||||
|
||||
func NewClient(accessKeyId string, accessSecret string) *Client {
|
||||
return &Client{accessKeyId: accessKeyId, accessSecret: accessSecret}
|
||||
}
|
||||
|
||||
func (t *Client) SetSignName(signName string) *Client {
|
||||
t.signName = signName
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Client) SetTemplateCode(code string) *Client {
|
||||
t.templateCode = code
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Client) SendSms(m map[string]interface{}, phone string) error {
|
||||
if t.signName == "" {
|
||||
return errors.New("签名不能为空")
|
||||
}
|
||||
client, err := dysmsapi.NewClientWithAccessKey("cn-hangzhou", t.accessKeyId, t.accessSecret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
request := dysmsapi.CreateSendSmsRequest()
|
||||
request.Scheme = "https"
|
||||
request.PhoneNumbers = phone
|
||||
request.SignName = t.signName
|
||||
request.TemplateCode = t.templateCode
|
||||
request.TemplateParam = t.mapToJson(m)
|
||||
|
||||
response, err := client.SendSms(request)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
if response.Code == "OK" {
|
||||
return nil
|
||||
} else {
|
||||
return errors.New(response.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Client) mapToJson(TemplateParamMap map[string]interface{}) string {
|
||||
mjson, _ := json.Marshal(TemplateParamMap)
|
||||
return string(mjson)
|
||||
}
|
50
pkg/myCobra/cobra.go
Normal file
50
pkg/myCobra/cobra.go
Normal file
@ -0,0 +1,50 @@
|
||||
package myCobra
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type SimpleCmd struct {
|
||||
Use string
|
||||
Short string
|
||||
Example string
|
||||
PreRun func()
|
||||
RunE func() error
|
||||
cobraModel *cobra.Command
|
||||
}
|
||||
|
||||
func (t *SimpleCmd) GetCobra() *cobra.Command {
|
||||
if t.cobraModel == nil {
|
||||
t.cobraModel = &cobra.Command{
|
||||
Use: t.Use,
|
||||
Short: t.Short,
|
||||
Example: t.Example,
|
||||
SilenceUsage: true,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
t.PreRun()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return t.RunE()
|
||||
},
|
||||
}
|
||||
}
|
||||
return t.cobraModel
|
||||
}
|
||||
|
||||
func (t *SimpleCmd) SetArgsFunc(argsFunc func(args []string) error) {
|
||||
t.GetCobra().Args = func(cmd *cobra.Command, args []string) error {
|
||||
return argsFunc(args)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *SimpleCmd) SetStringVar(p *string, name, shorthand string, value string, usage string) {
|
||||
t.GetCobra().PersistentFlags().StringVarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
|
||||
func (t *SimpleCmd) AddCommand(cmd *SimpleCmd) {
|
||||
t.GetCobra().AddCommand(cmd.GetCobra())
|
||||
}
|
||||
|
||||
func (t *SimpleCmd) Execute() error {
|
||||
return t.GetCobra().Execute()
|
||||
}
|
88
pkg/myGorm/gorm.go
Normal file
88
pkg/myGorm/gorm.go
Normal file
@ -0,0 +1,88 @@
|
||||
package myGorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SimpleORM struct {
|
||||
user string
|
||||
password string
|
||||
host string
|
||||
name string
|
||||
charset string
|
||||
runMode string
|
||||
loggerConfig logger.Config
|
||||
loggerLevel string
|
||||
}
|
||||
|
||||
func NewSimpleORM(user string, password string, host string, name string, charset string, runMode string) *SimpleORM {
|
||||
orm := &SimpleORM{
|
||||
user: user,
|
||||
password: password,
|
||||
host: host,
|
||||
name: name,
|
||||
charset: charset,
|
||||
runMode: runMode,
|
||||
loggerConfig: logger.Config{
|
||||
SlowThreshold: time.Second, // 慢 SQL 阈值
|
||||
Colorful: false, // 禁用彩色打印
|
||||
LogLevel: logger.Info,
|
||||
},
|
||||
}
|
||||
if runMode == "release" {
|
||||
orm.loggerConfig.LogLevel = logger.Silent
|
||||
}
|
||||
|
||||
return orm
|
||||
}
|
||||
|
||||
func (t *SimpleORM) getDSN() string {
|
||||
if t.charset == "" {
|
||||
t.charset = "utf8mb4"
|
||||
}
|
||||
return fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=%s&parseTime=True&loc=Local",
|
||||
t.user,
|
||||
t.password,
|
||||
t.host,
|
||||
t.name,
|
||||
t.charset,
|
||||
)
|
||||
}
|
||||
|
||||
func (t *SimpleORM) SetLoggerConfig(l logger.Config) {
|
||||
t.loggerConfig = l
|
||||
}
|
||||
|
||||
func (t *SimpleORM) SetLoggerLevel(level string) {
|
||||
if strings.ToLower(level) == "silent" {
|
||||
t.loggerConfig.LogLevel = logger.Silent
|
||||
} else if strings.ToLower(level) == "error" {
|
||||
t.loggerConfig.LogLevel = logger.Error
|
||||
} else if strings.ToLower(level) == "warn" {
|
||||
t.loggerConfig.LogLevel = logger.Warn
|
||||
} else if strings.ToLower(level) == "info" {
|
||||
t.loggerConfig.LogLevel = logger.Info
|
||||
}
|
||||
}
|
||||
|
||||
func (t *SimpleORM) ConnectMysql() *gorm.DB {
|
||||
Db, err := gorm.Open(
|
||||
mysql.Open(t.getDSN()), &gorm.Config{
|
||||
Logger: logger.New(
|
||||
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
|
||||
t.loggerConfig,
|
||||
),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic("failed to connect database")
|
||||
}
|
||||
return Db
|
||||
}
|
32
pkg/myHttp/header.go
Normal file
32
pkg/myHttp/header.go
Normal file
@ -0,0 +1,32 @@
|
||||
package myHttp
|
||||
|
||||
func (t *Client) HasHeader(key string) bool {
|
||||
for k, _ := range t.headers {
|
||||
if key == k {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *Client) SetHeaders(header map[string]string) *Client {
|
||||
t.headers = header
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Client) AddHeader(key, value string) *Client {
|
||||
t.headers[key] = value
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Client) AddHeaders(header map[string]string) *Client {
|
||||
for k, v := range header {
|
||||
t.headers[k] = v
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Client) DelHeader(key string) *Client {
|
||||
delete(t.headers, key)
|
||||
return t
|
||||
}
|
22
pkg/myHttp/index.go
Normal file
22
pkg/myHttp/index.go
Normal file
@ -0,0 +1,22 @@
|
||||
package myHttp
|
||||
|
||||
import (
|
||||
"code.zhecent.com/gopkg/light-core/pkg/myUrl"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
url *myUrl.UrlCli
|
||||
headers map[string]string
|
||||
}
|
||||
|
||||
func NewClient(url string) (*Client, error) {
|
||||
urlObj, err := myUrl.NewUrlCliWithParse(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Client{url: urlObj}, nil
|
||||
}
|
||||
|
||||
func (t *Client) GetMyUrl() *myUrl.UrlCli {
|
||||
return t.url
|
||||
}
|
57
pkg/myHttp/json.go
Normal file
57
pkg/myHttp/json.go
Normal file
@ -0,0 +1,57 @@
|
||||
package myHttp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (t *Client) PostJson(request interface{}, response interface{}) error {
|
||||
var buf bytes.Buffer
|
||||
encoder := json.NewEncoder(&buf)
|
||||
encoder.SetEscapeHTML(false)
|
||||
if err := encoder.Encode(request); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// HTTP请求
|
||||
req, err := http.NewRequest("POST", t.url.String(), &buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//添加请求头
|
||||
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
if len(t.headers) > 0 {
|
||||
for key, value := range t.headers {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return errors.New("http.Status:" + resp.Status)
|
||||
}
|
||||
return json.NewDecoder(resp.Body).Decode(response)
|
||||
}
|
||||
|
||||
func (t *Client) GetJson(response interface{}) error {
|
||||
httpResp, err := http.Get(t.url.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer httpResp.Body.Close()
|
||||
|
||||
if httpResp.StatusCode != http.StatusOK {
|
||||
return errors.New("http.Status:" + httpResp.Status)
|
||||
}
|
||||
return json.NewDecoder(httpResp.Body).Decode(response)
|
||||
}
|
115
pkg/myJwt/jwt.go
Normal file
115
pkg/myJwt/jwt.go
Normal file
@ -0,0 +1,115 @@
|
||||
package myJwt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Claims struct {
|
||||
UserId int `json:"uid"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
func (t Claims) toSimpleJwt() *SimpleJwt {
|
||||
return &SimpleJwt{
|
||||
Audience: t.Audience,
|
||||
ExpiresAt: t.ExpiresAt,
|
||||
Id: t.ID,
|
||||
IssuedAt: t.IssuedAt,
|
||||
Issuer: t.Issuer,
|
||||
NotBefore: t.NotBefore,
|
||||
Subject: t.Subject,
|
||||
userId: t.UserId,
|
||||
jwtSecret: "",
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type SimpleJwt struct {
|
||||
Audience jwt.ClaimStrings
|
||||
ExpiresAt *jwt.NumericDate
|
||||
Id string
|
||||
IssuedAt *jwt.NumericDate
|
||||
Issuer string
|
||||
NotBefore *jwt.NumericDate
|
||||
Subject string
|
||||
|
||||
userId int
|
||||
jwtSecret string
|
||||
}
|
||||
|
||||
func NewSimpleJwt(userId int, jwtSecret string) *SimpleJwt {
|
||||
return &SimpleJwt{
|
||||
userId: userId,
|
||||
jwtSecret: jwtSecret,
|
||||
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(90 * 24 * time.Hour)),
|
||||
Issuer: "zhecent",
|
||||
}
|
||||
}
|
||||
|
||||
func (t *SimpleJwt) SetExpiresAt(expiresAt time.Time) {
|
||||
t.ExpiresAt = jwt.NewNumericDate(expiresAt)
|
||||
}
|
||||
|
||||
func (t *SimpleJwt) makeClaims() Claims {
|
||||
return Claims{
|
||||
UserId: t.userId,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: t.ExpiresAt,
|
||||
Issuer: t.Issuer,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *SimpleJwt) GetUserId() int {
|
||||
return t.userId
|
||||
}
|
||||
|
||||
func (t *SimpleJwt) GenerateToken() (string, error) {
|
||||
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, t.makeClaims())
|
||||
token, err := tokenClaims.SignedString([]byte(t.jwtSecret))
|
||||
return token, err
|
||||
}
|
||||
|
||||
func (t *SimpleJwt) MustGenerateToken() string {
|
||||
s, e := t.GenerateToken()
|
||||
if e != nil {
|
||||
panic(e.Error())
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func ParseToken(token string, jwtSecret string) (*SimpleJwt, error) {
|
||||
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(jwtSecret), nil
|
||||
})
|
||||
|
||||
if tokenClaims != nil {
|
||||
if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
|
||||
return claims.toSimpleJwt(), nil
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case errors.Is(err, jwt.ErrTokenMalformed):
|
||||
return nil, errors.New("that's not even a token")
|
||||
case errors.Is(err, jwt.ErrTokenSignatureInvalid):
|
||||
// Invalid signature
|
||||
return nil, errors.New("invalid signature")
|
||||
case errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet):
|
||||
// Token is either expired or not active yet
|
||||
return nil, errors.New("timing is everything")
|
||||
default:
|
||||
return nil, errors.New("token校验失败")
|
||||
}
|
||||
}
|
||||
|
||||
func MustParseToken(token string, jwtSecret string) *SimpleJwt {
|
||||
s, e := ParseToken(token, jwtSecret)
|
||||
if e != nil {
|
||||
panic(e.Error())
|
||||
}
|
||||
return s
|
||||
}
|
138
pkg/myOss/index.go
Normal file
138
pkg/myOss/index.go
Normal file
@ -0,0 +1,138 @@
|
||||
package myOss
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Model struct {
|
||||
Path string
|
||||
Bucket string
|
||||
ACLType string
|
||||
Endpoint string
|
||||
AccessKeyID string
|
||||
SecretAccessKey string
|
||||
StorageClassType string
|
||||
CdnUrl string
|
||||
ossClient *oss.Client
|
||||
ossBucket *oss.Bucket
|
||||
}
|
||||
|
||||
func (t *Model) MustGetOssClient() *oss.Client {
|
||||
if t.ossClient == nil {
|
||||
client, err := oss.New(t.Endpoint, t.AccessKeyID, t.SecretAccessKey, oss.Timeout(10, 120))
|
||||
if err != nil {
|
||||
panic("function oss.New() Filed, err:" + err.Error())
|
||||
}
|
||||
t.ossClient = client
|
||||
}
|
||||
return t.ossClient
|
||||
}
|
||||
|
||||
func (t *Model) MustGetDefaultOssBucket() *oss.Bucket {
|
||||
if t.ossBucket == nil {
|
||||
client := t.MustGetOssClient()
|
||||
bucket, err := client.Bucket(t.Bucket)
|
||||
|
||||
if err != nil {
|
||||
panic("function client.Bucket() Filed, err:" + err.Error())
|
||||
}
|
||||
t.ossBucket = bucket
|
||||
}
|
||||
return t.ossBucket
|
||||
}
|
||||
|
||||
func (t *Model) PutObject(savePath, fileName string, reader io.Reader, contentType string) (*RespPath, error) {
|
||||
err := t.MustGetDefaultOssBucket().PutObject(
|
||||
fmt.Sprintf("%s/%s", savePath, fileName),
|
||||
reader,
|
||||
oss.ContentType(contentType),
|
||||
t.GetObjectStorageClass(),
|
||||
t.GetObjectAcl(),
|
||||
)
|
||||
return &RespPath{
|
||||
Path: savePath,
|
||||
Name: fileName,
|
||||
Host: t.CdnUrl,
|
||||
}, err
|
||||
|
||||
}
|
||||
|
||||
func (t *Model) MustPutObject(savePath, fileName string, reader io.Reader, contentType string) *RespPath {
|
||||
p, err := t.PutObject(savePath, fileName, reader, contentType)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (t *Model) GetObjectMeta(key string) (http.Header, error) {
|
||||
if strings.HasPrefix(key, "/") {
|
||||
key = strings.TrimLeft(key, "/")
|
||||
}
|
||||
return t.MustGetDefaultOssBucket().GetObjectMeta(key)
|
||||
}
|
||||
|
||||
func (t *Model) DeleteObject(key string) error {
|
||||
// 删除单个文件。objectName表示删除OSS文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
|
||||
// 如需删除文件夹,请将objectName设置为对应的文件夹名称。如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。
|
||||
//这里需要处理一下路径,如果第一个是/,要去掉
|
||||
|
||||
if strings.HasPrefix(key, "/") {
|
||||
key = strings.TrimLeft(key, "/")
|
||||
}
|
||||
if t.IsFileExist(key) {
|
||||
return t.MustGetDefaultOssBucket().DeleteObject(key)
|
||||
}
|
||||
return fmt.Errorf("文件不存在")
|
||||
}
|
||||
|
||||
func (t *Model) IsFileExist(key string) bool {
|
||||
if strings.HasPrefix(key, "/") {
|
||||
key = strings.TrimLeft(key, "/")
|
||||
}
|
||||
exist, err := t.MustGetDefaultOssBucket().IsObjectExist(key)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return exist
|
||||
}
|
||||
|
||||
func (t *Model) GetObjectStorageClass() oss.Option {
|
||||
switch t.StorageClassType { // 根据配置文件进行指定存储类型
|
||||
case "Standard": // 指定存储类型为标准存储
|
||||
return oss.ObjectStorageClass(oss.StorageStandard)
|
||||
case "IA": // 指定存储类型为很少访问存储
|
||||
return oss.ObjectStorageClass(oss.StorageIA)
|
||||
case "Archive": // 指定存储类型为归档存储。
|
||||
return oss.ObjectStorageClass(oss.StorageArchive)
|
||||
case "ColdArchive": // 指定存储类型为归档存储。
|
||||
return oss.ObjectStorageClass(oss.StorageColdArchive)
|
||||
default: // 无匹配结果就是标准存储
|
||||
return oss.ObjectStorageClass(oss.StorageStandard)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Model) GetObjectAcl() oss.Option {
|
||||
switch t.ACLType { // 根据配置文件进行指定访问权限
|
||||
case "private": // 指定访问权限为私有读写
|
||||
return oss.ObjectACL(oss.ACLPrivate) // 指定访问权限为公共读
|
||||
case "public-read":
|
||||
return oss.ObjectACL(oss.ACLPublicRead) // 指定访问权限为公共读
|
||||
case "public-read-write":
|
||||
return oss.ObjectACL(oss.ACLPublicReadWrite) // 指定访问权限为公共读写
|
||||
case "default":
|
||||
return oss.ObjectACL(oss.ACLDefault) // 指定访问权限为公共读
|
||||
default:
|
||||
return oss.ObjectACL(oss.ACLPrivate) // 默认为访问权限为公共读
|
||||
}
|
||||
}
|
||||
|
||||
type RespPath struct {
|
||||
Path string
|
||||
Name string
|
||||
Host string
|
||||
}
|
145
pkg/myPay/alipay.go
Normal file
145
pkg/myPay/alipay.go
Normal file
@ -0,0 +1,145 @@
|
||||
package myPay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/alipay"
|
||||
"github.com/shopspring/decimal"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type AliPay struct {
|
||||
ctx context.Context
|
||||
cli *alipay.Client
|
||||
params *AliPayImpl
|
||||
orderNo string
|
||||
amount int
|
||||
description string
|
||||
notifyUrl string
|
||||
returnUrl string
|
||||
}
|
||||
|
||||
func NewAliPay(params *AliPayImpl) *AliPay {
|
||||
client, err := alipay.NewClient(params.AppId, params.PrivateKey, params.IsProd)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
// 打开Debug开关,输出日志,默认是关闭的
|
||||
if params.IsProd {
|
||||
client.DebugSwitch = gopay.DebugOff
|
||||
} else {
|
||||
client.DebugSwitch = gopay.DebugOn
|
||||
}
|
||||
|
||||
client.SetLocation(alipay.LocationShanghai).
|
||||
SetCharset(alipay.UTF8).
|
||||
SetSignType(alipay.RSA2).
|
||||
AutoVerifySign([]byte(params.PublicKey))
|
||||
|
||||
if err := client.SetCertSnByContent([]byte(params.AppCertContent), []byte(params.AliPayRootCertContent), []byte(params.PublicKey)); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
return &AliPay{params: params, cli: client, ctx: context.Background()}
|
||||
}
|
||||
|
||||
func (t *AliPay) GetCli() *alipay.Client {
|
||||
return t.cli
|
||||
}
|
||||
|
||||
func (t *AliPay) SetCommonConfig(notifyUrl string, returnUrl string) *AliPay {
|
||||
t.notifyUrl = notifyUrl
|
||||
t.returnUrl = returnUrl
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *AliPay) SetOrderInfo(orderNo string, amount int, description string) *AliPay {
|
||||
t.orderNo = orderNo
|
||||
t.amount = amount
|
||||
t.description = description
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *AliPay) SetCertSnByContent(appCertContent, aliPayRootCertContent []byte) error {
|
||||
return t.cli.SetCertSnByContent(appCertContent, aliPayRootCertContent, []byte(t.params.PublicKey))
|
||||
}
|
||||
|
||||
func (t *AliPay) SetCertSnByPath(appCertPath, aliPayRootCertPath, aliPayPublicCertPath string) error {
|
||||
return t.cli.SetCertSnByPath(appCertPath, aliPayRootCertPath, aliPayPublicCertPath)
|
||||
}
|
||||
|
||||
func (t *AliPay) setBodyMap() gopay.BodyMap {
|
||||
if t.description == "" || t.orderNo == "" || t.notifyUrl == "" {
|
||||
panic("param is empty")
|
||||
}
|
||||
if t.amount == 0 {
|
||||
panic("amount is zero")
|
||||
}
|
||||
|
||||
// 配置公共参数
|
||||
t.cli.SetNotifyUrl(t.notifyUrl).
|
||||
SetReturnUrl(t.returnUrl)
|
||||
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("subject", t.description)
|
||||
bm.Set("out_trade_no", t.orderNo)
|
||||
bm.Set("total_amount", t.fen2Yuan(uint64(t.amount)))
|
||||
return bm
|
||||
}
|
||||
|
||||
func (t *AliPay) GetWapPay(quitUrl string) (string, error) {
|
||||
bm := t.setBodyMap()
|
||||
bm.Set("quit_url", quitUrl)
|
||||
bm.Set("product_code", "QUICK_WAP_WAY")
|
||||
return t.cli.TradeWapPay(t.ctx, bm)
|
||||
}
|
||||
|
||||
func (t *AliPay) GetPagePay() (string, error) {
|
||||
bm := t.setBodyMap()
|
||||
bm.Set("product_code", "FAST_INSTANT_TRADE_PAY")
|
||||
return t.cli.TradePagePay(t.ctx, bm)
|
||||
}
|
||||
|
||||
func (t *AliPay) GetAppPay() (string, error) {
|
||||
bm := t.setBodyMap()
|
||||
bm.Set("product_code", "QUICK_MSECURITY_PAY")
|
||||
return t.cli.TradeAppPay(t.ctx, bm)
|
||||
}
|
||||
|
||||
func (t *AliPay) Notify(req *http.Request) (*AlipayNotifyResp, error) {
|
||||
notifyReq, err := alipay.ParseNotifyToBodyMap(req)
|
||||
if err != nil {
|
||||
return nil, errors.New("解析回调失败")
|
||||
}
|
||||
|
||||
if ok, err := alipay.VerifySign(t.params.PublicKey, notifyReq); err != nil || ok == false {
|
||||
return nil, errors.New("sign Error")
|
||||
}
|
||||
|
||||
return &AlipayNotifyResp{resp: notifyReq}, nil
|
||||
}
|
||||
|
||||
func (t *AliPay) GetOrderNo() string {
|
||||
return t.orderNo
|
||||
}
|
||||
|
||||
func (t *AliPay) GetAmount() int {
|
||||
return t.amount
|
||||
}
|
||||
|
||||
type AliPayImpl struct {
|
||||
AppId string
|
||||
PublicKey string
|
||||
PrivateKey string
|
||||
IsProd bool
|
||||
AppCertContent string
|
||||
AliPayRootCertContent string
|
||||
}
|
||||
|
||||
func (t *AliPay) fen2Yuan(price uint64) string {
|
||||
d := decimal.New(1, 2)
|
||||
result := decimal.NewFromInt(int64(price)).DivRound(d, 2).String()
|
||||
return result
|
||||
}
|
28
pkg/myPay/alipay_notify.go
Normal file
28
pkg/myPay/alipay_notify.go
Normal file
@ -0,0 +1,28 @@
|
||||
package myPay
|
||||
|
||||
import "github.com/go-pay/gopay"
|
||||
|
||||
type AlipayNotifyResp struct {
|
||||
resp gopay.BodyMap
|
||||
}
|
||||
type AlipayNotifyRespInfo struct {
|
||||
TradeStatus string
|
||||
OutTradeNo string
|
||||
SellerId string
|
||||
TradeNo string
|
||||
GmtPayment string
|
||||
}
|
||||
|
||||
func (t *AlipayNotifyResp) IsSuccess() bool {
|
||||
return t.resp.Get("trade_status") == "TRADE_SUCCESS"
|
||||
}
|
||||
|
||||
func (t *AlipayNotifyResp) GetResult() *AlipayNotifyRespInfo {
|
||||
return &AlipayNotifyRespInfo{
|
||||
TradeStatus: t.resp.Get("trade_status"),
|
||||
OutTradeNo: t.resp.Get("out_trade_no"),
|
||||
SellerId: t.resp.Get("seller_id"),
|
||||
TradeNo: t.resp.Get("trade_no"),
|
||||
GmtPayment: t.resp.Get("gmt_payment"),
|
||||
}
|
||||
}
|
261
pkg/myPay/wechat.go
Normal file
261
pkg/myPay/wechat.go
Normal file
@ -0,0 +1,261 @@
|
||||
package myPay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/wechat/v3"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Wechat struct {
|
||||
ctx context.Context
|
||||
cli *wechat.ClientV3
|
||||
params *WechatPayV3Impl
|
||||
orderNo string
|
||||
amount int
|
||||
description string
|
||||
notifyUrl string
|
||||
profitSharing bool
|
||||
}
|
||||
|
||||
func NewWechat(params *WechatPayV3Impl) *Wechat {
|
||||
// NewClientV3 初始化微信客户端 v3
|
||||
// mchid:商户ID 或者服务商模式的 sp_mchid
|
||||
// serialNo:商户证书的证书序列号
|
||||
// apiV3Key:apiV3Key,商户平台获取
|
||||
// privateKey:私钥 apiclient_key.pem 读取后的内容
|
||||
client, err := wechat.NewClientV3(params.MchId, params.SerialNo, params.ApiV3Key, params.PKContent)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
// 设置微信平台API证书和序列号(推荐开启自动验签,无需手动设置证书公钥等信息)
|
||||
//client.SetPlatformCert([]byte(""), "")
|
||||
|
||||
// 启用自动同步返回验签,并定时更新微信平台API证书(开启自动验签时,无需单独设置微信平台API证书和序列号)
|
||||
client.SetPlatformCert([]byte(params.WxPkContent), params.WxPkSerialNo)
|
||||
// 启用自动同步返回验签,并定时更新微信平台API证书
|
||||
//err = client.AutoVerifySign()
|
||||
//if err != nil {
|
||||
// return nil, err
|
||||
//}
|
||||
|
||||
// 打开Debug开关,输出日志,默认是关闭的
|
||||
if params.IsProd {
|
||||
client.DebugSwitch = gopay.DebugOff
|
||||
} else {
|
||||
client.DebugSwitch = gopay.DebugOn
|
||||
}
|
||||
|
||||
return &Wechat{params: params, cli: client, ctx: context.Background()}
|
||||
}
|
||||
|
||||
func (t *Wechat) GetCli() *wechat.ClientV3 {
|
||||
return t.cli
|
||||
}
|
||||
|
||||
func (t *Wechat) SetCommonConfig(notifyUrl string) *Wechat {
|
||||
t.notifyUrl = notifyUrl
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Wechat) SetOrderInfo(orderNo string, amount int, description string) *Wechat {
|
||||
t.orderNo = orderNo
|
||||
t.amount = amount
|
||||
t.description = description
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Wechat) setBodyMap() gopay.BodyMap {
|
||||
if t.description == "" || t.orderNo == "" || t.notifyUrl == "" {
|
||||
panic("param is empty")
|
||||
}
|
||||
if t.amount == 0 {
|
||||
panic("amount is zero")
|
||||
}
|
||||
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("description", t.description).
|
||||
Set("out_trade_no", t.orderNo).
|
||||
Set("time_expire", time.Now().Add(10*time.Minute).Format(time.RFC3339)).
|
||||
Set("notify_url", t.notifyUrl).
|
||||
SetBodyMap("amount", func(bm gopay.BodyMap) {
|
||||
bm.Set("total", t.amount).Set("currency", "CNY")
|
||||
})
|
||||
if t.profitSharing {
|
||||
bm.SetBodyMap("settle_info", func(bm gopay.BodyMap) {
|
||||
bm.Set("profit_sharing", true)
|
||||
})
|
||||
}
|
||||
|
||||
return bm
|
||||
}
|
||||
|
||||
func (t *Wechat) SetProfitSharing(b bool) *Wechat {
|
||||
t.profitSharing = b
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Wechat) GetApp() (*wechat.AppPayParams, error) {
|
||||
wxRsp, err := t.cli.V3TransactionApp(t.ctx, t.setBodyMap().Set("appid", t.params.AppAppid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if wxRsp.Code == wechat.Success {
|
||||
//校验签名
|
||||
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
|
||||
return nil, err2
|
||||
}
|
||||
|
||||
//获取调起参数
|
||||
return t.cli.PaySignOfApp(t.params.AppAppid, wxRsp.Response.PrepayId)
|
||||
} else {
|
||||
return nil, errors.New(wxRsp.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Wechat) GetJsapi(openId string) (*wechat.JSAPIPayParams, error) {
|
||||
wxRsp, err := t.cli.V3TransactionJsapi(t.ctx,
|
||||
t.setBodyMap().Set("appid", t.params.MpAppid).SetBodyMap("payer", func(bm gopay.BodyMap) {
|
||||
bm.Set("openid", openId)
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if wxRsp.Code == wechat.Success {
|
||||
//校验签名
|
||||
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
|
||||
return nil, err2
|
||||
}
|
||||
|
||||
//获取调起参数
|
||||
return t.cli.PaySignOfJSAPI(t.params.MpAppid, wxRsp.Response.PrepayId)
|
||||
} else {
|
||||
return nil, errors.New(wxRsp.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Wechat) GetJsapiForMini(openId string) (*wechat.JSAPIPayParams, error) {
|
||||
wxRsp, err := t.cli.V3TransactionJsapi(t.ctx,
|
||||
t.setBodyMap().Set("appid", t.params.MiniAppid).SetBodyMap("payer", func(bm gopay.BodyMap) {
|
||||
bm.Set("openid", openId)
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if wxRsp.Code == wechat.Success {
|
||||
//校验签名
|
||||
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
|
||||
return nil, err2
|
||||
}
|
||||
|
||||
//获取调起参数
|
||||
return t.cli.PaySignOfJSAPI(t.params.MiniAppid, wxRsp.Response.PrepayId)
|
||||
} else {
|
||||
return nil, errors.New(wxRsp.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Wechat) GetNative() (*wechat.Native, error) {
|
||||
wxRsp, err := t.cli.V3TransactionNative(t.ctx, t.setBodyMap().Set("appid", t.params.MpAppid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if wxRsp.Code == wechat.Success {
|
||||
//校验签名
|
||||
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
|
||||
return nil, err2
|
||||
}
|
||||
|
||||
//获取调起参数
|
||||
return wxRsp.Response, err
|
||||
} else {
|
||||
return nil, errors.New(wxRsp.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Wechat) GetH5(ip string, appName string, appUrl string) (*wechat.H5Url, error) {
|
||||
wxRsp, err := t.cli.V3TransactionH5(t.ctx, t.setBodyMap().Set("appid", t.params.MpAppid).SetBodyMap("scene_info", func(bm gopay.BodyMap) {
|
||||
bm.Set("payer_client_ip", ip)
|
||||
bm.SetBodyMap("h5_info", func(bm gopay.BodyMap) {
|
||||
bm.Set("type", "Wap")
|
||||
bm.Set("app_url", appUrl)
|
||||
bm.Set("app_name", appName)
|
||||
})
|
||||
}))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if wxRsp.Code == wechat.Success {
|
||||
//校验签名
|
||||
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
|
||||
return nil, err2
|
||||
}
|
||||
|
||||
//获取调起参数
|
||||
return wxRsp.Response, nil
|
||||
} else {
|
||||
return nil, errors.New(wxRsp.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Wechat) Notify(req *http.Request) (*WechatNotifyResp, error) {
|
||||
notifyReq, err := wechat.V3ParseNotify(req)
|
||||
if err != nil {
|
||||
return nil, errors.New("解析回调失败")
|
||||
}
|
||||
|
||||
err = notifyReq.VerifySignByPK(t.cli.WxPublicKey())
|
||||
if err != nil {
|
||||
return nil, errors.New("sign Error")
|
||||
}
|
||||
|
||||
if notifyReq.EventType == "TRANSACTION.SUCCESS" {
|
||||
result, err := notifyReq.DecryptPayCipherText(t.params.ApiV3Key)
|
||||
if err != nil {
|
||||
return nil, errors.New("解密错误")
|
||||
} else {
|
||||
return &WechatNotifyResp{resp: result}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New(notifyReq.EventType)
|
||||
}
|
||||
|
||||
func (t *Wechat) GetOrderNo() string {
|
||||
return t.orderNo
|
||||
}
|
||||
|
||||
func (t *Wechat) GetAmount() int {
|
||||
return t.amount
|
||||
}
|
||||
|
||||
func NotifySuccess(msg string) (int, *wechat.V3NotifyRsp) {
|
||||
return http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: msg}
|
||||
}
|
||||
|
||||
func NotifyFail(msg string) (int, *wechat.V3NotifyRsp) {
|
||||
return http.StatusBadRequest, &wechat.V3NotifyRsp{Code: gopay.FAIL, Message: msg}
|
||||
}
|
||||
|
||||
type WechatPayV3Impl struct {
|
||||
MpAppid string
|
||||
AppAppid string
|
||||
MiniAppid string
|
||||
MchId string
|
||||
ApiV3Key string
|
||||
SerialNo string
|
||||
PKContent string
|
||||
WxPkSerialNo string
|
||||
WxPkContent string
|
||||
IsProd bool
|
||||
}
|
15
pkg/myPay/wechat_notify.go
Normal file
15
pkg/myPay/wechat_notify.go
Normal file
@ -0,0 +1,15 @@
|
||||
package myPay
|
||||
|
||||
import "github.com/go-pay/gopay/wechat/v3"
|
||||
|
||||
type WechatNotifyResp struct {
|
||||
resp *wechat.V3DecryptPayResult
|
||||
}
|
||||
|
||||
func (t *WechatNotifyResp) IsSuccess() bool {
|
||||
return t.resp.TradeState == "SUCCESS"
|
||||
}
|
||||
|
||||
func (t *WechatNotifyResp) GetResult() *wechat.V3DecryptPayResult {
|
||||
return t.resp
|
||||
}
|
23
pkg/myRedis/Ierator.go
Normal file
23
pkg/myRedis/Ierator.go
Normal file
@ -0,0 +1,23 @@
|
||||
package myRedis
|
||||
|
||||
type Iterator struct {
|
||||
data []interface{}
|
||||
index int
|
||||
}
|
||||
|
||||
func NewIterator(data []interface{}) *Iterator {
|
||||
return &Iterator{data: data}
|
||||
}
|
||||
|
||||
func (t *Iterator) HasNext() bool {
|
||||
if t.data == nil || len(t.data) == 0 {
|
||||
return false
|
||||
}
|
||||
return t.index < len(t.data)
|
||||
}
|
||||
|
||||
func (t *Iterator) Next() (ret interface{}) {
|
||||
ret = t.data[t.index]
|
||||
t.index = t.index + 1
|
||||
return
|
||||
}
|
33
pkg/myRedis/IntResult.go
Normal file
33
pkg/myRedis/IntResult.go
Normal file
@ -0,0 +1,33 @@
|
||||
package myRedis
|
||||
|
||||
type IntResult struct {
|
||||
Result int64
|
||||
Err error
|
||||
}
|
||||
|
||||
func NewIntResult(result int64, err error) *IntResult {
|
||||
return &IntResult{Result: result, Err: err}
|
||||
}
|
||||
|
||||
func (t *IntResult) Unwrap() int64 {
|
||||
if t.Err != nil {
|
||||
panic(t.Err)
|
||||
}
|
||||
|
||||
return t.Result
|
||||
}
|
||||
|
||||
func (t *IntResult) UnwrapOr(str int64) int64 {
|
||||
if t.Err != nil {
|
||||
return str
|
||||
} else {
|
||||
return t.Result
|
||||
}
|
||||
}
|
||||
|
||||
func (t *IntResult) UnwrapOrElse(f func() int64) int64 {
|
||||
if t.Err != nil {
|
||||
return f()
|
||||
}
|
||||
return t.Result
|
||||
}
|
25
pkg/myRedis/InterfaceResult.go
Normal file
25
pkg/myRedis/InterfaceResult.go
Normal file
@ -0,0 +1,25 @@
|
||||
package myRedis
|
||||
|
||||
type InterfaceResult struct {
|
||||
Result interface{}
|
||||
Err error
|
||||
}
|
||||
|
||||
func NewInterfaceResult(result interface{}, err error) *InterfaceResult {
|
||||
return &InterfaceResult{Result: result, Err: err}
|
||||
}
|
||||
|
||||
func (t *InterfaceResult) Unwrap() interface{} {
|
||||
if t.Err != nil {
|
||||
panic(t.Err)
|
||||
}
|
||||
|
||||
return t.Result
|
||||
}
|
||||
|
||||
func (t *InterfaceResult) UnwrapOr(a interface{}) interface{} {
|
||||
if t.Err != nil {
|
||||
return a
|
||||
}
|
||||
return t.Result
|
||||
}
|
52
pkg/myRedis/OperationAttr.go
Normal file
52
pkg/myRedis/OperationAttr.go
Normal file
@ -0,0 +1,52 @@
|
||||
package myRedis
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
AttrExpr = "expr"
|
||||
AttrNx = "nx"
|
||||
AttrXx = "xx"
|
||||
)
|
||||
|
||||
type empty struct {
|
||||
}
|
||||
|
||||
type OperationAttr struct {
|
||||
Name string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type OperationAttrs []*OperationAttr
|
||||
|
||||
func (t OperationAttrs) Find(name string) *InterfaceResult {
|
||||
for _, attr := range t {
|
||||
if attr.Name == name {
|
||||
return NewInterfaceResult(attr.Value, nil)
|
||||
}
|
||||
}
|
||||
return NewInterfaceResult(nil, fmt.Errorf("OperationAttrs found error:%s", name))
|
||||
}
|
||||
|
||||
func WithExpire(t time.Duration) *OperationAttr {
|
||||
return &OperationAttr{
|
||||
Name: AttrExpr,
|
||||
Value: t,
|
||||
}
|
||||
}
|
||||
|
||||
func WithNX() *OperationAttr {
|
||||
return &OperationAttr{
|
||||
Name: AttrNx,
|
||||
Value: empty{},
|
||||
}
|
||||
}
|
||||
|
||||
func WithXX() *OperationAttr {
|
||||
return &OperationAttr{
|
||||
Name: AttrXx,
|
||||
Value: empty{},
|
||||
}
|
||||
}
|
132
pkg/myRedis/SimpleCache.go
Normal file
132
pkg/myRedis/SimpleCache.go
Normal file
@ -0,0 +1,132 @@
|
||||
package myRedis
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
SerializerNot = ""
|
||||
SerializerJson = "json"
|
||||
SerializerGob = "gob"
|
||||
)
|
||||
|
||||
type CacheGetterFunc func() interface{}
|
||||
|
||||
type SimpleCache struct {
|
||||
Operation *StringOperation
|
||||
Expire time.Duration
|
||||
CacheGetter CacheGetterFunc
|
||||
Serializer string //序列化方式
|
||||
}
|
||||
|
||||
func NewSimpleCache(operation *StringOperation, expire time.Duration, serializer string) *SimpleCache {
|
||||
return &SimpleCache{Operation: operation, Expire: expire, Serializer: serializer}
|
||||
}
|
||||
|
||||
func (t *SimpleCache) SetCacheGetterFunc(f CacheGetterFunc) *SimpleCache {
|
||||
t.CacheGetter = f
|
||||
return t
|
||||
}
|
||||
|
||||
// 设置缓存
|
||||
func (t *SimpleCache) SetCache(key string, value interface{}) {
|
||||
//if t.Serializer == SerializerNot {
|
||||
//}
|
||||
if t.Serializer == SerializerJson {
|
||||
f := func() string {
|
||||
j, e := json.Marshal(value)
|
||||
if e != nil {
|
||||
return e.Error()
|
||||
} else {
|
||||
return string(j)
|
||||
}
|
||||
}
|
||||
t.Operation.Set(key, f(), WithExpire(t.Expire)).Unwrap()
|
||||
} else if t.Serializer == SerializerGob {
|
||||
f := func() string {
|
||||
var buf = &bytes.Buffer{}
|
||||
enc := gob.NewEncoder(buf)
|
||||
if err := enc.Encode(value); err != nil {
|
||||
return ""
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
t.Operation.Set(key, f(), WithExpire(t.Expire)).Unwrap()
|
||||
} else {
|
||||
t.Operation.Set(key, value, WithExpire(t.Expire)).Unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *SimpleCache) GetCache(key string) (ret interface{}) {
|
||||
//如果没有设置的话
|
||||
if t.CacheGetter == nil {
|
||||
panic("没有设置CacheGetter")
|
||||
}
|
||||
|
||||
if t.Serializer == SerializerNot {
|
||||
}
|
||||
if t.Serializer == SerializerJson {
|
||||
f := func() string {
|
||||
j, e := json.Marshal(t.CacheGetter())
|
||||
if e != nil {
|
||||
return e.Error()
|
||||
} else {
|
||||
return string(j)
|
||||
}
|
||||
}
|
||||
ret = t.Operation.Get(key).UnwrapOrElse(func() string {
|
||||
data := f()
|
||||
t.Operation.Set(key, data, WithExpire(t.Expire)).Unwrap()
|
||||
return data
|
||||
})
|
||||
}
|
||||
|
||||
if t.Serializer == SerializerGob {
|
||||
f := func() string {
|
||||
var buf = &bytes.Buffer{}
|
||||
enc := gob.NewEncoder(buf)
|
||||
if err := enc.Encode(t.CacheGetter()); err != nil {
|
||||
return ""
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
ret = t.Operation.Get(key).UnwrapOrElse(func() string {
|
||||
data := f()
|
||||
t.Operation.Set(key, data, WithExpire(t.Expire)).Unwrap()
|
||||
return data
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (t *SimpleCache) DelCache(key string) int64 {
|
||||
return t.Operation.Del(key).UnwrapOr(0)
|
||||
}
|
||||
|
||||
func (t *SimpleCache) GetCacheForObject(key string, obj interface{}) interface{} {
|
||||
ret := t.GetCache(key)
|
||||
if ret == nil {
|
||||
return nil
|
||||
}
|
||||
if t.Serializer == SerializerNot {
|
||||
obj = ret
|
||||
} else if t.Serializer == SerializerJson {
|
||||
err := json.Unmarshal([]byte(ret.(string)), obj)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
} else if t.Serializer == SerializerGob {
|
||||
|
||||
var buf = &bytes.Buffer{}
|
||||
buf.WriteString(ret.(string))
|
||||
dec := gob.NewDecoder(buf)
|
||||
if dec.Decode(obj) != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
29
pkg/myRedis/SliceResult.go
Normal file
29
pkg/myRedis/SliceResult.go
Normal file
@ -0,0 +1,29 @@
|
||||
package myRedis
|
||||
|
||||
type SliceResult struct {
|
||||
Result []interface{}
|
||||
Err error
|
||||
}
|
||||
|
||||
func NewSliceResult(result []interface{}, err error) *SliceResult {
|
||||
return &SliceResult{Result: result, Err: err}
|
||||
}
|
||||
|
||||
func (t *SliceResult) Unwrap() []interface{} {
|
||||
if t.Err != nil {
|
||||
panic(t.Err)
|
||||
}
|
||||
return t.Result
|
||||
}
|
||||
|
||||
func (t *SliceResult) UnwrapOr(strs []interface{}) []interface{} {
|
||||
if t.Err != nil {
|
||||
return strs
|
||||
} else {
|
||||
return t.Result
|
||||
}
|
||||
}
|
||||
|
||||
func (t *SliceResult) Iter() *Iterator {
|
||||
return NewIterator(t.Result)
|
||||
}
|
52
pkg/myRedis/StringCache.go
Normal file
52
pkg/myRedis/StringCache.go
Normal file
@ -0,0 +1,52 @@
|
||||
package myRedis
|
||||
|
||||
import (
|
||||
"github.com/redis/go-redis/v9"
|
||||
"time"
|
||||
)
|
||||
|
||||
type StringCache struct {
|
||||
Operation *StringOperation
|
||||
Expire time.Duration
|
||||
DefaultString string
|
||||
}
|
||||
|
||||
func NewStringCache(redisClient *redis.Client) *StringCache {
|
||||
return &StringCache{
|
||||
Operation: NewStringOperation(redisClient),
|
||||
Expire: time.Second * 0,
|
||||
DefaultString: "",
|
||||
}
|
||||
}
|
||||
|
||||
func (t *StringCache) SetExpire(expire time.Duration) *StringCache {
|
||||
t.Expire = expire
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *StringCache) SetDefaultString(defaultString string) *StringCache {
|
||||
t.DefaultString = defaultString
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *StringCache) SetCache(key string, value string) {
|
||||
t.Operation.Set(key, value, WithExpire(t.Expire))
|
||||
}
|
||||
|
||||
func (t *StringCache) GetCache(key string) (ret string) {
|
||||
ret = t.Operation.Get(key).UnwrapOrElse(func() string {
|
||||
if t.DefaultString != "" {
|
||||
t.SetCache(key, t.DefaultString)
|
||||
}
|
||||
return t.DefaultString
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (t *StringCache) IsExist(key string) bool {
|
||||
return t.Operation.Exist(key).UnwrapOr(0) != 0
|
||||
}
|
||||
|
||||
func (t *StringCache) DelCache(key string) int64 {
|
||||
return t.Operation.Del(key).UnwrapOr(0)
|
||||
}
|
48
pkg/myRedis/StringOperation.go
Normal file
48
pkg/myRedis/StringOperation.go
Normal file
@ -0,0 +1,48 @@
|
||||
package myRedis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"time"
|
||||
)
|
||||
|
||||
type StringOperation struct {
|
||||
ctx context.Context
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func NewStringOperation(client *redis.Client) *StringOperation {
|
||||
return &StringOperation{ctx: context.Background(), client: client}
|
||||
}
|
||||
|
||||
func (t *StringOperation) Set(key string, value interface{}, attrs ...*OperationAttr) *InterfaceResult {
|
||||
exp := OperationAttrs(attrs).Find(AttrExpr).UnwrapOr(0 * time.Second).(time.Duration)
|
||||
|
||||
nx := OperationAttrs(attrs).Find(AttrNx).UnwrapOr(nil)
|
||||
if nx != nil {
|
||||
return NewInterfaceResult(t.client.SetNX(t.ctx, key, value, exp).Result())
|
||||
}
|
||||
|
||||
xx := OperationAttrs(attrs).Find(AttrXx).UnwrapOr(nil)
|
||||
if xx != nil {
|
||||
return NewInterfaceResult(t.client.SetXX(t.ctx, key, value, exp).Result())
|
||||
}
|
||||
|
||||
return NewInterfaceResult(t.client.Set(t.ctx, key, value, exp).Result())
|
||||
}
|
||||
|
||||
func (t *StringOperation) Get(key string) *StringResult {
|
||||
return NewStringResult(t.client.Get(t.ctx, key).Result())
|
||||
}
|
||||
|
||||
func (t *StringOperation) MGet(key ...string) *SliceResult {
|
||||
return NewSliceResult(t.client.MGet(t.ctx, key...).Result())
|
||||
}
|
||||
|
||||
func (t *StringOperation) Del(key string) *IntResult {
|
||||
return NewIntResult(t.client.Del(t.ctx, key).Result())
|
||||
}
|
||||
|
||||
func (t *StringOperation) Exist(key string) *IntResult {
|
||||
return NewIntResult(t.client.Exists(t.ctx, key).Result())
|
||||
}
|
33
pkg/myRedis/StringResult.go
Normal file
33
pkg/myRedis/StringResult.go
Normal file
@ -0,0 +1,33 @@
|
||||
package myRedis
|
||||
|
||||
type StringResult struct {
|
||||
Result string
|
||||
Err error
|
||||
}
|
||||
|
||||
func NewStringResult(result string, err error) *StringResult {
|
||||
return &StringResult{Result: result, Err: err}
|
||||
}
|
||||
|
||||
func (t *StringResult) Unwrap() string {
|
||||
if t.Err != nil {
|
||||
panic(t.Err)
|
||||
}
|
||||
|
||||
return t.Result
|
||||
}
|
||||
|
||||
func (t *StringResult) UnwrapOr(str string) string {
|
||||
if t.Err != nil {
|
||||
return str
|
||||
} else {
|
||||
return t.Result
|
||||
}
|
||||
}
|
||||
|
||||
func (t *StringResult) UnwrapOrElse(f func() string) string {
|
||||
if t.Err != nil {
|
||||
return f()
|
||||
}
|
||||
return t.Result
|
||||
}
|
33
pkg/myRedis/cli.go
Normal file
33
pkg/myRedis/cli.go
Normal file
@ -0,0 +1,33 @@
|
||||
package myRedis
|
||||
|
||||
import (
|
||||
"github.com/redis/go-redis/v9"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func NewClient(client *redis.Client) *Client {
|
||||
if client == nil {
|
||||
panic("redis client is nil")
|
||||
}
|
||||
return &Client{client: client}
|
||||
}
|
||||
|
||||
func (t *Client) GetClient() *redis.Client {
|
||||
return t.client
|
||||
}
|
||||
|
||||
func (t *Client) NewStringCache() *StringCache {
|
||||
return NewStringCache(t.client)
|
||||
}
|
||||
|
||||
func (t *Client) NewJsonCache(expire time.Duration) *SimpleCache {
|
||||
return NewSimpleCache(NewStringOperation(t.client), expire, SerializerJson)
|
||||
}
|
||||
|
||||
func (t *Client) NewGobCache(expire time.Duration) *SimpleCache {
|
||||
return NewSimpleCache(NewStringOperation(t.client), expire, SerializerGob)
|
||||
}
|
60
pkg/myRedis/index.go
Normal file
60
pkg/myRedis/index.go
Normal file
@ -0,0 +1,60 @@
|
||||
package myRedis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type SimpleRedis struct {
|
||||
Host string
|
||||
Password string
|
||||
hosts map[int]*Hosts
|
||||
}
|
||||
|
||||
type Hosts struct {
|
||||
clientOnce sync.Once
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func NewSimpleRedis(host string, password string) *SimpleRedis {
|
||||
return &SimpleRedis{Host: host, Password: password, hosts: map[int]*Hosts{}}
|
||||
}
|
||||
|
||||
func (t *SimpleRedis) connectRedis(index int) *redis.Client {
|
||||
if t.hosts[index] == nil {
|
||||
t.hosts[index] = &Hosts{
|
||||
clientOnce: sync.Once{},
|
||||
client: nil,
|
||||
}
|
||||
}
|
||||
|
||||
t.hosts[index].clientOnce.Do(func() {
|
||||
redisClient := redis.NewClient(&redis.Options{
|
||||
Addr: t.Host,
|
||||
Password: t.Password, // no password set
|
||||
DB: index, // use default DB
|
||||
//连接池容量以闲置链接数量
|
||||
PoolSize: 15,
|
||||
MinIdleConns: 10,
|
||||
})
|
||||
pong, err := redisClient.Ping(context.Background()).Result()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("connect error:%s", err))
|
||||
}
|
||||
log.Println(fmt.Sprintf("redis newClient success, index:%d, pong: %s", index, pong))
|
||||
|
||||
t.hosts[index].client = redisClient
|
||||
})
|
||||
return t.hosts[index].client
|
||||
}
|
||||
|
||||
func (t *SimpleRedis) ConnectDefaultRedis() *Client {
|
||||
return t.GetRedisClient(0)
|
||||
}
|
||||
|
||||
func (t *SimpleRedis) GetRedisClient(index int) *Client {
|
||||
return NewClient(t.connectRedis(index))
|
||||
}
|
42
pkg/myUrl/index.go
Normal file
42
pkg/myUrl/index.go
Normal file
@ -0,0 +1,42 @@
|
||||
package myUrl
|
||||
|
||||
import "net/url"
|
||||
|
||||
type UrlCli struct {
|
||||
url url.URL
|
||||
params url.Values
|
||||
}
|
||||
|
||||
func NewUrlCli(scheme string, host string) *UrlCli {
|
||||
return &UrlCli{url: url.URL{Scheme: scheme, Host: host}, params: url.Values{}}
|
||||
}
|
||||
|
||||
func NewUrlCliWithParse(data string) (*UrlCli, error) {
|
||||
urlObj, err := url.Parse(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &UrlCli{
|
||||
url: *urlObj,
|
||||
params: urlObj.Query(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *UrlCli) Set(m map[string]string) {
|
||||
params := url.Values{}
|
||||
for s, s2 := range m {
|
||||
params.Set(s, s2)
|
||||
}
|
||||
t.params = params
|
||||
}
|
||||
|
||||
func (t *UrlCli) Add(key, value string) *UrlCli {
|
||||
t.params.Set(key, value)
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *UrlCli) String() string {
|
||||
baseURL := t.url
|
||||
baseURL.RawQuery = t.params.Encode()
|
||||
return baseURL.String()
|
||||
}
|
31
pkg/myViper/viper.go
Normal file
31
pkg/myViper/viper.go
Normal file
@ -0,0 +1,31 @@
|
||||
package myViper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type SimpleViper struct {
|
||||
config interface{}
|
||||
configType string
|
||||
configName string
|
||||
configPath string
|
||||
}
|
||||
|
||||
func NewSimpleViper(config interface{}, configType string, configName string, configPath string) *SimpleViper {
|
||||
return &SimpleViper{config: config, configType: configType, configName: configName, configPath: configPath}
|
||||
}
|
||||
|
||||
func (t *SimpleViper) Apply() {
|
||||
v := viper.New()
|
||||
v.SetConfigFile(fmt.Sprintf("%s/%s.yaml", t.configPath, t.configName))
|
||||
v.SetConfigType(t.configType)
|
||||
err := v.ReadInConfig()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Fatal error config file: %s \n", err))
|
||||
}
|
||||
|
||||
if err := v.Unmarshal(t.config); err != nil {
|
||||
panic(fmt.Errorf("Fatal Unmarshal error config file: %s \n", err))
|
||||
}
|
||||
}
|
8
test/start_test.go
Normal file
8
test/start_test.go
Normal file
@ -0,0 +1,8 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStart(t *testing.T) {
|
||||
}
|
100
util/convert.go
Normal file
100
util/convert.go
Normal file
@ -0,0 +1,100 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// 字符串转Int
|
||||
// intStr:数字的字符串
|
||||
func String2Int(intStr string) (intNum int) {
|
||||
intNum, _ = strconv.Atoi(intStr)
|
||||
return
|
||||
}
|
||||
|
||||
// 字符串转Int64
|
||||
// intStr:数字的字符串
|
||||
func String2Int64(intStr string) (int64Num int64) {
|
||||
intNum, _ := strconv.Atoi(intStr)
|
||||
int64Num = int64(intNum)
|
||||
return
|
||||
}
|
||||
|
||||
// 字符串转Float64
|
||||
// floatStr:小数点数字的字符串
|
||||
func String2Float64(floatStr string) (floatNum float64) {
|
||||
floatNum, _ = strconv.ParseFloat(floatStr, 64)
|
||||
return
|
||||
}
|
||||
|
||||
// 字符串转Float32
|
||||
// floatStr:小数点数字的字符串
|
||||
func String2Float32(floatStr string) (floatNum float32) {
|
||||
floatNum64, _ := strconv.ParseFloat(floatStr, 32)
|
||||
floatNum = float32(floatNum64)
|
||||
return
|
||||
}
|
||||
|
||||
// Int转字符串
|
||||
// intNum:数字字符串
|
||||
func Int2String(intNum int) (intStr string) {
|
||||
intStr = strconv.Itoa(intNum)
|
||||
return
|
||||
}
|
||||
|
||||
// Int64转字符串
|
||||
// intNum:数字字符串
|
||||
func Int642String(intNum int64) (int64Str string) {
|
||||
//10, 代表10进制
|
||||
int64Str = strconv.FormatInt(intNum, 10)
|
||||
return
|
||||
}
|
||||
|
||||
// Float64转字符串
|
||||
// floatNum:float64数字
|
||||
// prec:精度位数(不传则默认float数字精度)
|
||||
func Float64ToString(floatNum float64, prec ...int) (floatStr string) {
|
||||
if len(prec) > 0 {
|
||||
floatStr = strconv.FormatFloat(floatNum, 'f', prec[0], 64)
|
||||
return
|
||||
}
|
||||
floatStr = strconv.FormatFloat(floatNum, 'f', -1, 64)
|
||||
return
|
||||
}
|
||||
|
||||
// Float32转字符串
|
||||
// floatNum:float32数字
|
||||
// prec:精度位数(不传则默认float数字精度)
|
||||
func Float32ToString(floatNum float32, prec ...int) (floatStr string) {
|
||||
if len(prec) > 0 {
|
||||
floatStr = strconv.FormatFloat(float64(floatNum), 'f', prec[0], 32)
|
||||
return
|
||||
}
|
||||
floatStr = strconv.FormatFloat(float64(floatNum), 'f', -1, 32)
|
||||
return
|
||||
}
|
||||
|
||||
// 二进制转10进制
|
||||
func BinaryToDecimal(bit string) (num int) {
|
||||
fields := strings.Split(bit, "")
|
||||
lens := len(fields)
|
||||
var tempF float64 = 0
|
||||
for i := 0; i < lens; i++ {
|
||||
floatNum := String2Float64(fields[i])
|
||||
tempF += floatNum * math.Pow(2, float64(lens-i-1))
|
||||
}
|
||||
num = int(tempF)
|
||||
return
|
||||
}
|
||||
|
||||
// BytesToString 0 拷贝转换 slice byte 为 string
|
||||
func BytesToString(b []byte) (s string) {
|
||||
_bptr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
_sptr := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||
_sptr.Data = _bptr.Data
|
||||
_sptr.Len = _bptr.Len
|
||||
return s
|
||||
}
|
12
util/md5.go
Normal file
12
util/md5.go
Normal file
@ -0,0 +1,12 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
func EncodeMD5(value string) string {
|
||||
m := md5.New()
|
||||
m.Write([]byte(value))
|
||||
return hex.EncodeToString(m.Sum(nil))
|
||||
}
|
36
util/password/password.go
Normal file
36
util/password/password.go
Normal file
@ -0,0 +1,36 @@
|
||||
package password
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"errors"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func Encode(userPassword string) (string, error) {
|
||||
md5Password := md5.Sum([]byte(userPassword))
|
||||
encode, err := generatePassword(string(md5Password[:]))
|
||||
if err != nil {
|
||||
return "", errors.New("密码加密失败")
|
||||
} else {
|
||||
return string(encode), nil
|
||||
}
|
||||
}
|
||||
func ValidateCode(userPassword string, hashed string) (isOK bool, err error) {
|
||||
md5Password := md5.Sum([]byte(userPassword))
|
||||
isOk, err := validatePassword(string(md5Password[:]), hashed)
|
||||
return isOk, err
|
||||
}
|
||||
|
||||
//generatePassword 给密码就行加密操作
|
||||
func generatePassword(userPassword string) ([]byte, error) {
|
||||
return bcrypt.GenerateFromPassword([]byte(userPassword), bcrypt.DefaultCost)
|
||||
}
|
||||
|
||||
//validatePassword 密码比对
|
||||
func validatePassword(userPassword string, hashed string) (isOK bool, err error) {
|
||||
if err = bcrypt.CompareHashAndPassword([]byte(hashed), []byte(userPassword)); err != nil {
|
||||
return false, errors.New("密码错误!")
|
||||
}
|
||||
return true, nil
|
||||
|
||||
}
|
42
util/random.go
Normal file
42
util/random.go
Normal file
@ -0,0 +1,42 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 随机生成字符串
|
||||
func RandomString(l int) string {
|
||||
str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
|
||||
bytes := []byte(str)
|
||||
var result []byte = make([]byte, 0, l)
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
for i := 0; i < l; i++ {
|
||||
result = append(result, bytes[r.Intn(len(bytes))])
|
||||
}
|
||||
return BytesToString(result)
|
||||
}
|
||||
|
||||
// 随机生成纯字符串
|
||||
func RandomPureString(l int) string {
|
||||
str := "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
|
||||
bytes := []byte(str)
|
||||
var result []byte = make([]byte, 0, l)
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
for i := 0; i < l; i++ {
|
||||
result = append(result, bytes[r.Intn(len(bytes))])
|
||||
}
|
||||
return BytesToString(result)
|
||||
}
|
||||
|
||||
// 随机生成数字字符串
|
||||
func RandomNumber(l int) string {
|
||||
str := "0123456789"
|
||||
bytes := []byte(str)
|
||||
var result []byte
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
for i := 0; i < l; i++ {
|
||||
result = append(result, bytes[r.Intn(len(bytes))])
|
||||
}
|
||||
return BytesToString(result)
|
||||
}
|
104
util/string.go
Normal file
104
util/string.go
Normal file
@ -0,0 +1,104 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
//判断是否是数字字符串
|
||||
func IsDigit(str string) bool {
|
||||
for _, x := range []rune(str) {
|
||||
if !unicode.IsDigit(x) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func Atoi(i string) int {
|
||||
if i == "" {
|
||||
return 0
|
||||
}
|
||||
j, err := strconv.Atoi(i)
|
||||
if err != nil {
|
||||
return 0
|
||||
} else {
|
||||
return j
|
||||
}
|
||||
}
|
||||
|
||||
func StringToInt(s interface{}) int {
|
||||
switch i := s.(type) {
|
||||
case string:
|
||||
return Atoi(i)
|
||||
case float32:
|
||||
return int(i)
|
||||
case float64:
|
||||
return int(i)
|
||||
case int:
|
||||
return i
|
||||
case uint:
|
||||
return int(i)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰转蛇形 snake string
|
||||
* @description XxYy to xx_yy , XxYY to xx_y_y
|
||||
* @date 2020/7/30
|
||||
* @param s 需要转换的字符串
|
||||
* @return string
|
||||
**/
|
||||
func SnakeString(s string) string {
|
||||
data := make([]byte, 0, len(s)*2)
|
||||
j := false
|
||||
num := len(s)
|
||||
for i := 0; i < num; i++ {
|
||||
d := s[i]
|
||||
// or通过ASCII码进行大小写的转化
|
||||
// 65-90(A-Z),97-122(a-z)
|
||||
//判断如果字母为大写的A-Z就在前面拼接一个_
|
||||
if i > 0 && d >= 'A' && d <= 'Z' && j {
|
||||
data = append(data, '_')
|
||||
}
|
||||
if d != '_' {
|
||||
j = true
|
||||
}
|
||||
data = append(data, d)
|
||||
}
|
||||
//ToLower把大写字母统一转小写
|
||||
return strings.ToLower(string(data[:]))
|
||||
}
|
||||
|
||||
/**
|
||||
* 蛇形转驼峰
|
||||
* @description xx_yy to XxYx xx_y_y to XxYY
|
||||
* @date 2020/7/30
|
||||
* @param s要转换的字符串
|
||||
* @return string
|
||||
**/
|
||||
func CamelString(s string) string {
|
||||
data := make([]byte, 0, len(s))
|
||||
j := false
|
||||
k := false
|
||||
num := len(s) - 1
|
||||
for i := 0; i <= num; i++ {
|
||||
d := s[i]
|
||||
if k == false && d >= 'A' && d <= 'Z' {
|
||||
k = true
|
||||
}
|
||||
if d >= 'a' && d <= 'z' && (j || k == false) {
|
||||
d = d - 32
|
||||
j = false
|
||||
k = true
|
||||
}
|
||||
if k && d == '_' && num > i && s[i+1] >= 'a' && s[i+1] <= 'z' {
|
||||
j = true
|
||||
continue
|
||||
}
|
||||
data = append(data, d)
|
||||
}
|
||||
return string(data[:])
|
||||
}
|
13
util/validator.go
Normal file
13
util/validator.go
Normal file
@ -0,0 +1,13 @@
|
||||
package util
|
||||
|
||||
import "regexp"
|
||||
|
||||
// 识别手机号码
|
||||
func IsMobile(mobile string) bool {
|
||||
result, _ := regexp.MatchString(`^(1[0-9][0-9]\d{4,8})$`, mobile)
|
||||
if result {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user