docs: shared crate strategy for WZP ↔ featherChat interop
Defines 5 tasks (FC-CRATE-1/2/3, WZP-CRATE-1/2) to make both projects' crates importable by each other: featherChat side: - FC-CRATE-1: Make warzone-protocol standalone (replace workspace deps) - FC-CRATE-2: Add CallSignal variant using wzp-proto types - FC-CRATE-3: Extract warzone-identity micro-crate (optional) WZP side (after FC-CRATE-1): - WZP-CRATE-1: Replace identity mirror with real warzone-protocol dep - WZP-CRATE-2: Verify wzp-proto works as git dep from featherChat Priority: FC-CRATE-1 first (30 min, unblocks everything). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
230
docs/WZP-FC-SHARED-CRATES.md
Normal file
230
docs/WZP-FC-SHARED-CRATES.md
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
# Shared Crate Strategy: WZP ↔ featherChat
|
||||||
|
|
||||||
|
**Goal:** Both projects import each other's crates directly instead of duplicating code. A change to identity derivation in featherChat automatically applies in WZP, and vice versa for call signaling types.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Current Problem
|
||||||
|
|
||||||
|
- `warzone-protocol` uses workspace dependency inheritance (`Cargo.toml` has `ed25519-dalek.workspace = true`). When WZP tries to use it as a path dep, Cargo fails because it can't resolve workspace references from outside the featherChat workspace.
|
||||||
|
- WZP had to mirror featherChat's `identity.rs`, `mnemonic.rs`, and `Fingerprint` type in `wzp-crypto/src/identity.rs` — duplicate code that can drift.
|
||||||
|
- featherChat will need `wzp_proto::SignalMessage` for the `WireMessage::CallSignal` variant — another potential duplication.
|
||||||
|
|
||||||
|
## Solution: Make Key Crates Standalone-Importable
|
||||||
|
|
||||||
|
### What featherChat Needs to Do
|
||||||
|
|
||||||
|
#### FC-CRATE-1: Make `warzone-protocol` standalone-publishable
|
||||||
|
|
||||||
|
**File:** `warzone/crates/warzone-protocol/Cargo.toml`
|
||||||
|
|
||||||
|
Replace all `workspace = true` references with explicit versions:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Before:
|
||||||
|
ed25519-dalek.workspace = true
|
||||||
|
x25519-dalek.workspace = true
|
||||||
|
|
||||||
|
# After:
|
||||||
|
ed25519-dalek = { version = "2", features = ["serde", "rand_core"] }
|
||||||
|
x25519-dalek = { version = "2", features = ["serde", "static_secrets"] }
|
||||||
|
chacha20poly1305 = "0.10"
|
||||||
|
hkdf = "0.12"
|
||||||
|
sha2 = "0.10"
|
||||||
|
rand = "0.8"
|
||||||
|
bip39 = "2"
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
serde_json = "1"
|
||||||
|
bincode = "1"
|
||||||
|
thiserror = "2"
|
||||||
|
hex = "0.4"
|
||||||
|
base64 = "0.22"
|
||||||
|
uuid = { version = "1", features = ["v4"] }
|
||||||
|
zeroize = { version = "1", features = ["derive"] }
|
||||||
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
k256 = { version = "0.13", features = ["ecdsa", "serde"] }
|
||||||
|
tiny-keccak = { version = "2", features = ["keccak"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
**Keep workspace inheritance working too** by using the `[package]` fallback pattern:
|
||||||
|
```toml
|
||||||
|
[package]
|
||||||
|
name = "warzone-protocol"
|
||||||
|
version = "0.0.20"
|
||||||
|
edition = "2021"
|
||||||
|
# Remove version.workspace and edition.workspace — use explicit values
|
||||||
|
```
|
||||||
|
|
||||||
|
This way the crate still works inside the featherChat workspace AND can be imported by WZP as a path dependency.
|
||||||
|
|
||||||
|
**Test:** From the WZP repo, this should work:
|
||||||
|
```toml
|
||||||
|
# In wzp-crypto/Cargo.toml:
|
||||||
|
warzone-protocol = { path = "../../deps/featherchat/warzone/crates/warzone-protocol" }
|
||||||
|
```
|
||||||
|
|
||||||
|
**Effort:** 30 minutes. Mechanical replacement, then `cargo build` to verify.
|
||||||
|
|
||||||
|
#### FC-CRATE-2: Add `wzp-proto` as a git dependency for `CallSignal`
|
||||||
|
|
||||||
|
**File:** `warzone/crates/warzone-protocol/Cargo.toml`
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
# WarzonePhone signaling types (for CallSignal WireMessage variant)
|
||||||
|
wzp-proto = { git = "ssh://git@git.manko.yoga:222/manawenuz/wz-phone.git", optional = true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
wzp = ["wzp-proto"]
|
||||||
|
```
|
||||||
|
|
||||||
|
**File:** `warzone/crates/warzone-protocol/src/message.rs`
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub enum WireMessage {
|
||||||
|
// ... existing variants ...
|
||||||
|
|
||||||
|
/// Voice/video call signaling (requires "wzp" feature).
|
||||||
|
#[cfg(feature = "wzp")]
|
||||||
|
CallSignal {
|
||||||
|
id: String,
|
||||||
|
sender_fingerprint: String,
|
||||||
|
signal: wzp_proto::SignalMessage, // Typed, not opaque bytes
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Voice/video call signaling (without wzp feature — opaque bytes).
|
||||||
|
#[cfg(not(feature = "wzp"))]
|
||||||
|
CallSignal {
|
||||||
|
id: String,
|
||||||
|
sender_fingerprint: String,
|
||||||
|
signal: Vec<u8>, // Opaque JSON bytes
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Alternative (simpler):** Always use `Vec<u8>` for the signal field and let the consumer deserialize. This avoids the feature flag complexity:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
CallSignal {
|
||||||
|
id: String,
|
||||||
|
sender_fingerprint: String,
|
||||||
|
signal_json: String, // JSON-serialized wzp_proto::SignalMessage
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
featherChat server treats it as opaque. WZP client deserializes it to `SignalMessage`.
|
||||||
|
|
||||||
|
**Effort:** 1-2 hours.
|
||||||
|
|
||||||
|
#### FC-CRATE-3: Extract shared identity types to a micro-crate (optional, long-term)
|
||||||
|
|
||||||
|
Create `warzone-identity` crate containing only:
|
||||||
|
- `Seed` (generation, from_bytes, from_hex, from_mnemonic, to_mnemonic)
|
||||||
|
- `IdentityKeyPair` (derive from seed)
|
||||||
|
- `PublicIdentity` (verifying key, encryption key, fingerprint)
|
||||||
|
- `Fingerprint` (SHA-256 truncated, display format)
|
||||||
|
- `hkdf_derive()` helper
|
||||||
|
|
||||||
|
Both `warzone-protocol` and `wzp-crypto` depend on `warzone-identity` instead of each implementing their own. This is the cleanest long-term solution but requires more refactoring.
|
||||||
|
|
||||||
|
**Crate structure:**
|
||||||
|
```
|
||||||
|
warzone-identity/
|
||||||
|
├── Cargo.toml (standalone, no workspace inheritance)
|
||||||
|
├── src/
|
||||||
|
│ ├── lib.rs
|
||||||
|
│ ├── seed.rs
|
||||||
|
│ ├── identity.rs
|
||||||
|
│ ├── fingerprint.rs
|
||||||
|
│ └── mnemonic.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dependencies:** ed25519-dalek, x25519-dalek, hkdf, sha2, bip39, hex, zeroize
|
||||||
|
|
||||||
|
Both projects import it:
|
||||||
|
```toml
|
||||||
|
# featherChat:
|
||||||
|
warzone-identity = { path = "../warzone-identity" }
|
||||||
|
|
||||||
|
# WZP (via submodule):
|
||||||
|
warzone-identity = { path = "deps/featherchat/warzone-identity" }
|
||||||
|
```
|
||||||
|
|
||||||
|
**Effort:** Half a day. Extract code from warzone-protocol, update imports in both projects.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### What WZP Needs to Do (after featherChat completes FC-CRATE-1)
|
||||||
|
|
||||||
|
#### WZP-CRATE-1: Replace identity mirror with real dependency
|
||||||
|
|
||||||
|
Once `warzone-protocol` is standalone-importable:
|
||||||
|
|
||||||
|
**File:** `crates/wzp-crypto/Cargo.toml`
|
||||||
|
```toml
|
||||||
|
# Remove bip39 and hex (now comes from warzone-protocol)
|
||||||
|
# Add:
|
||||||
|
warzone-protocol = { path = "../../deps/featherchat/warzone/crates/warzone-protocol" }
|
||||||
|
```
|
||||||
|
|
||||||
|
**File:** `crates/wzp-crypto/src/identity.rs`
|
||||||
|
Replace the entire file with re-exports:
|
||||||
|
```rust
|
||||||
|
//! featherChat identity — re-exported from warzone-protocol.
|
||||||
|
pub use warzone_protocol::identity::{IdentityKeyPair, Seed};
|
||||||
|
pub use warzone_protocol::types::Fingerprint;
|
||||||
|
```
|
||||||
|
|
||||||
|
**File:** `crates/wzp-crypto/src/handshake.rs`
|
||||||
|
Use `warzone_protocol::identity::Seed` internally instead of raw HKDF calls.
|
||||||
|
|
||||||
|
**Effort:** 1 hour (after FC-CRATE-1 is done).
|
||||||
|
|
||||||
|
#### WZP-CRATE-2: Make `wzp-proto` standalone-importable
|
||||||
|
|
||||||
|
`wzp-proto` already has explicit dependency versions (not workspace-inherited for external deps). It should work as a git dependency from featherChat. Verify:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From a scratch project:
|
||||||
|
cargo add --git ssh://git@git.manko.yoga:222/manawenuz/wz-phone.git wzp-proto
|
||||||
|
```
|
||||||
|
|
||||||
|
If this fails, replace any remaining workspace references in `wzp-proto/Cargo.toml` with explicit versions.
|
||||||
|
|
||||||
|
**Key types featherChat needs from wzp-proto:**
|
||||||
|
- `SignalMessage` (CallOffer, CallAnswer, IceCandidate, Hangup, etc.)
|
||||||
|
- `QualityProfile` (for codec negotiation)
|
||||||
|
- `HangupReason`
|
||||||
|
|
||||||
|
**Effort:** 30 minutes to verify and fix.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommended Order
|
||||||
|
|
||||||
|
1. **FC-CRATE-1** — Make warzone-protocol standalone (30 min, unblocks everything)
|
||||||
|
2. **WZP-CRATE-2** — Verify wzp-proto works as git dep (30 min)
|
||||||
|
3. **FC-CRATE-2** — Add CallSignal with opaque signal_json field (1-2 hours)
|
||||||
|
4. **WZP-CRATE-1** — Replace identity mirror with real dep (1 hour)
|
||||||
|
5. **FC-CRATE-3** — Extract warzone-identity micro-crate (optional, half day)
|
||||||
|
|
||||||
|
After steps 1-4, both projects share types directly:
|
||||||
|
- WZP imports `warzone-protocol` for identity/seed/fingerprint
|
||||||
|
- featherChat imports `wzp-proto` (via git) for `SignalMessage` types
|
||||||
|
- No duplicated code, no drift risk
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dependency Graph After Integration
|
||||||
|
|
||||||
|
```
|
||||||
|
warzone-identity (shared micro-crate, optional step 5)
|
||||||
|
↑ ↑
|
||||||
|
warzone-protocol wzp-crypto
|
||||||
|
↑ ↑
|
||||||
|
warzone-server wzp-proto ← wzp-codec, wzp-fec, wzp-transport
|
||||||
|
↑ ↑
|
||||||
|
warzone-client wzp-client, wzp-relay, wzp-web
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user