Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee9e399a81 | ||
|
|
ed9b0dd248 | ||
|
|
02edbdae8d | ||
|
|
5e75094c16 | ||
|
|
140317e2df | ||
|
|
8e2301eb34 | ||
|
|
c673da89cf | ||
|
|
005cf11b2a | ||
|
|
8195d633a1 |
@@ -1,9 +1,9 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ayflying/utility_go"
|
"github.com/ayflying/utility_go/pkg"
|
||||||
"github.com/gogf/gf/v2/util/gutil"
|
"github.com/gogf/gf/v2/util/gutil"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type {cfg}Cfg struct {
|
type {cfg}Cfg struct {
|
||||||
@@ -23,7 +23,7 @@ func (c *{mod}Mod) Load(_cfg ...string) {
|
|||||||
c.lock.Lock()
|
c.lock.Lock()
|
||||||
defer c.lock.Unlock()
|
defer c.lock.Unlock()
|
||||||
c.cfgArr = make([]*{cfg}Cfg, 0)
|
c.cfgArr = make([]*{cfg}Cfg, 0)
|
||||||
data, err := utility_go.Config.GetFile("{file}")
|
data, err := pkg.Config().GetFile("{file}")
|
||||||
err = data.Scan(&c.cfgArr)
|
err = data.Scan(&c.cfgArr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -4,7 +4,7 @@ go 1.24.0
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/apolloconfig/agollo/v4 v4.4.0
|
github.com/apolloconfig/agollo/v4 v4.4.0
|
||||||
github.com/ayflying/excel2json v1.1.8
|
github.com/ayflying/excel2json v1.1.9
|
||||||
github.com/elastic/go-elasticsearch/v8 v8.18.0
|
github.com/elastic/go-elasticsearch/v8 v8.18.0
|
||||||
github.com/go-pay/crypto v0.0.1
|
github.com/go-pay/crypto v0.0.1
|
||||||
github.com/go-pay/gopay v1.5.109
|
github.com/go-pay/gopay v1.5.109
|
||||||
|
|||||||
5
go.sum
5
go.sum
@@ -50,9 +50,8 @@ github.com/apolloconfig/agollo/v4 v4.4.0/go.mod h1:6WjI68IzqMk/Y6ghMtrj5AX6Uewo2
|
|||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/ayflying/excel2json v1.1.7 h1:gp4Ls6hNXd1EuT2MEiDQ6yPLaSKIFWkGyaNajMTc59c=
|
github.com/ayflying/excel2json v1.1.9 h1:AKaUFc/FNQXV/53/VSgp3J+2d4PMWhVpTDRj/yx3VOs=
|
||||||
github.com/ayflying/excel2json v1.1.7/go.mod h1:GjXYP2cDzeTgQxssQ3ba8QRa9JsScAeJMwCrZ7QTlQo=
|
github.com/ayflying/excel2json v1.1.9/go.mod h1:GjXYP2cDzeTgQxssQ3ba8QRa9JsScAeJMwCrZ7QTlQo=
|
||||||
github.com/ayflying/excel2json v1.1.8/go.mod h1:GjXYP2cDzeTgQxssQ3ba8QRa9JsScAeJMwCrZ7QTlQo=
|
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
|
|||||||
103
package/pay/taptap/sign.go
Normal file
103
package/pay/taptap/sign.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package taptap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pTapTap struct {
|
||||||
|
Secret string `json:"secret" dc:"秘钥"`
|
||||||
|
//OrderId string `json:"order_id" dc:"订单唯一 ID"`
|
||||||
|
ClientId string `json:"client_id" dc:"应用的 Client ID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(clientId string, secret string) *pTapTap {
|
||||||
|
return &pTapTap{
|
||||||
|
Secret: secret,
|
||||||
|
ClientId: clientId,
|
||||||
|
//OrderId: orderId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign signs the request.
|
||||||
|
func (p *pTapTap) Sign(req *http.Request, secret string) (string, error) {
|
||||||
|
//获取请求参数
|
||||||
|
//req := g.RequestFromCtx(ctx).Request
|
||||||
|
return Sign(req, secret)
|
||||||
|
}
|
||||||
|
|
||||||
|
//func (p *pTapTap) SignOld(ctx context.Context, method, url string, token string, data any) (sign string, ts int64, nonce string, err error) {
|
||||||
|
// //secret := p.Secret
|
||||||
|
// //ts = gtime.Now().Unix()
|
||||||
|
// //nonce = grand.S(5)
|
||||||
|
// //header := http.Header{
|
||||||
|
// // "Content-Type": {"Content-Type: application/json; charset=utf-8"},
|
||||||
|
// // "X-Tap-Ts": {strconv.FormatInt(ts, 10)},
|
||||||
|
// // "X-Tap-Nonce": {nonce},
|
||||||
|
// //}
|
||||||
|
// //if method == "POST" {
|
||||||
|
// // header.Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
// //}
|
||||||
|
// ////ctx := context.Background()
|
||||||
|
// //request := g.RequestFromCtx(ctx).Request
|
||||||
|
// //body, _ := json.Marshal(data)
|
||||||
|
// ////req, err := http.NewRequestWithContext(ctx, method, url, strings.NewReader(string(body)))
|
||||||
|
// //req.Header = header
|
||||||
|
// //sign, err = Sign(req, secret)
|
||||||
|
// //if err != nil {
|
||||||
|
// // panic(err)
|
||||||
|
// //}
|
||||||
|
// //req.Header.Set("X-Tap-Sign", sign)
|
||||||
|
// //return
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Sign signs the request.
|
||||||
|
func Sign(req *http.Request, secret string) (string, error) {
|
||||||
|
methodPart := req.Method
|
||||||
|
urlPathAndQueryPart := req.URL.RequestURI()
|
||||||
|
headersPart, err := getHeadersPart(req.Header)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
bodyPart, err := io.ReadAll(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
signParts := methodPart + "\n" + urlPathAndQueryPart + "\n" + headersPart + "\n" + string(bodyPart) + "\n"
|
||||||
|
fmt.Println(signParts)
|
||||||
|
h := hmac.New(sha256.New, []byte(secret))
|
||||||
|
h.Write([]byte(signParts))
|
||||||
|
rawSign := h.Sum(nil)
|
||||||
|
sign := base64.StdEncoding.EncodeToString(rawSign)
|
||||||
|
return sign, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getHeadersPart returns the headers part of the request.
|
||||||
|
func getHeadersPart(header http.Header) (string, error) {
|
||||||
|
var headerKeys []string
|
||||||
|
for k, v := range header {
|
||||||
|
k = strings.ToLower(k)
|
||||||
|
if !strings.HasPrefix(k, "x-tap-") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if k == "x-tap-sign" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(v) > 1 {
|
||||||
|
return "", fmt.Errorf("invalid header, %q has multiple values", k)
|
||||||
|
}
|
||||||
|
headerKeys = append(headerKeys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(headerKeys)
|
||||||
|
headers := make([]string, 0, len(headerKeys))
|
||||||
|
for _, k := range headerKeys {
|
||||||
|
headers = append(headers, fmt.Sprintf("%s:%s", k, header.Get(k)))
|
||||||
|
}
|
||||||
|
return strings.Join(headers, "\n"), nil
|
||||||
|
}
|
||||||
129
package/pay/taptap/taptap.go
Normal file
129
package/pay/taptap/taptap.go
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
package taptap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gogf/gf/v2/encoding/gjson"
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
"github.com/gogf/gf/v2/net/gclient"
|
||||||
|
"github.com/gogf/gf/v2/os/gctx"
|
||||||
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
|
"github.com/gogf/gf/v2/util/grand"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetPayData struct {
|
||||||
|
Data struct {
|
||||||
|
Order struct {
|
||||||
|
Order
|
||||||
|
} `json:"order"`
|
||||||
|
} `json:"data"`
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Order struct {
|
||||||
|
OrderID string `json:"order_id"` // 订单唯一 ID
|
||||||
|
PurchaseToken string `json:"purchase_token"` // 用于订单核销的 token
|
||||||
|
ClientID string `json:"client_id"` // 应用的 Client ID
|
||||||
|
OpenID string `json:"open_id"` // 用户的开放平台 ID
|
||||||
|
UserRegion string `json:"user_region"` // 用户地区
|
||||||
|
GoodsOpenID string `json:"goods_open_id"` // 商品唯一 ID
|
||||||
|
GoodsName string `json:"goods_name"` // 商品名称
|
||||||
|
Status PaymentStatus `json:"status"` // 订单状态
|
||||||
|
Amount string `json:"amount"` // 金额(本币金额 x 1,000,000)
|
||||||
|
Currency string `json:"currency"` // 币种
|
||||||
|
CreateTime string `json:"create_time"` // 创建时间
|
||||||
|
PayTime string `json:"pay_time"` // 支付时间
|
||||||
|
Extra string `json:"extra"` // 商户自定义数据,如角色信息等,长度不超过 255 UTF-8 字符
|
||||||
|
}
|
||||||
|
type PaymentStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ChargePending PaymentStatus = "charge.pending" // 待支付
|
||||||
|
ChargeSucceeded PaymentStatus = "charge.succeeded" //支付成功
|
||||||
|
ChargeConfirmed PaymentStatus = "charge.confirmed" //已核销
|
||||||
|
ChargeOverdue PaymentStatus = "charge.overdue" //支付超时关闭
|
||||||
|
RefundPending PaymentStatus = "refund.pending" //退款中
|
||||||
|
RefundSucceeded PaymentStatus = "refund.succeeded" //退款成功
|
||||||
|
RefundFailed PaymentStatus = "refund.failed" //退款失败
|
||||||
|
RefundRejected PaymentStatus = "refund.rejected" //退款被拒绝
|
||||||
|
)
|
||||||
|
|
||||||
|
// 查询订单信息
|
||||||
|
func (p *pTapTap) Info(ctx context.Context, order string) (getPayData *GetPayData, err error) {
|
||||||
|
url := fmt.Sprintf("https://cloud-payment.tapapis.cn/order/v1/info?client_id=%v&order_id=%v", p.ClientId, order)
|
||||||
|
getPayData, err = p.get(ctx, url)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证并核销订单
|
||||||
|
func (p *pTapTap) Verify(ctx context.Context, req any) (getPayData *GetPayData, err error) {
|
||||||
|
url := fmt.Sprintf("https://cloud-payment.tapapis.cn/order/v1/verify?client_id=%v", p.ClientId)
|
||||||
|
getPayData, err = p.get(ctx, url, req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pTapTap) get(ctx context.Context, url string, _data ...any) (getPayData *GetPayData, err error) {
|
||||||
|
|
||||||
|
var _get *gclient.Response
|
||||||
|
|
||||||
|
var header = map[string]string{
|
||||||
|
"Content-Type": "Content-Type: application/json; charset=utf-8",
|
||||||
|
"X-Tap-Nonce": grand.S(6),
|
||||||
|
"X-Tap-Ts": gtime.Now().TimestampStr(),
|
||||||
|
}
|
||||||
|
ctx2 := context.Background()
|
||||||
|
var method = "GET"
|
||||||
|
if len(_data) > 0 {
|
||||||
|
method = "POST"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//temp := []byte(`{"event_type":"charge.succeeded","order":{"order_id":"1790288650833465345","purchase_token":"rT2Et9p0cfzq4fwjrTsGSacq0jQExFDqf5gTy1alp+Y=","client_id":"o6nD4iNavjQj75zPQk","open_id":"4+Axcl2RFgXbt6MZwdh++w==","user_region":"US","goods_open_id":"com.goods.open_id","goods_name":"TestGoodsName","status":"charge.succeeded","amount":"19000000000","currency":"USD","create_time":"1716168000","pay_time":"1716168000","extra":"1111111111111111111"}}`)
|
||||||
|
var body io.Reader
|
||||||
|
if len(_data) > 0 {
|
||||||
|
body = bytes.NewBuffer(gjson.MustEncode(_data[0]))
|
||||||
|
} else {
|
||||||
|
body = bytes.NewBuffer([]byte{})
|
||||||
|
}
|
||||||
|
req, _ := http.NewRequestWithContext(ctx2, method, url, body)
|
||||||
|
for k, v := range header {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
sign, err2 := p.Sign(req, p.Secret)
|
||||||
|
if err2 != nil {
|
||||||
|
err = err2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Header.Set("X-Tap-Sign", sign)
|
||||||
|
header["X-Tap-Sign"] = sign
|
||||||
|
if len(_data) == 0 {
|
||||||
|
_get, err = g.Client().Header(header).ContentJson().Get(gctx.New(), url)
|
||||||
|
} else {
|
||||||
|
_get, err = g.Client().Header(header).ContentJson().Post(gctx.New(), url, _data[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
getPayData = &GetPayData{}
|
||||||
|
resData := _get.ReadAll()
|
||||||
|
g.Dump(resData)
|
||||||
|
if err = json.Unmarshal(resData, &getPayData); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !getPayData.Success {
|
||||||
|
err = errors.New(string(resData))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
63
package/pay/xiaomi/helper.go
Normal file
63
package/pay/xiaomi/helper.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package xiaomi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SignatureHelper 签名辅助类
|
||||||
|
type SignatureHelper struct{}
|
||||||
|
|
||||||
|
// hmacSHA1 计算HMAC-SHA1哈希值
|
||||||
|
func hmacSHA1(data, key string) string {
|
||||||
|
h := hmac.New(sha1.New, []byte(key))
|
||||||
|
h.Write([]byte(data))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign 计算hmac-sha1签名
|
||||||
|
func (m *MiPay) Sign(params map[string]string, secretKey string) string {
|
||||||
|
if _, ok := params["signature"]; ok {
|
||||||
|
delete(params, "signature")
|
||||||
|
}
|
||||||
|
for k, v := range params {
|
||||||
|
if v == "" || v == "0" {
|
||||||
|
delete(params, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sortString := m.buildSortString(params)
|
||||||
|
signature := hmacSHA1(sortString, secretKey)
|
||||||
|
return signature
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifySignature 验证签名
|
||||||
|
func (m *MiPay) VerifySignature(params map[string]string, signature, secretKey string) bool {
|
||||||
|
tmpSign := m.Sign(params, secretKey)
|
||||||
|
return tmpSign == signature
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildSortString 构造排序字符串
|
||||||
|
func (m *MiPay) buildSortString(params map[string]string) string {
|
||||||
|
if len(params) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按键排序
|
||||||
|
keys := make([]string, 0, len(params))
|
||||||
|
for k := range params {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
// 构建排序字符串
|
||||||
|
var fields []string
|
||||||
|
for _, k := range keys {
|
||||||
|
fields = append(fields, fmt.Sprintf("%s=%s", k, params[k]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(fields, "&")
|
||||||
|
}
|
||||||
29
package/pay/xiaomi/xiaomi.go
Normal file
29
package/pay/xiaomi/xiaomi.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package xiaomi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
"github.com/gogf/gf/v2/os/gctx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config 小米支付配置信息
|
||||||
|
type Config struct {
|
||||||
|
AppID string `json:"app_id"` // 应用ID
|
||||||
|
AppSecret string `json:"app_secret"` // 应用密钥
|
||||||
|
//PrivateKey string // 商户私钥(如需证书)
|
||||||
|
//MIAPIURL string // 小米支付API基础地址
|
||||||
|
//IsSandbox bool // 是否沙箱环境
|
||||||
|
}
|
||||||
|
|
||||||
|
// Miipay 小米支付客户端
|
||||||
|
type MiPay struct {
|
||||||
|
config *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *MiPay {
|
||||||
|
_cfg, _ := g.Cfg().Get(gctx.New(), "pay.xiaomi")
|
||||||
|
var cfg *Config
|
||||||
|
_cfg.Scan(&cfg)
|
||||||
|
return &MiPay{
|
||||||
|
config: cfg,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/gogf/gf/v2/crypto/gmd5"
|
"github.com/gogf/gf/v2/crypto/gmd5"
|
||||||
"github.com/gogf/gf/v2/encoding/gjson"
|
"github.com/gogf/gf/v2/encoding/gjson"
|
||||||
"github.com/gogf/gf/v2/os/gcache"
|
"github.com/gogf/gf/v2/os/gcache"
|
||||||
|
"github.com/gogf/gf/v2/os/gctx"
|
||||||
"github.com/gogf/gf/v2/os/gfile"
|
"github.com/gogf/gf/v2/os/gfile"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
@@ -80,7 +81,7 @@ func (a *AdapterFile) DelIndex(FileName interface{}) {
|
|||||||
arr := strings.Split(text, "|")
|
arr := strings.Split(text, "|")
|
||||||
if arr[0] == FileName {
|
if arr[0] == FileName {
|
||||||
//save = true
|
//save = true
|
||||||
err = gfile.ReplaceFile(text, "", fileIndex)
|
err = gfile.ReplaceFile(text+"\n", "", fileIndex)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,11 +185,12 @@ func (a *AdapterFile) Data(ctx context.Context) (data map[interface{}]interface{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *AdapterFile) Keys(ctx context.Context) (keys []interface{}, err error) {
|
func (a *AdapterFile) Keys(ctx context.Context) (keys []interface{}, err error) {
|
||||||
|
keys = make([]interface{}, 0)
|
||||||
gfile.ReadLines(fileIndex, func(text string) (err error) {
|
gfile.ReadLines(fileIndex, func(text string) (err error) {
|
||||||
|
arr := strings.Split(text, "|")
|
||||||
|
keys = append(keys, arr[0])
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +250,23 @@ func (a *AdapterFile) Close(ctx context.Context) error {
|
|||||||
|
|
||||||
func NewAdapterFile(filePath string) gcache.Adapter {
|
func NewAdapterFile(filePath string) gcache.Adapter {
|
||||||
fileIndex = path.Join(filePath, fileIndex)
|
fileIndex = path.Join(filePath, fileIndex)
|
||||||
return &AdapterFile{
|
|
||||||
|
//清空过期文件目录
|
||||||
|
delKeys := make([]interface{}, 0)
|
||||||
|
gfile.ReadLines(fileIndex, func(text string) error {
|
||||||
|
arr := strings.Split(text, "|")
|
||||||
|
if gtime.Now().Unix() > gconv.Int64(arr[1]) {
|
||||||
|
delKeys = append(delKeys, arr[0])
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
obj := &AdapterFile{
|
||||||
FilePath: filePath,
|
FilePath: filePath,
|
||||||
}
|
}
|
||||||
|
if len(delKeys) > 0 {
|
||||||
|
obj.Remove(gctx.New(), delKeys...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/elastic/go-elasticsearch/v8/typedapi/types"
|
"github.com/elastic/go-elasticsearch/v8/typedapi/types"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gctx"
|
"github.com/gogf/gf/v2/os/gctx"
|
||||||
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -23,6 +24,13 @@ type Elastic struct {
|
|||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type elkBulk struct {
|
||||||
|
Index struct {
|
||||||
|
Index string `json:"_index"`
|
||||||
|
Id string `json:"_id"`
|
||||||
|
} `json:"index"`
|
||||||
|
}
|
||||||
|
|
||||||
func NewV1(name string) *Elastic {
|
func NewV1(name string) *Elastic {
|
||||||
var cfg elasticsearch.Config
|
var cfg elasticsearch.Config
|
||||||
_cfg := g.Cfg().MustGetWithEnv(gctx.New(), "elasticsearch")
|
_cfg := g.Cfg().MustGetWithEnv(gctx.New(), "elasticsearch")
|
||||||
@@ -52,7 +60,7 @@ func NewV1(name string) *Elastic {
|
|||||||
// fmt.Printf("index:%#v\n", resp.Index)
|
// fmt.Printf("index:%#v\n", resp.Index)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// Set 索引文档
|
// Set 添加文档索引文档
|
||||||
func (s *Elastic) Set(ctx context.Context, key string, data interface{}) (err error) {
|
func (s *Elastic) Set(ctx context.Context, key string, data interface{}) (err error) {
|
||||||
// 添加文档
|
// 添加文档
|
||||||
_, err = s.client.Index(s.name).Id(key).Document(data).Do(ctx)
|
_, err = s.client.Index(s.name).Id(key).Document(data).Do(ctx)
|
||||||
@@ -61,11 +69,20 @@ func (s *Elastic) Set(ctx context.Context, key string, data interface{}) (err er
|
|||||||
|
|
||||||
// SetBulk 批量添加文档
|
// SetBulk 批量添加文档
|
||||||
func (s *Elastic) SetBulk(ctx context.Context, data []any) (err error) {
|
func (s *Elastic) SetBulk(ctx context.Context, data []any) (err error) {
|
||||||
var save *bulk.Request
|
var save bulk.Request
|
||||||
save = &bulk.Request{
|
save = make(bulk.Request, 0)
|
||||||
data,
|
for _, v := range data {
|
||||||
|
val := gconv.Map(v)
|
||||||
|
var saveIndex = elkBulk{}
|
||||||
|
saveIndex.Index.Index = s.name
|
||||||
|
if _, ok := val["uuid"]; ok {
|
||||||
|
saveIndex.Index.Id = val["uuid"].(string)
|
||||||
|
}
|
||||||
|
save = append(save, saveIndex)
|
||||||
|
save = append(save, v)
|
||||||
}
|
}
|
||||||
s.client.Bulk().Index(s.name).Request(save).Do(ctx)
|
//save = data
|
||||||
|
_, err = s.client.Bulk().Index(s.name).Request(&save).Do(ctx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
37
pkg/s3/s3.go
37
pkg/s3/s3.go
@@ -24,13 +24,14 @@ var (
|
|||||||
|
|
||||||
// DataType 定义了 S3 配置的数据结构,用于存储访问 S3 所需的各种信息
|
// DataType 定义了 S3 配置的数据结构,用于存储访问 S3 所需的各种信息
|
||||||
type DataType struct {
|
type DataType struct {
|
||||||
AccessKey string `json:"access_key"` // 访问 S3 的密钥 ID
|
AccessKey string `json:"access_key"` // 访问 S3 的密钥 ID
|
||||||
SecretKey string `json:"secret_key"` // 访问 S3 的密钥
|
SecretKey string `json:"secret_key"` // 访问 S3 的密钥
|
||||||
Address string `json:"address"` // S3 服务的地址
|
Address string `json:"address"` // S3 服务的地址
|
||||||
Ssl bool `json:"ssl"` // 是否使用 SSL 加密连接
|
Ssl bool `json:"ssl"` // 是否使用 SSL 加密连接
|
||||||
Url string `json:"url"` // S3 服务的访问 URL
|
Url string `json:"url"` // S3 服务的访问 URL
|
||||||
BucketName string `json:"bucket_name"` // 默认存储桶名称
|
BucketName string `json:"bucket_name"` // 默认存储桶名称
|
||||||
BucketNameCdn string `json:"bucket_name_cdn"` // CDN 存储桶名称
|
BucketNameCdn string `json:"bucket_name_cdn"` // CDN 存储桶名称
|
||||||
|
Provider string `json:"provider"` // S3 服务的提供方
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mod 定义了 S3 模块的结构体,包含一个 S3 客户端实例和配置信息
|
// Mod 定义了 S3 模块的结构体,包含一个 S3 客户端实例和配置信息
|
||||||
@@ -64,6 +65,7 @@ func New(_name ...string) *Mod {
|
|||||||
&minio.Options{
|
&minio.Options{
|
||||||
Creds: credentials.NewStaticV4(cfg.AccessKey, cfg.SecretKey, ""),
|
Creds: credentials.NewStaticV4(cfg.AccessKey, cfg.SecretKey, ""),
|
||||||
Secure: cfg.Ssl,
|
Secure: cfg.Ssl,
|
||||||
|
//BucketLookup: minio.BucketLookupPath,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -133,11 +135,13 @@ func (s *Mod) ListBuckets() []minio.BucketInfo {
|
|||||||
func (s *Mod) PutObject(f io.Reader, name string, bucketName string, _size ...int64) (res minio.UploadInfo, err error) {
|
func (s *Mod) PutObject(f io.Reader, name string, bucketName string, _size ...int64) (res minio.UploadInfo, err error) {
|
||||||
// 初始化文件大小为 -1,表示将读取文件至结束
|
// 初始化文件大小为 -1,表示将读取文件至结束
|
||||||
var size = int64(-1)
|
var size = int64(-1)
|
||||||
if len(_size) > 0 {
|
//if len(_size) > 0 {
|
||||||
size = _size[0]
|
// size = _size[0]
|
||||||
}
|
//}
|
||||||
// 调用 S3 客户端上传文件,设置内容类型为 "application/octet-stream"
|
// 调用 S3 客户端上传文件,设置内容类型为 "application/octet-stream"
|
||||||
res, err = s.client.PutObject(ctx, bucketName, name, f, size, minio.PutObjectOptions{ContentType: "application/octet-stream"})
|
res, err = s.client.PutObject(ctx, bucketName, name, f, size, minio.PutObjectOptions{
|
||||||
|
//ContentType: "application/octet-stream",
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// 记录上传错误日志
|
// 记录上传错误日志
|
||||||
g.Log().Error(ctx, err)
|
g.Log().Error(ctx, err)
|
||||||
@@ -148,6 +152,7 @@ func (s *Mod) PutObject(f io.Reader, name string, bucketName string, _size ...in
|
|||||||
// RemoveObject 从指定存储桶中删除指定名称的文件
|
// RemoveObject 从指定存储桶中删除指定名称的文件
|
||||||
func (s *Mod) RemoveObject(name string, bucketName string) (err error) {
|
func (s *Mod) RemoveObject(name string, bucketName string) (err error) {
|
||||||
opts := minio.RemoveObjectOptions{
|
opts := minio.RemoveObjectOptions{
|
||||||
|
ForceDelete: true,
|
||||||
//GovernanceBypass: true,
|
//GovernanceBypass: true,
|
||||||
//VersionID: "myversionid",
|
//VersionID: "myversionid",
|
||||||
}
|
}
|
||||||
@@ -187,9 +192,15 @@ func (s *Mod) GetUrl(filePath string, defaultFile ...string) (url string) {
|
|||||||
filePath = defaultFile[0]
|
filePath = defaultFile[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.cfg.Ssl {
|
//switch s.cfg.Provider {
|
||||||
url = get + filePath
|
//case "qiniu":
|
||||||
} else {
|
// url = get + path.Join(bucketName, filePath)
|
||||||
|
//default:
|
||||||
|
// url = get + filePath
|
||||||
|
//}
|
||||||
|
url = get + filePath
|
||||||
|
|
||||||
|
if !s.cfg.Ssl {
|
||||||
url = get + path.Join(bucketName, filePath)
|
url = get + path.Join(bucketName, filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user