1
0
mirror of https://github.com/silenceper/wechat.git synced 2026-02-04 12:52:27 +08:00

规范目录

This commit is contained in:
silenceper
2020-01-20 13:54:04 +08:00
parent 9b06954b10
commit 15ebd71a04
75 changed files with 985 additions and 1871 deletions

5
miniprogram/README.md Normal file
View File

@@ -0,0 +1,5 @@
# 微信小程序
[官方文档](https://developers.weixin.qq.com/miniprogram/dev/framework/)
## 快速入门

View File

@@ -1,9 +1,11 @@
package miniprogram
package analysis
import (
"encoding/json"
"fmt"
"github.com/silenceper/wechat/miniprogram/context"
"github.com/silenceper/wechat/util"
)
@@ -30,10 +32,20 @@ const (
getAnalysisVisitPageURL = "https://api.weixin.qq.com/datacube/getweanalysisappidvisitpage?access_token=%s"
)
//Analysis analyis 数据分析
type Analysis struct {
*context.Context
}
//NewAnalysis new
func NewAnalysis(ctx *context.Context) *Analysis {
return &Analysis{ctx}
}
// fetchData 拉取统计数据
func (wxa *MiniProgram) fetchData(urlStr string, body interface{}) (response []byte, err error) {
func (analysis *Analysis) fetchData(urlStr string, body interface{}) (response []byte, err error) {
var accessToken string
accessToken, err = wxa.GetAccessToken()
accessToken, err = analysis.GetAccessToken()
if err != nil {
return
}
@@ -42,8 +54,8 @@ func (wxa *MiniProgram) fetchData(urlStr string, body interface{}) (response []b
return
}
// AnalysisRetainItem 留存项结构
type AnalysisRetainItem struct {
// RetainItem 留存项结构
type RetainItem struct {
Key int `json:"key"` // 标识0开始表示当天1表示1甜后以此类推
Value int `json:"value"` // key对应日期的新增用户数/活跃用户数key=0时或留存用户数k>0时
}
@@ -51,18 +63,18 @@ type AnalysisRetainItem struct {
// ResAnalysisRetain 小程序留存数据返回
type ResAnalysisRetain struct {
util.CommonError
RefDate string `json:"ref_date"` // 日期
VisitUVNew []AnalysisRetainItem `json:"visit_uv_new"` // 新增用户留存
VisitUV []AnalysisRetainItem `json:"visit_uv"` // 活跃用户留存
RefDate string `json:"ref_date"` // 日期
VisitUVNew []RetainItem `json:"visit_uv_new"` // 新增用户留存
VisitUV []RetainItem `json:"visit_uv"` // 活跃用户留存
}
// getAnalysisRetain 获取用户访问小程序留存数据(日、月、周)
func (wxa *MiniProgram) getAnalysisRetain(urlStr string, beginDate, endDate string) (result ResAnalysisRetain, err error) {
func (analysis *Analysis) getAnalysisRetain(urlStr string, beginDate, endDate string) (result ResAnalysisRetain, err error) {
body := map[string]string{
"begin_date": beginDate,
"end_date": endDate,
}
response, err := wxa.fetchData(urlStr, body)
response, err := analysis.fetchData(urlStr, body)
if err != nil {
return
}
@@ -78,18 +90,18 @@ func (wxa *MiniProgram) getAnalysisRetain(urlStr string, beginDate, endDate stri
}
// GetAnalysisDailyRetain 获取用户访问小程序日留存
func (wxa *MiniProgram) GetAnalysisDailyRetain(beginDate, endDate string) (result ResAnalysisRetain, err error) {
return wxa.getAnalysisRetain(getAnalysisDailyRetainURL, beginDate, endDate)
func (analysis *Analysis) GetAnalysisDailyRetain(beginDate, endDate string) (result ResAnalysisRetain, err error) {
return analysis.getAnalysisRetain(getAnalysisDailyRetainURL, beginDate, endDate)
}
// GetAnalysisMonthlyRetain 获取用户访问小程序月留存
func (wxa *MiniProgram) GetAnalysisMonthlyRetain(beginDate, endDate string) (result ResAnalysisRetain, err error) {
return wxa.getAnalysisRetain(getAnalysisMonthlyRetainURL, beginDate, endDate)
func (analysis *Analysis) GetAnalysisMonthlyRetain(beginDate, endDate string) (result ResAnalysisRetain, err error) {
return analysis.getAnalysisRetain(getAnalysisMonthlyRetainURL, beginDate, endDate)
}
// GetAnalysisWeeklyRetain 获取用户访问小程序周留存
func (wxa *MiniProgram) GetAnalysisWeeklyRetain(beginDate, endDate string) (result ResAnalysisRetain, err error) {
return wxa.getAnalysisRetain(getAnalysisWeeklyRetainURL, beginDate, endDate)
func (analysis *Analysis) GetAnalysisWeeklyRetain(beginDate, endDate string) (result ResAnalysisRetain, err error) {
return analysis.getAnalysisRetain(getAnalysisWeeklyRetainURL, beginDate, endDate)
}
// ResAnalysisDailySummary 小程序访问数据概况
@@ -104,12 +116,12 @@ type ResAnalysisDailySummary struct {
}
// GetAnalysisDailySummary 获取用户访问小程序数据概况
func (wxa *MiniProgram) GetAnalysisDailySummary(beginDate, endDate string) (result ResAnalysisDailySummary, err error) {
func (analysis *Analysis) GetAnalysisDailySummary(beginDate, endDate string) (result ResAnalysisDailySummary, err error) {
body := map[string]string{
"begin_date": beginDate,
"end_date": endDate,
}
response, err := wxa.fetchData(getAnalysisDailySummaryURL, body)
response, err := analysis.fetchData(getAnalysisDailySummaryURL, body)
if err != nil {
return
}
@@ -141,12 +153,12 @@ type ResAnalysisVisitTrend struct {
}
// getAnalysisRetain 获取小程序访问数据趋势(日、月、周)
func (wxa *MiniProgram) getAnalysisVisitTrend(urlStr string, beginDate, endDate string) (result ResAnalysisVisitTrend, err error) {
func (analysis *Analysis) getAnalysisVisitTrend(urlStr string, beginDate, endDate string) (result ResAnalysisVisitTrend, err error) {
body := map[string]string{
"begin_date": beginDate,
"end_date": endDate,
}
response, err := wxa.fetchData(urlStr, body)
response, err := analysis.fetchData(urlStr, body)
if err != nil {
return
}
@@ -162,18 +174,18 @@ func (wxa *MiniProgram) getAnalysisVisitTrend(urlStr string, beginDate, endDate
}
// GetAnalysisDailyVisitTrend 获取用户访问小程序数据日趋势
func (wxa *MiniProgram) GetAnalysisDailyVisitTrend(beginDate, endDate string) (result ResAnalysisVisitTrend, err error) {
return wxa.getAnalysisVisitTrend(getAnalysisDailyVisitTrendURL, beginDate, endDate)
func (analysis *Analysis) GetAnalysisDailyVisitTrend(beginDate, endDate string) (result ResAnalysisVisitTrend, err error) {
return analysis.getAnalysisVisitTrend(getAnalysisDailyVisitTrendURL, beginDate, endDate)
}
// GetAnalysisMonthlyVisitTrend 获取用户访问小程序数据月趋势
func (wxa *MiniProgram) GetAnalysisMonthlyVisitTrend(beginDate, endDate string) (result ResAnalysisVisitTrend, err error) {
return wxa.getAnalysisVisitTrend(getAnalysisMonthlyVisitTrendURL, beginDate, endDate)
func (analysis *Analysis) GetAnalysisMonthlyVisitTrend(beginDate, endDate string) (result ResAnalysisVisitTrend, err error) {
return analysis.getAnalysisVisitTrend(getAnalysisMonthlyVisitTrendURL, beginDate, endDate)
}
// GetAnalysisWeeklyVisitTrend 获取用户访问小程序数据周趋势
func (wxa *MiniProgram) GetAnalysisWeeklyVisitTrend(beginDate, endDate string) (result ResAnalysisVisitTrend, err error) {
return wxa.getAnalysisVisitTrend(getAnalysisWeeklyVisitTrendURL, beginDate, endDate)
func (analysis *Analysis) GetAnalysisWeeklyVisitTrend(beginDate, endDate string) (result ResAnalysisVisitTrend, err error) {
return analysis.getAnalysisVisitTrend(getAnalysisWeeklyVisitTrendURL, beginDate, endDate)
}
// UserPortraitItem 用户画像项目
@@ -203,12 +215,12 @@ type ResAnalysisUserPortrait struct {
}
// GetAnalysisUserPortrait 获取小程序新增或活跃用户的画像分布数据
func (wxa *MiniProgram) GetAnalysisUserPortrait(beginDate, endDate string) (result ResAnalysisUserPortrait, err error) {
func (analysis *Analysis) GetAnalysisUserPortrait(beginDate, endDate string) (result ResAnalysisUserPortrait, err error) {
body := map[string]string{
"begin_date": beginDate,
"end_date": endDate,
}
response, err := wxa.fetchData(getAnalysisUserPortraitURL, body)
response, err := analysis.fetchData(getAnalysisUserPortraitURL, body)
if err != nil {
return
}
@@ -244,12 +256,12 @@ type ResAnalysisVisitDistribution struct {
}
// GetAnalysisVisitDistribution 获取用户小程序访问分布数据
func (wxa *MiniProgram) GetAnalysisVisitDistribution(beginDate, endDate string) (result ResAnalysisVisitDistribution, err error) {
func (analysis *Analysis) GetAnalysisVisitDistribution(beginDate, endDate string) (result ResAnalysisVisitDistribution, err error) {
body := map[string]string{
"begin_date": beginDate,
"end_date": endDate,
}
response, err := wxa.fetchData(getAnalysisVisitDistributionURL, body)
response, err := analysis.fetchData(getAnalysisVisitDistributionURL, body)
if err != nil {
return
}
@@ -284,12 +296,12 @@ type ResAnalysisVisitPage struct {
}
// GetAnalysisVisitPage 获取小程序页面访问数据
func (wxa *MiniProgram) GetAnalysisVisitPage(beginDate, endDate string) (result ResAnalysisVisitPage, err error) {
func (analysis *Analysis) GetAnalysisVisitPage(beginDate, endDate string) (result ResAnalysisVisitPage, err error) {
body := map[string]string{
"begin_date": beginDate,
"end_date": endDate,
}
response, err := wxa.fetchData(getAnalysisVisitPageURL, body)
response, err := analysis.fetchData(getAnalysisVisitPageURL, body)
if err != nil {
return
}

View File

@@ -1,9 +1,10 @@
package miniprogram
package auth
import (
"encoding/json"
"fmt"
"github.com/silenceper/wechat/miniprogram/context"
"github.com/silenceper/wechat/util"
)
@@ -11,6 +12,16 @@ const (
code2SessionURL = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"
)
//Auth 登录/用户信息
type Auth struct {
*context.Context
}
//NewAuth new auth
func NewAuth(ctx *context.Context) *Auth {
return &Auth{ctx}
}
// ResCode2Session 登录凭证校验的返回结果
type ResCode2Session struct {
util.CommonError
@@ -20,9 +31,9 @@ type ResCode2Session struct {
UnionID string `json:"unionid"` // 用户在开放平台的唯一标识符在满足UnionID下发条件的情况下会返回
}
// Code2Session 登录凭证校验
func (wxa *MiniProgram) Code2Session(jsCode string) (result ResCode2Session, err error) {
urlStr := fmt.Sprintf(code2SessionURL, wxa.AppID, wxa.AppSecret, jsCode)
//Code2Session 登录凭证校验
func (auth *Auth) Code2Session(jsCode string) (result ResCode2Session, err error) {
urlStr := fmt.Sprintf(code2SessionURL, auth.AppID, auth.AppSecret, jsCode)
var response []byte
response, err = util.HTTPGet(urlStr)
if err != nil {
@@ -38,3 +49,8 @@ func (wxa *MiniProgram) Code2Session(jsCode string) (result ResCode2Session, err
}
return
}
//GetPaidUnionID 用户支付完成后,获取该用户的 UnionId无需用户授权
func (auth *Auth) GetPaidUnionID() {
//TODO
}

View File

@@ -0,0 +1,15 @@
package basic
import "github.com/silenceper/wechat/miniprogram/context"
//Basic struct
type Basic struct {
*context.Context
}
//NewBasic 实例
func NewBasic(context *context.Context) *Basic {
basic := new(Basic)
basic.Context = context
return basic
}

View File

@@ -1,4 +1,4 @@
package miniprogram
package basic
import (
"crypto/aes"
@@ -96,7 +96,7 @@ func getCipherText(sessionKey, encryptedData, iv string) ([]byte, error) {
}
// Decrypt 解密数据
func (wxa *MiniProgram) Decrypt(sessionKey, encryptedData, iv string) (*UserInfo, error) {
func (basic *Basic) Decrypt(sessionKey, encryptedData, iv string) (*UserInfo, error) {
cipherText, err := getCipherText(sessionKey, encryptedData, iv)
if err != nil {
return nil, err
@@ -106,14 +106,14 @@ func (wxa *MiniProgram) Decrypt(sessionKey, encryptedData, iv string) (*UserInfo
if err != nil {
return nil, err
}
if userInfo.Watermark.AppID != wxa.AppID {
if userInfo.Watermark.AppID != basic.AppID {
return nil, ErrAppIDNotMatch
}
return &userInfo, nil
}
// DecryptPhone 解密数据(手机)
func (wxa *MiniProgram) DecryptPhone(sessionKey, encryptedData, iv string) (*PhoneInfo, error) {
func (basic *Basic) DecryptPhone(sessionKey, encryptedData, iv string) (*PhoneInfo, error) {
cipherText, err := getCipherText(sessionKey, encryptedData, iv)
if err != nil {
return nil, err
@@ -123,7 +123,7 @@ func (wxa *MiniProgram) DecryptPhone(sessionKey, encryptedData, iv string) (*Pho
if err != nil {
return nil, err
}
if phoneInfo.Watermark.AppID != wxa.AppID {
if phoneInfo.Watermark.AppID != basic.AppID {
return nil, ErrAppIDNotMatch
}
return &phoneInfo, nil

View File

@@ -0,0 +1,12 @@
package config
import (
"github.com/silenceper/wechat/cache"
)
//Config config for 小程序
type Config struct {
AppID string `json:"app_id"` //appid
AppSecret string `json:"app_secret"` //appsecret
Cache cache.Cache
}

View File

@@ -0,0 +1,87 @@
package context
import (
"encoding/json"
"fmt"
"sync"
"time"
"github.com/silenceper/wechat/util"
)
const (
//AccessTokenURL 获取access_token的接口
AccessTokenURL = "https://api.weixin.qq.com/cgi-bin/token"
//CacheKeyPrefix cache前缀
CacheKeyPrefix = "gowechat_miniprogram_"
)
//ResAccessToken struct
type ResAccessToken struct {
util.CommonError
AccessToken string `json:"access_token"`
ExpiresIn int64 `json:"expires_in"`
}
//GetAccessTokenFunc 获取 access token 的函数签名
type GetAccessTokenFunc func(ctx *Context) (accessToken string, err error)
//SetAccessTokenLock 设置读写锁一个appID一个读写锁
func (ctx *Context) SetAccessTokenLock(l *sync.RWMutex) {
ctx.accessTokenLock = l
}
//SetGetAccessTokenFunc 设置自定义获取accessToken的方式, 需要自己实现缓存
func (ctx *Context) SetGetAccessTokenFunc(f GetAccessTokenFunc) {
ctx.accessTokenFunc = f
}
//GetAccessToken 获取access_token
func (ctx *Context) GetAccessToken() (accessToken string, err error) {
ctx.accessTokenLock.Lock()
defer ctx.accessTokenLock.Unlock()
if ctx.accessTokenFunc != nil {
return ctx.accessTokenFunc(ctx)
}
accessTokenCacheKey := fmt.Sprintf("%s_access_token_%s", CacheKeyPrefix, ctx.AppID)
val := ctx.Cache.Get(accessTokenCacheKey)
if val != nil {
accessToken = val.(string)
return
}
//从微信服务器获取
var resAccessToken ResAccessToken
resAccessToken, err = ctx.GetAccessTokenFromServer()
if err != nil {
return
}
accessToken = resAccessToken.AccessToken
return
}
//GetAccessTokenFromServer 强制从微信服务器获取token
func (ctx *Context) GetAccessTokenFromServer() (resAccessToken ResAccessToken, err error) {
url := fmt.Sprintf("%s?grant_type=client_credential&appid=%s&secret=%s", AccessTokenURL, ctx.AppID, ctx.AppSecret)
var body []byte
body, err = util.HTTPGet(url)
if err != nil {
return
}
err = json.Unmarshal(body, &resAccessToken)
if err != nil {
return
}
if resAccessToken.ErrMsg != "" {
err = fmt.Errorf("get access_token error : errcode=%v , errormsg=%v", resAccessToken.ErrCode, resAccessToken.ErrMsg)
return
}
accessTokenCacheKey := fmt.Sprintf("%s_access_token_%s", CacheKeyPrefix, ctx.AppID)
expires := resAccessToken.ExpiresIn - 1500
err = ctx.Cache.Set(accessTokenCacheKey, resAccessToken.AccessToken, time.Duration(expires)*time.Second)
return
}

View File

@@ -0,0 +1,18 @@
package context
import (
"sync"
"github.com/silenceper/wechat/miniprogram/config"
)
// Context struct
type Context struct {
*config.Config
//accessTokenLock 读写锁 同一个AppID一个
accessTokenLock *sync.RWMutex
//accessTokenFunc 自定义获取 access token 的方法
accessTokenFunc GetAccessTokenFunc
}

View File

@@ -1,17 +1,60 @@
package miniprogram
import (
"github.com/silenceper/wechat/context"
"sync"
"github.com/silenceper/wechat/miniprogram/analysis"
"github.com/silenceper/wechat/miniprogram/auth"
"github.com/silenceper/wechat/miniprogram/basic"
"github.com/silenceper/wechat/miniprogram/config"
"github.com/silenceper/wechat/miniprogram/context"
"github.com/silenceper/wechat/miniprogram/qrcode"
"github.com/silenceper/wechat/miniprogram/tcb"
)
// MiniProgram struct extends context
//MiniProgram 微信小程序相关API
type MiniProgram struct {
*context.Context
ctx *context.Context
}
// NewMiniProgram 实例化小程序接口
func NewMiniProgram(context *context.Context) *MiniProgram {
miniProgram := new(MiniProgram)
miniProgram.Context = context
return miniProgram
//NewMiniProgram 实例化小程序API
func NewMiniProgram(cfg *config.Config) *MiniProgram {
if cfg.Cache == nil {
panic("cache未设置")
}
ctx := &context.Context{
Config: cfg,
}
ctx.SetAccessTokenLock(new(sync.RWMutex))
return &MiniProgram{ctx}
}
// GetContext get Context
func (miniProgram *MiniProgram) GetContext() *context.Context {
return miniProgram.ctx
}
// GetBasic 基础接口(小程序加解密)
func (miniProgram *MiniProgram) GetBasic() *basic.Basic {
return basic.NewBasic(miniProgram.ctx)
}
//GetAuth 登录/用户信息相关接口
func (miniProgram *MiniProgram) GetAuth() *auth.Auth {
return auth.NewAuth(miniProgram.ctx)
}
//GetAnalysis 数据分析
func (miniProgram *MiniProgram) GetAnalysis() *analysis.Analysis {
return analysis.NewAnalysis(miniProgram.ctx)
}
//GetQRCode 小程序码相关API
func (miniProgram *MiniProgram) GetQRCode() *qrcode.QRCode {
return qrcode.NewQRCode(miniProgram.ctx)
}
//GetTcb 小程序云开发API
func (miniProgram *MiniProgram) GetTcb() *tcb.Tcb {
return tcb.NewTcb(miniProgram.ctx)
}

View File

@@ -1,10 +1,11 @@
package miniprogram
package qrcode
import (
"encoding/json"
"fmt"
"strings"
"github.com/silenceper/wechat/miniprogram/context"
"github.com/silenceper/wechat/util"
)
@@ -14,6 +15,25 @@ const (
getWXACodeUnlimitURL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s"
)
//QRCode struct
type QRCode struct {
*context.Context
}
//NewQRCode 实例
func NewQRCode(context *context.Context) *QRCode {
qrCode := new(QRCode)
qrCode.Context = context
return qrCode
}
// Color QRCode color
type Color struct {
R string `json:"r"`
G string `json:"g"`
B string `json:"b"`
}
// QRCoder 小程序码参数
type QRCoder struct {
// page 必须是已经发布的小程序存在的页面,根路径前不要填加 /,不能携带参数参数请放在scene字段里如果不填写这个字段默认跳主页面
@@ -32,17 +52,10 @@ type QRCoder struct {
IsHyaline bool `json:"is_hyaline,omitempty"`
}
// Color QRCode color
type Color struct {
R string `json:"r"`
G string `json:"g"`
B string `json:"b"`
}
// fetchCode 请求并返回二维码二进制数据
func (wxa *MiniProgram) fetchCode(urlStr string, body interface{}) (response []byte, err error) {
func (qrCode *QRCode) fetchCode(urlStr string, body interface{}) (response []byte, err error) {
var accessToken string
accessToken, err = wxa.GetAccessToken()
accessToken, err = qrCode.GetAccessToken()
if err != nil {
return
}
@@ -74,18 +87,18 @@ func (wxa *MiniProgram) fetchCode(urlStr string, body interface{}) (response []b
// CreateWXAQRCode 获取小程序二维码,适用于需要的码数量较少的业务场景
// 文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/createWXAQRCode.html
func (wxa *MiniProgram) CreateWXAQRCode(coderParams QRCoder) (response []byte, err error) {
return wxa.fetchCode(createWXAQRCodeURL, coderParams)
func (qrCode *QRCode) CreateWXAQRCode(coderParams QRCoder) (response []byte, err error) {
return qrCode.fetchCode(createWXAQRCodeURL, coderParams)
}
// GetWXACode 获取小程序码,适用于需要的码数量较少的业务场景
// 文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/getWXACode.html
func (wxa *MiniProgram) GetWXACode(coderParams QRCoder) (response []byte, err error) {
return wxa.fetchCode(getWXACodeURL, coderParams)
func (qrCode *QRCode) GetWXACode(coderParams QRCoder) (response []byte, err error) {
return qrCode.fetchCode(getWXACodeURL, coderParams)
}
// GetWXACodeUnlimit 获取小程序码,适用于需要的码数量极多的业务场景
// 文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/getWXACodeUnlimit.html
func (wxa *MiniProgram) GetWXACodeUnlimit(coderParams QRCoder) (response []byte, err error) {
return wxa.fetchCode(getWXACodeUnlimitURL, coderParams)
func (qrCode *QRCode) GetWXACodeUnlimit(coderParams QRCoder) (response []byte, err error) {
return qrCode.fetchCode(getWXACodeUnlimitURL, coderParams)
}

32
miniprogram/tcb/README.md Normal file
View File

@@ -0,0 +1,32 @@
# 小程序-云开发 SDK
Tencent Cloud Base [文档](https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/)
## 使用说明
**初始化配置**
```golang
//使用memcache保存access_token也可选择redis或自定义cache
memCache=cache.NewMemcache("127.0.0.1:11211")
//配置小程序参数
config := &wechat.Config{
AppID: "your app id",
AppSecret: "your app secret",
Cache: memCache,
}
wc := wechat.NewWechat(config)
wcTcb := wc.GetTcb()
```
### 举例
#### 触发云函数
```golang
res, err := wcTcb.InvokeCloudFunction("test-xxxx", "add", `{"a":1,"b":2}`)
if err != nil {
panic(err)
}
```
更多使用方法参考[GODOC](https://godoc.org/github.com/silenceper/wechat/tcb)

View File

@@ -0,0 +1,35 @@
package tcb
import (
"fmt"
"github.com/silenceper/wechat/util"
)
const (
//触发云函数
invokeCloudFunctionURL = "https://api.weixin.qq.com/tcb/invokecloudfunction"
)
//InvokeCloudFunctionRes 云函数调用返回结果
type InvokeCloudFunctionRes struct {
util.CommonError
RespData string `json:"resp_data"` //云函数返回的buffer
}
//InvokeCloudFunction 云函数调用
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/functions/invokeCloudFunction.html
func (tcb *Tcb) InvokeCloudFunction(env, name, args string) (*InvokeCloudFunctionRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s&env=%s&name=%s", invokeCloudFunctionURL, accessToken, env, name)
response, err := util.HTTPPost(uri, args)
if err != nil {
return nil, err
}
invokeCloudFunctionRes := &InvokeCloudFunctionRes{}
err = util.DecodeWithError(response, invokeCloudFunctionRes, "InvokeCloudFunction")
return invokeCloudFunctionRes, err
}

418
miniprogram/tcb/database.go Normal file
View File

@@ -0,0 +1,418 @@
package tcb
import (
"fmt"
"github.com/silenceper/wechat/util"
)
const (
//数据库导入
databaseMigrateImportURL = "https://api.weixin.qq.com/tcb/databasemigrateimport"
//数据库导出
databaseMigrateExportURL = "https://api.weixin.qq.com/tcb/databasemigrateexport"
//数据库迁移状态查询
databaseMigrateQueryInfoURL = "https://api.weixin.qq.com/tcb/databasemigratequeryinfo"
//变更数据库索引
updateIndexURL = "https://api.weixin.qq.com/tcb/updateindex"
//新增集合
databaseCollectionAddURL = "https://api.weixin.qq.com/tcb/databasecollectionadd"
//删除集合
databaseCollectionDeleteURL = "https://api.weixin.qq.com/tcb/databasecollectiondelete"
//获取特定云环境下集合信息
databaseCollectionGetURL = "https://api.weixin.qq.com/tcb/databasecollectionget"
//数据库插入记录
databaseAddURL = "https://api.weixin.qq.com/tcb/databaseadd"
//数据库删除记录
databaseDeleteURL = "https://api.weixin.qq.com/tcb/databasedelete"
//数据库更新记录
databaseUpdateURL = "https://api.weixin.qq.com/tcb/databaseupdate"
//数据库查询记录
databaseQueryURL = "https://api.weixin.qq.com/tcb/databasequery"
//统计集合记录数或统计查询语句对应的结果记录数
databaseCountURL = "https://api.weixin.qq.com/tcb/databasecount"
//ConflictModeInster 冲突处理模式 插入
ConflictModeInster ConflictMode = 1
//ConflictModeUpsert 冲突处理模式 更新
ConflictModeUpsert ConflictMode = 2
//FileTypeJSON 的合法值 json
FileTypeJSON FileType = 1
//FileTypeCsv 的合法值 csv
FileTypeCsv FileType = 2
)
//ConflictMode 冲突处理模式
type ConflictMode int
//FileType 文件上传和导出的允许文件类型
type FileType int
//ValidDirections 合法的direction值
var ValidDirections = []string{"1", "-1", "2dsphere"}
//DatabaseMigrateExportReq 数据库出 请求参数
type DatabaseMigrateExportReq struct {
Env string `json:"env,omitempty"` //云环境ID
FilePath string `json:"file_path,omitempty"` //导出文件路径(导入文件需先上传到同环境的存储中,可使用开发者工具或 HTTP API的上传文件 API上传
FileType FileType `json:"file_type,omitempty"` //导出文件类型,文件格式参考数据库导入指引中的文件格式部分 1:json 2:csv
Query string `json:"query,omitempty"` //导出条件
}
//DatabaseMigrateExportRes 数据库导出 返回结果
type DatabaseMigrateExportRes struct {
util.CommonError
JobID int64 `json:"job_id"` //导出任务ID可使用数据库迁移进度查询 API 查询导入进度及结果
}
//DatabaseMigrateImportReq 数据库导入 请求参数
type DatabaseMigrateImportReq struct {
Env string `json:"env,omitempty"` //云环境ID
CollectionName string `json:"collection_name,omitempty"` //集合名称
FilePath string `json:"file_path,omitempty"` //导出文件路径(文件会导出到同环境的云存储中,可使用获取下载链接 API 获取下载链接)
FileType FileType `json:"file_type,omitempty"` //导入文件类型,文件格式参考数据库导入指引中的文件格式部分 1:json 2:csv
StopOnError bool `json:"stop_on_error,omitempty"` //是否在遇到错误时停止导入
ConflictMode ConflictMode `json:"conflict_mode,omitempty"` //冲突处理模式 1:inster 2:UPSERT
}
//DatabaseMigrateImportRes 数据库导入 返回结果
type DatabaseMigrateImportRes struct {
util.CommonError
JobID int64 `json:"job_id"` //导入任务ID可使用数据库迁移进度查询 API 查询导入进度及结果
}
//DatabaseMigrateQueryInfoRes 数据库迁移状态查询
type DatabaseMigrateQueryInfoRes struct {
util.CommonError
Status string `json:"status"` //导出状态
RecordSuccess int64 `json:"record_success"` //导出成功记录数
RecordFail int64 `json:"record_fail"` //导出失败记录数
ErrMsg string `json:"err_msg"` //导出错误信息
FileURL string `json:"file_url"` //导出文件下载地址
}
//UpdateIndexReq 变更数据库索引 请求参数
type UpdateIndexReq struct {
Env string `json:"env,omitempty"` //云环境ID
CollectionName string `json:"collection_name,omitempty"` //集合名称
CreateIndexes []CreateIndex `json:"create_indexes,omitempty"` //新增索引
DropIndexes []DropIndex `json:"drop_indexes,omitempty"` //删除索引
}
//CreateIndex 新增索引
type CreateIndex struct {
Name string `json:"name,omitempty"` //索引名
Unique bool `json:"unique,omitempty"` //是否唯一
Keys []CreateIndexKey `json:"keys,omitempty"` //索引字段
}
//CreateIndexKey create index key
type CreateIndexKey struct {
Name string `json:"name,omitempty"` //字段名
Direction string `json:"direction,omitempty"` //字段排序
}
//DropIndex 删除索引
type DropIndex struct {
Name string `json:"name,omitempty"`
}
//DatabaseCollectionReq 新增/删除集合请求参数
type DatabaseCollectionReq struct {
Env string `json:"env,omitempty"` //云环境ID
CollectionName string `json:"collection_name,omitempty"` //集合名称
}
//DatabaseCollectionGetReq 获取特定云环境下集合信息请求
type DatabaseCollectionGetReq struct {
Env string `json:"env,omitempty"` //云环境ID
Limit int64 `json:"limit,omitempty"` //获取数量限制
Offset int64 `json:"offset,omitempty"` //偏移量
}
//DatabaseCollectionGetRes 获取特定云环境下集合信息结果
type DatabaseCollectionGetRes struct {
util.CommonError
Pager struct {
Limit int64 `json:"limit"` //单次查询限制
Offset int64 `json:"offset"` //偏移量
Total int64 `json:"total"` //符合查询条件的记录总数
} `json:"pager"`
Collections []struct {
Name string `json:"name"` //集合名
Count int64 `json:"count"` //表中文档数量
Size int64 `json:"size"` //表的大小(即表中文档总大小),单位:字节
IndexCount int64 `json:"index_count"` //索引数量
IndexSize int64 `json:"index_size"` //索引占用大小,单位:字节
} `json:"collections"`
}
//DatabaseReq 数据库插入/删除/更新/查询/统计记录请求参数
type DatabaseReq struct {
Env string `json:"env,omitempty"` //云环境ID
Query string `json:"query,omitempty"` //数据库操作语句
}
//DatabaseAddRes 数据库插入记录返回结果
type DatabaseAddRes struct {
util.CommonError
IDList []string `json:"id_list"` //插入成功的数据集合主键_id。
}
//DatabaseDeleteRes 数据库删除记录返回结果
type DatabaseDeleteRes struct {
util.CommonError
Deleted int64 `json:"deleted"` //删除记录数量
}
//DatabaseUpdateRes 数据库更新记录返回结果
type DatabaseUpdateRes struct {
util.CommonError
Matched int64 `json:"matched"` //更新条件匹配到的结果数
Modified int64 `json:"modified"` //修改的记录数注意使用set操作新插入的数据不计入修改数目
ID string `json:"id"`
}
//DatabaseQueryRes 数据库查询记录 返回结果
type DatabaseQueryRes struct {
util.CommonError
Pager struct {
Limit int64 `json:"limit"` //单次查询限制
Offset int64 `json:"offset"` //偏移量
Total int64 `json:"total"` //符合查询条件的记录总数
} `json:"pager"`
Data []string `json:"data"`
}
//DatabaseCountRes 统计集合记录数或统计查询语句对应的结果记录数 返回结果
type DatabaseCountRes struct {
util.CommonError
Count int64 `json:"count"` //记录数量
}
//DatabaseMigrateImport 数据库导入
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateImport.html
func (tcb *Tcb) DatabaseMigrateImport(req *DatabaseMigrateImportReq) (*DatabaseMigrateImportRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s", databaseMigrateImportURL, accessToken)
response, err := util.PostJSON(uri, req)
if err != nil {
return nil, err
}
databaseMigrateImportRes := &DatabaseMigrateImportRes{}
err = util.DecodeWithError(response, databaseMigrateImportRes, "DatabaseMigrateImport")
return databaseMigrateImportRes, err
}
//DatabaseMigrateExport 数据库导出
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateExport.html
func (tcb *Tcb) DatabaseMigrateExport(req *DatabaseMigrateExportReq) (*DatabaseMigrateExportRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s", databaseMigrateExportURL, accessToken)
response, err := util.PostJSON(uri, req)
if err != nil {
return nil, err
}
databaseMigrateExportRes := &DatabaseMigrateExportRes{}
err = util.DecodeWithError(response, databaseMigrateExportRes, "DatabaseMigrateExport")
return databaseMigrateExportRes, err
}
//DatabaseMigrateQueryInfo 数据库迁移状态查询
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateQueryInfo.html
func (tcb *Tcb) DatabaseMigrateQueryInfo(env string, jobID int64) (*DatabaseMigrateQueryInfoRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s", databaseMigrateQueryInfoURL, accessToken)
response, err := util.PostJSON(uri, map[string]interface{}{
"env": env,
"job_id": jobID,
})
if err != nil {
return nil, err
}
databaseMigrateQueryInfoRes := &DatabaseMigrateQueryInfoRes{}
err = util.DecodeWithError(response, databaseMigrateQueryInfoRes, "DatabaseMigrateQueryInfo")
return databaseMigrateQueryInfoRes, err
}
//UpdateIndex 变更数据库索引
//https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/updateIndex.html
func (tcb *Tcb) UpdateIndex(req *UpdateIndexReq) error {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return err
}
uri := fmt.Sprintf("%s?access_token=%s", updateIndexURL, accessToken)
response, err := util.PostJSON(uri, req)
if err != nil {
return err
}
return util.DecodeWithCommonError(response, "UpdateIndex")
}
//DatabaseCollectionAdd 新增集合
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionAdd.html
func (tcb *Tcb) DatabaseCollectionAdd(env, collectionName string) error {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return err
}
uri := fmt.Sprintf("%s?access_token=%s", databaseCollectionAddURL, accessToken)
response, err := util.PostJSON(uri, &DatabaseCollectionReq{
Env: env,
CollectionName: collectionName,
})
if err != nil {
return err
}
return util.DecodeWithCommonError(response, "DatabaseCollectionAdd")
}
//DatabaseCollectionDelete 删除集合
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionDelete.html
func (tcb *Tcb) DatabaseCollectionDelete(env, collectionName string) error {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return err
}
uri := fmt.Sprintf("%s?access_token=%s", databaseCollectionDeleteURL, accessToken)
response, err := util.PostJSON(uri, &DatabaseCollectionReq{
Env: env,
CollectionName: collectionName,
})
if err != nil {
return err
}
return util.DecodeWithCommonError(response, "DatabaseCollectionDelete")
}
//DatabaseCollectionGet 获取特定云环境下集合信息
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionGet.html
func (tcb *Tcb) DatabaseCollectionGet(env string, limit, offset int64) (*DatabaseCollectionGetRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s", databaseCollectionGetURL, accessToken)
response, err := util.PostJSON(uri, &DatabaseCollectionGetReq{
Env: env,
Limit: limit,
Offset: offset,
})
if err != nil {
return nil, err
}
databaseCollectionGetRes := &DatabaseCollectionGetRes{}
err = util.DecodeWithError(response, databaseCollectionGetRes, "DatabaseCollectionGet")
return databaseCollectionGetRes, err
}
//DatabaseAdd 数据库插入记录
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseAdd.html
func (tcb *Tcb) DatabaseAdd(env, query string) (*DatabaseAddRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s", databaseAddURL, accessToken)
response, err := util.PostJSON(uri, &DatabaseReq{
Env: env,
Query: query,
})
if err != nil {
return nil, err
}
databaseAddRes := &DatabaseAddRes{}
err = util.DecodeWithError(response, databaseAddRes, "DatabaseAdd")
return databaseAddRes, err
}
//DatabaseDelete 数据库插入记录
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseDelete.html
func (tcb *Tcb) DatabaseDelete(env, query string) (*DatabaseDeleteRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s", databaseDeleteURL, accessToken)
response, err := util.PostJSON(uri, &DatabaseReq{
Env: env,
Query: query,
})
if err != nil {
return nil, err
}
databaseDeleteRes := &DatabaseDeleteRes{}
err = util.DecodeWithError(response, databaseDeleteRes, "DatabaseDelete")
return databaseDeleteRes, err
}
//DatabaseUpdate 数据库插入记录
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseUpdate.html
func (tcb *Tcb) DatabaseUpdate(env, query string) (*DatabaseUpdateRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s", databaseUpdateURL, accessToken)
response, err := util.PostJSON(uri, &DatabaseReq{
Env: env,
Query: query,
})
if err != nil {
return nil, err
}
databaseUpdateRes := &DatabaseUpdateRes{}
err = util.DecodeWithError(response, databaseUpdateRes, "DatabaseUpdate")
return databaseUpdateRes, err
}
//DatabaseQuery 数据库查询记录
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseQuery.html
func (tcb *Tcb) DatabaseQuery(env, query string) (*DatabaseQueryRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s", databaseQueryURL, accessToken)
response, err := util.PostJSON(uri, &DatabaseReq{
Env: env,
Query: query,
})
if err != nil {
return nil, err
}
databaseQueryRes := &DatabaseQueryRes{}
err = util.DecodeWithError(response, databaseQueryRes, "DatabaseQuery")
return databaseQueryRes, err
}
//DatabaseCount 统计集合记录数或统计查询语句对应的结果记录数
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCount.html
func (tcb *Tcb) DatabaseCount(env, query string) (*DatabaseCountRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s", databaseCountURL, accessToken)
response, err := util.PostJSON(uri, &DatabaseReq{
Env: env,
Query: query,
})
if err != nil {
return nil, err
}
databaseCountRes := &DatabaseCountRes{}
err = util.DecodeWithError(response, databaseCountRes, "DatabaseCount")
return databaseCountRes, err
}

134
miniprogram/tcb/file.go Normal file
View File

@@ -0,0 +1,134 @@
package tcb
import (
"fmt"
"github.com/silenceper/wechat/util"
)
const (
//获取文件上传链接
uploadFilePathURL = "https://api.weixin.qq.com/tcb/uploadfile"
//获取文件下载链接
batchDownloadFileURL = "https://api.weixin.qq.com/tcb/batchdownloadfile"
//删除文件链接
batchDeleteFileURL = "https://api.weixin.qq.com/tcb/batchdeletefile"
)
//UploadFileReq 上传文件请求值
type UploadFileReq struct {
Env string `json:"env,omitempty"`
Path string `json:"path,omitempty"`
}
//UploadFileRes 上传文件返回结果
type UploadFileRes struct {
util.CommonError
URL string `json:"url"` //上传url
Token string `json:"token"` //token
Authorization string `json:"authorization"` //authorization
FileID string `json:"file_id"` //文件ID
CosFileID string `json:"cos_file_id"` //cos文件ID
}
//BatchDownloadFileReq 上传文件请求值
type BatchDownloadFileReq struct {
Env string `json:"env,omitempty"`
FileList []*DownloadFile `json:"file_list,omitempty"`
}
//DownloadFile 文件信息
type DownloadFile struct {
FileID string `json:"fileid"` //文件ID
MaxAge int64 `json:"max_age"` //下载链接有效期
}
//BatchDownloadFileRes 上传文件返回结果
type BatchDownloadFileRes struct {
util.CommonError
FileList []struct {
FileID string `json:"file_id"` //文件ID
DownloadURL string `json:"download_url"` //下载链接
Status int64 `json:"status"` //状态码
ErrMsg string `json:"errmsg"` //该文件错误信息
} `json:"file_list"`
}
//BatchDeleteFileReq 批量删除文件请求参数
type BatchDeleteFileReq struct {
Env string `json:"env,omitempty"`
FileIDList []string `json:"fileid_list,omitempty"`
}
//BatchDeleteFileRes 批量删除文件返回结果
type BatchDeleteFileRes struct {
util.CommonError
DeleteList []struct {
FileID string `json:"fileid"`
Status int64 `json:"status"`
ErrMsg string `json:"errmsg"`
} `json:"delete_list"`
}
//UploadFile 上传文件
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/uploadFile.html
func (tcb *Tcb) UploadFile(env, path string) (*UploadFileRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s", uploadFilePathURL, accessToken)
req := &UploadFileReq{
Env: env,
Path: path,
}
response, err := util.PostJSON(uri, req)
if err != nil {
return nil, err
}
uploadFileRes := &UploadFileRes{}
err = util.DecodeWithError(response, uploadFileRes, "UploadFile")
return uploadFileRes, err
}
//BatchDownloadFile 获取文件下载链接
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/batchDownloadFile.html
func (tcb *Tcb) BatchDownloadFile(env string, fileList []*DownloadFile) (*BatchDownloadFileRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s", batchDownloadFileURL, accessToken)
req := &BatchDownloadFileReq{
Env: env,
FileList: fileList,
}
response, err := util.PostJSON(uri, req)
if err != nil {
return nil, err
}
batchDownloadFileRes := &BatchDownloadFileRes{}
err = util.DecodeWithError(response, batchDownloadFileRes, "BatchDownloadFile")
return batchDownloadFileRes, err
}
//BatchDeleteFile 批量删除文件
//reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/batchDeleteFile.html
func (tcb *Tcb) BatchDeleteFile(env string, fileIDList []string) (*BatchDeleteFileRes, error) {
accessToken, err := tcb.GetAccessToken()
if err != nil {
return nil, err
}
uri := fmt.Sprintf("%s?access_token=%s", batchDeleteFileURL, accessToken)
req := &BatchDeleteFileReq{
Env: env,
FileIDList: fileIDList,
}
response, err := util.PostJSON(uri, req)
if err != nil {
return nil, err
}
batchDeleteFileRes := &BatchDeleteFileRes{}
err = util.DecodeWithError(response, batchDeleteFileRes, "BatchDeleteFile")
return batchDeleteFileRes, nil
}

15
miniprogram/tcb/tcb.go Normal file
View File

@@ -0,0 +1,15 @@
package tcb
import "github.com/silenceper/wechat/miniprogram/context"
//Tcb Tencent Cloud Base
type Tcb struct {
*context.Context
}
//NewTcb new Tencent Cloud Base
func NewTcb(context *context.Context) *Tcb {
return &Tcb{
context,
}
}