-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbaidusms.go
139 lines (127 loc) · 3.39 KB
/
baidusms.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package baidusms
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
type Region = string
const (
_ Region = ""
RegionBJ = "bj"
RegionGZ = "gz"
)
// BaiduSMS is config of sms service. AccessKey, SecretKey, Region should be provided
// Region is one of "bj" and "gz"
type BaiduSMS struct {
AccessKey string
SecretKey string
Region string
}
// SuccessResponse is success body of baidu response
type SuccessResponse struct {
Code string `json:"code"`
Message string `json:"message"`
RequestID string `json:"requestId"`
}
// ErrSendFail is fail body of baidu response
type ErrSendFail struct {
HTTPCode int
APICode string
Message string
RequestID string
}
func (e *ErrSendFail) Error() string {
return fmt.Sprintf(
"Baidu SMS API error, httpcode: %d, code: %s, message: %s, requestID: %s",
e.HTTPCode, e.APICode, e.Message, e.RequestID,
)
}
const (
// Version of baidusms
Version = "3.0.0"
gzHost = "smsv3.gz.baidubce.com"
bjHost = "smsv3.bj.baidubce.com"
)
func (bd BaiduSMS) sendRequest(method string, path string, body string) (*SuccessResponse, error) {
now := time.Now()
auth := auth{bd.AccessKey, bd.SecretKey}
var host string
if strings.ToLower(bd.Region) == "gz" {
host = gzHost
} else {
host = bjHost
}
targetURL := fmt.Sprintf("https://%s%s", host, path)
req, err := http.NewRequest(method, targetURL, strings.NewReader(body))
req.Header.Add("User-Agent", fmt.Sprintf("bce-sdk-go/%s", Version))
req.Header.Add("Host", host)
req.Header.Add("Connection", "close")
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Content-Length", strconv.FormatInt(req.ContentLength, 10))
req.Header.Add("x-bce-date", getCanonicalTime(now))
sum := sha256.Sum256([]byte(body))
req.Header.Add("x-bce-content-sha256", hex.EncodeToString(sum[:]))
headers := req.Header
req.Header.Add("Authorization", auth.generateAuthorization(method, path, headers, url.Values{}, now))
client := &http.Client{
Timeout: 10 * time.Second,
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
bodyBytes, readErr := ioutil.ReadAll(resp.Body)
if readErr != nil {
return nil, readErr
}
var s SuccessResponse
err = json.Unmarshal(bodyBytes, &s)
if err != nil {
return nil, err
}
if s.Code != "1000" {
// only 1000 is correct
return nil, &ErrSendFail{
HTTPCode: resp.StatusCode,
APICode: s.Code,
Message: s.Message,
RequestID: s.RequestID,
}
}
return &s, nil
}
return nil, &ErrSendFail{
HTTPCode: resp.StatusCode,
}
}
type requestBody struct {
SignatureID string `json:"signatureId"`
Mobile string `json:"mobile"`
Template string `json:"template"`
ContentVar map[string]string `json:"contentVar"`
}
// SendSMSCode will call HTTP request to Baidu API to send a sms
// mobile should be array (length limited in 1-200) of E.164 phoneNumber
func (bd BaiduSMS) SendSMSCode(
mobile []string,
template string,
signatureID string,
contentVar map[string]string,
) (*SuccessResponse, error) {
path := "/api/v3/sendSms"
body := requestBody{signatureID, strings.Join(mobile, ","), template, contentVar}
bodyStr, err := json.Marshal(body)
if err != nil {
return nil, err
}
return bd.sendRequest("POST", path, string(bodyStr))
}