upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/docs/explanation/comparison.md
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-11-04 10:25:53 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-11-04 10:25:53 +0000
commit52bad9954cdddf55ab749fd0c6387edbc766632f (patch)
treed9dd2078b70a627a71d1adb9555cee83faec5cd0 /docs/explanation/comparison.md
parentdb460efdd4cf34d3b6ac8c19b1b8f89f22bc279f (diff)
docs: use Diátaxis structure
Diffstat (limited to 'docs/explanation/comparison.md')
-rw-r--r--docs/explanation/comparison.md256
1 files changed, 256 insertions, 0 deletions
diff --git a/docs/explanation/comparison.md b/docs/explanation/comparison.md
new file mode 100644
index 0000000..be16f9e
--- /dev/null
+++ b/docs/explanation/comparison.md
@@ -0,0 +1,256 @@
1# ngit-grasp vs ngit-relay Comparison
2
3## High-Level Comparison
4
5| Aspect | ngit-relay (Reference) | ngit-grasp (This Project) |
6|--------|------------------------|---------------------------|
7| **Language** | Go | Rust |
8| **Architecture** | Multi-process (nginx, git-http-backend, hooks, relay) | Single integrated process |
9| **Authorization** | Git pre-receive hook | Inline HTTP handler |
10| **Packaging** | Docker + supervisord | Single binary or Docker |
11| **Configuration** | Multiple config files | Environment variables |
12| **Deployment** | Docker Compose | Binary or Docker |
13| **Testing** | Go tests + shell scripts | Rust unit + integration tests |
14
15## Component Breakdown
16
17### ngit-relay (Go)
18
19```
20┌─────────────────────────────────────────────────┐
21│ Docker Container │
22├─────────────────────────────────────────────────┤
23│ │
24│ ┌──────────┐ ┌─────────────────────┐ │
25│ │ nginx │────────▶│ git-http-backend │ │
26│ │ :80 │ │ (C binary) │ │
27│ └──────────┘ └──────────┬──────────┘ │
28│ │ │ │
29│ │ ▼ │
30│ │ ┌─────────────────┐ │
31│ │ │ Git Repo │ │
32│ │ │ + Hooks │ │
33│ │ └────────┬────────┘ │
34│ │ │ │
35│ │ ▼ │
36│ │ ┌─────────────────┐ │
37│ │ │ pre-receive │ │
38│ │ │ (Go binary) │ │
39│ │ └────────┬────────┘ │
40│ │ │ │
41│ │ │ WebSocket │
42│ │ ▼ │
43│ │ ┌─────────────────┐ │
44│ └─────────────────▶│ Khatru Relay │ │
45│ │ (Go) │ │
46│ └─────────────────┘ │
47│ │
48│ ┌──────────────────────────────────────────┐ │
49│ │ supervisord │ │
50│ │ - nginx │ │
51│ │ - khatru │ │
52│ │ - proactive-sync │ │
53│ └──────────────────────────────────────────┘ │
54│ │
55└─────────────────────────────────────────────────┘
56```
57
58### ngit-grasp (Rust)
59
60```
61┌─────────────────────────────────────────────────┐
62│ ngit-grasp (Single Binary) │
63├─────────────────────────────────────────────────┤
64│ │
65│ ┌──────────────────────────────────────────┐ │
66│ │ actix-web HTTP Server │ │
67│ │ :8080 │ │
68│ └───────┬──────────────────────┬────────────┘ │
69│ │ │ │
70│ ▼ ▼ │
71│ ┌──────────────┐ ┌──────────────────┐ │
72│ │ Git Handlers │ │ Nostr Relay │ │
73│ │ │ │ (relay-builder) │ │
74│ │ - upload-pk │ │ │ │
75│ │ - receive-pk │◀─────│ - Policies │ │
76│ │ + inline │ query│ - Event store │ │
77│ │ validation │ │ - WebSocket │ │
78│ └──────┬───────┘ └──────────────────┘ │
79│ │ │
80│ ▼ │
81│ ┌──────────────┐ │
82│ │ Git Repos │ │
83│ │ (spawned │ │
84│ │ git cmds) │ │
85│ └──────────────┘ │
86│ │
87│ ┌──────────────────────────────────────────┐ │
88│ │ Shared State (Arc<AppState>) │ │
89│ │ - RepositoryManager │ │
90│ │ - NostrClient │ │
91│ │ - StateCache │ │
92│ └──────────────────────────────────────────┘ │
93│ │
94└─────────────────────────────────────────────────┘
95```
96
97## Detailed Feature Comparison
98
99### Git Protocol Handling
100
101| Feature | ngit-relay | ngit-grasp |
102|---------|-----------|-----------|
103| Implementation | git-http-backend (C) | git-http-backend (Rust crate) |
104| Process model | nginx → C binary | actix-web → Rust handler |
105| Upload pack | Passthrough | Passthrough with validation |
106| Receive pack | Hook-based auth | Inline validation |
107| Error handling | Hook stderr | HTTP response |
108| CORS | nginx config | actix-cors middleware |
109
110### Nostr Relay
111
112| Feature | ngit-relay | ngit-grasp |
113|---------|-----------|-----------|
114| Implementation | Khatru (Go) | nostr-relay-builder (Rust) |
115| Event store | Badger (Go) | LMDB or NDB (Rust) |
116| Policies | Go functions | Rust traits |
117| WebSocket | Khatru built-in | nostr-relay-builder |
118| NIP-11 | Manual JSON | Built-in support |
119
120### Authorization Logic
121
122| Feature | ngit-relay | ngit-grasp |
123|---------|-----------|-----------|
124| Location | pre-receive hook | HTTP handler |
125| Language | Go | Rust |
126| State query | WebSocket to localhost:3334 | In-process function call |
127| Error reporting | stderr → git client | HTTP response body |
128| Ref validation | Line-by-line stdin | Parsed from request body |
129| Maintainer resolution | Recursive Go function | Recursive Rust function |
130| State caching | Per-request | Shared cache with TTL |
131
132### Repository Management
133
134| Feature | ngit-relay | ngit-grasp |
135|---------|-----------|-----------|
136| Creation | Event hook + shell commands | Event hook + tokio::process |
137| Configuration | git config via shell | git config via tokio::process |
138| Hook installation | Symlinks | Not needed (inline auth) |
139| Permissions | chown nginx:nginx | tokio::fs permissions |
140| Path structure | `<npub>/<id>.git` | `<npub>/<id>.git` (same) |
141
142### Deployment
143
144| Feature | ngit-relay | ngit-grasp |
145|---------|-----------|-----------|
146| Dependencies | nginx, git, Go runtime | git, Rust binary (no runtime) |
147| Process management | supervisord | Single process (tokio) |
148| Configuration | Multiple files + .env | .env only |
149| Docker image size | ~500MB (Alpine + tools) | ~50MB (scratch + binary + git) |
150| Startup time | ~2-5 seconds | ~0.5 seconds |
151| Memory usage | ~100-200MB (multiple processes) | ~50-100MB (single process) |
152
153### Development Experience
154
155| Feature | ngit-relay | ngit-grasp |
156|---------|-----------|-----------|
157| Build time | Fast (Go) | Medium (Rust first build, then fast) |
158| Type safety | Go (good) | Rust (excellent) |
159| Testing | Go test + shell | Rust test (unit + integration) |
160| Debugging | Multiple processes | Single process |
161| Hot reload | Manual | cargo-watch |
162| IDE support | Good (Go) | Excellent (rust-analyzer) |
163
164## Performance Comparison (Estimated)
165
166| Metric | ngit-relay | ngit-grasp | Notes |
167|--------|-----------|-----------|-------|
168| Startup | ~2-5s | ~0.5s | Fewer processes |
169| Memory | ~150MB | ~75MB | Single process, no GC |
170| CPU (idle) | ~1-2% | ~0.5% | Fewer processes |
171| Push latency | +50-100ms | +10-20ms | No hook spawn overhead |
172| Clone latency | ~same | ~same | Both passthrough to Git |
173| Concurrent pushes | Good | Excellent | Tokio async vs goroutines |
174| Event ingestion | Good | Excellent | Rust async + zero-copy |
175
176*Note: These are estimates. Actual performance depends on workload and hardware.*
177
178## Code Complexity
179
180### Lines of Code (Estimated)
181
182| Component | ngit-relay | ngit-grasp |
183|-----------|-----------|-----------|
184| Main server | ~150 | ~200 |
185| Git handlers | ~0 (C binary) | ~500 |
186| Auth logic | ~200 | ~300 |
187| Nostr relay | ~500 | ~100 (using library) |
188| Shared utils | ~300 | ~200 |
189| Config/setup | ~200 | ~100 |
190| **Total** | **~1,350** | **~1,400** |
191
192Similar complexity, but ngit-grasp has:
193- More Git protocol code (we implement it)
194- Less Nostr relay code (using library)
195- Less deployment code (no hooks/supervisord)
196
197## Migration Path
198
199For users of ngit-relay, migration to ngit-grasp would involve:
200
2011. **Export data** from Badger to LMDB/NDB
2022. **Copy Git repositories** (same structure)
2033. **Update environment variables** (mostly compatible)
2044. **Change deployment** from Docker Compose to binary/Docker
2055. **Update URLs** if domain changes
206
207The **Nostr events** and **Git data** are compatible - only the server changes.
208
209## When to Choose Each
210
211### Choose ngit-relay (Reference) if:
212
213- ✅ You need a proven, production-tested implementation
214- ✅ You're already familiar with Go
215- ✅ You want to stay close to the reference
216- ✅ You need to deploy immediately
217- ✅ You prefer Docker Compose workflows
218
219### Choose ngit-grasp (This Project) if:
220
221- ✅ You want better performance and lower resource usage
222- ✅ You prefer Rust's type safety and ecosystem
223- ✅ You want simpler deployment (single binary)
224- ✅ You want to contribute to a modern codebase
225- ✅ You're building on top of the GRASP protocol
226- ✅ You want inline authorization over hooks
227- ✅ You need better integration testing
228
229## Future Roadmap Comparison
230
231### ngit-relay (Reference)
232- ✅ GRASP-01 complete
233- 🔄 GRASP-02 in progress
234- ⏭️ GRASP-05 planned
235- ⏭️ NIP-42 auth-to-read
236- ⏭️ NIP-70 protected events
237- ⏭️ Spam prevention
238
239### ngit-grasp (This Project)
240- 🔄 GRASP-01 in development
241- ⏭️ GRASP-02 planned (easier with Rust async)
242- ⏭️ GRASP-05 planned
243- ⏭️ Advanced caching strategies
244- ⏭️ Metrics and observability
245- ⏭️ Plugin system for custom policies
246
247## Conclusion
248
249Both implementations are valid approaches to GRASP:
250
251- **ngit-relay** is the mature, proven reference implementation
252- **ngit-grasp** is a modern, performant alternative with better DX
253
254The choice depends on your priorities: stability vs. performance, familiarity vs. innovation, proven vs. cutting-edge.
255
256For new deployments where performance and simplicity matter, **ngit-grasp** is the recommended choice. For production systems requiring maximum stability, **ngit-relay** is the safer bet until ngit-grasp reaches maturity.