package blossom import ( "bytes" "crypto/sha256" "fmt" "io" "net/http" "time" ) type Client struct { serverURL string httpClient *http.Client } type BlossomResponse struct { Hash string `json:"hash"` } func NewClient(serverURL string) *Client { return &Client{ serverURL: serverURL, httpClient: &http.Client{ Timeout: 30 * time.Second, }, } } func (c *Client) Put(data []byte) (string, error) { url := c.serverURL + "/upload" req, err := http.NewRequest("PUT", url, bytes.NewReader(data)) if err != nil { return "", fmt.Errorf("error creating PUT request: %w", err) } req.Header.Set("Content-Type", "application/octet-stream") req.Header.Set("Content-Length", fmt.Sprintf("%d", len(data))) resp, err := c.httpClient.Do(req) if err != nil { return "", fmt.Errorf("error executing PUT request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return "", fmt.Errorf("PUT request failed with status %d: %s", resp.StatusCode, string(body)) } // Calculate SHA-256 hash hasher := sha256.New() hasher.Write(data) hash := fmt.Sprintf("%x", hasher.Sum(nil)) return hash, nil } func (c *Client) Get(hash string) ([]byte, error) { url := c.serverURL + "/" + hash resp, err := c.httpClient.Get(url) if err != nil { return nil, fmt.Errorf("error executing GET request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("GET request failed with status %d", resp.StatusCode) } data, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("error reading response body: %w", err) } return data, nil } // MockClient for testing without a real Blossom server type MockClient struct { storage map[string][]byte } func NewMockClient() *MockClient { return &MockClient{ storage: make(map[string][]byte), } } func (m *MockClient) Put(data []byte) (string, error) { // Calculate SHA-256 hash hasher := sha256.New() hasher.Write(data) hash := fmt.Sprintf("%x", hasher.Sum(nil)) m.storage[hash] = data return hash, nil } func (m *MockClient) Get(hash string) ([]byte, error) { data, exists := m.storage[hash] if !exists { return nil, fmt.Errorf("blob not found: %s", hash) } return data, nil }