117 lines
2.9 KiB
Go
117 lines
2.9 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"mime/multipart"
|
||
|
"net/http"
|
||
|
"net/url"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
type gokapiClient struct {
|
||
|
httpClient *http.Client
|
||
|
host *url.URL
|
||
|
apiKey string
|
||
|
}
|
||
|
|
||
|
func newGokapiClient(host *url.URL, apiKey string) *gokapiClient {
|
||
|
return &gokapiClient{
|
||
|
httpClient: &http.Client{},
|
||
|
host: host,
|
||
|
apiKey: apiKey,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (gc *gokapiClient) uploadChunk(ctx context.Context, fi uploadInfo, offset int64, data io.Reader) error {
|
||
|
var body bytes.Buffer
|
||
|
|
||
|
boundary, err := gc.prepUploadChunkBody(&body, fi, offset, data)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
actionURL := gc.host.ResolveReference(&url.URL{Path: "/api/chunk/add"})
|
||
|
|
||
|
req, err := http.NewRequestWithContext(ctx, "POST", actionURL.String(), &body)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
req.Header.Set("Accept", "application/json")
|
||
|
req.Header.Set("Apikey", gc.apiKey)
|
||
|
req.Header.Set("Content-Type", "multipart/form-data; boundary="+boundary)
|
||
|
|
||
|
resp, err := gc.httpClient.Do(req)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
|
||
|
if resp.StatusCode != http.StatusOK {
|
||
|
return fmt.Errorf("upload chunk failed with status code %d", resp.StatusCode)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (gc *gokapiClient) finalizeChunk(ctx context.Context, fi uploadInfo) (UploadResponse, error) {
|
||
|
actionURL := gc.host.ResolveReference(&url.URL{Path: "/api/chunk/complete"})
|
||
|
|
||
|
formData := url.Values{}
|
||
|
formData.Set("uuid", fi.chunkID)
|
||
|
formData.Set("filename", fi.filename)
|
||
|
formData.Set("filesize", strconv.FormatInt(fi.totalSize, 10))
|
||
|
formData.Set("contenttype", fi.contentType)
|
||
|
formData.Set("allowedDownloads", strconv.Itoa(fi.allowedDownloads))
|
||
|
formData.Set("expiryDays", strconv.Itoa(fi.expiryDays))
|
||
|
formData.Set("password", fi.password)
|
||
|
|
||
|
req, err := http.NewRequestWithContext(ctx, "POST", actionURL.String(), strings.NewReader(formData.Encode()))
|
||
|
if err != nil {
|
||
|
return UploadResponse{}, err
|
||
|
}
|
||
|
req.Header.Set("Accept", "application/json")
|
||
|
req.Header.Set("Apikey", gc.apiKey)
|
||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||
|
|
||
|
resp, err := gc.httpClient.Do(req)
|
||
|
if err != nil {
|
||
|
return UploadResponse{}, err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
|
||
|
if resp.StatusCode != http.StatusOK {
|
||
|
return UploadResponse{}, fmt.Errorf("upload chunk finalization with status code %d", resp.StatusCode)
|
||
|
}
|
||
|
|
||
|
var r UploadResponse
|
||
|
if err := json.NewDecoder(resp.Body).Decode(&r); err != nil {
|
||
|
return UploadResponse{}, err
|
||
|
}
|
||
|
|
||
|
return r, nil
|
||
|
}
|
||
|
|
||
|
func (gc *gokapiClient) prepUploadChunkBody(w io.Writer, fi uploadInfo, offset int64, data io.Reader) (string, error) {
|
||
|
mw := multipart.NewWriter(w)
|
||
|
defer mw.Close()
|
||
|
|
||
|
mw.WriteField("uuid", fi.chunkID)
|
||
|
mw.WriteField("filesize", strconv.FormatInt(fi.totalSize, 10))
|
||
|
mw.WriteField("offset", strconv.FormatInt(offset, 10))
|
||
|
|
||
|
fileWriter, err := mw.CreateFormFile("file", fi.filename)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
_, err = io.Copy(fileWriter, data)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
return mw.Boundary(), nil
|
||
|
}
|