Implemented a queue-based architecture to eliminate the race condition in keycard communication.
Status: ✅ Core infrastructure complete (Phase 2)
keycard-qt-status/
├── include/keycard-qt/
│ ├── card_command.h ← Command Pattern interface
│ └── communication_manager.h ← Queue dispatcher
├── src/
│ ├── card_command.cpp ← Command implementations
│ └── communication_manager.cpp ← Manager implementation
└── Documentation:
├── QUEUE_ARCHITECTURE_README.md ← Start here!
├── ARCHITECTURE_CHANGES.md ← Deep dive
├── INTEGRATION_GUIDE.md ← How to integrate
├── IMPLEMENTATION_STATUS.md ← Status tracking
└── QUICK_START.md ← This file
#include "keycard-qt/communication_manager.h"
// Create
auto manager = new Keycard::CommunicationManager(this);
// Connect signals
connect(manager, &Keycard::CommunicationManager::cardInitialized,
this, &MyClass::onCardInit);
// Start
manager->start(channel, pairingStorage, passwordProvider);// Create command
auto cmd = std::make_unique<Keycard::VerifyPINCommand>("123456");
// Enqueue
QUuid token = manager->enqueueCommand(std::move(cmd));
// Wait for result signal
connect(manager, &Keycard::CommunicationManager::commandCompleted,
[](QUuid token, Keycard::CommandResult result) {
if (result.success) {
qDebug() << "Success:" << result.data;
} else {
qDebug() << "Error:" << result.error;
}
});// Create and execute
auto cmd = std::make_unique<Keycard::GetStatusCommand>();
Keycard::CommandResult result = manager->executeCommandSync(std::move(cmd));
if (result.success) {
QVariantMap status = result.data.toMap();
int pinRetries = status["pinRetryCount"].toInt();
}Card Detected → SessionManager & CommandSet both try to initialize
↓
RACE CONDITION!
↓
Random failures
Card Detected
↓
CommunicationManager
↓
[Initialize Atomically]
↓
[Queue Commands]
↓
[Execute Serially]
↓
No races, predictable!
- Want overview? → Read
QUEUE_ARCHITECTURE_README.md - Want details? → Read
ARCHITECTURE_CHANGES.md - Want to integrate? → Read
INTEGRATION_GUIDE.md - Want status? → Read
IMPLEMENTATION_STATUS.md
- CardCommand interface (Command Pattern)
- CommunicationManager (queue dispatcher)
- Communication thread (dedicated for card I/O)
- Atomic initialization sequence
- Both async and sync APIs
- Build system updated
- Comprehensive documentation
Phase 2: ✅ COMPLETE
- Modify SessionManager to use CommunicationManager
- Add feature flag to switch architectures
- Keep backward compatibility
- Unit tests
- Integration tests
- Stress tests
- Canary testing
- Gradual rollout
- Monitoring
cd keycard-qt-status
mkdir build && cd build
cmake ..
makeShould compile without errors!
- Encapsulates one operation
- Implements
execute(CommandSet*) - Returns CommandResult
- Manages command queue
- Runs dedicated communication thread
- Handles card initialization
- Provides async & sync APIs
Idle → Initializing → Ready → Processing → Ready
↑ ↓
└──────────────────────────────────────────┘
- ❌ Race conditions
- ❌ Unpredictable failures
- ❌ Corrupted state
- ✅ No races (atomic init)
- ✅ Predictable (serial execution)
- ✅ Clean state management
See usage examples in:
ARCHITECTURE_CHANGES.md- Multiple examplesINTEGRATION_GUIDE.md- SessionManager integration- Source code comments - Inline examples
- Declare in
card_command.h:
class MyCommand : public CardCommand {
public:
MyCommand(params...);
CommandResult execute(CommandSet*) override;
QString name() const override { return "MY_COMMAND"; }
};- Implement in
card_command.cpp:
CommandResult MyCommand::execute(CommandSet* cmdSet) {
// Your logic here
bool ok = cmdSet->someOperation();
return ok ? CommandResult::fromSuccess(data)
: CommandResult::fromError(error);
}- Use it:
auto cmd = std::make_unique<MyCommand>(args);
manager->enqueueCommand(std::move(cmd));- Check CMakeLists.txt includes new files
- Verify Qt6 Core is available
- Check include paths
- Enable logging:
QLoggingCategory::setFilterRules("keycard.*=true") - Check state transitions in logs
- Verify card detection events
- See
INTEGRATION_GUIDE.mdfor step-by-step - Use feature flag for gradual rollout
- Keep old code path for fallback
- Check documentation (4 comprehensive files)
- Review source code comments
- Compare with Go implementation
- Ask the team!
What: Queue-based architecture for keycard communication
Why: Eliminate race condition between SessionManager and CommandSet
How: Single communication thread + command queue + atomic init
Status: Core infrastructure complete, ready for integration
Next: Integrate with SessionManager and test thoroughly
Result: No more races, predictable behavior, maintainable code!
Last Updated: December 16, 2024
Phase: 2 Complete, 3 Pending
Status: ✅ Ready for Integration