@@ -0,0 +1,8 @@ | |||
# 默认忽略的文件 | |||
/shelf/ | |||
/workspace.xml | |||
# Datasource local storage ignored files | |||
/dataSources/ | |||
/dataSources.local.xml | |||
# 基于编辑器的 HTTP 客户端请求 | |||
/httpRequests/ |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<project version="4"> | |||
<component name="ProjectModuleManager"> | |||
<modules> | |||
<module fileurl="file://$PROJECT_DIR$/.idea/zyos_go_jg_push.iml" filepath="$PROJECT_DIR$/.idea/zyos_go_jg_push.iml" /> | |||
</modules> | |||
</component> | |||
</project> |
@@ -0,0 +1,6 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<project version="4"> | |||
<component name="VcsDirectoryMappings"> | |||
<mapping directory="$PROJECT_DIR$" vcs="Git" /> | |||
</component> | |||
</project> |
@@ -0,0 +1,9 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<module type="WEB_MODULE" version="4"> | |||
<component name="Go" enabled="true" /> | |||
<component name="NewModuleRootManager"> | |||
<content url="file://$MODULE_DIR$" /> | |||
<orderEntry type="inheritedJdk" /> | |||
<orderEntry type="sourceFolder" forTests="false" /> | |||
</component> | |||
</module> |
@@ -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 |
@@ -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= |
@@ -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 | |||
} |
@@ -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) | |||
} |
@@ -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 系统浏览器打开 | |||
} |
@@ -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) | |||
} |
@@ -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) | |||
} |
@@ -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)) | |||
} |