Skip to content

Conversation

@wizzomafizzo
Copy link
Member

Summary

Major improvements to reader management with stable, persistent reader IDs and better lifecycle handling.

Key Changes

Stable Reader IDs

  • Add cross-platform USB topology path resolution (Linux, macOS, Windows)
  • Reader IDs are now based on physical USB port location, not device path
  • IDs persist across reboots and device name changes (e.g., /dev/ttyUSB0/dev/ttyUSB1)
  • New pkg/readers/identity.go with GenerateReaderID() function

Reader Capabilities System

  • New pkg/readers/capabilities.go defining reader capabilities
  • Capabilities: CapabilityRemovable, CapabilityWrite, etc.
  • Each reader driver declares its capabilities

Disconnection Detection Fix

  • Fix PN532 and LibNFC readers not being removed when unplugged
  • Add connected bool to PN532 that tracks session lifecycle
  • Update LibNFC Connected() to check polling flag
  • Upgrade go-pn532 v0.14.0 → v0.15.0 (fixes polling loop exit on I/O errors)

API Changes

  • ReaderInfo response adds readerId (stable) and driver fields
  • TokenResponse adds readerId field
  • readers.write and readers.write.cancel accept optional readerId param to target specific reader

Files Changed

  • pkg/helpers/usb_{linux,darwin,windows}.go - USB topology resolution
  • pkg/readers/identity.go - Reader ID generation
  • pkg/readers/capabilities.go - Capabilities system
  • pkg/readers/*.go - All drivers updated with ReaderID() method
  • pkg/api/models/*.go - New fields in params and responses
  • pkg/api/methods/readers.go - Refactored to use new reader selection
  • pkg/service/readers.go - Reader management updates

Add GetUSBTopologyPath helper that resolves device paths to their
physical USB port topology (e.g., "1-2.3"). This provides stable
device identification that survives reboots, useful for persistent
reader identification.

Platform implementations:
- Linux: Uses sysfs to resolve device major/minor to USB topology
- Windows: Uses SetupAPI to extract USBROOT/USB port segments
- Darwin: Uses IOKit to traverse USB device hierarchy
Reduce hash portion from 26 to 8 base32 characters for improved
readability while maintaining sufficient uniqueness for local device
identification. 40 bits provides ~1 trillion combinations, far
exceeding practical collision risk for per-system reader counts.

Example: pn532-jbsxmwkziaxvk3dfjbsxmwkz → pn532-ujqixjv6
When readers were unplugged, they remained in the readers list indefinitely
because Connected() continued to return true even after the underlying
connection failed.

PN532:
- Add `connected` bool field that tracks session lifecycle
- Set to true before session starts, false when session exits (via defer)
- Update Connected() to check this field instead of context state

LibNFC:
- Update Connected() to check `polling` flag (already set false on I/O errors)
- Matches pattern used by other serial-based readers

Also upgrades go-pn532 v0.14.0 → v0.15.0 which fixes polling loops to exit
on fatal I/O errors instead of retrying forever.
@sentry
Copy link

sentry bot commented Jan 3, 2026

Achieves 100% test coverage on all functions in autodetect.go including:
- Connected/failed map operations with driver ID normalization
- Detection flow with various driver enable/auto-detect states
- Connection success, open errors, and connection failures
- Close error handling in multiple contexts
- Logging with state changes and heartbeats
- Concurrent access safety
- Exclude list handling for connected reader paths
@wizzomafizzo wizzomafizzo merged commit 4a6fc4a into main Jan 3, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants