feat: native clipboard image sync (Linux, opt-in sync_images)
This commit is contained in:
+27
-18
@@ -5,6 +5,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
@@ -84,8 +85,25 @@ func buildTLSConfig(opts Options) *tls.Config {
|
||||
// Errors are logged but not returned — a single unreachable peer should not
|
||||
// block other peers or the daemon loop.
|
||||
func (b *Broadcaster) Broadcast(text string) {
|
||||
body, ok := b.marshalPayload(text)
|
||||
if !ok {
|
||||
b.BroadcastPayload(dedup.Payload{Text: text})
|
||||
}
|
||||
|
||||
// BroadcastImage sends an image (base64-encoded) to all peers in parallel.
|
||||
func (b *Broadcaster) BroadcastImage(mime string, data []byte) {
|
||||
b.BroadcastPayload(dedup.Payload{
|
||||
Mime: mime,
|
||||
Data: base64.StdEncoding.EncodeToString(data),
|
||||
})
|
||||
}
|
||||
|
||||
// BroadcastPayload sends an arbitrary payload to all peers in parallel.
|
||||
func (b *Broadcaster) BroadcastPayload(p dedup.Payload) {
|
||||
p.Ts = time.Now().UnixNano()
|
||||
p.Origin = b.origin
|
||||
|
||||
body, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
log.Printf("peer: marshal payload: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -99,8 +117,13 @@ func (b *Broadcaster) Broadcast(text string) {
|
||||
// has completed (or failed). Used by the one-shot mode so the process does not
|
||||
// exit before the payload is on the wire.
|
||||
func (b *Broadcaster) BroadcastSync(text string) {
|
||||
body, ok := b.marshalPayload(text)
|
||||
if !ok {
|
||||
body, err := json.Marshal(dedup.Payload{
|
||||
Text: text,
|
||||
Ts: time.Now().UnixNano(),
|
||||
Origin: b.origin,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("peer: marshal payload: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -116,20 +139,6 @@ func (b *Broadcaster) BroadcastSync(text string) {
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (b *Broadcaster) marshalPayload(text string) ([]byte, bool) {
|
||||
payload := dedup.Payload{
|
||||
Text: text,
|
||||
Ts: time.Now().UnixNano(),
|
||||
Origin: b.origin,
|
||||
}
|
||||
body, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
log.Printf("peer: marshal payload: %v", err)
|
||||
return nil, false
|
||||
}
|
||||
return body, true
|
||||
}
|
||||
|
||||
// snapshot returns a copy of the current peer list under read lock.
|
||||
func (b *Broadcaster) snapshot() []config.PeerConfig {
|
||||
b.mu.RLock()
|
||||
|
||||
@@ -61,3 +61,35 @@ func TestBroadcastEmptyPeers(t *testing.T) {
|
||||
b.Broadcast("test")
|
||||
b.Broadcast("")
|
||||
}
|
||||
|
||||
func TestBroadcastImage(t *testing.T) {
|
||||
received := make(chan dedup.Payload, 1)
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var p dedup.Payload
|
||||
if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
|
||||
t.Errorf("decode: %v", err)
|
||||
}
|
||||
received <- p
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
b := NewBroadcaster([]config.PeerConfig{{Name: "p", Addr: ts.Listener.Addr().String()}}, "my-machine", Options{})
|
||||
b.BroadcastImage("image/png", []byte{1, 2, 3})
|
||||
|
||||
select {
|
||||
case p := <-received:
|
||||
if p.Mime != "image/png" {
|
||||
t.Errorf("mime = %q, want \"image/png\"", p.Mime)
|
||||
}
|
||||
if p.Data != "AQID" { // base64 of {1,2,3}
|
||||
t.Errorf("data = %q, want \"AQID\"", p.Data)
|
||||
}
|
||||
if p.Text != "" {
|
||||
t.Errorf("text = %q, want empty", p.Text)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("timeout waiting for image broadcast")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user