Compare commits
24 Commits
af3a8435b9
...
d2ae9e258b
| Author | SHA1 | Date |
|---|---|---|
|
|
d2ae9e258b | |
|
|
f4c1cdb283 | |
|
|
d350e22c50 | |
|
|
1e1d966023 | |
|
|
e45b0d8b95 | |
|
|
271a3579a1 | |
|
|
0820c34450 | |
|
|
ccc7894e50 | |
|
|
4489f801ca | |
|
|
2f86b5dd30 | |
|
|
74725d735d | |
|
|
593342b848 | |
|
|
43d91bd3d8 | |
|
|
6770bae66a | |
|
|
863d64b53a | |
|
|
006c8de201 | |
|
|
3458c6fc4e | |
|
|
086162dc67 | |
|
|
bfdd9339e6 | |
|
|
d74c2284cf | |
|
|
b456c3da06 | |
|
|
010cacb4b1 | |
|
|
0d82e7521f | |
|
|
9c46469b67 |
|
|
@ -10,3 +10,4 @@ test
|
|||
go.sum
|
||||
pkg
|
||||
test.go
|
||||
.claude
|
||||
|
|
|
|||
18
go.mod
18
go.mod
|
|
@ -7,7 +7,9 @@ require (
|
|||
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf
|
||||
github.com/eclipse/paho.mqtt.golang v1.5.1
|
||||
github.com/gin-gonic/gin v1.11.0
|
||||
github.com/go-redis/redis v6.15.9+incompatible
|
||||
github.com/gomodule/redigo v1.9.2
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
||||
github.com/minio/minio-go v6.0.14+incompatible
|
||||
github.com/qiniu/go-sdk/v7 v7.25.4
|
||||
|
|
@ -15,7 +17,7 @@ require (
|
|||
github.com/spf13/cast v1.10.0
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.21
|
||||
golang.org/x/crypto v0.42.0
|
||||
golang.org/x/crypto v0.47.0
|
||||
gorm.io/gorm v1.31.0
|
||||
)
|
||||
|
||||
|
|
@ -47,6 +49,8 @@ require (
|
|||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/onsi/gomega v1.39.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.54.0 // indirect
|
||||
|
|
@ -58,12 +62,12 @@ require (
|
|||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/arch v0.20.0 // indirect
|
||||
golang.org/x/image v0.31.0 // indirect
|
||||
golang.org/x/mod v0.27.0 // indirect
|
||||
golang.org/x/net v0.44.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.36.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/tools v0.36.0 // indirect
|
||||
golang.org/x/mod v0.32.0 // indirect
|
||||
golang.org/x/net v0.49.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.40.0 // indirect
|
||||
golang.org/x/text v0.33.0 // indirect
|
||||
golang.org/x/tools v0.41.0 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
modernc.org/fileutil v1.0.0 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -316,6 +316,11 @@ func (a *App) Upload(path, kind string) (string, error) {
|
|||
return cast.ToString(result["media_id"]), nil
|
||||
}
|
||||
|
||||
func (a *App) MediaUrl(mediaId string) string {
|
||||
mUrl := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s", a.GetToken(), mediaId)
|
||||
return mUrl
|
||||
}
|
||||
|
||||
func (q *App) GetJsapiConfig(url string) (*JsapiConfig, error) {
|
||||
ticket, err := q.getJsapiTicket()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ package qyweixin
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.u8t.cn/open/gosdk/util"
|
||||
"git.u8t.cn/open/goutil"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cast"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Applyer struct {
|
||||
|
|
@ -90,57 +91,8 @@ type AppApprove struct {
|
|||
}
|
||||
|
||||
func (d *ApproveDetail) GetValue(title string) string {
|
||||
|
||||
for _, content := range d.ApplyData.Contents {
|
||||
|
||||
isEqual := false
|
||||
for _, ti := range content.Title {
|
||||
if ti.Text == title {
|
||||
isEqual = true
|
||||
}
|
||||
}
|
||||
|
||||
if !isEqual {
|
||||
continue
|
||||
}
|
||||
|
||||
var value string
|
||||
if content.Control == "Selector" {
|
||||
for _, v := range content.Value.Selector.Options[0].Value {
|
||||
if v.Text != "" {
|
||||
value = v.Text
|
||||
}
|
||||
}
|
||||
} else if content.Control == "Text" || content.Control == "Textarea" {
|
||||
value = content.Value.Text
|
||||
} else if content.Control == "Date" {
|
||||
value = content.Value.Date.Timestamp
|
||||
} else if content.Control == "Money" {
|
||||
value = content.Value.NewMoney
|
||||
} else if content.Control == "File" {
|
||||
value = content.Value.Files[0].FileId
|
||||
} else if content.Control == "Vacation" { //请假 : 请假类型,开始时间,结束时间,请假时长
|
||||
tp := content.Value.Vacation.Selector.Options[0].Value[0].Text
|
||||
value = tp + "," + cast.ToString(content.Value.Vacation.Attendance.DateRange.NewBegin) +
|
||||
"," + cast.ToString(content.Value.Vacation.Attendance.DateRange.NewEnd) +
|
||||
"," + cast.ToString(content.Value.Vacation.Attendance.DateRange.NewDuration)
|
||||
} else if content.Control == "PunchCorrection" { //补卡:日期,时间,状态
|
||||
mp := cast.ToStringMap(content.Value.PunchCorrection)
|
||||
ddate := cast.ToString(mp["daymonthyear"])
|
||||
dtime := cast.ToString(mp["time"])
|
||||
if ddate == "" {
|
||||
ddate = dtime
|
||||
}
|
||||
value = ddate + "," + dtime + "," + cast.ToString(mp["state"])
|
||||
} else if content.Control == "BankAccount" {
|
||||
mp := cast.ToStringMap(content.Value.BankAccount)
|
||||
value = cast.ToString(mp["account_type"]) + "," + cast.ToString(mp["account_name"]) + "," + cast.ToString(mp["account_number"])
|
||||
} else if content.Control == "Number" {
|
||||
value = content.Value.NewNumber
|
||||
}
|
||||
return value
|
||||
}
|
||||
return ""
|
||||
data := d.GetData()
|
||||
return data[title]
|
||||
}
|
||||
|
||||
func (d *ApproveDetail) GetData() map[string]string {
|
||||
|
|
@ -165,9 +117,11 @@ func (d *ApproveDetail) GetData() map[string]string {
|
|||
} else if content.Control == "Money" {
|
||||
value = content.Value.NewMoney
|
||||
} else if content.Control == "File" {
|
||||
if len(content.Value.Files) > 0 {
|
||||
value = content.Value.Files[0].FileId
|
||||
fileIds := make([]string, 0)
|
||||
for _, v := range content.Value.Files {
|
||||
fileIds = append(fileIds, v.FileId)
|
||||
}
|
||||
value = strings.Join(fileIds, ",")
|
||||
} else if content.Control == "Vacation" { //请假 : 请假类型,开始时间,结束时间,请假时长
|
||||
tp := content.Value.Vacation.Selector.Options[0].Value[0].Text
|
||||
value = tp + "," + cast.ToString(content.Value.Vacation.Attendance.DateRange.NewBegin) +
|
||||
|
|
@ -220,7 +174,7 @@ func (q *AppApprove) GetDetail(spNo string) (*ApproveDetail, error) {
|
|||
}
|
||||
var rsp ApproveDetailRsp
|
||||
|
||||
fmt.Println("spno: %s, detail: %s", spNo, string(rspBody))
|
||||
//fmt.Println("spno: %s, detail: %s", spNo, string(rspBody))
|
||||
if err := json.Unmarshal(rspBody, &rsp); err != nil {
|
||||
log.Errorf("get body[%s] json error :%s", string(rspBody), err.Error())
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ package qyweixin
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"git.u8t.cn/open/gosdk/util"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"git.u8t.cn/open/goutil"
|
||||
"github.com/spf13/cast"
|
||||
"time"
|
||||
|
||||
"git.u8t.cn/open/gosdk/util"
|
||||
"git.u8t.cn/open/goutil"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -14,6 +15,7 @@ var (
|
|||
urlQyWeixinHrGetStaffInfo = "https://qyapi.weixin.qq.com/cgi-bin/hr/get_staff_info"
|
||||
urlQyWeixinHrGetDepartment = "https://qyapi.weixin.qq.com/cgi-bin/department/list"
|
||||
urlQyWeixinHrGetDepartmentUser = "https://qyapi.weixin.qq.com/cgi-bin/user/list"
|
||||
urlQyWeixinHrGetContactInfo = "https://qyapi.weixin.qq.com/cgi-bin/user/get"
|
||||
)
|
||||
|
||||
type AppHr struct {
|
||||
|
|
@ -22,10 +24,11 @@ type AppHr struct {
|
|||
}
|
||||
|
||||
type Department struct {
|
||||
Id int64 `json:"id"`
|
||||
Pid int64 `json:"pid"`
|
||||
Name string `json:"name"`
|
||||
Leader []string `json:"leader"`
|
||||
Id int64 `json:"id"`
|
||||
Pid int64 `json:"pid"`
|
||||
Name string `json:"name"`
|
||||
Leader []string `json:"leader"`
|
||||
Childchren []*Department `json:"childchren"`
|
||||
}
|
||||
|
||||
type StaffInfo struct {
|
||||
|
|
@ -42,12 +45,38 @@ type StaffInfo struct {
|
|||
BankCard string
|
||||
}
|
||||
|
||||
type ContactInfo struct {
|
||||
Realname string
|
||||
DirectLeader []string
|
||||
DepartmentId []int64
|
||||
IsDepartmentLeader []int
|
||||
}
|
||||
|
||||
func NewAppHr(cfg *AppConfig) *AppHr {
|
||||
return &AppHr{
|
||||
App: *NewApp(cfg),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *AppHr) GetContactInfo(userId string) (*ContactInfo, error) {
|
||||
reqUrl := fmt.Sprintf("%s?access_token=%s&userid=%s", urlQyWeixinHrGetContactInfo, h.GetToken(), userId)
|
||||
|
||||
rspBody, err := util.HttpGet(reqUrl, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
contract := new(ContactInfo)
|
||||
result, err := h.GetResult(rspBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
contract.Realname = cast.ToString(result["name"])
|
||||
contract.DirectLeader = cast.ToStringSlice(result["direct_leader"])
|
||||
contract.DepartmentId = cast.ToInt64Slice(result["department"])
|
||||
contract.IsDepartmentLeader = cast.ToIntSlice(result["is_leader_in_dept"])
|
||||
return contract, nil
|
||||
}
|
||||
|
||||
func (h *AppHr) GetStaffInfo(userId string) (*StaffInfo, error) {
|
||||
reqUrl := fmt.Sprintf("%s?access_token=%s", urlQyWeixinHrGetStaffInfo, h.GetToken())
|
||||
reqBody := make(map[string]interface{})
|
||||
|
|
@ -108,6 +137,7 @@ func (h *AppHr) GetDepartment(id int64) ([]*Department, error) {
|
|||
result := make([]*Department, 0)
|
||||
|
||||
departments := cast.ToSlice(resp["department"])
|
||||
|
||||
for _, dd := range departments {
|
||||
d := cast.ToStringMap(dd)
|
||||
r := new(Department)
|
||||
|
|
@ -116,7 +146,9 @@ func (h *AppHr) GetDepartment(id int64) ([]*Department, error) {
|
|||
r.Id = cast.ToInt64(d["id"])
|
||||
r.Pid = cast.ToInt64(d["parentid"])
|
||||
result = append(result, r)
|
||||
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ package storage
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/minio/minio-go"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/minio/minio-go"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
|
@ -61,9 +63,13 @@ func (s *Minio) Put(fileName, objectName string, onProcess func(fsize, uploaded
|
|||
|
||||
objectName = strings.TrimLeft(objectName, "/ ")
|
||||
ext := strings.TrimLeft(path.Ext(fileName), ".")
|
||||
contentType := ext2ContentType(ext)
|
||||
if contentType == "" {
|
||||
contentType = detectContentType(fileName)
|
||||
}
|
||||
|
||||
_, err := s.client.FPutObjectWithContext(ctx, s.config.Bucket, objectName, fileName,
|
||||
minio.PutObjectOptions{ContentType: ext2ContentType(ext)})
|
||||
minio.PutObjectOptions{ContentType: contentType})
|
||||
if err != nil {
|
||||
log.Errorf("upload file to minio error:%s", err.Error())
|
||||
return err
|
||||
|
|
@ -108,7 +114,7 @@ func (s *Minio) List(objectPrefix string) ([]string, error) {
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Minio) Url(objectName string, expire time.Duration) string {
|
||||
func (s *Minio) Url(objectName string, expire time.Duration, https ...bool) string {
|
||||
if err := s.Init(); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
|
@ -116,11 +122,19 @@ func (s *Minio) Url(objectName string, expire time.Duration) string {
|
|||
if expire > time.Hour*24*7 || expire == -1 {
|
||||
expire = time.Hour * 24 * 7
|
||||
}
|
||||
|
||||
baseUrl := s.config.BaseUrl
|
||||
if len(https) > 0 && https[0] {
|
||||
if strings.HasPrefix(baseUrl, "http://") {
|
||||
baseUrl = "https://" + strings.TrimPrefix(baseUrl, "http://")
|
||||
}
|
||||
}
|
||||
|
||||
var params url.Values
|
||||
u, err := s.client.PresignedGetObject(s.config.Bucket, objectName, expire, params)
|
||||
if err != nil {
|
||||
log.Errorf("error:%s", err.Error())
|
||||
return fmt.Sprintf("%s/%s/%s", s.config.BaseUrl, s.config.Bucket, objectName)
|
||||
return fmt.Sprintf("%s/%s/%s", baseUrl, s.config.Bucket, objectName)
|
||||
}
|
||||
|
||||
return u.String()
|
||||
|
|
@ -128,9 +142,78 @@ func (s *Minio) Url(objectName string, expire time.Duration) string {
|
|||
}
|
||||
|
||||
func (s *Minio) Stat(objectName string) (*ObjectInfo, error) {
|
||||
return nil, nil
|
||||
if err := s.Init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
objectName = strings.TrimLeft(objectName, "/ ")
|
||||
stat, err := s.client.StatObject(s.config.Bucket, objectName, minio.StatObjectOptions{})
|
||||
if err != nil {
|
||||
// 文件不存在不算错误,返回 nil, nil
|
||||
if isMinioNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
log.Errorf("stat object from minio error:%s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := &ObjectInfo{
|
||||
Size: stat.Size,
|
||||
Hash: stat.ETag,
|
||||
MimeType: stat.ContentType,
|
||||
PutTime: stat.LastModified.Unix(),
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (s *Minio) Fetch(url, objectName string) error {
|
||||
// isMinioNotFound 检查是否为 MinIO 文件不存在错误
|
||||
func isMinioNotFound(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
// MinIO 返回 NoSuchKey 表示文件不存在
|
||||
if respErr, ok := err.(minio.ErrorResponse); ok {
|
||||
return respErr.Code == "NoSuchKey" || respErr.Code == "NotFound"
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Minio) Fetch(urlStr, objectName string, local ...bool) error {
|
||||
if err := s.Init(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 从 URL 下载文件
|
||||
resp, err := http.Get(urlStr)
|
||||
if err != nil {
|
||||
log.Errorf("fetch file from url error:%s", err.Error())
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("fetch file from url failed, status: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// 获取文件名和 Content-Type
|
||||
objectName = strings.TrimLeft(objectName, "/ ")
|
||||
// 优先根据文件扩展名推断 Content-Type,确保图片能正确预览
|
||||
ext := strings.TrimLeft(path.Ext(objectName), ".")
|
||||
contentType := ext2ContentType(ext)
|
||||
if contentType == "" {
|
||||
contentType = resp.Header.Get("Content-Type")
|
||||
}
|
||||
|
||||
// 上传到 MinIO
|
||||
ctx, cancel := context.WithTimeout(context.Background(), s.config.Timeout)
|
||||
defer cancel()
|
||||
|
||||
_, err = s.client.PutObjectWithContext(ctx, s.config.Bucket, objectName, resp.Body, resp.ContentLength,
|
||||
minio.PutObjectOptions{ContentType: contentType})
|
||||
if err != nil {
|
||||
log.Errorf("upload fetched file to minio error:%s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,13 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/qiniu/go-sdk/v7/auth/qbox"
|
||||
"github.com/qiniu/go-sdk/v7/storage"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type QiniuConfig struct {
|
||||
|
|
@ -152,7 +155,7 @@ func (s *Qiniu) Get(objectName, fileName string) error {
|
|||
return Download(url, fileName)
|
||||
}
|
||||
|
||||
func (s *Qiniu) Url(objectName string, expire time.Duration) string {
|
||||
func (s *Qiniu) Url(objectName string, expire time.Duration, https ...bool) string {
|
||||
mac := qbox.NewMac(s.config.AK, s.config.SK)
|
||||
cfg := storage.Config{
|
||||
UseHTTPS: false,
|
||||
|
|
@ -166,8 +169,11 @@ func (s *Qiniu) Url(objectName string, expire time.Duration) string {
|
|||
if len(domains) <= 0 {
|
||||
return ""
|
||||
}
|
||||
domain := "http://" + domains[0].Domain
|
||||
if len(https) > 0 && https[0] {
|
||||
domain = "https://" + domains[0].Domain
|
||||
}
|
||||
|
||||
domain := "https://" + domains[0].Domain
|
||||
if expire == 0 {
|
||||
return storage.MakePublicURLv2(domain, objectName)
|
||||
} else {
|
||||
|
|
@ -185,6 +191,10 @@ func (s *Qiniu) Stat(objectName string) (*ObjectInfo, error) {
|
|||
bucketManager := storage.NewBucketManager(mac, &cfg)
|
||||
fileInfo, err := bucketManager.Stat(s.config.Bucket, objectName)
|
||||
if err != nil {
|
||||
// 文件不存在不算错误,返回 nil, nil
|
||||
if isQiniuNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -196,7 +206,22 @@ func (s *Qiniu) Stat(objectName string) (*ObjectInfo, error) {
|
|||
return info, nil
|
||||
}
|
||||
|
||||
func (s *Qiniu) Fetch(url, objectName string) error {
|
||||
// isQiniuNotFound 检查是否为七牛云文件不存在错误
|
||||
func isQiniuNotFound(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
// 七牛云错误码 612 表示文件不存在
|
||||
if respErr, ok := err.(*storage.ErrorInfo); ok {
|
||||
return respErr.Code == 612
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Qiniu) Fetch(url, objectName string, local ...bool) error {
|
||||
if len(local) > 0 && local[0] == true {
|
||||
return s.fetchLocal(url, objectName)
|
||||
}
|
||||
mac := qbox.NewMac(s.config.AK, s.config.SK)
|
||||
cfg := storage.Config{
|
||||
UseHTTPS: false,
|
||||
|
|
@ -211,3 +236,19 @@ func (s *Qiniu) Fetch(url, objectName string) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Qiniu) fetchLocal(url, objectName string) error {
|
||||
objectName = strings.TrimLeft(objectName, "/ ")
|
||||
ext := strings.TrimLeft(path.Ext(objectName), ".")
|
||||
|
||||
tmpFile := fmt.Sprintf("%d.%s", time.Now().UnixMilli(), ext)
|
||||
if err := Download(url, tmpFile); err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tmpFile)
|
||||
|
||||
if err := s.Put(tmpFile, objectName, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ type Storage interface {
|
|||
Put(fileName, objectName string, onProcess func(fsize, uploaded int64)) error
|
||||
Get(objectName, fileName string) error
|
||||
Del(objectName string) error
|
||||
Url(objectName string, expire time.Duration) string
|
||||
Url(objectName string, expire time.Duration, https ...bool) string //https参数是否生成https参数
|
||||
Stat(objectName string) (*ObjectInfo, error)
|
||||
List(objectPrefix string) ([]string, error)
|
||||
Fetch(url, objectName string) error
|
||||
Fetch(url, objectName string, local ...bool) error //local参数决定是否先下载到本地在上传,七牛云下载企业微信的文件需要不能直接下载
|
||||
}
|
||||
|
|
|
|||
110
storage/util.go
110
storage/util.go
|
|
@ -21,16 +21,116 @@ func contentType2Ext(contentType string) string {
|
|||
|
||||
func ext2ContentType(ext string) string {
|
||||
ext = strings.ToLower(ext)
|
||||
if ext == "jpg" || ext == "jpeg" {
|
||||
switch ext {
|
||||
// 图片格式
|
||||
case "jpg", "jpeg":
|
||||
return "image/jpeg"
|
||||
} else if ext == "png" {
|
||||
case "png":
|
||||
return "image/png"
|
||||
} else if ext == "mp3" {
|
||||
case "gif":
|
||||
return "image/gif"
|
||||
case "webp":
|
||||
return "image/webp"
|
||||
case "bmp":
|
||||
return "image/bmp"
|
||||
case "svg", "svgz":
|
||||
return "image/svg+xml"
|
||||
case "ico":
|
||||
return "image/x-icon"
|
||||
case "tiff", "tif":
|
||||
return "image/tiff"
|
||||
case "avif":
|
||||
return "image/avif"
|
||||
case "apng":
|
||||
return "image/apng"
|
||||
// 音频格式
|
||||
case "mp3":
|
||||
return "audio/mpeg"
|
||||
} else if ext == "mp4" {
|
||||
case "wav":
|
||||
return "audio/wav"
|
||||
case "ogg":
|
||||
return "audio/ogg"
|
||||
case "flac":
|
||||
return "audio/flac"
|
||||
case "aac":
|
||||
return "audio/aac"
|
||||
case "m4a":
|
||||
return "audio/mp4"
|
||||
// 视频格式
|
||||
case "mp4":
|
||||
return "video/mp4"
|
||||
case "avi":
|
||||
return "video/x-msvideo"
|
||||
case "mov", "qt":
|
||||
return "video/quicktime"
|
||||
case "webm":
|
||||
return "video/webm"
|
||||
case "flv":
|
||||
return "video/x-flv"
|
||||
case "mkv":
|
||||
return "video/x-matroska"
|
||||
case "wmv":
|
||||
return "video/x-ms-wmv"
|
||||
case "m3u8":
|
||||
return "application/vnd.apple.mpegurl"
|
||||
case "ts":
|
||||
return "video/mp2t"
|
||||
// 文档格式
|
||||
case "pdf":
|
||||
return "application/pdf"
|
||||
case "doc":
|
||||
return "application/msword"
|
||||
case "docx":
|
||||
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
||||
case "xls":
|
||||
return "application/vnd.ms-excel"
|
||||
case "xlsx":
|
||||
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
case "ppt":
|
||||
return "application/vnd.ms-powerpoint"
|
||||
case "pptx":
|
||||
return "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
||||
case "txt":
|
||||
return "text/plain"
|
||||
case "html", "htm":
|
||||
return "text/html"
|
||||
case "css":
|
||||
return "text/css"
|
||||
case "js":
|
||||
return "application/javascript"
|
||||
case "json":
|
||||
return "application/json"
|
||||
case "xml":
|
||||
return "application/xml"
|
||||
case "zip":
|
||||
return "application/zip"
|
||||
case "rar":
|
||||
return "application/x-rar-compressed"
|
||||
case "7z":
|
||||
return "application/x-7z-compressed"
|
||||
case "gz":
|
||||
return "application/gzip"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// detectContentType 从文件内容检测 MIME 类型
|
||||
func detectContentType(filePath string) string {
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// 读取前 512 字节用于检测
|
||||
buf := make([]byte, 512)
|
||||
n, err := f.Read(buf)
|
||||
if err != nil && err != io.EOF {
|
||||
return ""
|
||||
}
|
||||
|
||||
return http.DetectContentType(buf[:n])
|
||||
}
|
||||
|
||||
func Download(url, path string) error {
|
||||
|
|
|
|||
77
util/http.go
77
util/http.go
|
|
@ -9,26 +9,36 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
httpClient *http.Client
|
||||
)
|
||||
|
||||
func init() {
|
||||
httpClient = &http.Client{
|
||||
Timeout: 20 * time.Second,
|
||||
Transport: &http.Transport{
|
||||
MaxIdleConns: 200,
|
||||
MaxIdleConnsPerHost: 50,
|
||||
MaxConnsPerHost: 500,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// PostJson 请求
|
||||
func HttpPostJson(link string, header map[string]string, json []byte) ([]byte, error) {
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
//忽略https的证书
|
||||
client.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", link, bytes.NewBuffer(json))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if header != nil {
|
||||
for k, v := range header {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
|
||||
for k, v := range header {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -41,24 +51,17 @@ func HttpPostJson(link string, header map[string]string, json []byte) ([]byte, e
|
|||
|
||||
// PostJson 请求
|
||||
func HttpPutJson(link string, header map[string]string, json []byte) ([]byte, error) {
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
//忽略https的证书
|
||||
client.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("PUT", link, bytes.NewBuffer(json))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if header != nil {
|
||||
for k, v := range header {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
|
||||
for k, v := range header {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -71,22 +74,15 @@ func HttpPutJson(link string, header map[string]string, json []byte) ([]byte, er
|
|||
|
||||
// Get 请求 link:请求url
|
||||
func HttpGet(link string, header map[string]string) ([]byte, error) {
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
//忽略https的证书
|
||||
client.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", link, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if header != nil {
|
||||
for k, v := range header {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
|
||||
for k, v := range header {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -99,22 +95,15 @@ func HttpGet(link string, header map[string]string) ([]byte, error) {
|
|||
|
||||
// Get 请求 link:请求url
|
||||
func HttpDelete(link string, header map[string]string) ([]byte, error) {
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
//忽略https的证书
|
||||
client.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("DELETE", link, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if header != nil {
|
||||
for k, v := range header {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
|
||||
for k, v := range header {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue