p2p-counter v1.2.5
Capacitor P2P Counter Plugin
A Capacitor plugin that enables mesh network communication between multiple mobile devices using WebRTC with NFC handshake for initial device discovery. Supports real-time counter synchronization and duplicate entry detection across all connected devices.
Installation
npm install p2p-counter
npx cap sync
API
NFC Methods
startNFCDiscovery()
: Start NFC discovery modestopNFCDiscovery()
: Stop NFC discovery modesendNFCMessage({ message: string })
: Send NFC message for initial handshake
WebRTC Methods
initializeWebRTC()
: Initialize WebRTC connectioncreatePeerConnection({ deviceId: string, isInitiator: boolean })
: Create P2P connection with another devicesendCounter({ code: string, isPresent: boolean })
: Broadcast counter data and attendance status to all connected peersdisconnectPeer({ deviceId: string })
: Disconnect from a specific peerstartKeepalive()
: Start sending keepalive signals to maintain mesh stabilitystopKeepalive()
: Stop sending keepalive signals
Events
nfcDiscovered
: Fired when NFC tag is discoveredcounterReceived
: Fired when counter data is received from any peerpeerConnected
: Fired when peer connection is establishedpeerDisconnected
: Fired when peer connection is lostpeerTimeout
: Fired when a peer hasn't responded to keepalive signalsduplicateDetected
: Fired when a duplicate entry is detected
Network Health Monitoring
The plugin provides network health statistics through the getNetworkStats()
method:
const stats = await P2PCounter.getNetworkStats();
console.log(stats.averageLatency); // Average latency in ms
console.log(stats.packetLoss); // Packet loss rate (0-1)
console.log(stats.keepaliveInterval); // Current keepalive interval in ms
Recommended thresholds:
- Good: < 500ms latency, < 5% packet loss
- Fair: < 1000ms latency, < 10% packet loss
- Poor: > 1000ms latency or > 10% packet loss
Connection Methods
The plugin supports multiple methods for establishing the initial WebRTC connection:
1. NFC Connection (Default)
// Start NFC discovery
await P2PCounter.startNFCDiscovery();
// Listen for NFC discovery
P2PCounter.addListener('nfcDiscovered', async (data) => {
await P2PCounter.initializeWebRTC();
await P2PCounter.createPeerConnection({
deviceId: data.deviceId,
isInitiator: true
});
});
2. Share API Connection
// Share connection info using native share sheet
await P2PCounter.shareConnectionInfo();
// Receive shared connection info
P2PCounter.addListener('connectionReceived', async (data) => {
await P2PCounter.receiveConnectionInfo({ sharedData: data.url });
});
3. QR Code Connection
// Generate QR code
const { qrData } = await P2PCounter.generateConnectionQR();
// Display qrData in your UI (base64 image)
// Scan QR code
await P2PCounter.scanConnectionQR();
Example Implementation
const initiateConnection = async () => {
try {
// Try Share API first on mobile
if (platform === 'ios' || platform === 'android') {
await P2PCounter.shareConnectionInfo();
} else {
// Fallback to QR code
const { qrData } = await P2PCounter.generateConnectionQR();
setQRCode(qrData); // Display in UI
}
} catch (err) {
console.error('Connection initiation failed:', err);
}
};
Each method will automatically establish the WebRTC connection once the initial handshake is complete.
Usage Example
import { P2PCounter } from 'capacitor-p2p-counter';
// Start NFC discovery
await P2PCounter.startNFCDiscovery();
// Listen for NFC discovery
P2PCounter.addListener('nfcDiscovered', async (data) => {
// Initialize WebRTC when NFC is discovered
await P2PCounter.initializeWebRTC();
await P2PCounter.createPeerConnection({
deviceId: data.deviceId,
isInitiator: true
});
});
// Listen for counter updates
P2PCounter.addListener('counterReceived', (data) => {
console.log('Received code:', data.code, 'Present:', data.isPresent, 'at:', data.timestamp);
});
// Start keepalive system
await P2PCounter.startKeepalive();
// Listen for peer timeouts
P2PCounter.addListener('peerTimeout', (data) => {
console.log('Peer timed out:', data.deviceId);
});
// Listen for duplicates
P2PCounter.addListener('duplicateDetected', (data) => {
console.log('Duplicate code detected:', data.code);
});
// Monitor network health
setInterval(async () => {
const stats = await P2PCounter.getNetworkStats();
console.log('Network Health:', stats);
}, 5000);
// Send counter update
await P2PCounter.sendCounter({ code: 'QR123', isPresent: true });
// Update when attendee leaves
await P2PCounter.sendCounter({ code: 'QR123', isPresent: false });
// Disconnect from a peer
await P2PCounter.disconnectPeer({ deviceId: 'device123' });
Requirements
- iOS 13+
- Android API level 24+
- Capacitor 5+
Network Analysis and Scaling
Keepalive System Analysis
The plugin uses a 5-second ping/pong keepalive system. Here's the network traffic analysis:
Message Sizes:
- Ping/Pong: ~65 bytes (including WebRTC overhead)
- Counter Message: ~140 bytes
Traffic Per Device:
Bandwidth per device = 52 × (n-1) bytes/second
Where n is the number of connected devices
Practical Limits:
- Optimal performance: 50-75 devices
- Theoretical maximum: ~245 devices (using 10% of 1Mbps connection)
Limiting Factors:
- Network latency
- Message processing overhead
- Connection management
- Counter messages priority
Adaptive Keepalive System: The plugin implements an intelligent keepalive system that automatically adjusts based on network conditions:
- Base interval: 5 seconds
- Dynamic range: 5-30 seconds
- Adjustment factors:
- Network latency
- Packet loss rate
- Number of connected peers
The system:
- Monitors RTT (Round Trip Time) for each peer
- Tracks packet loss patterns
- Adjusts intervals per-peer when needed
- Prevents cascade failures
Scaling Recommendations:
- Increase keepalive interval to 10-15 seconds for larger networks
- Implement hierarchical mesh with subnet coordinators
- Use binary protocol instead of JSON for better efficiency
Notes
- NFC capabilities must be enabled in your app's capabilities (iOS) and manifest (Android)
- WebRTC connections require proper STUN/TURN server configuration for NAT traversal
Advanced Features Documentation
Mesh Network Management
MeshDiscoveryManager
Handles peer discovery and network topology management:
startDiscovery()
: Initiates peer discovery processstopDiscovery()
: Stops peer discoveryhandleAnnouncement(deviceId: string, data: JSONObject)
: Processes peer announcementsgetDiscoverySnapshot()
: Returns current network topology statecleanupStaleEntries()
: Removes inactive peers
Configuration:
const discoveryConfig = {
announcementInterval: 10000, // 10 seconds
peerTimeout: 30000, // 30 seconds
maxPeers: 10 // Maximum direct connections
}
MeshTopologyManager
Manages mesh network topology and message routing:
addPeer(deviceId: string, connectedPeers: string[])
: Adds new peer to meshremovePeer(deviceId: string)
: Removes peer from meshshouldRelayMessage(sourceId: string, targetId: string)
: Determines if local node should relay messagegetOptimalRoute(targetId: string)
: Calculates optimal message pathreorganizeMesh()
: Optimizes mesh connections
Configuration:
const topologyConfig = {
maxHops: 5, // Maximum message relay hops
minPeersPerNode: 2, // Minimum direct connections
maxPeersPerNode: 5, // Maximum direct connections
reorganizationCooldown: 10000 // 10 seconds between reorganizations
}
Message Management
MessagePriorityManager
Handles message prioritization and delivery guarantees:
- Priority Levels:
CRITICAL
: Immediate delivery, max retriesHIGH
: Prioritized delivery, multiple retriesMEDIUM
: Standard delivery, limited retriesLOW
: Best-effort delivery, no retries
await P2PCounter.sendCounter({
code: 'QR123',
isPresent: true,
priority: 'HIGH'
});
MessageProcessor
Handles message fragmentation and reassembly:
- Automatic message chunking (16KB chunks)
- Compression for messages > 1KB
- Guaranteed order delivery
- Message assembly and validation
MessageDeduplicator
Prevents duplicate message processing:
- Message fingerprinting
- Time-based deduplication window
- Cross-device synchronization
Network Analysis Tools
Enhanced statistics available through getNetworkStats()
:
interface DetailedNetworkStats {
averageLatency: number; // ms
packetLoss: number; // 0-1
keepaliveInterval: number; // ms
messageCount: number; // Total messages processed
networkStrength: number; // 0-1
peerStats: {
deviceId: string;
latency: number;
packetLoss: number;
connectionQuality: number;
}[];
topologyHealth: {
redundancy: number; // Network path redundancy
avgHopCount: number; // Average hops between nodes
fragmentationRisk: number; // Risk of network splitting
};
}
Message Flow Visualization
The plugin provides a visualization system for debugging and monitoring:
P2PCounter.addListener('messageStatus', (event: MessageStatusEvent) => {
console.log('Message:', event.messageId);
console.log('Status:', event.status);
console.log('Path:', event.path);
console.log('Attempts:', event.attempts);
console.log('Latency:', event.latency);
});
Advanced Usage Examples
Implementing Custom Message Priority
// Configure message priority
const message = {
type: 'counter',
code: 'QR123',
priority: 'HIGH',
retryPolicy: {
maxAttempts: 3,
backoffMs: 1000,
timeout: 5000
}
};
// Send with priority
await P2PCounter.sendPrioritizedMessage(message);
Mesh Network Optimization
// Configure mesh optimization
await P2PCounter.configureMesh({
optimizationInterval: 30000, // 30 seconds
targetRedundancy: 2, // Minimum path redundancy
loadBalancing: true, // Enable load balancing
adaptiveRouting: true // Enable adaptive routing
});
// Monitor mesh health
P2PCounter.addListener('meshHealth', (stats) => {
console.log('Redundancy:', stats.redundancy);
console.log('Average Hop Count:', stats.avgHopCount);
console.log('Network Stability:', stats.stability);
});
Performance Considerations
Message Priority System:
- Critical messages: < 100ms delivery target
- High priority: < 500ms delivery target
- Standard messages: < 2000ms delivery target
Resource Usage:
- Memory: ~50MB per 100 connected peers
- CPU: 2-5% average utilization
- Battery: ~2% per hour with 10 peers
Scaling Characteristics:
- Linear bandwidth growth per peer
- Quadratic message processing overhead
- Optimized for 50-75 device mesh networks