From 15a13e5dd973c80a33a176f7a44cda887f6435b8 Mon Sep 17 00:00:00 2001 From: huangjiajun <582604932@qq.com> Date: Mon, 4 Jul 2022 11:07:41 +0800 Subject: [PATCH] =?UTF-8?q?add=20reverse:for=20v1.0.0=20=E6=9E=81=E5=85=89?= =?UTF-8?q?=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 8 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + .idea/zyos_go_jg_push.iml | 9 ++ go.mod | 5 + go.sum | 2 + hdl/jg_push.go | 65 ++++++++ hdl/push_test.go | 30 ++++ md/jg_push.go | 90 +++++++++++ utils/convert.go | 328 ++++++++++++++++++++++++++++++++++++++ utils/curl.go | 170 ++++++++++++++++++++ utils/serialize.go | 23 +++ 12 files changed, 744 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/zyos_go_jg_push.iml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 hdl/jg_push.go create mode 100644 hdl/push_test.go create mode 100644 md/jg_push.go create mode 100644 utils/convert.go create mode 100644 utils/curl.go create mode 100644 utils/serialize.go diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..6ac1cc3 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..3ba676a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/zyos_go_jg_push.iml b/.idea/zyos_go_jg_push.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/zyos_go_jg_push.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..3343900 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module code.fnuoos.com/go_rely_warehouse/zyos_go_jg_push.git + +go 1.15 + +require github.com/syyongx/php2go v0.9.7 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..6ba1677 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/syyongx/php2go v0.9.7 h1:boZtLbm2xYbW49mX9M7Vq2zkVhBhv3fCqs2T16d2bGA= +github.com/syyongx/php2go v0.9.7/go.mod h1:meN2eIhhUoxOd2nMxbpe8g6cFPXI5O9/UAAuz7oDdzw= diff --git a/hdl/jg_push.go b/hdl/jg_push.go new file mode 100644 index 0000000..09d49e3 --- /dev/null +++ b/hdl/jg_push.go @@ -0,0 +1,65 @@ +package jg_push + +import ( + "code.fnuoos.com/go_rely_warehouse/zyos_go_jg_push.git/md" + jg_push_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_jg_push.git/utils" + "encoding/json" + "errors" + "fmt" + "github.com/syyongx/php2go" +) + +func Send(appKey, appSecret string, param md.PushParam) (interface{}, error) { + + if appKey == "" || appSecret == "" { + return nil, errors.New("配置未设置") + } + url := "https://api.jpush.cn/v3/push" + var iosAlert = md.PushIosAlert{Title: param.Title, Body: param.Content} + req := md.PushRequest{ + Platform: param.Platform, + Audience: param.Audience, + Notification: struct { + Android md.PushAndroid `json:"android"` + Ios md.PushIos `json:"ios"` + }{ + Android: md.PushAndroid{ + Alert: param.Content, + Extras: param.Extras, + Title: param.Title, + }, + Ios: md.PushIos{ + Alert: iosAlert, + Extras: param.Extras, + Sound: "default", + }, + }, + Message: struct { + Extras interface{} `json:"extras"` + MsgContent string `json:"msg_content"` + }{ + Extras: param.Extras, + MsgContent: param.Content, + }, + Options: struct { + TimeToLive int `json:"time_to_live"` + }{ + TimeToLive: 86400, + }, + } + key := php2go.Base64Encode(appKey + ":" + appSecret) + headers := map[string]string{ + "Content-Type": "application/json", + "Authorization": "Basic " + key, + } + b, err := json.Marshal(req) + if err != nil { + return nil, err + } + res, err := jg_push_utils.CurlPost(url, b, headers) + if err != nil { + return nil, err + } + fmt.Println(res) + return res, nil +} diff --git a/hdl/push_test.go b/hdl/push_test.go new file mode 100644 index 0000000..072c00f --- /dev/null +++ b/hdl/push_test.go @@ -0,0 +1,30 @@ +package jg_push + +import ( + "code.fnuoos.com/go_rely_warehouse/zyos_go_jg_push.git/md" + "encoding/json" + "testing" +) + +func TestPush(t *testing.T) { + var aud = md.PushAudience{Alias: []string{"123456_736"}} + var extrasData = md.NextCommModData{} + extrasStr, _ := json.Marshal(extrasData) + var extras = md.SkipData{ + SkipName: "测试", + SkipIdentifier: "pub.flutter.invite_friends", + RequiredLogin: "1", + RequiredTaobaoAuth: "0", + IsJump: "1", + Url: "", + Data: string(extrasStr), + } + var param = md.PushParam{ + Platform: "all", + Audience: aud, + Title: "API推送", + Content: "哈哈哈哈", + Extras: extras, + } + Send("6033fc3e19543740413d19aa", "ca7db52b63f7833299042f6a", param) +} diff --git a/md/jg_push.go b/md/jg_push.go new file mode 100644 index 0000000..67bdff0 --- /dev/null +++ b/md/jg_push.go @@ -0,0 +1,90 @@ +package md + +type PushAndroid struct { + Alert string `json:"alert"` //通知内容 + //BuilderID int64 `json:"builder_id"` 通知栏样式 ID + Extras interface{} `json:"extras"` + Title string `json:"title"` //通知标题 +} +type PushIos struct { + Alert interface{} `json:"alert"` + Extras interface{} `json:"extras"` + Sound string `json:"sound"` +} +type PushIosAlert struct { + Title string `json:"title"` + Body string `json:"body"` +} +type PushAudience struct { + Alias []string `json:"alias"` +} +type PushRequest struct { + Platform interface{} `json:"platform"` //推送平台设置 全部:all 安卓:android iOS:ios ["android", "ios","quickapp"] + Audience interface{} `json:"audience"` //全部:all 别名 {"alias" : [ "4314", "892", "4531"] } + Notification struct { //通知内容体,是被推送到客户端的内容。 + Android PushAndroid `json:"android"` + Ios PushIos `json:"ios"` + } `json:"notification"` + Message struct { + Extras interface{} `json:"extras"` + MsgContent string `json:"msg_content"` + } `json:"message"` + + Options struct { + TimeToLive int `json:"time_to_live"` + } `json:"options"` +} + +type PushParam struct { + Platform interface{} `json:"platform"` //推送平台设置 全部:all 安卓:android iOS:ios ["android", "ios","quickapp"] + Audience interface{} `json:"audience"` //全部:all 别名 {"alias" : [ "4314", "892", "4531"] } + Title string `json:"title"` + Content string `json:"content"` + Extras interface{} `json:"extras"` +} + +type SkipData struct { + SkipName string `json:"skip_name"` + SkipIdentifier string `json:"skip_identifier"` + RequiredLogin string `json:"required_login"` + RequiredTaobaoAuth string `json:"required_taobao_auth"` + IsJump string `json:"is_jump"` + Url string `json:"url"` + Data string `json:"data"` +} +type NextCommModData struct { + FromCoinId string `json:"from_coin_id"` + ToCoinId string `json:"to_coin_id"` + Url string `json:"url"` + AppId string `json:"app_id"` + StoreId string `json:"store_id"` + AlipayUrl string `json:"alipay_url"` + AlipayAppid string `json:"alipay_appid"` + ActivityId string `json:"activity_id"` + Id string `json:"id"` + AdName string `json:"ad_name"` + AndroidAdID string `json:"android_ad_id"` + AndroidMediaID string `json:"android_media_id"` + AutoClickAd string `json:"auto_click_ad"` + Autoplay string `json:"autoplay"` + BrandID string `json:"brand_id"` + Conditions string `json:"conditions"` + CreateAt string `json:"create_at"` + EndTime string `json:"end_time"` + Img string `json:"img"` + IosAdID string `json:"ios_ad_id"` + IosMediaID string `json:"ios_media_id"` + IsRecommend interface{} `json:"is_recommend"` + LevelLimitID string `json:"level_limit_id"` + LevelLimitName string `json:"level_limit_name"` + LevelWeight string `json:"level_weight"` + NeedLocation int64 `json:"need_location"` + SdkType string `json:"sdk_type"` + SourceType string `json:"source_type"` + StartTime string `json:"start_time"` + UpdateAt string `json:"update_at"` + VisitCount string `json:"visit_count"` + CountingDown string `json:"counting_down" ` + LevelType string `json:"level_type"` + OpenType string `json:"open_type" ` //app 应用内打开 browser 系统浏览器打开 +} diff --git a/utils/convert.go b/utils/convert.go new file mode 100644 index 0000000..f990d11 --- /dev/null +++ b/utils/convert.go @@ -0,0 +1,328 @@ +package jg_push_utils + +import ( + "encoding/binary" + "encoding/json" + "fmt" + "math" + "strconv" + "strings" +) + +func ToString(raw interface{}, e error) (res string) { + if e != nil { + return "" + } + return AnyToString(raw) +} + +func ToInt64(raw interface{}, e error) int64 { + if e != nil { + return 0 + } + return AnyToInt64(raw) +} +func Float64ToStrByPrec(f float64, prec int) string { + return strconv.FormatFloat(f, 'f', prec, 64) +} +func AnyToBool(raw interface{}) bool { + switch i := raw.(type) { + case float32, float64, int, int64, uint, uint8, uint16, uint32, uint64, int8, int16, int32: + return i != 0 + case []byte: + return i != nil + case string: + if i == "false" { + return false + } + return i != "" + case error: + return false + case nil: + return true + } + val := fmt.Sprint(raw) + val = strings.TrimLeft(val, "&") + if strings.TrimLeft(val, "{}") == "" { + return false + } + if strings.TrimLeft(val, "[]") == "" { + return false + } + // ptr type + b, err := json.Marshal(raw) + if err != nil { + return false + } + if strings.TrimLeft(string(b), "\"\"") == "" { + return false + } + if strings.TrimLeft(string(b), "{}") == "" { + return false + } + return true +} + +func AnyToInt64(raw interface{}) int64 { + switch i := raw.(type) { + case string: + res, _ := strconv.ParseInt(i, 10, 64) + return res + case []byte: + return BytesToInt64(i) + case int: + return int64(i) + case int64: + return i + case uint: + return int64(i) + case uint8: + return int64(i) + case uint16: + return int64(i) + case uint32: + return int64(i) + case uint64: + return int64(i) + case int8: + return int64(i) + case int16: + return int64(i) + case int32: + return int64(i) + case float32: + return int64(i) + case float64: + return int64(i) + case error: + return 0 + case bool: + if i { + return 1 + } + return 0 + } + return 0 +} + +func AnyToString(raw interface{}) string { + switch i := raw.(type) { + case []byte: + return string(i) + case int: + return strconv.FormatInt(int64(i), 10) + case int64: + return strconv.FormatInt(i, 10) + case float32: + return Float64ToStr(float64(i)) + case float64: + return Float64ToStr(i) + case uint: + return strconv.FormatInt(int64(i), 10) + case uint8: + return strconv.FormatInt(int64(i), 10) + case uint16: + return strconv.FormatInt(int64(i), 10) + case uint32: + return strconv.FormatInt(int64(i), 10) + case uint64: + return strconv.FormatInt(int64(i), 10) + case int8: + return strconv.FormatInt(int64(i), 10) + case int16: + return strconv.FormatInt(int64(i), 10) + case int32: + return strconv.FormatInt(int64(i), 10) + case string: + return i + case error: + return i.Error() + case bool: + return strconv.FormatBool(i) + } + return fmt.Sprintf("%#v", raw) +} + +func AnyToFloat64(raw interface{}) float64 { + switch i := raw.(type) { + case []byte: + f, _ := strconv.ParseFloat(string(i), 64) + return f + case int: + return float64(i) + case int64: + return float64(i) + case float32: + return float64(i) + case float64: + return i + case uint: + return float64(i) + case uint8: + return float64(i) + case uint16: + return float64(i) + case uint32: + return float64(i) + case uint64: + return float64(i) + case int8: + return float64(i) + case int16: + return float64(i) + case int32: + return float64(i) + case string: + f, _ := strconv.ParseFloat(i, 64) + return f + case bool: + if i { + return 1 + } + } + return 0 +} + +func ToByte(raw interface{}, e error) []byte { + if e != nil { + return []byte{} + } + switch i := raw.(type) { + case string: + return []byte(i) + case int: + return Int64ToBytes(int64(i)) + case int64: + return Int64ToBytes(i) + case float32: + return Float32ToByte(i) + case float64: + return Float64ToByte(i) + case uint: + return Int64ToBytes(int64(i)) + case uint8: + return Int64ToBytes(int64(i)) + case uint16: + return Int64ToBytes(int64(i)) + case uint32: + return Int64ToBytes(int64(i)) + case uint64: + return Int64ToBytes(int64(i)) + case int8: + return Int64ToBytes(int64(i)) + case int16: + return Int64ToBytes(int64(i)) + case int32: + return Int64ToBytes(int64(i)) + case []byte: + return i + case error: + return []byte(i.Error()) + case bool: + if i { + return []byte("true") + } + return []byte("false") + } + return []byte(fmt.Sprintf("%#v", raw)) +} + +func Int64ToBytes(i int64) []byte { + var buf = make([]byte, 8) + binary.BigEndian.PutUint64(buf, uint64(i)) + return buf +} + +func BytesToInt64(buf []byte) int64 { + return int64(binary.BigEndian.Uint64(buf)) +} + +func StrToInt(s string) int { + res, _ := strconv.Atoi(s) + return res +} + +func StrToInt64(s string) int64 { + res, _ := strconv.ParseInt(s, 10, 64) + return res +} + +func Float32ToByte(float float32) []byte { + bits := math.Float32bits(float) + bytes := make([]byte, 4) + binary.LittleEndian.PutUint32(bytes, bits) + + return bytes +} + +func ByteToFloat32(bytes []byte) float32 { + bits := binary.LittleEndian.Uint32(bytes) + return math.Float32frombits(bits) +} + +func Float64ToByte(float float64) []byte { + bits := math.Float64bits(float) + bytes := make([]byte, 8) + binary.LittleEndian.PutUint64(bytes, bits) + return bytes +} + +func ByteToFloat64(bytes []byte) float64 { + bits := binary.LittleEndian.Uint64(bytes) + return math.Float64frombits(bits) +} + +func Float64ToStr(f float64) string { + return strconv.FormatFloat(f, 'f', 2, 64) +} +func Float64ToStrPrec1(f float64) string { + return strconv.FormatFloat(f, 'f', 1, 64) +} + +func Float64ToStrPrec6(f float64) string { + return strconv.FormatFloat(f, 'f', 6, 64) +} + +func Float32ToStr(f float32) string { + return Float64ToStr(float64(f)) +} + +func StrToFloat64(s string) float64 { + res, err := strconv.ParseFloat(s, 64) + if err != nil { + return 0 + } + return res +} + +func StrToFloat32(s string) float32 { + res, err := strconv.ParseFloat(s, 32) + if err != nil { + return 0 + } + return float32(res) +} + +func StrToBool(s string) bool { + b, _ := strconv.ParseBool(s) + return b +} + +func BoolToStr(b bool) string { + if b { + return "true" + } + return "false" +} + +func FloatToInt64(f float64) int64 { + return int64(f) +} + +func IntToStr(i int) string { + return strconv.Itoa(i) +} + +func Int64ToStr(i int64) string { + return strconv.FormatInt(i, 10) +} diff --git a/utils/curl.go b/utils/curl.go new file mode 100644 index 0000000..8b09d3f --- /dev/null +++ b/utils/curl.go @@ -0,0 +1,170 @@ +package jg_push_utils + +import ( + "bytes" + "crypto/tls" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "sort" + "strings" + "time" +) + +var CurlDebug bool + +func CurlGet(router string, header map[string]string) ([]byte, error) { + return curl(http.MethodGet, router, nil, header) +} + +// 只支持form 与json 提交, 请留意body的类型, 支持string, []byte, map[string]string +func CurlPost(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl(http.MethodPost, router, body, header) +} + +func CurlPut(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl(http.MethodPut, router, body, header) +} + +// 只支持form 与json 提交, 请留意body的类型, 支持string, []byte, map[string]string +func CurlPatch(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl(http.MethodPatch, router, body, header) +} + +// CurlDelete is curl delete +func CurlDelete(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl(http.MethodDelete, router, body, header) +} + +func curl(method, router string, body interface{}, header map[string]string) ([]byte, error) { + var reqBody io.Reader + contentType := "application/json" + switch v := body.(type) { + case string: + reqBody = strings.NewReader(v) + case []byte: + reqBody = bytes.NewReader(v) + case map[string]string: + val := url.Values{} + for k, v := range v { + val.Set(k, v) + } + reqBody = strings.NewReader(val.Encode()) + contentType = "application/x-www-form-urlencoded" + case map[string]interface{}: + val := url.Values{} + for k, v := range v { + val.Set(k, v.(string)) + } + reqBody = strings.NewReader(val.Encode()) + contentType = "application/x-www-form-urlencoded" + } + if header == nil { + header = map[string]string{"Content-Type": contentType} + } + if _, ok := header["Content-Type"]; !ok { + header["Content-Type"] = contentType + } + resp, er := CurlReq(method, router, reqBody, header) + if er != nil { + return nil, er + } + res, err := ioutil.ReadAll(resp.Body) + if CurlDebug { + blob := SerializeStr(body) + if contentType != "application/json" { + blob = HttpBuild(body) + } + fmt.Printf("\n\n=====================\n[url]: %s\n[time]: %s\n[method]: %s\n[content-type]: %v\n[req_header]: %s\n[req_body]: %#v\n[resp_err]: %v\n[resp_header]: %v\n[resp_body]: %v\n=====================\n\n", + router, + time.Now().Format("2006-01-02 15:04:05.000"), + method, + contentType, + HttpBuildQuery(header), + blob, + err, + SerializeStr(resp.Header), + string(res), + ) + } + resp.Body.Close() + return res, err +} + +func CurlReq(method, router string, reqBody io.Reader, header map[string]string) (*http.Response, error) { + req, _ := http.NewRequest(method, router, reqBody) + if header != nil { + for k, v := range header { + req.Header.Set(k, v) + } + } + // 绕过github等可能因为特征码返回503问题 + // https://www.imwzk.com/posts/2021-03-14-why-i-always-get-503-with-golang/ + defaultCipherSuites := []uint16{0xc02f, 0xc030, 0xc02b, 0xc02c, 0xcca8, 0xcca9, 0xc013, 0xc009, + 0xc014, 0xc00a, 0x009c, 0x009d, 0x002f, 0x0035, 0xc012, 0x000a} + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + CipherSuites: append(defaultCipherSuites[8:], defaultCipherSuites[:8]...), + }, + }, + // 获取301重定向 + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + return client.Do(req) +} + +// 组建get请求参数,sortAsc true为小到大,false为大到小,nil不排序 a=123&b=321 +func HttpBuildQuery(args map[string]string, sortAsc ...bool) string { + str := "" + if len(args) == 0 { + return str + } + if len(sortAsc) > 0 { + keys := make([]string, 0, len(args)) + for k := range args { + keys = append(keys, k) + } + if sortAsc[0] { + sort.Strings(keys) + } else { + sort.Sort(sort.Reverse(sort.StringSlice(keys))) + } + for _, k := range keys { + str += "&" + k + "=" + args[k] + } + } else { + for k, v := range args { + str += "&" + k + "=" + v + } + } + return str[1:] +} + +func HttpBuild(body interface{}, sortAsc ...bool) string { + params := map[string]string{} + if args, ok := body.(map[string]interface{}); ok { + for k, v := range args { + params[k] = AnyToString(v) + } + return HttpBuildQuery(params, sortAsc...) + } + if args, ok := body.(map[string]string); ok { + for k, v := range args { + params[k] = AnyToString(v) + } + return HttpBuildQuery(params, sortAsc...) + } + if args, ok := body.(map[string]int); ok { + for k, v := range args { + params[k] = AnyToString(v) + } + return HttpBuildQuery(params, sortAsc...) + } + return AnyToString(body) +} diff --git a/utils/serialize.go b/utils/serialize.go new file mode 100644 index 0000000..9534f93 --- /dev/null +++ b/utils/serialize.go @@ -0,0 +1,23 @@ +package jg_push_utils + +import ( + "encoding/json" +) + +func Serialize(data interface{}) []byte { + res, err := json.Marshal(data) + if err != nil { + return []byte{} + } + return res +} + +func Unserialize(b []byte, dst interface{}) { + if err := json.Unmarshal(b, dst); err != nil { + dst = nil + } +} + +func SerializeStr(data interface{}, arg ...interface{}) string { + return string(Serialize(data)) +}