first commit

This commit is contained in:
Space-Banane
2026-01-17 15:19:07 +01:00
commit 4e637bc27d
15 changed files with 511 additions and 0 deletions

26
client/embedicon.go Normal file
View File

@@ -0,0 +1,26 @@
//go:build ignore
// +build ignore
package main
import (
"fmt"
"os"
)
func main() {
data, err := os.ReadFile("../syncup.ico")
if err != nil {
fmt.Println("Error reading icon:", err)
return
}
fmt.Println("var EmbeddedIcon = []byte{")
for i, b := range data {
if i%12 == 0 {
fmt.Print("\n\t")
}
fmt.Printf("0x%02X, ", b)
}
fmt.Println("\n}")
}

25
client/go.mod Normal file
View File

@@ -0,0 +1,25 @@
module clipboard-on-the-go
go 1.25.5
require (
github.com/joho/godotenv v1.5.1
golang.design/x/clipboard v0.7.1
)
require (
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 // indirect
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect
github.com/getlantern/systray v1.2.2 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
golang.org/x/exp/shiny v0.0.0-20250606033433-dcc06ee1d476 // indirect
golang.org/x/image v0.28.0 // indirect
golang.org/x/mobile v0.0.0-20250606033058-a2a15c67f36f // indirect
golang.org/x/sys v0.33.0 // indirect
)

42
client/go.sum Normal file
View File

@@ -0,0 +1,42 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So=
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk=
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc=
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0=
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc=
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA=
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
github.com/getlantern/systray v1.2.2 h1:dCEHtfmvkJG7HZ8lS/sLklTH4RKUcIsKrAD9sThoEBE=
github.com/getlantern/systray v1.2.2/go.mod h1:pXFOI1wwqwYXEhLPm9ZGjS2u/vVELeIgNMY5HvhHhcE=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.design/x/clipboard v0.7.1 h1:OEG3CmcYRBNnRwpDp7+uWLiZi3hrMRJpE9JkkkYtz2c=
golang.design/x/clipboard v0.7.1/go.mod h1:i5SiIqj0wLFw9P/1D7vfILFK0KHMk7ydE72HRrUIgkg=
golang.org/x/exp/shiny v0.0.0-20250606033433-dcc06ee1d476 h1:Wdx0vgH5Wgsw+lF//LJKmWOJBLWX6nprsMqnf99rYDE=
golang.org/x/exp/shiny v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:ygj7T6vSGhhm/9yTpOQQNvuAUFziTH7RUiH74EoE2C8=
golang.org/x/image v0.28.0 h1:gdem5JW1OLS4FbkWgLO+7ZeFzYtL3xClb97GaUzYMFE=
golang.org/x/image v0.28.0/go.mod h1:GUJYXtnGKEUgggyzh+Vxt+AviiCcyiwpsl8iQ8MvwGY=
golang.org/x/mobile v0.0.0-20250606033058-a2a15c67f36f h1:/n+PL2HlfqeSiDCuhdBbRNlGS/g2fM4OHufalHaTVG8=
golang.org/x/mobile v0.0.0-20250606033058-a2a15c67f36f/go.mod h1:ESkJ836Z6LpG6mTVAhA48LpfW/8fNR0ifStlH2axyfg=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=

10
client/icon.go Normal file
View File

@@ -0,0 +1,10 @@
package main
// EmbeddedIcon contains the icon data
// To generate this, run: go run embedicon.go
var EmbeddedIcon = []byte{
// Replace this with your actual icon bytes
// You can use a tool or script to convert syncup.ico to byte array
// For now, using minimal PNG as placeholder
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
}

144
client/sync.go Normal file
View File

@@ -0,0 +1,144 @@
package main
import (
"bytes"
"fmt"
"log"
"github.com/getlantern/systray"
"github.com/gorilla/websocket"
"golang.design/x/clipboard"
)
var (
conn *websocket.Conn
lastClipboard []byte
identification string
isConnected bool
)
func onReady() {
// Use embedded icon
systray.SetIcon(EmbeddedIcon)
systray.SetTitle("Clipboard Sync")
systray.SetTooltip("Clipboard synchronization active")
mStatus := systray.AddMenuItem("Status: Connecting...", "Connection status")
mStatus.Disable()
systray.AddSeparator()
mQuit := systray.AddMenuItem("Quit", "Quit the application")
// Start clipboard monitoring
go monitorClipboard()
// Start client connection
go startClient(mStatus)
// Handle menu interactions
go func() {
for {
select {
case <-mQuit.ClickedCh:
systray.Quit()
}
}
}()
}
func onExit() {
if conn != nil {
conn.Close()
}
log.Println("Exiting clipboard sync client")
}
func startClient(statusItem *systray.MenuItem) {
// Use embedded configuration
identification = EmbeddedIdentification
server_ip := EmbeddedServerIP
server_port := EmbeddedServerPort
server_connection := "ws://" + server_ip + ":" + server_port + "/ws"
if identification == "" || server_ip == "" || server_port == "" {
log.Println("Missing configuration")
statusItem.SetTitle("Status: Config error")
return
}
// Connect to the server
var connectErr error
conn, _, connectErr = websocket.DefaultDialer.Dial(server_connection, nil)
if connectErr != nil {
log.Println("Error connecting to server:", connectErr)
statusItem.SetTitle("Status: Connection failed")
return
}
// Send identification to the server
sendMessage(conn, websocket.TextMessage, []byte(identification))
isConnected = true
statusItem.SetTitle(fmt.Sprintf("Status: Connected (%s)", identification))
log.Println("Connected to server")
// Listen for messages from the server
for {
messageType, message, err := conn.ReadMessage()
if err != nil {
log.Println("Error reading message:", err)
isConnected = false
statusItem.SetTitle("Status: Disconnected")
return
}
handleMessage(messageType, message)
}
}
func handleMessage(messageType int, message []byte) {
log.Printf("Received clipboard update: %d bytes", len(message))
// Update local clipboard tracking to avoid re-sending
lastClipboard = make([]byte, len(message))
copy(lastClipboard, message)
// Write to clipboard
clipboard.Write(clipboard.FmtText, message)
log.Println("Clipboard updated")
}
func sendMessage(conn *websocket.Conn, messageType int, message []byte) {
err := conn.WriteMessage(messageType, message)
if err != nil {
log.Println("Error sending message:", err)
}
}
func monitorClipboard() {
for {
if isConnected && conn != nil {
data := clipboard.Read(clipboard.FmtText)
// Check if clipboard has changed
if len(data) > 0 && !bytes.Equal(data, lastClipboard) {
log.Printf("Clipboard changed, sending to server: %d bytes", len(data))
sendMessage(conn, websocket.TextMessage, data)
lastClipboard = make([]byte, len(data))
copy(lastClipboard, data)
}
}
}
}
func getDefaultIcon() []byte {
return EmbeddedIcon
}
func main() {
// Initialize clipboard
clip_err := clipboard.Init()
if clip_err != nil {
log.Fatal("Failed to initialize clipboard:", clip_err)
}
// Run systray application
systray.Run(onReady, onExit)
}