From 405a390dd8801e79a70605ed92fc8ed5ee8381ce Mon Sep 17 00:00:00 2001
From: kevin
Date: Thu, 30 Jul 2026 14:44:28 +0800
Subject: [PATCH 1/6] Upgrade from Wails v2 to v3 with expanded test coverage
Migrate the desktop app to Wails v3 (application services, Event.Emit,
dialog API, data-file-drop-target) and keep Linux on gtk3/webkit2gtk 4.1.
Add App API integration tests before the upgrade so transfers, settings,
and event wiring keep working across the cutover.
---
.github/workflows/ci.yml | 22 +-
.github/workflows/release.yml | 41 +-
.gitignore | 10 +-
README.md | 36 +-
Taskfile.yml | 47 +++
app.go | 59 ++-
app_api_test.go | 256 +++++++++++
build/Taskfile.yml | 398 ++++++++++++++++++
build/config.yml | 47 +++
build/darwin/Assets.car | Bin 0 -> 1631800 bytes
build/darwin/Info.dev.plist | 34 ++
build/darwin/Info.plist | 29 ++
build/darwin/Taskfile.yml | 193 +++++++++
build/darwin/icons.icns | Bin 0 -> 119102 bytes
build/linux/Taskfile.yml | 220 ++++++++++
build/linux/appimage/build.sh | 35 ++
build/linux/croc-desktop.desktop | 10 +
build/linux/desktop | 13 +
build/linux/nfpm/nfpm.yaml | 80 ++++
build/linux/nfpm/scripts/postinstall.sh | 21 +
build/linux/nfpm/scripts/postremove.sh | 1 +
build/linux/nfpm/scripts/preinstall.sh | 1 +
build/linux/nfpm/scripts/preremove.sh | 1 +
build/windows/Taskfile.yml | 195 +++++++++
build/windows/icon.ico | Bin 0 -> 12452 bytes
build/windows/info.json | 15 +
build/windows/msix/app_manifest.xml | 55 +++
build/windows/msix/template.xml | 54 +++
build/windows/nsis/project.nsi | 119 ++++++
build/windows/nsis/wails_tools.nsh | 261 ++++++++++++
build/windows/wails.exe.manifest | 22 +
e2e/README.md | 4 +-
e2e/run.sh | 12 +-
frontend/bindings/croc-desktop/app.ts | 196 +++++++++
frontend/bindings/croc-desktop/index.ts | 12 +
frontend/bindings/croc-desktop/models.ts | 310 ++++++++++++++
.../wailsapp/wails/v3/internal/eventcreate.ts | 9 +
.../wailsapp/wails/v3/internal/eventdata.d.ts | 2 +
frontend/eslint.config.js | 2 +-
frontend/package-lock.json | 7 +
frontend/package.json | 1 +
frontend/src/api.ts | 102 ++++-
frontend/src/components/DropZone.tsx | 6 +-
frontend/src/wails.d.ts | 10 +-
frontend/tsconfig.json | 3 +-
frontend/vite.config.ts | 7 +-
go.mod | 28 +-
go.sum | 76 +---
logger.go | 10 +-
main.go | 78 ++--
packaging/windows/Product.wxs | 2 +-
qrdecode.go | 20 +-
relay.go | 13 +-
transfer.go | 13 +-
wails.json | 13 -
55 files changed, 2970 insertions(+), 241 deletions(-)
create mode 100644 Taskfile.yml
create mode 100644 app_api_test.go
create mode 100644 build/Taskfile.yml
create mode 100644 build/config.yml
create mode 100644 build/darwin/Assets.car
create mode 100644 build/darwin/Info.dev.plist
create mode 100644 build/darwin/Info.plist
create mode 100644 build/darwin/Taskfile.yml
create mode 100644 build/darwin/icons.icns
create mode 100644 build/linux/Taskfile.yml
create mode 100644 build/linux/appimage/build.sh
create mode 100755 build/linux/croc-desktop.desktop
create mode 100644 build/linux/desktop
create mode 100644 build/linux/nfpm/nfpm.yaml
create mode 100644 build/linux/nfpm/scripts/postinstall.sh
create mode 100644 build/linux/nfpm/scripts/postremove.sh
create mode 100644 build/linux/nfpm/scripts/preinstall.sh
create mode 100644 build/linux/nfpm/scripts/preremove.sh
create mode 100644 build/windows/Taskfile.yml
create mode 100644 build/windows/icon.ico
create mode 100644 build/windows/info.json
create mode 100644 build/windows/msix/app_manifest.xml
create mode 100644 build/windows/msix/template.xml
create mode 100644 build/windows/nsis/project.nsi
create mode 100644 build/windows/nsis/wails_tools.nsh
create mode 100644 build/windows/wails.exe.manifest
create mode 100644 frontend/bindings/croc-desktop/app.ts
create mode 100644 frontend/bindings/croc-desktop/index.ts
create mode 100644 frontend/bindings/croc-desktop/models.ts
create mode 100644 frontend/bindings/github.com/wailsapp/wails/v3/internal/eventcreate.ts
create mode 100644 frontend/bindings/github.com/wailsapp/wails/v3/internal/eventdata.d.ts
delete mode 100644 wails.json
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 65964e3..2788b59 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -27,21 +27,31 @@ jobs:
working-directory: frontend
run: npm ci && npm run build
+ # Wails v3 Linux defaults to gtk4/webkitgtk6; this project targets the
+ # gtk3/webkit2gtk 4.1 stack (EXTRA_TAGS=gtk3) for broader distro support.
+ - name: Install webview deps
+ run: sudo apt-get update && sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev
+
- name: golangci-lint
# built from source with the runner's Go so its language version
# always matches go.mod (prebuilt binaries lag behind)
run: |
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
- golangci-lint run ./...
+ golangci-lint run --build-tags gtk3 ./...
- name: gofmt check
- run: test -z "$(gofmt -l .)" || { gofmt -l .; exit 1; }
+ run: |
+ files=$(find . -name '*.go' \
+ -not -path './frontend/node_modules/*' \
+ -not -path './e2e/node_modules/*' \
+ -not -path './bin/*')
+ test -z "$(gofmt -l $files)" || { gofmt -l $files; exit 1; }
- name: go vet
- run: go vet ./...
+ run: go vet -tags gtk3 ./...
- name: go test
- run: go test -timeout 300s ./...
+ run: go test -tags gtk3 -timeout 300s ./...
frontend:
name: Frontend — format, lint, typecheck, build
@@ -95,8 +105,8 @@ jobs:
cache: npm
cache-dependency-path: frontend/package-lock.json
- - name: Install Wails CLI
- run: go install github.com/wailsapp/wails/v2/cmd/wails@v2.13.0
+ - name: Install Wails v3 CLI
+ run: go install -tags gtk3 github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0-alpha2.119
- name: Install webview and display deps
run: sudo apt-get update && sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev xvfb
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 44a331a..8210cf2 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -44,15 +44,26 @@ jobs:
cache: npm
cache-dependency-path: frontend/package-lock.json
- - name: Install Wails CLI
- run: go install github.com/wailsapp/wails/v2/cmd/wails@v2.13.0
+ - name: Install Wails v3 CLI
+ # gtk3 tag: CLI itself links webkit; needed on Linux runners without gtk4
+ run: go install -tags gtk3 github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0-alpha2.119
- name: Install Linux webview deps
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev imagemagick
- - name: Build
- run: wails build -platform ${{ matrix.platform }} -tags webkit2_41 -o ${{ matrix.bin }}
+ # Wails v3 builds for the host OS via Taskfile; matrix runners are
+ # native (ubuntu → linux, macos → darwin, windows → windows).
+ # Linux uses EXTRA_TAGS=gtk3 (webkit2gtk 4.1) so CI doesn't need gtk4.
+ - name: Build (Linux)
+ if: runner.os == 'Linux'
+ run: wails3 build -tags gtk3
+ env:
+ EXTRA_TAGS: gtk3
+
+ - name: Build (macOS / Windows)
+ if: runner.os != 'Linux'
+ run: wails3 build
# ---------- Linux: AppImage ----------
@@ -66,7 +77,8 @@ jobs:
if: runner.os == 'Linux'
run: |
mkdir -p AppDir/usr/bin
- cp build/bin/croc-desktop AppDir/usr/bin/
+ # v3 places host builds in bin/ (Taskfile BIN_DIR)
+ cp bin/croc-desktop AppDir/usr/bin/
# linuxdeploy only accepts standard icon resolutions (max 512px)
# and deploys the icon by basename, which must match Icon=croc-desktop
convert build/appicon.png -resize 512x512 /tmp/croc-desktop.png
@@ -84,11 +96,20 @@ jobs:
- name: Ad-hoc sign and package DMG
if: runner.os == 'macOS'
run: |
- cd build/bin
- codesign --deep --force --sign - croc-desktop.app
- mkdir -p dmg
- cp -R croc-desktop.app dmg/
- hdiutil create -volname croc -srcfolder dmg -ov -format UDZO ../../${{ matrix.artifact }}
+ # wails3 package lays out a .app under bin/; fall back to a bare binary
+ APP_PATH="bin/croc-desktop.app"
+ if [ ! -d "$APP_PATH" ]; then
+ wails3 package
+ fi
+ if [ -d "$APP_PATH" ]; then
+ codesign --deep --force --sign - "$APP_PATH"
+ mkdir -p dmg
+ cp -R "$APP_PATH" dmg/
+ else
+ mkdir -p dmg
+ cp bin/croc-desktop dmg/
+ fi
+ hdiutil create -volname croc -srcfolder dmg -ov -format UDZO ${{ matrix.artifact }}
# ---------- Windows: MSI ----------
diff --git a/.gitignore b/.gitignore
index 484f7dc..b6fd652 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,11 @@
# Binaries / build output
+bin/
build/bin/
/croc-gui
+/croc-desktop
+
+# Task (taskfile.dev) cache
+.task/
# Test binary, built with `go test -c`
*.test
@@ -9,5 +14,8 @@ build/bin/
frontend/node_modules/
frontend/dist/
-# Wails generated bindings
+# Wails v2 generated bindings (legacy)
frontend/wailsjs/
+
+# Wails v3 binding generation temps
+frontend/.bindings-tmp-*/
diff --git a/README.md b/README.md
index a74bd8c..5a84b4e 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@
-
+
@@ -79,37 +79,49 @@ Download from [Releases](https://github.com/SihanTeng/croc-desktop/releases):
## Develop
-Prerequisites: Go (see `go.mod`), Node.js + npm, the Wails v2 CLI
-(`go install github.com/wailsapp/wails/v2/cmd/wails@latest`), and platform
-webview deps (`wails doctor`; on Linux: GTK3 + webkit2gtk dev packages, e.g.
-`webkit2gtk4.1-devel` on Fedora, `libwebkit2gtk-4.1-dev` on Debian/Ubuntu).
+Prerequisites: Go (see `go.mod`), Node.js + npm, the Wails v3 CLI, and
+platform webview deps (`wails3 doctor`).
```sh
-wails dev # hot-reload; on distros with webkit2gtk 4.1:
- # WEBKIT_DISABLE_DMABUF_RENDERER=1 wails dev -tags webkit2_41
+# Install the CLI (use -tags gtk3 on Linux if you have webkit2gtk 4.1 but not gtk4)
+go install -tags gtk3 github.com/wailsapp/wails/v3/cmd/wails3@latest
+
+# Linux: GTK3 + webkit2gtk 4.1 (this project’s default), e.g.
+# webkit2gtk4.1-devel on Fedora, libwebkit2gtk-4.1-dev on Debian/Ubuntu
+# Optional native gtk4 path: install gtk4 + webkitgtk 6 and build with EXTRA_TAGS=
+
+WEBKIT_DISABLE_DMABUF_RENDERER=1 wails3 dev # or: task dev
```
(`WEBKIT_DISABLE_DMABUF_RENDERER=1` works around a WebKitGTK crash on some
Wayland compositors.)
+Dev mode loads the Vite server (default port **34115** for this project) and
+rebuilds Go on change. Frontend bindings live under `frontend/bindings/` and
+are regenerated during `wails3 build` / `wails3 generate bindings`.
+
## Build
```sh
-wails build # add -tags webkit2_41 where applicable
-# binary lands in build/bin/
+wails3 build -tags gtk3 # Linux with webkit2gtk 4.1 (default for this repo)
+# or: task build
+# binary lands in bin/croc-desktop
```
+On macOS/Windows, omit the gtk3 tag (`wails3 build`). For Linux with gtk4 +
+webkitgtk 6 installed: `EXTRA_TAGS= wails3 build`.
+
## Test
Three layers:
-- **Backend** (`go test .`): unit tests for settings/history/logger/code
+- **Backend** (`go test -tags gtk3 .`): unit tests for settings/history/logger/code
parsing plus headless integration tests that drive the real transfer path
(`App` methods → `src/croc` → in-process relay) without a window:
```sh
npm --prefix frontend install && npm --prefix frontend run build # frontend/dist for go:embed
- go test .
+ go test -tags gtk3 .
```
- **Frontend** (`npm --prefix frontend run test`): vitest unit tests for the
@@ -117,7 +129,7 @@ Three layers:
- **Browser E2E** (`./e2e/run.sh`): playwright drives the real app UI in a
browser against throwaway croc peers — send text, receive with preview,
- decline, Esc cancel, history & logs. Uses the running `wails dev` instance
+ decline, Esc cancel, history & logs. Uses the running `wails3 dev` instance
if there is one, otherwise boots a hermetic sandbox (local relay + isolated
config). See `e2e/README.md`.
diff --git a/Taskfile.yml b/Taskfile.yml
new file mode 100644
index 0000000..42b7934
--- /dev/null
+++ b/Taskfile.yml
@@ -0,0 +1,47 @@
+version: '3'
+
+vars:
+ APP_NAME: "croc-desktop"
+ BIN_DIR: "bin"
+ PACKAGE_MANAGER: '{{.PACKAGE_MANAGER | default "npm"}}'
+ VITE_PORT: '{{.WAILS_VITE_PORT | default 34115}}'
+ GOOS: '{{.GOOS | default OS}}'
+ # Default to gtk3 on Linux so builds work with webkit2gtk 4.1 (same as v2).
+ # For native gtk4/webkitgtk 6: EXTRA_TAGS= (empty) or install gtk4 + webkitgtk6.
+ EXTRA_TAGS: '{{.EXTRA_TAGS | default "gtk3"}}'
+
+includes:
+ common: ./build/Taskfile.yml
+ windows: ./build/windows/Taskfile.yml
+ darwin: ./build/darwin/Taskfile.yml
+ linux: ./build/linux/Taskfile.yml
+
+tasks:
+ build:
+ summary: Builds the application
+ cmds:
+ - task: "{{.GOOS}}:build"
+ vars:
+ EXTRA_TAGS: "{{.EXTRA_TAGS}}"
+ DEV: "{{.DEV}}"
+ ARCH: "{{.ARCH}}"
+ OUTPUT: "{{.OUTPUT}}"
+
+ package:
+ summary: Packages a production build of the application
+ cmds:
+ - task: "{{.GOOS}}:package"
+ vars:
+ EXTRA_TAGS: "{{.EXTRA_TAGS}}"
+
+ run:
+ summary: Runs the application
+ cmds:
+ - task: "{{.GOOS}}:run"
+ vars:
+ EXTRA_TAGS: "{{.EXTRA_TAGS}}"
+
+ dev:
+ summary: Runs the application in development mode
+ cmds:
+ - wails3 dev -config ./build/config.yml -port {{.VITE_PORT}}
diff --git a/app.go b/app.go
index 4eeccc9..d1729e0 100644
--- a/app.go
+++ b/app.go
@@ -14,11 +14,11 @@ import (
"github.com/schollz/croc/v10/src/croc"
"github.com/schollz/croc/v10/src/utils"
"github.com/skip2/go-qrcode"
- wailsruntime "github.com/wailsapp/wails/v2/pkg/runtime"
+ "github.com/wailsapp/wails/v3/pkg/application"
)
-// App is the Wails-bound backend. All exported methods are callable from the
-// frontend.
+// App is the Wails-bound backend service. All exported methods are callable
+// from the frontend via generated bindings.
type App struct {
tm *transferManager
rm *relayManager
@@ -46,40 +46,55 @@ func NewApp() *App {
}
}
-func (a *App) startup(ctx context.Context) {
- a.lm.setWailsCtx(ctx)
- a.tm.setWailsCtx(ctx)
- a.rm.setWailsCtx(ctx)
- wailsruntime.OnFileDrop(ctx, a.onFileDrop)
+// ServiceStartup wires managers to the Wails event bus. File drops are handled
+// on the window in main.go.
+func (a *App) ServiceStartup(_ context.Context, _ application.ServiceOptions) error {
+ a.wireEmit(func(event string, data interface{}) {
+ if app := application.Get(); app != nil {
+ app.Event.Emit(event, data)
+ }
+ })
a.logInfo("app", "croc-desktop started")
+ return nil
}
-func (a *App) shutdown(ctx context.Context) {
+// ServiceShutdown cancels any in-flight transfer and stops a hosted relay.
+func (a *App) ServiceShutdown() error {
a.tm.cancelTransfer()
a.rm.stop()
+ return nil
}
-// onFileDrop receives native file drops (paths, not web File objects) and
-// forwards them to the frontend.
-func (a *App) onFileDrop(x, y int, paths []string) {
- if a.tm.wailsCtx == nil {
- return
- }
- wailsruntime.EventsEmit(a.tm.wailsCtx, "files:dropped", paths)
+// wireEmit publishes frontend events; tests inject a capture sink instead.
+func (a *App) wireEmit(emit func(event string, data interface{})) {
+ a.tm.setEmit(emit)
+ a.lm.setEmit(emit)
+ a.rm.setEmit(emit)
}
// --- dialogs ---
func (a *App) PickFiles() ([]string, error) {
- return wailsruntime.OpenMultipleFilesDialog(a.tm.wailsCtx, wailsruntime.OpenDialogOptions{
- Title: "Choose files to send",
- })
+ app := application.Get()
+ if app == nil {
+ return nil, fmt.Errorf("application not ready")
+ }
+ return app.Dialog.OpenFile().
+ CanChooseFiles(true).
+ SetTitle("Choose files to send").
+ PromptForMultipleSelection()
}
func (a *App) PickDirectory() (string, error) {
- return wailsruntime.OpenDirectoryDialog(a.tm.wailsCtx, wailsruntime.OpenDialogOptions{
- Title: "Choose a folder",
- })
+ app := application.Get()
+ if app == nil {
+ return "", fmt.Errorf("application not ready")
+ }
+ return app.Dialog.OpenFile().
+ CanChooseDirectories(true).
+ CanChooseFiles(false).
+ SetTitle("Choose a folder").
+ PromptForSingleSelection()
}
// PathsIsDir reports which of the given paths are directories, so the UI can
diff --git a/app_api_test.go b/app_api_test.go
new file mode 100644
index 0000000..599b694
--- /dev/null
+++ b/app_api_test.go
@@ -0,0 +1,256 @@
+package main
+
+import (
+ "encoding/base64"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+ "time"
+)
+
+// Coverage for App methods that the frontend calls frequently but that
+// previously had little or no automated coverage. These must keep working
+// across the Wails v2 → v3 migration.
+
+func TestPathsIsDir(t *testing.T) {
+ dir := t.TempDir()
+ file := filepath.Join(dir, "f.txt")
+ if err := os.WriteFile(file, []byte("x"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ nested := filepath.Join(dir, "sub")
+ if err := os.Mkdir(nested, 0o755); err != nil {
+ t.Fatal(err)
+ }
+
+ a := NewApp()
+ got := a.PathsIsDir([]string{file, nested, filepath.Join(dir, "missing"), dir})
+ want := map[string]bool{nested: true, dir: true}
+ if len(got) != 2 {
+ t.Fatalf("PathsIsDir: got %v, want 2 dirs", got)
+ }
+ for _, p := range got {
+ if !want[p] {
+ t.Errorf("unexpected dir %q in %v", p, got)
+ }
+ }
+ if a.PathsIsDir(nil) != nil && len(a.PathsIsDir(nil)) != 0 {
+ t.Fatalf("nil paths should yield empty slice, got %v", a.PathsIsDir(nil))
+ }
+}
+
+func TestGetQrPng(t *testing.T) {
+ a := NewApp()
+ b64, err := a.GetQrPng("4523-ivan-twist-order")
+ if err != nil {
+ t.Fatalf("GetQrPng: %v", err)
+ }
+ if b64 == "" {
+ t.Fatal("expected non-empty base64 PNG")
+ }
+ raw, err := base64.StdEncoding.DecodeString(b64)
+ if err != nil {
+ t.Fatalf("not valid base64: %v", err)
+ }
+ // PNG magic
+ if len(raw) < 8 || string(raw[:8]) != "\x89PNG\r\n\x1a\n" {
+ t.Fatalf("expected PNG payload, got %d bytes starting %x", len(raw), raw[:min(8, len(raw))])
+ }
+}
+
+func TestGetDefaultDownloadDir(t *testing.T) {
+ a := NewApp()
+ dir, err := a.GetDefaultDownloadDir()
+ if err != nil {
+ t.Fatalf("GetDefaultDownloadDir: %v", err)
+ }
+ if dir == "" {
+ t.Fatal("expected a non-empty download dir")
+ }
+ st, err := os.Stat(dir)
+ if err != nil || !st.IsDir() {
+ t.Fatalf("download dir %q is not a directory: %v", dir, err)
+ }
+}
+
+func TestIsTransferRunningAndConcurrentSend(t *testing.T) {
+ srcDir := t.TempDir()
+ src := filepath.Join(srcDir, "busy.txt")
+ if err := os.WriteFile(src, []byte("payload"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+
+ a, _ := newTestApp()
+ if a.IsTransferRunning() {
+ t.Fatal("expected no transfer before StartSend")
+ }
+ if _, err := a.StartSend([]string{src}); err != nil {
+ t.Fatalf("StartSend: %v", err)
+ }
+ if !a.IsTransferRunning() {
+ t.Fatal("expected transfer to be running after StartSend")
+ }
+ if _, err := a.StartSend([]string{src}); err == nil || !strings.Contains(err.Error(), "already in progress") {
+ t.Fatalf("expected 'already in progress', got %v", err)
+ }
+ if err := a.StartReceive("4523-ivan-twist-order", t.TempDir()); err == nil ||
+ !strings.Contains(err.Error(), "already in progress") {
+ t.Fatalf("expected 'already in progress' on receive, got %v", err)
+ }
+ a.CancelTransfer()
+ // cancel is async; give it a moment to clear the running flag
+ deadline := time.Now().Add(10 * time.Second)
+ for a.IsTransferRunning() && time.Now().Before(deadline) {
+ time.Sleep(50 * time.Millisecond)
+ }
+ if a.IsTransferRunning() {
+ t.Fatal("transfer still running after cancel")
+ }
+}
+
+func TestHistoryAndLogsClear(t *testing.T) {
+ a, l := newTestApp()
+ // seed a completed text transfer so history is non-empty
+ const msg = "history clear test"
+ receiver, receiverLog := newTestApp()
+ receiverLog.onAccept = func() { receiver.RespondAccept(true) }
+
+ code, err := a.StartSendText(msg)
+ if err != nil {
+ t.Fatalf("StartSendText: %v", err)
+ }
+ if err := receiver.StartReceive(code, t.TempDir()); err != nil {
+ t.Fatalf("StartReceive: %v", err)
+ }
+ waitDone(t, receiverLog, "text receive")
+ waitDone(t, l, "text send")
+
+ if len(a.GetHistory()) == 0 {
+ t.Fatal("expected history after transfer")
+ }
+ a.ClearHistory()
+ if h := a.GetHistory(); h == nil || len(h) != 0 {
+ t.Fatalf("ClearHistory left %v", h)
+ }
+
+ // log buffer starts empty under newTestApp (no startup wiring)
+ if logs := a.GetLogs(); logs == nil || len(logs) != 0 {
+ // may have entries from transfer; just ensure Clear works
+ }
+ a.ClearLogs()
+ if logs := a.GetLogs(); logs == nil || len(logs) != 0 {
+ t.Fatalf("ClearLogs left %v", logs)
+ }
+}
+
+func TestEmitWiringDeliversEvents(t *testing.T) {
+ // Verifies the swappable emit path used by tests (and, after the v3
+ // migration, by ServiceStartup) reaches the frontend event surface.
+ a, l := newTestApp()
+ a.tm.emitEvent(eventState, "connecting")
+ select {
+ case s := <-l.states:
+ if s != "connecting" {
+ t.Fatalf("got state %q", s)
+ }
+ case <-time.After(time.Second):
+ t.Fatal("emit did not deliver state event")
+ }
+}
+
+func TestFolderTransfer(t *testing.T) {
+ srcDir := t.TempDir()
+ sub := filepath.Join(srcDir, "folder")
+ if err := os.Mkdir(sub, 0o755); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(sub, "a.txt"), []byte("aaa"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(sub, "b.txt"), []byte("bbb"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+
+ sender, senderLog := newTestApp()
+ receiver, receiverLog := newTestApp()
+ receiverLog.onAccept = func() { receiver.RespondAccept(true) }
+
+ code, err := sender.StartSend([]string{sub})
+ if err != nil {
+ t.Fatalf("StartSend folder: %v", err)
+ }
+ outDir := t.TempDir()
+ if err := receiver.StartReceive(code, outDir); err != nil {
+ t.Fatalf("StartReceive: %v", err)
+ }
+
+ p := waitDone(t, receiverLog, "folder receive")
+ waitDone(t, senderLog, "folder send")
+ if len(p.Files) != 2 {
+ t.Fatalf("expected 2 files, got %+v", p.Files)
+ }
+ for _, name := range []string{"a.txt", "b.txt"} {
+ found := false
+ for _, f := range p.Files {
+ if strings.HasSuffix(f.Name, name) || filepath.Base(f.Name) == name {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Errorf("missing %s in %+v", name, p.Files)
+ }
+ }
+}
+
+func TestGetFileDataURLTooLarge(t *testing.T) {
+ // Don't actually allocate 64 MiB+; override via a sparse-ish check using
+ // a temp file we report as large by writing past the cap if cheap, or
+ // skip when disk is constrained. Write just over maxPreviewBytes only
+ // when short — use a smaller direct size assertion via the constant.
+ if testing.Short() {
+ t.Skip("skipping large-file preview test in short mode")
+ }
+ dir := t.TempDir()
+ path := filepath.Join(dir, "big.bin")
+ // create a sparse file by seeking; falls back to a smaller write if needed
+ f, err := os.Create(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Truncate(maxPreviewBytes + 1); err != nil {
+ _ = f.Close()
+ t.Fatal(err)
+ }
+ _ = f.Close()
+
+ a := NewApp()
+ if _, err := a.GetFileDataURL(path); err == nil || !strings.Contains(err.Error(), "too large") {
+ t.Fatalf("expected too-large error, got %v", err)
+ }
+}
+
+func TestNormalizeCodeViaApp(t *testing.T) {
+ a := NewApp()
+ code, err := a.NormalizeCode("croc 4523-ivan-twist-order")
+ if err != nil {
+ t.Fatalf("NormalizeCode: %v", err)
+ }
+ if code != "4523-ivan-twist-order" {
+ t.Fatalf("got %q", code)
+ }
+ if _, err := a.NormalizeCode(" "); err == nil {
+ t.Fatal("expected error for empty input")
+ }
+}
+
+func TestSaveSettingsInvalidThrottle(t *testing.T) {
+ t.Setenv("CROC_CONFIG_DIR", t.TempDir())
+ a := NewApp()
+ s := a.GetSettings()
+ s.ThrottleUpload = "not-a-rate"
+ if err := a.SaveSettings(s); err == nil || !strings.Contains(err.Error(), "invalid upload limit") {
+ t.Fatalf("expected invalid throttle error, got %v", err)
+ }
+}
diff --git a/build/Taskfile.yml b/build/Taskfile.yml
new file mode 100644
index 0000000..d39d290
--- /dev/null
+++ b/build/Taskfile.yml
@@ -0,0 +1,398 @@
+version: '3'
+
+tasks:
+ go:mod:tidy:
+ summary: Runs `go mod tidy`
+ internal: true
+ # Universal/multi-arch builds invoke this concurrently from parallel deps;
+ # two `go mod tidy` processes racing on go.mod can corrupt it (#4637).
+ run: once
+ cmds:
+ - go mod tidy
+
+ install:frontend:deps:
+ summary: Install frontend dependencies
+ run: once
+ cmds:
+ - task: install:frontend:deps:{{.PACKAGE_MANAGER}}
+
+ install:frontend:deps:npm:
+ dir: frontend
+ sources:
+ - package.json
+ - package-lock.json
+ generates:
+ - node_modules
+ preconditions:
+ - sh: npm version
+ msg: "Looks like npm isn't installed. Npm is part of the Node installer: https://nodejs.org/en/download/"
+ cmds:
+ - npm install
+
+ install:frontend:deps:bun:
+ dir: frontend
+ sources:
+ - package.json
+ - bun.lock
+ - bun.lockb
+ generates:
+ - node_modules
+ preconditions:
+ - sh: bun --version
+ msg: "bun not found"
+ cmds:
+ - bun install
+
+ install:frontend:deps:pnpm:
+ dir: frontend
+ sources:
+ - package.json
+ - pnpm-lock.yaml
+ generates:
+ - node_modules
+ preconditions:
+ - sh: pnpm --version
+ msg: "pnpm not found"
+ cmds:
+ - pnpm install
+
+ install:frontend:deps:yarn:
+ dir: frontend
+ sources:
+ - package.json
+ - yarn.lock
+ status:
+ - test -d node_modules || test -f .pnp.cjs
+ preconditions:
+ - sh: yarn --version
+ msg: "yarn not found"
+ cmds:
+ - yarn install
+
+ build:frontend:
+ label: build:frontend (DEV={{.DEV}} RUNNER={{.PACKAGE_MANAGER}})
+ summary: Build the frontend project
+ # darwin:build:universal runs its per-arch builds as parallel deps, each of
+ # which depends on this task. Without run:once the two executions race:
+ # one regenerates frontend/bindings (-clean deletes it first) while the
+ # other's bundler is reading it, failing intermittently with
+ # 'Could not resolve "./bindings/"' (#4637).
+ run: once
+ dir: frontend
+ sources:
+ - "**/*"
+ - exclude: node_modules/**/*
+ generates:
+ - dist/**/*
+ deps:
+ - task: install:frontend:deps
+ - task: generate:bindings
+ vars:
+ BUILD_FLAGS:
+ ref: .BUILD_FLAGS
+ OBFUSCATED:
+ ref: .OBFUSCATED
+ cmds:
+ - task: frontend:run
+ vars:
+ SCRIPT: '{{if eq .DEV "true"}}build:dev{{else}}build{{end}}'
+ env:
+ PRODUCTION: '{{if eq .DEV "true"}}false{{else}}true{{end}}'
+
+ frontend:run:
+ summary: Run a frontend script with selected runner
+ cmds:
+ - task: frontend:run:{{.PACKAGE_MANAGER}}
+ vars:
+ SCRIPT: "{{.SCRIPT}}"
+ vars:
+ SCRIPT: "{{.SCRIPT}}"
+
+ frontend:run:npm:
+ dir: frontend
+ cmds:
+ - npm run {{.SCRIPT}} -q
+ vars:
+ SCRIPT: "{{.SCRIPT}}"
+
+ frontend:run:yarn:
+ dir: frontend
+ cmds:
+ - yarn {{.SCRIPT}}
+ vars:
+ SCRIPT: "{{.SCRIPT}}"
+
+ frontend:run:pnpm:
+ dir: frontend
+ cmds:
+ - pnpm run {{.SCRIPT}}
+ vars:
+ SCRIPT: "{{.SCRIPT}}"
+
+ frontend:run:bun:
+ dir: frontend
+ cmds:
+ - bun run {{.SCRIPT}}
+ vars:
+ SCRIPT: "{{.SCRIPT}}"
+
+ frontend:vendor:puppertino:
+ summary: Fetches Puppertino CSS into frontend/public for consistent mobile styling
+ sources:
+ - frontend/public/puppertino/puppertino.css
+ generates:
+ - frontend/public/puppertino/puppertino.css
+ cmds:
+ - |
+ set -euo pipefail
+ mkdir -p frontend/public/puppertino
+ # If bundled Puppertino exists, prefer it. Otherwise, try to fetch, but don't fail build on error.
+ if [ ! -f frontend/public/puppertino/puppertino.css ]; then
+ echo "No bundled Puppertino found. Attempting to fetch from GitHub..."
+ if curl -fsSL https://raw.githubusercontent.com/codedgar/Puppertino/main/dist/css/full.css -o frontend/public/puppertino/puppertino.css; then
+ curl -fsSL https://raw.githubusercontent.com/codedgar/Puppertino/main/LICENSE -o frontend/public/puppertino/LICENSE || true
+ echo "Puppertino CSS downloaded to frontend/public/puppertino/puppertino.css"
+ else
+ echo "Warning: Could not fetch Puppertino CSS. Proceeding without download since template may bundle it."
+ fi
+ else
+ echo "Using bundled Puppertino at frontend/public/puppertino/puppertino.css"
+ fi
+ # Ensure index.html includes Puppertino CSS and button classes
+ INDEX_HTML=frontend/index.html
+ if [ -f "$INDEX_HTML" ]; then
+ if ! grep -q 'href="/puppertino/puppertino.css"' "$INDEX_HTML"; then
+ # Insert Puppertino link tag after style.css link
+ awk '
+ /href="\/style.css"\/?/ && !x { print; print " "; x=1; next }1
+ ' "$INDEX_HTML" > "$INDEX_HTML.tmp" && mv "$INDEX_HTML.tmp" "$INDEX_HTML"
+ fi
+ # Replace default .btn with Puppertino primary button classes if present
+ sed -E -i'' 's/class=\"btn\"/class=\"p-btn p-prim-col\"/g' "$INDEX_HTML" || true
+ fi
+
+
+
+ generate:bindings:
+ summary: Generates bindings for the frontend
+ run: once
+ deps:
+ - task: go:mod:tidy
+ sources:
+ - "**/*.[jt]s"
+ - exclude: frontend/**/*
+ - frontend/bindings/**/* # Rerun when switching between dev/production mode causes changes in output
+ - "**/*.go"
+ - go.mod
+ - go.sum
+ generates:
+ - frontend/bindings/**/*
+ cmds:
+ - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true -time-type=Date{{if eq .OBFUSCATED "true"}} -obfuscated{{end}} -ts
+
+ generate:icons:
+ summary: Generates Windows `.ico` and Mac `.icns` from an image; on macOS, `-iconcomposerinput appicon.icon -macassetdir darwin` also produces `Assets.car` from a `.icon` file (skipped on other platforms).
+ run: once
+ dir: build
+ sources:
+ - "appicon.png"
+ - "appicon.icon"
+ generates:
+ - "darwin/icons.icns"
+ - "windows/icon.ico"
+ cmds:
+ - wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico -iconcomposerinput appicon.icon -macassetdir darwin
+
+ dev:frontend:
+ summary: Runs the frontend in development mode
+ deps:
+ - task: install:frontend:deps
+ cmds:
+ - task: frontend:dev:{{.PACKAGE_MANAGER}}
+
+ frontend:dev:npm:
+ dir: frontend
+ cmds:
+ - npm run dev -- --port {{.VITE_PORT}} --strictPort
+
+ frontend:dev:yarn:
+ dir: frontend
+ cmds:
+ - yarn dev --port {{.VITE_PORT}} --strictPort
+
+ frontend:dev:pnpm:
+ dir: frontend
+ cmds:
+ - pnpm dev --port {{.VITE_PORT}} --strictPort
+
+ frontend:dev:bun:
+ dir: frontend
+ cmds:
+ - bun run dev --port {{.VITE_PORT}} --strictPort
+
+ update:build-assets:
+ summary: Updates the build assets
+ dir: build
+ cmds:
+ - wails3 update build-assets -name "{{.APP_NAME}}" -binaryname "{{.APP_NAME}}" -config config.yml -dir .
+
+ build:server:
+ summary: Builds the application in server mode (no GUI, HTTP server only)
+ desc: |
+ Builds a production server binary by default: -tags server,production,
+ -trimpath and a stripped binary, mirroring the desktop `build` task.
+ Server mode runs as a pure HTTP server without native GUI dependencies.
+
+ Usage: task build:server [DEV=true] [OBFUSCATED=true] [EXTRA_TAGS=tag1,tag2]
+ DEV=true development server (-tags server, no strip, inlining kept)
+ OBFUSCATED=true obfuscated build via garble (requires garble installed)
+ EXTRA_TAGS additional comma-separated build tags
+ deps:
+ - task: build:frontend
+ vars:
+ DEV:
+ ref: .DEV
+ BUILD_FLAGS:
+ ref: .BUILD_FLAGS
+ OBFUSCATED:
+ ref: .OBFUSCATED
+ preconditions:
+ - sh: '{{if eq .OBFUSCATED "true"}}command -v garble >/dev/null 2>&1{{else}}true{{end}}'
+ msg: "garble is required for obfuscated builds. Install it with: go install mvdan.cc/garble@v0.16.0 (requires Go 1.24+). See https://github.com/burrowers/garble/releases for version/toolchain compatibility."
+ cmds:
+ - '{{if eq .OBFUSCATED "true"}}garble {{.GARBLE_ARGS}} build{{else}}go build{{end}} {{.BUILD_FLAGS}} -o "{{.BIN_DIR}}/{{.APP_NAME}}-server{{exeExt}}"'
+ vars:
+ BUILD_FLAGS: '-tags server{{if eq .DEV "true"}}{{if eq .OBFUSCATED "true"}},wails_obfuscated{{end}}{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -buildvcs=false -gcflags=all="-l"{{else}},production{{if eq .OBFUSCATED "true"}},wails_obfuscated{{end}}{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -trimpath -buildvcs=false -ldflags="-w -s"{{end}}'
+
+ run:server:
+ summary: Builds and runs a development server (DEV=true)
+ deps:
+ - task: build:server
+ vars:
+ DEV: "true"
+ cmds:
+ - '"./{{.BIN_DIR}}/{{.APP_NAME}}-server{{exeExt}}"'
+
+ build:docker:
+ summary: Builds a Docker image for server mode deployment
+ desc: |
+ Creates a minimal Docker image containing the production server binary.
+ Defaults to a pure-Go static binary on a distroless/static base. The
+ production frontend is built first so the embedded assets are current.
+
+ Usage: task build:docker [TAG=myapp:latest] [CGO_ENABLED=1] [GO_IMAGE=...] [RUNTIME_IMAGE=...]
+ For CGO apps, set CGO_ENABLED=1 with libc-compatible builder/runtime images, e.g.:
+ task build:docker CGO_ENABLED=1 GO_IMAGE=golang:bookworm RUNTIME_IMAGE=gcr.io/distroless/base-debian12
+ deps:
+ # Build the production frontend so frontend/dist (embedded by the Go build
+ # inside the image) is present and current in the Docker build context.
+ # Pass the server,production tags so binding generation analyses the same
+ # build the Docker image compiles, not the default-tag build.
+ - task: build:frontend
+ vars:
+ BUILD_FLAGS: "-tags server,production"
+ cmds:
+ - >-
+ docker build
+ --build-arg CGO_ENABLED={{.CGO_ENABLED | default "0"}}
+ --build-arg GO_IMAGE={{.GO_IMAGE | default "golang:alpine"}}
+ --build-arg RUNTIME_IMAGE={{.RUNTIME_IMAGE | default "gcr.io/distroless/static-debian12"}}
+ -t {{.TAG | default (printf "%s:latest" .APP_NAME)}}
+ -f build/docker/Dockerfile.server .
+ vars:
+ TAG: "{{.TAG}}"
+ preconditions:
+ - sh: docker info > /dev/null 2>&1
+ msg: "Docker is required. Please install Docker first."
+ - sh: test -f build/docker/Dockerfile.server
+ msg: "Dockerfile.server not found. Run 'wails3 update build-assets' to generate it."
+
+ run:docker:
+ summary: Builds and runs the Docker image
+ desc: |
+ Builds the Docker image and runs it, exposing port 8080.
+ Usage: task run:docker [TAG=myapp:latest] [PORT=8080]
+ Note: The internal container port is always 8080. The PORT variable
+ only changes the host port mapping. Ensure your app uses port 8080
+ or modify the Dockerfile to match your ServerOptions.Port setting.
+ deps:
+ - task: build:docker
+ vars:
+ TAG:
+ ref: .TAG
+ cmds:
+ - docker run --rm -p {{.PORT | default "8080"}}:8080 {{.TAG | default (printf "%s:latest" .APP_NAME)}}
+ vars:
+ TAG: "{{.TAG}}"
+ PORT: "{{.PORT}}"
+
+ setup:docker:
+ summary: Builds Docker image for cross-compilation (~800MB download)
+ desc: |
+ Builds the Docker image needed for cross-compiling to any platform.
+ Run this once to enable cross-platform builds from any OS.
+ cmds:
+ - docker build -t wails-cross -f build/docker/Dockerfile.cross build/docker/
+ preconditions:
+ - sh: docker info > /dev/null 2>&1
+ msg: "Docker is required. Please install Docker first."
+
+ ios:device:list:
+ summary: Lists connected iOS devices (UDIDs)
+ cmds:
+ - xcrun xcdevice list
+
+ ios:run:device:
+ summary: Build, install, and launch on a physical iPhone using Apple tools (xcodebuild/devicectl)
+ vars:
+ PROJECT: '{{.PROJECT}}' # e.g., build/ios/xcode/.xcodeproj
+ SCHEME: '{{.SCHEME}}' # e.g., ios.dev
+ CONFIG: '{{.CONFIG | default "Debug"}}'
+ DERIVED: '{{.DERIVED | default "build/ios/DerivedData"}}'
+ UDID: '{{.UDID}}' # from `task ios:device:list`
+ BUNDLE_ID: '{{.BUNDLE_ID}}' # e.g., com.yourco.wails.ios.dev
+ TEAM_ID: '{{.TEAM_ID}}' # optional, if your project is not already set up for signing
+ preconditions:
+ - sh: xcrun -f xcodebuild
+ msg: "xcodebuild not found. Please install Xcode."
+ - sh: xcrun -f devicectl
+ msg: "devicectl not found. Please update to Xcode 15+ (which includes devicectl)."
+ - sh: test -n '{{.PROJECT}}'
+ msg: "Set PROJECT to your .xcodeproj path (e.g., PROJECT=build/ios/xcode/App.xcodeproj)."
+ - sh: test -n '{{.SCHEME}}'
+ msg: "Set SCHEME to your app scheme (e.g., SCHEME=ios.dev)."
+ - sh: test -n '{{.UDID}}'
+ msg: "Set UDID to your device UDID (see: task ios:device:list)."
+ - sh: test -n '{{.BUNDLE_ID}}'
+ msg: "Set BUNDLE_ID to your app's bundle identifier (e.g., com.yourco.wails.ios.dev)."
+ cmds:
+ - |
+ set -euo pipefail
+ echo "Building for device: UDID={{.UDID}} SCHEME={{.SCHEME}} PROJECT={{.PROJECT}}"
+ XCB_ARGS=(
+ -project "{{.PROJECT}}"
+ -scheme "{{.SCHEME}}"
+ -configuration "{{.CONFIG}}"
+ -destination "id={{.UDID}}"
+ -derivedDataPath "{{.DERIVED}}"
+ -allowProvisioningUpdates
+ -allowProvisioningDeviceRegistration
+ )
+ # Optionally inject signing identifiers if provided
+ if [ -n '{{.TEAM_ID}}' ]; then XCB_ARGS+=(DEVELOPMENT_TEAM={{.TEAM_ID}}); fi
+ if [ -n '{{.BUNDLE_ID}}' ]; then XCB_ARGS+=(PRODUCT_BUNDLE_IDENTIFIER={{.BUNDLE_ID}}); fi
+ xcodebuild "${XCB_ARGS[@]}" build | xcpretty || true
+ # If xcpretty isn't installed, run without it
+ if [ "${PIPESTATUS[0]}" -ne 0 ]; then
+ xcodebuild "${XCB_ARGS[@]}" build
+ fi
+ # Find built .app
+ APP_PATH=$(find "{{.DERIVED}}/Build/Products" -type d -name "*.app" -maxdepth 3 | head -n 1)
+ if [ -z "$APP_PATH" ]; then
+ echo "Could not locate built .app under {{.DERIVED}}/Build/Products" >&2
+ exit 1
+ fi
+ echo "Installing: $APP_PATH"
+ xcrun devicectl device install app --device "{{.UDID}}" "$APP_PATH"
+ echo "Launching: {{.BUNDLE_ID}}"
+ xcrun devicectl device process launch --device "{{.UDID}}" --stderr console --stdout console "{{.BUNDLE_ID}}"
diff --git a/build/config.yml b/build/config.yml
new file mode 100644
index 0000000..c111314
--- /dev/null
+++ b/build/config.yml
@@ -0,0 +1,47 @@
+# Wails v3 project configuration for croc-desktop.
+# When you update `info` or `fileAssociations`, run
+# `wails3 task common:update:build-assets` to update the assets.
+version: '3'
+
+info:
+ companyName: "croc"
+ productName: "croc-desktop"
+ productIdentifier: "com.schollz.croc-desktop"
+ description: "Desktop GUI for croc — encrypted peer-to-peer file transfer"
+ copyright: "© 2026 croc"
+ comments: "croc-desktop"
+ version: "0.2.0"
+
+dev_mode:
+ root_path: .
+ log_level: warn
+ debounce: 1000
+ ignore:
+ dir:
+ - .git
+ - node_modules
+ - frontend
+ - bin
+ - e2e
+ - docs
+ file:
+ - .DS_Store
+ - .gitignore
+ - .gitkeep
+ - "*_test.go"
+ watched_extension:
+ - "*.go"
+ - "*.js"
+ - "*.ts"
+ git_ignore: true
+ executes:
+ - cmd: wails3 build -tags gtk3 DEV=true
+ type: blocking
+ - cmd: wails3 task common:dev:frontend
+ type: background
+ - cmd: wails3 task run EXTRA_TAGS=gtk3
+ type: primary
+
+fileAssociations: []
+
+other: []
diff --git a/build/darwin/Assets.car b/build/darwin/Assets.car
new file mode 100644
index 0000000000000000000000000000000000000000..32e5ad91eba4596cfa231db1f7b25101a84295f1
GIT binary patch
literal 1631800
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