Skip to content

Commit 0890d57

Browse files
committed
docs: Update README and create Wiki
- Final audit complete. - Removed junk files. - Refined error handling (unwrap -> expect). - Added comprehensive README.md. - Created Docs/Wiki structure for GitHub.
1 parent ded34c2 commit 0890d57

10 files changed

Lines changed: 247 additions & 193 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ Thumbs.db
3030
!README.md
3131
docs/audit/
3232
/*.sh
33-
/.txt
33+
/.txt.git/hooks/pre-commit

README.md

Lines changed: 66 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -1,208 +1,84 @@
11
# Ironfish
22

3-
<div align="left">
3+
Ironfish is a **fault-tolerant, distributed chess analysis engine** built with Rust. It leverages **Stockfish**, **Docker**, and **Gossip protocols** to create a resilient, scalable, and self-healing cluster for chess position analysis.
44

5-
[![Status](https://img.shields.io/badge/Status-Active-success?style=flat-square)]()
6-
[![Rust](https://img.shields.io/badge/Rust-1.75%2B-orange?style=flat-square&logo=rust)](https://www.rust-lang.org)
7-
[![License](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](LICENSE)
8-
[![Docker](https://img.shields.io/badge/Docker-Supported-2496ED?style=flat-square&logo=docker)]()
9-
[![Protocol](https://img.shields.io/badge/Protocol-gRPC%20%7C%20REST%20%7C%20GraphQL-purple?style=flat-square)]()
5+
## Key Features
106

11-
</div>
7+
- **Distributed Analysis:** Distributes chess analysis workload across a cluster of nodes.
8+
- **Fault Tolerance:** Built-in leader election (Hybrid Raft/Bully) and self-healing capabilities. If a node dies, the cluster recovers automatically.
9+
- **Auto-Discovery:** Nodes discover each other via Static config, UDP Multicast, or DNS (Cloud/Kubernetes).
10+
- **Load Balancing:** CPU-aware and Queue-aware load balancing strategies.
11+
- **Secure API:** Token-based authentication (`X-Admin-Key` for management, Bearer tokens for usage).
12+
- **Multi-Protocol Support:** Single port (8080) exposes REST, gRPC, and GraphQL APIs.
13+
- **Observability:** Built-in metrics (`/v1/metrics`) tracking CPU, Memory, and Engine usage.
1214

13-
<div align="center">
14-
<img src="assets/logo.png" alt="Ironfish Logo" width="256" />
15-
</div>
15+
## Architecture
1616

17-
A distributed, fault-tolerant chess position analysis system using Stockfish, built entirely in Rust.
18-
19-
## Features
20-
21-
- **Multi-Protocol API** - REST, gRPC, and GraphQL on separate ports
22-
- **HA Clustering** - Automatic node discovery and gossip-based token replication
23-
- **Token Authentication** - Secure API access with cluster-wide token synchronization
24-
- **Stockfish Integration** - Engine pool for concurrent position analysis
25-
- **Admin CLI** - Cluster management and token administration
17+
Ironfish operates as a cluster of identical nodes. Each node runs:
18+
1. **API Layer:** Axum (REST/GraphQL) + Tonic (gRPC) multiplexed on port 8080.
19+
2. **Cluster Service:** Handles membership, gossip, and failure detection.
20+
3. **Stockfish Pool:** Manages a pool of Stockfish engine processes for analysis.
2621

2722
## Quick Start
2823

29-
### Single Node
30-
31-
```bash
32-
# Build
33-
cargo build --release
34-
35-
# Run (requires Stockfish installed)
36-
STOCKFISH_PATH=/usr/local/bin/stockfish ./target/release/ironfish-server
37-
```
24+
### Prerequisites
25+
* Docker & Docker Compose
26+
* (Optional) Rust toolchain for local development
27+
28+
### Running a Cluster
29+
30+
1. **Start the cluster:**
31+
```bash
32+
docker compose up -d
33+
```
34+
This spins up 3 nodes (`node1`, `node2`, `node3`).
35+
36+
2. **Create an Admin Token:**
37+
```bash
38+
# Use the default admin key "cluster-admin-secret" defined in docker-compose.yml
39+
curl -X POST http://localhost:8080/_admin/tokens \
40+
-H "X-Admin-Key: cluster-admin-secret" \
41+
-H "Content-Type: application/json" \
42+
-d '{"name": "my-token"}'
43+
```
44+
*Response:* `{"token": "iff_..."}`
45+
46+
3. **Analyze a Position:**
47+
```bash
48+
curl -X POST http://localhost:8080/v1/analyze \
49+
-H "Authorization: Bearer <YOUR_TOKEN>" \
50+
-H "Content-Type: application/json" \
51+
-d '{
52+
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
53+
"depth": 15
54+
}'
55+
```
56+
57+
### API Endpoints
58+
59+
| Method | Path | Description | Auth |
60+
| :--- | :--- | :--- | :--- |
61+
| `GET` | `/v1/health` | Node health status | None |
62+
| `GET` | `/v1/metrics` | System & Cluster metrics | Bearer |
63+
| `POST` | `/v1/analyze` | Analyze FEN position | Bearer |
64+
| `POST` | `/graphql` | GraphQL Endpoint | Bearer |
65+
| `POST` | `/_admin/tokens` | Create API Token | Admin Key |
66+
| `DELETE` | `/_admin/tokens/:id` | Revoke API Token | Admin Key |
3867

39-
### Docker Cluster (Example 3 nodes)
68+
## Development
4069

70+
### Pre-commit Hooks
71+
The project includes a pre-commit hook to ensure code quality.
4172
```bash
42-
# Start cluster
43-
docker compose up -d
44-
45-
# Check health
46-
curl http://localhost:8080/v1/health
47-
curl http://localhost:8082/v1/health
48-
curl http://localhost:8084/v1/health
49-
50-
# Create API token
51-
curl -X POST -H "X-Admin-Key: cluster-admin-secret" \
52-
-H "Content-Type: application/json" -d '{}' \
53-
http://localhost:8080/_admin/tokens
54-
55-
# Analyze position
56-
curl -X POST -H "Authorization: Bearer <token>" \
57-
-H "Content-Type: application/json" \
58-
-d '{"fen": "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1", "depth": 15}' \
59-
http://localhost:8080/v1/analyze
73+
cp pre-commit .git/hooks/pre-commit
74+
chmod +x .git/hooks/pre-commit
6075
```
6176

62-
## API Endpoints
63-
64-
### REST API (Port 8080)
65-
66-
| Method | Endpoint | Description |
67-
|--------|----------|-------------|
68-
| POST | `/v1/analyze` | Analyze chess position |
69-
| POST | `/v1/bestmove` | Get best move only |
70-
| GET | `/v1/health` | Health check (public) |
71-
| GET | `/v1/metrics` | Engine metrics |
72-
73-
### Admin API (Requires X-Admin-Key header)
74-
75-
| Method | Endpoint | Description |
76-
|--------|----------|-------------|
77-
| GET | `/_admin/tokens` | List all tokens |
78-
| POST | `/_admin/tokens` | Create new token |
79-
| DELETE | `/_admin/tokens/:id` | Revoke token |
80-
| GET | `/_admin/cluster/status` | Cluster membership |
81-
82-
### gRPC API (Port 8081)
83-
77+
### Running Tests
8478
```bash
85-
# List services
86-
grpcurl -plaintext localhost:8081 list
87-
88-
# Analyze position
89-
grpcurl -plaintext -H "authorization: Bearer <token>" \
90-
-d '{"fen": "startpos", "depth": 10}' \
91-
localhost:8081 chess.ChessAnalysis/Analyze
92-
```
93-
94-
### GraphQL API (Port 8080/graphql)
95-
96-
```graphql
97-
query {
98-
analyze(fen: "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1", depth: 15) {
99-
bestMove { from to }
100-
evaluation { scoreType value }
101-
}
102-
}
79+
cargo test --workspace
10380
```
104-
105-
## Configuration
106-
107-
### Environment Variables
108-
109-
| Variable | Default | Description |
110-
|----------|---------|-------------|
111-
| `IRONFISH_NODE_ID` | auto | Node identifier |
112-
| `IRONFISH_BIND_ADDRESS` | 0.0.0.0:8080 | Listen address |
113-
| `IRONFISH_CLUSTER_PEERS` | - | Comma-separated peer list |
114-
| `IRONFISH_TOKEN_SECRET` | dev-secret | Shared HMAC secret for tokens |
115-
| `IRONFISH_ADMIN_KEY` | - | Admin API authentication key |
116-
| `STOCKFISH_PATH` | /usr/local/bin/stockfish | Path to Stockfish binary |
117-
118-
### Config File (config/default.toml)
119-
120-
```toml
121-
[node]
122-
id = "auto"
123-
bind_address = "0.0.0.0:8080"
124-
data_dir = "/var/lib/ironfish"
125-
126-
[stockfish]
127-
binary_path = "/usr/bin/stockfish"
128-
pool_size = 4
129-
default_depth = 20
130-
131-
[cluster]
132-
enabled = true
133-
heartbeat_interval_ms = 1000
134-
gossip_interval_ms = 5000
135-
136-
[discovery]
137-
static_peers = ["node2:8080", "node3:8080"]
138-
multicast_enabled = true
139-
140-
[auth]
141-
enabled = true
142-
token_ttl_days = 365
143-
```
144-
145-
## Project Structure
146-
147-
```
148-
ironfish/
149-
├── Cargo.toml # Workspace root
150-
├── Dockerfile # Multi-stage build
151-
├── docker-compose.yml # 3-node cluster setup
152-
├── crates/
153-
│ ├── ironfish-core/ # Core types, traits, errors
154-
│ ├── ironfish-stockfish/ # Stockfish engine pool
155-
│ ├── ironfish-auth/ # Token management & middleware
156-
│ ├── ironfish-cluster/ # Clustering & gossip
157-
│ │ ├── src/
158-
│ │ │ ├── discovery/ # Peer discovery (static, multicast)
159-
│ │ │ ├── consensus/ # Raft + Bully algorithms
160-
│ │ │ ├── gossip.rs # Token replication
161-
│ │ │ └── network.rs # TCP transport
162-
│ ├── ironfish-api/ # REST, gRPC, GraphQL
163-
│ │ ├── proto/ # Protobuf definitions
164-
│ │ └── src/
165-
│ │ ├── rest/ # Axum handlers
166-
│ │ ├── grpc/ # Tonic service
167-
│ │ └── graphql/ # async-graphql schema
168-
│ ├── ironfish-cli/ # Admin CLI tool
169-
│ └── ironfish-server/ # Main binary
170-
└── config/
171-
└── default.toml # Default configuration
172-
```
173-
174-
## Development
175-
176-
```bash
177-
# Run tests
178-
cargo test --all
179-
180-
# Run with logging
181-
RUST_LOG=info cargo run -p ironfish-server
182-
183-
# Format code
184-
cargo fmt --all
185-
186-
# Lint
187-
cargo clippy --all -- -D warnings
188-
```
189-
190-
## Cluster Features
191-
192-
### Token Replication
193-
194-
Tokens created on any node are automatically replicated to all cluster nodes via gossip protocol. Token revocations are also propagated cluster-wide.
195-
196-
### Auto-Discovery
197-
198-
Nodes discover each other using:
199-
1. **Static peers** - Hostname:port list (supports DNS resolution)
200-
2. **Multicast** - UDP discovery on local network (239.255.42.98:7878)
201-
202-
### Shared Authentication
203-
204-
All nodes must use the same `IRONFISH_TOKEN_SECRET` to validate tokens created by other nodes.
81+
Note: Docker integration tests run sequentially to avoid port conflicts.
20582

20683
## License
207-
208-
MIT
84+
MIT

crates/ironfish-cluster/src/node.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ impl Default for NodeConfig {
1414
fn default() -> Self {
1515
Self {
1616
id: None,
17-
bind_address: "0.0.0.0:8080".parse().unwrap(),
17+
bind_address: "0.0.0.0:8080".parse().expect("valid default bind address"),
1818
priority: 100,
1919
version: env!("CARGO_PKG_VERSION").to_string(),
2020
}

crates/ironfish-server/src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ fn default_bind_address() -> SocketAddr {
105105
std::env::var("IRONFISH_BIND_ADDRESS")
106106
.ok()
107107
.and_then(|s| s.parse().ok())
108-
.unwrap_or_else(|| "0.0.0.0:8080".parse().unwrap())
108+
.unwrap_or_else(|| "0.0.0.0:8080".parse().expect("valid default address"))
109109
}
110110
fn default_data_dir() -> PathBuf {
111111
PathBuf::from("/var/lib/ironfish")

docs/wiki/API-Reference.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# API Reference
2+
3+
## Authentication
4+
5+
* **Admin Actions:** Require `X-Admin-Key` header. Configured via `IRONFISH_ADMIN_KEY` env var.
6+
* **User Actions:** Require `Authorization: Bearer <TOKEN>` header.
7+
8+
## REST API
9+
10+
### Health
11+
`GET /v1/health`
12+
Returns 200 OK if the node is running.
13+
14+
### Metrics
15+
`GET /v1/metrics`
16+
**Auth:** Bearer
17+
Returns system metrics:
18+
```json
19+
{
20+
"cpu_usage": 12.5,
21+
"memory_usage": 0.45,
22+
"active_analyses": 2
23+
}
24+
```
25+
26+
### Analyze
27+
`POST /v1/analyze`
28+
**Auth:** Bearer
29+
**Body:**
30+
```json
31+
{
32+
"fen": "...",
33+
"depth": 20
34+
}
35+
```
36+
37+
## GraphQL API
38+
Endpoint: `/graphql`
39+
40+
### Query: Cluster Status
41+
```graphql
42+
query {
43+
clusterStatus {
44+
nodes {
45+
id
46+
state
47+
address
48+
}
49+
leader
50+
healthy
51+
}
52+
}
53+
```
54+
55+
## gRPC API
56+
Service: `ChessAnalysis`
57+
* `Analyze(AnalyzeRequest) returns (AnalyzeResponse)`

docs/wiki/Architecture.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Architecture
2+
3+
## Overview
4+
5+
Ironfish follows a **peer-to-peer** architecture where all nodes are capable of performing analysis and serving API requests. The cluster maintains state consistency using a **Gossip Protocol** and achieves high availability through **Leader Election**.
6+
7+
## Core Components
8+
9+
### 1. Networking & Discovery
10+
* **Gossip Protocol:** Uses a random-peer gossip mechanism to disseminate cluster state (membership, health, load).
11+
* **Discovery:**
12+
* `Static`: Hardcoded list of peers (good for simple setups).
13+
* `Multicast`: UDP discovery for local networks.
14+
* `DNS`: Resolves SRV/A records to find peers (ideal for Kubernetes Headless Services).
15+
16+
### 2. Consensus (Hybrid)
17+
* **Bully Algorithm:** Used for initial leader election due to its speed in small, stable clusters.
18+
* **Raft-like Terms:** Implements "Terms" to prevent split-brain scenarios and ensure strictly increasing versioning of the cluster state.
19+
20+
### 3. Load Balancing
21+
* **CpuAware:** Nodes broadcast their CPU usage and Queue depth via gossip.
22+
* **Selection:** The entry node selects the best peer (lowest score based on CPU + Queue + Latency) to forward the analysis request to.
23+
24+
### 4. Engine Management
25+
* **Stockfish Pool:** Each node manages a local pool of Stockfish processes.
26+
* **Zombie Killer:** A background task monitors child processes and restarts them if they become unresponsive or die unexpectedly.

0 commit comments

Comments
 (0)