blob: 17cc4f1e2ed58d526e0f24e15514b7a5b7b8a77c [file] [log] [blame]
package swservice
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"crypto/tls"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
log "github.com/Sirupsen/logrus"
"io/ioutil"
"net"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
type WebSession struct {
AppId string
TermId string
Appsecret string
BaseUrl string
DefaultTimeout int
session_key string
ssl_verify bool
}
func safe_get_json_int(value interface{}) int {
if value == nil {
return 0
}
s := fmt.Sprintf("%v", value)
if i, err := strconv.Atoi(s); err != nil {
return 0
} else {
return i
}
}
type ServiceResponse struct {
RetCode int
RetMsg string
Result map[string]interface{}
}
func NewServiceResponseFromJson(json_data interface{}) *ServiceResponse {
if json_data == nil {
return nil
}
res := &ServiceResponse{}
res.Result = json_data.(map[string]interface{})
res.RetCode = safe_get_json_int(res.Result["retcode"])
res.RetMsg = res.GetStrValue("retmsg")
return res
}
func (r *ServiceResponse) GetIntValue(name string) int {
return safe_get_json_int(r.Result[name])
}
func (r *ServiceResponse) GetStrValue(name string) string {
if s, ok := r.Result[name]; ok {
return fmt.Sprintf("%v", s)
} else {
return ""
}
}
func (r *ServiceResponse) GetFloatValue(name string) float64 {
if s, ok := r.Result[name]; ok {
t := fmt.Sprintf("%v", s)
if f, err := strconv.ParseFloat(t, 64); err != nil {
return 0.0
} else {
return f
}
} else {
return 0.0
}
}
func (w *WebSession) DoGet(uri string, params map[string]string) (*http.Response, error) {
client := w.NewClient(3)
full_url := w.BaseUrl + uri
vl := url.Values{}
if params != nil {
for k, v := range params {
vl.Add(k, v)
}
}
full_url = full_url + "?" + vl.Encode()
// fmt.Printf("%v\n", full_url)
return client.Get(full_url)
}
func (w *WebSession) GetTimestamp() string {
t := time.Now()
return fmt.Sprintf("%04d%02d%02d%02d%02d%02d", t.Year(), t.Month(), t.Day(),
t.Hour(), t.Minute(), t.Second())
}
func (w *WebSession) SignWithKey(key, message string) string {
mac := hmac.New(sha1.New, []byte(key))
mac.Write([]byte(message))
res := mac.Sum(nil)
return hex.EncodeToString(res)
}
func (w *WebSession) Sign(message string) string {
return w.SignWithKey(w.Appsecret, message)
}
func (w *WebSession) NewClient(timeout int) *http.Client {
var transport http.Transport
if strings.HasPrefix(w.BaseUrl, "https://") {
var b bool
if w.ssl_verify {
b = false
} else {
b = true
}
transport = http.Transport{MaxIdleConnsPerHost: 0, DisableKeepAlives: true,
TLSClientConfig: &tls.Config{InsecureSkipVerify: b},
TLSHandshakeTimeout: time.Duration(timeout) * time.Second,
Dial: func(network, addr string) (net.Conn, error) {
default_timeout := time.Duration(1) * time.Second
return net.DialTimeout(network, addr, default_timeout)
}}
} else if strings.HasPrefix(w.BaseUrl, "http://") {
transport = http.Transport{MaxIdleConnsPerHost: 0, DisableKeepAlives: true,
Dial: func(network, addr string) (net.Conn, error) {
default_timeout := time.Duration(1) * time.Second
return net.DialTimeout(network, addr, default_timeout)
}}
}
return &http.Client{Transport: &transport, Timeout: time.Duration(timeout) * time.Second}
}
func (w *WebSession) DoPost(uri string, param map[string]string) (*http.Response, error) {
client := w.NewClient(3)
param["app_id"] = w.AppId
param["term_id"] = w.TermId
param["sign_method"] = "HMAC"
param["session_key"] = w.session_key
ts := w.GetTimestamp()
param["timestamp"] = ts
param["sign"] = w.Sign(w.AppId + w.TermId + w.session_key + ts)
full_url := w.BaseUrl + uri
data, err := json.Marshal(param)
if err != nil {
return nil, err
}
var r *http.Response
r, err = client.Post(full_url, "application/json", bytes.NewReader(data))
if err != nil || r.StatusCode != 200 {
log.Errorf("Status=%v, err=%v", r, err)
}
return r, err
}
func (w *WebSession) Auth() error {
token, err := w.getAuthToken()
if err != nil {
return err
}
err = w.getAppAccessKey(token)
if err != nil {
return err
}
return nil
}
func NewSession(appid, appsecret, termid, baseurl string, timeout int, sslVerify bool) *WebSession {
return &WebSession{
AppId: appid,
Appsecret: appsecret,
TermId: termid,
BaseUrl: baseurl,
DefaultTimeout: timeout,
ssl_verify: sslVerify}
}
func (w *WebSession) getAuthToken() (string, error) {
type FormJson struct {
AppId string `json:"app_id"`
TermId string `json:"term_id"`
AccessToken string `json:"access_token"`
}
uri := fmt.Sprintf("/authservice/getauth/%v/getaccesstoken", w.AppId)
params := make(map[string]string)
params["term_id"] = w.TermId
r, err := w.DoGet(uri, params)
if err != nil {
// log.Errorf("Status = %v, err = %v\n", r.StatusCode, err)
return "", err
}
if r.StatusCode != 200 {
return "", errors.New("请求失败")
}
body, err := ioutil.ReadAll(r.Body)
defer r.Body.Close()
s := &FormJson{}
err = json.Unmarshal(body, &s)
if err != nil {
log.Errorf("json unmarshal err %v", err)
return "", errors.New("解析失败")
}
return s.AccessToken, nil
}
func (w *WebSession) getAppAccessKey(token string) error {
type FormJson struct {
AppId string `json:"app_id"`
TermId string `json:"term_id"`
SessionKey string `json:"session_key"`
CardKey string `json:"card_key"`
}
uri := fmt.Sprintf("/authservice/getauth/%v", w.AppId)
params := make(map[string]string)
params["term_id"] = w.TermId
params["access_token"] = token
params["timestamp"] = w.GetTimestamp()
params["v"] = "1"
params["sign"] = w.Sign(token + params["timestamp"])
params["sign_method"] = "HMAC"
r, err := w.DoGet(uri, params)
if err != nil || r.StatusCode != 200 {
log.Errorf(" err = %v\n", err)
return err
}
body, err := ioutil.ReadAll(r.Body)
defer r.Body.Close()
s := &FormJson{}
err = json.Unmarshal(body, &s)
if err != nil {
log.Errorf("json unmarshal err %v", err)
}
w.session_key = s.SessionKey
return nil
}
func (w *WebSession) CallYKTApi(request *MessageWriter) (*MessageReader, error) {
call_data := request.Serialize()
params := make(map[string]string)
params["funcdata"] = call_data
r, err := w.DoPost("/ecardservice/ecardapi", params)
if err != nil {
log.Errorf(" err = %v\n", err)
return nil, err
}
defer r.Body.Close()
if r.StatusCode != 200 {
return nil, errors.New(fmt.Sprintf("Request StatusCode:%v", r.StatusCode))
}
body, err := ioutil.ReadAll(r.Body)
return NewMessageReader(body), nil
}
func (w *WebSession) CallService(path string, params map[string]interface{},
sign_field []string, timeout int) (response *ServiceResponse, err error) {
return w.CallService2(path, params, timeout, sign_field...)
}
func (w *WebSession) CallService2(path string, params map[string]interface{}, timeout int,
sign_field ...string) (response *ServiceResponse, err error) {
client := w.NewClient(timeout)
err = nil
params["app_id"] = w.AppId
params["term_id"] = w.TermId
ts := w.GetTimestamp()
params["timestamp"] = ts
vl := &url.Values{}
for k, v := range params {
vl.Set(k, fmt.Sprintf("%v", v))
}
sign_data := ""
for _, k := range sign_field {
if v, ok := params[k]; ok {
sign_data += fmt.Sprintf("%v", v)
}
}
sign_data += ts + w.session_key
vl.Set("sign_method", "HMAC")
log.Debugf("Sign: key[%v] data[%v]\n", w.session_key, sign_data)
vl.Set("sign", w.SignWithKey(w.Appsecret, sign_data))
full_url := w.BaseUrl + path
log.Debugf("CallService: %v\n", full_url)
var r *http.Response
r, err = client.Post(full_url, "application/x-www-form-urlencoded",
bytes.NewReader([]byte(vl.Encode())))
if err != nil {
log.Errorf("Status=%v, err=%v", r, err)
return
}
defer r.Body.Close()
if r.StatusCode != 200 {
log.Errorf("Request Error %v\n", r.StatusCode)
err = errors.New(fmt.Sprintf("Request Error, StatusCode : %v", r.StatusCode))
return
}
body, err := ioutil.ReadAll(r.Body)
var s interface{}
err = json.Unmarshal(body, &s)
if err != nil {
log.Errorf("json unmarshal err %v", err)
return
}
response = NewServiceResponseFromJson(s)
return
}