| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- package qiyuesuosdk
- import (
- "bytes"
- "crypto/md5"
- "encoding/hex"
- "encoding/json"
- "fmt"
- "io"
- "mime/multipart"
- "net/http"
- "net/url"
- "strings"
- "time"
- "git.sxidc.com/student-physical-examination/contract_lock_sdk/utils"
- "github.com/google/uuid"
- )
- // Client 契约锁开放平台客户端;仅封装 HTTP/签名与契约锁 API,不含业务状态机。
- type Client struct {
- cfg Config
- signDefaults SignDefaults
- sdk *utils.SdkClient
- http *http.Client
- }
- // New 创建客户端。signDefaults 可为零值,签章时可按请求单独传入 ProcessID/Launcher。
- func New(cfg Config, signDefaults SignDefaults) *Client {
- address := strings.TrimRight(cfg.Address, "/")
- return &Client{
- cfg: cfg,
- signDefaults: signDefaults,
- sdk: utils.NewSdkClient(address, cfg.AppToken, cfg.AppSecret),
- http: &http.Client{Timeout: 60 * time.Second},
- }
- }
- func (c *Client) baseURL() string {
- return strings.TrimRight(c.cfg.Address, "/")
- }
- func (c *Client) authHeaders() map[string]string {
- nonce := uuid.NewString()
- timestamp := fmt.Sprintf("%d", time.Now().UnixMilli())
- raw := c.cfg.AppToken + c.cfg.AppSecret + timestamp + nonce
- sum := md5.Sum([]byte(raw))
- return map[string]string{
- "x-qys-accesstoken": c.cfg.AppToken,
- "x-qys-timestamp": timestamp,
- "x-qys-nonce": nonce,
- "x-qys-signature": hex.EncodeToString(sum[:]),
- }
- }
- func (c *Client) postJSON(path string, body any, out any) error {
- payload, err := json.Marshal(body)
- if err != nil {
- return err
- }
- req, err := http.NewRequest(http.MethodPost, c.baseURL()+path, bytes.NewReader(payload))
- if err != nil {
- return err
- }
- req.Header.Set("Content-Type", "application/json;charset=UTF-8")
- for k, v := range c.authHeaders() {
- req.Header.Set(k, v)
- }
- return c.doJSON(req, out)
- }
- func (c *Client) getQuery(path string, query url.Values, out any) error {
- u := c.baseURL() + path
- if len(query) > 0 {
- u += "?" + query.Encode()
- }
- req, err := http.NewRequest(http.MethodGet, u, nil)
- if err != nil {
- return err
- }
- for k, v := range c.authHeaders() {
- req.Header.Set(k, v)
- }
- return c.doJSON(req, out)
- }
- func (c *Client) doJSON(req *http.Request, out any) error {
- resp, err := c.http.Do(req)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
- data, err := io.ReadAll(resp.Body)
- if err != nil {
- return err
- }
- if out == nil {
- return nil
- }
- return json.Unmarshal(data, out)
- }
- func (c *Client) postMultipart(path string, fields map[string]string, fileField string, fileBytes []byte, out any) error {
- var buf bytes.Buffer
- w := multipart.NewWriter(&buf)
- for k, v := range fields {
- if err := w.WriteField(k, v); err != nil {
- return err
- }
- }
- if len(fileBytes) > 0 && fileField != "" {
- part, err := w.CreateFormFile(fileField, "document.pdf")
- if err != nil {
- return err
- }
- if _, err = part.Write(fileBytes); err != nil {
- return err
- }
- }
- if err := w.Close(); err != nil {
- return err
- }
- req, err := http.NewRequest(http.MethodPost, c.baseURL()+path, &buf)
- if err != nil {
- return err
- }
- req.Header.Set("Content-Type", w.FormDataContentType())
- for k, v := range c.authHeaders() {
- req.Header.Set(k, v)
- }
- return c.doJSON(req, out)
- }
- func (c *Client) download(path string, query url.Values) ([]byte, error) {
- u := c.baseURL() + path
- if len(query) > 0 {
- u += "?" + query.Encode()
- }
- req, err := http.NewRequest(http.MethodGet, u, nil)
- if err != nil {
- return nil, err
- }
- for k, v := range c.authHeaders() {
- req.Header.Set(k, v)
- }
- resp, err := c.http.Do(req)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
- return io.ReadAll(resp.Body)
- }
- func (c *Client) serviceOK(resp *utils.SdkResponse) error {
- if resp == nil {
- return fmt.Errorf("qiyuesuo: empty sdk response")
- }
- if resp.Message == "SUCCESS" {
- return nil
- }
- return fmt.Errorf("qiyuesuo: %s", resp.Message)
- }
- func (c *Client) serviceString(resp *utils.SdkResponse) (string, error) {
- if err := c.serviceOK(resp); err != nil {
- return "", err
- }
- if resp.Result == nil {
- return "", nil
- }
- if s, ok := resp.Result.(string); ok {
- return s, nil
- }
- return "", fmt.Errorf("qiyuesuo: unexpected result type %T", resp.Result)
- }
- func (c *Client) resolveProcessID(id string) string {
- if id != "" {
- return id
- }
- return c.signDefaults.ProcessID
- }
- func (c *Client) resolveLauncher(name string) string {
- if name != "" {
- return name
- }
- return c.signDefaults.TenantName
- }
|