package service
|
|
import (
|
"car-service/extend/util"
|
"car-service/models"
|
"encoding/json"
|
"errors"
|
"fmt"
|
"github.com/astaxie/beego"
|
"strings"
|
"sync"
|
"time"
|
)
|
var latestToken *TokenResult
|
var lock sync.RWMutex
|
func getCacheToken() string {
|
lock.Lock()
|
defer lock.Unlock()
|
if latestToken != nil {
|
return latestToken.Token
|
}
|
return ""
|
}
|
func updateToken(newT *TokenResult) {
|
lock.Lock()
|
defer lock.Unlock()
|
latestToken = newT
|
}
|
|
func init() {
|
newToken, err := RefreshToken()
|
if err == nil {
|
updateToken(newToken)
|
}
|
ticker := time.NewTicker(time.Hour * 20)
|
go func() {
|
for {
|
select {
|
case <-ticker.C:
|
if t,err := RefreshToken();err == nil {
|
updateToken(t)
|
}
|
default:
|
time.Sleep(time.Second * 5)
|
}
|
}
|
}()
|
}
|
|
//批量解绑别名
|
func UnbindAlias(cid string) (bool, error) {
|
var uc models.UserClient
|
ucList := uc.GetByCid(cid)
|
if ucList ==nil {
|
return true,errors.New("ucList is nil")
|
}
|
var aliasArr []string
|
for _,als := range ucList {
|
aliasArr = append(aliasArr, als.PhoneNum)
|
}
|
appId := beego.AppConfig.String("pushAppId")
|
baseUrl := beego.AppConfig.String("pushBaseUrl") + appId
|
retryTimes := 0
|
ReTry:
|
token := getCacheToken()
|
if token == "" {
|
return false, errors.New("token is nil")
|
}
|
url := baseUrl + "/user/alias"
|
header := map[string]string {
|
"token": token,
|
}
|
caArr := make([]map[string]string, 0)
|
for _,as := range aliasArr {
|
caArr = append(caArr, map[string]string{
|
"cid": cid,
|
"alias": as,
|
})
|
}
|
|
reqBody := map[string]interface{}{
|
"data_list": caArr,
|
}
|
b,err := util.DoDeleteRequest(url, util.CONTENT_TYPE_UTF8_JSON, reqBody, header)
|
if err !=nil {
|
fmt.Println("DoDelete err:", err)
|
return false, err
|
}
|
var result PushResult
|
err = json.Unmarshal(b, &result)
|
if err != nil {
|
fmt.Println("unmarshal err:", err)
|
return false, err
|
}
|
if result.Code == 0 { //解绑成功
|
return true, nil
|
} else if result.Code == 10001 { //token过期
|
if retryTimes <=3 {
|
newToken, err := RefreshToken()
|
if err == nil {
|
updateToken(newToken)
|
retryTimes++
|
goto ReTry
|
}
|
}
|
}
|
return false, errors.New(result.Msg)
|
}
|
|
//一个别名最多允许绑定10个cid
|
func BindAlias(cid, alias string) (bool, error) {
|
appId := beego.AppConfig.String("pushAppId")
|
baseUrl := beego.AppConfig.String("pushBaseUrl") + appId
|
retryTimes := 0
|
ReTry:
|
token := getCacheToken()
|
if token == "" {
|
return false, errors.New("token is nil")
|
}
|
url := baseUrl+"/user/alias"
|
caArr := make([]map[string]string, 0)
|
caArr = append(caArr, map[string]string{
|
"cid": cid,
|
"alias": alias,
|
})
|
reqBody := map[string]interface{} {
|
"data_list":caArr,
|
}
|
header := map[string]string {
|
"token": token,
|
}
|
b, err := util.DoPostRequest(url, util.CONTENT_TYPE_UTF8_JSON, reqBody, nil, header)
|
if err !=nil {
|
fmt.Println("DoPost err:", err)
|
return false, err
|
}
|
var result PushResult
|
err = json.Unmarshal(b, &result)
|
if err != nil {
|
fmt.Println("unmarshal err:", err)
|
return false, err
|
}
|
if result.Code == 0 { //绑定成功
|
return true, nil
|
} else if result.Code == 10001 { //token过期
|
if retryTimes <=3 {
|
newToken, err := RefreshToken()
|
if err == nil {
|
updateToken(newToken)
|
retryTimes++
|
goto ReTry
|
}
|
}
|
}
|
return false, errors.New(result.Msg)
|
}
|
|
type PushResult struct {
|
Code int `json:"code"`
|
Msg string `json:"msg"`
|
Data interface{} `json:"data"`
|
}
|
|
type TokenResult struct {
|
ExpireTime string `json:"expire_time"`
|
Token string `json:"token"`
|
}
|
|
type CreatePushMsgResult struct {
|
TaskId string `json:"taskid"`
|
}
|
|
func createPushMsg(title string, msg string) (bool,string, error) {
|
appId := beego.AppConfig.String("pushAppId")
|
baseUrl := beego.AppConfig.String("pushBaseUrl") + appId
|
retryTimes := 0
|
ReTry:
|
token := getCacheToken()
|
if token == "" {
|
return false, "", errors.New("token is nil")
|
}
|
url := baseUrl+"/push/list/message"
|
intent := "intent:#Intent;action=android.intent.action.oppopush;launchFlags=0x14000000;component=uni.UNIEDF0B5C/io.dcloud.PandoraEntry;S.UP-OL-SU=true;S.title="+title+";S.content="+msg+";S.payload=test;end"
|
androidPush := map[string]map[string]map[string]string {
|
"ups": {
|
"notification": {
|
"title": title,
|
"body": msg,
|
"big_text": msg,
|
"click_type": "intent",
|
"intent": intent,
|
},
|
},
|
}
|
iosPush := map[string]interface{}{
|
"type":"notify",
|
"payload":"育英中学停车",
|
"aps":map[string]interface{}{
|
"alert":map[string]string{
|
"title": title,
|
"body": msg,
|
},
|
"content-available":0,
|
},
|
}
|
reqBody := map[string]interface{} {
|
"request_id": time.Now().Format("20060102150405") + util.GenValidateCode(6),
|
"settings":map[string]int {
|
"ttl": 8 * 3600 * 1000,
|
},
|
"push_message": map[string]map[string]string {
|
"notification": {
|
"title": title,
|
"body": msg,
|
"click_type": "intent",
|
"intent": intent,
|
},
|
},
|
"push_channel": map[string]interface{} {
|
"android": androidPush,
|
"ios":iosPush,
|
},
|
}
|
header := map[string]string {
|
"token": token,
|
}
|
b, err := util.DoPostRequest(url, util.CONTENT_TYPE_UTF8_JSON, reqBody, nil, header)
|
if err !=nil {
|
fmt.Println("DoPost err:", err)
|
return false, "",err
|
}
|
var result PushResult
|
err = json.Unmarshal(b, &result)
|
if err != nil {
|
fmt.Println("unmarshal err:", err)
|
return false, "",err
|
}
|
if result.Code == 0 {
|
rb,uErr := json.Marshal(result.Data)
|
if uErr == nil {
|
var tResult CreatePushMsgResult
|
if uErr =json.Unmarshal(rb, &tResult); uErr ==nil {
|
return true, tResult.TaskId, nil
|
} else {
|
return false, "", uErr
|
}
|
} else {
|
return false, "", uErr
|
}
|
} else if result.Code == 10001 { //token过期
|
if retryTimes <=3 {
|
newToken, err := RefreshToken()
|
if err == nil {
|
updateToken(newToken)
|
retryTimes++
|
goto ReTry
|
}
|
}
|
}
|
return false, "", errors.New(result.Msg)
|
}
|
|
//对已注册的用户进行消息推送。调用此接口前需调用创建消息接口设置消息内容
|
func PushByAlias(title string, msg string, isTest bool) (bool, error, []string) {
|
var aliasArr []string
|
|
pushUserM := make(map[string]string)
|
var userE models.User
|
allUsers, _ := userE.GetAllUsers()
|
if allUsers != nil {
|
for _,u := range allUsers {
|
pushUserM[u.Id] = u.PhoneNum
|
}
|
}
|
if len(pushUserM) == 0 {
|
return false,errors.New("len(pushUserM) == 0"),aliasArr
|
}
|
carPersonM := make(map[string]string) //以车牌号为key,value是hik的personId
|
csv := NewCarService()
|
carPersons := csv.GetVehicleListByPerson("")
|
if carPersons != nil {
|
for _, cp := range carPersons {
|
ncPlateNo := preDealPlateNo(cp.PlateNo) //去掉汉字,D和0替换成*
|
if ncPlateNo != "" {
|
carPersonM[ncPlateNo] = cp.PersonId
|
}
|
}
|
}
|
delPersonIdM := make(map[string]string)
|
spaceNos := csv.FindSpaceNo("")
|
for _,sn := range spaceNos {
|
if sn.State == 1 && sn.PlateNo != "" { //已经把车停到停车场的车主,不再推送消息
|
realPlateNo := preDealPlateNo(sn.PlateNo)
|
if realPlateNo != "" {
|
if pId,ok := carPersonM[realPlateNo];ok {
|
delPersonIdM[pId] = pId
|
delete(carPersonM, realPlateNo)
|
}
|
}
|
}
|
}
|
var uc models.UserClient
|
for _,personId := range carPersonM {
|
if phoneNum,ok := pushUserM[personId]; ok { //此人已注册到系统,并且车不在停车库内
|
if _,in := delPersonIdM[personId];!in {
|
if uc.Exist(phoneNum) {
|
aliasArr = append(aliasArr, phoneNum)
|
}
|
}
|
}
|
}
|
lenAS := len(aliasArr)
|
if lenAS == 0 {
|
return false, errors.New("没有推送目标,aliasArr is empty"),aliasArr
|
}
|
if isTest {
|
//只给内部手机号推
|
testPhones := beego.AppConfig.String("testPushPhones")
|
if testPhones == "" {
|
return false, errors.New("test push aliasArr is empty"),aliasArr
|
}
|
aliasArr = strings.Split(testPhones, ",")
|
}
|
|
cResult, taskId, ce := createPushMsg(title, msg)
|
fmt.Println("createPushMsg taskId:", taskId, "cResult:",cResult, "err:", ce)
|
if !cResult {
|
return false, errors.New("创建推送前置消息失败"),aliasArr
|
}
|
|
//alias 单次推送长度上限是200
|
pushTime := 1
|
if lenAS > 200 {
|
pushTime = lenAS / 200
|
if lenAS % 200 >0 {
|
pushTime++
|
}
|
}
|
|
isSuccess := false
|
for i:=0;i<pushTime;i++ {
|
var curAliasArr []string
|
start := i*200
|
end := (i+1)*200 -1
|
if i<pushTime-1 {
|
curAliasArr = aliasArr[start:end]
|
} else {
|
//取剩余所有
|
curAliasArr = aliasArr[start:]
|
}
|
if len(curAliasArr) >0 {
|
flag, e := doPush(taskId, curAliasArr)
|
if e != nil {
|
fmt.Println("doPush err:", e)
|
}
|
if flag {
|
isSuccess = true
|
}
|
}
|
}
|
if isSuccess {
|
return true, nil,aliasArr
|
}
|
|
return false, errors.New("推送失败"),aliasArr
|
}
|
|
//预处理车牌号,去除首个汉字,以及忽略D和0
|
func preDealPlateNo(pn string) string {
|
if pn != "" {
|
r := []rune(pn)
|
ncStr := string(r[1:])
|
newPlateNo := strings.ReplaceAll(ncStr, "D", "*")
|
newPlateNo = strings.ReplaceAll(newPlateNo, "0", "*")
|
return newPlateNo
|
}
|
return ""
|
}
|
|
func doPush(taskId string, aliasArr []string) (bool,error) {
|
appId := beego.AppConfig.String("pushAppId")
|
baseUrl := beego.AppConfig.String("pushBaseUrl") + appId
|
retryTimes := 0
|
ReTry:
|
token := getCacheToken()
|
if token == "" {
|
return false, errors.New("token is nil")
|
}
|
url := baseUrl+"/push/list/alias"
|
reqBody := map[string]interface{} {
|
"audience":map[string]interface{}{
|
"alias": aliasArr,
|
},
|
"taskid": taskId,
|
"is_async": false,
|
}
|
header := map[string]string {
|
"token": token,
|
}
|
b, err := util.DoPostRequest(url, util.CONTENT_TYPE_UTF8_JSON, reqBody, nil, header)
|
if err !=nil {
|
fmt.Println("DoPost err:", err)
|
return false, err
|
}
|
var result PushResult
|
err = json.Unmarshal(b, &result)
|
if err != nil {
|
fmt.Println("unmarshal err:", err)
|
return false, err
|
}
|
if result.Code == 0 {
|
return true, nil
|
} else if result.Code == 10001 { //token过期
|
if retryTimes <=3 {
|
newToken, err := RefreshToken()
|
if err == nil {
|
updateToken(newToken)
|
retryTimes++
|
goto ReTry
|
}
|
}
|
} else {
|
fmt.Println("推送结果:", result)
|
}
|
return false, errors.New("推送失败")
|
}
|
|
func NightPush(title string, msg string) (bool, error, []string, []string) {
|
var aliasArr []string
|
var carOwners []string
|
|
pushUserM := make(map[string]string)
|
var userE models.User
|
allUsers, _ := userE.GetAllUsers()
|
if allUsers != nil {
|
for _,u := range allUsers {
|
pushUserM[u.Id] = u.PhoneNum
|
}
|
}
|
if len(pushUserM) == 0 {
|
return false, errors.New("len(pushUserM) == 0"), aliasArr, carOwners
|
}
|
carPersonM := make(map[string]string)
|
csv := NewCarService()
|
carPersons := csv.GetVehicleListByPerson("")
|
if carPersons != nil {
|
for _, cp := range carPersons {
|
cnPlateNo := preDealPlateNo(cp.PlateNo)
|
if cnPlateNo != "" {
|
carPersonM[cnPlateNo] = cp.PersonId
|
}
|
}
|
}
|
//夜间某些领导的车可以停在车库内
|
var vipPlateNoArr []string
|
vipArr := strings.Split(beego.AppConfig.String("nightVipPlateNos"), ",")
|
if vipArr != nil && len(vipArr) >0 {
|
for _,po := range vipArr {
|
if po != "" {
|
cnPo := preDealPlateNo(po)
|
if cnPo != "" {
|
vipPlateNoArr = append(vipPlateNoArr, cnPo)
|
}
|
}
|
}
|
}
|
|
hikPersonMap := csv.GetHikPersonMap()
|
|
spaceNos := csv.FindSpaceNo("")
|
var uc models.UserClient
|
for _,sn := range spaceNos {
|
if sn.State == 1 { //车尚在停车场的车牌
|
inCnPlateNo := preDealPlateNo(sn.PlateNo)
|
if inCnPlateNo != "" {
|
if !isVipCar(inCnPlateNo, vipPlateNoArr) {
|
if personId,ok := carPersonM[inCnPlateNo];ok {
|
if phoneNum,ok := pushUserM[personId]; ok {
|
if uc.Exist(phoneNum) {
|
aliasArr = append(aliasArr, phoneNum)
|
}
|
}
|
|
if v,ex := hikPersonMap[personId]; ex {
|
carOwners = append(carOwners, v.PersonName)
|
}
|
} else { //找不到车主,即视为临时车,将车牌作为车主姓名推送
|
carOwners = append(carOwners, sn.PlateNo)
|
}
|
}
|
}
|
}
|
}
|
|
if len(aliasArr) == 0 {
|
fmt.Println("没有推送目标,aliasArr is empty")
|
return false, errors.New("没有推送目标,aliasArr is empty"), aliasArr, carOwners
|
}
|
|
cResult, taskId, ce := createPushMsg(title, msg)
|
if !cResult {
|
fmt.Println("createPushMsg taskId:", taskId, "err:", ce)
|
return false, errors.New("创建推送前置消息失败"), aliasArr, carOwners
|
}
|
|
b,e := doPush(taskId, aliasArr)
|
return b,e, aliasArr, carOwners
|
}
|
|
//vip车主,不接收请离开的通知,也不通知管理员这个车还在车库内
|
func isVipCar(targetPlateNo string, vipPlateNoArr []string) bool {
|
b := false
|
if vipPlateNoArr != nil {
|
for _,v := range vipPlateNoArr {
|
if targetPlateNo == v {
|
b = true
|
break
|
}
|
}
|
}
|
return b
|
}
|
|
//如果夜间有给车库内的车主推送“请尽快驶离”的消息,则告知管理员 有哪些车尚停在车库内
|
func Push2Manager(title string, msg string) (bool, error, []string) {
|
if len(msg) > 256 {
|
fmt.Println("夜间停留车太多,message:", msg)
|
|
r := []rune(msg)
|
msg = string(r[:125])+"..."
|
}
|
managers := beego.AppConfig.String("nightManagerPhones")
|
if managers == "" {
|
return false, errors.New("夜间推送管理员手机号未配置"), []string{}
|
}
|
managerArr := strings.Split(managers, ",")
|
if len(managerArr) == 0 {
|
fmt.Println("没有推送目标,managerArr is empty")
|
return false, errors.New("管理员手机号未配置"), managerArr
|
}
|
|
cResult, taskId, ce := createPushMsg(title, msg)
|
if !cResult {
|
fmt.Println("createPushMsg taskId:", taskId, "err:", ce)
|
return false, errors.New("创建推送前置消息失败"), managerArr
|
}
|
|
b,e := doPush(taskId, managerArr)
|
return b,e, managerArr
|
}
|
|
/*
|
func PushAll(title string, msg string) (bool,error) {
|
appId := beego.AppConfig.String("pushAppId")
|
baseUrl := beego.AppConfig.String("pushBaseUrl") + appId
|
retryTimes := 0
|
ReTry:
|
token := getCacheToken()
|
if token == "" {
|
return false, errors.New("token is nil")
|
}
|
url := baseUrl+"/push/all"
|
intent := "intent:#Intent;action=android.intent.action.oppopush;launchFlags=0x14000000;component=uni.UNIEDF0B5C/io.dcloud.PandoraEntry;S.UP-OL-SU=true;S.title="+title+";S.content="+msg+";S.payload=test;end"
|
androidPush := map[string]map[string]map[string]string {
|
"ups": {
|
"notification": {
|
"title": title,
|
"body": msg,
|
"click_type": "intent",
|
"intent": intent,
|
},
|
},
|
}
|
iosPush := map[string]interface{}{
|
"type":"notify",
|
"payload":"育英中学停车",
|
"aps":map[string]interface{}{
|
"alert":map[string]string{
|
"title": title,
|
"body": msg,
|
},
|
"content-available":0,
|
//"sound":"com.gexin.ios.silence",
|
//"category":"ACTIONABLE",
|
},
|
"auto_badge":"+1",
|
}
|
reqBody := map[string]interface{} {
|
"request_id": time.Now().Format("20060102150405") + util.GenValidateCode(6),
|
"settings":map[string]int {
|
"ttl": 8 * 3600 * 1000,
|
},
|
"audience": "all",
|
"push_message": map[string]map[string]string {
|
"notification": {
|
"title": title,
|
"body": msg,
|
"click_type": "intent",
|
"intent": intent,
|
},
|
},
|
"push_channel": map[string]interface{} {
|
"android": androidPush,
|
"ios": iosPush,
|
},
|
}
|
header := map[string]string {
|
"token": token,
|
}
|
b, err := util.DoPostRequest(url, util.CONTENT_TYPE_UTF8_JSON, reqBody, nil, header)
|
if err !=nil {
|
fmt.Println("DoPost err:", err)
|
return false, err
|
}
|
var result PushResult
|
err = json.Unmarshal(b, &result)
|
if err != nil {
|
fmt.Println("unmarshal err:", err)
|
return false, err
|
}
|
if result.Code == 0 {
|
return true, nil
|
} else if result.Code == 10001 { //token过期
|
if retryTimes <=3 {
|
newToken, err := RefreshToken()
|
if err == nil {
|
updateToken(newToken)
|
retryTimes++
|
goto ReTry
|
}
|
}
|
} else {
|
fmt.Println("推送结果:", result)
|
}
|
|
return false, errors.New("推送失败")
|
}*/
|
|
func RefreshToken() (*TokenResult,error) {
|
appId := beego.AppConfig.String("pushAppId")
|
appKey := beego.AppConfig.String("pushAppKey")
|
masterSecret := beego.AppConfig.String("pushMasterSecret")
|
baseUrl := beego.AppConfig.String("pushBaseUrl") + appId
|
url := baseUrl +"/auth"
|
timestamp := fmt.Sprintf("%v", time.Now().UnixNano() / 1e6)
|
sign := util.Sha256(appKey + timestamp + masterSecret)
|
reqBody := map[string]interface{} {
|
"sign": sign,
|
"timestamp": timestamp,
|
"appkey": appKey,
|
}
|
b, err := util.DoPostRequest(url, util.CONTENT_TYPE_UTF8_JSON, reqBody, nil, nil)
|
if err !=nil {
|
fmt.Println("DoPost err:", err)
|
return nil, err
|
}
|
var result PushResult
|
err = json.Unmarshal(b, &result)
|
if err != nil {
|
fmt.Println("unmarshal err:", err)
|
return nil, err
|
}
|
if result.Code == 0 {
|
db, err := json.Marshal(result.Data)
|
if err != nil {
|
fmt.Println("marshal err:", err)
|
return nil, err
|
}
|
var t TokenResult
|
err = json.Unmarshal(db, &t)
|
if err != nil {
|
fmt.Println("unmarshal err:", err)
|
return nil, err
|
}
|
return &t, nil
|
}
|
return nil, errors.New("获取unipush平台token失败")
|
}
|