191 lines
6.3 KiB
Go
191 lines
6.3 KiB
Go
// Package client provides a Go SDK for interacting with the MapleFile API.
|
|
package client
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
)
|
|
|
|
// CreatePendingFile creates a new file in pending state.
|
|
func (c *Client) CreatePendingFile(ctx context.Context, input *CreateFileInput) (*PendingFile, error) {
|
|
var resp PendingFile
|
|
if err := c.doRequest(ctx, "POST", "/api/v1/files/pending", input, &resp, true); err != nil {
|
|
return nil, err
|
|
}
|
|
return &resp, nil
|
|
}
|
|
|
|
// GetFile returns a single file by ID.
|
|
func (c *Client) GetFile(ctx context.Context, id string) (*File, error) {
|
|
path := fmt.Sprintf("/api/v1/file/%s", id)
|
|
var resp File
|
|
if err := c.doRequest(ctx, "GET", path, nil, &resp, true); err != nil {
|
|
return nil, err
|
|
}
|
|
return &resp, nil
|
|
}
|
|
|
|
// UpdateFile updates a file's metadata.
|
|
func (c *Client) UpdateFile(ctx context.Context, id string, input *UpdateFileInput) (*File, error) {
|
|
path := fmt.Sprintf("/api/v1/file/%s", id)
|
|
var resp File
|
|
if err := c.doRequest(ctx, "PUT", path, input, &resp, true); err != nil {
|
|
return nil, err
|
|
}
|
|
return &resp, nil
|
|
}
|
|
|
|
// DeleteFile soft-deletes a file.
|
|
func (c *Client) DeleteFile(ctx context.Context, id string) error {
|
|
path := fmt.Sprintf("/api/v1/file/%s", id)
|
|
return c.doRequest(ctx, "DELETE", path, nil, nil, true)
|
|
}
|
|
|
|
// DeleteMultipleFiles deletes multiple files at once.
|
|
func (c *Client) DeleteMultipleFiles(ctx context.Context, fileIDs []string) error {
|
|
input := DeleteMultipleFilesInput{FileIDs: fileIDs}
|
|
return c.doRequest(ctx, "POST", "/api/v1/files/delete-multiple", input, nil, true)
|
|
}
|
|
|
|
// GetPresignedUploadURL gets a presigned URL for uploading file content.
|
|
func (c *Client) GetPresignedUploadURL(ctx context.Context, fileID string) (*PresignedURL, error) {
|
|
path := fmt.Sprintf("/api/v1/file/%s/upload-url", fileID)
|
|
var resp PresignedURL
|
|
if err := c.doRequest(ctx, "GET", path, nil, &resp, true); err != nil {
|
|
return nil, err
|
|
}
|
|
return &resp, nil
|
|
}
|
|
|
|
// CompleteFileUpload marks the file upload as complete and transitions it to active state.
|
|
func (c *Client) CompleteFileUpload(ctx context.Context, fileID string, input *CompleteUploadInput) (*File, error) {
|
|
path := fmt.Sprintf("/api/v1/file/%s/complete", fileID)
|
|
var resp File
|
|
if err := c.doRequest(ctx, "POST", path, input, &resp, true); err != nil {
|
|
return nil, err
|
|
}
|
|
return &resp, nil
|
|
}
|
|
|
|
// GetPresignedDownloadURL gets a presigned URL for downloading file content.
|
|
func (c *Client) GetPresignedDownloadURL(ctx context.Context, fileID string) (*PresignedDownloadResponse, error) {
|
|
path := fmt.Sprintf("/api/v1/file/%s/download-url", fileID)
|
|
var resp PresignedDownloadResponse
|
|
if err := c.doRequest(ctx, "GET", path, nil, &resp, true); err != nil {
|
|
return nil, err
|
|
}
|
|
return &resp, nil
|
|
}
|
|
|
|
// ReportDownloadCompleted reports that a file download has completed.
|
|
func (c *Client) ReportDownloadCompleted(ctx context.Context, fileID string) error {
|
|
path := fmt.Sprintf("/api/v1/file/%s/download-completed", fileID)
|
|
return c.doRequest(ctx, "POST", path, nil, nil, true)
|
|
}
|
|
|
|
// ArchiveFile archives a file.
|
|
func (c *Client) ArchiveFile(ctx context.Context, id string) (*File, error) {
|
|
path := fmt.Sprintf("/api/v1/file/%s/archive", id)
|
|
var resp File
|
|
if err := c.doRequest(ctx, "PUT", path, nil, &resp, true); err != nil {
|
|
return nil, err
|
|
}
|
|
return &resp, nil
|
|
}
|
|
|
|
// RestoreFile restores an archived file.
|
|
func (c *Client) RestoreFile(ctx context.Context, id string) (*File, error) {
|
|
path := fmt.Sprintf("/api/v1/file/%s/restore", id)
|
|
var resp File
|
|
if err := c.doRequest(ctx, "PUT", path, nil, &resp, true); err != nil {
|
|
return nil, err
|
|
}
|
|
return &resp, nil
|
|
}
|
|
|
|
// ListFilesByCollection returns all files in a collection.
|
|
func (c *Client) ListFilesByCollection(ctx context.Context, collectionID string) ([]*File, error) {
|
|
path := fmt.Sprintf("/api/v1/collection/%s/files", collectionID)
|
|
var resp struct {
|
|
Files []*File `json:"files"`
|
|
}
|
|
if err := c.doRequest(ctx, "GET", path, nil, &resp, true); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp.Files, nil
|
|
}
|
|
|
|
// ListRecentFiles returns the user's recent files.
|
|
func (c *Client) ListRecentFiles(ctx context.Context) ([]*File, error) {
|
|
var resp struct {
|
|
Files []*File `json:"files"`
|
|
}
|
|
if err := c.doRequest(ctx, "GET", "/api/v1/files/recent", nil, &resp, true); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp.Files, nil
|
|
}
|
|
|
|
// SyncFiles fetches file changes since the given cursor.
|
|
func (c *Client) SyncFiles(ctx context.Context, input *SyncInput) (*FileSyncResponse, error) {
|
|
var resp FileSyncResponse
|
|
if err := c.doRequest(ctx, "POST", "/api/v1/files/sync", input, &resp, true); err != nil {
|
|
return nil, err
|
|
}
|
|
return &resp, nil
|
|
}
|
|
|
|
// UploadToPresignedURL uploads data to an S3 presigned URL.
|
|
// This is a helper method for uploading encrypted file content directly to S3.
|
|
func (c *Client) UploadToPresignedURL(ctx context.Context, presignedURL string, data []byte, contentType string) error {
|
|
req, err := http.NewRequestWithContext(ctx, "PUT", presignedURL, bytes.NewReader(data))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create upload request: %w", err)
|
|
}
|
|
|
|
req.Header.Set("Content-Type", contentType)
|
|
req.ContentLength = int64(len(data))
|
|
|
|
resp, err := c.httpClient.Do(req)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to upload to presigned URL: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
return fmt.Errorf("upload failed with status %d: %s", resp.StatusCode, string(body))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DownloadFromPresignedURL downloads data from an S3 presigned URL.
|
|
// This is a helper method for downloading encrypted file content directly from S3.
|
|
func (c *Client) DownloadFromPresignedURL(ctx context.Context, presignedURL string) ([]byte, error) {
|
|
req, err := http.NewRequestWithContext(ctx, "GET", presignedURL, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create download request: %w", err)
|
|
}
|
|
|
|
resp, err := c.httpClient.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to download from presigned URL: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
return nil, fmt.Errorf("download failed with status %d: %s", resp.StatusCode, string(body))
|
|
}
|
|
|
|
data, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read download response: %w", err)
|
|
}
|
|
|
|
return data, nil
|
|
}
|