package cabinet import ( "bytes" "fmt" "io" "mime/multipart" "net/http" "net/url" ) type Client struct { BaseURL string HTTP *http.Client Token string } func New(baseURL string, opts ...ClientOption) *Client { c := &Client{ BaseURL: baseURL, HTTP: http.DefaultClient, } for _, opt := range opts { opt(c) } return c } type ClientOption func(*Client) func WithHTTPClient(client *http.Client) ClientOption { return func(c *Client) { c.HTTP = client } } func WithToken(token string) ClientOption { return func(c *Client) { c.Token = token } } func (c *Client) Redirect(u string) (string, *http.Response, error) { vals := url.Values{ "url": []string{u}, } if c.Token != "" { vals["token"] = []string{c.Token} } resp, err := c.HTTP.PostForm(fmt.Sprintf("%s/r", c.BaseURL), vals) if err != nil { return "", nil, err } if resp.StatusCode != 200 { return "", resp, fmt.Errorf("non-200 status code: %s", resp.Status) } body, err := io.ReadAll(resp.Body) if err != nil { return "", resp, err } resp.Body = io.NopCloser(bytes.NewReader(body)) return string(body), resp, nil } func (c *Client) File(name string, f io.Reader) (string, *http.Response, error) { var buf bytes.Buffer mp := multipart.NewWriter(&buf) token, err := mp.CreateFormField("token") if err != nil { return "", nil, err } if _, err := token.Write([]byte(c.Token)); err != nil { return "", nil, err } file, err := mp.CreateFormFile("file", name) if err != nil { return "", nil, err } if _, err := io.Copy(file, f); err != nil { return "", nil, err } if err := mp.Close(); err != nil { return "", nil, err } req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/f", c.BaseURL), &buf) if err != nil { return "", nil, err } req.Header.Set("Content-Type", mp.FormDataContentType()) resp, err := c.HTTP.Do(req) if err != nil { return "", nil, err } if resp.StatusCode != 200 { return "", resp, fmt.Errorf("non-200 status code: %s", resp.Status) } body, err := io.ReadAll(resp.Body) if err != nil { return "", resp, err } resp.Body = io.NopCloser(bytes.NewReader(body)) return string(body), resp, nil }