diff options
Diffstat (limited to 'docs/explanation/comparison.md')
| -rw-r--r-- | docs/explanation/comparison.md | 256 |
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 | |||
| 192 | Similar 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 | |||
| 199 | For users of ngit-relay, migration to ngit-grasp would involve: | ||
| 200 | |||
| 201 | 1. **Export data** from Badger to LMDB/NDB | ||
| 202 | 2. **Copy Git repositories** (same structure) | ||
| 203 | 3. **Update environment variables** (mostly compatible) | ||
| 204 | 4. **Change deployment** from Docker Compose to binary/Docker | ||
| 205 | 5. **Update URLs** if domain changes | ||
| 206 | |||
| 207 | The **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 | |||
| 249 | Both 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 | |||
| 254 | The choice depends on your priorities: stability vs. performance, familiarity vs. innovation, proven vs. cutting-edge. | ||
| 255 | |||
| 256 | For 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. | ||