feat: native clipboard image sync (Linux, opt-in sync_images)

This commit is contained in:
2026-08-14 09:51:25 -04:00
parent 884415c1c1
commit 147cba6d2a
15 changed files with 274 additions and 48 deletions
+16 -3
View File
@@ -35,9 +35,12 @@ func NewFilter(origin string) *Filter {
}
}
// Payload represents an incoming clip payload from a peer.
// Payload represents an incoming clip payload from a peer. It carries either
// text (Text) or a base64-encoded image (Mime + Data).
type Payload struct {
Text string `json:"text"`
Mime string `json:"mime,omitempty"`
Data string `json:"data,omitempty"` // base64-encoded image bytes
Ts int64 `json:"ts"`
Origin string `json:"origin"`
}
@@ -58,7 +61,7 @@ func (f *Filter) ShouldIgnore(p Payload) bool {
}
// Guard 3: ignore content we recently wrote (hash match).
hash := hashText(p.Text)
hash := hashText(p.Text + "\x00" + p.Data)
for _, h := range f.cache {
if h == hash {
return true
@@ -71,11 +74,21 @@ func (f *Filter) ShouldIgnore(p Payload) bool {
// MarkWritten records that we just wrote text to the local clipboard.
// This populates the hash cache and updates the last-write timestamp.
func (f *Filter) MarkWritten(text string) {
f.markWritten(text)
}
// MarkWrittenPayload records that we just wrote a payload (text or image) to
// the local clipboard, so echoes of it are ignored.
func (f *Filter) MarkWrittenPayload(p Payload) {
f.markWritten(p.Text + "\x00" + p.Data)
}
func (f *Filter) markWritten(content string) {
f.mu.Lock()
defer f.mu.Unlock()
now := time.Now().UnixNano()
hash := hashText(text)
hash := hashText(content)
// Ring buffer: overwrite oldest entry when full.
if len(f.cache) < defaultCacheSize {
+16
View File
@@ -69,6 +69,22 @@ func TestShouldAcceptNewContent(t *testing.T) {
}
}
func TestShouldIgnoreDuplicateImageHash(t *testing.T) {
f := NewFilter("machine-a")
f.MarkWrittenPayload(Payload{Mime: "image/png", Data: "aGVsbG8="})
p := Payload{
Mime: "image/png",
Data: "aGVsbG8=",
Ts: time.Now().UnixNano(),
Origin: "machine-b",
}
if !f.ShouldIgnore(p) {
t.Error("should ignore image payload with recently written data hash")
}
}
func TestCacheEviction(t *testing.T) {
f := NewFilter("machine-a")