- Discovery — Devices broadcast their presence via UDP beacons on the local network (port 9129). Each device periodically sends a JSON heartbeat containing its ID, name, type, and transfer port. Other devices listen and maintain a live device table with a 10-second TTL.
- Pairing — Scan a QR code or enter a 6-digit code to connect devices across subnets, or when auto-discovery doesn't reach them.
- Transfer — The sender streams files over plain HTTP/TCP by default. The optional QUIC setting probes HTTP/3 first and falls back to TCP before the transfer is prepared. Each file includes a SHA-256 checksum; the receiver hashes the incoming stream, rejects mismatches, and only then moves the partial file into place.
- Accept/Reject — The receiver sees an incoming file prompt and can accept or decline. Auto-accept can be enabled in settings.
- Progress — Real-time progress, speed, and ETA are shown for every transfer. Pause, resume, and cancel are supported.
Failed or interrupted receives are written to a Light-owned partial filename and removed automatically. Stale partial artifacts older than 24 hours are also pruned. On Android, temporary files created by the document picker are removed after sending and stale picker cache is cleaned at app startup.
- Zero Config — Auto-discovery on LAN, no manual setup required
- Cross-Platform — Wails-based desktop and mobile targets, with Windows and Android builds in the current release workflow
- QR Pairing — Scan a QR code or enter a 6-digit code to connect devices
- Real-time Progress — Live speed, ETA, and per-file progress tracking
- Pause / Resume / Cancel — Full transfer control at any time
- Accept / Reject — Incoming files require consent (or auto-accept)
- Bidirectional Sharing — Each peer can send back to a remembered sender
- Parallel Transfers — Up to four selected files can upload concurrently
- Transfer History — Completed and failed transfers are logged
- Safe file handling — Collision-safe destination names plus automatic cleanup of failed and stale partial files
- Dark Theme — Industrial-utilitarian design with amber accents
See docs/FEATURES.md for the complete current feature inventory and known limitations.
TCP remains the stable default. The quic transport setting probes HTTP/3
over UDP on the transfer port and falls back to TCP before /api/prepare or
any file body is sent when the peer does not support QUIC or UDP is unavailable.
QUIC mode is opt-in and should be enabled on each peer that should accept HTTP/3. It uses an ephemeral self-signed certificate: traffic is encrypted, but peer identity is not authenticated yet. TCP remains the recommended default.
Direct Wi-Fi/Android Wi-Fi Direct and Windows Wi-Fi Direct adapters are not part of the current transport mode. The app can still use a manually created hotspot or Wi-Fi Direct network when the devices receive reachable LAN addresses; native connection management is a separate platform integration.
To compare the local transport paths:
go test ./internal/light -run '^$' -bench '^BenchmarkTransferTransport$' -benchtime=1s| Layer | Technology |
|---|---|
| Backend | Go 1.25 + Wails v3 |
| Frontend | Vue 3 + TypeScript + Vite 8 + Tailwind CSS 3 |
| Discovery | UDP broadcast beacons (port 9129) |
| Transfer | Plain HTTP/TCP (port 9120, configurable) with optional HTTP/3 over QUIC |
| History | JSON file (~/.light/history.json) |
| QR | skip2/go-qrcode + jsQR (browser) |
main.go Wails composition, embedded assets
internal/light/ Go backend package
models.go Domain types (Device, Transfer, Settings, etc.)
settings.go SettingsService — config persistence + device ID
discovery.go DiscoveryService — UDP beacon broadcast + Diagnostics
filetransfer.go FileTransferService — HTTP server + sender upload
quic.go Experimental HTTP/3 server/client + TCP fallback
transport_bench_test.go Local TCP-versus-QUIC integration test and benchmark
transfermanager.go TransferManager — progress tracking + JSON history
qr.go QRCodeService — QR generation + pairing codes
broadcast_windows.go SO_BROADCAST (Windows, syscall)
broadcast_unix.go SO_BROADCAST (Linux/macOS/Android, syscall)
frontend/ Vue 3 application + generated Wails bindings
src/
composables/ Reactive stores (useDiscovery, useTransfers, useSettings, useUI)
components/ UI components (devices, transfer, pair, common, layout)
views/ Page views (Send, Receive, History, Settings)
styles/ Tailwind CSS + design tokens
lib/ Helpers (event listener, byte formatting)
build/ Wails platform/build configuration
| Platform | Link |
|---|---|
| Windows | Installer |
| Android | APK |
- Go 1.25+
- Node.js 22+
- Wails3 CLI (
go install github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0-beta.2)
# Clone the repository
git clone https://github.com/Aswanidev-vs/light.git
cd light
# Install dependencies
cd frontend && npm install && cd ..
# Start development server
wails3 dev# Build for current platform
wails3 build
# Build Windows
GOOS=windows wails3 build
# Build Android APK
wails3 task android:packageSettings are stored in ~/.light/settings.json:
{
"deviceName": "My Device",
"port": 9120,
"downloadDir": "~/Downloads/Light",
"autoAccept": false,
"theme": "dark",
"transportMode": "tcp"
}| Field | Default | Description |
|---|---|---|
deviceName |
hostname | Name shown to other devices |
port |
9120 | TCP port for the file transfer HTTP server |
downloadDir |
~/Downloads/Light |
Where received files are saved |
autoAccept |
false | Accept incoming files without prompting |
theme |
dark | UI theme (dark only for now) |
transportMode |
tcp | tcp for the stable path, or quic to try HTTP/3 first and fall back to TCP |
┌─────────────────────────────────────────────────┐
│ Frontend (Vue 3) │
│ SendView · ReceiveView · HistoryView · Settings │
│ ↕ Events.On / wails.Call │
├─────────────────────────────────────────────────┤
│ Wails v3 bindings │
│ ↕ app.Event.Emit / exported methods │
├─────────────────────────────────────────────────┤
│ Go Backend │
│ DiscoveryService ── UDP broadcast (9129) │
│ FileTransferService ── HTTP server (9120) │
│ TransferManager ── progress + JSON history │
│ QRCodeService ── QR generation + pairing codes │
│ SettingsService ── config persistence │
└─────────────────────────────────────────────────┘
↕ UDP beacons ↕ HTTP transfer
┌──────────────┐ ┌──────────────┐
│ Peer Device │ ◄─────► │ Peer Device │
└──────────────┘ └──────────────┘
The old mDNS-based discovery was replaced with a simpler, more reliable UDP beacon broadcast protocol:
- Port: 9129 (fixed UDP)
- Beacon payload:
{ id, name, type, port, pairingCode, ts } - Send: Per-interface directed broadcast +
255.255.255.255+ loopback (all unconditionally, not fallback-on-error) - Receive: Wildcard UDP socket on
0.0.0.0:9129 - Device ID: Persisted
crypto/randUUID in~/.light/deviceid(never derived from a cert, never a constant) - Diagnostics:
Diagnostics()RPC + loopback self-test separates "socket broken" vs "packets not crossing network" vs "peer not answering"
This project is licensed under the MIT License - see the LICENSE file for details.
Made with care for fast, private file sharing
