Initial commit
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
package versionSer
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"stat/api/proto"
|
||||
"stat/common/utils"
|
||||
downloadinfo "stat/models/downloadinfo"
|
||||
"stat/models/versionMod"
|
||||
"stat/service/cacheSer"
|
||||
"stat/statg"
|
||||
"time"
|
||||
|
||||
"github.com/xxjwxc/public/myglobal/snowflake"
|
||||
)
|
||||
|
||||
func GenerateConfigFile(origin, target, configFile, DC, PC string) ([]byte, string) {
|
||||
if len(DC) > 0 && len(PC) > 0 {
|
||||
node, err := snowflake.NewNode(1)
|
||||
if err == nil {
|
||||
id := node.Generate()
|
||||
target = fmt.Sprintf("%s?dc=%s&pc=%s&UID=%d", target, DC, PC, id)
|
||||
}
|
||||
} else if len(DC) > 0 {
|
||||
node, err := snowflake.NewNode(1)
|
||||
if err == nil {
|
||||
id := node.Generate()
|
||||
target = fmt.Sprintf("%s?dc=%s&UID=%d", target, DC, id)
|
||||
}
|
||||
} else if len(PC) > 0 {
|
||||
node, err := snowflake.NewNode(1)
|
||||
if err == nil {
|
||||
id := node.Generate()
|
||||
target = fmt.Sprintf("%s?pc=%s&UID=%d", target, PC, id)
|
||||
}
|
||||
} else {
|
||||
node, err := snowflake.NewNode(1)
|
||||
if err == nil {
|
||||
id := node.Generate()
|
||||
target = fmt.Sprintf("%s?UID=%d", target, id)
|
||||
}
|
||||
}
|
||||
target = fmt.Sprintf("%s&isLight=true", target)
|
||||
output, _, err := readFile("conf/"+configFile, origin, target)
|
||||
if err != nil {
|
||||
output, _ = os.ReadFile("conf/" + configFile)
|
||||
}
|
||||
return output, configFile
|
||||
}
|
||||
|
||||
func GetAppConfig(appId int32) (origin, target, config string) {
|
||||
endpoint := statg.GlobalAppIdEndpoints[appId]
|
||||
if endpoint != nil {
|
||||
origin = endpoint.H5Origin
|
||||
target = endpoint.H5Target
|
||||
config = endpoint.H5Config
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PageButtonClick 落地页点击下载返回最新的下载链接
|
||||
func GetH5Config(ctx context.Context, req *proto.H5ConfigReq, userAgent string, ip string) ([]byte, string) {
|
||||
req.DC = utils.RepairDC(req.DC)
|
||||
downloadInfo := &downloadinfo.DownloadInfoModel{
|
||||
AppId: req.AppId,
|
||||
IP: ip,
|
||||
PC: req.PC,
|
||||
DC: req.DC,
|
||||
SysType: "light",
|
||||
PackageType: versionMod.Light,
|
||||
PeerIP: ip,
|
||||
Domain: req.Domain,
|
||||
UserAgent: userAgent,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
cacheSer.Writers.LandPageClickWriter.Add(downloadInfo)
|
||||
origin, target, config := GetAppConfig(req.AppId)
|
||||
if origin == "" || target == "" || config == "" {
|
||||
return nil, "madou.mobileconfig"
|
||||
}
|
||||
return GenerateConfigFile(origin, target, config, req.DC, req.PC)
|
||||
}
|
||||
|
||||
func readFile(filePath string, origin, target string) ([]byte, bool, error) {
|
||||
var err error
|
||||
var data []byte
|
||||
cacheKey := fmt.Sprintf("h5config#%s", filePath)
|
||||
if cache, exists := cacheSer.Cache.Get(cacheKey); exists {
|
||||
if item, ok := cache.([]byte); ok {
|
||||
data = item
|
||||
}
|
||||
}
|
||||
if data == nil {
|
||||
data, err = os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
cacheSer.Cache.Set(cacheKey, data, 0)
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(bytes.NewReader(data))
|
||||
needHandle := false
|
||||
output := make([]byte, 0)
|
||||
for {
|
||||
line, _, err := reader.ReadLine()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return output, needHandle, nil
|
||||
}
|
||||
return nil, needHandle, err
|
||||
}
|
||||
if ok, _ := regexp.Match(origin, line); ok {
|
||||
reg := regexp.MustCompile(origin)
|
||||
newByte := reg.ReplaceAll(line, []byte(target))
|
||||
output = append(output, newByte...)
|
||||
output = append(output, []byte("\n")...)
|
||||
if !needHandle {
|
||||
needHandle = true
|
||||
}
|
||||
} else {
|
||||
output = append(output, line...)
|
||||
output = append(output, []byte("\n")...)
|
||||
}
|
||||
}
|
||||
return output, needHandle, nil
|
||||
}
|
||||
|
||||
func GetH5ConfigV2(ctx context.Context, req *proto.H5ConfigReq, ip string) proto.H5ConfigV2Resp {
|
||||
if req.AppId == 694 {
|
||||
return proto.H5ConfigV2Resp{
|
||||
URL: "http://awll.yangjiaolian.top/91seman.mobileconfig",
|
||||
}
|
||||
}
|
||||
|
||||
return proto.H5ConfigV2Resp{}
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
package versionSer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"stat/common/crypt"
|
||||
"stat/common/redis"
|
||||
"stat/common/utils"
|
||||
"stat/models/channelmod"
|
||||
"stat/models/channelpackage"
|
||||
"stat/models/versionMod"
|
||||
"stat/statg"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
func GetChannelApkOutputPath(appId int32, channel string, version string, date time.Time) string {
|
||||
endpoint := statg.GlobalAppIdEndpoints[appId]
|
||||
if endpoint == nil {
|
||||
return ""
|
||||
}
|
||||
if endpoint.NameEn == "" {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf(`%s/package/%s_%s_%s-%s.apk`, endpoint.NameEn, endpoint.NameEn, date.Format("20060102150405"), version, channel)
|
||||
}
|
||||
|
||||
func GetPackageBaseDomain(appId int32) []string {
|
||||
packageUrlString := statg.Conf.URL.PackageUrl
|
||||
if appId == 999 && len(statg.Conf.URL.BiliPackageUrl) > 0 {
|
||||
packageUrlString = statg.Conf.URL.BiliPackageUrl
|
||||
} else if appId == 777 && len(statg.Conf.URL.HuanqiuPackageUrl) > 0 {
|
||||
packageUrlString = statg.Conf.URL.HuanqiuPackageUrl
|
||||
} else if appId == 444 && len(statg.Conf.URL.ManhuaPackageUrl) > 0 {
|
||||
packageUrlString = statg.Conf.URL.ManhuaPackageUrl
|
||||
}
|
||||
packageUrlArray := strings.Split(packageUrlString, ";")
|
||||
return packageUrlArray
|
||||
}
|
||||
|
||||
func ApkReportErrorLinks(ctx context.Context, pack *channelpackage.ChannelPackage, msg []string) {
|
||||
if time.Since(pack.CheckLink) > channelpackage.ApkCheckLinkDuration {
|
||||
filter := bson.M{
|
||||
channelpackage.FN.ChannelPackage.Id: pack.Id,
|
||||
channelpackage.FN.ChannelPackage.CheckLink: pack.CheckLink,
|
||||
}
|
||||
update := bson.M{
|
||||
"$set": bson.M{
|
||||
channelpackage.FN.ChannelPackage.CheckLink: time.Now(),
|
||||
},
|
||||
}
|
||||
// 更新成功是生成apk的必要条件
|
||||
if err := channelpackage.UpdateOneChannelPackage(ctx, filter, update); err != nil {
|
||||
return
|
||||
}
|
||||
// 汇报TG
|
||||
text := fmt.Sprintf("检测到渠道包链接无法下载:\n")
|
||||
text += fmt.Sprintf("渠道:【%s】\n", pack.Channel)
|
||||
text += fmt.Sprintf("应用:【%s,ID=%d】\n", statg.GlobalEndpoints.GetAppShortNameById(pack.AppId), pack.AppId)
|
||||
text += fmt.Sprintf("版本:【%s】\n", pack.Version)
|
||||
text += fmt.Sprintf("文件:【%s】\n", pack.FileName)
|
||||
text += fmt.Sprintf("生成:【%s】\n", pack.GenTime.Format(time.DateTime))
|
||||
text += fmt.Sprintf("错误: %s\n", msg)
|
||||
text += fmt.Sprintf("提示: /channel_apk -channel=%s -app=%d", pack.Channel, pack.AppId)
|
||||
statg.Bot.SendChannelApkMessage(text)
|
||||
}
|
||||
}
|
||||
|
||||
func ApkCheckLinks(pack *channelpackage.ChannelPackage, domains []string) (bool, []string) {
|
||||
ctx := context.Background()
|
||||
links := pack.GetAllLink(domains)
|
||||
if len(links) <= 0 {
|
||||
return false, links
|
||||
}
|
||||
var msg string
|
||||
for i := 0; i < len(links); i++ {
|
||||
link := links[i]
|
||||
err := CheckPackageLink(ctx, link)
|
||||
if err != nil {
|
||||
msg += fmt.Sprintf("【链接:%s】错误:%s\n", link, err.Error())
|
||||
}
|
||||
}
|
||||
return false, links
|
||||
}
|
||||
|
||||
func TryMakeChannelApk(ctx context.Context, appId int32, channel string, version *versionMod.VersionModel, pack *channelpackage.ChannelPackage, reason string, forceMake bool, logBody io.Writer) (*channelpackage.ChannelPackage, error) {
|
||||
// 检查版本有没有原始链接
|
||||
if len(version.Link) <= 0 {
|
||||
return pack, fmt.Errorf("version %d link is empty", version.Id)
|
||||
}
|
||||
// 先检查渠道是否存在
|
||||
remoteFile := GetChannelApkOutputPath(appId, channel, version.VersionNum, time.Now())
|
||||
chanInfo, err := channelmod.FindOneChannelInfo(ctx, bson.M{
|
||||
channelmod.FN.ChannelInfo.Channel: channel,
|
||||
})
|
||||
if err != nil {
|
||||
return pack, fmt.Errorf("渠道包生成失败,查询渠道【%s】出错: %v", channel, err)
|
||||
}
|
||||
if !chanInfo.Status {
|
||||
return pack, fmt.Errorf("渠道包生成失败,渠道【%s】已被禁用,请启用该渠道后再次尝试", channel)
|
||||
}
|
||||
if !slices.Contains(chanInfo.AppIds, appId) {
|
||||
return pack, fmt.Errorf("渠道包生成失败,应用【%s, ID=%d】未在渠道【%s】代理应用的列表中【%v】", statg.GlobalEndpoints.GetAppShortNameById(appId), appId, channel, chanInfo.AppIds)
|
||||
}
|
||||
// 开始生成
|
||||
lockCode := rand.Int63()
|
||||
packID := primitive.NewObjectID()
|
||||
now := time.Now()
|
||||
if pack == nil {
|
||||
pack = &channelpackage.ChannelPackage{
|
||||
Id: packID,
|
||||
AppId: appId,
|
||||
Channel: channel,
|
||||
Version: version.VersionNum,
|
||||
FileName: version.Md5,
|
||||
UrlPath: remoteFile,
|
||||
Status: channelpackage.ChanApkStatusMaking,
|
||||
Desc: version.Info,
|
||||
Reason: reason,
|
||||
GenError: "第一次生成",
|
||||
GenCount: 0,
|
||||
LockCode: lockCode,
|
||||
LockTime: now,
|
||||
GenTime: now,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
// 插入成功是生成apk的必要条件
|
||||
serr := channelpackage.InsertOneChannelPackage(ctx, pack)
|
||||
if serr != nil {
|
||||
return pack, fmt.Errorf("渠道包生成失败,插入渠道包记录失败: \n渠道:【%s】\n应用:【%s,ID=%d】\n错误: %s", channel, statg.GlobalEndpoints.GetAppShortNameById(appId), appId, serr.Error())
|
||||
}
|
||||
} else {
|
||||
packID = pack.Id
|
||||
if ok, left, tip := pack.CanMake(forceMake); !ok {
|
||||
return pack, fmt.Errorf("渠道包生成失败【%s】,请在过【%v】后,再次尝试生成渠道【%s】的渠道包", tip, left, channel)
|
||||
}
|
||||
filter := bson.M{
|
||||
channelpackage.FN.ChannelPackage.Id: packID,
|
||||
channelpackage.FN.ChannelPackage.LockCode: pack.LockCode,
|
||||
}
|
||||
update := bson.M{
|
||||
"$set": bson.M{
|
||||
channelpackage.FN.ChannelPackage.LockCode: lockCode,
|
||||
channelpackage.FN.ChannelPackage.LockTime: time.Now(),
|
||||
channelpackage.FN.ChannelPackage.GenTime: time.Now(),
|
||||
},
|
||||
}
|
||||
// 更新成功是生成apk的必要条件
|
||||
if serr := channelpackage.UpdateOneChannelPackage(ctx, filter, update); serr != nil {
|
||||
return pack, fmt.Errorf("update failed, code:%d, msg:%s", serr.Code, serr.Msg)
|
||||
}
|
||||
}
|
||||
filter := bson.M{
|
||||
channelpackage.FN.ChannelPackage.Id: packID,
|
||||
channelpackage.FN.ChannelPackage.LockCode: lockCode,
|
||||
}
|
||||
err = makeChannelApk(version.Link[0], channel, remoteFile, logBody)
|
||||
if err != nil {
|
||||
// write error
|
||||
update := bson.M{
|
||||
"$inc": bson.M{
|
||||
channelpackage.FN.ChannelPackage.GenCount: 1,
|
||||
},
|
||||
"$set": bson.M{
|
||||
channelpackage.FN.ChannelPackage.LockTime: time.Time{}, // 重置锁
|
||||
channelpackage.FN.ChannelPackage.GenError: err.Error(),
|
||||
channelpackage.FN.ChannelPackage.Status: channelpackage.ChanApkStatusFailure,
|
||||
},
|
||||
}
|
||||
_ = channelpackage.UpdateOneChannelPackage(ctx, filter, update)
|
||||
return pack, err
|
||||
}
|
||||
update := bson.M{
|
||||
"$set": bson.M{
|
||||
channelpackage.FN.ChannelPackage.GenError: "success",
|
||||
channelpackage.FN.ChannelPackage.UrlPath: remoteFile,
|
||||
channelpackage.FN.ChannelPackage.FileName: version.Md5,
|
||||
channelpackage.FN.ChannelPackage.Version: version.VersionNum,
|
||||
channelpackage.FN.ChannelPackage.GenTime: time.Now(),
|
||||
channelpackage.FN.ChannelPackage.Reason: reason,
|
||||
channelpackage.FN.ChannelPackage.Desc: version.Info,
|
||||
channelpackage.FN.ChannelPackage.LockTime: time.Time{}, // 重置锁
|
||||
channelpackage.FN.ChannelPackage.Status: channelpackage.ChanApkStatusSuccess,
|
||||
},
|
||||
}
|
||||
if serr := channelpackage.UpdateOneChannelPackage(ctx, filter, update); serr != nil {
|
||||
return pack, fmt.Errorf("update failed,, code:%d, msg:%s", serr.Code, serr.Msg)
|
||||
}
|
||||
|
||||
//if forceMake {
|
||||
// // 自动开启渠道自动打包
|
||||
// update := bson.M{
|
||||
// "$set": bson.M{channelmod.FN.ChannelInfo.AutoGenApk: true},
|
||||
// }
|
||||
// _ = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channel}, update)
|
||||
//}
|
||||
|
||||
pack2, serr := channelpackage.FindOneChannelPackage(ctx, filter)
|
||||
if serr != nil {
|
||||
return pack, fmt.Errorf("find failed, code:%d, msg:%s", serr.Code, serr.Msg)
|
||||
}
|
||||
return pack2, nil
|
||||
}
|
||||
|
||||
func makeChannelApk(downUrl string, channel string, remoteFile string, logBody io.Writer) error {
|
||||
var out []byte
|
||||
var err error
|
||||
// 生成临时apk文件名
|
||||
step := 1
|
||||
tempPath := os.TempDir()
|
||||
srcName := utils.RandStringBytes(12)
|
||||
dstName := utils.RandStringBytes(12)
|
||||
tmpSrcApk := filepath.Join(tempPath, srcName+".apk")
|
||||
tmpDstPath := filepath.Join(tempPath, dstName)
|
||||
if logBody != nil {
|
||||
logBody.Write([]byte(fmt.Sprintf("tmpSrcApk=%s\n", tmpSrcApk)))
|
||||
logBody.Write([]byte(fmt.Sprintf("tmpDstPath=%s\n", tmpDstPath)))
|
||||
}
|
||||
// 下载apk原始文件
|
||||
step = 2
|
||||
cmd := exec.Command("/usr/bin/curl",
|
||||
"-o",
|
||||
tmpSrcApk,
|
||||
downUrl)
|
||||
out, err = cmd.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w, step=%d", err, step)
|
||||
}
|
||||
if logBody != nil {
|
||||
logBody.Write([]byte(fmt.Sprintf("step=%d, cmd=%s, out=%s\n", step, cmd.String(), string(out))))
|
||||
}
|
||||
defer func() {
|
||||
_ = os.Remove(tmpSrcApk)
|
||||
}()
|
||||
step = 3
|
||||
// 生成渠道包
|
||||
cmd = exec.Command("/usr/bin/java", // 测试服 /tools/jdk/bin/java 正式服 /usr/bin/java
|
||||
"-jar",
|
||||
"/usr/lib/jar/packer-ng-2.0.1.jar",
|
||||
"generate",
|
||||
fmt.Sprintf("--channels=%s", channel),
|
||||
fmt.Sprintf("--output=%s", tmpDstPath),
|
||||
tmpSrcApk)
|
||||
out, err = cmd.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w, step=%d", err, step)
|
||||
}
|
||||
if logBody != nil {
|
||||
logBody.Write([]byte(fmt.Sprintf("step=%d, cmd=%s, out=%s\n", step, cmd.String(), string(out))))
|
||||
}
|
||||
step = 4
|
||||
// 上传到下载服务器
|
||||
fileName := filepath.Join(tmpDstPath, fmt.Sprintf("%s-%s.apk", srcName, channel))
|
||||
defer func() {
|
||||
_ = os.Remove(fileName)
|
||||
}()
|
||||
cmd = exec.Command("/usr/bin/curl",
|
||||
"-T",
|
||||
fileName,
|
||||
"-u",
|
||||
"213apk:5JLm6dKS42Nsxmif",
|
||||
fmt.Sprintf("ftp://216.83.58.213:21/%s", remoteFile))
|
||||
out, err = cmd.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w, step=%d", err, step)
|
||||
}
|
||||
if logBody != nil {
|
||||
logBody.Write([]byte(fmt.Sprintf("step=%d, cmd=%s, out=%s\n", step, cmd.String(), string(out))))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SendLinkErrorMessageToBot(text string) {
|
||||
defer utils.RecoverError(nil)
|
||||
key := crypt.StrToMd5(text)
|
||||
hash := redis.NewHash(redis.StatRds.Client(), redis.GetDownloadCheckBotMsgHashKey())
|
||||
_, _ = hash.Expire(time.Hour)
|
||||
if exists, err := hash.Exists(key); err == nil && !exists {
|
||||
_ = statg.Bot.SendMonitorMessage(text)
|
||||
_, _ = hash.Set(key, text)
|
||||
}
|
||||
}
|
||||
|
||||
func CheckChannelApkAutoGen(ctx context.Context, appId int32, channel string, version *versionMod.VersionModel, pack *channelpackage.ChannelPackage) {
|
||||
var err error
|
||||
if apkGenLock.LockedCount() > channelpackage.ApkGenerateParallelMax {
|
||||
return // 不能超出并行任务数
|
||||
}
|
||||
lockKey := fmt.Sprintf("id=%d#ch=%s", appId, channel)
|
||||
expired := time.Now().Add(5 * time.Minute)
|
||||
if locked := apkGenLock.TryLock(lockKey, expired); locked {
|
||||
defer apkGenLock.UnLock(lockKey, expired)
|
||||
bEnable := statg.Conf.ApkGenEnable
|
||||
if !bEnable {
|
||||
channelInfo, _ := channelmod.FindOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channel})
|
||||
if channelInfo != nil && channelInfo.AutoGenApk {
|
||||
bEnable = true
|
||||
}
|
||||
}
|
||||
if bEnable {
|
||||
canMake := pack == nil
|
||||
if !canMake {
|
||||
canMake, _, _ = pack.CanMake(false)
|
||||
}
|
||||
if canMake {
|
||||
go func() {
|
||||
defer utils.RecoverError(nil)
|
||||
pack, err = TryMakeChannelApk(ctx, appId, channel, version, pack, "", false, nil)
|
||||
if err == nil && pack != nil {
|
||||
text := fmt.Sprintf("渠道包已全自动生成:\n")
|
||||
text += fmt.Sprintf("渠道:【%s】\n", pack.Channel)
|
||||
text += fmt.Sprintf("应用:【%s,ID=%d】\n", statg.GlobalEndpoints.GetAppShortNameById(pack.AppId), pack.AppId)
|
||||
text += fmt.Sprintf("版本:【%s】\n", version.VersionNum)
|
||||
text += fmt.Sprintf("文件:【%s】\n", version.Md5)
|
||||
text += fmt.Sprintf("发布:【%s】\n", version.CreatedAt.Format(time.DateTime))
|
||||
text += fmt.Sprintf("生成:【%s】\n", pack.GenTime.Format(time.DateTime))
|
||||
baseUrls := GetPackageBaseDomain(pack.AppId)
|
||||
for index, baseUrl := range baseUrls {
|
||||
text += fmt.Sprintf("下载链接-%d: %s\n", index, pack.GetRandomLink([]string{baseUrl}))
|
||||
}
|
||||
statg.Bot.SendChannelApkMessage(text)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
package versionSer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"stat/api/proto"
|
||||
"stat/common/stdLog"
|
||||
"stat/common/utils"
|
||||
"stat/models/channelpackage"
|
||||
"stat/models/downloadCpc"
|
||||
downloadinfo "stat/models/downloadinfo"
|
||||
"stat/models/versionMod"
|
||||
"stat/service/cacheSer"
|
||||
"stat/service/crossSer"
|
||||
"stat/statg"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
type ChannelParams struct {
|
||||
PC string `json:"i" bson:"i"` //推广码
|
||||
DC string `json:"dc" bson:"dc"` //商区序列
|
||||
CH string `json:"ch" bson:"ch"` //渠道
|
||||
}
|
||||
|
||||
var (
|
||||
appSvrUrlDict = make(map[int32]string)
|
||||
appSvrIdxDict = make(map[int32]statg.ServerIndex)
|
||||
once sync.Once
|
||||
apkGenLock = utils.NewExpiredLock()
|
||||
landPageVisit = utils.NewExpiredLock()
|
||||
landPageClick = utils.NewExpiredLock()
|
||||
landPageVisitIpTimeout = time.Hour // 每个IP,1个小时内无论访问多少次,都算一次
|
||||
landPageClickIpTimeout = time.Hour // 每个IP,1个小时内无论访问多少次,都算一次
|
||||
)
|
||||
|
||||
func Init() {
|
||||
once.Do(func() {
|
||||
for _, endpoint := range statg.GlobalEndpoints {
|
||||
appSvrIdxDict[endpoint.AppId] = endpoint.OwnerIndex
|
||||
if url, ok := statg.Conf.InnerServers[endpoint.OwnerIndex]; ok {
|
||||
appSvrUrlDict[endpoint.AppId] = url
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// CrossButtonClick 跨服务器点击下载返回最新的下载链接
|
||||
func CrossButtonClick(ctx context.Context, userAgent string, peerIP string, req *proto.PageButtonClickReq) (resp *proto.PageButtonClickResp, err error) {
|
||||
req.Ip = peerIP
|
||||
srvIdx := appSvrIdxDict[req.AppId]
|
||||
if srvIdx == statg.ServerIndexNone {
|
||||
return nil, fmt.Errorf("appid %d not found", req.AppId)
|
||||
}
|
||||
if srvIdx == statg.Conf.ServerIndex {
|
||||
return PageButtonClick(ctx, peerIP, userAgent, req)
|
||||
}
|
||||
addr := appSvrUrlDict[req.AppId]
|
||||
if addr == "" {
|
||||
return nil, fmt.Errorf("appid %d server not found", req.AppId)
|
||||
}
|
||||
res := crossSer.CrossAppDownloadRes{}
|
||||
err = crossSer.InnerRequest(addr+"/api/stat/inner/appDownload", req, &res, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res.Data == nil {
|
||||
return nil, fmt.Errorf("data not found")
|
||||
}
|
||||
return res.Data, nil
|
||||
}
|
||||
|
||||
// PageButtonClick 落地页点击下载返回最新的下载链接
|
||||
func PageButtonClick(ctx context.Context, userAgent string, peerIP string, req *proto.PageButtonClickReq) (resp *proto.PageButtonClickResp, err error) {
|
||||
resp = &proto.PageButtonClickResp{}
|
||||
|
||||
var channelCode ChannelParams
|
||||
// TODO 存储记录
|
||||
_ = json.Unmarshal([]byte(req.Channel), &channelCode)
|
||||
|
||||
if req.Ip == "" {
|
||||
req.Ip = peerIP
|
||||
}
|
||||
channelCode.DC = utils.RepairDC(channelCode.DC)
|
||||
|
||||
if req.Terminal == "ios" && req.PackageType == versionMod.Light {
|
||||
var h5Req = &proto.H5ConfigReq{
|
||||
AppId: req.AppId,
|
||||
DC: channelCode.DC,
|
||||
PC: channelCode.PC,
|
||||
Domain: channelCode.PC,
|
||||
}
|
||||
resp.Terminal = req.Terminal
|
||||
resp.PackageType = req.PackageType
|
||||
resp.Status = true
|
||||
resp.LightData, _ = GetH5Config(ctx, h5Req, userAgent, req.Ip)
|
||||
return
|
||||
}
|
||||
|
||||
downloadInfo := &downloadinfo.DownloadInfoModel{
|
||||
AppId: req.AppId,
|
||||
IP: req.Ip,
|
||||
Domain: req.Domain,
|
||||
PC: channelCode.PC,
|
||||
DC: channelCode.DC,
|
||||
CH: channelCode.CH,
|
||||
SysType: strings.ToLower(strings.TrimSpace(req.Terminal)),
|
||||
PackageType: req.PackageType,
|
||||
PeerIP: peerIP,
|
||||
UserAgent: userAgent,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
//和APP统一
|
||||
if req.PackageType == versionMod.Shop {
|
||||
downloadInfo.SysType = "h5_ios"
|
||||
}
|
||||
|
||||
if landPageClick.TryLock(req.Ip, time.Now().Add(landPageClickIpTimeout)) {
|
||||
cacheSer.Writers.LandPageClickWriter.Add(downloadInfo)
|
||||
}
|
||||
if downloadInfo.IP == "" {
|
||||
downloadInfo.IP = peerIP
|
||||
}
|
||||
|
||||
var data *versionMod.VersionModel
|
||||
cacheKey := fmt.Sprintf("version_button#appId:%d#%s#%d", req.AppId, req.Terminal, req.PackageType)
|
||||
if cache, exists := cacheSer.Cache.Get(cacheKey); exists {
|
||||
if item, ok := cache.(*versionMod.VersionModel); ok {
|
||||
data = item
|
||||
}
|
||||
}
|
||||
if data == nil {
|
||||
data, err = versionMod.ButtonClick(ctx, req.AppId, req.Terminal, req.PackageType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cacheSer.Cache.Set(cacheKey, data, 2*time.Minute)
|
||||
}
|
||||
|
||||
resp.PackageType = data.PackageType
|
||||
resp.Status = data.Status
|
||||
resp.Terminal = data.Terminal
|
||||
resp.VersionNum = data.VersionNum
|
||||
resp.BackUrl = data.BackLink
|
||||
resp.Link = append(resp.Link, data.Link...)
|
||||
|
||||
// IOS的TF包管理
|
||||
if req.PackageType == versionMod.Tf {
|
||||
// 1. FT包管理
|
||||
|
||||
for _, tfInfo := range data.TfInfo {
|
||||
one := proto.TfInfo{
|
||||
AppName: tfInfo.AppName,
|
||||
AppIcon: tfInfo.AppIcon,
|
||||
URL: tfInfo.URL,
|
||||
}
|
||||
resp.Tf = append(resp.Tf, one)
|
||||
}
|
||||
|
||||
if len(resp.Tf) == 0 {
|
||||
resp.Tf = make([]proto.TfInfo, 0)
|
||||
for _, v := range data.Link {
|
||||
tmp := proto.TfInfo{
|
||||
URL: v,
|
||||
}
|
||||
if len(data.BackLink) > 0 {
|
||||
tmp.BackUrl = data.BackLink
|
||||
}
|
||||
resp.Tf = append(resp.Tf, tmp)
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
if data.Terminal == "ios" {
|
||||
// 配置多个随机返回一个
|
||||
if len(data.Link) >= 1 {
|
||||
resp.Link = make([]string, 0)
|
||||
index := rand.Intn(len(data.Link))
|
||||
resp.Link = append(resp.Link, data.Link[index])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 新增批量打包逻辑
|
||||
if req.Terminal == "android" && len(data.Md5) > 0 {
|
||||
randTime := int64(60*60) + int64(rand.Intn(60*60))
|
||||
|
||||
requestPackageTime := time.Now().Add(-time.Second * time.Duration(randTime))
|
||||
// 下载链接
|
||||
projectString := ""
|
||||
beginPath := ""
|
||||
pathList := strings.Split(strings.Replace(data.Md5, ".apk", "", -1), "_")
|
||||
if len(pathList) == 3 {
|
||||
beginPath = strings.TrimSpace(pathList[len(pathList)-1])
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
endpoint := statg.GlobalAppIdEndpoints[req.AppId]
|
||||
if endpoint != nil {
|
||||
projectString = fmt.Sprintf("%s/out/%s/%s%s_", endpoint.NameEn, beginPath, endpoint.NameEn, requestPackageTime.Format("20060102")[2:])
|
||||
}
|
||||
if projectString != "" {
|
||||
packageUrlString := statg.Conf.URL.PackageUrl
|
||||
if req.AppId == 999 && len(statg.Conf.URL.BiliPackageUrl) > 0 {
|
||||
packageUrlString = statg.Conf.URL.BiliPackageUrl
|
||||
} else if req.AppId == 777 && len(statg.Conf.URL.HuanqiuPackageUrl) > 0 {
|
||||
packageUrlString = statg.Conf.URL.HuanqiuPackageUrl
|
||||
} else if req.AppId == 444 && len(statg.Conf.URL.ManhuaPackageUrl) > 0 {
|
||||
packageUrlString = statg.Conf.URL.ManhuaPackageUrl
|
||||
}
|
||||
|
||||
packageUrlArray := strings.Split(packageUrlString, ";")
|
||||
|
||||
if len(packageUrlArray) > 0 {
|
||||
if len(channelCode.DC) > 0 { //&&
|
||||
pack, serr := channelpackage.FindOneChannelPackage(ctx, bson.M{
|
||||
channelpackage.FN.ChannelPackage.AppId: req.AppId,
|
||||
channelpackage.FN.ChannelPackage.Channel: channelCode.DC,
|
||||
channelpackage.FN.ChannelPackage.Version: data.VersionNum,
|
||||
channelpackage.FN.ChannelPackage.FileName: data.Md5,
|
||||
})
|
||||
if serr == nil || serr.Code == stdLog.DataNotExist {
|
||||
if pack != nil && pack.Status == channelpackage.ChanApkStatusSuccess {
|
||||
pass, links := ApkCheckLinks(pack, packageUrlArray)
|
||||
if pass {
|
||||
resp.Link = links
|
||||
_ = pack.IncDownCount(ctx)
|
||||
return resp, nil
|
||||
} else {
|
||||
ApkReportErrorLinks(ctx, pack, links)
|
||||
}
|
||||
} else {
|
||||
CheckChannelApkAutoGen(ctx, req.AppId, channelCode.DC, data, pack)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 默认使用第一个
|
||||
passedLinks := make([]string, 0)
|
||||
for _, packageLink := range packageUrlArray {
|
||||
link := strings.TrimSpace(packageLink + projectString + data.Md5)
|
||||
checklink := link
|
||||
cerr := CheckPackageLink(ctx, checklink)
|
||||
if cerr != nil {
|
||||
// log.Error("AppVersion", log.Any("link", link), log.E(cerr))
|
||||
// if statg.Conf.RunMod == consts.RunModRelease && !slices.Contains([]int32{666, 998}, req.AppId) {
|
||||
// appDict, _ := appInfoMod.GetAllAppIdNameMap(ctx)
|
||||
// text := fmt.Sprintf("【%s】Android 下载链接异常:\n链接:%s\n错误:%s\n", appDict[req.AppId], link, cerr.Error())
|
||||
// SendLinkErrorMessageToBot(text)
|
||||
// }
|
||||
} else {
|
||||
passedLinks = append(passedLinks, link)
|
||||
}
|
||||
}
|
||||
if len(passedLinks) > 0 {
|
||||
resp.Link = passedLinks
|
||||
}
|
||||
} else {
|
||||
link := strings.TrimSpace(packageUrlString + projectString + data.Md5)
|
||||
resp.Link = []string{link}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// PageButtonList 落地页获取下载按钮
|
||||
func PageButtonList(ctx context.Context, isIos bool, peerIP string, req *proto.PageButtonListReq) (resp *proto.PageButtonListResp, err error) {
|
||||
resp = &proto.PageButtonListResp{
|
||||
IosTF: false,
|
||||
}
|
||||
var channelCode ChannelParams
|
||||
// TODO 存储记录
|
||||
_ = json.Unmarshal([]byte(req.Channel), &channelCode)
|
||||
|
||||
channelCode.DC = utils.RepairDC(channelCode.DC)
|
||||
|
||||
req.Ip = peerIP
|
||||
|
||||
if req.Ip != "" {
|
||||
logInfo := &downloadCpc.DownloadCpc{
|
||||
AppId: req.AppId,
|
||||
IP: req.Ip,
|
||||
PC: channelCode.PC,
|
||||
DC: channelCode.DC,
|
||||
CH: channelCode.CH,
|
||||
PeerIP: peerIP,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
if landPageVisit.TryLock(req.Ip, time.Now().Add(landPageVisitIpTimeout)) {
|
||||
cacheSer.Writers.LandPageVisitWriter.Add(logInfo)
|
||||
}
|
||||
}
|
||||
cacheKey := fmt.Sprintf("version_button_list#appId:%d", req.AppId)
|
||||
var buttons versionMod.VersionList
|
||||
if cache, exists := cacheSer.Cache.Get(cacheKey); exists {
|
||||
if list, ok := cache.(versionMod.VersionList); ok {
|
||||
buttons = list
|
||||
}
|
||||
}
|
||||
if buttons == nil {
|
||||
buttons, err = versionMod.ButtonList(ctx, req.AppId)
|
||||
if err != nil {
|
||||
err = errors.New("服务器内部错误")
|
||||
return
|
||||
}
|
||||
cacheSer.Cache.Set(cacheKey, buttons, 0)
|
||||
}
|
||||
|
||||
if len(buttons) < 1 {
|
||||
err = errors.New("请开启版本")
|
||||
return
|
||||
}
|
||||
|
||||
for _, value := range buttons {
|
||||
if isIos && value.Terminal == "android" {
|
||||
// 如果是ios设备请求,记录是android 跳过
|
||||
continue
|
||||
}
|
||||
if value.PackageType == versionMod.Enterprise && value.Terminal == "ios" {
|
||||
resp.IosDown = true
|
||||
}
|
||||
if value.PackageType == versionMod.Shop && value.Terminal == "ios" {
|
||||
resp.IosStore = true
|
||||
if len(value.Link) > 0 {
|
||||
resp.IosLink = value.Link[0]
|
||||
}
|
||||
}
|
||||
if value.PackageType == versionMod.Tf && value.Terminal == "ios" {
|
||||
resp.IosTF = true
|
||||
}
|
||||
if value.PackageType == versionMod.Light && value.Terminal == "ios" {
|
||||
resp.IosH5 = true
|
||||
}
|
||||
}
|
||||
// android下载按钮
|
||||
packageUrlString := statg.Conf.URL.PackageUrl
|
||||
if req.AppId == 999 && len(statg.Conf.URL.BiliPackageUrl) > 0 {
|
||||
packageUrlString = statg.Conf.URL.BiliPackageUrl
|
||||
} else if req.AppId == 777 && len(statg.Conf.URL.HuanqiuPackageUrl) > 0 {
|
||||
packageUrlString = statg.Conf.URL.HuanqiuPackageUrl
|
||||
} else if req.AppId == 444 && len(statg.Conf.URL.ManhuaPackageUrl) > 0 {
|
||||
packageUrlString = statg.Conf.URL.ManhuaPackageUrl
|
||||
}
|
||||
packageUrlArray := strings.Split(packageUrlString, ";")
|
||||
resp.AndroidButton = len(packageUrlArray)
|
||||
// 是否有渠道包
|
||||
var version *versionMod.VersionModel
|
||||
versionKey := fmt.Sprintf("version_button#appId:%d#%s#%d", req.AppId, "android", 0)
|
||||
if cache, exists := cacheSer.Cache.Get(versionKey); exists {
|
||||
if item, ok := cache.(*versionMod.VersionModel); ok {
|
||||
version = item
|
||||
}
|
||||
}
|
||||
if version == nil {
|
||||
version, err = versionMod.ButtonClick(ctx, req.AppId, "android", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cacheSer.Cache.Set(cacheKey, version, 2*time.Minute)
|
||||
}
|
||||
|
||||
pack, serr := channelpackage.FindOneChannelPackage(ctx, bson.M{
|
||||
channelpackage.FN.ChannelPackage.AppId: req.AppId,
|
||||
channelpackage.FN.ChannelPackage.Channel: channelCode.DC,
|
||||
channelpackage.FN.ChannelPackage.Version: version.VersionNum,
|
||||
channelpackage.FN.ChannelPackage.FileName: version.Md5,
|
||||
})
|
||||
if serr != nil && serr.Code != stdLog.DataNotExist {
|
||||
return nil, errors.New(serr.Msg)
|
||||
}
|
||||
if pack != nil && pack.Status == channelpackage.ChanApkStatusSuccess {
|
||||
resp.HasChannelApk = true
|
||||
}
|
||||
|
||||
// ----------------End---------------
|
||||
|
||||
resp.Contact = proto.ContactInfo{
|
||||
Telegram: "https://t.me/madoutiktok",
|
||||
Paoto: "https://ptcc.in/madouyingshi",
|
||||
Madou: "http://madou101.com",
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
package versionSer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"stat/api/proto"
|
||||
"stat/common/enum/consts"
|
||||
"stat/common/genId"
|
||||
"stat/common/log"
|
||||
"stat/common/redis"
|
||||
"stat/common/tf"
|
||||
"stat/common/utils"
|
||||
"stat/models/appInfoMod"
|
||||
"stat/models/versionMod"
|
||||
"stat/statg"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/caixw/lib.go/encoding/version"
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
// ListVersion 获取版本信息
|
||||
func ListVersion(ctx context.Context, req *proto.VersionListReq) (resp *proto.VersionListResp, err error) {
|
||||
resp = &proto.VersionListResp{
|
||||
Data: make([]*proto.VersionInfo, 0),
|
||||
}
|
||||
|
||||
skip, limit := utils.ToDBPage(req.PageNum, req.PageSize)
|
||||
|
||||
data, count, err := versionMod.GetVersionList(ctx, req.AppId, skip, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
appInfoList, err := appInfoMod.GetAllAppInfo(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, v := range data {
|
||||
versionInfo := proto.VersionInfo{
|
||||
Id: v.Id,
|
||||
AppId: v.AppId,
|
||||
VersionNum: v.VersionNum,
|
||||
Terminal: v.Terminal,
|
||||
Link: v.Link,
|
||||
Info: v.Info,
|
||||
PackageType: v.PackageType,
|
||||
IsForceUpdate: v.IsForceUpdate,
|
||||
MinVersion: v.MinVersion,
|
||||
Status: v.Status,
|
||||
Size: v.Size,
|
||||
Md5: v.Md5,
|
||||
BackLink: v.BackLink,
|
||||
}
|
||||
for _, appinfo := range appInfoList {
|
||||
if appinfo.AppId == v.AppId {
|
||||
versionInfo.AppName = appinfo.Name
|
||||
}
|
||||
}
|
||||
resp.Data = append(resp.Data, &versionInfo)
|
||||
}
|
||||
resp.Count = count
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteVersion 删除版本
|
||||
func DeleteVersion(ctx context.Context, id int64) (err error) {
|
||||
err = versionMod.DelVersion(ctx, id)
|
||||
return
|
||||
}
|
||||
|
||||
// AddVersion 添加版本
|
||||
func AddVersion(ctx context.Context, req *proto.VersionAddReq) (err error) {
|
||||
model := &versionMod.VersionModel{}
|
||||
|
||||
// TODO:修改成指针
|
||||
err = copier.Copy(model, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
model.TfInfo = make([]versionMod.TfInfo, 0)
|
||||
if req.PackageType == versionMod.Tf {
|
||||
for _, url := range req.Link {
|
||||
tmp := versionMod.TfInfo{
|
||||
URL: strings.TrimSpace(url),
|
||||
}
|
||||
if req.PackageType == versionMod.Tf {
|
||||
result, err := tf.CheckTFValid(url)
|
||||
if err != nil {
|
||||
log.Error("runCheckUrl CheckTFValid", log.Any("url", url), log.E(err))
|
||||
continue
|
||||
}
|
||||
tmp.AppIcon = result.AppIcon
|
||||
tmp.AppName = result.AppName
|
||||
}
|
||||
model.TfInfo = append(model.TfInfo, tmp)
|
||||
}
|
||||
}
|
||||
model.VersionNum = strings.TrimSpace(model.VersionNum)
|
||||
model.CreatedAt = time.Now()
|
||||
model.UpdatedAt = time.Now()
|
||||
model.Id = genId.GetNextVersionId()
|
||||
|
||||
err = versionMod.AddVersion(ctx, model)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteVersion 删除版本
|
||||
func UpdateVersion(ctx context.Context, req *proto.VersionUpdateReq) (err error) {
|
||||
model := &versionMod.VersionModel{}
|
||||
err = copier.Copy(model, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
model.TfInfo = make([]versionMod.TfInfo, 0)
|
||||
if req.PackageType != nil && *req.PackageType == versionMod.Tf {
|
||||
for _, url := range *req.Link {
|
||||
tmp := versionMod.TfInfo{
|
||||
URL: strings.TrimSpace(url),
|
||||
}
|
||||
if *req.PackageType == versionMod.Tf {
|
||||
result, err := tf.CheckTFValid(url)
|
||||
if err != nil {
|
||||
log.Error("runCheckUrl CheckTFValid", log.Any("url", url), log.E(err))
|
||||
continue
|
||||
}
|
||||
tmp.AppIcon = result.AppIcon
|
||||
tmp.AppName = result.AppName
|
||||
}
|
||||
model.TfInfo = append(model.TfInfo, tmp)
|
||||
}
|
||||
}
|
||||
|
||||
model.UpdatedAt = time.Now()
|
||||
|
||||
err = versionMod.UpdateVersion(ctx, model)
|
||||
return
|
||||
}
|
||||
|
||||
func AppVersion(ctx context.Context, req *proto.AppVersionReq) (resp *proto.AppVersionResp, err error) {
|
||||
var list1 []*versionMod.VersionModel
|
||||
var list []*versionMod.VersionModel
|
||||
resp = &proto.AppVersionResp{}
|
||||
|
||||
if req.SysType == "android" {
|
||||
list1, err = versionMod.FindVersByPkgTyps(ctx, req.AppId, req.SysType, req.CurVersion, 0)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// ios 包
|
||||
list1, err = versionMod.FindIosVersion(ctx, req.AppId, req.SysType, req.CurVersion, []versionMod.PkgType{versionMod.Shop})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
list = make([]*versionMod.VersionModel, 0)
|
||||
for _, v := range list1 {
|
||||
if version.Compare(v.VersionNum, req.CurVersion) > 0 {
|
||||
list = append(list, v)
|
||||
} else if req.CurVersion == "9.9.9" {
|
||||
list = append(list, v)
|
||||
}
|
||||
}
|
||||
if len(list) == 0 || len(req.CurVersion) == 0 || req.CurVersion == "null" {
|
||||
resp.HasNewVersion = false
|
||||
return
|
||||
}
|
||||
|
||||
var minVersion string
|
||||
for _, value := range list {
|
||||
if len(value.MinVersion) > 0 && value.MinVersion > minVersion {
|
||||
minVersion = value.MinVersion
|
||||
break
|
||||
} else if value.IsForceUpdate {
|
||||
minVersion = value.VersionNum
|
||||
}
|
||||
}
|
||||
|
||||
resp.HasNewVersion = true
|
||||
resp.ServerVersion = list[0].VersionNum
|
||||
resp.DownloadLink = list[0].Link
|
||||
resp.Description = list[0].Info
|
||||
resp.IsForceUpdate = list[0].IsForceUpdate
|
||||
|
||||
if len(minVersion) > 0 {
|
||||
if minVersion > req.CurVersion {
|
||||
resp.IsForceUpdate = true
|
||||
}
|
||||
}
|
||||
|
||||
if len(resp.DownloadLink) > 0 && len(resp.DownloadLink[0]) < 2 && list[0].Terminal == "ios" && len(list[0].BackLink) > 2 {
|
||||
resp.DownloadLink = []string{list[0].BackLink}
|
||||
return
|
||||
}
|
||||
|
||||
// // 新增批量打包逻辑
|
||||
if req.SysType == "android" && len(list[0].Md5) > 0 {
|
||||
// 包名称:com.pf.ys201114
|
||||
randTime := int64(60*60) + int64(rand.Intn(60*60))
|
||||
|
||||
requestPackageTime := time.Now().Add(-time.Second * time.Duration(randTime)) // 报毒包随机
|
||||
// 下载链接
|
||||
projectString := ""
|
||||
beginPath := ""
|
||||
pathList := strings.Split(strings.Replace(list[0].Md5, ".apk", "", -1), "_")
|
||||
if len(pathList) > 0 {
|
||||
beginPath = strings.TrimSpace(pathList[len(pathList)-1])
|
||||
} else {
|
||||
return
|
||||
}
|
||||
endpoint := statg.GlobalAppIdEndpoints[req.AppId]
|
||||
if endpoint != nil {
|
||||
projectString = fmt.Sprintf("%s/out/%s/%s%s_", endpoint.NameEn, beginPath, endpoint.NameEn, requestPackageTime.Format("20060102")[2:])
|
||||
}
|
||||
if projectString != "" {
|
||||
packageUrlString := statg.Conf.URL.PackageUrl
|
||||
if req.AppId == 999 && len(statg.Conf.URL.BiliPackageUrl) > 0 {
|
||||
packageUrlString = statg.Conf.URL.BiliPackageUrl
|
||||
} else if req.AppId == 777 && len(statg.Conf.URL.HuanqiuPackageUrl) > 0 {
|
||||
packageUrlString = statg.Conf.URL.HuanqiuPackageUrl
|
||||
} else if req.AppId == 444 && len(statg.Conf.URL.ManhuaPackageUrl) > 0 {
|
||||
packageUrlString = statg.Conf.URL.ManhuaPackageUrl
|
||||
}
|
||||
packageUrlArray := strings.Split(packageUrlString, ";")
|
||||
packageUrl := packageUrlString
|
||||
if len(packageUrlArray) > 0 {
|
||||
// 默认使用第一个
|
||||
packageUrl = packageUrlArray[0]
|
||||
}
|
||||
link := strings.TrimSpace(packageUrl + projectString + list[0].Md5)
|
||||
|
||||
checklink := link
|
||||
cerr := CheckPackageLink(ctx, checklink)
|
||||
if cerr != nil {
|
||||
log.Error("AppVersion", log.Any("link", link), log.E(cerr))
|
||||
if statg.Conf.RunMod == consts.RunModRelease {
|
||||
// 比特币和溅射淫行下载链接异常不需要报警
|
||||
if req.AppId != 998 {
|
||||
//text := fmt.Sprintf("[警告]:应用名称:统计中心\nandroid下载链接异常: 版本:%s-->%s\n链接%s %s\n\n", req.CurVersion, list[0].VersionNum, link, cerr.Error())
|
||||
appDict, _ := appInfoMod.GetAllAppIdNameMap(ctx)
|
||||
text := fmt.Sprintf("【%s】Android下载链接异常:\n链接:%s\n错误:%s\n", appDict[req.AppId], link, cerr.Error())
|
||||
SendLinkErrorMessageToBot(text)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
resp.DownloadLink = []string{link}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CheckPackageLink 下载链接下载检测
|
||||
func CheckPackageLink(ctx context.Context, url_https string) (err error) {
|
||||
url := strings.Replace(url_https, "https", "http", -1)
|
||||
redisKey := fmt.Sprintf("channelpackagecheck:%s", url)
|
||||
status, _ := redis.StatRds.Exists(redisKey)
|
||||
if status { // 存在
|
||||
return nil
|
||||
}
|
||||
|
||||
// 检测下载地址
|
||||
resp, err := http.Head(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusGatewayTimeout {
|
||||
return fmt.Errorf("file is %d ", resp.StatusCode)
|
||||
}
|
||||
_ = redis.StatRds.Set(redisKey, "1", 24*time.Hour)
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewChannelDownLoadLink(ctx context.Context, req *proto.ChannelDownLoadLinkReq) (resp *proto.ChannelDownLoadLinkResp) {
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user