peerpigeon
Version:
WebRTC-based peer-to-peer mesh networking library with intelligent routing and signaling server
305 lines (238 loc) • 7.6 kB
Markdown
Successfully implemented native binary message support in PeerPigeon, eliminating the need for JSON serialization of binary data (Uint8Array, ArrayBuffer, etc.).
## Problem Solved
**Before**: PeerPigeon used `JSON.stringify()` to serialize all messages, which:
- Corrupted binary data (converted to objects like `{"0": 1, "1": 2, ...}`)
- Added significant overhead (33%+ size increase with base64)
- Reduced performance
- Required manual encoding/decoding
**After**: Binary data is sent directly over WebRTC data channels:
- Preserves binary data integrity
- No serialization overhead
- Direct ArrayBuffer transfer
- Efficient and fast
## Changes Made
### 1. Core WebRTC Layer (`PeerConnection.js`)
#### Constructor
Added binary message state tracking:
```javascript
this._expectingBinaryMessage = false;
this._binaryMessageSize = 0;
```
Enhanced to detect and handle binary data:
```javascript
sendMessage(message) {
if (message instanceof ArrayBuffer || ArrayBuffer.isView(message)) {
// Send binary header
dataChannel.send(JSON.stringify({ type: '__BINARY__', size }));
// Send binary payload
dataChannel.send(buffer);
} else {
// Regular JSON message
dataChannel.send(JSON.stringify(message));
}
}
```
Enhanced to receive and parse binary messages:
```javascript
dataChannel.onmessage = (event) => {
if (event.data instanceof ArrayBuffer) {
// Handle binary payload
const uint8Array = new Uint8Array(event.data);
emit('message', { type: 'binary', data: uint8Array, size });
} else {
// Handle JSON or binary header
const message = JSON.parse(event.data);
if (message.type === '__BINARY__') {
this._expectingBinaryMessage = true;
}
}
}
```
Added binary message routing:
```javascript
handleIncomingMessage(message, fromPeerId) {
if (message.type === 'binary' && message.data instanceof Uint8Array) {
this.mesh.emit('binaryMessageReceived', {
from: fromPeerId,
data: message.data,
size: message.size,
timestamp: Date.now()
});
return;
}
// ... rest of message handling
}
```
**Send to Specific Peer:**
```javascript
async sendBinaryData(targetPeerId, binaryData) {
const peerConnection = this.connectionManager.peers.get(targetPeerId);
return peerConnection.sendMessage(binaryData);
}
```
**Broadcast to All:**
```javascript
async broadcastBinaryData(binaryData) {
const peers = this.getConnectedPeers();
let sentCount = 0;
for (const peer of peers) {
if (await this.sendBinaryData(peer.peerId, binaryData)) {
sentCount++;
}
}
return sentCount;
}
```
Added new interfaces and methods:
```typescript
// Event interface
export interface BinaryMessageEvent {
from: string;
data: Uint8Array;
size: number;
timestamp: number;
}
// Methods
sendBinaryData(targetPeerId: string, binaryData: Uint8Array | ArrayBuffer): Promise<boolean>;
broadcastBinaryData(binaryData: Uint8Array | ArrayBuffer): Promise<number>;
// Events
addEventListener(event: 'binaryMessageReceived', listener: (data: BinaryMessageEvent) => void): void;
on(event: 'binaryMessageReceived', listener: (data: BinaryMessageEvent) => void): this;
```
```javascript
// To specific peer
const data = new Uint8Array([1, 2, 3, 4, 5]);
await mesh.sendBinaryData(targetPeerId, data);
// Broadcast to all
const count = await mesh.broadcastBinaryData(data);
```
```javascript
mesh.addEventListener('binaryMessageReceived', (event) => {
const { from, data, size } = event;
console.log(`Received ${size} bytes from ${from}`);
// data is Uint8Array
});
```
1. **`docs/BINARY_MESSAGES.md`** - Complete guide with:
- API documentation
- Usage examples (text, files, images, chunking)
- Performance considerations
- Best practices
- Troubleshooting
2. **`examples/binary-message-demo.html`** - Interactive demo showing:
- Random binary data transmission
- Test patterns
- Text encoding/decoding
- Peer selection (unicast/broadcast)
- Real-time stats and hex dumps
- Activity logging
## Technical Details
### Message Flow
1. **Sender**: Detects binary → Sends header → Sends payload
2. **Receiver**: Receives header → Sets flag → Receives payload → Emits event
3. **Application**: Listens to `binaryMessageReceived` event
### Protocol
```
[Header Message - JSON]
{ "type": "__BINARY__", "size": 1024 }
[]
<raw binary data>
```
- JSON messages work exactly as before
- No breaking changes to existing code
- Binary support is additive
| Metric | JSON + Base64 | Native Binary |
|--------|---------------|---------------|
| Size Overhead | +33% | 0% |
| Serialization | Yes | No |
| Type Conversion | Yes | No |
| Data Integrity | Lossy | Perfect |
| Speed | Slower | Faster |
- **File transfers**: Send files peer-to-peer
- **Media streaming**: Raw audio/video data
- **Binary protocols**: Custom protocols
- **Encryption**: Send encrypted data
- **Large datasets**: Scientific/analytics data
- **Images**: Canvas pixel data
The demo can be tested by:
```bash
npm run hub
npm run http
http://localhost:8080/examples/binary-message-demo.html
```
Works in all modern browsers with:
- WebRTC RTCDataChannel ✅
- ArrayBuffer/Uint8Array ✅
- TextEncoder/Decoder ✅
Tested on: Chrome, Firefox, Safari, Edge
Possible improvements:
- [ ] Automatic chunking for large files
- [ ] Built-in compression
- [ ] Progress callbacks
- [ ] Streaming API
- [ ] Binary encryption
- [ ] Reliability layer with ACKs
1. `src/PeerConnection.js` - Core binary handling
2. `src/ConnectionManager.js` - Message routing
3. `src/PeerPigeonMesh.js` - Public API methods
4. `types/index.d.ts` - TypeScript definitions
1. `docs/BINARY_MESSAGES.md` - Documentation
2. `examples/binary-message-demo.html` - Interactive demo
3. `docs/BINARY_IMPLEMENTATION_SUMMARY.md` - This file
Build completed successfully:
```
✅ Browser bundle created at dist/peerpigeon-browser.js
📦 Binary message support included
```
```javascript
// Initialize mesh
const mesh = new PeerPigeonMesh({
signalingServer: 'ws://localhost:3000',
autoConnect: true
});
await mesh.connect();
// Send binary data
const data = new Uint8Array(1024);
crypto.getRandomValues(data);
await mesh.broadcastBinaryData(data);
// Receive binary data
mesh.addEventListener('binaryMessageReceived', (event) => {
console.log(`Received ${event.size} bytes from ${event.from}`);
processData(event.data); // Uint8Array
});
```
Binary message support is now fully implemented and ready for use. The feature:
- ✅ Works transparently with existing code
- ✅ Maintains backward compatibility
- ✅ Provides significant performance benefits
- ✅ Includes comprehensive documentation
- ✅ Has interactive demo for testing
- ✅ Supports all major browsers
Users can now send binary data efficiently without JSON serialization overhead!