This repository has been archived on 2026-02-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
2026-01-07 09:17:03 +01:00

70 lines
1.8 KiB
Go

package main
import (
"bytes"
"encoding/base64"
"fmt"
"log"
"net/http"
"strconv"
"time"
)
const (
propagateTimeout = 10 * time.Second
)
// Propagator handles forwarding data to peer nodes.
type Propagator struct {
peers []string
client *http.Client
}
// NewPropagator creates a new Propagator instance.
func NewPropagator(peers []string) *Propagator {
return &Propagator{
peers: peers,
client: &http.Client{
Timeout: propagateTimeout,
},
}
}
// PropagateToAllPeers sends the data to all configured peers serially.
// Errors are logged but do not stop propagation to remaining peers.
func (p *Propagator) PropagateToAllPeers(data []byte, filename string, signature []byte, timestamp int64) {
for _, peer := range p.peers {
if err := p.propagateToPeer(peer, data, filename, signature, timestamp); err != nil {
log.Printf("Failed to propagate to peer %s: %v", peer, err)
}
}
}
// propagateToPeer sends data to a single peer.
func (p *Propagator) propagateToPeer(peer string, data []byte, filename string, signature []byte, timestamp int64) error {
url := peer + "/data"
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("X-Filename", filename)
req.Header.Set("X-Signature", base64.StdEncoding.EncodeToString(signature))
req.Header.Set("X-Timestamp", strconv.FormatInt(timestamp, 10))
req.Header.Set("Content-Type", "application/octet-stream")
resp, err := p.client.Do(req)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
// Accept 200 (stored) or 409 (already have newer) as success
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusConflict {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
return nil
}