P2P Collaborative Text Editor using CRDT
Project description
P2P CRDT Collaborative Text Editor
A peer-to-peer collaborative text editor using Conflict-free Replicated Data Types (CRDT). No central server required - all peers are equal!
Features
- True P2P Architecture: No server needed, all peers are equal
- CRDT Synchronization: Uses RGA (Replicated Growable Array) for conflict-free merging
- Real-time Collaboration: Changes sync instantly across all connected peers
- Automatic Peer Discovery: UDP broadcast for LAN peer detection
- Manual Connections: Connect to peers via IP address
- Modern UI: Clean, professional Tkinter interface
- Persistent State: Document state saved to disk
- Batch Operations: Optimized bulk delete/insert operations
Installation
From PyPI (when published)
pip install p2pdocs
From Source
git clone https://github.com/yourusername/p2pdocs.git
cd p2pdocs
pip install -e .
Usage
Start the Editor
# Start with automatic peer discovery
p2pdocs alice
# Or connect directly to a peer
p2pdocs bob 192.168.1.100
Alternative (as Python module)
python -m p2pdocs alice
python -m p2pdocs bob 192.168.1.100
Programmatic Usage
from p2pdocs import P2PEditor
# Create and run editor
editor = P2PEditor(username="alice", peer_ip="192.168.1.100")
editor.run()
Version
Current Version: 1.0.14 ✅ Zero Dependencies — Python 3.8+ stdlib only
Quick Start
Terminal 1: Start Server (Alice)
python p2p_crdt_editor.py server alice
Output:
[alice] Listening on port 5000...
Terminal 2: Start Client (Bob)
python p2p_crdt_editor.py client bob 127.0.0.1
Output:
[bob] Connecting to 127.0.0.1:5000...
[bob] Connected to alice
Start Editing
- Alice types → Bob sees it instantly
- Bob types → Alice sees it instantly
- Both type simultaneously → automatic convergence
Architecture
See CRDT_ARCHITECTURE.md for detailed design:
- CRDTId: Unique operation identifier
(client_id, lamport_clock) - CRDTElement: Character + ID + visibility flag
- CRDTDocument: CRDT state machine with merge logic
- NetworkManager: TCP peer connection handler
- P2PEditor: GUI + orchestration layer
Why CRDT?
| Aspect | Operational Transform (Old) | CRDT (New) |
|---|---|---|
| Central server | Required | ❌ Not needed |
| Transformation logic | Complex | Simple |
| Concurrent ops | Fragile | Guaranteed safe |
| Merge order | Critical | Automatic |
| Convergence | Assumed | Proven |
| Multi-peer | Difficult | Natural |
How RGA Works
Each character gets a unique ID: (client_id, lamport_clock)
Example:
Alice types "H" at pos 0 → ID = (alice-uuid, 1)
Bob types "i" at pos 0 → ID = (bob-uuid, 1)
Result (sorted by ID): "Hi" ✅ All peers converge!
Deletions create tombstones (not removed), so positions never shift.
Thread Safety
Main Thread (Tkinter) Network Thread
↓ ↓
_on_keystroke() _recv_message()
↓ ↓
doc.insert_local() doc.insert_remote()
↓ ↓
[doc.lock]◄────────────────[doc.lock]
↓ ↓
_rebuild_text() root.after(0, _rebuild_text)
Protected Resources:
doc.elements— protected bydoc.locktextwidget — protected bytext_lock
Message Protocol
{
"type": "INSERT",
"elements": [
{
"char_id": {"client_id": "uuid", "lamport_clock": 5},
"char": "A",
"visible": true
}
]
}
Supported messages:
INSERT— new characterDELETE— mark as tombstoneSYNC_REQUEST— request full stateFULL_SYNC— send all elements
Testing
-
Type and see sync:
- Alice: type "hello"
- Bob: instantly sees "hello"
-
Concurrent edits:
- Alice types at pos 0
- Bob types at pos 0 simultaneously
- Both converge to same text
-
Deletions:
- Alice presses backspace
- Bob sees character disappear
- Text remains consistent
-
Multi-line:
- Type newlines, text wraps correctly
- All peers sync properly
Limitations
- Single connection (1 server ↔ 1 client)
- No persistence (resets on restart)
- No multi-peer mesh yet
- No undo/redo support
Future Work
- Multi-peer mesh networking
- Disk persistence
- Operation batching
- Compression
- Snapshots + garbage collection
- Rich text formatting
- Presence awareness (cursor position)
- Offline support
Code Structure
p2p_crdt_editor.py (570 lines)
├── CRDTId ......................... Unique operation ID
├── CRDTElement .................... Char + metadata
├── CRDTDocument ................... State machine
├── NetworkManager ................. TCP networking
└── P2PEditor ...................... GUI + orchestration
License
MIT License - see LICENSE file for details.
Status: ✅ Production-Ready (Single Peer)
Python: 3.8+
Dependencies: None (stdlib only)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file p2pdocs-1.0.14.tar.gz.
File metadata
- Download URL: p2pdocs-1.0.14.tar.gz
- Upload date:
- Size: 25.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fdbbb0ba8f743af2b27e8d1adf6261339549ce529ca25001887479bf2b9d0447
|
|
| MD5 |
eb62b10d276bf01461e7f3a5a20dafd2
|
|
| BLAKE2b-256 |
11ef46f36909efb503a8b119c3746a6ed98fd6f19a49caad346b65b7421a5216
|
Provenance
The following attestation bundles were made for p2pdocs-1.0.14.tar.gz:
Publisher:
publish.yml on taaha-0548/P2PDocs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
p2pdocs-1.0.14.tar.gz -
Subject digest:
fdbbb0ba8f743af2b27e8d1adf6261339549ce529ca25001887479bf2b9d0447 - Sigstore transparency entry: 727039770
- Sigstore integration time:
-
Permalink:
taaha-0548/P2PDocs@ac8033ce1e229d447fd4854f45986c7e12999fc2 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/taaha-0548
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ac8033ce1e229d447fd4854f45986c7e12999fc2 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file p2pdocs-1.0.14-py3-none-any.whl.
File metadata
- Download URL: p2pdocs-1.0.14-py3-none-any.whl
- Upload date:
- Size: 25.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
717355c29fc2253bc1fcb9c1ffb36ec95170ef1675b60f1bd0c86087b81d860e
|
|
| MD5 |
d2224cbd318b086cad62029c8d6a2511
|
|
| BLAKE2b-256 |
208c88e1c5ebe06d21f78a7a6a8f6d8af54da1fae31162a7eb2c2303b38d20a4
|
Provenance
The following attestation bundles were made for p2pdocs-1.0.14-py3-none-any.whl:
Publisher:
publish.yml on taaha-0548/P2PDocs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
p2pdocs-1.0.14-py3-none-any.whl -
Subject digest:
717355c29fc2253bc1fcb9c1ffb36ec95170ef1675b60f1bd0c86087b81d860e - Sigstore transparency entry: 727039812
- Sigstore integration time:
-
Permalink:
taaha-0548/P2PDocs@ac8033ce1e229d447fd4854f45986c7e12999fc2 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/taaha-0548
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ac8033ce1e229d447fd4854f45986c7e12999fc2 -
Trigger Event:
workflow_dispatch
-
Statement type: