211 lines
4.6 KiB
Go
211 lines
4.6 KiB
Go
package cav2
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha1"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"hospital-admin-api/config"
|
|
"hospital-admin-api/global"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type Client struct {
|
|
BaseURL string
|
|
AppID string
|
|
AppSecret string
|
|
HTTPClient *http.Client
|
|
}
|
|
|
|
func NewClient(baseURL, appID, appSecret string) *Client {
|
|
return &Client{
|
|
BaseURL: strings.TrimRight(baseURL, "/"),
|
|
AppID: appID,
|
|
AppSecret: appSecret,
|
|
HTTPClient: &http.Client{
|
|
Timeout: 15 * time.Second,
|
|
},
|
|
}
|
|
}
|
|
|
|
func NewClientFromConfig() *Client {
|
|
baseURL := config.C.CaOnlineV2.CaOnlineAPIURL
|
|
appID := config.C.CaOnlineV2.CaOnlineAppID
|
|
appSecret := config.C.CaOnlineV2.CaOnlineAppSecret
|
|
|
|
if baseURL == "" {
|
|
baseURL = config.C.CaOnline.CaOnlineApiUrl
|
|
}
|
|
if appID == "" {
|
|
appID = config.C.CaOnline.CaOnlineAppId
|
|
}
|
|
if appSecret == "" {
|
|
appSecret = config.C.CaOnline.CaOnlineAppSecret
|
|
}
|
|
|
|
return NewClient(
|
|
baseURL,
|
|
appID,
|
|
appSecret,
|
|
)
|
|
}
|
|
|
|
func (c *Client) postForm(path string, form url.Values, out interface{}) error {
|
|
if c == nil {
|
|
return errors.New("ca v2 client is nil")
|
|
}
|
|
if c.BaseURL == "" || c.AppID == "" || c.AppSecret == "" {
|
|
return errors.New("ca v2 client config is incomplete")
|
|
}
|
|
if c.HTTPClient == nil {
|
|
c.HTTPClient = &http.Client{Timeout: 15 * time.Second}
|
|
}
|
|
|
|
payload := strings.NewReader(form.Encode())
|
|
req, err := http.NewRequest(http.MethodPost, c.BaseURL+path, payload)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
req.Header.Set("app_id", c.AppID)
|
|
req.Header.Set("signature", c.signature(form))
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
if err != nil {
|
|
c.logUpstreamError(path, form, "request_error", err.Error())
|
|
return err
|
|
}
|
|
defer func() {
|
|
_ = resp.Body.Close()
|
|
}()
|
|
|
|
respBody, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
c.logUpstreamError(path, form, "read_body_error", err.Error())
|
|
return err
|
|
}
|
|
|
|
c.logUpstreamResponse(path, form, resp.StatusCode, string(respBody))
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("ca v2 request failed: http %d", resp.StatusCode)
|
|
}
|
|
|
|
var envelope responseEnvelope
|
|
if err := json.Unmarshal(respBody, &envelope); err != nil {
|
|
c.logUpstreamError(path, form, "unmarshal_error", err.Error())
|
|
return err
|
|
}
|
|
|
|
if envelope.ResultCode != 0 {
|
|
if envelope.ResultMsg != "" {
|
|
c.logUpstreamError(path, form, "upstream_business_error", envelope.ResultMsg)
|
|
return errors.New(envelope.ResultMsg)
|
|
}
|
|
return fmt.Errorf("ca v2 request failed with code %d", envelope.ResultCode)
|
|
}
|
|
|
|
if out == nil {
|
|
return nil
|
|
}
|
|
|
|
body := strings.TrimSpace(string(envelope.Body))
|
|
if body == "" || body == "null" {
|
|
return nil
|
|
}
|
|
|
|
return json.Unmarshal(envelope.Body, out)
|
|
}
|
|
|
|
func (c *Client) postFormForString(path string, form url.Values) (string, error) {
|
|
var raw json.RawMessage
|
|
if err := c.postForm(path, form, &raw); err != nil {
|
|
return "", err
|
|
}
|
|
body := strings.TrimSpace(string(raw))
|
|
if body == "" || body == "null" {
|
|
return "", nil
|
|
}
|
|
|
|
var text string
|
|
if err := json.Unmarshal(raw, &text); err == nil {
|
|
return text, nil
|
|
}
|
|
|
|
var data map[string]string
|
|
if err := json.Unmarshal(raw, &data); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
for _, key := range []string{"url", "authUrl", "faceUrl", "h5Url"} {
|
|
if value := strings.TrimSpace(data[key]); value != "" {
|
|
return value, nil
|
|
}
|
|
}
|
|
|
|
return "", errors.New("ca v2 string body not found")
|
|
}
|
|
|
|
func (c *Client) signature(form url.Values) string {
|
|
keys := make([]string, 0, len(form))
|
|
for key := range form {
|
|
keys = append(keys, key)
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
values := make([]string, 0, len(keys))
|
|
for _, key := range keys {
|
|
for _, value := range form[key] {
|
|
values = append(values, value)
|
|
}
|
|
}
|
|
|
|
h := hmac.New(sha1.New, []byte(c.AppSecret))
|
|
h.Write([]byte(strings.Join(values, "&")))
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
}
|
|
|
|
func setValue(form url.Values, key, value string) {
|
|
if strings.TrimSpace(value) == "" {
|
|
return
|
|
}
|
|
form.Set(key, value)
|
|
}
|
|
|
|
func (c *Client) logUpstreamResponse(path string, form url.Values, statusCode int, body string) {
|
|
if global.Logger == nil {
|
|
return
|
|
}
|
|
|
|
global.Logger.WithFields(logrus.Fields{
|
|
"module": "ca_v2",
|
|
"upstream_path": path,
|
|
"upstream_status": statusCode,
|
|
"request_form": form.Encode(),
|
|
"response_body": body,
|
|
}).Info("ca v2 upstream response")
|
|
}
|
|
|
|
func (c *Client) logUpstreamError(path string, form url.Values, stage string, message string) {
|
|
if global.Logger == nil {
|
|
return
|
|
}
|
|
|
|
global.Logger.WithFields(logrus.Fields{
|
|
"module": "ca_v2",
|
|
"stage": stage,
|
|
"upstream_path": path,
|
|
"request_form": form.Encode(),
|
|
}).Error(message)
|
|
}
|