first commit

This commit is contained in:
2026-02-17 13:06:23 +08:00
commit 7cbd3d061d
349 changed files with 126558 additions and 0 deletions
+242
View File
@@ -0,0 +1,242 @@
package api
import (
"fmt"
"io"
"log"
// "log"
"net/http"
_ "net/http/pprof"
"os"
"path/filepath"
"sync"
"time"
"xiawan/wx/api/middleware"
"xiawan/wx/api/req"
"xiawan/wx/api/router"
"xiawan/wx/api/service"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/db"
"xiawan/wx/db/table"
"xiawan/wx/srv/srvconfig"
"github.com/gin-gonic/gin"
)
func TLog() {
dir, _ := filepath.Abs(filepath.Dir(""))
logFileName := time.Now().Format("20060102") + ".log"
logFileAllPath := dir + "/log/" + logFileName
_, err := os.Stat(logFileAllPath)
var f *os.File
if err != nil {
f, _ = os.Create(logFileAllPath)
} else {
f, _ = os.OpenFile(logFileAllPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
}
gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
gin.DefaultErrorWriter = io.MultiWriter(f, os.Stderr)
log.SetOutput(gin.DefaultWriter)
if srvconfig.GlobalSetting.Debug {
gin.SetMode(gin.DebugMode)
} else {
gin.SetMode(gin.ReleaseMode)
}
}
func WXServerGinHttpApiStart() error {
TLog() // 初始化日志
service.InitWXServerRouter() // 初始化路由
go InitAnewLogin() // 初始化重新上线
// 设置中间件
app := router.SetUpRouter(func(engine *gin.Engine) {
engine.Use(middleware.Cors)
engine.Use(gin.Recovery())
}, false)
// 启动 http 服务
go func() {
_ = http.ListenAndServe(":"+srvconfig.GlobalSetting.Port, nil)
}()
// 启动 gin 服务
err := app.Run(srvconfig.GlobalSetting.Host + ":" + srvconfig.GlobalSetting.Port)
if err != nil {
return err
}
return nil
}
const concurrencyLimit = 100 // 并发限制
// InitAnewLogin 初始化重新上线,后期考虑用分页存redis多线程实现
func InitAnewLogin() {
// 清理缓存
db.DelObj("wx_sync_msg_topic")
db.ClearSyncMsgCache("_syncMsg")
db.ClearSyncMsgCache("_syncHttp")
db.ClearSyncMsgCache("_wx_sync_msg_topic")
db.DelObj("wx_sync_msg_topic")
list := db.QueryListUserInfo()
sem := make(chan struct{}, concurrencyLimit) // 创建带缓冲通道,用于限制并发数
var wg sync.WaitGroup
for _, v := range list {
// 只为已登录的用户初始化连接,避免未登录用户的重连尝试
if v.State == 0 || v.State == 4 { // MMLoginStateNoLogin 或 MMLoginStateLogout
fmt.Printf("跳过未登录用户的连接初始化: %s (状态: %d)\n", v.UUID, v.State)
continue
}
// 初始化代理
key := fmt.Sprintf("%s%s", "wechat:Proxy:", v.UUID)
exists, _ := db.Exists(key)
newModel := &req.GetLoginQrCodeModel{
Proxy: "",
Check: false,
}
if exists {
//获取代理
db.GETObj(key, &newModel)
}
wg.Add(1)
go func(_v table.UserInfoEntity) {
defer wg.Done()
// 获取信号量,确保并发数不超过限制
sem <- struct{}{}
defer func() { <-sem }() // 执行完毕后释放信号量
// 捕获 panic,防止程序崩溃
defer func() {
if r := recover(); r != nil {
fmt.Printf("初始化上线-Recovered from panic: %v\n", r)
// 这里可以记录日志或者执行其他的恢复操作
}
}()
service.InitLoginStatusService(_v.UUID, false, true, *newModel)
}(v)
}
// 等待所有协程完成
wg.Wait()
fmt.Println("初始化上线完成")
// 启动定期清理未登录连接的协程
go func() {
ticker := time.NewTicker(5 * time.Minute) // 每5分钟清理一次
defer ticker.Stop()
for range ticker.C {
cleanupUnloggedConnections()
}
}()
}
// cleanupUnloggedConnections 清理未登录状态的连接
func cleanupUnloggedConnections() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("cleanupUnloggedConnections发生panic: %v\n", r)
}
}()
// fmt.Println("开始清理未登录连接...")
connectMgr := service.WXServer.GetWXConnectMgr()
connectInfo := connectMgr.GetConnectInfo()
// fmt.Printf("连接信息类型: %T\n", connectInfo)
// 安全获取connections
connectionsRaw, exists := connectInfo["connections"]
if !exists {
fmt.Println("警告:没有找到connections字段")
return
}
// fmt.Printf("connections类型: %T\n", connectionsRaw)
connections, ok := connectionsRaw.([]map[string]interface{})
if !ok {
fmt.Printf("错误:connections类型断言失败,实际类型: %T\n", connectionsRaw)
return
}
// fmt.Printf("找到 %d 个连接\n", len(connections))
for _, conn := range connections {
// fmt.Printf("处理连接 %d\n", i)
// 修复类型断言问题:loginState 实际是 uint32 类型
loginStateRaw := conn["loginState"]
// fmt.Printf("loginState原始值: %v, 类型: %T\n", loginStateRaw, loginStateRaw)
var loginState int
// 安全的类型转换
switch v := loginStateRaw.(type) {
case uint32:
loginState = int(v)
case int:
loginState = v
default:
// fmt.Printf("警告:未知的 loginState 类型: %T, 跳过此连接\n", v)
continue
}
// 修复userInfo类型断言问题
userInfoRaw := conn["userInfo"]
// fmt.Printf("userInfo原始值类型: %T\n", userInfoRaw)
var uuid string
// 安全处理不同类型的userInfo
switch v := userInfoRaw.(type) {
case *baseinfo.UserInfo:
uuid = v.UUID
// fmt.Printf("从*baseinfo.UserInfo获取UUID: %s\n", uuid)
case map[string]interface{}:
if uuidRaw, exists := v["UUID"]; exists {
if uuidStr, ok := uuidRaw.(string); ok {
uuid = uuidStr
// fmt.Printf("从map[string]interface{}获取UUID: %s\n", uuid)
} else {
// fmt.Printf("警告:UUID类型不是string,类型: %T, 跳过此连接\n", uuidRaw)
continue
}
} else {
// fmt.Println("警告:userInfo中没有找到UUID字段,跳过此连接")
continue
}
default:
// fmt.Printf("警告:未知的 userInfo 类型: %T, 跳过此连接\n", v)
continue
}
// fmt.Printf("连接 %d: UUID=%s, loginState=%d\n", i, uuid, loginState)
// 如果是未登录或已登出状态,清理连接
if loginState == 0 || loginState == 4 { // MMLoginStateNoLogin 或 MMLoginStateLogout
wxConn := connectMgr.GetWXConnectByUserInfoUUID(uuid)
if wxConn != nil {
// fmt.Printf("清理未登录用户的连接: %s (状态: %d)\n", uuid, loginState)
wxConn.Stop()
connectMgr.Remove(wxConn)
} else {
// fmt.Printf("未找到用户连接对象: %s\n", uuid)
}
}
}
// fmt.Println("清理未登录连接完成")
}
// socks5://ztb44:1454@27.128.157.125:4015
+199
View File
@@ -0,0 +1,199 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"xiawan/wx/srv/srvconfig"
"github.com/gin-gonic/gin"
)
func IsValidAdminKey(key string) (bool, vo.DTO) {
if key == srvconfig.GlobalSetting.AdminKey {
return true, vo.NewSuccess(gin.H{}, "")
}
return false, vo.NewFail("软件授权 ADMIN_KEY 错误")
}
// GenAuthKey1 生成授权码(新设备)
func GenAuthKey1(ctx *gin.Context) {
reqModel := new(req.GenAuthKeyModel)
key, _ := ctx.GetQuery("key")
flag, errRes := IsValidAdminKey(key)
if !flag {
ctx.JSON(http.StatusOK, errRes)
return
}
_ = ctx.ShouldBindJSON(&reqModel)
result := service.GenAuthKeyService(reqModel.Count, reqModel.Days)
ctx.JSON(http.StatusOK, result)
}
// GenAuthKey2 生成授权码(新设备)
func GenAuthKey2(ctx *gin.Context) {
key, _ := ctx.GetQuery("key")
flag, errRes := IsValidAdminKey(key)
if !flag {
ctx.JSON(http.StatusOK, errRes)
return
}
reqModel := new(req.GenAuthKeyModel)
_ = ctx.BindQuery(&reqModel)
result := service.GenAuthKeyService(reqModel.Count, reqModel.Days)
ctx.JSON(http.StatusOK, result)
}
// GenAuthKey3 生成授权码(1-日 7-周 30-月 90-季 180-半年 365-年 30000-永久)此key不使用无过期时间
func GenAuthKey3(ctx *gin.Context) {
reqModel := new(req.GenAuthKeyTypeModel)
key, _ := ctx.GetQuery("key")
flag, errRes := IsValidAdminKey(key)
if !flag {
ctx.JSON(http.StatusOK, errRes)
return
}
_ = ctx.ShouldBindJSON(&reqModel)
result := service.GenAuthKeyService3(reqModel.Count, reqModel.Type)
ctx.JSON(http.StatusOK, result)
}
// 西柚云授权码延期
func DelayAuthKeyNew(ctx *gin.Context) {
reqModel := new(req.DelayAuthKeyModelNew)
_ = ctx.ShouldBindJSON(&reqModel)
key, _ := ctx.GetQuery("key")
_, err := service.CheckKey(key)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
_, err = service.CheckKey(reqModel.KeyUse)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
result := service.DelayAuthKeyServiceNew(key, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// 西柚云解绑授权码
func UnbindAuthKey(ctx *gin.Context) {
key, _ := ctx.GetQuery("key")
_, err := service.CheckKey(key)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
result := service.UnbindAuthKeyService(key)
ctx.JSON(http.StatusOK, result)
}
// 西柚云查看配置
func GetConfig(ctx *gin.Context) {
key, _ := ctx.GetQuery("key")
_, err := service.CheckKey(key)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
result := service.GetConfigService(key)
ctx.JSON(http.StatusOK, result)
}
// DelayAuthKey 授权码延期
func DelayAuthKey(ctx *gin.Context) {
reqModel := new(req.DelayAuthKeyModel)
key, _ := ctx.GetQuery("key")
flag, errRes := IsValidAdminKey(key)
if !flag {
ctx.JSON(http.StatusOK, errRes)
return
}
_ = ctx.ShouldBindJSON(&reqModel)
// 延期授权码 AuthKey
result := service.DelayAuthKeyService(*reqModel)
ctx.JSON(http.StatusOK, result)
}
// DeleteAuthKey 删除授权码
func DeleteAuthKey(ctx *gin.Context) {
reqModel := new(req.DeleteAuthKeyModel)
key, _ := ctx.GetQuery("key")
flag, errRes := IsValidAdminKey(key)
if !flag {
ctx.JSON(http.StatusOK, errRes)
return
}
_ = ctx.ShouldBindJSON(&reqModel)
// 删除授权码 AuthKey
result := service.DeleteAuthKeyService(*reqModel)
ctx.JSON(http.StatusOK, result)
}
// 禁用授权码
func DisableAuthKey(ctx *gin.Context) {
reqModel := new(req.BannedAuthKeyModel)
key, _ := ctx.GetQuery("key")
flag, errRes := IsValidAdminKey(key)
if !flag {
ctx.JSON(http.StatusOK, errRes)
return
}
_ = ctx.ShouldBindJSON(&reqModel)
// 禁用授权码 AuthKey
result := service.BannedAuthKeyService(*reqModel)
ctx.JSON(http.StatusOK, result)
}
// HttpSyncLicenseKey 同步卡密激活状态, HTTP-轮询方式
func HttpSyncLicenseKey(ctx *gin.Context) {
key, _ := ctx.GetQuery("key")
flag, errRes := IsValidAdminKey(key)
if !flag {
ctx.JSON(http.StatusOK, errRes)
return
}
result := service.HttpSyncLicenseKeyService()
ctx.JSON(http.StatusOK, result)
}
// GetLicenseKey 查询卡密有效期
func GetLicenseKey(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetLicenseKeyService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// GetActiveLicenseKeys 查询所有激活状态的卡密
func GetActiveLicenseKeys(ctx *gin.Context) {
adminKey, _ := ctx.GetQuery("key")
flag, errRes := IsValidAdminKey(adminKey)
if !flag {
ctx.JSON(http.StatusOK, errRes)
return
}
result := service.GetActiveLicenseKeysService()
ctx.JSON(http.StatusOK, result)
}
+315
View File
@@ -0,0 +1,315 @@
package controller
import (
"encoding/json"
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"github.com/gin-gonic/gin"
)
// GetA8KeyApi 授权链接
func GetA8KeyApi(ctx *gin.Context) {
reqModel := new(req.GetA8KeyRequestModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetA8KeyService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// JSLoginApi 授权小程序(返回授权后的code)
func JSLoginApi(ctx *gin.Context) {
reqModel := new(req.AppletModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.JsLoginService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// JSOperateWxDataApi 小程序云函数操作
func JSOperateWxDataApi(ctx *gin.Context) {
reqModel := new(req.AppletModel)
reqModel.Opt = 1
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
if len(strings.TrimSpace(reqModel.Data)) == 0 {
reqModel.Data = "{\"with_credentials\":true,\"from_component\":true,\"data\":{\"lang\":\"zh_CN\"},\"api_name\":\"webapi_getuserinfo\"}"
}
var js json.RawMessage
err := json.Unmarshal([]byte(reqModel.Data), &js)
if err != nil {
// 要执行的 小程序云函数 Data 数据不合法
ctx.JSON(http.StatusOK, vo.NewFail("小程序云函数 Data 数据不是合法 JSON"))
return
}
result := service.JSOperateWxDataService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SdkOauthAuthorizeApi app 应用授权
func SdkOauthAuthorizeApi(ctx *gin.Context) {
reqModel := new(req.AppletModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SdkOauthAuthorizeService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QRConnectAuthorizeApi 二维码授权请求
func QRConnectAuthorizeApi(ctx *gin.Context) {
reqModel := new(req.QRConnectAuthorizeModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QRConnectAuthorizeService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QRConnectAuthorizeConfirmApi 二维码授权确认
func QRConnectAuthorizeConfirmApi(ctx *gin.Context) {
reqModel := new(req.QRConnectAuthorizeModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QRConnectAuthorizeConfirmService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetMpA8KeyApi 授权链接
func GetMpA8KeyApi(ctx *gin.Context) {
reqModel := new(req.GetMpA8KeyModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetMpA8Service(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// AuthMpLoginApi 授权公众号登录
func AuthMpLoginApi(ctx *gin.Context) {
reqModel := new(req.GetMpA8KeyModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.AuthMpLoginService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// 获取公众号历史消息
func GetMpHistoryMessageApi(ctx *gin.Context) {
reqModel := new(req.GetMpHistoryMsgModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetAppletHistoryMsg(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetAppMsgExtApi 阅读公众号文章
func GetAppMsgExtApi(ctx *gin.Context) {
reqModel := new(req.ReadParam)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetAppMsgExtService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetAppMsgReadCountApi 获取公众号文章阅读数
func GetAppMsgReadCountApi(ctx *gin.Context) {
reqModel := new(req.ReadParam)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetAppMsgReadCountService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetAppMsgExtLikeApi 点赞公众号文章
func GetAppMsgExtLikeApi(ctx *gin.Context) {
reqModel := new(req.ReadParam)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetAppMsgExtLikeService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// ChannelsLoginApi 视频号助手扫码登录
func ChannelsLoginApi(ctx *gin.Context) {
reqModel := new(req.ChannelsLoginModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ChannelsLoginService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// ShopLoginConfirmApi 微信小店确认登录
func ShopLoginConfirmApi(ctx *gin.Context) {
reqModel := new(req.ShopLoginConfirmModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ShopLoginConfirmService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
func ScanQrcodeEventReportApi(ctx *gin.Context) {
reqModel := new(req.ShopLoginConfirmModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ScanQrcodeEventReportService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
func ExtDeviceLoginConfirmGetApi(ctx *gin.Context) {
reqModel := new(req.ShopLoginConfirmModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ShopLoginConfirmGetService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
func ExtDeviceLoginConfirmOkApi(ctx *gin.Context) {
reqModel := new(req.ShopLoginConfirmModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ShopLoginConfirmOkService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
+23
View File
@@ -0,0 +1,23 @@
package controller
import (
"net/http"
"xiawan/wx/api/vo"
"github.com/gin-gonic/gin"
)
func validateData(ctx *gin.Context, model interface{}) bool {
// ShouldBindJSON
err := ctx.ShouldBindJSON(&model)
if err != nil {
ctx.JSON(http.StatusOK, vo.DTO{
Code: vo.FAIL_DATA,
Data: nil,
Text: "\"提交数据错误!\"",
})
ctx.Abort()
return false
}
return true
}
+92
View File
@@ -0,0 +1,92 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/db"
"xiawan/wx/db/table"
"github.com/gin-gonic/gin"
)
// SetCallbackApi 设置消息回调配置
func SetCallbackApi(ctx *gin.Context) {
config := new(req.MessageCallbackConfigModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &config) {
return
}
// 使用传入的queryKey作为UUID
configInDB := table.MessageCallbackConfig{
UUID: queryKey,
CallbackURL: config.CallbackURL,
Enabled: config.Enabled,
}
// 保存配置到数据库
err := db.SaveMessageCallbackConfig(&configInDB)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail("保存消息回调配置失败: "+err.Error()))
return
}
ctx.JSON(http.StatusOK, vo.NewSuccess(gin.H{}, "设置消息回调成功"))
}
// GetCallbackApi 获取消息回调配置
func GetCallbackApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 查询数据库获取回调配置
config, err := db.GetMessageCallbackConfig(queryKey)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail("获取消息回调配置失败: "+err.Error()))
return
}
if config == nil {
ctx.JSON(http.StatusOK, vo.NewFail("未找到消息回调配置"))
return
}
// 转换为响应模型
response := req.MessageCallbackConfigModel{
CallbackURL: config.CallbackURL,
Enabled: config.Enabled,
}
ctx.JSON(http.StatusOK, vo.NewSuccessObj(response, "获取消息回调配置成功"))
}
// DeleteCallbackApi 删除消息回调配置
func DeleteCallbackApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 从数据库删除回调配置
err := db.DeleteMessageCallbackConfig(queryKey)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail("删除消息回调配置失败: "+err.Error()))
return
}
ctx.JSON(http.StatusOK, vo.NewSuccess(gin.H{}, "删除消息回调配置成功"))
}
+474
View File
@@ -0,0 +1,474 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"github.com/gin-gonic/gin"
)
// AutoRedApi 自动抢红包
func AutoRedApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.AutoRedRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealAutoRed(&params)
// 调用服务逻辑处理
result := service.AutoRedRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// TransferApi 自动接收转账
func TransferApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.AutoTransferRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealTransfer(&params)
// 调用服务逻辑处理
result := service.TransferRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// DelayRedApi 延迟领取红包
func DelayRedApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.DelayRedRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealDelayRed(&params)
// 调用服务逻辑处理
result := service.DelayRedRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// DelayTransferApi 延迟接收转账
func DelayTransferApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.DelayAutoTransferRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealDelayTransfer(&params)
// 调用服务逻辑处理
result := service.DelayTransferRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// KeywordAvoidanceApi 关键字包不抢
func KeywordAvoidanceApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.KeywordAvoidanceRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealKeywordAvoidance(&params)
// 调用服务逻辑处理
result := service.KeywordAvoidanceRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// AutoLikeApi 自动点赞
func AutoLikeApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.AutoLikeRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealAutoLike(&params)
// 调用服务逻辑处理
result := service.AutoLikeRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// AutoForwardApi 朋友圈跟随转发
func AutoForwardApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.AutoForwardRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealAutoForward(&params)
// 调用服务逻辑处理
result := service.AutoForwardRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// FavoriteForwardApi 朋友圈收藏转发
func FavoriteForwardApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.FavoriteForwardRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealFavoriteForward(&params)
// 调用服务逻辑处理
result := service.FavoriteForwardRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// AutoCommentApi 朋友圈自动评论
func AutoCommentApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.AutoCommentRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealAutoComment(&params)
// 调用服务逻辑处理
result := service.AutoCommentRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// MomentsApi 定时发朋友圈
func MomentsApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.MomentsRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealMoments(&params)
// 调用服务逻辑处理
result := service.MomentsRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// MomentsPostApi 发大视频朋友圈
func MomentsPostApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.MomentsPostRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealMomentsPost(&params)
// 调用服务逻辑处理
result := service.MomentsPostRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// WelcomeNewMemberApi 欢迎新人入群
func WelcomeNewMemberApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.WelcomeNewMemberRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealWelcomeNewMember(&params)
// 调用服务逻辑处理
result := service.WelcomeNewMemberRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// KeywordKickApi 关键词自动踢人
func KeywordKickApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.KeywordKickRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealKeywordKick(&params)
// 调用服务逻辑处理
result := service.KeywordKickRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// KeywordAutoReplyApi 关键词自动回复
func KeywordAutoReplyApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.KeywordAutoReplyRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealKeywordAutoReply(&params)
// 调用服务逻辑处理
result := service.KeywordAutoReplyRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// MessageForwardingApi 万群同步
func MessageForwardingApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
// 确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.MessageForwardingRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealMessageForwarding(&params)
// 调用服务逻辑处理
result := service.MessageForwardingRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
// AutoApproveApi 自动通过好友
func AutoApproveApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
// 定义请求模型并绑定参数
var params req.AutoApproveRequestModel
if err := ctx.ShouldBindJSON(&params); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"message": "参数解析错误",
"error": err.Error(),
})
return
}
// 参数完整性、安全性处理
req.DealAutoApprove(&params)
// 调用服务逻辑处理
result := service.AutoApproveRequestService(queryKey, params)
// 返回处理结果
ctx.JSON(http.StatusOK, result)
}
+59
View File
@@ -0,0 +1,59 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"github.com/gin-gonic/gin"
)
// GetFinderSearchApi 视频号搜索
func GetFinderSearchApi(ctx *gin.Context) {
reqModel := new(req.FinderSearchModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetFinderSearchService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// FinderUserPrepareApi 视频号中心
func FinderUserPrepareApi(ctx *gin.Context) {
reqModel := new(req.FinderUserPrepareModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.FinderUserPrepareService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// FinderFollowApi 关注取消
func FinderFollowApi(ctx *gin.Context) {
reqModel := new(req.FinderFollowModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.FinderFollowService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
+88
View File
@@ -0,0 +1,88 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"github.com/gin-gonic/gin"
)
// FavSyncApi 同步收藏
func FavSyncApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.FavSyncService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// GetFavListApi 获取收藏list
func GetFavListApi(ctx *gin.Context) {
reqModel := new(req.FavInfoModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetFavListService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetFavInfoApi 获取收藏信息
func GetFavInfoApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetFavInfoService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// BatchDelFavItemApi 删除收藏
func BatchDelFavItemApi(ctx *gin.Context) {
reqModel := new(req.FavInfoModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.BatchDelFavItemService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// BatchGetFavItemApi 获取收藏详细
func BatchGetFavItemApi(ctx *gin.Context) {
reqModel := new(req.FavInfoModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.BatchGetFavItemService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
+27
View File
@@ -0,0 +1,27 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"github.com/gin-gonic/gin"
)
// UploadAppAttachApi 上传文件
func UploadAppAttachApi(ctx *gin.Context) {
reqModel := new(req.UploadAppAttachModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.UploadAppAttachService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
+230
View File
@@ -0,0 +1,230 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"github.com/gin-gonic/gin"
)
// GetContactListApi 获取全部联系人
func GetContactListApi(ctx *gin.Context) {
reqModel := new(req.GetContactListModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetContactListService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetFriendListApi 获取好友列表
func GetFriendListApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetFriendListService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// GetGroupListApi 获取保存的群聊列表
func GetGroupListApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetGroupListService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// GetGHListApi 获取关注的公众号列表
func GetGHListApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetGHListService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// FollowGHApi 关注公众号
func FollowGHApi(ctx *gin.Context) {
reqModel := new(req.FollowGHModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.FollowGHService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// UploadMContactApi 上传手机通讯录好友
func UploadMContactApi(ctx *gin.Context) {
reqModel := new(req.UploadMContactModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.UploadMContactService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetMFriendApi 获取手机通讯录好友
func GetMFriendApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetMFriendService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// GetContactContactApi 获取联系人详情
func GetContactContactApi(ctx *gin.Context) {
reqModel := new(req.BatchGetContactModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetContactContactService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetFriendRelationApi 获取好友关系
func GetFriendRelationApi(ctx *gin.Context) {
reqModel := new(req.GetFriendRelationModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetFriendRelationService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SearchContactRequestApi 搜索联系人
func SearchContactRequestApi(ctx *gin.Context) {
reqModel := new(req.SearchContactRequestModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SearchContactRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// VerifyUserRequestApi 验证好友/添加好友
func VerifyUserRequestApi(ctx *gin.Context) {
reqModel := new(req.VerifyUserRequestModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.VerifyUserRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// AgreeAddApi 同意好友请求
func AgreeAddApi(ctx *gin.Context) {
reqModel := new(req.VerifyUserRequestModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
if reqModel.Scene == 0 {
reqModel.Scene = 0x06
}
result := service.VerifyUserRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// DetectDeadFans 检测僵死粉
func DetectDeadFans(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.StartFriendTaskService(queryKey, 1) // 1表示检测僵死粉任务
ctx.JSON(http.StatusOK, result)
}
// CleanDeadFans 清理僵死粉
func CleanDeadFans(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.StartFriendTaskService(queryKey, 2) // 2表示清理僵死粉任务
ctx.JSON(http.StatusOK, result)
}
+368
View File
@@ -0,0 +1,368 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"github.com/gin-gonic/gin"
)
// GetChatroomQrCode 获取群二维码
func GetChatroomQrCode(ctx *gin.Context) {
reqModel := new(req.GetChatroomQrCodeModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
if !strings.HasSuffix(reqModel.ChatRoomName, "@chatroom") {
ctx.JSON(http.StatusOK, vo.NewFail("非法的 ChatRoomId"))
return
}
result := service.GetChatroomQrCodeService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetChatroomAnnouncementApi 设置群公告
func SetChatroomAnnouncementApi(ctx *gin.Context) {
reqModel := new(req.UpdateChatroomAnnouncementModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetChatroomAnnouncementService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetChatroomMemberDetailApi 获取群成员详细
func GetChatroomMemberDetailApi(ctx *gin.Context) {
reqModel := new(req.GetChatroomMemberDetailModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetChatroomMemberDetailService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetQuitChatroomApi 退出群聊
func GetQuitChatroomApi(ctx *gin.Context) {
reqModel := new(req.GetChatroomMemberDetailModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QuitChatroomService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// CreateChatRoomApi 创建群请求
func CreateChatRoomApi(ctx *gin.Context) {
reqModel := new(req.CreateChatRoomModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.CreateChatRoomService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// InviteChatroomMembersApi 邀请群成员
func InviteChatroomMembersApi(ctx *gin.Context) {
reqModel := new(req.InviteChatroomMembersModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.InviteChatroomMembersService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// AddChatRoomMembersApi 添加群成员
func AddChatRoomMembersApi(ctx *gin.Context) {
reqModel := new(req.InviteChatroomMembersModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.AddChatRoomMemberService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// ScanIntoUrlGroupApi 扫码入群
func ScanIntoUrlGroupApi(ctx *gin.Context) {
reqModel := new(req.ScanIntoUrlGroupModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ScanIntoUrlGroupService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendAddChatRoomMemberApi 添加好友进群
func SendAddChatRoomMemberApi(ctx *gin.Context) {
reqModel := new(req.InviteChatroomMembersModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.AddChatRoomMemberService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendDelDelChatRoomMemberApi 删除群成员
func SendDelDelChatRoomMemberApi(ctx *gin.Context) {
reqModel := new(req.InviteChatroomMembersModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendDelDelChatRoomMemberService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendTransferGroupOwnerApi 转让群
func SendTransferGroupOwnerApi(ctx *gin.Context) {
reqModel := new(req.TransferGroupOwnerModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendTransferGroupOwnerService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// ConsentToJoinGroupApi 同意入群
func ConsentToJoinGroupApi(ctx *gin.Context) {
reqModel := new(req.ConsentToJoinGroupModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ConsentToJoinGroupService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetGetChatRoomInfoDetailApi 获取群公告
func SetGetChatRoomInfoDetailApi(ctx *gin.Context) {
reqModel := new(req.GetChatroomMemberDetailModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetGetChatRoomInfoDetailService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetChatRoomInfoApi 获取群详情
func GetChatRoomInfoApi(ctx *gin.Context) {
reqModel := new(req.ChatRoomWxIdListModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetChatRoomInfoService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// MoveToContractApi 获取群聊
func MoveToContractApi(ctx *gin.Context) {
reqModel := new(req.MoveContractModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.MoveToContractService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetChatroomAccessVerifyApi 设置群聊邀请开关
func SetChatroomAccessVerifyApi(ctx *gin.Context) {
reqModel := new(req.SetChatroomAccessVerifyModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetChatroomAccessVerifyService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// AddChatroomAdminApi 添加群管理员
func AddChatroomAdminApi(ctx *gin.Context) {
reqModel := new(req.ChatroomMemberModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.AddChatroomAdminService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// DelChatroomAdminApi 删除群管理员
func DelChatroomAdminApi(ctx *gin.Context) {
reqModel := new(req.ChatroomMemberModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.DelChatroomAdminService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetChatroomNameApi 设置群昵称
func SetChatroomNameApi(ctx *gin.Context) {
reqModel := new(req.ChatroomNameModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetChatroomNameService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendPatApi 群拍一拍功能
func SendPatApi(ctx *gin.Context) {
reqModel := new(req.SendPatModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendPatService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GroupListApi 获取群列表
func GroupListApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.NewSyncHistoryMessageService(queryKey)
ctx.JSON(http.StatusOK, result)
}
+99
View File
@@ -0,0 +1,99 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"github.com/gin-gonic/gin"
)
// GetContactLabelListApi 获取标签列表
func GetContactLabelListApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetContactLabelListRequestService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// AddContactLabelRequestApi 添加列表
func AddContactLabelRequestApi(ctx *gin.Context) {
reqModel := new(req.LabelModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.AddContactLabelRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// DelContactLabelRequestApi 删除标签
func DelContactLabelRequestApi(ctx *gin.Context) {
reqModel := new(req.LabelModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.DelContactLabelRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// ModifyLabelRequestApi 修改标签
func ModifyLabelRequestApi(ctx *gin.Context) {
reqModel := new(req.LabelModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ModifyLabelRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetWXFriendListByLabelIDApi 获取标签下所有好友
func GetWXFriendListByLabelIDApi(ctx *gin.Context) {
reqModel := new(req.LabelModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetWXFriendListByLabelIDService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
+437
View File
@@ -0,0 +1,437 @@
package controller
import (
"errors"
"fmt"
"math/rand"
"net/http"
"os"
"strings"
"time"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseutils"
"xiawan/wx/db"
"github.com/gin-gonic/gin"
"github.com/gogf/guuid"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
// 检查请求参数 key 对应的 license 是否可用
func checkLicense(ctx *gin.Context) (string, error) {
queryKey, isExist := ctx.GetQuery("key")
errMsg := fmt.Sprintf("%s 该 key 无效! 请 检查正确性 或 联系管理员生成", queryKey)
if !isExist || len(strings.TrimSpace(queryKey)) == 0 {
// 请求参数中没有携带 license 或者 license 为空
return "", errors.New(errMsg)
}
has, err := db.HasLicense(queryKey)
if has == nil || err != nil {
// MySQL 数据库没有该 license
return "", errors.New(errMsg)
}
if db.CheckExpiry(has.ExpiryDate, has.Type) {
// MySQL 数据库中的该 license 已过期
return "", errors.New(fmt.Sprintf("%s 该 key 已过期!", queryKey))
}
// license 可用
return queryKey, nil
}
// GetLoginQrCodeTempShow HTML展示登录二维码
func GetLoginQrCodeTempShow(ctx *gin.Context) {
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
//获取二维码
qrcodeResponse, dto := service.GetLoginQrCodeShow(queryKey)
// 二维码写入到文件
baseutils.WriteToFile(qrcodeResponse.GetQrcode().GetSrc(), "static/qrcode/"+qrcodeResponse.GetUuid()+".png")
// 延时删除图片
go func() {
time.Sleep(time.Second * 10)
err := os.Remove("static/qrcode/" + qrcodeResponse.GetUuid() + ".png")
if err != nil {
return
}
}()
if dto.Code == vo.SUCCESS {
ctx.HTML(http.StatusOK, "login.tmpl", gin.H{"img": qrcodeResponse.GetUuid()})
} else {
ctx.HTML(http.StatusOK, "err.tmpl", gin.H{"showlog": dto})
}
}
// GetLoginQrCodeNewApi 获取登录二维码-iPad(异地IP必须用代理! socks5://username:password@ipv4:port)
func GetLoginQrCodeNewApi(ctx *gin.Context) {
reqModel := new(req.GetLoginQrCodeModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetLoginQrCodeNewService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetLoginQrCodeNewApi 获取登录二维码-直登(异地IP必须用代理! socks5://username:password@ipv4:port)
func GetLoginQrCodeNewApiDirect(ctx *gin.Context) {
reqModel := new(req.GetLoginQrCodeModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetLoginQrCodeNewServiceDirect(queryKey, *reqModel, reqModel.IpadOrmac)
ctx.JSON(http.StatusOK, result)
}
// WxBindOpMobileForRegApi 获取验证码
func WxBindOpMobileForRegApi(ctx *gin.Context) {
reqModel := new(req.WxBindOpMobileForModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.WxBindOpMobileForRegService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// Get62DataApi 提取62数据
func Get62DataApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist {
queryKey = guuid.New().String()
}
result := service.Get62DataService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// PhoneDeviceLoginApi 辅助新手机登录
func PhoneDeviceLoginApi(ctx *gin.Context) {
reqModel := new(req.PhoneLoginModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.PhoneDeviceLoginService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// DeviceIdLoginApi 62账号密码登录
func DeviceIdLoginApi(ctx *gin.Context) {
reqModel := new(req.DeviceIdLoginModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.DeviceIdLoginService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SmsLoginApi 短信登录
func SmsLoginApi(ctx *gin.Context) {
reqModel := new(req.DeviceIdLoginModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
reqModel.Password = "strdm@," + reqModel.Password
result := service.SmsLoginService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// A16LoginApi A16数据登录
func A16LoginApi(ctx *gin.Context) {
reqModel := new(req.DeviceIdLoginModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.A16LoginService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// LoginNewApi 62LoginNew新疆号登录
func LoginNewApi(ctx *gin.Context) {
reqModel := new(req.DeviceIdLoginModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
reqModel.Type = 1
result := service.A16LoginService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// CheckLoginStatusApi 检测扫码状态
func CheckLoginStatusApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.CheckLoginQrCodeStatusService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// GetInItStatusApi 初始化状态
func GetInItStatusApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetInItStatusService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// WakeUpLoginApi 唤醒登录(只限扫码登录)
func WakeUpLoginApi(ctx *gin.Context) {
reqModel := new(req.GetLoginQrCodeModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.WakeUpLoginService(queryKey, reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetLoginStatusApi 获取在线状态
func GetLoginStatusApi(ctx *gin.Context) {
autoLogin := true
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
isAutoLogin, isExist := ctx.GetQuery("autoLogin")
if isExist {
if strings.Contains(isAutoLogin, "false") {
autoLogin = false
}
}
result := service.GetLoginStatusService(queryKey, false, autoLogin)
ctx.JSON(http.StatusOK, result)
}
// GetSafetyInfoApi 获取安全设备列表
func GetSafetyInfoApi(ctx *gin.Context) {
queryKey, _ := ctx.GetQuery("key")
result := service.GetSafetyInfoService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// DelSafeDeviceApi 删除安全设备
func DelSafeDeviceApi(ctx *gin.Context) {
reqModel := new(req.DelSafeDeviceModel)
queryKey, _ := ctx.GetQuery("key")
if !validateData(ctx, &reqModel) {
return
}
result := service.DelSafeDeviceService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetBoundHardDevice 获取硬件设备情况
func GetBoundHardDevice(ctx *gin.Context) {
queryKey, _ := ctx.GetQuery("key")
result := service.GetBoundHardDeviceService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// CheckCanSetAliasApi 检测微信登录环境
func CheckCanSetAliasApi(ctx *gin.Context) {
queryKey, _ := ctx.GetQuery("key")
result := service.CheckCanSetAliasService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// IWXConnectMgrApi 打印链接数量
func IWXConnectMgrApi(ctx *gin.Context) {
result := service.IWXConnectMgrService()
ctx.JSON(http.StatusOK, result)
}
// GetConnectInfo 打印链接信息
func GetConnectInfo(ctx *gin.Context) {
result := service.GetConnectInfo()
ctx.JSON(http.StatusOK, result)
}
// LogOutRequestApi 退出登录
func LogOutRequestApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.LogOutService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// MacLoginApi 获取Mac登录二维码 (异地IP必须用代理 socks5://username:password@ipv4:port)
func MacLoginApi(ctx *gin.Context) {
reqModel := new(req.GetLoginQrCodeModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.MacLoginService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// AndroidPadLoginApi 获取安卓平板登录二维码 (异地IP必须用代理 socks5://username:password@ipv4:port)
func AndroidPadLoginApi(ctx *gin.Context) {
reqModel := new(req.GetLoginQrCodeModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.AndroidPadLoginService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// CarLoginApi 获取车载登录二维码 (异地IP必须用代理 socks5://username:password@ipv4:port)
func CarLoginApi(ctx *gin.Context) {
reqModel := new(req.GetLoginQrCodeModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.CarLoginService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// VerifyCodeApi 验证码验证(输入iPad登录验证码)
func VerifyCodeApi(ctx *gin.Context) {
reqModel := new(req.VerifyCodeModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
param := req.VerifyCodeModel{
Code: reqModel.Code,
Data62: reqModel.Data62,
Ticket: reqModel.Ticket,
}
result := service.Verificationcode2(param, queryKey)
ctx.JSON(http.StatusOK, result)
}
// VerifyCodeSlideApi 过mac滑块验证
func VerifyCodeApiSlide(ctx *gin.Context) {
reqModel := new(req.SlideTicketModel)
queryKey, _ := ctx.GetQuery("key")
if queryKey != "1234520" {
ctx.JSON(http.StatusOK, vo.NewFail("key错误"))
return
}
if !validateData(ctx, &reqModel) {
return
}
param := req.SlideTicketModel{
Data62: reqModel.Data62,
Ticket: reqModel.Ticket,
RandStr: reqModel.RandStr,
SlideTicket: reqModel.SlideTicket,
}
result := service.VerificationcodeSlide(param)
ctx.JSON(http.StatusOK, result)
}
// WinLoginService win登录
func WinLoginService(ctx *gin.Context) {
reqModel := new(req.GetLoginQrCodeModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.WinLoginService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
+479
View File
@@ -0,0 +1,479 @@
package controller
import (
"net/http"
"strings"
req "xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"log"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
// AddMessageMgrApi 添加要发送的文本消息进入管理器
func AddMessageMgrApi(ctx *gin.Context) {
reqModel := new(req.SendMessageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.AddMessageMgrService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
var (
upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
)
// GetSyncMsgApi 同步消息,ws协议; 下面有【同步消息-HTTP-轮询方式】
// GetSyncMsgApi 处理同步消息的 API 请求。
// 它从请求中获取查询参数 "key",如果不存在或为空,则返回 400 错误和相应的错误信息。
// 如果 "key" 有效,则调用 WebSocketHandler 进行后续处理。
func GetSyncMsgApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
ctx.JSON(http.StatusBadRequest, gin.H{
"error": "无效的key",
})
return
}
service.WebSocketHandler(ctx, queryKey)
return
}
// HttpSyncMsg 同步消息, HTTP-轮询方式
func HttpSyncMsg(ctx *gin.Context) {
reqModel := new(req.SyncMessageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(queryKey))
return
}
_ = ctx.ShouldBindJSON(&reqModel)
if reqModel.Count < 0 {
ctx.JSON(http.StatusOK, vo.NewFail("Count参数错误"))
return
}
result := service.HttpSyncMsg(queryKey, reqModel.Count)
ctx.JSON(http.StatusOK, result)
}
// SendImageMessageApi 发送图片消息
func SendImageMessageApi(ctx *gin.Context) {
reqModel := new(req.SendMessageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(queryKey))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendImageMessageService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendImageNewMessageApi 发送图片消息(New
func SendImageNewMessageApi(ctx *gin.Context) {
reqModel := new(req.SendMessageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Keys
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendImageNewMessageService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendTextMessageApi 发送文本消息
func SendTextMessageApi(ctx *gin.Context) {
reqModel := new(req.SendMessageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendTextMessageService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// ShareCardMessageApi 分享名片消息
func ShareCardMessageApi(ctx *gin.Context) {
reqModel := new(req.ShareCardParam)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ShareCardMessageService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendTextMessageNoShow 不显示会话(不删聊天记录)
func SendTextMessageNoShow(ctx *gin.Context) {
reqModel := new(req.MessageNoShowParam)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendTextMessageNoShowService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// ForwardImageMessageApi 转发图片
func ForwardImageMessageApi(ctx *gin.Context) {
reqModel := new(req.ForwardMessageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ForwardImageMessageService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// ForwardVideoMessageApi 转发视频
func ForwardVideoMessageApi(ctx *gin.Context) {
reqModel := new(req.ForwardMessageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ForwardVideoMessageService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendEmojiMessageApi 发送表情
func SendEmojiMessageApi(ctx *gin.Context) {
reqModel := new(req.SendEmojiMessageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendEmojiMessageService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// ForwardEmojiApi 转发表情,包含动图
func ForwardEmojiApi(ctx *gin.Context) {
reqModel := new(req.SendEmojiMessageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ForwardEmojiService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendAppMessageApi 发送App消息
func SendAppMessageApi(ctx *gin.Context) {
reqModel := new(req.AppMessageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendAppMessageService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// RevokeMsgApi 撤销消息
func RevokeMsgApi(ctx *gin.Context) {
reqModel := new(req.RevokeMsgModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.RevokeMsgService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// RevokeMsgNewApi 撤回消息(New
func RevokeMsgNewApi(ctx *gin.Context) {
reqModel := new(req.RevokeMsgModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
// 检查是否有ClientImgIdStr字段,如果有则是图片消息
if reqModel.ClientImgIdStr != "" {
reqModel.IsImage = true
log.Printf("尝试撤回图片消息: NewMsgId=%s, ClientMsgId=%d, CreateTime=%d, ClientImgIdStr=%s",
reqModel.NewMsgId, reqModel.ClientMsgId, reqModel.CreateTime, reqModel.ClientImgIdStr)
}
result := service.RevokeMsgNewService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// UploadVoiceRequestApi 发送语音
func UploadVoiceRequestApi(ctx *gin.Context) {
reqModel := new(req.SendUploadVoiceRequestModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.UploadVoiceRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// CdnUploadVideoRequestApi 上传视频
func CdnUploadVideoRequestApi(ctx *gin.Context) {
reqModel := new(req.CdnUploadVideoRequest)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendCdnUploadVideoRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendCdnDownloadApi 下载 请求
func SendCdnDownloadApi(ctx *gin.Context) {
reqModel := new(req.DownMediaModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendCdnDownloadService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetMsgBigImgApi 获取图片(高清图片下载)
func GetMsgBigImgApi(ctx *gin.Context) {
reqModel := new(req.DownloadParam)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetMsgBigImgService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetMsgVideoApi 获取视频(视频数据下载)
func GetMsgVideoApi(ctx *gin.Context) {
reqModel := new(req.DownloadParam)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetMsgVideoService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// NewSyncHistoryMessageApi 同步历史消息
func NewSyncHistoryMessageApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.NewSyncHistoryMessageService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// GroupMassMsgTextApi 群发接口
func GroupMassMsgTextApi(ctx *gin.Context) {
reqModel := new(req.GroupMassMsgTextModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GroupMassMsgTextService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GroupMassMsgImageApi 群发图片
func GroupMassMsgImageApi(ctx *gin.Context) {
reqModel := new(req.GroupMassMsgImageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GroupMassMsgImageService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetMsgVoiceApi 下载语音消息
func GetMsgVoiceApi(ctx *gin.Context) {
reqModel := new(req.DownloadVoiceModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetMsgVoiceService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// DownloadEmojiGifApi 下载表情
func DownloadEmojiGifApi(ctx *gin.Context) {
reqModel := new(req.DownloadEmojiModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(queryKey))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.DownloadEmojiGifService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// UploadImageToCDNApi 纯CDN图片上传接口
func UploadImageToCDNApi(ctx *gin.Context) {
reqModel := new(req.UploadImageToCDNModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.UploadImageToCDNService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
+158
View File
@@ -0,0 +1,158 @@
package controller
import (
"encoding/xml"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"github.com/gin-gonic/gin"
)
// GetMyQrCode 获取我的二维码
func GetMyQrCode(ctx *gin.Context) {
reqModel := new(req.GetQrCodeModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetMyQrCodeService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetPeopleNearbyApi 查看附近的人
func GetPeopleNearbyApi(ctx *gin.Context) {
reqModel := new(req.PeopleNearbyModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetPeopleNearbyService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// UpdateCmdStatusApi 更新指令状态, key 为指令 idValue 为指令状态 0|1ValueStr 为字符串值
func UpdateCmdStatusApi(ctx *gin.Context) {
reqModel := new(req.ModifyCmdStatusModelNew)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.UpdateCmdStatusService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetProjectFullPathApi 获取项目完整路径
func GetProjectFullPathApi(ctx *gin.Context) {
execPath, err := os.Executable() // 获取可执行文件的路径
if err != nil {
log.Fatalf("Failed to get executable path: %v", err)
ctx.JSON(http.StatusNotFound, "")
return
}
execPath, err = filepath.EvalSymlinks(execPath) // 解析符号链接,获取真实路径
if err != nil {
log.Fatalf("Failed to evaluate symlinks: %v", err)
ctx.JSON(http.StatusNotFound, "")
return
}
// 获取可执行文件所在目录
dir := filepath.Dir(execPath)
ctx.JSON(http.StatusOK, dir)
}
// 企微图片下载
func QWImageDownloadApi(ctx *gin.Context) {
reqModel := new(req.DownloadQWImageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
// 解析XML,提取 AesKey / FileURL / FileType
type imageXML struct {
XMLName xml.Name `xml:"msg"`
Img struct {
AESKey string `xml:"aeskey,attr"`
CdnMidImgURL string `xml:"cdnmidimgurl,attr"`
CdnThumbURL string `xml:"cdnthumburl,attr"`
TpURL string `xml:"tpurl,attr"`
TpThumbAESKey string `xml:"tpthumbaeskey,attr"`
} `xml:"img"`
}
var parsed imageXML
if err := xml.Unmarshal([]byte(reqModel.Xml), &parsed); err != nil {
ctx.JSON(http.StatusOK, vo.NewFail("XML解析失败:"+err.Error()))
return
}
aesKey := strings.TrimSpace(parsed.Img.AESKey)
if aesKey == "" {
aesKey = strings.TrimSpace(parsed.Img.TpThumbAESKey)
}
fileURL := ""
tpurl := strings.TrimSpace(parsed.Img.TpURL)
if tpurl != "" {
if u, err := url.Parse(tpurl); err == nil {
f := u.Query().Get("f")
if f != "" {
fileURL = f
} else {
// 回退为完整tpurl(如果缺少f参数)
fileURL = tpurl
}
} else {
fileURL = tpurl
}
} else {
fileURL = strings.TrimSpace(parsed.Img.CdnMidImgURL)
if fileURL == "" {
fileURL = strings.TrimSpace(parsed.Img.CdnThumbURL)
}
}
if aesKey == "" || fileURL == "" {
ctx.JSON(http.StatusOK, vo.NewFail("参数错误:无法从XML提取必要字段(AesKey或FileURL)"))
return
}
model := req.DownMediaModel{
AesKey: aesKey,
FileURL: fileURL,
FileType: 1, // 默认 1
}
result := service.SendCdnDownloadService(queryKey, model)
ctx.JSON(http.StatusOK, result)
}
+153
View File
@@ -0,0 +1,153 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"github.com/gin-gonic/gin"
)
// GetBandCardListApi 获取银行卡信息
func GetBandCardListApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetBandCardListService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// GeneratePayQCodeApi 生成自定义收款二维码
func GeneratePayQCodeApi(ctx *gin.Context) {
reqModel := new(req.GeneratePayQCodeModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GeneratePayQCodeService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// CollectMoneyApi 确定收款
func CollectMoneyApi(ctx *gin.Context) {
reqModel := new(req.CollectmoneyModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.CollectMoneyService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// WXCreateRedPacketApi 创建红包
func WXCreateRedPacketApi(ctx *gin.Context) {
reqModel := new(baseinfo.RedPacket)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.WXCreateRedPacketService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// OpenRedEnvelopesApi 拆红包
func OpenRedEnvelopesApi(ctx *gin.Context) {
reqModel := new(baseinfo.HongBaoItem)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.OpenRedEnvelopesService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QueryRedEnvelopesDetailApi 查看红包详情
func QueryRedEnvelopesDetailApi(ctx *gin.Context) {
reqModel := new(baseinfo.HongBaoItem)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QueryRedEnvelopesDetailService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetRedPacketListApi 查看红包领取列表
func GetRedPacketListApi(ctx *gin.Context) {
reqModel := new(baseinfo.GetRedPacketList)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetRedPacketListService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// CreatePreTransferApi 创建转账
func CreatePreTransferApi(ctx *gin.Context) {
reqModel := new(req.CreatePreTransfer)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.CreatePreTransferService(queryKey, reqModel)
ctx.JSON(http.StatusOK, result)
}
// ConfirmPreTransferApi 确认转账(客户端版本过低会无法转账)
func ConfirmPreTransferApi(ctx *gin.Context) {
reqModel := new(req.ConfirmPreTransfer)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.ConfirmPreTransferService(queryKey, reqModel)
ctx.JSON(http.StatusOK, result)
}
@@ -0,0 +1,27 @@
package controller
import (
"net/http"
"xiawan/wx/api/service"
"github.com/gin-gonic/gin"
)
// GetProxyMappingList 获取代理映射列表
func GetProxyMappingList(ctx *gin.Context) {
list, err := service.GetProxyMappingList()
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{
"code": -1,
"msg": err.Error(),
"data": nil,
})
return
}
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"msg": "success",
"data": list,
})
}
+375
View File
@@ -0,0 +1,375 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"github.com/gin-gonic/gin"
)
// QWContactApi 提取企业 wx 详情
func QWContactApi(ctx *gin.Context) {
reqModel := new(req.QWContactModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWContactService(queryKey, reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWSyncContactApi 提取全部的企业通讯录
func QWSyncContactApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.QWSyncContactService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// QWRemarkApi 备注企业 wxid
func QWRemarkApi(ctx *gin.Context) {
reqModel := new(req.QWRemarkModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWRemarkService(queryKey, reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWCreateChatRoomApi 创建企业群
func QWCreateChatRoomApi(ctx *gin.Context) {
reqModel := new(req.QWCreateModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWCreateChatRoomService(queryKey, reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWSearchContactApi 搜手机或企业对外名片链接提取验证
func QWSearchContactApi(ctx *gin.Context) {
reqModel := new(req.SearchContactModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWSearchContactService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWApplyAddContactApi 向企业微信打招呼
func QWApplyAddContactApi(ctx *gin.Context) {
reqModel := new(req.QWApplyAddContactModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWApplyAddContactService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWAddContactApi 单向加企业微信
func QWAddContactApi(ctx *gin.Context) {
reqModel := new(req.QWApplyAddContactModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWAddContactService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWSyncChatRoomApi 提取全部企业微信群-
func QWSyncChatRoomApi(ctx *gin.Context) {
reqModel := new(req.QWSyncChatRoomModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWSyncChatRoomService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWChatRoomTransferOwnerApi 转让企业群
func QWChatRoomTransferOwnerApi(ctx *gin.Context) {
reqModel := new(req.QWChatRoomTransferOwnerModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWChatRoomTransferOwnerService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWAddChatRoomMemberApi 直接拉朋友进企业群
func QWAddChatRoomMemberApi(ctx *gin.Context) {
reqModel := new(req.QWAddChatRoomMemberModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWAddChatRoomMemberService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWInviteChatRoomMemberApi 发送群邀请链接
func QWInviteChatRoomMemberApi(ctx *gin.Context) {
reqModel := new(req.QWAddChatRoomMemberModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWInviteChatRoomMemberService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWDelChatRoomMemberApi 删除企业群成员
func QWDelChatRoomMemberApi(ctx *gin.Context) {
reqModel := new(req.QWAddChatRoomMemberModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWDelChatRoomMemberService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWGetChatRoomMemberApi 提取企业群全部成员
func QWGetChatRoomMemberApi(ctx *gin.Context) {
reqModel := new(req.QWAddChatRoomMemberModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWGetChatRoomMemberService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWGetChatroomInfoApi 提取企业群名称公告设定等信息
func QWGetChatroomInfoApi(ctx *gin.Context) {
reqModel := new(req.QWAddChatRoomMemberModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWGetChatroomInfoService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWGetChatRoomQRApi 提取企业群二维码
func QWGetChatRoomQRApi(ctx *gin.Context) {
reqModel := new(req.QWAddChatRoomMemberModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWGetChatRoomQRService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWAppointChatRoomAdminApi 增加企业管理员
func QWAppointChatRoomAdminApi(ctx *gin.Context) {
reqModel := new(req.QWAddChatRoomMemberModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWAppointChatRoomAdminService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWDelChatRoomAdminApi 移除群管理员
func QWDelChatRoomAdminApi(ctx *gin.Context) {
reqModel := new(req.QWAddChatRoomMemberModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWDelChatRoomAdminService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWAcceptChatRoomRequestApi 同意进企业群
func QWAcceptChatRoomRequestApi(ctx *gin.Context) {
reqModel := new(req.QWAcceptChatRoomModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWAcceptChatRoomRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWAdminAcceptJoinChatRoomSetApi 设定企业群管理审核进群
func QWAdminAcceptJoinChatRoomSetApi(ctx *gin.Context) {
reqModel := new(req.QWAdminAcceptJoinChatRoomSetModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWAdminAcceptJoinChatRoomSetService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWModChatRoomNameApi 修改企业群名称
func QWModChatRoomNameApi(ctx *gin.Context) {
reqModel := new(req.QWModChatRoomNameModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWModChatRoomNameService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWModChatRoomMemberNickApi 修改成员在群中呢称
func QWModChatRoomMemberNickApi(ctx *gin.Context) {
reqModel := new(req.QWModChatRoomNameModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWModChatRoomMemberNickService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWChatRoomAnnounceApi 发布企业群公告
func QWChatRoomAnnounceApi(ctx *gin.Context) {
reqModel := new(req.QWModChatRoomNameModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.QWChatRoomAnnounceService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// QWDelChatRoomApi 删除企业群
func QWDelChatRoomApi(ctx *gin.Context) {
reqModel := new(req.QWModChatRoomNameModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendQWDelChatRoomService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
+288
View File
@@ -0,0 +1,288 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"github.com/gin-gonic/gin"
)
// DownloadMediaApi 下载朋友圈视频
func DownloadMediaApi(ctx *gin.Context) {
reqModel := new(req.DownloadMediaModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.DownloadMediaService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetFriendCircleDaysApi 设置朋友圈可见天数
func SetFriendCircleDaysApi(ctx *gin.Context) {
reqModel := new(req.SetFriendCircleDaysModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetFriendCircleDaysService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendFriendCircleApi 发送朋友圈
func SendFriendCircleApi(ctx *gin.Context) {
reqModel := new(req.SnsPostItemModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendFriendCircleService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendFriendCircleByXMlApi 发送朋友圈XML结构
func SendFriendCircleByXMlApi(ctx *gin.Context) {
reqModel := new(baseinfo.TimelineObject)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendFriendCircleByXMlService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// UploadFriendCircleImageApi 上传图片信息
func UploadFriendCircleImageApi(ctx *gin.Context) {
reqModel := new(req.UploadFriendCircleModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, " ") == "" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.UploadFriendCircleImageService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendSnsCommentRequestApi 点赞评论
func SendSnsCommentRequestApi(ctx *gin.Context) {
reqModel := new(req.SendSnsCommentRequestModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendSnsCommentRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendSnsObjectOpRequestApi 朋友圈操作
func SendSnsObjectOpRequestApi(ctx *gin.Context) {
reqModel := new(req.SendSnsObjectOpRequestModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendSnsObjectOpRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendSnsTimeLineRequestApi 获取朋友圈主页
func SendSnsTimeLineRequestApi(ctx *gin.Context) {
reqModel := new(req.GetSnsInfoModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendSnsTimeLineRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendSnsUserPageRequestApi 获取指定人朋友圈
func SendSnsUserPageRequestApi(ctx *gin.Context) {
reqModel := new(req.GetSnsInfoModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendSnsUserPageRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendSnsObjectDetailByIdApi 获取指定id朋友圈
func SendSnsObjectDetailByIdApi(ctx *gin.Context) {
reqModel := new(req.GetIdDetailModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendSnsObjectDetailByIdService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetBackgroundImageApi 设置朋友圈背景图片
func SetBackgroundImageApi(ctx *gin.Context) {
reqModel := new(req.SetBackgroundImageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetBackgroundImageService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendFavItemCircleApi 转发收藏朋友圈id
func SendFavItemCircleApi(ctx *gin.Context) {
reqModel := new(req.SendFavItemCircle)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendFavItemCircleService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendOneIdCircleApi 一键转发朋友圈
func SendOneIdCircleApi(ctx *gin.Context) {
reqModel := new(req.GetIdDetailModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendOneIdCircleService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetCollectCircleApi 获取收藏朋友圈详情
func GetCollectCircleApi(ctx *gin.Context) {
reqModel := new(req.SendFavItemCircle)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetCollectCircleService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetSnsSync 同步朋友圈
func GetSnsSync(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetSnsSyncService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// CdnSnsVideoUploadApi 上传CDN朋友圈视频
func CdnSnsVideoUploadApi(ctx *gin.Context) {
reqModel := new(req.CdnSnsVideoUploadModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.CdnSnsVideoUploadService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
+549
View File
@@ -0,0 +1,549 @@
package controller
import (
"net/http"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/service"
"xiawan/wx/api/vo"
"github.com/gin-gonic/gin"
)
// GetRedisSyncMsgApi 获取缓存在redis中的消息
func GetRedisSyncMsgApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
// reqModel := new(req.GetSyncMsgModel)
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
//if !validateData(ctx, &reqModel) {
// return
//}
result := service.GetRedisSyncMsgService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// GetOnlineInfoApi 获取在线设备信息
func GetOnlineInfoApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.OnlineInfoService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// GetProfileApi 获取个人资料信息
func GetProfileApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetProfileService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// DelContactApi 删除好友
func DelContactApi(ctx *gin.Context) {
reqModel := new(req.DelContactModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendDelContactService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// ModifyUserInfoRequestApi 修改资料
func ModifyUserInfoRequestApi(ctx *gin.Context) {
reqModel := new(req.ModifyUserInfo)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendModifyUserInfoRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// UpdateNickNameApi 修改名称
func UpdateNickNameApi(ctx *gin.Context) {
reqModel := new(req.UpdateNickNameModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.UpdateNickNameService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetNickNameApi 设置昵称
func SetNickNameApi(ctx *gin.Context) {
reqModel := new(req.UpdateNickNameModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
reqModel.Scene = 1
result := service.SetNickNameService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetSexApi 修改性别
func SetSexApi(ctx *gin.Context) {
reqModel := new(req.UpdateSexModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetSexService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// ResetGenderApi 重置性别
func ResetGenderApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
reqModel := &req.ModifyUserInfo{
City: "",
Country: "",
InitFlag: 0,
NickName: "",
Province: "",
Sex: 0,
Signature: "",
}
result := service.SendModifyUserInfoRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetSignatureApi 修改签名
func SetSignatureApi(ctx *gin.Context) {
reqModel := new(req.UpdateNickNameModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
reqModel.Scene = 2
result := service.SetNickNameService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// ChangePwdRequestRequestApi 更改密码
func ChangePwdRequestRequestApi(ctx *gin.Context) {
reqModel := new(req.SendChangePwdRequestModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
// 判断 旧密码
if reqModel.OldPass == "" {
ctx.JSON(http.StatusOK, vo.NewFail("旧密码不能为空"))
ctx.Abort()
return
}
// 判断 旧密码
if reqModel.OldPass == reqModel.NewPass {
ctx.JSON(http.StatusOK, vo.NewFail("新旧密码不能相同"))
return
}
result := service.SendChangePwdRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// UploadHeadImageApi 上传头像
func UploadHeadImageApi(ctx *gin.Context) {
reqModel := new(req.UploadHeadImageModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.UploadHeadImageService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// UpdateAutoPassApi 修改加好友需要验证属性
func UpdateAutoPassApi(ctx *gin.Context) {
reqModel := new(req.UpdateAutopassModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.UpdateAutoPassService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SendModifyRemarkRequestApi 修改备注
func SendModifyRemarkRequestApi(ctx *gin.Context) {
reqModel := new(req.SendModifyRemarkRequestModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SendModifyRemarkRequestService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetWechatApi 设置微信号
func SetWechatApi(ctx *gin.Context) {
reqModel := new(req.AlisaModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetWechatService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// UpdateStepNumberApi 修改步数
func UpdateStepNumberApi(ctx *gin.Context) {
reqModel := new(req.UpdateStepNumberModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.UpdateStepNumberService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetUserRankLikeCountApi 获取步数排行数据列表
func GetUserRankLikeCountApi(ctx *gin.Context) {
reqModel := new(req.UserRankLikeModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.GetUserRankLikeCountService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetFunctionSwitchApi 设置添加我的方式
func SetFunctionSwitchApi(ctx *gin.Context) {
reqModel := new(req.WxFunctionSwitchModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetFunctionSwitchService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetSendPatApi 设置拍一拍名称
func SetSendPatApi(ctx *gin.Context) {
reqModel := new(req.SetSendPatModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetSendPatService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// SetProxyApi 修改Socks5代理 socks5://username:password@ipv4:port
func SetProxyApi(ctx *gin.Context) {
reqModel := new(req.GetLoginQrCodeModel)
queryKey, err := checkLicense(ctx)
if err != nil {
ctx.JSON(http.StatusOK, vo.NewFail(err.Error()))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetProxyService(queryKey, *reqModel)
if result.Code != vo.SUCCESS {
ctx.JSON(http.StatusOK, result)
return
}
if !reqModel.Check { // 无需发送检测代理请求
ctx.JSON(http.StatusOK, result)
return
}
// 设置代理成功; 请求获取登录状态 及 在线设备信息
// 触发 AutoLogin 自动二次登录
loginStatus := service.GetLoginStatusService(queryKey, false, true)
if loginStatus.Code != vo.SUCCESS { // 登录失效
ctx.JSON(http.StatusOK, vo.DTO{
Code: vo.FAIL,
Data: gin.H{
"proxyInfo": result.Data,
},
Text: loginStatus.Text,
})
return
}
// 获取当前在线设备信息
onlineInfo := service.OnlineInfoService(queryKey)
if onlineInfo.Code != vo.SUCCESS { // 登录失效
ctx.JSON(http.StatusOK, vo.DTO{
Code: vo.FAIL,
Data: gin.H{
"proxyInfo": result.Data,
"loginStatus": loginStatus.Data,
},
Text: onlineInfo.Text,
})
return
}
ctx.JSON(http.StatusOK, vo.DTO{
Code: vo.SUCCESS,
Data: gin.H{
"proxyInfo": result.Data,
"loginStatus": loginStatus.Data,
"onlineInfo": onlineInfo.Data,
},
Text: "",
})
}
// SetKeywordReplyApi 设置关键词自动回复
func SetKeywordReplyApi(ctx *gin.Context) {
reqModel := new(req.SetKeywordReplyModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetKeywordReplyService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetKeywordReplyApi 获取关键词自动回复配置
func GetKeywordReplyApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetKeywordReplyService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// SetWelcomeApi 设置欢迎词配置
func SetWelcomeApi(ctx *gin.Context) {
reqModel := new(req.SetWelcomeModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetWelcomeService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetWelcomeApi 获取欢迎词配置
func GetWelcomeApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetWelcomeService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// SetAdminKeywordApi 设置管理员关键词配置
func SetAdminKeywordApi(ctx *gin.Context) {
reqModel := new(req.SetAdminKeywordModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetAdminKeywordService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetAdminKeywordApi 获取管理员关键词配置
func GetAdminKeywordApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetAdminKeywordService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// SetKickKeywordApi 设置踢人关键词配置
func SetKickKeywordApi(ctx *gin.Context) {
reqModel := new(req.SetKickKeywordModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetKickKeywordService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetKickKeywordApi 获取踢人关键词配置
func GetKickKeywordApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetKickKeywordService(queryKey)
ctx.JSON(http.StatusOK, result)
}
// SetInviteKeywordApi 设置关键词邀请入群配置
func SetInviteKeywordApi(ctx *gin.Context) {
reqModel := new(req.SetInviteKeywordModel)
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
if !validateData(ctx, &reqModel) {
return
}
result := service.SetInviteKeywordService(queryKey, *reqModel)
ctx.JSON(http.StatusOK, result)
}
// GetInviteKeywordApi 获取关键词邀请入群配置
func GetInviteKeywordApi(ctx *gin.Context) {
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
//确保每次都有Key
ctx.JSON(http.StatusOK, vo.NewFailUUId(""))
return
}
result := service.GetInviteKeywordService(queryKey)
ctx.JSON(http.StatusOK, result)
}
+117
View File
@@ -0,0 +1,117 @@
package middleware
import (
"bytes"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"io"
"net/http"
"time"
"xiawan/wx/db"
)
/*
**
认证
*/
func BasicAuth() gin.HandlerFunc {
return func(c *gin.Context) {
auth := c.Request.Header.Get("Authorization")
if auth == "" {
RsqK(c, "授权码不能为空")
return
}
modelAuth := &Auth{}
var key = fmt.Sprintf("api:auth:%s", auth)
modelAuth = GetCacheAuth(key)
if modelAuth == nil {
rsq := Get("http://119.45.28.143:8000/api/v1/auth?key=" + auth)
if err := json.Unmarshal([]byte(rsq), &modelAuth); err == nil {
if modelAuth.Data == 200 {
CacheAuthAdd(key, modelAuth)
c.Next()
return
}
RsqK(c, modelAuth.Msg)
return
}
} else {
if modelAuth.Data == 200 {
CacheAuthAdd(key, modelAuth)
c.Next()
return
}
RsqK(c, modelAuth.Msg)
return
}
}
}
func RsqK(c *gin.Context, msg string) {
c.AbortWithStatus(http.StatusCreated)
respVo := &RespVo{
Code: http.StatusOK,
Message: msg,
Data: http.StatusCreated,
}
c.JSON(http.StatusOK, respVo)
}
type Auth struct {
Code int32
Data int32
Msg string
}
// {"code":0,"message":"","data":""}
type RespVo struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
// 发送GET请求
// url: 请求地址
// response 请求返回的内容
func Get(url string) string {
// 超时时间:15秒
client := &http.Client{Timeout: 15 * time.Second}
resp, err := client.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var buffer [512]byte
result := bytes.NewBuffer(nil)
for {
n, err := resp.Body.Read(buffer[0:])
result.Write(buffer[0:n])
if err != nil && err == io.EOF {
break
} else if err != nil {
panic(err)
}
}
return result.String()
}
// 添加授权缓存
func CacheAuthAdd(key string, val *Auth) {
cache := db.GetCaChe()
isContains := cache.Contains(key)
if !isContains {
cache.Set(key, val, time.Hour*1)
return
}
}
// 查询授权缓存
func GetCacheAuth(key string) *Auth {
cache := db.GetCaChe()
isContains := cache.Contains(key)
if !isContains {
return nil
}
return cache.Get(key).(*Auth)
}
+17
View File
@@ -0,0 +1,17 @@
package middleware
import (
"github.com/gin-gonic/gin"
)
func Cors(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
+52
View File
@@ -0,0 +1,52 @@
package middleware
import (
"net/http"
"strings"
"xiawan/wx/api/vo"
"xiawan/wx/db"
"xiawan/wx/srv/srvconfig"
"github.com/gin-gonic/gin"
)
var NotFilterReqRouterArray = []string{
"/v1/login/GetLoginStatus",
"/v1/login/WakeUpLogin",
"/v1/login/DeviceLogin",
"/v1/login/GetLoginQrCode",
}
// FilterInstanceMiddleware 过滤不同服务器不同的实例 避免出现串号问题
func FilterInstanceMiddleware(ctx *gin.Context) {
// 放行指定请求
for _, s := range NotFilterReqRouterArray {
if s == ctx.FullPath() {
ctx.Next() //放行请求
return
}
}
// 是否带Key
queryKey, isExist := ctx.GetQuery("key")
if !isExist || strings.Trim(queryKey, "") == "" || strings.Trim(queryKey, "") == "null" {
ctx.Next() //放行请求
return
}
// 从数据库取该key 的用户信息
userInfoEntity := db.GetUserInfoEntity(queryKey)
if userInfoEntity == nil {
ctx.Next() //放行请求
return
}
if userInfoEntity.TargetIp == "" {
ctx.Next() //放行请求
return
}
// 判断是否为 同个服务器
if userInfoEntity.TargetIp != srvconfig.GlobalSetting.TargetIp {
ctx.JSON(http.StatusOK, vo.NewFAILDoesNotBelongToServer(queryKey))
ctx.Abort()
return
}
}
+21
View File
@@ -0,0 +1,21 @@
package req
// 消息回调相关的请求模型
// MessageCallbackConfigModel 消息回调配置请求模型
type MessageCallbackConfigModel struct {
CallbackURL string `json:"CallbackURL" binding:"required"` // 回调URL
Enabled bool `json:"Enabled"` // 是否启用回调
}
// MessageCallbackPayload 消息回调负载
type MessageCallbackPayload struct {
MessageID string `json:"message_id"` // 消息ID
FromUser string `json:"from_user"` // 发送者
ToUser string `json:"to_user"` // 接收者
IsGroup bool `json:"is_group"` // 是否群消息
MessageType int `json:"message_type"` // 消息类型
Content string `json:"content"` // 消息内容
MessageData interface{} `json:"message_data"` // 消息数据
CreateTime int64 `json:"create_time"` // 消息创建时间
}
+505
View File
@@ -0,0 +1,505 @@
package req
import (
"encoding/json"
"strings"
"time"
)
// 指令参数
// 自动抢红包 101
type AutoRedRequestModel struct {
Enable int32 `example:"1"` // 是否开启领取红包机制
Single int32 `example:"1"` // 是否仅抢单个红包(不同时抢多个)
AutoReply int32 `example:"1"` // 是否自动回复感谢
TimeInSeconds int32 `example:"0"` // 延迟回复的时间,单位为秒
ReplyMessages string // 回复内容(多个消息用逗号隔开)
}
func DealAutoRed(model *AutoRedRequestModel) {
if model.Enable != 1 {
model.Enable = 0
}
if model.Single != 1 {
model.Single = 0
}
if model.AutoReply != 1 {
model.AutoReply = 0
}
// TimeInSeconds 0-60
if model.TimeInSeconds < 0 {
model.TimeInSeconds = 0
} else if model.TimeInSeconds > 60 {
model.TimeInSeconds = 60
}
_, model.ReplyMessages = StringToSlice(model.ReplyMessages)
}
// 自动接收转账 106
type AutoTransferRequestModel struct {
Enable int32 `example:"1"` // 是否开启接收转账功能
AutoReply int32 `example:"1"` // 是否开启自动回复
TimeInSeconds int32 `example:"0"` // 延迟回复的时间,单位为秒
ReplyMessage string // 回复内容(仅一条)
}
func DealTransfer(model *AutoTransferRequestModel) {
if model.Enable != 1 {
model.Enable = 0
}
if model.AutoReply != 1 {
model.AutoReply = 0
}
// TimeInSeconds 0-60
if model.TimeInSeconds < 0 {
model.TimeInSeconds = 0
} else if model.TimeInSeconds > 60 {
model.TimeInSeconds = 60
}
model.ReplyMessage = StringTo1000(model.ReplyMessage)
}
// 延迟领取红包 103
type DelayRedRequestModel struct {
TimeInSeconds int32 `example:"0"` // 延迟领取红包的时间,单位为秒
}
func DealDelayRed(model *DelayRedRequestModel) {
// TimeInSeconds 0-60
if model.TimeInSeconds < 0 {
model.TimeInSeconds = 0
} else if model.TimeInSeconds > 60 {
model.TimeInSeconds = 60
}
}
// 延迟接收转账 113
type DelayAutoTransferRequestModel struct {
TimeInSeconds int32 `example:"0"` // 延迟接收转账的时间,单位为秒
}
func DealDelayTransfer(model *DelayAutoTransferRequestModel) {
// TimeInSeconds 0-60
if model.TimeInSeconds < 0 {
model.TimeInSeconds = 0
} else if model.TimeInSeconds > 60 {
model.TimeInSeconds = 60
}
}
// 关键字包不抢 118
type KeywordAvoidanceRequestModel struct {
Enable int32 `example:"1"` // 是否开启关键字包不抢
Keywords string // 设置关键字(多个用逗号隔开)
}
func DealKeywordAvoidance(model *KeywordAvoidanceRequestModel) {
if model.Enable != 1 {
model.Enable = 0
}
_, model.Keywords = StringToSlice(model.Keywords)
}
// 自动点赞 401
type AutoLikeRequestModel struct {
Enable int32 `example:"1"` // 是否开启自动点赞
StartTime string // 开始时间 // 点赞时间段
EndTime string // 结束时间// 点赞时间段
TimeInSeconds int32 `example:"0"` // 延迟点赞的时间,单位为秒
Mode int32 `example:"1"` // 模式,1-仅点赞分组,0-不点赞分组
Groups string // 设置分组,多个用逗号隔开
}
func DealAutoLike(model *AutoLikeRequestModel) {
if model.Enable != 1 {
model.Enable = 0
}
// TimeInSeconds 0-60
if model.TimeInSeconds < 0 {
model.TimeInSeconds = 0
} else if model.TimeInSeconds > 60 {
model.TimeInSeconds = 60
}
if model.Mode != 1 {
model.Mode = 0
}
_, model.Groups = StringToSlice(model.Groups)
}
// 朋友圈跟随转发 402
type AutoForwardRequestModel struct {
EnableAutoForward int32 `example:"1"` // 是否开启跟随转发
IsBlockAuthor int32 `example:"1"` // 是否屏蔽作者
IsBlockGroup int32 `example:"1"` // 是否屏蔽组
Groups string // 设置分组,多个用逗号隔开
}
func DealAutoForward(model *AutoForwardRequestModel) {
if model.EnableAutoForward != 1 {
model.EnableAutoForward = 0
}
if model.IsBlockAuthor != 1 {
model.IsBlockAuthor = 0
}
if model.IsBlockGroup != 1 {
model.IsBlockGroup = 0
}
_, model.Groups = StringToSlice(model.Groups)
}
// 朋友圈收藏转发 403
type FavoriteForwardRequestModel struct {
EnableFavoriteForward int32 `example:"1"` // 是否开启收藏转发
IsBlockAuthor int32 `example:"1"` // 是否屏蔽作者
IsBlockGroup int32 `example:"1"` // 是否屏蔽组
Groups string // 设置分组,多个用逗号隔开
}
func DealFavoriteForward(model *FavoriteForwardRequestModel) {
if model.EnableFavoriteForward != 1 {
model.EnableFavoriteForward = 0
}
if model.IsBlockAuthor != 1 {
model.IsBlockAuthor = 0
}
if model.IsBlockGroup != 1 {
model.IsBlockGroup = 0
}
_, model.Groups = StringToSlice(model.Groups)
}
// 朋友圈自动评论 404
type AutoCommentRequestModel struct {
Enable int32 `example:"1"` // 是否开启自动评论
CommentMessages string // 评论内容(多条用逗号隔开)
StartTime string // 评论时间段,开始时间
EndTime string // 评论时间段,结束时间
TimeInSeconds int32 `example:"0"` // 延迟评论的时间,单位为秒
Mode int32 `example:"1"` // 模式,1-仅评论分组,0-不评论分组
Groups string // 设置分组,多个用逗号隔开
}
func DealAutoComment(model *AutoCommentRequestModel) {
if model.Enable != 1 {
model.Enable = 0
}
_, model.CommentMessages = StringToSlice(model.CommentMessages)
// TimeInSeconds 0-60
if model.TimeInSeconds < 0 {
model.TimeInSeconds = 0
} else if model.TimeInSeconds > 60 {
model.TimeInSeconds = 60
}
if model.Mode != 1 {
model.Mode = 0
}
_, model.Groups = StringToSlice(model.Groups)
}
// 定时发朋友圈 405
type MomentsRequestModel struct {
MomentType int32 `example:"1"` // 发圈类型,1-文字,3-图片
MomentContent string // 朋友圈内容
MomentImages string // 朋友圈图片(最多上传9张,图片路径或链接用逗号隔开)
IsBlock int32 `example:"1"` // 发圈时屏蔽组
Groups string // 设置分组,多个用逗号隔开
ScheduledTime string // 预约发圈时间
Status int32 `example:"0"` // 状态,0-未发布,1-已发布,-1-发布失败
}
func DealMoments(model *MomentsRequestModel) {
// MomentType must be either 1 or 3
if model.MomentType != 3 {
model.MomentType = 1 // Default to 1 if invalid
}
model.MomentContent = StringTo1000(model.MomentContent)
_, model.MomentImages = StringToSlice(model.MomentImages)
if model.IsBlock != 1 {
model.IsBlock = 0
}
_, model.Groups = StringToSlice(model.Groups)
// Status can remain as is since it is already initialized
}
// 发大视频朋友圈 406
type MomentsPostRequestModel struct {
Content string // 朋友圈内容
VideoURL string // 视频,最大500M(最多上传1个)
IsBlock int32 `example:"1"` // 发圈时屏蔽组
Groups string // 设置分组,多个用逗号隔开
}
func DealMomentsPost(model *MomentsPostRequestModel) {
model.Content = StringTo1000(model.Content)
model.VideoURL = StringTo1000(model.VideoURL)
if model.IsBlock != 1 {
model.IsBlock = 0
}
_, model.Groups = StringToSlice(model.Groups)
}
// 欢迎新人入群 502
type WelcomeNewMemberRequestModel struct {
Enable int32 `example:"1"` // 是否开启欢迎新人入群
WelcomeMsg string // 欢迎语内容(仅一条)
Mode int32 `example:"1"` // 模式,1-仅欢迎设置群,0-不欢迎设置群
Rooms string // 设置的群
}
func DealWelcomeNewMember(model *WelcomeNewMemberRequestModel) {
if model.Enable != 1 {
model.Enable = 0
}
model.WelcomeMsg = StringTo1000(model.WelcomeMsg)
if model.Mode != 1 {
model.Mode = 0
}
_, model.Rooms = StringToSlice(model.Rooms)
}
// 关键词自动踢人 503
type KeywordKickRequestModel struct {
Enable int32 `example:"1"` // 是否开启关键词踢人
Keywords string // 触发的关键词(多条用逗号分隔)
IsLinkKick int32 `example:"1"` // 是否踢发链接的人
IsCardKick int32 `example:"1"` // 是否踢发名片的人
IsMiniProgramKick int32 `example:"1"` // 是否踢发小程序的人
IsImageQRCodeKick int32 `example:"1"` // 是否踢发图片二维码的人
Mode int32 `example:"1"` // 模式,1-仅踢设置群,0-不踢设置群
Rooms string // 设置的群
}
func DealKeywordKick(model *KeywordKickRequestModel) {
if model.Enable != 1 {
model.Enable = 0
}
_, model.Keywords = StringToSlice(model.Keywords)
if model.IsLinkKick != 1 {
model.IsLinkKick = 0
}
if model.IsCardKick != 1 {
model.IsCardKick = 0
}
if model.IsMiniProgramKick != 1 {
model.IsMiniProgramKick = 0
}
if model.IsImageQRCodeKick != 1 {
model.IsImageQRCodeKick = 0
}
if model.Mode != 1 {
model.Mode = 0
}
_, model.Rooms = StringToSlice(model.Rooms)
}
// 关键词自动回复 504
type ReplyKeywordsItem struct {
Keyword string // 触发的关键词
Content string // 回复的内容
NewMsgId string // 新消息ID 引用了文件助手某条消息时用这个字段
MsgType int32 // 收到消息时的类型:1-文本 3-图片 24-笔记 33-小程序 42-名片 49-链接
SendType int32 // 回复的类型,发送类型 1-文本 3-图片 49-笔记|链接 2002-小程序 42-名片
}
type KeywordAutoReplyRequestModel struct {
Enable int32 `example:"1"` // 是否开启关键词自动回复
PrivateReply int32 `example:"1"` // 是否回复私聊
Mode int32 `example:"1"` // 模式,1-仅回复设置群,0-不回复设置群
Rooms string // 设置的群
Keywords []ReplyKeywordsItem // 关键词设置
}
func DealKeywordAutoReply(model *KeywordAutoReplyRequestModel) {
if model.Enable != 1 {
model.Enable = 0
}
if model.PrivateReply != 1 {
model.PrivateReply = 0
}
if model.Mode != 1 {
model.Mode = 0
}
_, model.Rooms = StringToSlice(model.Rooms)
for i := range model.Keywords {
model.Keywords[i].Keyword = StringTo1000(model.Keywords[i].Keyword)
model.Keywords[i].Content = StringTo1000(model.Keywords[i].Content)
// MsgType and SendType are assumed to be validated outside this function
}
}
// 万群同步 505
type MessageForwardingRequestModel struct {
Enable int32 `example:"1"` // 是否开启消息转发
MainRoom string // 设置的主讲群
Lecturers string // 添加的讲师
ForwardRooms string // 设置的转发群
StartTime string // 转发时间段,开始时间
EndTime string // 转发时间段,结束时间
}
func DealMessageForwarding(model *MessageForwardingRequestModel) {
if model.Enable != 1 {
model.Enable = 0
}
model.MainRoom = StringTo1000(model.MainRoom)
model.Lecturers = StringTo1000(model.Lecturers)
_, model.ForwardRooms = StringToSlice(model.ForwardRooms)
// StartTime and EndTime are assumed to be valid formats validated outside this function
startTime, endTime := DealTimeRange(model.StartTime, model.EndTime)
model.StartTime = startTime
model.EndTime = endTime
}
// 自动通过好友 801
type AutoApproveRequestModel struct {
Enable int32 `example:"1"` // 是否开启自动通过验证
AutoReply int32 `example:"1"` // 是否通过验证后自动回复
ReplyMessage string // 回复内容(仅一条)
}
func DealAutoApprove(model *AutoApproveRequestModel) {
if model.Enable != 1 {
model.Enable = 0
}
if model.AutoReply != 1 {
model.AutoReply = 0
}
model.ReplyMessage = StringTo1000(model.ReplyMessage)
}
// 中文逗号转为英文逗号,清理换行符,过滤空字符串,返回字符串数组和字符串表示
func StringToSlice(str string) ([]string, string) {
// 清理换行符(包括 \n 和 \r)
str = strings.ReplaceAll(str, "\r", "")
// 回车符转成分隔付(逗号)
str = strings.ReplaceAll(str, "\n", ",")
// 将中文逗号替换为英文逗号
str = strings.ReplaceAll(str, "", ",")
// 按英文逗号分割成字符串数组
strArr := strings.Split(str, ",")
var result []string
var finalString string = ""
// 过滤掉空字符串,清理头尾空格
for _, v := range strArr {
v = strings.TrimSpace(v) // 去掉前后空格
if v != "" {
// 判断不能大于 1000 个字符
if len(finalString+","+v) > 1000 {
continue
}
if finalString != "" {
finalString += ","
}
finalString += v
result = append(result, v)
}
}
// 将数组转成字符串格式
// finalString := strings.Join(result, ",")
// 返回字符串数组和字符串
return result, finalString
}
// 判断字符串不能大于 1000 个字符,大于则截取前 1000 个字符
func StringTo1000(str string) string {
str = strings.TrimSpace(str) // 去掉前后空格
// 只取 前 1000 个字符
if len(str) > 1000 {
str = str[:1000]
}
return str
}
// 处理开始时间和结束时间,如果输入格式不正确,则使用默认值
func DealTimeRange(startTime string, endTime string) (string, string) {
const timeFormat = "15:04"
// 解析 StartTime
start, errStart := time.Parse(timeFormat, startTime)
if errStart != nil {
start = time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC) // 设置为 00:00
startTime = start.Format(timeFormat)
} else {
startTime = start.Format(timeFormat)
}
// 解析 EndTime
end, errEnd := time.Parse(timeFormat, endTime)
if errEnd != nil {
end = time.Date(0, 1, 1, 23, 59, 0, 0, time.UTC) // 设置为 23:59
endTime = end.Format(timeFormat)
} else {
endTime = end.Format(timeFormat)
}
// 如果 EndTime 小于 StartTime,则将 EndTime 设置为 StartTime
if end.Before(start) {
end = start
endTime = end.Format(timeFormat)
}
return startTime, endTime
}
// ToJSON 将任意结构体转换为 JSON 字符串
func ToJSONStr(input interface{}) (string, error) {
// 使用 json.Marshal 将对象转换为 JSON 字节数组
bytes, err := json.Marshal(input)
if err != nil {
// 如果转换失败,返回错误提示
return "", err
}
// 将字节数组转换为字符串并返回
return string(bytes), nil
}
// FromJSONS 将 JSON 字符串转换为任意结构体
func FromJSONS(input string, output interface{}) error {
if len(input) == 0 {
// 将空字符串替换为一个空 JSON 对象
input = "{}"
}
err := json.Unmarshal([]byte(input), output)
return err
}
// 定时任务执行函数 true 可以执行,false 不执行
func IsInTimeRange(StartTime string, EndTime string) bool {
// 获取系统当前时间(HH:mm 格式)
now := time.Now()
layout := "15:04"
currentTime, err := time.Parse(layout, now.Format(layout)) // 将当前时间转换为 HH:mm 格式
if err != nil {
// 如果解析失败,执行任务即可
return true
}
// 解析 StartTime 和 EndTime
startTime, err := time.Parse(layout, StartTime)
if err != nil {
// 如果解析失败,执行任务即可
return true
}
endTime, err := time.Parse(layout, EndTime)
if err != nil {
// 如果解析失败,执行任务即可
return true
}
// 判断当前时间是否在范围内
if (currentTime.After(startTime) || currentTime.Equal(startTime)) && (currentTime.Before(endTime) || currentTime.Equal(endTime)) {
// 执行任务
return true
} else {
// 不执行
return false
}
}
+7
View File
@@ -0,0 +1,7 @@
package req
// UploadAppAttachModel 上传文件请求模型
type UploadAppAttachModel struct {
// 文件base64编码内容
FileData string `json:"fileData" binding:"required"`
}
+18
View File
@@ -0,0 +1,18 @@
package req
// KeywordReplyPair 关键词回复对
type KeywordReplyPair struct {
Keyword string `json:"keyword"`
Reply string `json:"reply"`
}
// SetKeywordReplyModel 设置关键词回复请求
type SetKeywordReplyModel struct {
Enable bool `json:"enable"` // 是否启用关键词回复
Pairs []KeywordReplyPair `json:"pairs"` // 关键词回复对列表
}
// GetKeywordReplyModel 获取关键词回复请求
type GetKeywordReplyModel struct {
// 空结构体,不需要请求参数
}
+749
View File
@@ -0,0 +1,749 @@
package req
import (
"xiawan/wx/clientsdk/baseinfo"
)
type MessageItem struct {
ToUserName string // 接收者 wxid
TextContent string // 文本类型消息时内容
ImageContent string // 图片类型消息时图片的 base64 编码
MsgType int //1 Text 2 Image
AtWxIDList []string // 发送艾特消息时的 wxid 列表
}
type SendMessageModel struct {
MsgItem []MessageItem // 消息体数组
}
// SnsLocationInfo 朋友圈地址项
type SnsLocationInfoModel struct {
City string
Longitude string
Latitude string
PoiName string
PoiAddress string
PoiScale int32
PoiInfoURL string
PoiClassifyID string
PoiClassifyType uint32
PoiClickableStatus uint32
}
// SnsMediaItem 朋友圈媒体项
type SnsMediaItemModel struct {
ID uint32
Type uint32
Title string
Description string
Private uint32
UserData string
SubType uint32
URL string
URLType string
Thumb string
ThumType string
SizeWidth string
SizeHeight string
TotalSize string
VideoWidth string
VideoHeight string
MD5 string
VideoMD5 string
VideoDuration float64
}
type DownloadMediaModel struct {
Key string
URL string
}
type TransmitFriendCircleModel struct {
SourceID string
}
// 设置朋友圈可见天数
type SetFriendCircleDaysModel struct {
Function uint32
Value uint32
}
// SnsPostItem 发送朋友圈需要的信息
type SnsPostItemModel struct {
ContentStyle uint32 // 纯文字/图文/引用/视频
ContentUrl string
Description string
Privacy uint32 // 是否仅自己可见
Content string // 文本内容
MediaList []*SnsMediaItemModel // 图片/视频列表
WithUserList []string // 提醒好友看列表
GroupUserList []string // 可见好友列表
BlackList []string // 不可见好友列表
LocationInfo *SnsLocationInfoModel // 发送朋友圈的位置信息
}
type GetSnsInfoModel struct {
UserName string
FirstPageMD5 string
MaxID uint64
}
type GetIdDetailModel struct {
Id string
BlackList []string
LocationVal int64
Location baseinfo.Location
}
type SetBackgroundImageModel struct {
Url string
}
type SendFavItemCircle struct {
SourceID string
FavItemID uint32
BlackList []string
LocationVal int64
Location baseinfo.Location
}
// UploadFriendCircleModel 上传朋友圈图片视频信息
type UploadFriendCircleModel struct {
ImageDataList []string
VideoDataList []string
}
type ForwardImageItem struct {
ToUserName string
AesKey string
CdnMidImgUrl string
CdnMidImgSize int32
CdnThumbImgSize int32
}
type ForwardVideoItem struct {
ToUserName string
AesKey string
CdnVideoUrl string
Length int
PlayLength int
CdnThumbLength int
}
type ForwardMessageModel struct {
ForwardImageList []ForwardImageItem
ForwardVideoList []ForwardVideoItem
}
type SendEmojiItem struct {
ToUserName string
EmojiMd5 string
EmojiSize int32
}
type SendEmojiMessageModel struct {
EmojiList []SendEmojiItem
}
type RevokeMsgModel struct {
NewMsgId string
ClientMsgId uint64
CreateTime uint64
ToUserName string
IsImage bool // 标识是否为图片消息
ClientImgIdStr string // 保存clientImgId的原始字符串值
}
type AppMessageItem struct {
ToUserName string
ContentXML string
ContentType uint32 // 2001:(红包消息)
}
type AppMessageModel struct {
AppList []AppMessageItem
}
type UpdateChatroomAnnouncementModel struct {
ChatRoomName string // 群聊IDxxx@chatroom
Content string
}
type GetChatroomMemberDetailModel struct {
ChatRoomName string // 群聊IDxxx@chatroom
}
type ConsentToJoinGroupModel struct {
Url string
}
type ChatRoomWxIdListModel struct {
ChatRoomWxIdList []string
}
type SetChatroomAccessVerifyModel struct {
ChatRoomName string // 群聊IDxxx@chatroom
Enable bool
}
type ChatroomMemberModel struct {
UserList []string
ChatRoomName string // 群聊IDxxx@chatroom
}
type ChatroomNameModel struct {
Nickname string
ChatRoomName string // 群聊IDxxx@chatroom
}
type SendPatModel struct {
ChatRoomName string // 群聊IDxxx@chatroom
ToUserName string
Scene int64
}
type GroupListModel struct {
Key string
}
type SearchContactModel struct {
Tg string
FromScene uint64
UserName string
}
type QWApplyAddContactModel struct {
UserName string
V1 string
Content string
}
type QWSyncChatRoomModel struct {
Key string
}
type QWChatRoomTransferOwnerModel struct {
ChatRoomName string // 群聊IDxxx@chatroom
ToUserName string
}
type QWAddChatRoomMemberModel struct {
ChatRoomName string // 群聊IDxxx@chatroom
ToUserName []string
}
type QWAcceptChatRoomModel struct {
Link string
Opcode uint32
}
type QWAdminAcceptJoinChatRoomSetModel struct {
ChatRoomName string // 群聊IDxxx@chatroom
P int64
}
type QWModChatRoomNameModel struct {
ChatRoomName string // 群聊IDxxx@chatroom
Name string
}
type MoveContractModel struct {
ChatRoomName string // 群聊IDxxx@chatroom
Val uint32
}
type CreateChatRoomModel struct {
TopIc string
UserList []string
}
type TransferGroupOwnerModel struct {
ChatRoomName string // 群聊IDxxx@chatroom
NewOwnerUserName string
}
type InviteChatroomMembersModel struct {
ChatRoomName string // 群聊IDxxx@chatroom
UserList []string
}
type ScanIntoUrlGroupModel struct {
Url string
}
type SnsObjectOpItem struct {
SnsObjID string // 朋友圈ID
OpType uint32 // 操作码
DataLen uint32 // 其它数据长度
Data []byte // 其它数据
Ext uint32
}
type SendSnsObjectOpRequestModel struct {
SnsObjectOpList []SnsObjectOpItem
}
// ReplyCommentItem 回覆的评论项
type ReplyCommentItem struct {
UserName string // 评论的微信ID
NickName string // 发表评论的昵称
OpType uint32 // 操作类型:评论/点赞
Source uint32 // source
}
// SnsCommentItem 朋友圈项:发表评论/点赞
type SnsCommentItem struct {
OpType uint32 // 操作类型:评论/点赞
ItemID string // 朋友圈项ID
ToUserName string // 好友微信ID
Content string // 评论内容
CreateTime uint32 // 创建时间
ReplyCommentID uint32 // 回复的评论ID
ReplyItem ReplyCommentItem // 回覆的评论项
}
type SendSnsCommentRequestModel struct {
SnsCommentList []SnsCommentItem
Tx bool
}
type SnsObjectOpRequestModel struct {
SnsObjectOpList []SnsObjectOpItem
}
type DeviceIdLoginModel struct {
Proxy string // socks代理,例如:socks5://username:password@ipv4:port
LoginData string // 62 数据/A16 数据
UserName string // 手机号
Password string // 微信密码
Ticket string // SMS短信验证码
Type int
DeviceInfo DeviceInfo // 设备信息
}
type DeviceInfo struct {
Model string
AndroidId string
Manufacturer string
ImeI string
}
type DelSafeDeviceModel struct {
DeviceUUID string
}
type ExtDeviceLoginModel struct {
QrConnect string
}
type GetA8KeyRequestModel struct {
OpCode uint32
Scene uint32
ReqUrl string
}
type AppletModel struct {
AppId string // 应用ID
Opt int32 `example:"1"` // 小程序云函数操作的 Opt; 默认为1
Data string // 小程序云函数操作的 Data; json字符串, 注意必须是 json 字符串; 传空时默认值为: '{"with_credentials":true,"from_component":true,"data":{"lang":"zh_CN"},"api_name":"webapi_getuserinfo"}'
SdkName string
PackageName string
}
type VerifyUserItem struct {
Gh string
Scene int
}
// 获取通讯录好友
type GetContactListModel struct {
CurrentWxcontactSeq uint32
CurrentChatRoomContactSeq uint32
}
type FollowGHModel struct {
GHList []VerifyUserItem
}
type GetLoginQrCodeModel struct {
IpadOrmac string
Proxy string // socks代理,例如:socks5://username:password@ipv4:port
Check bool `example:"false"` // 修改代理时(SetProxy接口) 是否发送检测代理请求(可能导致请求超时)
}
type PhoneLoginModel struct {
Url string
}
type UploadMContactModel struct {
MobileList []string
Mobile string
Opcode int32
}
type QRConnectAuthorizeModel struct {
QrUrl string
}
type GetMpA8KeyModel struct {
Url string
Opcode uint32
Scene int64
}
// 历史消息
type GetMpHistoryMsgModel struct {
Url string
}
type GetQrCodeModel struct {
Style uint32 `example:"8"` // 个人二维码样式: 可设置为8, 其余自行探索
Recover bool // 保持默认值, 无需修改
}
type PeopleNearbyModel struct {
Longitude float32
Latitude float32
}
type ModifyCmdStatusModel struct {
Key string `example:"101"`
Value int `example:"1"`
ValueStr string `example:""`
Params1 string `example:"自定义参数1"`
Params2 string `example:"自定义参数2"`
Params3 string `example:"自定义参数3"`
Params4 string `example:"自定义参数4"`
}
type ModifyCmdStatusModelNew struct {
Key string `example:"101"`
Value int `example:"1"`
ValueStr string `example:""`
}
// ChannelsLoginModel 视频号助手扫码登录请求模型
type ChannelsLoginModel struct {
Url string `json:"url" binding:"required"` // 视频号助手扫码登录确认链接
FinderUsername string `json:"finderUsername"` // 指定要登录的视频号用户名,为空则选择第一个
}
// ShopLoginConfirmModel 微信小店确认登录请求模型
type ShopLoginConfirmModel struct {
Url string `json:"url" binding:"required"` // 登录二维码URL
}
type CollectmoneyModel struct {
InvalidTime string
TransFerId string
TransactionId string
ToUserName string
}
type OpenRedEnvelopesModel struct {
NativeUrl string
}
type FavInfoModel struct {
FavId uint32
KeyBuf string
}
type LabelModel struct {
UserLabelList []baseinfo.UserLabelInfoItem
// del labelId
LabelId string
LabelNameList []string
}
type GetSyncMsgModel struct {
Key string
}
type DelContactModel struct {
DelUserName string
}
type ModifyUserInfo struct {
City string
Country string
NickName string
Province string
Signature string
Sex uint32
InitFlag uint32
}
type UpdateNickNameModel struct {
Scene uint32
Val string
}
type UpdateSexModel struct {
Sex uint32
City string
Province string
Country string
}
type UploadHeadImageModel struct {
Base64 string
}
type SendChangePwdRequestModel struct {
OldPass string `json:"oldPass"` // 确保json标签是`oldPass`
NewPass string `json:"newPass"`
OpCode uint32 `json:"opCode"`
}
type SendModifyRemarkRequestModel struct {
UserName string
RemarkName string
}
// 设置微信号
type AlisaModel struct {
Alisa string
}
type UpdateAutopassModel struct {
SwitchType uint32
}
// 设置添加方式
type WxFunctionSwitchModel struct {
Function uint32
Value uint32
}
type SetSendPatModel struct {
Value string
}
// 修改步数
type UpdateStepNumberModel struct {
Number uint64
}
type UserRankLikeModel struct {
RankId string
}
// BatchGetContact
type BatchGetContactModel struct {
UserNames []string
RoomWxIDList []string
}
type SearchContactRequestModel struct {
OpCode uint32 // 操作类型
UserName string // 要搜索的内容(微信号、手机号、QQ号等)
FromScene uint32
SearchScene uint32 // 搜索场景
}
type GetFriendRelationModel struct {
UserName string
}
type SendUploadVoiceRequestModel struct {
ToUserName string
VoiceData string `json:"VoiceData"`
VoiceSecond, VoiceFormat int32
}
type CdnUploadVideoRequest struct {
ToUserName string
VideoData []byte // 视频数据
ThumbData []byte // ThumbData
}
type DownloadParam struct {
MsgId uint32 // 消息ID(注意是msg_id 不是new_msg_id)
TotalLen int // 下载数据的总长度
Section DataSection // 当前要获取的数据分包
ToUserName string // 下载图片时,图片消息的接收者
FromUserName string // 下载图片时,图片消息的发送者
CompressType int // 下载图片时,数据压缩类型(默认为0即可)
}
type DataSection struct {
StartPos uint32 // 数据分包开始位置
DataLen uint32 `example:"61440"` // 数据分包长度(不要超过 65535)
}
type GroupMassMsgTextModel struct {
ToUserName []string
Content string
}
type GroupMassMsgImageModel struct {
ToUserName []string
ImageBase64 string
}
type DownloadVoiceModel struct {
ToUserName string
NewMsgId string
Bufid string
Length int
}
type DownMediaModel struct {
AesKey string
FileURL string
FileType uint32
}
// VerifyUserRequestModel 添加好友/验证好友/打招呼 请求体
type VerifyUserRequestModel struct {
OpCode uint32 `example:"2"` // 操作类型: 1(免验证发送请求) 2(添加好友/发送验证申请) 3(同意好友/通过好友验证) 4(拒绝好友)
VerifyContent string // 添加好友时的(招呼语/验证信息)
Scene int `example:"3"` // 添加来源, 同意添加好友时传回调消息xml中的scene值.<br/>添加好友时的枚举值如下: <br/>1(QQ) 2(邮箱) 3(微信号) 4(QQ好友) 8(来自群聊) 13(通讯录)<br/>14(群聊) 15(手机号) 18(附近的人) 25(漂流瓶) 29(摇一摇) 30(二维码)
V3 string // V3用户名数据(SearchContact请求返回的UserValue)
V4 string // V4校验数据(SearchContact请求返回的AntispamTicket)
ChatRoomUserName string // 通过群来添加好友 需要设置此值为群id
}
type GeneratePayQCodeModel struct {
Name string // 收款备注
Money string // 金额(单位为分), 999 即为 9.99 元
}
type QWContactModel struct {
ToUserName string
ChatRoom string
T string
}
type QWRemarkModel struct {
ToUserName string
Name string
}
type QWCreateModel struct {
ToUserName []string
}
type FinderSearchModel struct {
Index uint32
Userver int32
UserKey string
Uuid string
}
type FinderUserPrepareModel struct {
Userver int32
}
type FinderFollowModel struct {
FinderUserName string
PosterUsername string
OpType int32
RefObjectId string
Cook string
Userver int32
}
type WxBindOpMobileForModel struct {
OpCode int64
PhoneNumber string
VerifyCode string
Reg uint64
Proxy string
}
type GenAuthKeyModel struct {
Count int `example:"1"` // 要生成 AuthKey 的个数; Count小于1默认设置为1
Days int `example:"30"` // AuthKey 的过期天数; Days小于1默认设置为30
}
type GenAuthKeyTypeModel struct {
Count int `example:"1"` // 要生成 AuthKey 的个数; Count小于1默认设置为1
Type int `example:"1"` // 类型 1日 7 周 30月 90季 180 半年 365年 30000永久(数字为标识,非准确天数)
}
type SyncMessageModel struct {
Count int // 同步几条消息; 接收空请求体, 默认为0, 同步所有消息
}
type GetChatroomQrCodeModel struct {
ChatRoomName string // 群聊IDxxx@chatroom
}
type DelayAuthKeyModel struct {
Key string // 要延期的 AuthKey
Days int `example:"30"` // AuthKey 的延期天数; Days 小于1默认设置为30
ExpiryDate string // AuthKey 的到期日期(例如: 2024-01-01); 与 Days 参数只能选其一(优先使用 ExpiryDate 参数)
}
type DelayAuthKeyModelNew struct {
KeyUse string // 被使用的key
}
type BannedAuthKeyModel struct {
Key string // 要禁用的 AuthKey
IsBanned int `example:"0"` // isBanned 1 禁用 默认设置为0
}
type DeleteAuthKeyModel struct {
Key string // 要删除的 AuthKey
Opt int // 删除操作 0:仅删除授权码 1:删除授权码相关的所有数据
}
type CreatePreTransfer struct {
ToUserName string // 要转账用户的wxid
Fee uint32 // 转账金额(单位为分)
Description string // 转账备注
}
type ConfirmPreTransfer struct {
BankType string // 付款方式 类型
BankSerial string // 付款方式 Serial序列号
ReqKey string // 创建转账返回的ReqKey
PayPassword string // 支付密码
}
type ShareCardParam struct {
ToUserName string // 消息接收者
CardWxId string // 名片wxid
CardNickName string // 名片昵称
CardAlias string // 名片别名(发送公众号名片时留空)
CardFlag int // 名片CertFlag(0:个人名片 24:公众号名片)
}
type MessageNoShowParam struct {
ToUserName string // 消息接收者
}
// CdnSnsVideoUploadModel CDN朋友圈视频上传请求模型
type CdnSnsVideoUploadModel struct {
VideoData string // 视频数据的base64编码
ThumbData string // 缩略图数据的base64编码
}
type ResponseResult struct {
Code int64
Success bool
Message string
Data interface{}
Data62 string
Debug string
}
type ResponseResult2 struct {
Code int64
Success bool
Message string
Data interface{}
Data62 string
DeviceId string
}
type SessionidQRParam struct {
Code int64
Success bool
Message string
Data interface{}
Data62 string
DeviceId string
}
// 用于公众号文章阅读和点赞功能的请求参数
type ReadParam struct {
Url string // 公众号文章URL
}
// VerifyCodeModel 验证码验证请求模型
type VerifyCodeModel struct {
Code string `json:"code" binding:"required"` // 验证码
Data62 string `json:"data62" binding:"required"` // 验证码
Ticket string `json:"ticket" binding:"required"` // 验证码
}
// SlideTicketModel 滑动验证码请求模型
type SlideTicketModel struct {
Data62 string `json:"data62" binding:"required"` // 验证码
Ticket string `json:"ticket" binding:"required"` // 验证码
RandStr string `json:"randstr" bingding:"required"`
SlideTicket string `json:"slideticket" binding:"required"`
}
// DownloadEmojiModel 下载表情gif请求模型
type DownloadEmojiModel struct {
XmlContent string `json:"xml_content" binding:"required"` // msg_type=47的消息xml内容
}
// DownloadQWImageModel 企微图片下载请求模型
// 企微图片下载
type DownloadQWImageModel struct {
Xml string `json:"xml" binding:"required"`
}
// UploadImageToCDNModel 纯CDN图片上传请求模型
type UploadImageToCDNModel struct {
ImageContent string `json:"imageContent" binding:"required"` // 图片的base64编码
}
+74
View File
@@ -0,0 +1,74 @@
package req
// WelcomeConfig 欢迎词配置
type WelcomeConfig struct {
Enable bool `json:"enable"` // 是否启用欢迎词
Content string `json:"content"` // 欢迎词内容
ChatRooms []string `json:"chat_rooms"` // 群聊列表 (后台维护,不再通过API设置)
GroupKeyword string `json:"group_keyword"` // 设置需要欢迎群的关键词
}
// SetWelcomeModel 设置欢迎词请求
type SetWelcomeModel struct {
Config WelcomeConfig `json:"config"` // 欢迎词配置
}
// GetWelcomeModel 获取欢迎词配置请求
type GetWelcomeModel struct {
// 空结构体,不需要请求参数
}
// AdminKeywordConfig 管理员关键词配置
type AdminKeywordConfig struct {
Enable bool `json:"enable"` // 是否启用关键词设置管理员
Keyword string `json:"keyword"` // 设置管理员的关键词
}
// SetAdminKeywordModel 设置管理员关键词请求
type SetAdminKeywordModel struct {
Config AdminKeywordConfig `json:"config"` // 管理员关键词配置
}
// GetAdminKeywordModel 获取管理员关键词配置请求
type GetAdminKeywordModel struct {
// 空结构体,不需要请求参数
}
// KickKeywordConfig 踢人关键词配置
type KickKeywordConfig struct {
Enable bool `json:"enable"` // 是否启用关键词踢人
Keyword string `json:"keyword"` // 踢人的关键词
}
// SetKickKeywordModel 设置踢人关键词请求
type SetKickKeywordModel struct {
Config KickKeywordConfig `json:"config"` // 踢人关键词配置
}
// GetKickKeywordModel 获取踢人关键词配置请求
type GetKickKeywordModel struct {
// 空结构体,不需要请求参数
}
// InviteKeywordPair 关键词与群ID对应关系
type InviteKeywordPair struct {
Keyword string `json:"keyword"` // 邀请关键词
ChatRoom string `json:"chat_room"` // 对应的群ID
}
// InviteKeywordConfig 关键词邀请入群配置
type InviteKeywordConfig struct {
Enable bool `json:"enable"` // 是否启用关键词邀请入群
SetupKeyword string `json:"setup_keyword"` // 设置关键词的关键词(例如:"设置加群关键词")
Pairs []InviteKeywordPair `json:"pairs"` // 关键词与群ID对应关系列表 (后台维护,不再通过API设置)
}
// SetInviteKeywordModel 设置关键词邀请入群请求
type SetInviteKeywordModel struct {
Config InviteKeywordConfig `json:"config"` // 关键词邀请入群配置
}
// GetInviteKeywordModel 获取关键词邀请入群配置请求
type GetInviteKeywordModel struct {
// 空结构体,不需要请求参数
}
+84
View File
@@ -0,0 +1,84 @@
{
"ID": 13353470632052600936,
"UserName": "wxid_h0jis127yas122",
"CreateTime": 1591857747,
"ContentDesc": "一名心",
"ContentDescShowType": 0,
"ContentDescScene": 0,
"Private": 0,
"SightFolded": 0,
"ShowFlag": 0,
"AppInfo": {
"ID": "",
"Version": "",
"AppName": "",
"InstallURL": "",
"FromURL": "",
"IsForceUpdate": 0
},
"SourceUserName": "",
"SourceNickName": "",
"StatisticsData": "",
"StatExtStr": "",
"ContentObject": {
"ContentStyle": 15,
"Title": "微信小视频",
"Description": "Sight",
"MediaList": {
"Media": [
{
"Enc": {
"Key": "",
"Value": 0
},
"ID": 13353470632432971876,
"Type": 6,
"Title": "",
"Description": "一名心",
"Private": 0,
"UserData": "",
"SubType": 0,
"VideoSize": {
"Width": "540",
"Height": "960"
},
"URL": {
"Type": "1",
"MD5": "85d98fe8eda3472129c5fd74524efaaa",
"VideoMD5": "a4c529f4b6c9f29f66427ecc14fe4ea4",
"Value": "http://szzjwxsns.video.qq.com/102/20202/snsvideodownload?filekey=30340201010420301e0201660402535a041085d98fe8eda3472129c5fd74524efaaa0203032ae5040d00000004627466730000000131&hy=SZ&storeid=32303230303631313134343232363030306365396638373436623638343337323538353830393030303030303636&dotrans=0&ef=15_0&bizid=1023"
},
"Thumb": {
"Type": "1",
"Value": "http://vweixinthumb.tc.qq.com/150/20250/snsvideodownload?filekey=30340201010420301e020200960402535a0410491963b8c72a914b121e6ca517797aad02024b4b040d00000004627466730000000131&hy=SZ&storeid=32303230303631313134343232363030306361636264373436623638343337323538353830393030303030303936&bizid=1023"
},
"Size": {
"Width": "540.000000",
"Height": "960.000000",
"TotalSize": "207589"
},
"VideoDuration": 4.033333
}
]
},
"ContentURL": "https://support.weixin.qq.com/cgi-bin/mmsupport-bin/readtemplate?t=page/common_page__upgrade&v=1"
},
"ActionInfo": {
"AppMsg": {
"MessageAction": ""
}
},
"Location": {
"PoiClassifyID": "",
"PoiName": "",
"PoiAddress": "",
"PoiClassifyType": 0,
"City": ""
},
"PublicUserName": "",
"StreamVideo": {
"StreamVideoURL": "",
"StreamVideoThumbURL": "",
"StreamVideoWebURL": ""
}
}
+95
View File
@@ -0,0 +1,95 @@
//图文
{
"ContentStyle": 1,
"MediaList": [
{
"ThumType": "1",
"Thumb": "调用上传朋友圈图片接口返回",
"Description": "",
"Type": 2,
"MD5": "dc3d66d0fdc3e51f7abad00373854f58",
"SizeWidth": "800",
"VideoDuration": 0,
"UserData": "",
"VideoMD5": "",
"Title": "",
"URLType": "1",
"VideoHeight": "",
"ID": 1,
"SizeHeight": "800",
"TotalSize": "126335",
"URL": "http://mmsns.qpic.cn/mmsns/PiajxSqBRaELqLq7KFRSzPrYTViaAFrzicTOp5uXczOTiadcrCkFQH1uWibXc0ZyX6kAd/0",
"VideoWidth": "",
"SubType": 0,
"Private": 0
}
],
"Privacy": 0,
"Content": "休闲时刻😚零食来一波~"
}
//文字
{
"ContentStyle": 2,
"Privacy": 0,
"Content": "\n休闲时刻😚零食来一波\r\n夏威夷果奶油味坚果"
}
//视频
{
"ContentStyle": 15,
"MediaList": [
{
"ThumType": "1",
"Thumb": "调用上传朋友圈图片接口返回",
"Description": "",
"Type": 2,
"MD5": "dc3d66d0fdc3e51f7abad00373854f58",
"SizeWidth": "800",
"VideoDuration": 0,
"UserData": "",
"VideoMD5": "",
"Title": "",
"URLType": "1",
"VideoHeight": "",
"ID": 1,
"SizeHeight": "800",
"TotalSize": "126335",
"URL": "http://aitao.wingscode.com/aitao/upload/663c78e5-1eca-40ca-98a3-8c5f109694b3.mp4?token=54fc22a143276ca331de63d706c0b8bd",
"VideoWidth": "",
"SubType": 0,
"Private": 0
}
],
"Privacy": 0,
"Content": "休闲时刻可口n大人小孩都爱吃"
}
//链接
{
"ContentStyle": 3,
"ContentUrl":"https://mp.weixin.qq.com/mp/homepage?__biz=MzA5MDQ5NTE5MQ==&amp;hid=1&amp;sn=8dccd03f475fec450f2f14b4690e247b&amp;scene=18&amp;devicetype=iOS12.4.3&amp;version=1700112a&amp;lang=zh_CN&amp;nettype=WIFI&amp;ascene=7&amp;session_us=gh_f5ed87696bbf&amp;fontScale=100&amp;pass_ticket=gM1DjNqeOCQghv7AQfAg41js%2FqFjJL87XQwUqv7V3HbGK8yxaNQ1FK%2B40xvX21P4&amp;wx_header=1&amp;scene=2",
"Description":"一个字读懂中国建筑——宫",
"MediaList": [
{
"ThumType": "1",
"Thumb": "http://szmmsns.qpic.cn/mmsns/DtE8MdW3UaMFPCO2PEm76HiafHmLXHbdAibbeNVDFs0mF7kqyhic4Lar5UdicZiahKmtxnuqYicBBQ920/150",
"Description": "",
"Type": 2,
"MD5": "",
"SizeWidth": "800",
"VideoDuration": 0,
"UserData": "",
"VideoMD5": "",
"Title": "艺术笔迹",
"URLType": "0",
"VideoHeight": "",
"ID": 1,
"SizeHeight": "800",
"TotalSize": "126335",
"URL": "http://mmbiz.qpic.cn/mmbiz_jpg/Ro4nV0WxTiaQgvyffia62XWMaEJnm1l7nrgHjNNhlIJom9ZD8KYn3iavIZJaAaFKC6W2UcKSDJoxW8QPUoWjA7Z6w/0",
"VideoWidth": "",
"SubType": 0,
"Private": 0
}
],
"Privacy": 0,
"Content": "鞯地苛左工地~"
}
+53
View File
@@ -0,0 +1,53 @@
{
"ContentStyle": 1,
"Privacy": 0,
"Content": "asdasdadasd",
"MediaList": [
{
"ID": 1,
"Type": 1,
"Title": "asdasd",
"Description": "sadasd",
"Private": 0,
"UserData": "asdasdas",
"SubType": 0,
"URL": "sadasd",
"URLType": "asdasd",
"Thumb": "asdasd",
"ThumType": "asdasd",
"SizeWidth": "asdasd",
"SizeHeight": "",
"TotalSize": "",
"VideoWidth": "",
"VideoHeight": "",
"MD5": "",
"VideoMD5": "",
"VideoDuration": 0
},
{
"ID": 2,
"Type": 1,
"Title": "asdasd",
"Description": "sadasd",
"Private": 0,
"UserData": "asdasdas",
"SubType": 0,
"URL": "sadasd",
"URLType": "asdasd",
"Thumb": "asdasd",
"ThumType": "asdasd",
"SizeWidth": "asdasd",
"SizeHeight": "",
"TotalSize": "",
"VideoWidth": "",
"VideoHeight": "",
"MD5": "",
"VideoMD5": "",
"VideoDuration": 0
}
],
"WithUserList": null,
"GroupUserList": null,
"BlackList": null,
"LocationInfo": null
}
+382
View File
@@ -0,0 +1,382 @@
package router
import (
"xiawan/wx/api/controller"
"xiawan/wx/api/swagger"
"xiawan/wx/srv/srvconfig"
"github.com/gin-gonic/gin"
)
type SetMiddleWare = func(engine *gin.Engine)
func SetUpRouter(middleware SetMiddleWare, debug bool) *gin.Engine {
//获取Gin实例
r := gin.Default()
//设置中间
if middleware != nil {
middleware(r)
}
// 设置首页重定向到 /docs
r.GET("/", func(c *gin.Context) {
c.Redirect(301, "/docs")
})
//加载模版下的所有文件
r.LoadHTMLGlob("static/templates/*")
//设置静态文件目录
r.Static("static", "static")
swagger.Init()
// 配置swagger
swagger.Setup(r)
setApi(r)
return r
}
// 设置url Version:v1
func setApi(engine *gin.Engine) {
ver := srvconfig.GlobalSetting.ApiVersion
// 管理
admin := engine.Group(ver + "/admin")
{
// 获取授权码(获取新设备)
admin.POST("/GenAuthKey1", controller.GenAuthKey1)
admin.GET("/GenAuthKey2", controller.GenAuthKey2)
admin.POST("/GenAuthKey3", controller.GenAuthKey3)
// 延期授权码
admin.POST("/DelayAuthKey", controller.DelayAuthKey)
// 删除授权码
admin.POST("/DeleteAuthKey", controller.DeleteAuthKey)
// 禁用授权码
admin.POST("/DisableAuthKey", controller.DisableAuthKey)
// 同步卡密激活状态
admin.GET("/HttpSyncLicenseKey", controller.HttpSyncLicenseKey)
// 获取所有激活状态的卡密
admin.GET("/GetActiveLicenseKeys", controller.GetActiveLicenseKeys)
// 获取代理映射列表
admin.GET("/GetProxyMappingList", controller.GetProxyMappingList)
}
// 登录
login := engine.Group(ver + "/login")
{
login.POST("/GetLoginQrCodeNewDirect", controller.GetLoginQrCodeNewApiDirect)
// 检测登陆状态
login.GET("/CheckLoginStatus", controller.CheckLoginStatusApi)
// A16登陆
login.POST("/A16Login", controller.A16LoginApi)
// 62登陆
login.POST("/DeviceLogin", controller.DeviceIdLoginApi)
// 唤醒登录
login.POST("/WakeUpLogin", controller.WakeUpLoginApi)
// 获取在线状态
login.GET("/GetLoginStatus", controller.GetLoginStatusApi)
// 输入验证码验证
login.POST("/VerifyCode", controller.VerifyCodeApi)
// 滑动验证码
login.POST("/VerifyCodeSlide", controller.VerifyCodeApiSlide)
// 退出登录
login.GET("/LogOut", controller.LogOutRequestApi)
// 打印链接数量
// login.GET("/GetIWXConnect", controller.IWXConnectMgrApi)
// 打印链接信息
//login.GET("/GetConnectInfo", controller.GetConnectInfo)
// 检测微信登陆环境
// login.GET("/CheckCanSetAlias", controller.CheckCanSetAliasApi)
// HTML展示登录二维码
// login.GET("/ShowQrCode", controller.GetLoginQrCodeTempShow)
// 62LoginNew新疆号登录
// login.POST("/LoginNew", controller.LoginNewApi)
// 短信登陆
// login.POST("/SmsLogin", controller.SmsLoginApi)
// Mac登录
// login.POST("/MacLogin", controller.MacLoginApi)
// 安卓平板登录
// login.POST("/AndroidPadLogin", controller.AndroidPadLoginApi)
// win登录
// login.POST("/WinLogin", controller.WinLoginService)
// 车载登录
// login.POST("/CarLogin", controller.CarLoginApi)
// 初始化状态
// login.GET("/GetInItStatus", controller.GetInItStatusApi)
// 扫码后直接登陆成功 改 845 已不需要验证码(25.5.24更新 已经859了 时过境迁啊)
// login.POST("/GetLoginQrCodeNew", controller.GetLoginQrCodeNewApi)
// 绕过验证码登录 GetLoginQrCodeNewApi
// login.POST("/GetLoginQrCodeNewX", controller.GetLoginQrCodeNewApiX)
// 辅助新手机登录
// login.POST("/PhoneDeviceLogin", controller.PhoneDeviceLoginApi)
// 获取62信息
// login.GET("/Get62Data", controller.Get62DataApi)
// 获取验证码
// login.POST("/WxBindOpMobileForReg", controller.WxBindOpMobileForRegApi)
}
// 设备
equipment := engine.Group(ver + "/equipment")
{
equipment.GET("/GetOnlineInfo", controller.GetOnlineInfoApi)
equipment.POST("/GetSafetyInfo", controller.GetSafetyInfoApi)
equipment.POST("/DelSafeDevice", controller.DelSafeDeviceApi)
equipment.GET("/GetBoundHardDevice", controller.GetBoundHardDevice)
}
// // 长链接同步消息
ws := engine.Group(ver + "/ws")
{
ws.GET("/GetSyncMsg", controller.GetSyncMsgApi)
}
// 消息
message := engine.Group(ver + "/message")
{
// HTTP-轮询 同步消息
message.POST("/HttpSyncMsg", controller.HttpSyncMsg)
message.POST("/AddMessageMgr", controller.AddMessageMgrApi)
message.POST("/SendImageMessage", controller.SendImageMessageApi)
message.POST("/SendImageNewMessage", controller.SendImageNewMessageApi)
message.POST("/UploadImageToCDN", controller.UploadImageToCDNApi) // 纯CDN图片上传 我直接反手一个绕过
message.POST("/SendTextMessage", controller.SendTextMessageApi)
message.POST("/ShareCardMessage", controller.ShareCardMessageApi)
message.POST("/ForwardImageMessage", controller.ForwardImageMessageApi)
message.POST("/ForwardVideoMessage", controller.ForwardVideoMessageApi)
message.POST("/SendEmojiMessage", controller.SendEmojiMessageApi)
message.POST("/ForwardEmoji", controller.ForwardEmojiApi)
message.POST("/SendAppMessage", controller.SendAppMessageApi)
message.POST("/RevokeMsg", controller.RevokeMsgApi)
message.POST("/RevokeMsgNew", controller.RevokeMsgNewApi)
message.POST("/SendVoice", controller.UploadVoiceRequestApi)
message.POST("/CdnUploadVideo", controller.CdnUploadVideoRequestApi)
message.POST("/SendCdnDownload", controller.SendCdnDownloadApi) // 统一改为企微图片下载(接收xml自动解析)
message.POST("/GetMsgBigImg", controller.GetMsgBigImgApi)
message.POST("/GetMsgVideo", controller.GetMsgVideoApi)
message.POST("/NewSyncHistoryMessage", controller.NewSyncHistoryMessageApi)
message.POST("/GetMsgVoice", controller.GetMsgVoiceApi)
message.POST("/GroupMassMsgText", controller.GroupMassMsgTextApi)
message.POST("/GroupMassMsgImage", controller.GroupMassMsgImageApi)
// 下载表情gif
message.POST("/DownloadEmojiGif", controller.DownloadEmojiGifApi)
// 消息回调相关接口
message.POST("/SetCallback", controller.SetCallbackApi)
message.GET("/GetCallback", controller.GetCallbackApi)
message.GET("/DeleteCallback", controller.DeleteCallbackApi)
//// SendTextMessageNoShow 不显示会话(不删聊天记录)
// message.POST("/SendTextMessageNoShow", controller.SendTextMessageNoShow)
}
// 朋友圈
sns := engine.Group(ver + "/sns")
{
sns.POST("/DownloadMedia", controller.DownloadMediaApi)
sns.POST("/SetFriendCircleDays", controller.SetFriendCircleDaysApi)
sns.POST("/SendFriendCircle", controller.SendFriendCircleApi)
sns.POST("/SendFriendCircleByXMl", controller.SendFriendCircleByXMlApi)
sns.POST("/UploadFriendCircleImage", controller.UploadFriendCircleImageApi)
sns.POST("/SendSnsComment", controller.SendSnsCommentRequestApi)
sns.POST("/SendSnsObjectOp", controller.SendSnsObjectOpRequestApi)
sns.POST("/SendSnsTimeLine", controller.SendSnsTimeLineRequestApi)
sns.POST("/SendSnsUserPage", controller.SendSnsUserPageRequestApi)
sns.POST("/SendSnsObjectDetailById", controller.SendSnsObjectDetailByIdApi)
sns.POST("/SetBackgroundImage", controller.SetBackgroundImageApi)
sns.POST("/SendFavItemCircle", controller.SendFavItemCircleApi)
sns.POST("/SendOneIdCircle", controller.SendOneIdCircleApi)
sns.POST("/GetCollectCircle", controller.GetCollectCircleApi)
sns.POST("/GetSnsSync", controller.GetSnsSync)
sns.POST("/CdnSnsVideoUpload", controller.CdnSnsVideoUploadApi)
}
// 群管理
group := engine.Group(ver + "/group")
{
// 获取群聊二维码
group.POST("/GetChatroomQrCode", controller.GetChatroomQrCode)
group.POST("/SetChatroomAnnouncement", controller.SetChatroomAnnouncementApi)
group.POST("/GetChatroomMemberDetail", controller.GetChatroomMemberDetailApi)
group.POST("/QuitChatroom", controller.GetQuitChatroomApi)
group.POST("/CreateChatRoom", controller.CreateChatRoomApi)
group.POST("/InviteChatroomMembers", controller.InviteChatroomMembersApi)
group.POST("/AddChatRoomMembers", controller.AddChatRoomMembersApi)
group.POST("/SendDelDelChatRoomMember", controller.SendDelDelChatRoomMemberApi)
group.POST("/ScanIntoUrlGroup", controller.ScanIntoUrlGroupApi)
group.POST("/SendTransferGroupOwner", controller.SendTransferGroupOwnerApi)
group.POST("/SetGetChatRoomInfoDetail", controller.SetGetChatRoomInfoDetailApi)
group.POST("/GetChatRoomInfo", controller.GetChatRoomInfoApi)
group.POST("/MoveToContract", controller.MoveToContractApi)
group.POST("/SetChatroomAccessVerify", controller.SetChatroomAccessVerifyApi)
group.POST("/AddChatroomAdmin", controller.AddChatroomAdminApi)
group.POST("/DelChatroomAdmin", controller.DelChatroomAdminApi)
group.POST("/SetChatroomName", controller.SetChatroomNameApi)
group.POST("/SendPat", controller.SendPatApi)
group.POST("/ToJoinGroup", controller.ConsentToJoinGroupApi)
// group.GET("/GroupList", controller.GroupListApi)
}
// 用户
user := engine.Group(ver + "/user")
{
user.POST("/GetMyQrCode", controller.GetMyQrCode)
user.GET("/GetProfile", controller.GetProfileApi)
user.POST("/ModifyUserInfo", controller.ModifyUserInfoRequestApi)
user.POST("/UpdateNickName", controller.UpdateNickNameApi)
user.POST("/SetNickName", controller.SetNickNameApi)
user.POST("/SetSignature", controller.SetSignatureApi)
user.POST("/SetSexDq", controller.SetSexApi)
user.POST("/ResetGender", controller.ResetGenderApi)
user.POST("/ChangePwd", controller.ChangePwdRequestRequestApi)
user.POST("/SetKeywordReply", controller.SetKeywordReplyApi)
user.GET("/GetKeywordReply", controller.GetKeywordReplyApi)
user.POST("/SetWelcome", controller.SetWelcomeApi)
user.GET("/GetWelcome", controller.GetWelcomeApi)
user.POST("/SetAdminKeyword", controller.SetAdminKeywordApi)
user.GET("/GetAdminKeyword", controller.GetAdminKeywordApi)
user.POST("/SetKickKeyword", controller.SetKickKeywordApi)
user.GET("/GetKickKeyword", controller.GetKickKeywordApi)
user.POST("/SetInviteKeyword", controller.SetInviteKeywordApi)
user.GET("/GetInviteKeyword", controller.GetInviteKeywordApi)
user.POST("/UploadHeadImage", controller.UploadHeadImageApi)
user.POST("/UpdateAutoPass", controller.UpdateAutoPassApi)
user.POST("/ModifyRemark", controller.SendModifyRemarkRequestApi)
user.POST("/SetWechat", controller.SetWechatApi)
user.POST("/SetFunctionSwitch", controller.SetFunctionSwitchApi)
user.POST("/SetSendPat", controller.SetSendPatApi)
user.POST("/SetProxy", controller.SetProxyApi)
}
// 公众号/小程序
applet := engine.Group(ver + "/applet")
{
applet.POST("/FollowGH", controller.FollowGHApi)
applet.POST("/GetA8Key", controller.GetA8KeyApi)
applet.POST("/JsLogin", controller.JSLoginApi)
applet.POST("/JSOperateWxData", controller.JSOperateWxDataApi)
applet.POST("/SdkOauthAuthorize", controller.SdkOauthAuthorizeApi)
applet.POST("/QRConnectAuthorize", controller.QRConnectAuthorizeApi)
applet.POST("/QRConnectAuthorizeConfirm", controller.QRConnectAuthorizeConfirmApi)
applet.POST("/GetMpA8Key", controller.GetMpA8KeyApi)
applet.POST("/GetMpHistoryMessage", controller.GetMpHistoryMessageApi)
applet.POST("/AuthMpLogin", controller.AuthMpLoginApi)
// 新增阅读公众号文章功能
applet.POST("/GetAppMsgExt", controller.GetAppMsgExtApi)
// 新增点赞公众号文章功能
applet.POST("/GetAppMsgExtLike", controller.GetAppMsgExtLikeApi)
// 新增获取公众号文章阅读数功能
applet.POST("/GetAppMsgReadCount", controller.GetAppMsgReadCountApi)
}
// 其他
other := engine.Group(ver + "/other")
{
other.POST("/GetPeopleNearby", controller.GetPeopleNearbyApi)
other.POST("/GetRedisSyncMsg", controller.GetRedisSyncMsgApi)
other.POST("/GetUserRankLikeCount", controller.GetUserRankLikeCountApi)
other.POST("/UpdateStepNumber", controller.UpdateStepNumberApi)
other.POST("/UpdateCmdStatus", controller.UpdateCmdStatusApi)
//// GetProjectFullPathApi 获取项目完整路径
other.GET("/GetProjectFullPath", controller.GetProjectFullPathApi)
// 上传文件
other.POST("/UploadAppAttach", controller.UploadAppAttachApi)
// 企微图片下载
other.POST("/QWImageDownload", controller.QWImageDownloadApi)
}
// 收藏
favor := engine.Group(ver + "/favor")
{
favor.GET("/FavSync", controller.FavSyncApi)
favor.POST("/GetFavList", controller.GetFavListApi)
favor.POST("/GetFavItemId", controller.BatchGetFavItemApi)
favor.POST("/BatchDelFavItem", controller.BatchDelFavItemApi)
}
// 标签
label := engine.Group(ver + "/label")
{
label.GET("/GetContactLabelList", controller.GetContactLabelListApi)
label.POST("/AddContactLabel", controller.AddContactLabelRequestApi)
label.POST("/DelContactLabel", controller.DelContactLabelRequestApi)
label.POST("/ModifyLabel", controller.ModifyLabelRequestApi)
label.POST("/GetWXFriendListByLabel", controller.GetWXFriendListByLabelIDApi)
}
// 朋友
friend := engine.Group(ver + "/friend")
{
friend.POST("/GetContactList", controller.GetContactListApi)
// friend.GET("/GetFriendList", controller.GetFriendListApi)
friend.GET("/GroupList", controller.GetGroupListApi)
friend.GET("/GetGHList", controller.GetGHListApi)
friend.GET("/GetMFriend", controller.GetMFriendApi)
friend.POST("/GetContactDetailsList", controller.GetContactContactApi)
friend.POST("/GetFriendRelation", controller.GetFriendRelationApi)
friend.POST("/UploadMContact", controller.UploadMContactApi)
friend.POST("/DelContact", controller.DelContactApi)
friend.POST("/SearchContact", controller.SearchContactRequestApi)
friend.POST("/VerifyUser", controller.VerifyUserRequestApi)
friend.POST("/AgreeAdd", controller.AgreeAddApi)
}
// 支付
pay := engine.Group(ver + "/pay")
{
pay.POST("/GetBandCardList", controller.GetBandCardListApi)
pay.POST("/GeneratePayQCode", controller.GeneratePayQCodeApi)
pay.POST("/Collectmoney", controller.CollectMoneyApi)
pay.POST("/WXCreateRedPacket", controller.WXCreateRedPacketApi)
pay.POST("/OpenRedEnvelopes", controller.OpenRedEnvelopesApi)
pay.POST("/GetRedEnvelopesDetail", controller.QueryRedEnvelopesDetailApi)
pay.POST("/GetRedPacketList", controller.GetRedPacketListApi)
pay.POST("/CreatePreTransfer", controller.CreatePreTransferApi)
pay.POST("/ConfirmPreTransfer", controller.ConfirmPreTransferApi)
}
// 视频号
finder := engine.Group(ver + "/finder")
{
finder.POST("/ChannelsLogin", controller.ChannelsLoginApi)
finder.POST("/FinderSearch", controller.GetFinderSearchApi)
finder.POST("/FinderUserPrepare", controller.FinderUserPrepareApi)
finder.POST("/FinderFollow", controller.FinderFollowApi)
}
// 微信小店
shop := engine.Group(ver + "/shop")
{
shop.POST("/ShopLoginConfirm", controller.ShopLoginConfirmApi)
shop.POST("/ExtDeviceLoginConfirmGet", controller.ExtDeviceLoginConfirmGetApi)
shop.POST("/ExtDeviceLoginConfirmOk", controller.ExtDeviceLoginConfirmOkApi)
shop.POST("/ScanQrcodeEventReport", controller.ScanQrcodeEventReportApi)
}
// 企业微信
qy := engine.Group(ver + "/qy")
{
qy.POST("/QWSearchContact", controller.QWSearchContactApi)
qy.POST("/QWApplyAddContact", controller.QWApplyAddContactApi)
qy.POST("QWAddContact", controller.QWAddContactApi)
qy.POST("/QWContact", controller.QWContactApi)
qy.POST("/QWSyncContact", controller.QWSyncContactApi)
qy.POST("/QWRemark", controller.QWRemarkApi)
qy.POST("/QWCreateChatRoom", controller.QWCreateChatRoomApi)
qy.POST("/QWSyncChatRoom", controller.QWSyncChatRoomApi)
qy.POST("/QWChatRoomTransferOwner", controller.QWChatRoomTransferOwnerApi)
qy.POST("/QWAddChatRoomMember", controller.QWAddChatRoomMemberApi)
qy.POST("/QWInviteChatRoomMember", controller.QWInviteChatRoomMemberApi)
qy.POST("/QWDelChatRoomMember", controller.QWDelChatRoomMemberApi)
qy.POST("/QWGetChatRoomMember", controller.QWGetChatRoomMemberApi)
qy.POST("/QWGetChatroomInfo", controller.QWGetChatroomInfoApi)
qy.POST("/QWGetChatRoomQR", controller.QWGetChatRoomQRApi)
qy.POST("/QWAppointChatRoomAdmin", controller.QWAppointChatRoomAdminApi)
qy.POST("/QWDelChatRoomAdmin", controller.QWDelChatRoomAdminApi)
qy.POST("/QWAcceptChatRoom", controller.QWAcceptChatRoomRequestApi)
qy.POST("/QWAdminAcceptJoinChatRoomSet", controller.QWAdminAcceptJoinChatRoomSetApi)
qy.POST("/QWModChatRoomName", controller.QWModChatRoomNameApi)
qy.POST("/QWModChatRoomMemberNick", controller.QWModChatRoomMemberNickApi)
qy.POST("/QWChatRoomAnnounce", controller.QWChatRoomAnnounceApi)
qy.POST("/QWDelChatRoom", controller.QWDelChatRoomApi)
}
}
+241
View File
@@ -0,0 +1,241 @@
package service
import (
"errors"
"fmt"
"strings"
"time"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/db"
"xiawan/wx/srv/wxface"
"github.com/gin-gonic/gin"
"github.com/lunny/log"
)
// 检查请求参数 key 对应的 license 是否可用
func CheckKey(queryKey string) (string, error) {
errMsg := fmt.Sprintf("%s 该 key 无效! 请 检查正确性 或 联系管理员生成", queryKey)
if len(strings.TrimSpace(queryKey)) == 0 {
// 请求参数中没有携带 license 或者 license 为空
return "", errors.New(errMsg)
}
has, err := db.HasLicense(queryKey)
if has == nil || err != nil {
// MySQL 数据库没有该 license
return "", errors.New(errMsg)
}
if db.CheckExpiry(has.ExpiryDate, has.Type) {
// MySQL 数据库中的该 license 已过期
return "", fmt.Errorf("%s 该 key 已过期!", queryKey)
}
// license 可用
return queryKey, nil
}
// GenAuthKeyService 生成授权码(新设备)
func GenAuthKeyService(count, days int) vo.DTO {
if count < 1 {
count = 1
}
if days < 1 {
days = 30
}
res := db.CreateLicense(count, days)
authKeys := strings.Split(res, "\n\t")
if len(res) == 0 {
authKeys = []string{}
}
return vo.NewSuccessObj(authKeys, "AuthKey生成成功")
}
// 按类型生成(不使用不计算时间)
func GenAuthKeyService3(count int, itype int) vo.DTO {
//1日 7 周 30月 90季 180 半年 365年 30000
types := []int{1, 7, 30, 90, 180, 365, 30000}
// 判断 itype 在 types 中
isType := false
for _, t := range types {
if t == itype {
isType = true
break
}
}
log.Println("isType", isType)
log.Println("Type", itype)
log.Println("types", types)
if !isType {
return vo.NewFail("type 参数错误")
}
res := db.CreateLicense3(count, itype)
authKeys := strings.Split(res, "\n\t")
if len(res) == 0 {
authKeys = []string{}
}
return vo.NewSuccessObj(authKeys, "AuthKey生成成功")
}
// 授权码延期 西柚云
func DelayAuthKeyServiceNew(key string, m req.DelayAuthKeyModelNew) vo.DTO {
if m.KeyUse == "" || key == "" {
return vo.NewFail("keyuse 参数错误")
}
// 计算被使用key的剩余天数
keyuse_expirydata, err := db.HasLicense(m.KeyUse)
if err != nil || keyuse_expirydata == nil {
return vo.NewFail("查询失败")
}
key_use_days := keyuse_expirydata.Type
ms := req.DelayAuthKeyModel{
Key: key,
Days: key_use_days,
ExpiryDate: "",
}
db.DeleteLicense(m.KeyUse, 2)
return DelayAuthKeyService(ms)
}
// 授权码解绑 西柚云
func UnbindAuthKeyService(key string) vo.DTO {
if key == "" {
return vo.NewFail("key 参数错误")
}
ms := req.DeleteAuthKeyModel{
Key: key,
Opt: 3,
}
return checkExIdPerformNoCreateConnect(key, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
wxAccount.GetUserInfo().SetLoginState(0)
if wxAccount.GetUserInfo().GetLoginState() == 0 {
return DeleteAuthKeyService(ms)
} else {
return vo.NewFail("解绑失败")
}
})
}
// 查看配置
func GetConfigService(key string) vo.DTO {
if key == "" {
return vo.NewFail("key 参数错误")
}
query, err := db.QueryCommand(key)
if err != nil {
return vo.NewFail("操作失败!")
}
return vo.NewSuccessObj(query, "操作成功!")
}
// DelayAuthKeyService 授权码延期
func DelayAuthKeyService(m req.DelayAuthKeyModel) vo.DTO {
if m.Days < 1 {
m.Days = 30
}
if len(strings.TrimSpace(m.ExpiryDate)) > 0 {
// 获取当前的过期日期
expiryDate, err := time.Parse("2006-01-02", m.ExpiryDate)
if err != nil {
return vo.NewFail("ExpiryDate 参数解析错误")
}
now := time.Now()
if expiryDate.Before(now) {
return vo.NewFail("ExpiryDate 参数设置错误")
}
// ExpiryDate 参数可用
m.ExpiryDate = strings.TrimSpace(m.ExpiryDate)
m.Days = 0
}
expiryDateStr, err := db.DelayLicense(m)
if err != nil {
return vo.NewFail("延期失败: " + err.Error())
}
// 延期成功; 更新已建立链接的授权码的过期时间
return getExistWxConnect(m.Key, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
if connect != nil {
connect.GetWXServer().UpdateExpiryDate(m.Key, expiryDateStr)
}
return vo.NewSuccess(gin.H{
"expiryDate": expiryDateStr,
}, "延期成功")
})
}
// 更新禁用状态
func BannedAuthKeyService(m req.BannedAuthKeyModel) vo.DTO {
bannedStr := "启用:0"
if m.IsBanned != 0 {
m.IsBanned = 1
bannedStr = "禁用:1"
}
err := db.DisableLicense(m.Key, m.IsBanned)
if err != nil {
return vo.NewFail("设置失败: " + err.Error())
}
// 延期成功; 更新已建立链接的授权码的过期时间
return getExistWxConnect(m.Key, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
if connect != nil {
connect.GetWXServer().UpdateDisable(m.Key, m.IsBanned)
}
return vo.NewSuccess(gin.H{
"isBanned": bannedStr,
}, "设置成功")
})
}
// HttpSyncLicenseKeyService HTTP-激活状态
func HttpSyncLicenseKeyService() vo.DTO {
results, err := db.HttpSyncLicenseKey()
if err != nil {
return vo.NewFail("发生错误: " + err.Error())
}
return vo.NewSuccessObj(results, "")
}
// DeleteAuthKeyService 删除授权码
func DeleteAuthKeyService(m req.DeleteAuthKeyModel) vo.DTO {
err := db.DeleteLicense(m.Key, m.Opt)
if err != nil {
return vo.NewFail("删除授权码失败: " + err.Error())
}
return vo.NewSuccess(gin.H{}, "删除成功")
}
// GetLicenseKeyService 查询卡密有效期
func GetLicenseKeyService(queryKey string) vo.DTO {
has, err := db.HasLicense(queryKey)
if err != nil {
return vo.NewFail("查询失败")
}
if has == nil {
return vo.NewFail("卡密不存在")
}
return vo.NewSuccessObj(has, "查询成功")
}
// GetActiveLicenseKeysService 获取所有激活状态的卡密
func GetActiveLicenseKeysService() vo.DTO {
results, err := db.GetActiveLicenseKeys()
if err != nil {
return vo.NewFail("查询失败: " + err.Error())
}
return vo.NewSuccessObj(results, "查询成功")
}
+919
View File
@@ -0,0 +1,919 @@
package service
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
"time"
"xiawan/wx/api/req"
"xiawan/wx/api/utils"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
)
// GetA8KeyService 授权链接
func GetA8KeyService(queryKey string, m req.GetA8KeyRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.GetA8KeyRequest(m.OpCode, m.Scene, m.ReqUrl, baseinfo.ThrIdGetA8Key)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// JSLoginService 小程序授权
func JsLoginService(queryKey string, m req.AppletModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.JSLoginRequest(m.AppId)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// JSOperateWxDataService 小程序云函数操作
func JSOperateWxDataService(queryKey string, m req.AppletModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.JSOperateWxDataRequest(m.AppId, m.Opt, m.Data)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
func SdkOauthAuthorizeService(queryKey string, m req.AppletModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.SdkOauthAuthorizeRequest(m.AppId, m.SdkName, m.PackageName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 二维码授权登录
func QRConnectAuthorizeService(queryKey string, m req.QRConnectAuthorizeModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.SendQRConnectAuthorize(m.QrUrl)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 二维码授权登录确认
func QRConnectAuthorizeConfirmService(queryKey string, m req.QRConnectAuthorizeModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.SendQRConnectAuthorizeConfirm(m.QrUrl)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 授权链接
func GetMpA8Service(queryKey string, m req.GetMpA8KeyModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.SendGetMpA8Request(m.Url, m.Opcode)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 授权公众号登录
func AuthMpLoginService(queryKey string, m req.GetMpA8KeyModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
m.Opcode = 2
resp, err := reqInvoker.SendGetMpA8Request(m.Url, m.Opcode)
if err != nil {
return vo.NewFail(err.Error())
}
if resp.BaseResponse.GetRet() == 0 {
if m.Scene == 0 {
v, cookie := utils.GetHTML(resp.GetFullURL(), resp.HttpHeader)
var passTicket = regexp.MustCompile(`var _pass_ticket = '([^']*)'`)
var appmsgToken = regexp.MustCompile(`var _appmsg_token = '([^']*)'`)
var qrticket = regexp.MustCompile(`var qrticket = '([^']*)'`)
data := url.Values{}
data.Add("uin", "777")
data.Add("key", "777")
data.Add("pass_ticket", passTicket.FindStringSubmatch(v)[1])
data.Add("appmsg_token", appmsgToken.FindStringSubmatch(v)[1])
data.Add("f", "json")
data.Add("param", "qrticket")
data.Add("qrticket", qrticket.FindStringSubmatch(v)[1])
rsp := utils.HttpPost("https://mp.weixin.qq.com/wap/loginauthqrcode?action=confirm", data, cookie)
return vo.NewSuccessObj(rsp, "授权登录成功")
} else if m.Scene == 1 {
v, cookie := utils.GetHTML(resp.GetFullURL(), resp.HttpHeader)
var ticket = regexp.MustCompile(`_ticket = "(.*?)",`)
var uuid = regexp.MustCompile(`_uuid = "(.*?)",`)
var passTicket = regexp.MustCompile(`_pass_ticket = "(.*?)",`)
var appmsgToken = regexp.MustCompile(`_appmsg_token = "(.*?)",`)
var msgId = regexp.MustCompile(`_msgid = "(.*?)",`)
var secondOpenId = regexp.MustCompile(`_second_openid = "(.*?)",`)
data := url.Values{}
data.Add("ticket", ticket.FindStringSubmatch(v)[1])
data.Add("uuid", uuid.FindStringSubmatch(v)[1])
data.Add("action", "check")
data.Add("uin", "777")
data.Add("key", "777")
data.Add("pass_ticket", passTicket.FindStringSubmatch(v)[1])
data.Add("appmsg_token", appmsgToken.FindStringSubmatch(v)[1])
data.Add("code", "invalid")
data.Add("type", "bind_second_admin")
data.Add("msgid", msgId.FindStringSubmatch(v)[1])
data.Add("second_openid", secondOpenId.FindStringSubmatch(v)[1])
data.Add("expire_time_type", "0")
data.Add("allow", "1")
rsp := utils.HttpPost("https://mp.weixin.qq.com/safe/safeconfirm_reply", data, cookie)
return vo.NewSuccessObj(rsp, "授权验证成功")
} else if m.Scene == 2 {
v, cookie := utils.GetHTML(resp.GetFullURL(), resp.HttpHeader)
var ticket = regexp.MustCompile(`_ticket = "(.*?)",`)
var uuid = regexp.MustCompile(`_uuid = "(.*?)",`)
var passTicket = regexp.MustCompile(`_pass_ticket = "(.*?)",`)
var appmsgToken = regexp.MustCompile(`_appmsg_token = "(.*?)",`)
var msgId = regexp.MustCompile(`_msgid = "(.*?)",`)
data := url.Values{}
data.Add("ticket", ticket.FindStringSubmatch(v)[1])
data.Add("uuid", uuid.FindStringSubmatch(v)[1])
data.Add("action", "check")
data.Add("uin", "777")
data.Add("key", "777")
data.Add("pass_ticket", passTicket.FindStringSubmatch(v)[1])
data.Add("appmsg_token", appmsgToken.FindStringSubmatch(v)[1])
data.Add("code", "invalid")
data.Add("type", "appkey")
data.Add("msgid", msgId.FindStringSubmatch(v)[1])
data.Add("allow", "1")
rsp := utils.HttpPost("https://mp.weixin.qq.com/safe/safeconfirm_reply", data, cookie)
return vo.NewSuccessObj(rsp, "授权验证成功")
} else if m.Scene == 3 {
v, cookie := utils.GetHTML(resp.GetFullURL(), resp.HttpHeader)
var passTicket = regexp.MustCompile(`pass_ticket: '(.*?)',`)
var qrcheckTicket = regexp.MustCompile(`qrcheck_ticket: '(.*?)',`)
var appmsgToken = regexp.MustCompile(`window.appmsg_token = "(.*?)";`)
data := url.Values{}
data.Add("f", "json")
data.Add("action", "scan")
data.Add("qrcheck_ticket", qrcheckTicket.FindStringSubmatch(v)[1])
data.Add("uin", "777")
data.Add("key", "777")
data.Add("pass_ticket", passTicket.FindStringSubmatch(v)[1])
data.Add("appmsg_token", appmsgToken.FindStringSubmatch(v)[1])
rsp := utils.HttpPost("https://mp.weixin.qq.com/wap/qrcheckoper", data, cookie)
return vo.NewSuccessObj(rsp, "授权验证成功")
} else if m.Scene == 4 {
v, cookie := utils.GetHTML(resp.GetFullURL(), resp.HttpHeader)
var passTicket = regexp.MustCompile(`pass_ticket: '(.*?)',`)
var appmsgToken = regexp.MustCompile(`appmsg_token: '(.*?)',`)
var qrcheckTicket = regexp.MustCompile(`qrcheck_ticket: '(.*?)',`)
data := url.Values{}
data.Add("f", "json")
data.Add("action", "confirm")
data.Add("operate_type", "1")
data.Add("qrcheck_ticket", qrcheckTicket.FindStringSubmatch(v)[1])
data.Add("uin", "777")
data.Add("key", "777")
data.Add("pass_ticket", passTicket.FindStringSubmatch(v)[1])
data.Add("appmsg_token", appmsgToken.FindStringSubmatch(v)[1])
rsp := utils.HttpPost("https://mp.weixin.qq.com/mp/wapsafeqrcode", data, cookie)
return vo.NewSuccessObj(rsp, "授权验证成功")
}
}
return vo.NewSuccessObj(resp, "失败")
})
}
// 获取公众号历史消息
func GetAppletHistoryMsg(queryKey string, m req.GetMpHistoryMsgModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
if m.Url == "" || m.Url == "undefined" || m.Url == "null" {
return vo.NewFail("url不能为空")
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
var Opcode = uint32(2) //
resp, err := reqInvoker.SendQWAcceptChatRoomRequest(m.Url, Opcode)
if err != nil {
return vo.NewFail(err.Error())
}
if resp.BaseResponse.GetRet() == 0 {
rsp := utils.HttpGet(resp.GetFullURL(), resp.HttpHeader)
return vo.NewSuccessObj(rsp, "成功")
}
return vo.NewSuccessObj(resp, "失败")
})
}
// GetAppMsgExtService 阅读公众号文章
func GetAppMsgExtService(queryKey string, m req.ReadParam) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
if m.Url == "" || m.Url == "undefined" || m.Url == "null" {
return vo.NewFail("url不能为空")
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
var Opcode = uint32(2)
resp, err := reqInvoker.SendGetMpA8Request(m.Url, Opcode)
if err != nil {
return vo.NewFail(err.Error())
}
if resp.BaseResponse.GetRet() != 0 {
return vo.NewFail("获取文章信息失败")
}
// 解析
urlObj, err := url.Parse(resp.GetFullURL())
if err != nil {
return vo.NewFail(fmt.Sprintf("解析URL异常:%v", err.Error()))
}
query := urlObj.Query()
if _, ok := query["pass_ticket"]; !ok {
return vo.NewFail("获取pass_ticket失败")
}
// 获取HTML页面和Cookie
_, cookie := utils.GetHTML(resp.GetFullURL(), resp.HttpHeader)
// 构建阅读请求
postUrl := "https://mp.weixin.qq.com/mp/getappmsgext?f=json&mock=&fasttmplajax=1&f=json&uin=&key=&pass_ticket=" +
query["pass_ticket"][0] + "&wxtoken=&devicetype=iOS13.3.1&clientversion=17000c2d&__biz=" +
url.QueryEscape(query["__biz"][0]) + "&appmsg_token=&x5=0&f=json&wx_header=1&pass_ticket=" + query["pass_ticket"][0]
postData := url.Values{}
postData.Add("r", "")
postData.Add("__biz", query["__biz"][0])
postData.Add("appmsg_type", "9")
postData.Add("mid", query["mid"][0])
postData.Add("sn", query["sn"][0])
postData.Add("idx", query["idx"][0])
postData.Add("scene", "126")
postData.Add("title", "")
postData.Add("ct", time.Now().String())
postData.Add("abtest_cookie", "")
postData.Add("devicetype", "iOS13.3.1")
postData.Add("version", "17000c2d")
postData.Add("is_need_ticket", "0")
postData.Add("is_need_ad", "0")
postData.Add("comment_id", "")
postData.Add("is_need_reward", "0")
postData.Add("both_ad", "0")
postData.Add("reward_uin_count", "0")
postData.Add("send_time", "")
postData.Add("msg_daily_idx", "1")
postData.Add("is_original", "0")
postData.Add("is_only_read", "1")
postData.Add("req_id", "")
postData.Add("pass_ticket", query["pass_ticket"][0])
postData.Add("is_temp_url", "0")
postData.Add("item_show_type", "0")
postData.Add("tmp_version", "1")
postData.Add("more_read_type", "0")
postData.Add("appmsg_like_type", "2")
postData.Add("related_video_sn", "")
postData.Add("vid", "")
postData.Add("is_pay_subscribe", "0")
postData.Add("pay_subscribe_uin_count", "0")
postData.Add("has_red_packet_cover", "0")
postData.Add("album_id", "")
result := utils.HttpPost(postUrl, postData, cookie)
return vo.NewSuccessObj(result, "阅读成功")
})
}
// GetAppMsgExtLikeService 点赞公众号文章
func GetAppMsgExtLikeService(queryKey string, m req.ReadParam) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
if m.Url == "" || m.Url == "undefined" || m.Url == "null" {
return vo.NewFail("url不能为空")
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
var Opcode = uint32(2)
resp, err := reqInvoker.SendGetMpA8Request(m.Url, Opcode)
if err != nil {
return vo.NewFail(err.Error())
}
if resp.BaseResponse.GetRet() != 0 {
return vo.NewFail("获取文章信息失败")
}
// 解析
urlObj, err := url.Parse(resp.GetFullURL())
if err != nil {
return vo.NewFail(fmt.Sprintf("解析URL异常:%v", err.Error()))
}
query := urlObj.Query()
if _, ok := query["pass_ticket"]; !ok {
return vo.NewFail("获取pass_ticket失败")
}
// 获取HTML页面和Cookie
bodyStr, cookie := utils.GetHTML(resp.GetFullURL(), resp.HttpHeader)
// 提取appmsg_token,用正则表达式
var appmsgToken string
reAppmsgToken := regexp.MustCompile(`var appmsg_token = ["'](.*?)["']`)
appmsgTokenMatches := reAppmsgToken.FindStringSubmatch(bodyStr)
if len(appmsgTokenMatches) > 1 {
appmsgToken = appmsgTokenMatches[1]
} else {
// 尝试另一种格式
reAppmsgToken = regexp.MustCompile(`appmsg_token="(.*?)"`)
appmsgTokenMatches = reAppmsgToken.FindStringSubmatch(bodyStr)
if len(appmsgTokenMatches) > 1 {
appmsgToken = appmsgTokenMatches[1]
}
}
// 构建阅读请求 (和阅读一样的请求,为了保证点赞成功)
postUrl := "https://mp.weixin.qq.com/mp/getappmsgext?f=json&mock=&fasttmplajax=1&f=json&uin=&key=&pass_ticket=" +
query["pass_ticket"][0] + "&wxtoken=&devicetype=iOS13.3.1&clientversion=17000c2d&__biz=" +
url.QueryEscape(query["__biz"][0]) + "&appmsg_token=&x5=0&f=json&wx_header=1&pass_ticket=" + query["pass_ticket"][0]
postData := url.Values{}
postData.Add("r", "")
postData.Add("__biz", query["__biz"][0])
postData.Add("appmsg_type", "9")
postData.Add("mid", query["mid"][0])
postData.Add("sn", query["sn"][0])
postData.Add("idx", query["idx"][0])
postData.Add("scene", "126")
postData.Add("title", "")
postData.Add("ct", time.Now().String())
postData.Add("abtest_cookie", "")
postData.Add("devicetype", "iOS13.3.1")
postData.Add("version", strconv.FormatInt(int64(baseinfo.ClientVersion), 16))
postData.Add("is_need_ticket", "0")
postData.Add("is_need_ad", "0")
postData.Add("comment_id", "")
postData.Add("is_need_reward", "0")
postData.Add("both_ad", "0")
postData.Add("reward_uin_count", "0")
postData.Add("send_time", "")
postData.Add("msg_daily_idx", "1")
postData.Add("is_original", "0")
postData.Add("is_only_read", "1")
postData.Add("req_id", "")
postData.Add("pass_ticket", query["pass_ticket"][0])
postData.Add("is_temp_url", "0")
postData.Add("item_show_type", "0")
postData.Add("tmp_version", "1")
postData.Add("more_read_type", "0")
postData.Add("appmsg_like_type", "2")
postData.Add("related_video_sn", "")
postData.Add("vid", "")
postData.Add("is_pay_subscribe", "0")
postData.Add("pay_subscribe_uin_count", "0")
postData.Add("has_red_packet_cover", "0")
postData.Add("album_id", "")
result := utils.HttpPost(postUrl, postData, cookie)
// 提取appmsgid,用正则表达式
reAppmsgid := regexp.MustCompile(`var appmsgid = ['"+][0-9]*['"+] \|\| ['"+][0-9]*['"+] \|\| ['"+][0-9]*['"+]`)
appmsgidStr := reAppmsgid.FindString(bodyStr)
reDigits := regexp.MustCompile(`[0-9]+`)
appmsgid := reDigits.FindString(appmsgidStr)
if appmsgid == "" {
return vo.NewFail("获取文章appmsgid失败")
}
// 构建点赞请求
likeUrl := "https://mp.weixin.qq.com/mp/appmsg_like?__biz=" + url.QueryEscape(query["__biz"][0]) +
"&mid=" + query["mid"][0] + "&idx=" + query["idx"][0] + "&like=1&f=json&appmsgid=" + appmsgid +
"&itemidx=&fasttmplajax=1&f=json&uin=777&key=777&pass_ticket=" + query["pass_ticket"][0] +
"&wxtoken=777&devicetype=iOS13.3.1&clientversion=" + strconv.FormatInt(int64(baseinfo.ClientVersion), 16) +
"&appmsg_token=" + appmsgToken + "&x5=0&f=json&wx_header=1"
// 创建自定义header,确保Cookie正确传递
header := make(map[string]string)
header["Cookie"] = strings.Join(cookie, "; ")
header["Content-Type"] = "application/x-www-form-urlencoded"
header["User-Agent"] = "Mozilla/5.0 (iPad; CPU OS 12_4_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.15(0x17000f31) NetType/WIFI Language/zh_CN"
header["Referer"] = resp.GetFullURL()
header["Origin"] = "https://mp.weixin.qq.com"
header["X-Requested-With"] = "XMLHttpRequest"
likeData := url.Values{}
likeData.Add("scene", "142")
likeData.Add("appmsg_like_type", "1")
likeData.Add("item_show_type", "0")
likeData.Add("client_version", strconv.FormatInt(int64(baseinfo.ClientVersion), 16))
likeData.Add("is_temp_url", "0")
likeData.Add("style", "1")
likeData.Add("exptype", "")
likeData.Add("expsessionid", "")
likeData.Add("request_id", time.Now().Format("20060102150405")+strconv.Itoa(int(time.Now().UnixNano()%1000)))
likeData.Add("device_type", "iOS13.3.1")
likeData.Add("appmsg_token", appmsgToken) // 使用从页面提取的appmsg_token
// 使用自定义的HTTP请求函数
req, err := http.NewRequest("POST", likeUrl, strings.NewReader(likeData.Encode()))
if err != nil {
return vo.NewFail(fmt.Sprintf("创建请求失败:%v", err.Error()))
}
for k, v := range header {
req.Header.Set(k, v)
}
// 添加更多调试信息
fmt.Printf("点赞请求URL: %s\n", likeUrl)
fmt.Printf("点赞请求参数: %s\n", likeData.Encode())
fmt.Printf("点赞请求Cookie: %s\n", header["Cookie"])
fmt.Printf("点赞请求appmsg_token: %s\n", appmsgToken)
client := &http.Client{}
httpResp, err := client.Do(req)
var likeResult string
if err != nil {
likeResult = fmt.Sprintf("{\"error\":\"%s\"}", err.Error())
} else {
defer httpResp.Body.Close()
respBody, _ := ioutil.ReadAll(httpResp.Body)
likeResult = string(respBody)
fmt.Printf("点赞响应: %s\n", likeResult)
}
return vo.NewSuccessObj(map[string]interface{}{
"read": result,
"like": likeResult,
}, "点赞成功")
})
}
// GetAppMsgReadCountService 获取公众号文章阅读数
func GetAppMsgReadCountService(queryKey string, m req.ReadParam) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
if m.Url == "" || m.Url == "undefined" || m.Url == "null" {
return vo.NewFail("url不能为空")
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
var Opcode = uint32(2)
resp, err := reqInvoker.SendGetMpA8Request(m.Url, Opcode)
if err != nil {
return vo.NewFail(err.Error())
}
if resp.BaseResponse.GetRet() != 0 {
return vo.NewFail("获取文章信息失败")
}
// 获取HTML页面内容
htmlContent, _ := utils.GetHTML(resp.GetFullURL(), resp.HttpHeader)
// 用正则表达式提取阅读数
readNumRegex := regexp.MustCompile(`var read_num_new = '(\d+)' \* 1;`)
readNumMatches := readNumRegex.FindStringSubmatch(htmlContent)
if len(readNumMatches) < 2 {
return vo.NewFail("未找到阅读数信息")
}
readCount := readNumMatches[1]
fullURL := resp.GetFullURL()
for _, h := range resp.HttpHeader {
if h.GetName() == "X-WECHAT-UIN" {
fullURL += "&uin=" + h.GetKey() + "&countrycode=CN"
} else if h.GetName() == "X-WECHAT-ACCTMODE" {
fullURL += "&acctmode=" + h.GetKey()
} else if h.GetName() == "X-WECHAT-KEY" {
fullURL += "&key=" + h.GetKey()
}
}
result := map[string]string{
"read_count": readCount,
"article_url": fullURL,
}
return vo.NewSuccessObj(result, "获取阅读数成功")
})
}
// ChannelsLoginService 视频号助手扫码登录
func ChannelsLoginService(queryKey string, m req.ChannelsLoginModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
if m.Url == "" || m.Url == "undefined" || m.Url == "null" {
return vo.NewFail("url不能为空")
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp1, err := reqInvoker.GetA8KeyRequest(2, 4, m.Url, baseinfo.ThrIdGetA8Key)
if err != nil {
return vo.NewFail("第一步失败: " + err.Error())
}
if resp1.BaseResponse.GetRet() != 0 {
return vo.NewFail(fmt.Sprintf("第一步失败, ret=%d, errMsg=%s", resp1.BaseResponse.GetRet(), resp1.BaseResponse.GetErrMsg().GetStr()))
}
fullURL := resp1.GetFullURL()
if fullURL == "" {
return vo.NewFail("第一步成功但未返回完整 URL")
}
parsedURL, err := url.Parse(fullURL)
if err != nil {
return vo.NewFail("解析 URL 失败: " + err.Error())
}
query := parsedURL.Query()
token := query.Get("token")
exportkey := query.Get("exportkey")
rid := fmt.Sprintf("%x-%x", time.Now().UnixNano()&0xFFFFFFFF, time.Now().UnixNano()&0xFFFFFFFF)
scanURL := fmt.Sprintf("https://channels.weixin.qq.com/cgi-bin/mmfinderassistant-bin/auth/scan-qrcode?token=%s&exportKey=%s&_rid=%s&exportkey=%s&_pageUrl=https://channels.weixin.qq.com/mobile/confirm_login.html",
url.QueryEscape(token), url.QueryEscape(exportkey), rid, url.QueryEscape(exportkey))
scanData := map[string]string{
"_rid": rid,
"exportkey": exportkey,
"_pageUrl": "https://channels.weixin.qq.com/mobile/confirm_login.html",
}
scanDataJSON, _ := json.Marshal(scanData)
scanResp := utils.HttpPostJSON(scanURL, string(scanDataJSON), nil)
// 解析 scan-qrcode 响应
var scanResult map[string]interface{}
if err := json.Unmarshal([]byte(scanResp), &scanResult); err != nil {
return vo.NewFail("解析 scan-qrcode 响应失败: " + err.Error())
}
if errCode, ok := scanResult["errCode"].(float64); !ok || errCode != 0 {
return vo.NewFail(fmt.Sprintf("scan-qrcode 失败: %v", scanResult))
}
data, ok := scanResult["data"].(map[string]interface{})
if !ok {
return vo.NewFail("scan-qrcode 响应格式错误")
}
finderList, ok := data["finderList"].([]interface{})
if !ok || len(finderList) == 0 {
return vo.NewFail("未找到 finderList")
}
var selectedFinder map[string]interface{}
if m.FinderUsername != "" && m.FinderUsername != "string" {
found := false
for _, finder := range finderList {
finderMap, ok := finder.(map[string]interface{})
if !ok {
continue
}
if username, ok := finderMap["finderUsername"].(string); ok && username == m.FinderUsername {
selectedFinder = finderMap
found = true
break
}
}
if !found {
return vo.NewFail(fmt.Sprintf("未找到指定的 finderUsername: %s", m.FinderUsername))
}
} else {
// 如果未指定或为默认值,选择第一个
firstFinder, ok := finderList[0].(map[string]interface{})
if !ok {
return vo.NewFail("finderList 格式错误")
}
selectedFinder = firstFinder
}
finderUsername, ok := selectedFinder["finderUsername"].(string)
if !ok {
return vo.NewFail("未找到 finderUsername")
}
rid2 := fmt.Sprintf("%x-%x", time.Now().UnixNano()&0xFFFFFFFF, time.Now().UnixNano()&0xFFFFFFFF)
authURL := fmt.Sprintf("https://channels.weixin.qq.com/cgi-bin/mmfinderassistant-bin/auth/finder-handle-auth?token=%s&exportKey=%s&action=0&finderUsername=%s&_rid=%s&exportkey=%s&_pageUrl=https://channels.weixin.qq.com/mobile/confirm_login.html",
url.QueryEscape(token), url.QueryEscape(exportkey), url.QueryEscape(finderUsername), rid2, url.QueryEscape(exportkey))
authData := map[string]string{
"_rid": rid2,
"exportkey": exportkey,
"_pageUrl": "https://channels.weixin.qq.com/mobile/confirm_login.html",
}
authDataJSON, _ := json.Marshal(authData)
authResp := utils.HttpPostJSON(authURL, string(authDataJSON), nil)
var authResult map[string]interface{}
if err := json.Unmarshal([]byte(authResp), &authResult); err != nil {
return vo.NewFail("解析 finder-handle-auth 响应失败: " + err.Error())
}
if errCode, ok := authResult["errCode"].(float64); !ok || errCode != 0 {
return vo.NewFail(fmt.Sprintf("finder-handle-auth 失败: %v", authResult))
}
result := map[string]interface{}{
"scan_qrcode": scanResult,
"handle_auth": authResult,
"full_url": fullURL,
"finder_username": finderUsername,
}
return vo.NewSuccessObj(result, "视频号助手登录成功")
})
}
// ShopLoginConfirmService 微信小店确认登录
func ShopLoginConfirmService(queryKey string, m req.ShopLoginConfirmModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
if m.Url == "" || m.Url == "undefined" || m.Url == "null" {
return vo.NewFail("url不能为空")
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
// 步骤1: 调用GetA8Key获取授权 (Scene=4)
// 这一步建立授权会话
resp1, err := reqInvoker.GetA8KeyRequest(2, 4, m.Url, baseinfo.ThrIdGetA8Key)
if err != nil {
return vo.NewFail("GetA8Key失败: " + err.Error())
}
if resp1.BaseResponse.GetRet() != 0 {
return vo.NewFail(fmt.Sprintf("GetA8Key失败, ret=%d, errMsg=%s", resp1.BaseResponse.GetRet(), resp1.BaseResponse.GetErrMsg().GetStr()))
}
// 步骤2: 调用CGI 8887模拟扫码事件上报
// 这一步模拟用户扫码行为,告诉服务器我们已经"扫码"了
_, err = reqInvoker.SendScanQrcodeEventReportRequest(resp1.GetFullURL())
if err != nil {
return vo.NewFail("扫码事件上报失败: " + err.Error())
}
// // 步骤3: 调用CGI 971获取确认信息 (包含6500+字节的token/session数据)
resp971, err := reqInvoker.SendExtDeviceLoginConfirmGetRequest(resp1.GetFullURL())
if err != nil {
return vo.NewFail("获取确认信息失败: " + err.Error())
}
if resp971.BaseResponse.GetRet() != 0 {
return vo.NewFail(fmt.Sprintf("获取确认信息失败, ret=%d, errMsg=%s", resp971.BaseResponse.GetRet(), resp971.BaseResponse.GetErrMsg().GetStr()))
}
// 步骤4: 调用CGI 972确认登录
resp, err := reqInvoker.SendExtDeviceLoginConfirmOkRequest(resp1.GetFullURL())
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
func ShopLoginConfirmGetService(queryKey string, m req.ShopLoginConfirmModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
if m.Url == "" || m.Url == "undefined" || m.Url == "null" {
return vo.NewFail("url不能为空")
}
reqInvoker := connect.GetWXReqInvoker()
url := strings.TrimSpace(m.Url)
resp971, err := reqInvoker.SendExtDeviceLoginConfirmGetRequest(url)
if err == nil && resp971.BaseResponse.GetRet() == 0 {
return vo.NewSuccessObj(resp971, "")
}
// resp1, err := reqInvoker.GetA8KeyRequest(2, 4, url, baseinfo.ThrIdGetA8Key)
// if err != nil {
// return vo.NewFail("GetA8Key失败: " + err.Error())
// }
// if resp1.BaseResponse.GetRet() != 0 {
// return vo.NewFail(fmt.Sprintf("GetA8Key失败, ret=%d, errMsg=%s", resp1.BaseResponse.GetRet(), resp1.BaseResponse.GetErrMsg().GetStr()))
// // }
// _, _ = reqInvoker.SendScanQrcodeEventReportRequest(resp1.GetFullURL())
// resp971, err = reqInvoker.SendExtDeviceLoginConfirmGetRequest(resp1.GetFullURL())
if err != nil {
return vo.NewFail("获取确认信息失败: " + err.Error())
}
return vo.NewSuccessObj(resp971, "")
})
}
func ShopLoginConfirmOkService(queryKey string, m req.ShopLoginConfirmModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
if m.Url == "" || m.Url == "undefined" || m.Url == "null" {
return vo.NewFail("url不能为空")
}
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.SendExtDeviceLoginConfirmOkRequest(m.Url)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
func ScanQrcodeEventReportService(queryKey string, m req.ShopLoginConfirmModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
if m.Url == "" || m.Url == "undefined" || m.Url == "null" {
return vo.NewFail("url不能为空")
}
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.SendScanQrcodeEventReportRequest(m.Url)
if err != nil {
return vo.NewFail("扫码事件上报失败: " + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
+429
View File
@@ -0,0 +1,429 @@
package service
import (
"fmt"
"reflect"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/clientsdk/proxynet"
"xiawan/wx/db"
"xiawan/wx/db/table"
"xiawan/wx/protobuf/wechat"
"xiawan/wx/srv"
"xiawan/wx/srv/srvconfig"
"xiawan/wx/srv/websrv"
"xiawan/wx/srv/wxcore"
"xiawan/wx/srv/wxface"
"xiawan/wx/srv/wxrouter"
"github.com/lunny/log"
)
// 基础服务功能
var WXServer wxface.IWXServer
type BusinessFunc = func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO
type USerInfoCallFunc = func(account *srv.WXAccount, invoker wxface.IWXReqInvoker, state uint32) vo.DTO
// 初始化微信响应路由
func InitWXServerRouter() {
// 开启服务器
wxServer := wxcore.NewWXServer()
// 注册微信响应路由
// wxServer.AddWXRouter(baseinfo.MMRequestTypeGetLoginQRCode, new(wxrouter.WXGetLoginQrcodeRouter)) // 获取登陆二维码响应
wxServer.AddWXRouter(baseinfo.MMRequestTypeCheckLoginQRCode, new(wxrouter.WXCheckQrcodeRouter)) // 检测二维码状态请求
wxServer.AddWXRouter(baseinfo.MMRequestTypePushQrLogin, new(wxrouter.WXPushQrCodeLoginRouter)) // 唤醒登录
wxServer.AddWXRouter(baseinfo.MMRequestTypeManualAuth, new(wxrouter.WXManualAuthRouter))
wxServer.AddWXRouter(baseinfo.MMRequestTypeHybridManualAuth, new(wxrouter.WXManualAuthRouter)) // 登录
wxServer.AddWXRouter(baseinfo.MMRequestTypeLogout, new(wxrouter.WXLogoutRouter)) // 退出登录
wxServer.AddWXRouter(baseinfo.MMRequestTypeAutoAuth, new(wxrouter.WXAutoAuthRouter)) // token登陆
wxServer.AddWXRouter(baseinfo.MMRequestTypeNewSync, new(wxrouter.WXNewSyncRouter)) // 同步消息,联系人
wxServer.AddWXRouter(baseinfo.MMRequestTypeNewInit, new(wxrouter.WXNewInitRouter)) // 首次登录初始化
wxServer.AddWXRouter(baseinfo.MMRequestTypeHeartBeat, new(wxrouter.WXHeartBeatRouter)) // 心跳包
wxServer.AddWXRouter(baseinfo.MMRequestTypeGetProfile, new(wxrouter.WXGetProfileRouter)) // 获取帐号信息
wxServer.AddWXRouter(baseinfo.MMRequestTypeGetCdnDNS, new(wxrouter.WXGetCDNDnsRouter)) // 获取CDNDns信息
wxServer.AddWXRouter(baseinfo.MMRequestTypeInitContact, new(wxrouter.WXInitContactRouter)) // 初始化联系人
wxServer.AddWXRouter(baseinfo.MMRequestTypeBatchGetContactBriefInfo, new(wxrouter.WXBatchGetContactBriefInfoReqRouter)) // 初始化联系人
// wxServer.AddWXRouter(baseinfo.MMRequestTypeGetContact, new(wxrouter.WXGetContactRouter)) // 批量获取联系人信息
wxServer.AddWXRouter(baseinfo.MMRequestTypeReceiveWxHB, new(wxrouter.WXReceiveHBRouter)) // 接收红包
wxServer.AddWXRouter(baseinfo.MMRequestTypeOpenWxHB, new(wxrouter.WXOpenHBRouter)) // 打开红包
// wxServer.AddWXRouter(baseinfo.MMRequestTypeOplog, new(wxrouter.WXOplogRouter)) // Oplog请求
// wxServer.AddWXRouter(baseinfo.MMRequestTypeNewSendMsg, new(wxrouter.WXNewSendMsgRouter)) // 发送文本消息
wxServer.AddWXRouter(baseinfo.MMRequestTypeFavSync, new(wxrouter.WXFavSyncRouter)) // 同步收藏
wxServer.AddWXRouter(baseinfo.MMRequestTypeGetFavInfo, new(wxrouter.WXGetFavInfoRouter)) // 获取收藏信息
wxServer.AddWXRouter(baseinfo.MMRequestTypeBatchGetFavItem, new(wxrouter.WXBatchGetFavItemRouter)) // 获取单条收藏(收藏转发)
wxServer.AddWXRouter(baseinfo.MMRequestTypeMMSnsPost, new(wxrouter.WXSnsPostRouter)) // 发送朋友圈
wxServer.AddWXRouter(baseinfo.MMRequestTypeMMSnsSync, new(wxrouter.WXSnsSyncRouter)) // 同步朋友圈
wxServer.AddWXRouter(baseinfo.MMRequestTypeMMSnsUserPage, new(wxrouter.WXSnsUserPageRouter)) // 朋友圈同步转发
wxServer.AddWXRouter(baseinfo.MMRequestTypeMMSnsTimeLine, new(wxrouter.WXSnsTimeLineRouter)) // 同步朋友圈
wxServer.AddWXRouter(baseinfo.MMRequestTypeMMSnsComment, new(wxrouter.WXSnsCommentRouter)) // 评论/点赞朋友圈
wxServer.AddWXRouter(baseinfo.MMRequestTypeGetContactLabelList, new(wxrouter.WXGetContactLabelListRouter)) // 获取标签列表
wxServer.AddWXRouter(baseinfo.MMRequestTypeAddContactLabel, new(wxrouter.WXAddContactLabelRouter)) // 新增标签列表
wxServer.AddWXRouter(baseinfo.MMRequestTypeGetQrCode, new(wxrouter.WXGetQrcodeRouter)) // 获取二维码
// wxServer.AddWXRouter(baseinfo.MMRequestTypeBindQueryNew, new(wxrouter.WXBindQueryNewRouter)) // 获取钱包信息
wxServer.Start()
WXServer = wxServer
}
func CreateWXConnectByQueryKey(queryKey, proxy string, wxAccount *srv.WXAccount) wxface.IWXConnect {
var proxyInfo *proxynet.WXProxyInfo
if proxy != "" {
proxyInfo = proxynet.ParseWXProxyInfo(proxy)
}
if wxAccount == nil {
wxAccount = srv.NewWXAccount(&websrv.TaskInfo{
UUID: queryKey,
}, proxyInfo, uint32(0), nil)
}
wxConnect := wxcore.NewWXConnect(WXServer, wxAccount)
return wxConnect
}
// checkExIdReturn 检测实例Id并返回实例
func checkExIdReturn(queryKey string, ClientVersion uint32) wxface.IWXConnect {
// 判断 ClientVersion == 0
if !(int(ClientVersion) > 0) {
ClientVersion = baseinfo.ClientVersion
}
//获取实例管理器
connectMgr := WXServer.GetWXConnectMgr()
//查询的queryKey为空创建一个链接实例
if queryKey == "" {
return nil
}
//查询该链接是否存在
iwxConnect := connectMgr.GetWXConnectByUserInfoUUID(queryKey)
if iwxConnect != nil {
//执行回调方法
return iwxConnect
} else {
//如果链接管理器不存在该链接查询数据库是否存在
dbUserInfo := db.GetUSerInfoByUUID(queryKey)
//数据库存在该链接数据 重新实例化一个链接对象
if dbUserInfo != nil {
if !(int(dbUserInfo.ClientVersion) > 0) {
dbUserInfo.ClientVersion = ClientVersion
}
//创建一个用户信息
wxAccount := srv.NewWXAccount(&websrv.TaskInfo{
UUID: queryKey,
}, nil, dbUserInfo.ClientVersion, dbUserInfo)
//创建一个新链接
wxConnect := wxcore.NewWXConnect(WXServer, wxAccount)
//设置用户信息
wxAccount.SetUserInfo(dbUserInfo)
return wxConnect
} else {
//创建新一个用户信息
wxAccount := srv.NewWXAccount(&websrv.TaskInfo{
UUID: queryKey,
}, nil, ClientVersion, dbUserInfo)
//创建一个新链接
wxConnect := wxcore.NewWXConnect(WXServer, wxAccount)
return wxConnect
}
}
}
// 检查实例Id是否存在 不存在创建新的链接
func checkExIdPerform(queryKey string, ClientVersion uint32, businessFunc BusinessFunc) vo.DTO {
// 判断 ClientVersion == 0
if !(int(ClientVersion) > 0) {
ClientVersion = baseinfo.ClientVersion
}
//获取实例管理器
connectMgr := WXServer.GetWXConnectMgr()
//查询的queryKey为空创建一个链接实例
if queryKey == "" {
return businessFunc(nil, true)
}
//查询该链接是否存在
iwxConnect := connectMgr.GetWXConnectByUserInfoUUID(queryKey)
if iwxConnect != nil {
//执行回调方法
return businessFunc(iwxConnect, false)
} else {
//如果链接管理器不存在该链接查询数据库是否存在
dbUserInfo := db.GetUSerInfoByUUID(queryKey)
//数据库存在该链接数据 重新实例化一个链接对象
if dbUserInfo != nil {
if !(int(dbUserInfo.ClientVersion) > 0) {
dbUserInfo.ClientVersion = ClientVersion
}
// 设置代理信息
key := fmt.Sprintf("%s%s", "wechat:Proxy:", queryKey)
exists, _ := db.Exists(key)
newModel := &req.GetLoginQrCodeModel{
Proxy: "",
Check: false,
}
if exists {
db.GETObj(key, &newModel)
}
var proxyInfo *proxynet.WXProxyInfo
if newModel.Proxy != "" {
proxyInfo = proxynet.ParseWXProxyInfo(newModel.Proxy)
} else {
proxyInfo = nil
}
//创建一个用户信息
wxAccount := srv.NewWXAccount(&websrv.TaskInfo{
UUID: queryKey,
}, proxyInfo, dbUserInfo.ClientVersion, dbUserInfo)
//创建一个新链接
wxConnect := wxcore.NewWXConnect(WXServer, wxAccount)
//设置用户信息
wxAccount.SetUserInfo(dbUserInfo)
return businessFunc(wxConnect, false)
} else {
// 设置代理信息
key := fmt.Sprintf("%s%s", "wechat:Proxy:", queryKey)
exists, _ := db.Exists(key)
newModel := &req.GetLoginQrCodeModel{
Proxy: "",
Check: false,
}
if exists {
db.GETObj(key, &newModel)
}
var proxyInfo *proxynet.WXProxyInfo
if newModel.Proxy != "" {
proxyInfo = proxynet.ParseWXProxyInfo(newModel.Proxy)
} else {
proxyInfo = nil
}
//创建新一个用户信息
wxAccount := srv.NewWXAccount(&websrv.TaskInfo{
UUID: queryKey,
}, proxyInfo, ClientVersion, dbUserInfo)
//创建一个新链接
wxConnect := wxcore.NewWXConnect(WXServer, wxAccount)
return businessFunc(wxConnect, true)
}
}
}
// 检查实例Id是否存在 链接不存在返回错误不创建新链接
func checkExIdPerformNoCreateConnect(queryKey string, businessFunc BusinessFunc) vo.DTO {
ClientVersion := baseinfo.ClientVersion
//获取实例管理器
connectMgr := WXServer.GetWXConnectMgr()
//查询的queryKey为空创建一个链接实例
if queryKey == "" {
return businessFunc(nil, true)
}
//查询该链接是否存在
iwxConnect := connectMgr.GetWXConnectByUserInfoUUID(queryKey)
if iwxConnect != nil {
//执行回调方法
return businessFunc(iwxConnect, false)
} else {
//如果链接管理器不存在该链接查询数据库是否存在
dbUserInfo := db.GetUSerInfoByUUID(queryKey)
//数据库存在该链接数据 重新实例化一个链接对象
if dbUserInfo != nil {
if !(int(dbUserInfo.ClientVersion) > 0) {
dbUserInfo.ClientVersion = ClientVersion
}
// 设置代理信息
key := fmt.Sprintf("%s%s", "wechat:Proxy:", dbUserInfo.UUID)
exists, _ := db.Exists(key)
newModel := &req.GetLoginQrCodeModel{
Proxy: "",
Check: false,
}
if exists {
db.GETObj(key, &newModel)
}
var proxyInfo *proxynet.WXProxyInfo
if newModel.Proxy != "" {
proxyInfo = proxynet.ParseWXProxyInfo(newModel.Proxy)
} else {
proxyInfo = nil
}
//创建一个用户信息
wxAccount := srv.NewWXAccount(&websrv.TaskInfo{
UUID: queryKey,
}, proxyInfo, dbUserInfo.ClientVersion, dbUserInfo)
//创建一个新链接
wxConnect := wxcore.NewWXConnect(WXServer, wxAccount)
//设置用户信息
wxAccount.SetUserInfo(dbUserInfo)
return businessFunc(wxConnect, false)
} else {
// 诊断逻辑:为什么查不到?
reason := "未知原因"
var uEntity table.UserInfoEntity
err := db.MysqlDB.Where("uuid = ?", queryKey).First(&uEntity).Error
if err != nil {
reason = fmt.Sprintf("数据库UserInfo表未找到该UUID记录: %v", err)
} else {
// UUID 存在,检查 TargetIp
if srvconfig.GlobalSetting.TargetIp != "" && uEntity.TargetIp != srvconfig.GlobalSetting.TargetIp {
reason = fmt.Sprintf("TargetIp不匹配(DB:%s, Config:%s)", uEntity.TargetIp, srvconfig.GlobalSetting.TargetIp)
} else {
// 检查 DeviceInfo
// 判断是62还是A16
key := fmt.Sprintf("%s%s", "wechat:a16DeviceInfo:", uEntity.WxId)
exists, _ := db.Exists(key)
if !exists {
var dEntity table.DeviceInfoEntity
if err := db.MysqlDB.Where("wxId = ?", uEntity.WxId).First(&dEntity).Error; err != nil {
reason = fmt.Sprintf("缺少设备信息(DeviceInfo表无记录且Redis无A16缓存), WxId: %s, Err: %v", uEntity.WxId, err)
} else {
reason = "UserInfo和DeviceInfo都存在,但GetUSerInfoByUUID返回nil,可能是其他数据完整性问题"
}
} else {
reason = "UserInfo存在且有A16缓存,但GetUSerInfoByUUID返回nil,可能是反序列化或其他问题"
}
}
}
return vo.DTO{
Code: vo.FAIL_UUID,
Data: nil,
Text: fmt.Sprintf("%s 该链接不存在!调试信息: %s", queryKey, reason),
}
}
}
}
// 获取缓存中已存在的 wx 链接
func getExistWxConnect(queryKey string, businessFunc BusinessFunc) vo.DTO {
//获取实例管理器
connectMgr := WXServer.GetWXConnectMgr()
//查询的queryKey为空创建一个链接实例
if queryKey == "" {
return businessFunc(nil, true)
}
//查询该链接是否存在
iwxConnect := connectMgr.GetWXConnectByUserInfoUUID(queryKey)
if iwxConnect != nil {
//执行回调方法
userInfo := iwxConnect.GetWXAccount().GetUserInfo()
iwxConnect.GetWXAccount().SetUserInfo(userInfo)
return businessFunc(iwxConnect, false)
}
return businessFunc(nil, true)
}
func DeepFields(ifaceType reflect.Type) []reflect.StructField {
var fields []reflect.StructField
for i := 0; i < ifaceType.NumField(); i++ {
v := ifaceType.Field(i)
if v.Anonymous && v.Type.Kind() == reflect.Struct {
fields = append(fields, DeepFields(v.Type)...)
} else {
fields = append(fields, v)
}
}
return fields
}
func StructCopy(DstStructPtr interface{}, SrcStructPtr interface{}) {
srcv := reflect.ValueOf(SrcStructPtr)
dstv := reflect.ValueOf(DstStructPtr)
srct := reflect.TypeOf(SrcStructPtr)
dstt := reflect.TypeOf(DstStructPtr)
if srct.Kind() != reflect.Ptr || dstt.Kind() != reflect.Ptr ||
srct.Elem().Kind() == reflect.Ptr || dstt.Elem().Kind() == reflect.Ptr {
panic("Fatal error:type of parameters must be Ptr of value")
}
if srcv.IsNil() || dstv.IsNil() {
panic("Fatal error:value of parameters should not be nil")
}
srcV := srcv.Elem()
dstV := dstv.Elem()
srcfields := DeepFields(reflect.ValueOf(SrcStructPtr).Elem().Type())
for _, v := range srcfields {
if v.Anonymous {
continue
}
dst := dstV.FieldByName(v.Name)
src := srcV.FieldByName(v.Name)
if !dst.IsValid() {
continue
}
if src.Type() == dst.Type() && dst.CanSet() {
dst.Set(src)
continue
}
if src.Kind() == reflect.Ptr && !src.IsNil() && src.Type().Elem() == dst.Type() {
dst.Set(src.Elem())
continue
}
if dst.Kind() == reflect.Ptr && dst.Type().Elem() == src.Type() {
dst.Set(reflect.New(src.Type()))
dst.Elem().Set(src)
continue
}
}
return
}
/*
*
获取DeviceToken
*/
func checkDeviceToken(tmpUserInfo *baseinfo.UserInfo) {
//如果是android
if strings.HasPrefix(tmpUserInfo.LoginDataInfo.LoginData, "A") {
key := fmt.Sprintf("%s%s", "wechat:deviceTokenA16:", tmpUserInfo.LoginDataInfo.UserName)
exists, _ := db.Exists(key)
if exists {
//A16存redis
trustRes := &wechat.TrustResp{}
error := db.GETObj(key, &trustRes)
if error != nil {
log.Error("redis deviceToken is error=" + error.Error())
}
tmpUserInfo.DeviceInfoA16.DeviceToken = trustRes
} else {
tmpUserInfo.DeviceInfoA16.DeviceId = []byte(tmpUserInfo.LoginDataInfo.LoginData[:15])
tmpUserInfo.DeviceInfoA16.DeviceIdStr = tmpUserInfo.LoginDataInfo.LoginData
deviceTokenRsp, err := clientsdk.SendAndroIdDeviceTokenRequest(tmpUserInfo)
if err != nil {
log.Error("android 请求 deviceTokenRequest error!")
}
//保存5天
db.SETExpirationObj(key, &deviceTokenRsp, 60*60*24*5)
tmpUserInfo.DeviceInfoA16.DeviceToken = deviceTokenRsp
}
} else if strings.HasPrefix(tmpUserInfo.LoginDataInfo.LoginData, "62") {
key := fmt.Sprintf("%s%s", "wechat:deviceTokenIos:", tmpUserInfo.LoginDataInfo.UserName)
exists, _ := db.Exists(key)
if exists {
//ios存redis
trustRes := &wechat.TrustResp{}
error := db.GETObj(key, &trustRes)
if error != nil {
log.Error("ios redis deviceTokenIos is error=" + error.Error())
}
tmpUserInfo.DeviceInfo.DeviceToken = trustRes
} else {
deviceTokenRsp, err := clientsdk.SendIosDeviceTokenRequest(tmpUserInfo)
if err != nil {
log.Error("ios 请求 deviceTokenRequest error!")
}
//保存5天
db.SETExpirationObj(key, &deviceTokenRsp, 60*60*24*5)
tmpUserInfo.DeviceInfo.DeviceToken = deviceTokenRsp
fmt.Println(deviceTokenRsp, 333)
}
}
}
+280
View File
@@ -0,0 +1,280 @@
package service
import (
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
)
// AutoRedRequestService 自动抢红包
func AutoRedRequestService(queryKey string, m req.AutoRedRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// TransferRequestService 自动接收转账处理
func TransferRequestService(queryKey string, m req.AutoTransferRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// DelayRedRequestService 延迟领取红包处理
func DelayRedRequestService(queryKey string, m req.DelayRedRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// DelayTransferRequestService 延迟接收转账处理
func DelayTransferRequestService(queryKey string, m req.DelayAutoTransferRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// KeywordAvoidanceRequestService 关键字包不抢处理
func KeywordAvoidanceRequestService(queryKey string, m req.KeywordAvoidanceRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// AutoLikeRequestService 自动点赞处理
func AutoLikeRequestService(queryKey string, m req.AutoLikeRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// AutoForwardRequestService 朋友圈跟随转发处理
func AutoForwardRequestService(queryKey string, m req.AutoForwardRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// FavoriteForwardRequestService 朋友圈收藏转发处理
func FavoriteForwardRequestService(queryKey string, m req.FavoriteForwardRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// AutoCommentRequestService 朋友圈自动评论处理
func AutoCommentRequestService(queryKey string, m req.AutoCommentRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// MomentsRequestService 定时发朋友圈处理
func MomentsRequestService(queryKey string, m req.MomentsRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// MomentsPostRequestService 发大视频朋友圈处理
func MomentsPostRequestService(queryKey string, m req.MomentsPostRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// WelcomeNewMemberRequestService 欢迎新人入群处理
func WelcomeNewMemberRequestService(queryKey string, m req.WelcomeNewMemberRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// KeywordKickRequestService 关键词自动踢人处理
func KeywordKickRequestService(queryKey string, m req.KeywordKickRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// KeywordAutoReplyRequestService 关键词自动回复处理
func KeywordAutoReplyRequestService(queryKey string, m req.KeywordAutoReplyRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// MessageForwardingRequestService 万群同步处理
func MessageForwardingRequestService(queryKey string, m req.MessageForwardingRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
// AutoApproveRequestService 自动同意好友请求
func AutoApproveRequestService(queryKey string, m req.AutoApproveRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
return vo.NewSuccessObj(nil, "设置成功!")
})
}
+124
View File
@@ -0,0 +1,124 @@
package service
import (
"strconv"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
)
// FavSyncService 同步收藏
func FavSyncService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
// 同步收藏
resp, err := reqInvoker.SendFavSyncRequestResult()
if err != nil {
return vo.NewFail("FavSyncServiceerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 获取收藏list
func GetFavListService(queryKey string, req req.FavInfoModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
// 同步收藏
resp, err := reqInvoker.SendFavSyncListRequestResult(req.KeyBuf)
if err != nil {
return vo.NewFail("FavSyncServiceerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// GetFavInfoService 获取收藏信息
func BatchDelFavItemService(queryKey string, m req.FavInfoModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
// 获取收藏消息
resp, err := reqInvoker.SendBatchDelFavItemRequestResult(m.FavId)
if err != nil {
return vo.NewFail("BatchDelFavItemServiceerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// GetFavInfoService 获取收藏信息
func GetFavInfoService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
// 获取收藏消息
resp, err := reqInvoker.SendGetFavInfoRequestResult()
if err != nil {
return vo.NewFail("GetFavInfoServiceerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// GetFavInfoService 获取收藏详细
func BatchGetFavItemService(queryKey string, m req.FavInfoModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
// 获取收藏消息
resp, err := reqInvoker.SendBatchGetFavItemRequestResult(m.FavId)
if err != nil {
return vo.NewFail("GetFavInfoServiceerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
+49
View File
@@ -0,0 +1,49 @@
package service
import (
"encoding/base64"
"strconv"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
)
// UploadAppAttachService 上传文件服务
func UploadAppAttachService(queryKey string, m req.UploadAppAttachModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
// 获取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
// 判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
// 处理文件数据
fileData := m.FileData
sFileBase := strings.Split(fileData, ",")
if len(sFileBase) > 1 {
fileData = sFileBase[1]
}
fileBytes, err := base64.StdEncoding.DecodeString(fileData)
if err != nil {
return vo.NewFail("文件解码失败:" + err.Error())
}
// 上传文件
resp, err := reqInvoker.UploadAppAttach(fileBytes)
if err != nil {
return vo.NewFail("上传文件失败:" + err.Error())
}
return vo.NewSuccessObj(resp, "上传文件成功")
})
}
+75
View File
@@ -0,0 +1,75 @@
package service
import (
"github.com/google/uuid"
"strconv"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
)
// GetFinderSearchService 视频号搜索
func GetFinderSearchService(queryKey string, req req.FinderSearchModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
// 同步收藏
resp, err := reqInvoker.SendGetFinderSearchRequest(req.Index, req.Userver, req.UserKey, uuid.New().String())
if err != nil {
return vo.NewFail("GetFinderSearchServiceerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 视频号中心
func FinderUserPrepareService(queryKey string, req req.FinderUserPrepareModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
// 同步收藏
resp, err := reqInvoker.SendFinderUserPrepareRequest(req.Userver)
if err != nil {
return vo.NewFail("FinderUserPrepareServiceerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 视频号关注取消
func FinderFollowService(queryKey string, req req.FinderFollowModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendFinderFollowRequest(req.FinderUserName, req.OpType, req.RefObjectId, req.Cook, req.Userver, req.PosterUsername)
if err != nil {
return vo.NewFail("FinderUserPrepareServiceerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
+267
View File
@@ -0,0 +1,267 @@
package service
import (
"strconv"
"sync"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
"github.com/gin-gonic/gin"
"github.com/gogf/gf/container/garray"
)
// GetContactListService 获取联系人
func GetContactListService(queryKey string, req req.GetContactListModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := connect.GetWXReqInvoker()
//分页获取好友列表
resp, err := reqInvoker.SendGetContactListPageRequest(req.CurrentWxcontactSeq, req.CurrentChatRoomContactSeq)
if err != nil {
return vo.NewSuccess(gin.H{
"errMsg": resp.GetBaseResponse().GetErrMsg().GetStr(),
"retCode": resp.GetBaseResponse().GetRet(),
}, "")
}
return vo.NewSuccess(gin.H{
"ContactList": resp,
"errMsg": resp.GetBaseResponse().GetErrMsg().GetStr(),
"retCode": resp.GetBaseResponse().GetRet(),
}, "")
})
}
// GetFriendListService 获取好友
func GetFriendListService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取二级缓存器
iwxCache := connect.GetWXCache()
if !iwxCache.IsInitFinished() {
return vo.NewSuccess(gin.H{
"IsInitFinished": false,
}, "初始化未完成!")
}
return vo.NewSuccess(gin.H{
"IsInitFinished": true,
"count": len(wxAccount.GetWXFriendList()),
"friendList": wxAccount.GetWXFriendList(),
}, "")
})
}
// GetGroupListService 获取群列表
func GetGroupListService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取二级缓存器
iwxCache := connect.GetWXCache()
if !iwxCache.IsInitFinished() {
return vo.NewSuccess(gin.H{
"IsInitFinished": false,
}, "初始化未完成!")
}
return vo.NewSuccess(gin.H{
"IsInitFinished": true,
"count": len(wxAccount.GetWXGroupList()),
"GroupList": wxAccount.GetWXGroupList(),
}, "")
})
}
// GetGHListService 获取群列表
func GetGHListService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取二级缓存器
iwxCache := connect.GetWXCache()
if !iwxCache.IsInitFinished() {
return vo.NewSuccess(gin.H{
"IsInitFinished": false,
}, "初始化未完成!")
}
return vo.NewSuccess(gin.H{
"IsInitFinished": true,
"count": len(wxAccount.GetWXGhList()),
"GhList": wxAccount.GetWXGhList(),
}, "")
})
}
// FollowGHService 关注公众号
func FollowGHService(queryKey string, m req.FollowGHModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := connect.GetWXReqInvoker()
if len(m.GHList) <= 0 {
return vo.NewFail("没有要关注公众号。")
}
respArray := garray.New(true)
wg := sync.WaitGroup{}
for _, item := range m.GHList {
wg.Add(1)
go func(m req.VerifyUserItem) {
defer wg.Done()
resp, err := reqInvoker.VerifyUserRequest(1, "", m.Scene, m.Gh, m.Gh, "")
if err != nil {
respArray.Append(gin.H{
"GH": m.Gh,
"isFollowSuccess": false,
"errMsg": err.Error(),
})
return
}
isFollowSuccess := false
if resp.GetBaseResponse().GetRet() == 0 {
isFollowSuccess = true
}
respArray.Append(gin.H{
"GH": m.Gh,
"isFollowSuccess": isFollowSuccess,
"errMsg": resp.GetBaseResponse().GetErrMsg().GetStr(),
"retCode": resp.GetBaseResponse().GetRet(),
})
}(item)
}
wg.Wait()
return vo.NewSuccessObj(respArray.Interfaces(), "")
})
}
// UploadMContactService 上传手机通讯录好友
func UploadMContactService(queryKey string, m req.UploadMContactModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := connect.GetWXReqInvoker()
if len(m.MobileList) == 0 {
return vo.NewFail("没有要上传的手机号!")
}
/*lolDeviceInfoOsType := wxAccount.GetUserInfo().DeviceInfo.OsType
lolDeviceInfoOsTypeNumber := wxAccount.GetUserInfo().DeviceInfo.OsTypeNumber
userInfo := wxAccount.GetUserInfo().DeviceInfo
if !strings.HasSuffix(userInfo.OsType, "HUAWEI android") {
userInfo.OsType = "HUAWEI android"
userInfo.OsTypeNumber = "android 9.0"
reqInvoker.SendAutoAuthRequest()
}*/
resp, err := reqInvoker.UploadMContact(m.Mobile, m.MobileList, m.Opcode)
if err != nil {
return vo.NewFail("UploadMContactService - " + err.Error())
}
/*if strings.HasSuffix(userInfo.OsType, "HUAWEI android") {
userInfo := wxAccount.GetUserInfo().DeviceInfo
userInfo.OsType = lolDeviceInfoOsType
userInfo.OsTypeNumber = lolDeviceInfoOsTypeNumber
reqInvoker.SendAutoAuthRequest()
}*/
return vo.NewSuccessObj(resp, "操作成功!")
})
}
// GetMFriendService 获取手机通讯录好友
func GetMFriendService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.GetMFriend()
if err != nil {
return vo.NewFail("GetMFriendService - " + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// VerifyUserRequestService // 添加好友 // 关注公众号 // 同意好友请求
func VerifyUserRequestService(queryKey string, m req.VerifyUserRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.VerifyUserRequest(m.OpCode, m.VerifyContent, m.Scene, m.V3, m.V4, m.ChatRoomUserName)
if err != nil {
return vo.NewFail("VerifyUserRequestService err" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
+96
View File
@@ -0,0 +1,96 @@
package service
import (
"strconv"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
"xiawan/wx/srv/wxtask"
)
// SearchContactRequestService 搜索好友
func SearchContactRequestService(queryKey string, m req.SearchContactRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendSearchContactRequest(m.OpCode, m.FromScene, m.SearchScene, m.UserName)
if err != nil {
return vo.NewFail("SearchContactRequestService err:" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 获取好友关系
func GetFriendRelationService(queryKey string, m req.GetFriendRelationModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendGetFriendRelationRequest(m.UserName)
if err != nil {
return vo.NewFail("GetFriendRelationService err:" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 查联系人详情
func GetContactContactService(queryKey string, m req.BatchGetContactModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendGetContactRequestForList(m.UserNames, m.RoomWxIDList)
if err != nil {
return vo.NewFail("SearchContactRequestService err:" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// StartFriendTaskService 启动好友任务(1:检测僵死粉 2:清理僵死粉)
func StartFriendTaskService(queryKey string, taskType int) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 创建好友任务并执行
friendTask := wxtask.NewWXFriendTask(iwxConnect)
success := friendTask.StartFriendTask(taskType)
if !success {
return vo.NewFail("启动任务失败")
}
return vo.NewSuccessObj(nil, "任务启动成功")
})
}
+566
View File
@@ -0,0 +1,566 @@
package service
import (
"strconv"
"strings"
"xiawan/wx/api/req"
"xiawan/wx/api/utils"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/protobuf/wechat"
pb "xiawan/wx/protobuf/wechat"
"xiawan/wx/srv"
"xiawan/wx/srv/wxface"
"github.com/gin-gonic/gin"
"github.com/gogo/protobuf/proto"
)
// GetChatroomQrCodeService 获取群二维码
func GetChatroomQrCodeService(queryKey string, m req.GetChatroomQrCodeModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
// 获取群二维码请求
resp, err := reqInvoker.SendGetQrCodeRequest(m.ChatRoomName, uint32(0))
if err != nil {
return vo.NewFail("GetQrCodeerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// SetChatroomAnnouncementService 设置群公告
func SetChatroomAnnouncementService(queryKey string, m req.UpdateChatroomAnnouncementModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.SetChatRoomAnnouncementRequest(m.ChatRoomName, m.Content)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccess(gin.H{
"baseResp": resp.GetBaseResponse(),
}, "")
})
}
// ConsentToJoinGroupService 同意进入群聊
func ConsentToJoinGroupService(queryKey string, m req.ConsentToJoinGroupModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.ConsentToJoinGroupRequest(m.Url)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// GetChatroomMemberDetailService 获取群成员详细
func GetChatroomMemberDetailService(queryKey string, m req.GetChatroomMemberDetailModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.GetChatroomMemberDetailRequest(m.ChatRoomName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 获取群公告
func SetGetChatRoomInfoDetailService(queryKey string, m req.GetChatroomMemberDetailModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.SetGetChatRoomInfoDetailRequest(m.ChatRoomName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 获取群详情
func GetChatRoomInfoService(queryKey string, m req.ChatRoomWxIdListModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.SendGetContactRequest(m.ChatRoomWxIdList, nil, m.ChatRoomWxIdList, true)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 设置群昵称
func SetChatroomNameService(queryKey string, m req.ChatroomNameModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
chatRoomNames := strings.Split(m.ChatRoomName, ",")
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
getContactResp, err := reqInvoker.SendGetContactRequest(chatRoomNames, nil, chatRoomNames, true)
if err != nil {
return vo.NewFail(err.Error())
}
modContact := getContactResp.ContactList[0]
modContact.NickName = &pb.SKBuiltinString{
Str: proto.String(m.Nickname),
}
buffer, err := proto.Marshal(modContact)
cmdItem := baseinfo.ModifyItem{
CmdID: uint32(27),
Len: uint32(len(buffer)),
Data: buffer,
}
var cmdItems []*baseinfo.ModifyItem
cmdItems = append(cmdItems, &cmdItem)
error := reqInvoker.SendOplogRequest(cmdItems)
if error != nil {
return vo.NewFail(error.Error())
}
return vo.NewSuccessObj(nil, "成功")
})
}
// 保存群聊
func MoveToContractService(queryKey string, m req.MoveContractModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
chatRoomNames := strings.Split(m.ChatRoomName, ",")
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
getContactResp, err := reqInvoker.SendGetContactRequest(chatRoomNames, nil, chatRoomNames, true)
if err != nil {
return vo.NewFail(err.Error())
}
modContact := getContactResp.ContactList[0]
bit := uint32(0)
if m.Val == 1 {
bit = *(modContact.BitVal) | uint32(1<<0)
} else {
bit = *(modContact.BitVal) &^ uint32(1<<0)
}
ModContactData := &pb.ModContact{
UserName: &pb.SKBuiltinString{
Str: &m.ChatRoomName,
},
NickName: &pb.SKBuiltinString{},
Pyinitial: &pb.SKBuiltinString{},
QuanPin: &pb.SKBuiltinString{},
Sex: proto.Int32(0),
ImgBuf: &pb.SKBuiltinString_{
Len: proto.Uint32(0),
},
BitMask: modContact.BitMask,
BitVal: proto.Uint32(bit),
ImgFlag: proto.Uint32(0),
Remark: &pb.SKBuiltinString{
Str: modContact.Remark.Str,
},
RemarkPyinitial: &pb.SKBuiltinString{
Str: modContact.RemarkPyinitial.Str,
},
RemarkQuanPin: &pb.SKBuiltinString{
Str: modContact.RemarkQuanPin.Str,
},
ContactType: proto.Uint32(0),
ChatRoomNotify: proto.Uint32(1),
AddContactScene: proto.Uint32(0),
ExtFlag: proto.Uint32(0),
}
buffer, err := proto.Marshal(ModContactData)
cmdItem := baseinfo.ModifyItem{
CmdID: uint32(2),
Len: uint32(len(buffer)),
Data: buffer,
}
var cmdItems []*baseinfo.ModifyItem
cmdItems = append(cmdItems, &cmdItem)
error := reqInvoker.SendOplogRequest(cmdItems)
if error != nil {
return vo.NewFail(error.Error())
}
return vo.NewSuccessObj(nil, "成功")
})
}
// QuitChatroomService 退出群聊
func QuitChatroomService(queryKey string, m req.GetChatroomMemberDetailModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.GetQuitChatroomRequest(m.ChatRoomName)
if err != nil {
return vo.NewFail(err.Error())
}
//删除缓存中群
wxAccount.RemoveWXGroup(m.ChatRoomName)
return vo.NewSuccessObj(nil, "发送退群请求成功")
})
}
// CreateChatRoomService 创建群
func CreateChatRoomService(queryKey string, m req.CreateChatRoomModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendCreateChatRoomRequest(m.TopIc, m.UserList)
if err != nil {
return vo.NewFail("创建群失败!err :" + err.Error())
}
go addGroupCache(wxAccount, resp)
return vo.NewSuccessObj(resp, "")
})
}
// 添加到缓存
func addGroupCache(wx *srv.WXAccount, chatRoom *wechat.CreateChatRoomResponse) {
if chatRoom == nil || chatRoom.ChatRoomName.GetStr() == "{}" ||
chatRoom.ChatRoomName.GetStr() == "" {
return
}
v := make([]*wechat.ChatRoomMemberInfo, 0)
for _, val := range chatRoom.MemberList {
v = append(v, &wechat.ChatRoomMemberInfo{
UserName: proto.String(val.MemberName.GetStr()),
ChatroomMemberFlag: proto.Uint32(0),
})
}
modContact := &wechat.ModContact{
UserName: chatRoom.ChatRoomName,
NickName: chatRoom.Topic,
Pyinitial: chatRoom.Pyinitial,
QuanPin: chatRoom.QuanPin,
ChatRoomOwner: &wx.GetUserInfo().WxId,
SmallHeadImgUrl: chatRoom.SmallHeadImgUrl,
ChatroomMaxCount: proto.Uint32(uint32(50000)),
NewChatroomData: &wechat.ChatRoomMemberData{
MemberCount: chatRoom.MemberCount,
ChatroomMemberList: v,
},
}
wx.AddWXGroup(modContact)
}
// InviteChatroomMembersService 邀请群成员
func InviteChatroomMembersService(queryKey string, m req.InviteChatroomMembersModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendInviteChatroomMembersRequest(m.ChatRoomName, m.UserList)
if err != nil {
return vo.NewFail("InviteChatroomMembersServiceerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// AddChatRoomMemberService 添加群成员
func AddChatRoomMemberService(queryKey string, m req.InviteChatroomMembersModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendAddChatRoomMemberRequest(m.ChatRoomName, m.UserList)
if err != nil {
return vo.NewFail("InviteChatroomMembersServiceerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 删除群成员
func SendDelDelChatRoomMemberService(queryKey string, m req.InviteChatroomMembersModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendDelDelChatRoomMemberRequest(m.ChatRoomName, m.UserList)
if err != nil {
return vo.NewFail("InviteChatroomMembersServiceerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 转让群
func SendTransferGroupOwnerService(queryKey string, m req.TransferGroupOwnerModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendTransferGroupOwnerRequest(m.ChatRoomName, m.NewOwnerUserName)
if err != nil {
return vo.NewFail("InviteChatroomMembersServiceerr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 扫码入群
func ScanIntoUrlGroupService(queryKey string, m req.ScanIntoUrlGroupModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
if len(m.Url) == 0 {
return vo.NewFail("ScanIntoUrlGroupService url == empty")
}
resp, err := reqInvoker.GetA8KeyRequest(2, 4, m.Url, baseinfo.GetA8Key)
if err != nil {
return vo.NewFail("ScanIntoUrlGroupService err:" + err.Error())
}
if resp.GetBaseResponse().GetRet() != 0 {
return vo.NewSuccess(gin.H{
"isJoinSuccess": false,
"resp": resp,
}, "进群失败")
}
body, err := utils.ScanIntoGrouppost(resp.GetFullURL())
if err != nil && strings.Index(err.Error(), "@chatroom") != -1 {
return vo.NewSuccess(gin.H{
"isJoinSuccess": true,
"body": body,
"chatroomUrl": err.Error(),
"fullUrl": resp.GetFullURL(),
"resp": resp,
}, "进群成功")
}
msg := ""
if strings.Index(body, "频繁") != -1 {
msg = ",操作太频繁,请稍后再试!"
}
if strings.Index(body, "二维码已过期") != -1 {
msg = ",二维码已过期!"
}
if strings.Index(body, "该群聊邀请已过期") != -1 {
msg = ",该群聊邀请已过期!"
}
return vo.NewSuccess(gin.H{
"isJoinSuccess": true,
"body": body,
"fullUrl": resp.GetFullURL(),
"resp": resp,
}, "进群失败"+msg)
})
}
// 设置群聊邀请开关
func SetChatroomAccessVerifyService(queryKey string, m req.SetChatroomAccessVerifyModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
v := uint32(0)
if m.Enable {
v = uint32(2)
}
req := &wechat.ModChatRoomAccessVerifyRequest{
ChatRoomName: proto.String(m.ChatRoomName),
Status: proto.Uint32(v),
}
buffer, err := proto.Marshal(req)
cmdItem := baseinfo.ModifyItem{
CmdID: 66,
Len: uint32(len(buffer)),
Data: buffer,
}
var cmdItems []*baseinfo.ModifyItem
cmdItems = append(cmdItems, &cmdItem)
err = reqInvoker.SendOplogRequest(cmdItems)
if err != nil {
return vo.NewFail("SetFunctionSwitchService err:" + err.Error())
}
return vo.NewSuccessObj("ok", "成功")
})
}
// 添加群管理员
func AddChatroomAdminService(queryKey string, m req.ChatroomMemberModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendAddChatroomAdminRequest(m.ChatRoomName, m.UserList)
if err != nil {
return vo.NewFail("SendAddChatroomAdminRequesterr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 删除群管理
func DelChatroomAdminService(queryKey string, m req.ChatroomMemberModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendDelChatroomAdminRequest(m.ChatRoomName, m.UserList)
if err != nil {
return vo.NewFail("SendDelChatroomAdminRequesterr :" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
+58
View File
@@ -0,0 +1,58 @@
package service
import (
"encoding/json"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/db"
"github.com/gin-gonic/gin"
)
// SetKeywordReplyService 设置关键词回复
func SetKeywordReplyService(queryKey string, m req.SetKeywordReplyModel) vo.DTO {
// 将关键词回复对转换为JSON字符串
pairsJSON, err := json.Marshal(m.Pairs)
if err != nil {
return vo.NewFail("序列化关键词回复对失败")
}
// 更新B002和B002Str
enable := 0
if m.Enable {
enable = 1
}
_, err = db.UpdateCommand(queryKey, "B002", enable, "")
if err != nil {
return vo.NewFail("更新关键词回复状态失败")
}
_, err = db.UpdateCommand(queryKey, "B002Str", 0, string(pairsJSON))
if err != nil {
return vo.NewFail("更新关键词回复配置失败")
}
return vo.NewSuccess(gin.H{}, "设置成功")
}
// GetKeywordReplyService 获取关键词回复配置
func GetKeywordReplyService(queryKey string) vo.DTO {
command, err := db.QueryCommand(queryKey)
if err != nil {
return vo.NewFail("获取关键词回复配置失败")
}
var pairs []req.KeywordReplyPair
if command.B002Str != "" {
err = json.Unmarshal([]byte(command.B002Str), &pairs)
if err != nil {
return vo.NewFail("解析关键词回复配置失败")
}
}
return vo.NewSuccessObj(map[string]interface{}{
"enable": command.B002 == 1,
"pairs": pairs,
}, "获取成功")
}
+167
View File
@@ -0,0 +1,167 @@
package service
import (
"strconv"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
"github.com/lunny/log"
)
// GetContactLabelListRequestService 获取标签列表
func GetContactLabelListRequestService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendGetContactLabelListRequest(true)
if err != nil {
return vo.NewFail("GetContactLabelListRequestService" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// AddContactLabelRequestService 添加标签
func AddContactLabelRequestService(queryKey string, m req.LabelModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
if len(m.LabelNameList) == 0 {
return vo.NewFail("没有要添加的标签")
}
resp, err := reqInvoker.SendAddContactLabelRequest(m.LabelNameList, true)
if err != nil {
return vo.NewFail("AddContactLabelRequestService" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// DelContactLabelRequestService 删除标签
func DelContactLabelRequestService(queryKey string, m req.LabelModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendDelContactLabelRequest(m.LabelId)
if err != nil {
return vo.NewFail("SendDelContactLabelRequestService" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// ModifyLabelRequestService 修改标签
func ModifyLabelRequestService(queryKey string, m req.LabelModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendModifyLabelRequest(m.UserLabelList)
if err != nil {
return vo.NewFail("SendDelContactLabelRequestService" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 获取标签下好友
func GetWXFriendListByLabelIDService(queryKey string, req req.LabelModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
retList := make([]string, 0)
// 遍历好友 获取对应标签的好友列表
i, _ := strconv.Atoi(req.LabelId)
//重新拉取好友列表
if len(wxAccount.FriendMap) <= 0 {
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
var CurrentWxcontactSeq = uint32(0)
var CurrentChatRoomContactSeq = uint32(0)
for true {
resp, err := reqInvoker.SendGetContactListPageRequest(CurrentWxcontactSeq, CurrentChatRoomContactSeq)
if err != nil {
log.Error("分页请求获取联系人出现error")
break
}
if resp.BaseResponse.GetRet() != 0 {
log.Error("分页请求获取联系人出现error=0")
break
}
CurrentWxcontactSeq = resp.GetCurrentWxcontactSeq()
CurrentChatRoomContactSeq = resp.GetCurrentChatRoomContactSeq()
if len(resp.GetContactUsernameList()) <= 0 {
break
}
//批量获取联系人
response, error := reqInvoker.SendGetContactRequestForList(resp.GetContactUsernameList(), nil)
if error != nil {
log.Error("获取详情出现error")
}
if response.BaseResponse.GetRet() != 0 {
log.Error("获取详情出现error=0")
break
}
for _, v := range response.GetContactList() {
wxAccount.AddWXFriendContact(v)
}
}
}
for userName, modContact := range wxAccount.FriendMap {
if wxAccount.ContainsLabel(modContact.GetLabelIdlist(), uint32(i)) {
retList = append(retList, userName)
}
}
return vo.NewSuccessObj(retList, "")
})
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+77
View File
@@ -0,0 +1,77 @@
package service
import (
"strconv"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/db"
"xiawan/wx/srv/wxface"
)
// GetMyQrCodeService 获取个人二维码
func GetMyQrCodeService(queryKey string, m req.GetQrCodeModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
wxid := wxAccount.GetUserInfo().WxId
resp, err := reqInvoker.SendGetQrCodeRequest(wxid, m.Style)
if err != nil {
return vo.NewFail("GetQrCodeService err:" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 查看附近的人
func GetPeopleNearbyService(queryKey string, m req.PeopleNearbyModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendGetPeopleNearbyResultRequest(m.Longitude, m.Latitude)
if err != nil {
return vo.NewFail("GetPeopleNearbyService" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 修改指令状态
func UpdateCmdStatusService(queryKey string, m req.ModifyCmdStatusModelNew) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(wxConn wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := wxConn.GetWXAccount()
cache := wxConn.GetWXCache()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !wxConn.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
db.UpdateCommand(queryKey, m.Key, m.Value, m.ValueStr)
query, err := db.QueryCommand(queryKey)
if err != nil {
return vo.NewFail("操作失败!")
}
cache.SendUsageByText()
return vo.NewSuccessObj(query, "操作成功!")
})
}
+226
View File
@@ -0,0 +1,226 @@
package service
import (
"encoding/json"
"strconv"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
)
// 获取银行卡信息
func GetBandCardListService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
tmpReqItem := &baseinfo.TenPayReqItem{}
tmpReqItem.CgiCMD = 72
tmpReqItem.ReqText = ""
tenPayResp, err := reqInvoker.SendBandCardRequest(tmpReqItem)
if err != nil {
return vo.NewFail("GetBandCardListService err:" + err.Error())
}
// 解析响应
retResp := &baseinfo.TenPayResp{}
retText := tenPayResp.GetRetText().GetBuffer()
err = json.Unmarshal(retText, retResp)
if err != nil {
return vo.NewFail("查询QB信息失败")
}
return vo.NewSuccessObj(retResp, "")
})
}
// 生成自定义二维码
func GeneratePayQCodeService(queryKey string, req req.GeneratePayQCodeModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
var tenpayUrl = "delay_confirm_flag=0&desc=" + req.Name + "&fee=" + req.Money + "&fee_type=CNY&pay_scene=31&receiver_name=" + wxAccount.GetUserInfo().WxId + "&scene=31&transfer_scene=2"
wcPaySign, err := clientsdk.TenPaySignDes3(tenpayUrl, "%^&*Tenpay!@#$")
if err != nil {
return vo.NewFail("no")
}
tenpayUrl += "&WCPaySign=" + wcPaySign
tmpReqItem := &baseinfo.TenPayReqItem{}
tmpReqItem.CgiCMD = 94
tmpReqItem.ReqText = tenpayUrl
tenPayResp, err := reqInvoker.SendTenPayRequest(tmpReqItem)
if err != nil {
return vo.NewFail("GetBandCardListService err:" + err.Error())
}
// 解析响应
retResp := &baseinfo.GeneratePayQCodeResp{}
retText := tenPayResp.GetRetText().GetBuffer()
err = json.Unmarshal(retText, retResp)
if err != nil {
return vo.NewFail("查询QB信息失败")
}
return vo.NewSuccessObj(retResp, "")
})
}
// CollectMoneyService 确认收款
func CollectMoneyService(queryKey string, req req.CollectmoneyModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
tenpayUrl := "invalid_time=" + req.InvalidTime + "&op=confirm&total_fee=0&trans_id=" + req.TransFerId + "&transaction_id=" + req.TransactionId + "&username=" + req.ToUserName
wcPaySign, err := clientsdk.TenPaySignDes3(tenpayUrl, "%^&*Tenpay!@#$")
if err != nil {
return vo.NewFail("no")
}
tenpayUrl += "&WCPaySign=" + wcPaySign
tmpReqItem := &baseinfo.TenPayReqItem{}
tmpReqItem.CgiCMD = 85
tmpReqItem.ReqText = tenpayUrl
tenPayResp, err := reqInvoker.SendTenPayRequest(tmpReqItem)
if err != nil {
return vo.NewFail("CollectMoneyService err:" + err.Error())
}
return vo.NewSuccessObj(tenPayResp, "")
})
}
// 拆红包
func OpenRedEnvelopesService(queryKey string, req baseinfo.HongBaoItem) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
rsp, err := reqInvoker.SendOpenRedEnvelopesRequest(&req)
if err != nil {
return vo.NewFail("CollectMoneyService err:" + err.Error())
}
return vo.NewSuccessObj(rsp, "")
})
}
// 创建红包
func WXCreateRedPacketService(queryKey string, req baseinfo.RedPacket) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
rsp, err := reqInvoker.SendWXCreateRedPacketRequest(&req)
if err != nil {
return vo.NewFail("CollectMoneyService err:" + err.Error())
}
return vo.NewSuccessObj(rsp, "")
})
}
// 查看红包详情
func QueryRedEnvelopesDetailService(queryKey string, req baseinfo.HongBaoItem) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
rsp, err := reqInvoker.SendRedEnvelopesDetailRequest(&req)
if err != nil {
return vo.NewFail("QueryRedEnvelopesDetailService err:" + err.Error())
}
return vo.NewSuccessObj(string(rsp.GetRetText().GetBuffer()), "")
})
}
// 查看红包领取列表
func GetRedPacketListService(queryKey string, req baseinfo.GetRedPacketList) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
rsp, err := reqInvoker.SendGetRedPacketListRequest(&req)
if err != nil {
return vo.NewFail("QueryRedEnvelopesDetailService err:" + err.Error())
}
return vo.NewSuccessObj(string(rsp.GetRetText().GetBuffer()), "")
})
}
// CreatePreTransferService 创建转账
func CreatePreTransferService(queryKey string, req *req.CreatePreTransfer) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
tenPayResp, err := reqInvoker.SendCreatePreTransferRequest(req)
if err != nil {
return vo.NewFail("CreatePreTransferService err:" + err.Error())
}
return vo.NewSuccessObj(tenPayResp, "")
})
}
// ConfirmPreTransferService 确认转账
func ConfirmPreTransferService(queryKey string, req *req.ConfirmPreTransfer) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
tenPayResp, err := reqInvoker.SendConfirmPreTransferRequest(req)
if err != nil {
return vo.NewFail("ConfirmPreTransferService err:" + err.Error())
}
return vo.NewSuccessObj(tenPayResp, "")
})
}
+41
View File
@@ -0,0 +1,41 @@
package service
import (
"xiawan/wx/db/table"
)
// GetProxyMappingList 获取代理映射列表
func GetProxyMappingList() ([]table.ProxyMapping, error) {
// 固定返回代理映射列表
list := []table.ProxyMapping{
{ProxyNumber: "1", ProxyValue: "辽宁"},
{ProxyNumber: "2", ProxyValue: "上海"},
{ProxyNumber: "3", ProxyValue: "江苏"},
{ProxyNumber: "4", ProxyValue: "浙江"},
{ProxyNumber: "5", ProxyValue: "安徽"},
{ProxyNumber: "6", ProxyValue: "福建"},
{ProxyNumber: "7", ProxyValue: "江西"},
{ProxyNumber: "8", ProxyValue: "山东"},
{ProxyNumber: "9", ProxyValue: "河南"},
{ProxyNumber: "10", ProxyValue: "湖北"},
{ProxyNumber: "11", ProxyValue: "湖南"},
{ProxyNumber: "12", ProxyValue: "北京"},
{ProxyNumber: "13", ProxyValue: "天津"},
{ProxyNumber: "14", ProxyValue: "河北"},
{ProxyNumber: "15", ProxyValue: "山西"},
{ProxyNumber: "16", ProxyValue: "内蒙古"},
{ProxyNumber: "17", ProxyValue: "广东"},
{ProxyNumber: "18", ProxyValue: "广西"},
{ProxyNumber: "19", ProxyValue: "海南"},
{ProxyNumber: "20", ProxyValue: "陕西"},
{ProxyNumber: "21", ProxyValue: "甘肃"},
{ProxyNumber: "22", ProxyValue: "青海"},
{ProxyNumber: "23", ProxyValue: "宁夏"},
{ProxyNumber: "24", ProxyValue: "新疆"},
{ProxyNumber: "25", ProxyValue: "重庆"},
{ProxyNumber: "26", ProxyValue: "四川"},
{ProxyNumber: "27", ProxyValue: "贵州"},
{ProxyNumber: "28", ProxyValue: "云南"},
}
return list, nil
}
+495
View File
@@ -0,0 +1,495 @@
package service
import (
"github.com/gogo/protobuf/proto"
"strconv"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/protobuf/wechat"
"xiawan/wx/srv/wxface"
)
func QWContactService(queryKey string, m *req.QWContactModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendQWContactRequest(m.ToUserName, m.ChatRoom, m.T)
if err != nil {
return vo.NewFail("查询失败")
}
return vo.NewSuccessObj(resp, "")
})
}
// 提取全部的企业通寻录
func QWSyncContactService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendQWSyncContactRequest()
if err != nil {
return vo.NewFail("查询失败")
}
return vo.NewSuccessObj(resp, "")
})
}
// 备注企业 wxid
func QWRemarkService(queryKey string, m *req.QWRemarkModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
req := &wechat.QYModChatRoomTopicRequest{
G: proto.String(m.ToUserName),
P: proto.String(m.Name),
}
buffer, err := proto.Marshal(req)
err = reqInvoker.SendQWOpLogRequest(3, buffer)
if err != nil {
return vo.NewFail("失败")
}
return vo.NewSuccessObj("ok", "操作成功")
})
}
// 创建企业微信
func QWCreateChatRoomService(queryKey string, m *req.QWCreateModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendQWCreateChatRoomRequest(m.ToUserName)
if err != nil {
return vo.NewFail("失败")
}
return vo.NewSuccessObj(resp, "操作成功")
})
}
// 搜手机或企业对外名片链接提取验证
func QWSearchContactService(queryKey string, m req.SearchContactModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.SendQWSearchContactRequest(m.Tg, m.FromScene, m.UserName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 向企业微信打招呼
func QWApplyAddContactService(queryKey string, m req.QWApplyAddContactModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendQWApplyAddContactRequest(m.UserName, m.V1, m.Content)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj("ok", "操作成功")
})
}
// 单向加企业微信
func QWAddContactService(queryKey string, m req.QWApplyAddContactModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendQWAddContactRequest(m.UserName, m.V1, m.Content)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj("ok", "操作成功")
})
}
// 提取全部企业微信群
func QWSyncChatRoomService(queryKey string, m req.QWSyncChatRoomModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWSyncChatRoomRequest(m.Key)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 转让企业群
func QWChatRoomTransferOwnerService(queryKey string, m req.QWChatRoomTransferOwnerModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWChatRoomTransferOwnerRequest(m.ChatRoomName, m.ToUserName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 直接拉好友进群
func QWAddChatRoomMemberService(queryKey string, m req.QWAddChatRoomMemberModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWAddChatRoomMemberRequest(m.ChatRoomName, m.ToUserName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 发送群邀请链接
func QWInviteChatRoomMemberService(queryKey string, m req.QWAddChatRoomMemberModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWInviteChatRoomMemberRequest(m.ChatRoomName, m.ToUserName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 删除企业群成员
func QWDelChatRoomMemberService(queryKey string, m req.QWAddChatRoomMemberModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWDelChatRoomMemberRequest(m.ChatRoomName, m.ToUserName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 提取企业群全部成员
func QWGetChatRoomMemberService(queryKey string, m req.QWAddChatRoomMemberModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWGetChatRoomMemberRequest(m.ChatRoomName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// -提取企业群名称公告设定等信息
func QWGetChatroomInfoService(queryKey string, m req.QWAddChatRoomMemberModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWGetChatroomInfoRequest(m.ChatRoomName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 提取企业群二维码
func QWGetChatRoomQRService(queryKey string, m req.QWAddChatRoomMemberModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWGetChatRoomQRRequest(m.ChatRoomName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 增加企业管理员
func QWAppointChatRoomAdminService(queryKey string, m req.QWAddChatRoomMemberModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWAppointChatRoomAdminRequest(m.ChatRoomName, m.ToUserName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 移除群管理
func QWDelChatRoomAdminService(queryKey string, m req.QWAddChatRoomMemberModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWDelChatRoomAdminRequest(m.ChatRoomName, m.ToUserName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 同意进企业群
func QWAcceptChatRoomRequestService(queryKey string, m req.QWAcceptChatRoomModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWAcceptChatRoomRequest(m.Link, m.Opcode)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 设定企业群
func QWAdminAcceptJoinChatRoomSetService(queryKey string, m req.QWAdminAcceptJoinChatRoomSetModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWAdminAcceptJoinChatRoomSetRequest(m.ChatRoomName, m.P)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 修改企业群名称
func QWModChatRoomNameService(queryKey string, m req.QWModChatRoomNameModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWModChatRoomNameRequest(m.ChatRoomName, m.Name)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 修改成员在群中呢称
func QWModChatRoomMemberNickService(queryKey string, m req.QWModChatRoomNameModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWModChatRoomMemberNickRequest(m.ChatRoomName, m.Name)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 发布企业群公告
func QWChatRoomAnnounceService(queryKey string, m req.QWModChatRoomNameModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWChatRoomAnnounceRequest(m.ChatRoomName, m.Name)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
// 删除企业群
func SendQWDelChatRoomService(queryKey string, m req.QWModChatRoomNameModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
// 获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
rsp, err := reqInvoker.SendQWDelChatRoomRequest(m.ChatRoomName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(rsp, "操作成功")
})
}
+641
View File
@@ -0,0 +1,641 @@
package service
import (
"encoding/base64"
"fmt"
"log"
"regexp"
"strconv"
"strings"
"sync"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/clientsdk/baseutils"
"xiawan/wx/clientsdk/xmltool"
"xiawan/wx/protobuf/proto_ref"
"xiawan/wx/srv/defines"
"xiawan/wx/srv/wxcore"
"xiawan/wx/srv/wxface"
"github.com/gin-gonic/gin"
"github.com/gogf/gf/container/garray"
_ "github.com/gogf/gf/container/garray"
)
// SendSnsTimeLineRequestService 获取朋友圈主页
func SendSnsTimeLineRequestService(queryKey string, m req.GetSnsInfoModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
//获取朋友圈主页
resp, err := reqInvoker.SendSnsTimeLineRequestResult(m.FirstPageMD5, m.MaxID)
if err != nil {
return vo.NewFail("SendSnsTimeLineRequestService" + err.Error())
}
ObjectList := resp.GetObjectList()
if ObjectList != nil && len(ObjectList) > 0 {
for _, v := range ObjectList {
objectDesc := v.GetObjectDesc()
if objectDesc == nil {
continue
}
if objectDesc.GetBuffer() != nil {
v.SetObjectDescStr(objectDesc.GetBuffer())
}
}
}
return vo.NewSuccessObj(resp, "")
})
}
// 通过id获朋友圈详情
func SendSnsObjectDetailByIdService(queryKey string, m req.GetIdDetailModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
//获取好友朋友圈主页
id, _ := strconv.ParseUint(m.Id, 0, 64)
resp, err := reqInvoker.SendSnsObjectDetailRequest(id)
if err != nil {
return vo.NewFail("SendSnsTimeLineRequestService" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// SendSnsUserPageRequestService 获取指定人朋友圈
func SendSnsUserPageRequestService(queryKey string, m req.GetSnsInfoModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
//获取好友朋友圈主页
resp, err := reqInvoker.SendSnsUserPageRequest(m.UserName, m.FirstPageMD5, m.MaxID, true)
if err != nil {
return vo.NewFail("SendSnsUserPageRequestService" + err.Error())
}
count := resp.GetObjectCount()
if count > 0 {
snsObjList := resp.ObjectList
for _, snsObject := range snsObjList {
objDesc := snsObject.ObjectDesc
tmpTimeLineObj := &proto_ref.TimelineObject{}
// 反序列化 TimeLineXML
err := xmltool.Unmarshal(objDesc.Buffer, &tmpTimeLineObj)
if err != nil {
log.Println("GetSnsSyncService Parse TimeLineXML - xml.Unmarshal err:", err)
}
snsObject.ObjectInfo = tmpTimeLineObj
//snsObject.ObjectDesc = nil
}
}
return vo.NewSuccessObj(resp, "")
})
}
// 转发收藏朋友圈
func SendFavItemCircleService(queryKey string, m req.SendFavItemCircle) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
// 获取指定的朋友圈
objIDString := baseutils.GetNumberString(m.SourceID)
snsObjID, _ := strconv.ParseUint(objIDString, 10, 64)
snsObject, err := reqInvoker.SendSnsObjectDetailRequest(snsObjID)
if err != nil {
baseutils.PrintLog("WXSnsTransTask.doFavTask - SendSnsObjectDetailRequest err: " + err.Error())
return vo.NewFail("操作失败!" + err.Error())
}
//放入消息队例
currentTaskMgr := iwxConnect.GetWXTaskMgr()
taskMgr, _ := currentTaskMgr.(*wxcore.WXTaskMgr)
currentSnsTransTask := taskMgr.GetSnsTransTask()
// 转发朋友圈
err = currentSnsTransTask.DoSnsTransTask(snsObject, defines.MTaskTypeFavTrans, m.BlackList, m.Location, m.LocationVal)
if err == nil {
// 如果转发收藏成功则删除
reqInvoker.SendBatchDelFavItemRequest(m.FavItemID)
return vo.NewSuccessObj("ok", "操作成功!")
}
return vo.NewFail("操作失败!" + err.Error())
})
}
// 一键转发朋友圈
func SendOneIdCircleService(queryKey string, m req.GetIdDetailModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
// 获取指定的朋友圈
snsObjID, _ := strconv.ParseUint(m.Id, 10, 64)
snsObject, err := reqInvoker.SendSnsObjectDetailRequest(snsObjID)
if err != nil {
baseutils.PrintLog("WXSnsTransTask.doFavTask - SendSnsObjectDetailRequest err: " + err.Error())
return vo.NewFail("操作失败!" + err.Error())
}
//放入消息队例
currentTaskMgr := iwxConnect.GetWXTaskMgr()
taskMgr, _ := currentTaskMgr.(*wxcore.WXTaskMgr)
currentSnsTransTask := taskMgr.GetSnsTransTask()
// 转发朋友圈
err = currentSnsTransTask.DoSnsTransTask(snsObject, defines.MTaskTypeFavTrans, m.BlackList, m.Location, m.LocationVal)
if err == nil {
// 如果转发收藏成功则删除
return vo.NewSuccessObj("ok", "转发成功!")
}
return vo.NewFail("操作失败!" + err.Error())
})
}
// 获取收藏朋友圈详情
func GetCollectCircleService(queryKey string, m req.SendFavItemCircle) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
// 获取指定的朋友圈
objIDString := baseutils.GetNumberString(m.SourceID)
snsObjID, _ := strconv.ParseUint(objIDString, 10, 64)
snsObject, err := reqInvoker.SendSnsObjectDetailRequest(snsObjID)
if err != nil {
baseutils.PrintLog("WXSnsTransTask.doFavTask - SendSnsObjectDetailRequest err: " + err.Error())
return vo.NewFail("操作失败!" + err.Error())
}
return vo.NewSuccessObj(snsObject, "操作成功!")
})
}
// SetBackgroundImageApi 设置朋友圈图片
func SetBackgroundImageService(queryKey string, m req.SetBackgroundImageModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//习近平
content := fmt.Sprintf("<TimelineObject><id><![CDATA[0]]></id><username><![CDATA[%s]]></username><createTime><![CDATA[0]]></createTime><contentDescShowType>0</contentDescShowType><contentDescScene>0</contentDescScene><private><![CDATA[0]]></private><contentDesc></contentDesc><contentattr><![CDATA[0]]></contentattr><sourceUserName></sourceUserName><sourceNickName></sourceNickName><statisticsData></statisticsData><weappInfo><appUserName></appUserName><pagePath></pagePath></weappInfo><canvasInfoXml></canvasInfoXml><location poiClickableStatus=\"0\" poiClassifyId=\"\" poiScale=\"0\" longitude=\"0.0\" city=\"\" poiName=\"\" latitude=\"0.0\" poiClassifyType=\"0\" poiAddress=\"\" ></location><ContentObject><contentStyle><![CDATA[7]]></contentStyle><contentSubStyle><![CDATA[0]]></contentSubStyle><title>&#x0A;&#x0A;&#x0A;</title><description></description><contentUrl></contentUrl><mediaList><media><id><![CDATA[0]]></id><type><![CDATA[2]]></type><title></title><description></description><private><![CDATA[0]]></private><url type=\"1\" ><![CDATA[%s]]></url><thumb type=\"1\" ><![CDATA[%s]]></thumb>", wxAccount.GetUserInfo().WxId, m.Url, m.Url)
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
snsPostItem := baseinfo.SnsPostItem{
Content: content,
Xml: true,
MediaList: make([]*baseinfo.SnsMediaItem, 0),
}
resp, err := reqInvoker.SendSnsPostRequestNew(&snsPostItem)
if err != nil {
return vo.NewFail("操作失败!" + err.Error())
}
return vo.NewSuccessObj(resp, "操作成功!")
})
}
// 下载视频
func DownloadMediaService(queryKey string, req req.DownloadMediaModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
tmpEncKey, _ := strconv.Atoi(req.Key)
videoData, err := reqInvoker.SendCdnSnsVideoDownloadReuqest(uint64(tmpEncKey), req.URL)
if err != nil {
return vo.NewFail("下载失败!" + err.Error())
}
return vo.NewSuccessObj(videoData, "下载成功!")
})
}
// 设置朋友圈可见天数
func SetFriendCircleDaysService(queryKey string, postItem req.SetFriendCircleDaysModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SetFriendCircleDays(&postItem)
if err != nil {
return vo.NewFail("设置朋友圈可见天数失败!" + err.Error())
}
return vo.NewSuccessObj("ok", "设置朋友圈可见天数成功!")
})
}
// SendFriendCircle发送朋友圈
func SendFriendCircleService(queryKey string, postItem req.SnsPostItemModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
snsPostItem := baseinfo.SnsPostItem{
MediaList: make([]*baseinfo.SnsMediaItem, 0),
}
//对结构体进行复制
StructCopy(&snsPostItem, &postItem)
if postItem.LocationInfo != nil {
snsPostItem.LocationInfo = (*baseinfo.SnsLocationInfo)(postItem.LocationInfo)
}
if len(postItem.MediaList) > 0 {
for _, item := range postItem.MediaList {
var snsMediaItem baseinfo.SnsMediaItem
StructCopy(&snsMediaItem, item)
snsPostItem.MediaList = append(snsPostItem.MediaList, &snsMediaItem)
}
}
resp, err := reqInvoker.SendSnsPostRequestNew(&snsPostItem)
if err != nil {
return vo.NewFail("发送朋友圈失败!" + err.Error())
}
return vo.NewSuccessObj(resp, "发送朋友圈成功!")
})
}
// SendFriendCircleByXMlService 根据XML发送朋友圈
func SendFriendCircleByXMlService(queryKey string, postItem baseinfo.TimelineObject) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendSnsPostRequestByXML(&postItem, []string{})
if err != nil {
return vo.NewFail("发送朋友圈失败!" + err.Error())
}
return vo.NewSuccessObj(nil, "发送朋友圈成功!")
})
}
// UploadFriendCircleImagesService 上传朋友圈图片
func UploadFriendCircleImageService(queryKey string, m req.UploadFriendCircleModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
uploadRespArray := garray.New(true)
wg := new(sync.WaitGroup)
if len(m.ImageDataList) <= 0 {
return vo.NewFail("没有要上传的图片!")
}
for _, imageData := range m.ImageDataList {
sImageBase := strings.Split(imageData, ",")
if len(sImageBase) > 1 {
imageData = sImageBase[1]
}
imageBuffer, _ := base64.StdEncoding.DecodeString(imageData)
//生成一个Md5
imageId := baseutils.Md5ValueByte(imageBuffer, false)
fmt.Println(imageId)
//查询数据库是否存在该Id
//上传图片
wg.Add(1)
go func(image []byte, id string) {
defer wg.Done()
upImageResp, err := reqInvoker.SendCdnSnsUploadImageReuqest(image)
if err != nil {
uploadRespArray.Append(gin.H{
"imageId": imageId,
"errMgs": err.Error(),
})
} else {
uploadRespArray.Append(gin.H{
"imageId": imageId,
"resp": upImageResp,
})
}
}(imageBuffer, imageId)
}
wg.Wait()
return vo.NewSuccessObj(uploadRespArray.Interfaces(), "")
})
}
// SendSnsObjectOpRequestService 朋友圈操作
func SendSnsObjectOpRequestService(queryKey string, m req.SendSnsObjectOpRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
if len(m.SnsObjectOpList) <= 0 {
return vo.NewFail("没有要操作的Id")
}
opItems := make([]*baseinfo.SnsObjectOpItem, 0)
for _, item := range m.SnsObjectOpList {
var opItem baseinfo.SnsObjectOpItem
StructCopy(&opItem, &item)
opItems = append(opItems, &opItem)
}
resp, err := reqInvoker.SendSnsObjectOpRequest(opItems)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// SendSnsCommentRequestService 点赞/评论
func SendSnsCommentRequestService(queryKey string, m req.SendSnsCommentRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
respArray := garray.New(true)
wg := new(sync.WaitGroup)
if len(m.SnsCommentList) <= 0 {
return vo.NewFail("没有数据!")
}
for _, item := range m.SnsCommentList {
commItem := &baseinfo.SnsCommentItem{}
if item.OpType == baseinfo.MMSnsCommentTypeLike { //点赞
id, _ := strconv.ParseUint(item.ItemID, 0, 64)
commItem = clientsdk.CreateSnsCommentLikeItem(id, item.ToUserName)
} else if item.OpType == baseinfo.MMSnsCommentTypeComment { // 评论
//oldDevieType:=wxAccount.GetUserInfo().DeviceInfo.OsType
//wxAccount.GetUserInfo().DeviceInfo.OsType="wechat"
//_=reqInvoker.SendAutoAuthRequest()
/*defer func() {
wxAccount.GetUserInfo().DeviceInfo.OsType=oldDevieType
_=reqInvoker.SendAutoAuthRequest()
}()*/
//评论能用
if m.Tx {
item.Content = item.Content + "\n\n~~~~~~~~~~\n每日一练习,\n大大有进步"
}
id, _ := strconv.ParseUint(item.ItemID, 0, 64)
commItem = clientsdk.CreateSnsCommentItem(id, item.ToUserName, item.Content, nil)
commItem.ReplyItem = &baseinfo.ReplyCommentItem{}
StructCopy(commItem.ReplyItem, &item.ReplyItem)
}
wg.Add(1)
go func(commentItem *baseinfo.SnsCommentItem) {
defer wg.Done()
err := reqInvoker.SendSnsCommentRequest(commentItem)
if err != nil {
respArray.Append(gin.H{
"data": commentItem,
"isCommentSuccess": false,
"errMsg": err.Error(),
})
} else {
respArray.Append(gin.H{
"data": commentItem,
"isCommentSuccess": true,
"errMsg": "",
})
}
}(commItem)
}
wg.Wait()
return vo.NewSuccessObj(respArray.Interfaces(), "")
})
}
// GetSnsSyncService 同步朋友圈
func GetSnsSyncService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := connect.GetWXAccount()
userInfo := wxAccount.GetUserInfo()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := connect.GetWXReqInvoker()
snsSyncResp, err := reqInvoker.SendSnsSyncRequest(false)
if err != nil {
return vo.NewFail("GetSnsSyncService err:" + err.Error())
}
// 如果请求失败
retCode := snsSyncResp.GetBaseResponse().GetRet()
errMsg := snsSyncResp.GetBaseResponse().GetErrMsg().GetStr()
if retCode != baseinfo.MMOk {
return vo.NewFail("WXSnsSyncRouter err:" + strconv.Itoa(int(retCode)) + " msg = " + errMsg)
}
// 更新 key
userInfo.SnsSyncKey = snsSyncResp.GetKeyBuf().GetBuffer()
// 遍历同步到的朋友圈
tmpCmdList := snsSyncResp.GetCmdList()
tmpCount := tmpCmdList.GetCount()
// 定义正则表达式,用于匹配<TimelineObject>...</TimelineObject>之间的内容
re := regexp.MustCompile(`<TimelineObject>.*?</TimelineObject>`)
snsItems := make([]baseinfo.SnsSyncItem, 0)
if tmpCount > 0 {
itemList := snsSyncResp.GetCmdList().GetItemList()
for _, item := range itemList {
snsItem := baseinfo.SnsSyncItem{
CmdId: item.GetCmdId(),
}
tmpTimeLineObj := &baseinfo.TimelineObject{}
tmpTimeLineData := re.FindString(string(item.CmdBuf.Data))
// 反序列化 TimeLineXML
err := xmltool.Unmarshal([]byte(tmpTimeLineData), &tmpTimeLineObj)
if err != nil {
log.Println("GetSnsSyncService Parse TimeLineXML - xml.Unmarshal err:", err)
}
snsItem.TimelineInfo = *tmpTimeLineObj
snsItems = append(snsItems, snsItem)
}
}
resp := baseinfo.SnsSyncResp{
ContinueFlag: snsSyncResp.GetContinueFlag(),
SnsSyncKey: userInfo.SnsSyncKey,
SnsCount: tmpCount,
SnsItems: snsItems,
}
return vo.NewSuccessObj(resp, "")
})
}
// CdnSnsVideoUploadService 上传CDN朋友圈视频服务
func CdnSnsVideoUploadService(queryKey string, m req.CdnSnsVideoUploadModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
//取基本信息
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
//获取请求管理器
reqInvoker := iwxConnect.GetWXReqInvoker()
// 解码base64数据
videoData, err := base64.StdEncoding.DecodeString(m.VideoData)
if err != nil {
return vo.NewFail("视频数据解析失败!" + err.Error())
}
thumbData, err := base64.StdEncoding.DecodeString(m.ThumbData)
if err != nil {
return vo.NewFail("缩略图数据解析失败!" + err.Error())
}
//上传朋友圈视频
resp, err := reqInvoker.SendCdnSnsVideoUploadReuqest(videoData, thumbData)
if err != nil {
return vo.NewFail("上传朋友圈视频失败!" + err.Error())
}
return vo.NewSuccessObj(resp, "上传朋友圈视频成功")
})
}
+552
View File
@@ -0,0 +1,552 @@
package service
import (
"encoding/hex"
"fmt"
"strconv"
"time"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/clientsdk/baseutils"
"xiawan/wx/clientsdk/proxynet"
"xiawan/wx/db"
"xiawan/wx/db/table"
"xiawan/wx/protobuf/wechat"
"xiawan/wx/srv/wxcore"
"xiawan/wx/srv/wxface"
"github.com/gin-gonic/gin"
"github.com/gogo/protobuf/proto"
)
// logOutService 退出登录
func LogOutService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
// 在退出登录前,先清理WebSocket连接
currentTaskMgr := connect.GetWXTaskMgr()
if taskMgr, ok := currentTaskMgr.(*wxcore.WXTaskMgr); ok {
wsTask := taskMgr.SocketMsgTask
userUUID := wxAccount.GetUserInfo().UUID
// 清理WebSocket连接
existingConn := wsTask.GetWebSocket(userUUID)
if existingConn != nil {
fmt.Println("退出登录时清理WebSocket连接:", userUUID)
existingConn.Close()
wsTask.DeleteWebSocket(userUUID)
}
// 禁用WebSocket功能
wsTask.SetWebSocketEnabled(false)
}
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendLogoutRequest()
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccess(gin.H{}, "退出成功!")
})
}
// SendDelContactService 删除好友
func SendDelContactService(queryKey string, m req.DelContactModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendDelContactRequest(m.DelUserName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccess(gin.H{}, "删除成功!")
})
}
// OnlineInfoService 获取登录设备信息
func OnlineInfoService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendOnlineInfo()
if err != nil {
return vo.NewFail(err.Error())
}
deviceInfoList := make([]gin.H, 0)
for _, deviceInfo := range resp.GetOnlineList() {
deviceInfoList = append(deviceInfoList, gin.H{
"deviceType": deviceInfo.GetDeviceType(),
"deviceId": hex.EncodeToString(deviceInfo.GetDeviceID()),
"clientKey": deviceInfo.GetClientKey(),
"onlineStatus": deviceInfo.GetOnlineStatus(),
})
}
return vo.NewSuccessObj(gin.H{
"onlineCount": resp.GetOnlineCount(),
"onlineList": deviceInfoList,
}, "")
})
}
// GetProfileService 获取个人资料详细信息
func GetProfileService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
/*err := reqInvoker.SendGetProfileRequest()
if err != nil {
return vo.NewFail("获取个人资料失败")
}*/
profile, err := reqInvoker.SendGetProfileNewRequest()
if err != nil {
return vo.NewFail("获取个人资料失败")
}
return vo.NewSuccessObj(profile, "")
})
}
// SendModifyUserInfoRequest 修改资料
func SendModifyUserInfoRequestService(queryKey string, m req.ModifyUserInfo) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendModifyUserInfoRequest(m.City, m.Country, m.NickName, m.Province, m.Signature, m.Sex, m.InitFlag)
if err != nil {
return vo.NewFail("修改资料失败!")
}
return vo.NewSuccessObj(nil, "修改资料成功!")
})
}
// 修改名称
func UpdateNickNameService(queryKey string, m req.UpdateNickNameModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendUpdateNickNameRequest(m.Scene, m.Val)
if err != nil {
return vo.NewFail("修改名称失败!")
}
return vo.NewSuccessObj(nil, "修改成功!")
})
}
// 设置名称
func SetNickNameService(queryKey string, m req.UpdateNickNameModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendUpdateNickNameRequest(m.Scene, m.Val)
if err != nil {
return vo.NewFail("修改失败!")
}
return vo.NewSuccessObj(nil, "修改成功!")
})
}
// 修改姓别
func SetSexService(queryKey string, m req.UpdateSexModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SetSexService(m.Sex, m.Country, m.City, m.Province)
if err != nil {
return vo.NewFail("修改失败!")
}
return vo.NewSuccessObj(nil, "修改成功!")
})
}
func GetRedisSyncMsgService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.SendWxSyncMsg(queryKey)
// 如果没有同步到数据则返回
cmdList := resp.GetCmdList()
syncCount := cmdList.GetCount()
messageResp := new(table.SyncMessageResponse)
// 遍历同步的信息和群
itemList := cmdList.GetItemList()
for index := uint32(0); index < syncCount; index++ {
item := itemList[index]
itemID := item.GetCmdId()
// 同步到消息
if itemID == baseinfo.CmdIDAddMsg {
addMsg := &wechat.AddMsg{}
err := proto.Unmarshal(item.CmdBuf.Data, addMsg)
if err != nil {
baseutils.PrintLog(err.Error())
continue
}
}
messageResp.SetMessage(item.GetCmdBuf().GetData(), int32(itemID))
}
//发布同步信息消息
if err != nil {
return vo.NewFail(err.Error())
}
messageResp.Key = resp.KeyBuf
return vo.NewSuccessObj(*messageResp, "成功")
})
}
// SendChangePwdRequestService 更改密码
func SendChangePwdRequestService(queryKey string, m req.SendChangePwdRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendChangePwdRequest(m.OldPass, m.NewPass, m.OpCode)
if err != nil {
return vo.NewFail("SendChangePwdRequestService err:" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 上传头像
func UploadHeadImageService(queryKey string, m req.UploadHeadImageModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.UploadHeadImage(m.Base64)
if err != nil {
return vo.NewFail("SendChangePwdRequestService err:" + err.Error())
}
return vo.NewSuccessObj(resp, "成功")
})
}
// endModifyRemarkRequestService 修改备注
func SendModifyRemarkRequestService(queryKey string, m req.SendModifyRemarkRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
err := reqInvoker.SendModifyRemarkRequest(m.UserName, m.RemarkName)
if err != nil {
return vo.NewFail("SendChangePwdRequestService err:" + err.Error())
}
return vo.NewSuccessObj(nil, "成功")
})
}
// UpdateAutoPassService 修改加好友需要验证属性
func UpdateAutoPassService(queryKey string, m req.UpdateAutopassModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
err := reqInvoker.UpdateAutopassRequest(m.SwitchType)
if err != nil {
return vo.NewFail("UpdateAutoPassService err:" + err.Error())
}
return vo.NewSuccessObj(nil, "成功")
})
}
// 设置微信号
func SetWechatService(queryKey string, m req.AlisaModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
rsp, err := reqInvoker.SetWechatRequest(m.Alisa)
if err != nil {
return vo.NewFail("UpdateAutoPassService err:" + err.Error())
}
return vo.NewSuccessObj(rsp, "成功")
})
}
// 修改步数
func UpdateStepNumberService(queryKey string, m req.UpdateStepNumberModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
rsp, err := reqInvoker.UpdateStepNumberRequest(m.Number)
if err != nil {
return vo.NewFail("UpdateStepNumberService err:" + err.Error())
}
return vo.NewSuccessObj(rsp, "成功")
})
}
// 获取步数
func GetUserRankLikeCountService(queryKey string, m req.UserRankLikeModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
rsp, err := reqInvoker.SendGetUserRankLikeCountRequest(m.RankId)
if err != nil {
return vo.NewFail("UpdateStepNumberService err:" + err.Error())
}
return vo.NewSuccessObj(rsp, "成功")
})
}
// 设置添加我的方式
func SetFunctionSwitchService(queryKey string, m req.WxFunctionSwitchModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
req := &wechat.FunctionSwitch{
FunctionId: proto.Uint32(m.Function),
SwitchValue: proto.Uint32(m.Value),
}
buffer, err := proto.Marshal(req)
cmdItem := baseinfo.ModifyItem{
CmdID: 0x17,
Len: uint32(len(buffer)),
Data: buffer,
}
var cmdItems []*baseinfo.ModifyItem
cmdItems = append(cmdItems, &cmdItem)
err = reqInvoker.SendOplogRequest(cmdItems)
if err != nil {
return vo.NewFail("SetFunctionSwitchService err:" + err.Error())
}
return vo.NewSuccessObj("ok", "成功")
})
}
// 设置拍一拍名称
func SetSendPatService(queryKey string, m req.SetSendPatModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
req := &wechat.PatMod{
Value: proto.Int64(8),
Name: proto.String(m.Value),
}
buffer, err := proto.Marshal(req)
cmdItem := baseinfo.ModifyItem{
CmdID: 222,
Len: uint32(len(buffer)),
Data: buffer,
}
var cmdItems []*baseinfo.ModifyItem
cmdItems = append(cmdItems, &cmdItem)
err = reqInvoker.SendOplogRequest(cmdItems)
if err != nil {
return vo.NewFail("SetSendPatService err:" + err.Error())
}
return vo.NewSuccessObj("ok", "成功")
})
}
// SetProxyService 修改socks5代理
func SetProxyService(queryKey string, model req.GetLoginQrCodeModel) vo.DTO {
key := fmt.Sprintf("%s%s", "wechat:Proxy:", queryKey)
// 判断代理为空,清除 redis 缓存
if len(model.Proxy) == 0 {
//删除缓存
db.DelObj(key)
}
return getExistWxConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
if iwxConnect == nil {
return vo.NewFail("链接不存在! 但代理缓存已重置!Proxy:【" + model.Proxy + "】")
}
wxAccount := iwxConnect.GetWXAccount()
errMsg := ""
newProxyUrl := ""
oldProxyUrl := wxAccount.GetUserInfo().GetProxyUrl()
// 断开连接后 之后重新使用新代理建立连接
iwxConnect.Stop()
// 等待 500 毫秒
time.Sleep(time.Millisecond * 500)
// 判断是否删除代理
if len(model.Proxy) == 0 {
// 删除代理
wxAccount.GetUserInfo().RemoveProxy()
newProxyUrl = ""
} else {
// 修改代理
proxyInfo := proxynet.ParseWXProxyInfo(model.Proxy)
dialer := proxyInfo.GetDialer()
if dialer != nil {
wxAccount := iwxConnect.GetWXAccount()
wxAccount.GetUserInfo().SetProxy(proxyInfo)
newProxyUrl = wxAccount.GetUserInfo().GetProxyUrl()
} else {
errMsg = "代理链接格式错误, 正确示例:socks5://username:password@ipv4:port"
}
}
if len(errMsg) > 0 {
return vo.NewFail(errMsg)
}
// 重新二次登录
go func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("设置代理: %v\n", r)
}
}()
// 等 500 毫秒后重新初始化
time.Sleep(time.Millisecond * 500)
InitLoginStatusService(queryKey, false, true, model)
//存redis缓存
error := db.SETObj(key, model)
if error != nil {
}
}()
return vo.NewSuccess(gin.H{
"oldProxyUrl": oldProxyUrl,
"newProxyUrl": newProxyUrl,
}, errMsg)
})
}
+338
View File
@@ -0,0 +1,338 @@
package service
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"xiawan/wx/api/req"
)
type PrecheckRequest struct {
UUID string `json:"uuid"`
Precheck struct {
Ticket string `json:"ticket"`
} `json:"precheck"`
}
type VerifyMethodRequest struct {
UUID string `json:"uuid"`
GetVerifyMethod struct {
Ticket string `json:"ticket"`
} `json:"get_verify_method"`
}
type SubmitPinRequest struct {
UUID string `json:"uuid"`
SubmitPin struct {
Ticket string `json:"ticket"`
Pin string `json:"pin"`
} `json:"submit_pin"`
}
type VerificationcodeParam struct {
Key string
Code string
}
type OuterResponse struct {
Data string `json:"data"`
Status int `json:"status"`
UUID string `json:"uuid"` // 这里是个 JSON 字符串
}
// 定义结构体以匹配返回值
type ResponseData11 struct {
Data string `json:"data"`
Status int `json:"status"`
UUID string `json:"uuid"`
}
func getEncodedUUID(data string) (string, error) {
urlStr := "http://113.44.162.180:5001/get_uuid"
payload := map[string]string{"data": data}
payloadBytes, err := json.Marshal(payload)
if err != nil {
return "", err
}
req, err := http.NewRequest("POST", urlStr, bytes.NewBuffer(payloadBytes))
if err != nil {
return "", err
}
req.Header.Add("Authorization", "Bearer 4282f08a7f1743a06686f1d9dddfa213badb1406de7f6419e135761cca29a2aa")
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return "", err
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return "", err
}
// 先反序列化外层响应
var outerResp OuterResponse
if err := json.Unmarshal(body, &outerResp); err != nil {
return "", fmt.Errorf("unmarshal outer response failed: %w", err)
}
if outerResp.UUID == "" {
return "", fmt.Errorf("outerResp.UUID is empty")
}
// 对 outerResp.UUID 字符串再做一次反序列化
var innerResp ResponseData11
if err := json.Unmarshal([]byte(outerResp.UUID), &innerResp); err != nil {
return "", fmt.Errorf("unmarshal inner UUID json failed: %w", err)
}
if innerResp.UUID == "" {
return "", fmt.Errorf("innerResp.UUID is empty")
}
// URL编码真正的 uuid 字符串
encodedUUID := url.QueryEscape(innerResp.UUID)
return encodedUUID, nil
}
func precheck(uuid, Ticket string) (string, error) {
url := "https://weixin110.qq.com/security/acct/extdevauthslavecgi?t=extdevsignin%2Fslaveverify&ticket=" + Ticket + "&step=precheck&wechat_real_lang=zh_CN"
requestData := PrecheckRequest{
UUID: uuid,
Precheck: struct {
Ticket string `json:"ticket"`
}{
Ticket: Ticket, //3_2d512e8104f3992c5fa8bfa1047ab3bb ios 18.0.1 pc 3_76cdadf7b44f1e05ad8c140ba26dc044
},
}
fmt.Println("我是Ticket", Ticket)
jsonData, err := json.Marshal(requestData)
if err != nil {
return "", err
}
payload := bytes.NewBuffer(jsonData)
req, err := http.NewRequest("POST", url, payload)
if err != nil {
return "", err
}
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x63090a13) XWEB/85551")
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return "", err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", err
}
var data map[string]interface{}
err = json.Unmarshal(body, &data)
if err != nil {
return "", err
}
ret, ok1 := data["ret"].(float64)
errMsg, ok2 := data["err_msg"].(string)
if ok1 && ok2 && ret == 0 && errMsg == "成功。" {
return res.Header.Get("Set-Cookie"), nil
} else {
return "", nil
}
}
func getVerifyID(uuid, cookie, Ticket string) (string, error) {
url := "https://weixin110.qq.com/security/acct/extdevauthslavecgi?t=extdevsignin/slaveverify&ticket=" + Ticket + "&step=get_verify_method&wechat_real_lang=zh_CN"
requestData := VerifyMethodRequest{
UUID: uuid,
GetVerifyMethod: struct {
Ticket string `json:"ticket"`
}{
Ticket: Ticket,
},
}
jsonData, err := json.Marshal(requestData)
if err != nil {
return "", err
}
payload := bytes.NewBuffer(jsonData)
req, err := http.NewRequest("POST", url, payload)
if err != nil {
return "", err
}
req.Header.Add("Cookie", cookie)
//req.Header.Add("Accept", "*/*")
//req.Header.Add("Accept-Encoding", "gzip, deflate, br")
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x63090a13) XWEB/85551")
//req.Header.Add("Connection", "keep-alive")
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return "", err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", err
}
var responseData struct {
Data struct {
VerifyID string `json:"verify_id"`
} `json:"data"`
}
err = json.Unmarshal(body, &responseData)
if err != nil {
return "", err
}
if responseData.Data.VerifyID != "" {
return responseData.Data.VerifyID, nil
}
return "", nil
}
func submitPinAndCheck(secverifyid, uuid, pin, Ticket string) (bool, error) {
fmt.Println("--------------------------------\n", "secverifyid:", secverifyid, "\n", "uuid:", uuid, "\n", "pin:", pin, "\n", "Ticket:", Ticket, "\n--------------------------------")
url := "https://weixin110.qq.com/security/acct/commverifypincgi?t=extdevsignin/slaveverify&ticket=" + Ticket + "&step=submit_pin&secverifyid=" + secverifyid + "&wechat_real_lang=zh_CN"
requestData := SubmitPinRequest{
UUID: uuid,
SubmitPin: struct {
Ticket string `json:"ticket"`
Pin string `json:"pin"`
}{
Ticket: Ticket,
Pin: pin,
},
}
jsonData, err := json.Marshal(requestData)
if err != nil {
return false, err
}
payload := bytes.NewBuffer(jsonData)
req, err := http.NewRequest("POST", url, payload)
if err != nil {
return false, err
}
//req.Header.Add("Accept", "*/*")
//req.Header.Add("Accept-Encoding", "gzip, deflate, br")
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x63090a13) XWEB/8555")
//req.Header.Add("Connection", "keep-alive")
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return false, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return false, err
}
var responseData struct {
Ret int `json:"ret"`
}
fmt.Println("我是body", string(body))
err = json.Unmarshal(body, &responseData)
if err != nil {
return false, err
}
return responseData.Ret == 0, nil
}
func runAllSteps(data, pin, Ticket string) (req.ResponseResult, error) {
encodedUUID, err := getEncodedUUID(data)
if err != nil {
return req.ResponseResult{}, err
}
fmt.Println("我是encodedUUID", encodedUUID)
if encodedUUID == "" {
return req.ResponseResult{
Code: -1,
Success: false,
Message: "效验失败",
Data: nil,
}, nil
}
setCookie, err := precheck(encodedUUID, Ticket)
if err != nil {
return req.ResponseResult{}, err
}
fmt.Println("我是setCookie", setCookie)
if setCookie == "" {
return req.ResponseResult{
Code: -2,
Success: false,
Message: "效验失败",
Data: nil,
}, nil
}
verifyID, err := getVerifyID(encodedUUID, setCookie, Ticket)
if err != nil {
return req.ResponseResult{}, err
}
fmt.Println("我是verifyID", verifyID)
if verifyID == "" {
return req.ResponseResult{
Code: -3,
Success: false,
Message: "效验失败",
Data: nil,
}, nil
}
success, err := submitPinAndCheck(verifyID, encodedUUID, pin, Ticket)
if err != nil {
return req.ResponseResult{}, err
}
var message string
if success {
message = "验证成功,请调用检测二维码继续登录"
} else {
message = "验证失败"
}
return req.ResponseResult{
Code: 0,
Success: true,
Message: message,
Data: nil,
}, nil
}
func Verificationcode2(Data req.VerifyCodeModel, queryKey string) req.ResponseResult {
connectMgr := WXServer.GetWXConnectMgr()
iwxConnect := connectMgr.GetWXConnectByUserInfoUUID(queryKey)
if iwxConnect == nil {
return req.ResponseResult{
Code: -8,
Success: false,
Message: "用户不存在",
Data: nil,
}
}
temp_userinfo := iwxConnect.GetWXAccount().GetUserInfo()
result, err := runAllSteps(Data.Data62, Data.Code, Data.Ticket)
if err != nil {
fmt.Println(err)
}
if result.Success {
result.Data = temp_userinfo.Ticket
}
return result
}
+341
View File
@@ -0,0 +1,341 @@
// 过mac滑块
package service
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"xiawan/wx/api/req"
)
type PrecheckRequestSlide struct {
UUID string `json:"uuid"`
Precheck struct {
Ticket string `json:"ticket"`
} `json:"precheck"`
}
type VerifyMethodRequestSlide struct {
UUID string `json:"uuid"`
GetVerifyMethod struct {
Ticket string `json:"ticket"`
} `json:"get_verify_method"`
}
type SubmitPinRequestSlide struct {
Appid string `json:"appid"`
Ccdata string `json:"ccdata"`
RandStr string `json:"rand_str"`
Ticket string `json:"ticket"`
UUID string `json:"uuid"`
}
type VerificationcodeParamSlide struct {
Key string
Code string
}
type OuterResponseSlide struct {
Data string `json:"data"`
Status int `json:"status"`
UUID string `json:"uuid"` // 这里是个 JSON 字符串
}
// 定义结构体以匹配返回值
type ResponseData11Slide struct {
Data string `json:"data"`
Status int `json:"status"`
UUID string `json:"uuid"`
}
func getEncodedUUIDSlide(data string) (string, error) {
urlStr := "http://113.44.162.180:5001/get_uuid"
payload := map[string]string{"data": data}
payloadBytes, err := json.Marshal(payload)
if err != nil {
return "", err
}
req, err := http.NewRequest("POST", urlStr, bytes.NewBuffer(payloadBytes))
if err != nil {
return "", err
}
req.Header.Add("Authorization", "Bearer 4282f08a7f1743a06686f1d9dddfa213badb1406de7f6419e135761cca29a2aa")
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return "", err
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return "", err
}
// 先反序列化外层响应
var outerResp OuterResponse
if err := json.Unmarshal(body, &outerResp); err != nil {
return "", fmt.Errorf("unmarshal outer response failed: %w", err)
}
if outerResp.UUID == "" {
return "", fmt.Errorf("outerResp.UUID is empty")
}
// 对 outerResp.UUID 字符串再做一次反序列化
var innerResp ResponseData11Slide
if err := json.Unmarshal([]byte(outerResp.UUID), &innerResp); err != nil {
return "", fmt.Errorf("unmarshal inner UUID json failed: %w", err)
}
if innerResp.UUID == "" {
return "", fmt.Errorf("innerResp.UUID is empty")
}
// URL编码真正的 uuid 字符串
encodedUUID := url.QueryEscape(innerResp.UUID)
return encodedUUID, nil
}
func precheckSlide(uuid, Ticket string) (string, error) {
url := "https://weixin110.qq.com/security/acct/extdevauthslavecgi?t=extdevsignin%2Fslaveverify&ticket=" + Ticket + "&step=precheck&wechat_real_lang=zh_CN"
requestData := PrecheckRequestSlide{
UUID: uuid,
Precheck: struct {
Ticket string `json:"ticket"`
}{
Ticket: Ticket, //3_2d512e8104f3992c5fa8bfa1047ab3bb ios 18.0.1 pc 3_76cdadf7b44f1e05ad8c140ba26dc044
},
}
fmt.Println("我是Ticket", Ticket)
jsonData, err := json.Marshal(requestData)
if err != nil {
return "", err
}
payload := bytes.NewBuffer(jsonData)
req, err := http.NewRequest("POST", url, payload)
if err != nil {
return "", err
}
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x63090a13) XWEB/85551")
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return "", err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", err
}
var data map[string]interface{}
err = json.Unmarshal(body, &data)
if err != nil {
return "", err
}
ret, ok1 := data["ret"].(float64)
errMsg, ok2 := data["err_msg"].(string)
if ok1 && ok2 && ret == 0 && errMsg == "成功。" {
return res.Header.Get("Set-Cookie"), nil
} else {
return "", nil
}
}
func getVerifyIDSlide(uuid, cookie, Ticket string) (string, error) {
url := "https://weixin110.qq.com/security/acct/extdevauthslavecgi?t=extdevsignin/slaveverify&ticket=" + Ticket + "&step=get_verify_method&wechat_real_lang=zh_CN"
requestData := VerifyMethodRequest{
UUID: uuid,
GetVerifyMethod: struct {
Ticket string `json:"ticket"`
}{
Ticket: Ticket,
},
}
jsonData, err := json.Marshal(requestData)
if err != nil {
return "", err
}
payload := bytes.NewBuffer(jsonData)
req, err := http.NewRequest("POST", url, payload)
if err != nil {
return "", err
}
req.Header.Add("Cookie", cookie)
//req.Header.Add("Accept", "*/*")
//req.Header.Add("Accept-Encoding", "gzip, deflate, br")
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x63090a13) XWEB/85551")
//req.Header.Add("Connection", "keep-alive")
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return "", err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", err
}
var responseData struct {
Data struct {
VerifyID string `json:"verify_id"`
} `json:"data"`
}
err = json.Unmarshal(body, &responseData)
if err != nil {
return "", err
}
if responseData.Data.VerifyID != "" {
return responseData.Data.VerifyID, nil
}
return "", nil
}
func submitPinAndCheckSlide(secverifyid, uuid, slideTicket, randStr string) (bool, error) {
fmt.Println("--------------------------------\n", "secverifyid:", secverifyid, "\n", "uuid:", uuid, "\n", "slideTicket:", slideTicket, "\n", "randStr:", randStr, "\n--------------------------------")
url := "https://weixin110.qq.com/security/acct/commverifycodecgi?t=extdevsignin/slaveverify&step=verify_capt&secverifyid=" + secverifyid + "&wechat_real_lang=zh_CN&exportkey=&version=9"
requestData := SubmitPinRequestSlide{
UUID: uuid,
Appid: "2078688116",
Ccdata: "",
RandStr: randStr,
Ticket: slideTicket,
}
jsonData, err := json.Marshal(requestData)
if err != nil {
return false, err
}
payload := bytes.NewBuffer(jsonData)
req, err := http.NewRequest("POST", url, payload)
if err != nil {
return false, err
}
//req.Header.Add("Accept", "*/*")
//req.Header.Add("Accept-Encoding", "gzip, deflate, br")
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x63090a13) XWEB/8555")
//req.Header.Add("Connection", "keep-alive")
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return false, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return false, err
}
var responseData struct {
Ret int `json:"ret"`
}
fmt.Println("我是body", string(body))
err = json.Unmarshal(body, &responseData)
if err != nil {
return false, err
}
return responseData.Ret == 0, nil
}
func runAllStepsSlide(data, slideTicket, Ticket, randStr string) (req.ResponseResult, error) {
fmt.Println("data", data)
fmt.Println("slideTicket", slideTicket)
fmt.Println("Ticket", Ticket)
fmt.Println("randStr", randStr)
encodedUUID, err := getEncodedUUIDSlide(data)
if err != nil {
return req.ResponseResult{}, err
}
fmt.Println("我是encodedUUID", encodedUUID)
if encodedUUID == "" {
return req.ResponseResult{
Code: -1,
Success: false,
Message: "效验失败",
Data: nil,
}, nil
}
setCookie, err := precheckSlide(encodedUUID, Ticket)
if err != nil {
return req.ResponseResult{}, err
}
fmt.Println("我是setCookie", setCookie)
if setCookie == "" {
return req.ResponseResult{
Code: -2,
Success: false,
Message: "效验失败",
Data: nil,
}, nil
}
verifyID, err := getVerifyIDSlide(encodedUUID, setCookie, Ticket)
if err != nil {
return req.ResponseResult{}, err
}
fmt.Println("我是verifyID", verifyID)
if verifyID == "" {
return req.ResponseResult{
Code: -3,
Success: false,
Message: "效验失败",
Data: nil,
}, nil
}
success, err := submitPinAndCheckSlide(verifyID, encodedUUID, slideTicket, randStr)
if err != nil {
return req.ResponseResult{}, err
}
var message string
if success {
message = "验证成功,请调用检测二维码继续登录"
} else {
message = "验证失败"
}
return req.ResponseResult{
Code: 0,
Success: true,
Message: message,
Data: nil,
}, nil
}
func VerificationcodeSlide(Data req.SlideTicketModel) req.ResponseResult {
// connectMgr := WXServer.GetWXConnectMgr()
// iwxConnect := connectMgr.GetWXConnectByUserInfoUUID(queryKey)
// if iwxConnect == nil {
// return req.ResponseResult{
// Code: -8,
// Success: false,
// Message: "用户不存在",
// Data: nil,
// }
// }
// temp_userinfo := iwxConnect.GetWXAccount().GetUserInfo()
result, err := runAllStepsSlide(Data.Data62, Data.SlideTicket, Data.Ticket, Data.RandStr)
if err != nil {
fmt.Println(err)
}
// if result.Success {
// result.Data = temp_userinfo.Ticket
// }
return result
}
+244
View File
@@ -0,0 +1,244 @@
package service
import (
"encoding/json"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/db"
"github.com/gin-gonic/gin"
)
// SetWelcomeService 设置欢迎词配置
func SetWelcomeService(queryKey string, m req.SetWelcomeModel) vo.DTO {
// 获取现有配置,保留群聊列表
existingConfig := req.WelcomeConfig{
ChatRooms: []string{},
}
command, err := db.QueryCommand(queryKey)
if err == nil && command.B003Str != "" {
err = json.Unmarshal([]byte(command.B003Str), &existingConfig)
if err != nil {
// 解析失败,使用空列表
existingConfig.ChatRooms = []string{}
}
}
// 保留现有群聊列表
m.Config.ChatRooms = existingConfig.ChatRooms
// 将欢迎词配置转换为JSON字符串
configJSON, err := json.Marshal(m.Config)
if err != nil {
return vo.NewFail("序列化欢迎词配置失败")
}
// 更新B003和B003Str
enable := 0
if m.Config.Enable {
enable = 1
}
_, err = db.UpdateCommand(queryKey, "B003", enable, "")
if err != nil {
return vo.NewFail("更新欢迎词状态失败")
}
_, err = db.UpdateCommand(queryKey, "B003Str", 0, string(configJSON))
if err != nil {
return vo.NewFail("更新欢迎词配置失败")
}
return vo.NewSuccess(nil, "设置成功")
}
// GetWelcomeService 获取欢迎词配置
func GetWelcomeService(queryKey string) vo.DTO {
command, err := db.QueryCommand(queryKey)
if err != nil {
return vo.NewFail("查询欢迎词配置失败")
}
var config req.WelcomeConfig
if command.B003Str != "" {
err = json.Unmarshal([]byte(command.B003Str), &config)
if err != nil {
return vo.NewFail("解析欢迎词配置失败")
}
}
// 设置启用状态
config.Enable = command.B003 == 1
return vo.NewSuccess(gin.H{
"config": config,
}, "获取成功")
}
// SetAdminKeywordService 设置管理员关键词配置
func SetAdminKeywordService(queryKey string, m req.SetAdminKeywordModel) vo.DTO {
// 将管理员关键词配置转换为JSON字符串
configJSON, err := json.Marshal(m.Config)
if err != nil {
return vo.NewFail("序列化管理员关键词配置失败")
}
// 更新B004和B004Str
enable := 0
if m.Config.Enable {
enable = 1
}
_, err = db.UpdateCommand(queryKey, "B004", enable, "")
if err != nil {
return vo.NewFail("更新管理员关键词状态失败")
}
_, err = db.UpdateCommand(queryKey, "B004Str", 0, string(configJSON))
if err != nil {
return vo.NewFail("更新管理员关键词配置失败")
}
return vo.NewSuccess(nil, "设置成功")
}
// GetAdminKeywordService 获取管理员关键词配置
func GetAdminKeywordService(queryKey string) vo.DTO {
command, err := db.QueryCommand(queryKey)
if err != nil {
return vo.NewFail("查询管理员关键词配置失败")
}
var config req.AdminKeywordConfig
if command.B004Str != "" {
err = json.Unmarshal([]byte(command.B004Str), &config)
if err != nil {
return vo.NewFail("解析管理员关键词配置失败")
}
}
// 设置启用状态
config.Enable = command.B004 == 1
return vo.NewSuccess(gin.H{
"config": config,
}, "获取成功")
}
// SetKickKeywordService 设置踢人关键词配置
func SetKickKeywordService(queryKey string, m req.SetKickKeywordModel) vo.DTO {
// 将踢人关键词配置转换为JSON字符串
configJSON, err := json.Marshal(m.Config)
if err != nil {
return vo.NewFail("序列化踢人关键词配置失败")
}
// 更新B006和B006Str
enable := 0
if m.Config.Enable {
enable = 1
}
_, err = db.UpdateCommand(queryKey, "B006", enable, "")
if err != nil {
return vo.NewFail("更新踢人关键词状态失败")
}
_, err = db.UpdateCommand(queryKey, "B006Str", 0, string(configJSON))
if err != nil {
return vo.NewFail("更新踢人关键词配置失败")
}
return vo.NewSuccess(nil, "设置成功")
}
// GetKickKeywordService 获取踢人关键词配置
func GetKickKeywordService(queryKey string) vo.DTO {
command, err := db.QueryCommand(queryKey)
if err != nil {
return vo.NewFail("查询踢人关键词配置失败")
}
var config req.KickKeywordConfig
if command.B006Str != "" {
err = json.Unmarshal([]byte(command.B006Str), &config)
if err != nil {
return vo.NewFail("解析踢人关键词配置失败")
}
}
// 设置启用状态
config.Enable = command.B006 == 1
return vo.NewSuccess(gin.H{
"config": config,
}, "获取成功")
}
// SetInviteKeywordService 设置关键词邀请入群配置
func SetInviteKeywordService(queryKey string, m req.SetInviteKeywordModel) vo.DTO {
// 获取现有配置,保留已设置的关键词对
existingConfig := req.InviteKeywordConfig{
Pairs: []req.InviteKeywordPair{},
}
command, err := db.QueryCommand(queryKey)
if err == nil && command.B005Str != "" {
err = json.Unmarshal([]byte(command.B005Str), &existingConfig)
if err != nil {
// 解析失败,使用空列表
existingConfig.Pairs = []req.InviteKeywordPair{}
}
}
// 保留现有关键词对列表
m.Config.Pairs = existingConfig.Pairs
// 将关键词邀请入群配置转换为JSON字符串
configJSON, err := json.Marshal(m.Config)
if err != nil {
return vo.NewFail("序列化关键词邀请入群配置失败")
}
// 更新B005和B005Str
enable := 0
if m.Config.Enable {
enable = 1
}
_, err = db.UpdateCommand(queryKey, "B005", enable, "")
if err != nil {
return vo.NewFail("更新关键词邀请入群状态失败")
}
_, err = db.UpdateCommand(queryKey, "B005Str", 0, string(configJSON))
if err != nil {
return vo.NewFail("更新关键词邀请入群配置失败")
}
return vo.NewSuccess(nil, "设置成功")
}
// GetInviteKeywordService 获取关键词邀请入群配置
func GetInviteKeywordService(queryKey string) vo.DTO {
command, err := db.QueryCommand(queryKey)
if err != nil {
return vo.NewFail("查询关键词邀请入群配置失败")
}
var config req.InviteKeywordConfig
if command.B005Str != "" {
err = json.Unmarshal([]byte(command.B005Str), &config)
if err != nil {
return vo.NewFail("解析关键词邀请入群配置失败")
}
}
// 设置启用状态
config.Enable = command.B005 == 1
return vo.NewSuccess(gin.H{
"config": config,
}, "获取成功")
}
+65
View File
@@ -0,0 +1,65 @@
package swagger
import (
"reflect"
"xiawan/wx/api/req"
)
// 为避免自动分析控制器失败,手动指定Swagger定义
func init() {
// 添加回调API的Swagger定义
// 使用特殊的注册函数,确保这些API放在最前面
RegisterCallbackAPI("/message/SetCallback", "post", "设置消息回调", req.MessageCallbackConfigModel{})
RegisterCallbackAPI("/message/GetCallback", "get", "获取消息回调配置", nil)
RegisterCallbackAPI("/message/DeleteCallback", "get", "删除消息回调配置", nil)
// 手动注册回调模型
RegisterModel(req.MessageCallbackConfigModel{})
RegisterModel(req.MessageCallbackPayload{})
}
// RegisterCallbackAPI 注册回调API到Swagger文档并设置优先显示
func RegisterCallbackAPI(path, method, summary string, model interface{}) {
if manualAPIs[path] == nil {
manualAPIs[path] = make(map[string]SwgMap)
}
params := []SwgMap{
{
"in": "query",
"name": "key",
"type": "string",
"description": "账号唯一标识",
},
}
// 如果模型不为空,添加请求体参数
if model != nil {
modelType := reflect.TypeOf(model)
modelName := modelType.Name()
if modelName == "" && modelType.Kind() == reflect.Ptr {
modelName = modelType.Elem().Name()
}
params = append(params, SwgMap{
"in": "body",
"name": "body",
"description": "请求参数",
"schema": SwgMap{
"$ref": "#/definitions/" + modelName,
},
})
}
// 使用特殊的标签"消息回调"
manualAPIs[path][method] = SwgMap{
"summary": summary,
"parameters": params,
"responses": SwgMap{
"200": SwgMap{
"description": "",
},
},
"tags": []string{"消息回调"},
}
}
+87
View File
@@ -0,0 +1,87 @@
package swagger
import (
"reflect"
)
// 手动注册的API
var manualAPIs = make(map[string]map[string]SwgMap)
// 手动注册的模型
var manualModels = make(map[string]interface{})
// RegisterAPI 手动注册API到Swagger文档
func RegisterAPI(path, method, summary string, model interface{}) {
if manualAPIs[path] == nil {
manualAPIs[path] = make(map[string]SwgMap)
}
params := []SwgMap{
{
"in": "query",
"name": "key",
"type": "string",
"description": "账号唯一标识",
},
}
// 如果模型不为空,添加请求体参数
if model != nil {
modelType := reflect.TypeOf(model)
modelName := modelType.Name()
if modelName == "" && modelType.Kind() == reflect.Ptr {
modelName = modelType.Elem().Name()
}
params = append(params, SwgMap{
"in": "body",
"name": "body",
"description": "请求参数",
"schema": SwgMap{
"$ref": "#/definitions/" + modelName,
},
})
}
manualAPIs[path][method] = SwgMap{
"summary": summary,
"parameters": params,
"responses": SwgMap{
"200": SwgMap{
"description": "",
},
},
"tags": []string{getTag(path)},
}
}
// RegisterModel 手动注册模型到Swagger文档
func RegisterModel(model interface{}) {
modelType := reflect.TypeOf(model)
modelName := modelType.Name()
if modelName == "" && modelType.Kind() == reflect.Ptr {
modelName = modelType.Elem().Name()
}
manualModels[modelName] = model
}
// GetManualAPIs 获取所有手动注册的API
func GetManualAPIs() map[string]SwgMap {
result := make(map[string]SwgMap)
for path, methods := range manualAPIs {
pathMap := make(SwgMap)
for method, spec := range methods {
pathMap[method] = spec
}
result[path] = pathMap
}
return result
}
// GetManualModels 获取所有手动注册的模型
func GetManualModels() map[string]interface{} {
return manualModels
}
+11
View File
@@ -0,0 +1,11 @@
package swagger
import "github.com/gin-gonic/gin"
func Init() {
generateSwagger()
}
func Setup(r *gin.Engine) {
r.Static("docs", "static/swagger")
}
+730
View File
@@ -0,0 +1,730 @@
package swagger
import (
"encoding/json"
"fmt"
"os"
"path"
"reflect"
"regexp"
"sort"
"strings"
"xiawan/wx/srv/srvconfig"
"gopkg.in/yaml.v2"
)
type SwgMap map[string]interface{}
// 优先显示的API路径列表
var priorityPaths = []string{
"/message/SetCallback",
"/message/GetCallback",
"/message/DeleteCallback",
}
// 是否为优先显示的API路径
func isPriorityPath(path string) bool {
for _, pp := range priorityPaths {
if strings.HasSuffix(path, pp) {
return true
}
}
return false
}
// 获取排序的路径映射
func getSortedPaths(paths SwgMap) SwgMap {
// 创建一个新的排序后的paths映射
sortedPaths := make(SwgMap)
// 首先添加消息回调路径
for path, pathItem := range paths {
if isCallbackPath(strings.TrimPrefix(path, srvconfig.GlobalSetting.ApiVersion)) {
sortedPaths[path] = pathItem
}
}
// 然后添加其他优先路径
for path, pathItem := range paths {
if !isCallbackPath(strings.TrimPrefix(path, srvconfig.GlobalSetting.ApiVersion)) && isPriorityPath(path) {
sortedPaths[path] = pathItem
}
}
// 最后添加其余路径
for path, pathItem := range paths {
if !isCallbackPath(strings.TrimPrefix(path, srvconfig.GlobalSetting.ApiVersion)) && !isPriorityPath(path) {
sortedPaths[path] = pathItem
}
}
return sortedPaths
}
// 保存swagger生成后的回调,可通过此变量获取自定义生成的swagger
var GeneratedSwaggerData map[string]interface{}
// 检查path是否为消息回调路径
func isCallbackPath(path string) bool {
callbackPaths := []string{
"/message/SetCallback",
"/message/GetCallback",
"/message/DeleteCallback",
}
// 去除版本前缀
if strings.HasPrefix(path, srvconfig.GlobalSetting.ApiVersion) {
path = strings.TrimPrefix(path, srvconfig.GlobalSetting.ApiVersion)
}
for _, cbPath := range callbackPaths {
if path == cbPath {
return true
}
}
return false
}
// 获取排序后的路径,优先显示消息回调路径
func getCallbackPrioritizedPaths(paths map[string]interface{}) []string {
// 先分离回调路径和普通路径
var callbackPaths []string
var normalPaths []string
for path := range paths {
if isCallbackPath(path) {
callbackPaths = append(callbackPaths, path)
} else {
normalPaths = append(normalPaths, path)
}
}
// 对回调路径和普通路径分别排序
sort.Strings(callbackPaths)
sort.Strings(normalPaths)
// 合并路径,回调路径在前
return append(callbackPaths, normalPaths...)
}
func generateSwagger() {
bytes, err := os.ReadFile("./api/router/router.go")
if err != nil {
checkApiVersion()
return
}
lines := strings.Split(string(bytes), "\n")
var current string
routers := make(map[string][][]string)
for i := 0; i < len(lines); i++ {
line := strings.TrimSpace(lines[i])
if strings.Contains(line, ".Group(") {
reg := regexp.MustCompile("ver \\+ \"/(\\w+)")
if match := reg.FindStringSubmatch(line); len(match) >= 2 {
current = "/" + match[1]
next, handles := analyzeGroupRouter(lines, i+1)
i = next
routers[current] = append(routers[current], handles...)
continue
}
}
}
tags := []SwgMap{}
// 首先添加消息回调标签,确保它始终在最前面
callbackTag := SwgMap{"name": "消息回调", "description": "消息回调接口"}
tags = append(tags, callbackTag)
for k := range routers {
// k 为 URL 前缀
// 跳过已添加的消息回调标签
tagName := getTag(k)
if tagName == "消息回调" {
continue
}
tags = append(tags, SwgMap{"name": tagName, "description": k})
}
// 确保手动注册API的标签也被包含
for path := range GetManualAPIs() {
parts := strings.Split(path, "/")
if len(parts) > 1 {
tagPath := "/" + parts[1]
tagExists := false
tagName := getTag(tagPath)
// 跳过已添加的消息回调标签
if tagName == "消息回调" {
continue
}
for _, tag := range tags {
if tag["description"].(string) == tagPath {
tagExists = true
break
}
}
if !tagExists {
tags = append(tags, SwgMap{"name": tagName, "description": tagPath})
}
}
}
// 对 tags 进行排序(消息回调标签已经在最前面,所以从索引1开始排序)
if len(tags) > 1 {
sort.Slice(tags[1:], func(i, j int) bool {
val1 := getValue(tags[i+1]["description"].(string))
val2 := getValue(tags[j+1]["description"].(string))
return val1 < val2
})
}
// 合并自动分析和手动注册的路径
paths := analyseControllers(routers)
for path, pathItem := range GetManualAPIs() {
apiPath := fmt.Sprintf("%s%s", srvconfig.GlobalSetting.ApiVersion, path)
paths[apiPath] = pathItem
}
// 对paths进行排序,确保优先路径在前
paths = getSortedPaths(paths)
swgMap := SwgMap{
"swagger": "2.0",
"info": SwgMap{
"title": "8061-07-08算法",
"description": "长连接-自动心跳-自动二登-消息回调-长时间在线 \n 25.12.24 增加cdn高清图片上传接口, 修复初始化消息同步问题 \n 25.12.18 修复a16和62数据登录, 增加a16转62, 62转a16功能 \n25.12.13 修复二登后长链接失效问题 \n25.12.9 增加视频号助手扫码登录功能 \n 25.12.5 增加手机点击退出ipad登录后, 同步在线状态 \n 25.12.4 修复重启后代理丢失问题 \n 25.11.8 新增企微图片下载, 整合接收xml格式 \n 25.11.5 修复ws消息阻塞问题(断连后批量推送), 删除历史消息接收逻辑 \n 25.11.1 修复长语音下载问题 \n 25.9.1 增加mac滑块网页, 依旧用mac2ipad接口(但实测依旧不能pc同时在线) \n 25.8.21 增加mac滑块, mac2iPad(direct接口) \n 25.8.9 直登被和谐了, 另谋出路~ \n 25.8.6 消息回调格式封装外层key, 方便聚合聊天callback区分账号 \n 25.8.5 抽离直登和iPad登录,同步callback和ws消息格式 \n 25.8.3 直登iPad, 修复心跳相关问题, 重新拉到861, 下个版本跟新算法吧, 头痛 \n 25.8.1 增加群聊成员变动回调 \n 25.7.6 增加Windows登录(新号不建议用, 容易风控) 部分接口恢复859, 准备下个版本更新ccd+rqtx全方面升级860(本版本是需要收费的, 不更新不影响正常使用) \n 25.6.30 修复多次取码的状态问题 \n 25.6.28 拉到8060, 不能直接解决人脸, 很头痛 \n 25.6.16 重构数据库层, 增加使用SQLite分支, 方便打包分发 \n 25.6.14 增加车载登录, 自动切号绕过验证码/人脸 \n 25.5.28 修复输入验证码接口, 准备修复群聊消息同步问题 \n 25.5.24 增加输入登录验证码接口 \n 25.5.20 增加安卓平板, 配置文件增加是否切设备选项 \n 25.5.19 增加获取公众号文章阅读数量接口, 解决新设备确认和扫脸确认 \n 25.5.16 增加阅读/点赞接口,增加mac登录,增加删除手机通讯录接口 \n 25.5.15 增加文件上传功能, 优化文件转发功能, 准备增加输入登录验证码 \n 25.5.14 拉到8059, 准备更新ccd \n 25.5.13 每10次短连接前检查一次长连接状态(优先长链接) \n 25.5.12 增加回调持久化功能,修复登录状态缓存问题(逻辑错误) \n 25.5.11 增加消息回调功能,删除签名 \n 25.5.10 优化红包速度, 修复长连接消息同步失效 \n 25.5.9 修复因代波动导致长连接断开问题 \n 25.4.8 修复ws断链问题,解决跨域 \n 25.5.7 修复撤回图片逻辑 \n 25.5.6 增加朋友圈视频上传 \n 25.5.3 修复ws并发panic",
"contact": "",
"version": "仅供学习交流使用,禁止用于非法用途",
},
"basePath": srvconfig.GlobalSetting.ApiVersion,
"paths": paths,
"definitions": analyzeRequestModels(),
"tags": tags,
}
// 序列化为 YAML 格式
data, _ := yaml.Marshal(&swgMap)
_ = os.Chmod("./static/swagger/swagger.yml", 0777)
err = os.WriteFile("./static/swagger/swagger.yml", data, 0x0777)
bytes, _ = json.Marshal(swgMap)
//bytes, _ = json.MarshalIndent(swgMap, "", " ") // 缩进
_ = os.Chmod("./static/swagger/swagger.json", 0777)
err = os.WriteFile("./static/swagger/swagger.json", bytes, 0x0777)
fmt.Println("generateSwagger success")
}
func checkApiVersion() {
_ = os.Chmod("./static/swagger/swagger.yml", 0777)
_ = os.Chmod("./static/swagger/swagger.json", 0777)
// 加载 swagger.json
jsonBytes, err := os.ReadFile("./static/swagger/swagger.json")
if err != nil {
return
}
swgMap := SwgMap{}
err = json.Unmarshal(jsonBytes, &swgMap)
if err != nil {
return
}
swgMap["basePath"] = srvconfig.GlobalSetting.ApiVersion
// 序列化为 YAML 格式
data, _ := yaml.Marshal(&swgMap)
err = os.WriteFile("./static/swagger/swagger.yml", data, 0x0777)
jsonBytes, _ = json.Marshal(swgMap)
//bytes, _ = json.MarshalIndent(swgMap, "", " ") // 缩进
err = os.WriteFile("./static/swagger/swagger.json", jsonBytes, 0x0777)
fmt.Println("updateApiVersion success")
}
func analyzeRequestModels() SwgMap {
byts, _ := os.ReadFile("./api/req/model.go")
byts2, _ := os.ReadFile("./api/req/cmd-model.go")
lines := strings.Split(string(byts), "\n")
lines = append(lines, strings.Split(string(byts2), "\n")...)
// 添加回调模型文件
callbackModelBytes, err := os.ReadFile("./api/req/callbackModel.go")
if err == nil {
lines = append(lines, strings.Split(string(callbackModelBytes), "\n")...)
}
// 添加文件上传模型
fileModelBytes, err := os.ReadFile("./api/req/fileModel.go")
if err == nil {
lines = append(lines, strings.Split(string(fileModelBytes), "\n")...)
}
lines = append(lines, []string{
"type baseinfo.UserLabelInfoItem struct {",
" UserName string",
" LabelIDList string",
"}",
"type baseinfo.Location struct {",
" PoiClassifyID string",
" PoiName string",
" PoiAddress string",
" PoiClassifyType uint32",
" City string",
" Latitude string",
" Longitude string",
"}",
}...)
definitions := make(SwgMap)
for i := 0; i < len(lines); i++ {
line := lines[i]
if strings.HasPrefix(line, "type") {
matches := regexp.MustCompile("type ([\\w.]+) struct").FindStringSubmatch(line)
if len(matches) < 2 {
continue
}
name := matches[1]
definitions[name] = SwgMap{
"title": name,
"type": "object",
"properties": analyzeModeStruct(lines, i+1, name == "MessageItem"),
}
}
}
analyzeBaseInfoStruct(definitions)
// 整合手动注册的模型
for name, model := range GetManualModels() {
if _, exists := definitions[name]; !exists {
modelType := reflect.TypeOf(model)
if modelType.Kind() == reflect.Struct {
properties := make(SwgMap)
for i := 0; i < modelType.NumField(); i++ {
field := modelType.Field(i)
// 获取json标签
jsonTag := field.Tag.Get("json")
if jsonTag == "" || jsonTag == "-" {
continue
}
// 去掉json标签中的选项部分
jsonName := strings.Split(jsonTag, ",")[0]
// 获取字段类型
fieldType := field.Type.Name()
if fieldType == "" {
switch field.Type.Kind() {
case reflect.String:
fieldType = "string"
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
fieldType = "integer"
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
fieldType = "integer"
case reflect.Float32, reflect.Float64:
fieldType = "number"
case reflect.Bool:
fieldType = "boolean"
case reflect.Map:
fieldType = "object"
case reflect.Slice, reflect.Array:
fieldType = "array"
default:
fieldType = "object"
}
}
// 获取注释
description := field.Tag.Get("description")
if description == "" {
// 尝试从字段名后的注释中提取
description = strings.TrimSpace(field.Tag.Get("comment"))
}
// 构建属性定义
typeMap := convertType(fieldType)
typeMap["description"] = description
properties[jsonName] = typeMap
}
definitions[name] = SwgMap{
"title": name,
"type": "object",
"properties": properties,
}
}
}
}
return definitions
}
func analyzeModeStruct(lines []string, i int, debug bool) SwgMap {
props := make(SwgMap)
for _, line := range lines[i:] {
if strings.HasPrefix(strings.TrimSpace(line), "//") {
continue
}
if strings.HasPrefix(line, "}") {
break
}
columns := listTrimSpace(strings.Split(strings.TrimSpace(line), " "))
if !strings.HasPrefix(columns[len(columns)-1], "//") {
columns = append(columns, "//")
}
if debug {
// fmt.Printf("columns: %v\n", strings.Join(columns, ","))
// fmt.Printf("columns[len(columns)-2]: %v\n", columns[len(columns)-2])
}
typ := columns[len(columns)-2]
// 处理JSON标签
var jsonName string
for _, v := range columns[:len(columns)-2] {
// 跳过JSON标签和binding标签
if strings.Contains(v, "`json:") || strings.Contains(v, "`binding:") {
continue
}
// 获取JSON标签名
jsonTagMatch := regexp.MustCompile("`json:\"([^,\"]+)").FindStringSubmatch(line)
if len(jsonTagMatch) > 1 {
jsonName = jsonTagMatch[1]
} else {
jsonName = v
}
// 忽略binding标签对类型的影响
if strings.Contains(typ, "binding:") {
// 找到正确的类型(通常是binding标签前的类型)
for j, column := range columns {
if j > 0 && strings.Contains(column, "binding:") {
typ = columns[j-1]
break
}
}
}
desc := cloneMap(convertType(typ))
if v := columns[len(columns)-1]; v != "//" {
desc["description"] = strings.TrimPrefix(v, "//")
}
props[jsonName] = desc
if typ == "string" { // 设置 string 默认值为 空串
desc["example"] = ""
}
// 解析 example 的默认值 example:"1"
match := regexp.MustCompile("example:\"([\\w\\d]+)\"").FindStringSubmatch(line)
if len(match) < 2 {
continue
}
desc["example"] = match[1]
}
}
return props
}
var baseInfoNames = map[string]bool{
//"UserLabelInfoItem": true,
//"Location": true,
"RedPacket": true,
"HongBaoItem": true,
"HongBaoURLItem": true,
"GetRedPacketList": true,
"TimelineObject": true,
"ActionInfo": true,
"AppInfo": true,
"AppMsg": true,
"ContentObject": true,
"Location": true,
"Media": true,
"MediaList": true,
"StreamVideo": true,
"Enc": true,
"Size": true,
"Thumb": true,
"URL": true,
"VideoSize": true,
}
// 解析 controller 中使用的 项目根目录下 clientsdk/baseinfo 目录内的 Model 结构体
func analyzeBaseInfoStruct(definitions SwgMap) {
dirs, _ := os.ReadDir("./clientsdk/baseinfo")
for _, dir := range dirs {
dataBytes, _ := os.ReadFile(path.Join("./clientsdk/baseinfo", dir.Name()))
lines := strings.Split(string(dataBytes), "\n")
for i := 0; i < len(lines); i++ {
line := lines[i]
if !strings.HasPrefix(line, "type") {
continue
}
match := regexp.MustCompile("type ([\\w.]+) struct").FindStringSubmatch(line)
if len(match) < 2 {
continue
}
name := match[1]
if !baseInfoNames[name] {
continue
}
definitions[name] = SwgMap{
"title": name,
"type": "object",
"properties": analyzeModeStruct(lines, i+1, name == "MessageItem"),
}
}
}
}
var typesMap = map[string]SwgMap{
"byte": {"type": "integer", "format": "int"},
"int": {"type": "integer", "format": "int"},
"int32": {"type": "integer", "format": "int32"},
"int64": {"type": "integer", "format": "int64"},
"uint64": {"type": "integer", "format": "uint64"},
"bool": {"type": "boolean"},
"uint32": {"type": "integer", "format": "uint32"},
"float32": {"type": "number", "format": "double"},
"float64": {"type": "number", "format": "double"},
"string": {"type": "string"},
}
// TagInfo 定义结构体来存储索引和名称
type TagInfo struct {
Index int
Name string
}
// 创建特定的回调标签
var callbackTags = map[string]string{
"/message/SetCallback": "消息回调",
"/message/GetCallback": "消息回调",
"/message/DeleteCallback": "消息回调",
}
func getTag(key string) string {
v := srvconfig.GlobalSetting.ApiVersion
k := key
if strings.HasPrefix(key, v) {
k = key[len(v):]
}
// 检查是否为回调API路径
if tag, exists := callbackTags[k]; exists {
return tag
}
if value, ok := tagsMap[k]; ok {
return value.Name
}
return key
}
func getValue(key string) int {
// 消息回调路径和标签值为 -100,确保它们排在最前面
// 直接检查路径中是否包含特定的回调API路径
if strings.Contains(key, "/message/SetCallback") ||
strings.Contains(key, "/message/GetCallback") ||
strings.Contains(key, "/message/DeleteCallback") {
return -200
}
tagsMap := map[string]int{
"/login": -1,
"/message": 0,
"/pay": 1,
"/friend": 2,
"/user": 3,
"/group": 4,
"/admin": 5,
"/label": 6,
"/ws": 7,
"/sns": 8,
"/equipment": 9,
"/applet": 10,
"/favor": 11,
"/finder": 12,
"/qy": 13,
"/other": 14,
}
for path, val := range tagsMap {
if strings.HasPrefix(key, path) {
return val
}
}
return 100
}
var tagsMap = map[string]TagInfo{
//"/index/login": {0, "展示登录二维码"},
"/admin": {0, "管理"},
"/login": {1, "登录"},
"/ws": {2, "同步消息"},
"/message": {-1, "消息"},
"/pay": {4, "支付"},
"/friend": {5, "朋友"},
"/user": {6, "用户"},
"/group": {7, "群管理"},
"/label": {8, "标签"},
"/applet": {9, "公众号/小程序"},
"/sns": {10, "朋友圈"},
"/finder": {11, "视频号"},
"/favor": {12, "收藏"},
"/qy": {13, "企业微信"},
"/equipment": {14, "设备"},
"/other": {15, "其他"},
// "/cmd": {16, "用户指令"},
}
func convertType(typ string) SwgMap {
if strings.HasPrefix(typ, "[]") {
itr := strings.TrimPrefix(typ, "[]")
return SwgMap{"type": "array", "items": convertType(itr)}
}
if v, ok := typesMap[typ]; ok {
return v
}
return SwgMap{"$ref": "#/definitions/" + strings.Trim(typ, "*")}
}
func listTrimSpace(src []string) []string {
dst := make([]string, 0)
for i, v := range src {
if strings.TrimSpace(v) != "" {
if strings.HasPrefix(v, "`json:") {
continue
}
if strings.HasPrefix(v, "`xml:") {
continue
}
if strings.HasPrefix(v, "`example:") {
continue
}
if strings.HasPrefix(v, "//") {
dst = append(dst, strings.Join(src[i:], " "))
break
} else {
dst = append(dst, v)
}
}
}
return dst
}
func cloneMap(src SwgMap) SwgMap {
dict := make(SwgMap)
for k, v := range src {
dict[k] = v
}
return dict
}
func analyseControllers(routers map[string][][]string) SwgMap {
paths := SwgMap{}
handles := map[string]SwgMap{}
dirs, _ := os.ReadDir("./api/controller")
for _, dir := range dirs {
if strings.HasPrefix(dir.Name(), "baseController") {
continue
}
byts, _ := os.ReadFile(path.Join("./api/controller", dir.Name()))
lines := strings.Split(string(byts), "\n")
for i, v := range lines {
if strings.Contains(v, "func") && strings.Contains(v, "gin.Context)") {
matches := regexp.MustCompile("func ([\\w\\d]+)\\(c?tx? \\*gin.Context\\)").FindStringSubmatch(v)
if len(matches) < 2 {
// 正则表达式匹配失败,跳过此函数
continue
}
name := matches[1]
annotation := ""
if i > 0 {
annotation = strings.TrimSpace(strings.Trim(lines[i-1], "// "+name+" "))
}
pLine := ""
if i+1 < len(lines) {
pLine = lines[i+1]
if strings.TrimSpace(pLine) == "" && i+2 < len(lines) {
pLine = lines[i+2]
}
}
match := regexp.MustCompile("new\\((?:req|baseinfo).([\\w\\d]+)\\)").FindStringSubmatch(pLine)
params := []SwgMap{
{"in": "query",
"name": "key",
"type": "string",
"description": "账号唯一标识",
},
}
if len(match) > 1 {
params = append(params, SwgMap{
"in": "body",
"name": "body",
"description": "请求参数",
"schema": SwgMap{
"$ref": "#/definitions/" + match[1],
},
})
}
handles[name] = SwgMap{
"summary": annotation,
"parameters": params,
"responses": SwgMap{
"200": SwgMap{
"description": "",
},
},
}
}
}
}
for k, list := range routers {
for _, v := range list {
if len(v) < 3 {
// 路由定义不完整,跳过
continue
}
api := fmt.Sprint(k, "/", v[1])
method := strings.ToLower(v[0])
handler := strings.TrimPrefix(v[2], "controller.")
hmap, ok := handles[handler]
if !ok {
// 找不到对应的处理函数,跳过
continue
}
hmap["tags"] = []string{getTag(k)}
paths[api] = SwgMap{method: hmap}
}
}
return paths
}
func analyzeGroupRouter(lines []string, pos int) (int, [][]string) {
handles := make([][]string, 0)
for i, v := range lines[pos:] {
line := strings.TrimSpace(v)
if strings.HasPrefix(line, "{") ||
strings.HasPrefix(line, "//") ||
len(line) == 0 {
continue
} else if strings.HasPrefix(line, "}") {
return pos + i, handles
}
match := regexp.MustCompile("([POSTGE]+)\\(\"/([\\w\\d]+)\", ([\\d\\w.]+)\\)").FindStringSubmatch(line)
if len(match) >= 4 {
handles = append(handles, match[1:])
}
}
return len(lines), handles
}
+280
View File
@@ -0,0 +1,280 @@
package utils
import (
"crypto/md5"
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
"time"
"unsafe"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/protobuf/wechat"
"github.com/lunny/log"
)
func GenDefaultIpadUA() string {
var IPadVersion = int(baseinfo.ClientVersion)
code := IPadVersion
major := 0x0f & (code >> 24)
minor := 0xff & (code >> 16)
patch := 0xff & (code >> 8)
//build := 0xff & (code >> 0)
wxVersion := strconv.Itoa(major) + "." + strconv.Itoa(minor) + "." + strconv.Itoa(patch)
iPadOsVersionS := strings.Replace(baseinfo.IPadOsVersion, ".", "_", -1)
wechatUserAgent := fmt.Sprintf("Mozilla/5.0 (iPad; CPU iPad iPhone OS %s like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/%s(%s) NetType/WIFI Language/zh_CN", iPadOsVersionS, wxVersion, strconv.Itoa(code))
// 打印
log.Info("wechatUserAgent: ", wechatUserAgent)
return wechatUserAgent
}
func ScanIntoGrouppost(URL string) (string, error) {
var err error
postValue := url.Values{
"forBlackberry": {"forceToUsePost"},
}
req, err := http.PostForm(URL, postValue)
if err != nil {
return "", err
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Referer", URL)
req.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
req.Header.Add("User-Agent", "MMozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Mobile/9B176 MicroMessenger/4.3.2")
defer req.Body.Close()
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return "", err
}
return string(body), nil
}
var (
DeviceLenError = errors.New("设备长度错误!")
)
func GenerateWxDat(device string) (string, error) {
if len(device) < 32 {
return "", DeviceLenError
}
datByte := []byte(device)
datHex := hex.EncodeToString(datByte)
str := "62706c6973743030d4010203040506090a582476657273696f6e58246f626a65637473592461726368697665725424746f7012000186a0a2070855246e756c6c5f1020" + datHex + "5f100f4e534b657965644172636869766572d10b0c54726f6f74800108111a232d32373a406375787d0000000000000101000000000000000d0000000000000000000000000000007f"
return str, nil
}
func Md5V(str string) string {
h := md5.New()
h.Write([]byte(str))
return hex.EncodeToString(h.Sum(nil))
}
// 识别手机号码
func IsMobile(mobile string) bool {
result, _ := regexp.MatchString(`^(1[3|4|5|8][0-9]\d{4,8})$`, mobile)
if result {
return true
} else {
return false
}
}
/*
**
获取微信html页面
*/
func GetHTML(url string, headList []*wechat.GetA8KeyRespHeader) (string, []string) {
client := &http.Client{}
reqest, _ := http.NewRequest("GET", url, nil)
reqest.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
reqest.Header.Set("Accept-Charset", "utf-8;q=0.7,*;q=0.3")
//reqest.Header.Set("Accept-Encoding", "gzip, default")//这个有乱码,估计是没有解密,或解压缩
reqest.Header.Set("Accept-Encoding", "utf-8") //这就没有乱码了
reqest.Header.Set("Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3")
reqest.Header.Set("Cache-Control", "max-age=0")
reqest.Header.Set("Connection", "keep-alive")
reqest.Header.Set("Host", url)
reqest.Header.Set("User-Agent", "MMozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Mobile/9B176 MicroMessenger/8.3.2")
for _, head := range headList {
reqest.Header.Add(head.GetName(), head.GetKey())
}
response, _ := client.Do(reqest)
if response.StatusCode == 200 {
defer response.Body.Close()
body, _ := ioutil.ReadAll(response.Body)
bodystr := string(body)
v := response.Header
b := v["Set-Cookie"]
return bodystr, b //response.Header..Get("Set-Cookie")
}
return "", nil
}
func HttpPost(urls string, data url.Values, cookie []string) string {
client := &http.Client{}
retest, err := http.NewRequest("POST", urls, strings.NewReader(data.Encode()))
if err != nil {
log.Error("Http Post NewRequest出错!")
}
str := strings.Replace(strings.Trim(fmt.Sprint(cookie), "[]"), "HttpOnly", "", -1)
retest.Header.Add("Cookie", str)
retest.Header.Add("Content-Type", "application/x-www-form-urlencoded")
ua := GenDefaultIpadUA()
// retest.Header.Add("User-Agent", "Mozilla/5.0 (iPad; CPU OS 12_4_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.15(0x17000f31) NetType/WIFI Language/zh_CN")
retest.Header.Add("User-Agent", ua)
resp, err := client.Do(retest)
if err != nil {
log.Error("Http Post请求出错!")
return ""
}
// defer resp.Body.Close()
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("Http Post请求出错!")
}
return string(body)
}
func HttpGet(urls string, headList []*wechat.GetA8KeyRespHeader) string {
client := &http.Client{}
retest, err := http.NewRequest("GET", urls, nil)
if err != nil {
log.Error("Http Get NewRequest出错!")
}
for _, head := range headList {
retest.Header.Add(head.GetName(), head.GetKey())
}
retest.Header.Add("Accept", "*/*")
retest.Header.Add("Content-Type", "application/octet-stream")
// retest.Header.Add("ResultType", "Byte")
retest.Header.Add("Keep-Alive", "true")
ua := GenDefaultIpadUA()
// retest.Header.Add("User-Agent", "Mozilla/5.0 (iPad; CPU OS 12_4_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.15(0x17000f31) NetType/WIFI Language/zh_CN")
retest.Header.Add("User-Agent", ua)
resp, err := client.Do(retest)
if err != nil {
log.Error("Http Get请求出错!")
return ""
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("Http Get请求出错!")
}
return string(body)
}
func BytesString(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
// 获取传入的时间所在月份的第一天,即某月第一天的0点。如传入time.Now(), 返回当前月份的第一天0点时间。
func GetFirstDateOfMonth(d time.Time) time.Time {
d = d.AddDate(0, 0, -d.Day()+1)
return GetZeroTime(d)
}
// 获取传入的时间所在月份的最后一天,即某月最后一天的0点。如传入time.Now(), 返回当前月份的最后一天0点时间。
func GetLastDateOfMonth(d time.Time) time.Time {
return GetFirstDateOfMonth(d).AddDate(0, 1, -1)
}
// 获取某一天的0点时间
func GetZeroTime(d time.Time) time.Time {
return time.Date(d.Year(), d.Month(), d.Day(), 0, 0, 0, 0, d.Location())
}
// 生成随机设备姓名
var lastName = []string{
"赵", "钱", "孙", "李", "周", "吴", "郑", "王", "冯", "陈", "褚", "卫", "蒋",
"沈", "韩", "杨", "朱", "秦", "尤", "许", "何", "吕", "施", "张", "孔", "曹", "严", "华", "金", "魏",
"陶", "姜", "戚", "谢", "邹", "喻", "柏", "水", "窦", "章", "云", "苏", "潘", "葛", "奚", "范", "彭",
"郎", "鲁", "韦", "昌", "马", "苗", "凤", "花", "方", "任", "袁", "柳", "鲍", "史", "唐", "费", "薛",
"雷", "贺", "倪", "汤", "滕", "殷", "罗", "毕", "郝", "安", "常", "傅", "卞", "齐", "元", "顾", "孟",
"平", "黄", "穆", "萧", "尹", "姚", "邵", "湛", "汪", "祁", "毛", "狄", "米", "伏", "成", "戴", "谈",
"宋", "茅", "庞", "熊", "纪", "舒", "屈", "项", "祝", "董", "梁", "杜", "阮", "蓝", "闵", "季", "贾",
"路", "娄", "江", "童", "颜", "郭", "梅", "盛", "林", "钟", "徐", "邱", "骆", "高", "夏", "蔡", "田",
"樊", "胡", "凌", "霍", "虞", "万", "支", "柯", "管", "卢", "莫", "柯", "房", "裘", "缪", "解", "应",
"宗", "丁", "宣", "邓", "单", "杭", "洪", "包", "诸", "左", "石", "崔", "吉", "龚", "程", "嵇", "邢",
"裴", "陆", "荣", "翁", "荀", "于", "惠", "甄", "曲", "封", "储", "仲", "伊", "宁", "仇", "甘", "武",
"符", "刘", "景", "詹", "龙", "叶", "幸", "司", "黎", "溥", "印", "怀", "蒲", "邰", "从", "索", "赖",
"卓", "屠", "池", "乔", "胥", "闻", "莘", "党", "翟", "谭", "贡", "劳", "逄", "姬", "申", "扶", "堵",
"冉", "宰", "雍", "桑", "寿", "通", "燕", "浦", "尚", "农", "温", "别", "庄", "晏", "柴", "瞿", "阎",
"连", "习", "容", "向", "古", "易", "廖", "庾", "终", "步", "都", "耿", "满", "弘", "匡", "国", "文",
"寇", "广", "禄", "阙", "东", "欧", "利", "师", "巩", "聂", "关", "荆", "司马", "上官", "欧阳", "夏侯",
"诸葛", "闻人", "东方", "赫连", "皇甫", "尉迟", "公羊", "澹台", "公冶", "宗政", "濮阳", "淳于", "单于",
"太叔", "申屠", "公孙", "仲孙", "轩辕", "令狐", "徐离", "宇文", "长孙", "慕容", "司徒", "司空"}
var firstName = []string{
"伟", "刚", "勇", "毅", "俊", "峰", "强", "军", "平", "保", "东", "文", "辉", "力", "明", "永", "健", "世", "广", "志", "义",
"兴", "良", "海", "山", "仁", "波", "宁", "贵", "福", "生", "龙", "元", "全", "国", "胜", "学", "祥", "才", "发", "武", "新",
"利", "清", "飞", "彬", "富", "顺", "信", "子", "杰", "涛", "昌", "成", "康", "星", "光", "天", "达", "安", "岩", "中", "茂",
"进", "林", "有", "坚", "和", "彪", "博", "诚", "先", "敬", "震", "振", "壮", "会", "思", "群", "豪", "心", "邦", "承", "乐",
"绍", "功", "松", "善", "厚", "庆", "磊", "民", "友", "裕", "河", "哲", "江", "超", "浩", "亮", "政", "谦", "亨", "奇", "固",
"之", "轮", "翰", "朗", "伯", "宏", "言", "若", "鸣", "朋", "斌", "梁", "栋", "维", "启", "克", "伦", "翔", "旭", "鹏", "泽",
"晨", "辰", "士", "以", "建", "家", "致", "树", "炎", "德", "行", "时", "泰", "盛", "雄", "琛", "钧", "冠", "策", "腾", "楠",
"榕", "风", "航", "弘", "秀", "娟", "英", "华", "慧", "巧", "美", "娜", "静", "淑", "惠", "珠", "翠", "雅", "芝", "玉", "萍",
"红", "娥", "玲", "芬", "芳", "燕", "彩", "春", "菊", "兰", "凤", "洁", "梅", "琳", "素", "云", "莲", "真", "环", "雪", "荣",
"爱", "妹", "霞", "香", "月", "莺", "媛", "艳", "瑞", "凡", "佳", "嘉", "琼", "勤", "珍", "贞", "莉", "桂", "娣", "叶", "璧",
"璐", "娅", "琦", "晶", "妍", "茜", "秋", "珊", "莎", "锦", "黛", "青", "倩", "婷", "姣", "婉", "娴", "瑾", "颖", "露", "瑶",
"怡", "婵", "雁", "蓓", "纨", "仪", "荷", "丹", "蓉", "眉", "君", "琴", "蕊", "薇", "菁", "梦", "岚", "苑", "婕", "馨", "瑗",
"琰", "韵", "融", "园", "艺", "咏", "卿", "聪", "澜", "纯", "毓", "悦", "昭", "冰", "爽", "琬", "茗", "羽", "希", "欣", "飘",
"育", "滢", "馥", "筠", "柔", "竹", "霭", "凝", "晓", "欢", "霄", "枫", "芸", "菲", "寒", "伊", "亚", "宜", "可", "姬", "舒",
"影", "荔", "枝", "丽", "阳", "妮", "宝", "贝", "初", "程", "梵", "罡", "恒", "鸿", "桦", "骅", "剑", "娇", "纪", "宽", "苛",
"灵", "玛", "媚", "琪", "晴", "容", "睿", "烁", "堂", "唯", "威", "韦", "雯", "苇", "萱", "阅", "彦", "宇", "雨", "洋", "忠",
"宗", "曼", "紫", "逸", "贤", "蝶", "菡", "绿", "蓝", "儿", "翠", "烟", "小", "轩"}
var lastNameLen = len(lastName)
var firstNameLen = len(firstName)
func GetFullName() string {
rand.Seed(time.Now().UnixNano()) //设置随机数种子
var first string //名
for i := 0; i <= rand.Intn(1); i++ { //随机产生2位或者3位的名
first = fmt.Sprint(firstName[rand.Intn(firstNameLen-1)])
}
//返回姓名
return fmt.Sprintf("%s%s", fmt.Sprint(lastName[rand.Intn(lastNameLen-1)]), first)
}
// HttpPostJSON 发送 JSON POST 请求
func HttpPostJSON(urls string, jsonData string, cookie []string) string {
client := &http.Client{}
retest, err := http.NewRequest("POST", urls, strings.NewReader(jsonData))
if err != nil {
log.Error("Http Post JSON NewRequest出错!")
return ""
}
if cookie != nil && len(cookie) > 0 {
str := strings.Replace(strings.Trim(fmt.Sprint(cookie), "[]"), "HttpOnly", "", -1)
retest.Header.Add("Cookie", str)
}
retest.Header.Add("Content-Type", "application/json")
retest.Header.Add("Accept", "application/json, text/plain, */*")
retest.Header.Add("Origin", "https://channels.weixin.qq.com")
ua := GenDefaultIpadUA()
retest.Header.Add("User-Agent", ua)
resp, err := client.Do(retest)
if err != nil {
log.Error("Http Post JSON请求出错!")
return ""
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("Http Post JSON读取响应出错!")
return ""
}
return string(body)
}
+121
View File
@@ -0,0 +1,121 @@
package vo
import (
"fmt"
"xiawan/wx/srv/srvconfig"
"github.com/gin-gonic/gin"
)
type DTO struct {
//自定义提示状态码
Code interface{}
//数据展示
Data interface{}
//提示文本
Text interface{}
//是否成功
Success bool
//62数据
Data62 string
//票据
Ticket string
//微信验证URL(当Ticket不为空时提供)
WechatVerifyUrl string `json:"wechat_verify_url,omitempty"`
//用户操作指引(当Ticket不为空时提供)
VerifyInstructions string `json:"verify_instructions,omitempty"`
}
func NewFail(errMsg string) DTO {
return DTO{
Code: FAIL,
Data: nil,
Text: errMsg,
}
}
func NewFailOffline(errMsg string) DTO {
return DTO{
Code: FAIL_Offline,
Data: nil,
Text: errMsg,
}
}
func NewSuccess(h gin.H, msg string) DTO {
return DTO{
Code: SUCCESS,
Data: h,
Text: msg,
}
}
func NewSuccessObj(h interface{}, msg string) DTO {
return DTO{
Code: SUCCESS,
Data: h,
Text: msg,
}
}
// NewSuccessWithTicket 创建包含ticket和微信验证信息的成功响应
func NewSuccessWithTicket(data interface{}, msg, data62, ticket string) DTO {
dto := DTO{
Code: SUCCESS,
Data: data,
Text: msg,
Success: true,
Data62: data62,
Ticket: ticket,
}
// 如果有ticket,添加微信验证相关信息
if ticket != "" {
dto.WechatVerifyUrl = fmt.Sprintf("https://weixin110.qq.com/security/acct/newreadtemplate?t=extdevsignin/slaveverify&ticket=%s&lang=zh_CN", ticket)
dto.VerifyInstructions = "请按照以下步骤完成微信验证:\n1. 复制上面的 wechat_verify_url 链接\n2. 打开微信客户端\n3. 在微信聊天窗口中粘贴并发送该链接\n4. 点击链接完成验证(8.30又被和谐咯, 现在只能走网页版滑块, 哎~)"
}
return dto
}
func NewFailObj(h interface{}, msg string) DTO {
return DTO{
Code: FAIL,
Data: h,
Text: msg,
}
}
func NewFailUUId(uuid string) DTO {
return DTO{
Code: FAIL_UUID,
Data: nil,
Text: fmt.Sprintf("%s 该链接不存在!", uuid),
}
}
func NewFAILDoesNotBelongToServer(uuid string) DTO {
return DTO{
Code: FAIL_DoesNotBelongToServer,
Data: nil,
Text: fmt.Sprintf("%s 不属于[%s]该服务器实例", uuid, srvconfig.GlobalSetting.TargetIp),
}
}
const (
FAIL_DATA = -1 //数据格式错误
FAIL_UUID = -2 //UUID 不存在
FAIL_Bound = -3 //账号被绑定
FAIL_Offline = -4 //账号掉线
FAIL_DoesNotBelongToServer = -5 //UUId不需要该服务器实例
SUCCESS = 200 // 执行成功
FAIL = 300 // 执行失败
)
+16
View File
@@ -0,0 +1,16 @@
package vo
import "xiawan/wx/protobuf/wechat"
type QYChatroomContactVo struct {
List []*wechat.QYChatroomContactInfo
Key string
}
type DownloadVoiceData struct {
Base64 []byte
VoiceLength uint32
}
type GroupData struct {
Count int64
List interface{}
}