package internal import ( "fmt" "io" "net/http" "strings" "time" ) const ( defaultContentType string = "text/xml; charset=UTF-8" defaultAgent string = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; XFire Client +http://xfire.codehaus.org)" ) type Client struct { httpClient *http.Client } type CIIMSResponse struct { RawXML string } type HTTPStatusError struct { StatusCode int Status string Body string } func (e *HTTPStatusError) Error() string { body := e.Body if len(body) > 512 { body = body[:512] + "..." } if body == "" { return fmt.Sprintf("ciims returned %s", e.Status) } return fmt.Sprintf("ciims returned %s: %s", e.Status, body) } func NewClient(timeoutSec int) (*Client, error) { if timeoutSec <= 0 { return nil, fmt.Errorf("timeout must be positive") } return &Client{ httpClient: &http.Client{ Timeout: time.Duration(timeoutSec) * time.Second, }, }, nil } func (r *CIIMSResponse) IsFault() bool { return r != nil && r.ErrorMessage() != "" } func (r *CIIMSResponse) ErrorMessage() string { if r == nil { return "" } return GetErrMsg(r.RawXML) } func (r *CIIMSResponse) Messages() []string { if r == nil { return nil } return GetMsgs(r.RawXML) } func (c *Client) Send(url string, msg string) (*CIIMSResponse, error) { req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(msg)) if err != nil { return nil, err } req.Header.Set("Content-Type", defaultContentType) req.Header.Set("User-Agent", defaultAgent) req.Header.Set("SOAPAction", "") resp, err := c.httpClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() respBytes, err := io.ReadAll(resp.Body) if err != nil { return nil, err } body := string(respBytes) ciimsResp := &CIIMSResponse{RawXML: body} if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { return ciimsResp, &HTTPStatusError{ StatusCode: resp.StatusCode, Status: resp.Status, Body: body, } } return ciimsResp, nil }