From 9de26cc46bd093934178898e9ed92d30045ac1d4 Mon Sep 17 00:00:00 2001 From: Arjun <11359226+yourarj@users.noreply.github.com> Date: Sat, 22 Nov 2025 17:36:12 +0000 Subject: [PATCH 01/20] feat(protocol): implemented binary protocol Signed-off-by: Arjun <11359226+yourarj@users.noreply.github.com> - Implemented initial version of binary protocol - checksum functionality not implemented for the sake of simplicity Date: Sat Nov 22 17:36:12 2025 +0000 On branch core_protocol Changes to be committed: new file: .clippy.toml new file: .editorconfig new file: .rustfmt.toml new file: Cargo.toml new file: chat-core/Cargo.toml new file: chat-core/src/lib.rs new file: chat-core/src/protocol.rs new file: developer-tools/git/hooks/commit-msg new file: developer-tools/git/hooks/pre-commit new file: developer-tools/git/template/.gitmessage new file: rust-toolchain.toml --- .clippy.toml | 4 + .editorconfig | 11 +++ .rustfmt.toml | 14 ++++ Cargo.toml | 28 +++++++ chat-core/Cargo.toml | 14 ++++ chat-core/src/lib.rs | 1 + chat-core/src/protocol.rs | 93 ++++++++++++++++++++++++ developer-tools/git/hooks/commit-msg | 47 ++++++++++++ developer-tools/git/hooks/pre-commit | 84 +++++++++++++++++++++ developer-tools/git/template/.gitmessage | 41 +++++++++++ rust-toolchain.toml | 4 + 11 files changed, 341 insertions(+) create mode 100644 .clippy.toml create mode 100644 .editorconfig create mode 100644 .rustfmt.toml create mode 100644 Cargo.toml create mode 100644 chat-core/Cargo.toml create mode 100644 chat-core/src/lib.rs create mode 100644 chat-core/src/protocol.rs create mode 100644 developer-tools/git/hooks/commit-msg create mode 100755 developer-tools/git/hooks/pre-commit create mode 100644 developer-tools/git/template/.gitmessage create mode 100644 rust-toolchain.toml diff --git a/.clippy.toml b/.clippy.toml new file mode 100644 index 0000000..0906815 --- /dev/null +++ b/.clippy.toml @@ -0,0 +1,4 @@ +# High-performance Rust clippy configuration +cognitive-complexity-threshold = 25 +type-complexity-threshold = 600 +too-many-arguments-threshold = 10 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a778f02 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# EditorConfig is awesome: https://editorconfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 \ No newline at end of file diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..0b8dd82 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,14 @@ +# High-performance Rust formatting configuration +tab_spaces = 2 +hard_tabs = false + +# Code organization +reorder_imports = true +reorder_modules = true + +# Performance-oriented settings +force_explicit_abi = false + +# Readability +use_field_init_shorthand = true +use_try_shorthand = true diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..be73fea --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,28 @@ +[workspace] +resolver = "3" +members = ["chat-core"] +default-members = ["chat-core"] +exclude = ["developer-tools"] + +[workspace.package] +version = "0.1.0" +edition = "2024" +rust-version = "1.91.1" + +[workspace.dependencies] +tokio = { version = "1.0", features = ["full"] } +bincode = "2" +uuid = { version = "1", features = ["v4"] } +serde = { version = "1" } +dashmap = "5" +thiserror = "2" +tracing = "0.1" +tracing-subscriber = "0.3" +bytes = "1" + +# Testing and benchmarking +criterion = "0.7" +tokio-test = "0.4" + +# Development tools +once_cell = "1.0" diff --git a/chat-core/Cargo.toml b/chat-core/Cargo.toml new file mode 100644 index 0000000..e5fb8ba --- /dev/null +++ b/chat-core/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "chat-core" +version.workspace = true +edition.workspace = true +rust-version.workspace = true + +[dependencies] +dashmap = { workspace = true } +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +bytes = {workspace = true} +thiserror = { workspace = true } +bincode = { workspace = true} +serde = { workspace = true } +tracing = {workspace = true} diff --git a/chat-core/src/lib.rs b/chat-core/src/lib.rs new file mode 100644 index 0000000..1b800ec --- /dev/null +++ b/chat-core/src/lib.rs @@ -0,0 +1 @@ +pub mod protocol; diff --git a/chat-core/src/protocol.rs b/chat-core/src/protocol.rs new file mode 100644 index 0000000..9bce736 --- /dev/null +++ b/chat-core/src/protocol.rs @@ -0,0 +1,93 @@ +// common/src/lib.rs +use bincode::{self, Decode, Encode, config::Configuration}; +use bytes::{Bytes, BytesMut}; + +const BINCODE_STANDADRD_CONFIG: Configuration = bincode::config::standard(); + +/// Chat protocol messages exchanged between client and server +#[derive(Debug, Clone, Encode, Decode)] +pub enum ChatMessage { + Join { username: String }, + Leave { username: String }, + Message { username: String, content: String }, + Error { reason: String }, + Success { message: String }, +} + +impl ChatMessage { + /// Serialize message to bytes for network transmission + pub fn to_bytes(&self) -> Result { + let encoded = bincode::encode_to_vec(self, BINCODE_STANDADRD_CONFIG)?; + Ok(Bytes::from(encoded)) + } + + /// Deserialize message from bytes + pub fn from_bytes(bytes: &[u8]) -> Result { + bincode::decode_from_slice(bytes, BINCODE_STANDADRD_CONFIG).map(|(body, _)| body) + } + + /// Get username from message if present + pub fn username(&self) -> Option<&str> { + match self { + ChatMessage::Join { username } => Some(username), + ChatMessage::Leave { username } => Some(username), + ChatMessage::Message { username, .. } => Some(username), + _ => None, + } + } +} + +/// Frame size for message length prefix +pub const LENGTH_PREFIX: usize = 4; + +/// Encode a message with length prefix for framing +pub fn encode_message(message: &ChatMessage) -> Result { + let payload = message.to_bytes()?; + let mut frame = BytesMut::with_capacity(LENGTH_PREFIX + payload.len()); + frame.extend_from_slice(&(payload.len() as u32).to_be_bytes()); + frame.extend_from_slice(&payload); + Ok(frame.freeze()) +} + +/// Decode a message from framed bytes +pub fn decode_message(buf: &[u8]) -> Result { + ChatMessage::from_bytes(buf) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_message_serialization() { + let msg = ChatMessage::Message { + username: "test".to_string(), + content: "hello".to_string(), + }; + + let bytes = msg.to_bytes().unwrap(); + let decoded = ChatMessage::from_bytes(&bytes).unwrap(); + + match decoded { + ChatMessage::Message { username, content } => { + assert_eq!(username, "test"); + assert_eq!(content, "hello"); + } + _ => panic!("Unexpected message type"), + } + } + + #[test] + fn test_framing() { + let msg = ChatMessage::Join { + username: "user".to_string(), + }; + + let frame = encode_message(&msg).unwrap(); + assert!(frame.len() > LENGTH_PREFIX); + + // Test decoding without length prefix + let decoded = decode_message(&frame[LENGTH_PREFIX..]).unwrap(); + assert!(matches!(decoded, ChatMessage::Join { .. })); + } +} diff --git a/developer-tools/git/hooks/commit-msg b/developer-tools/git/hooks/commit-msg new file mode 100644 index 0000000..5e1a4ec --- /dev/null +++ b/developer-tools/git/hooks/commit-msg @@ -0,0 +1,47 @@ +#!/bin/sh + +# Conventional Commit message validation hook +# This hook will validate that commit messages follow the conventional commit format + +commit_msg=$(cat "$1") + +# Check if message is empty +if [ -z "$commit_msg" ]; then + echo "❌ Commit message cannot be empty" + exit 1 +fi + +# Extract the first line (header) +commit_header=$(echo "$commit_msg" | head -n1) + +# Check conventional commit format: type(scope): description +if ! echo "$commit_header" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)\([a-z0-9\-]+\): [a-z].*'; then + echo "❌ Commit message must follow conventional commit format:" + echo " (): " + echo "" + echo " Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert" + echo " Example: feat(auth): add login functionality" + echo "" + echo " Current message: $commit_header" + exit 1 +fi + +# Check subject length (should be <= 50 characters) +subject_length=$(echo "$commit_header" | wc -c) +if [ "$subject_length" -gt 51 ]; then + echo "❌ Subject line must be 50 characters or less" + echo " Current length: $((subject_length - 1)) characters" + echo " Current message: $commit_header" + exit 1 +fi + +# Check for proper capitalization (should start with lowercase) +first_char=$(echo "$commit_header" | cut -c1) +if [[ "$first_char" =~ [A-Z] ]]; then + echo "❌ Subject line should start with lowercase letter" + echo " Current message: $commit_header" + exit 1 +fi + +echo "✅ Commit message format is valid" +exit 0 diff --git a/developer-tools/git/hooks/pre-commit b/developer-tools/git/hooks/pre-commit new file mode 100755 index 0000000..0b18179 --- /dev/null +++ b/developer-tools/git/hooks/pre-commit @@ -0,0 +1,84 @@ +#!/bin/bash + +set -e + +echo "🔍 Running pre-commit checks ..." + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Function to print colored output +print_status() { + echo -e "${GREEN}✓${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}⚠${NC} $1" +} + +print_error() { + echo -e "${RED}✗${NC} $1" +} + +# Check if rust is installed +if ! command -v cargo &> /dev/null; then + print_error "Cargo/Rust not found. Please install Rust: https://rustup.rs/" + exit 1 +fi + +# Get list of staged Rust files +RUST_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.rs$' || true) + +if [ -z "$RUST_FILES" ]; then + print_warning "No Rust files staged for commit" + exit 0 +fi + +echo "📁 Staged Rust files:" +echo "$RUST_FILES" | sed 's/^/ /' + +# Check formatting +echo "" +echo "🔤 Checking code formatting..." +if ! cargo fmt --all -- --check; then + print_error "Code formatting issues found. Run 'cargo fmt --all' to fix them." + echo "" + echo "💡 To automatically format your code:" + echo " cargo fmt --all" + exit 1 +fi +print_status "Code formatting is correct" + +# Check for compilation errors +echo "" +echo "🔨 Checking compilation..." +if ! cargo check --all --all-features; then + print_error "Compilation failed. Please fix compilation errors." + exit 1 +fi +print_status "Code compiles successfully" + +# Run clippy for linting +echo "" +echo "🔍 Running clippy linter..." +if ! cargo clippy --all --all-features -- -D warnings; then + print_error "Clippy found issues. Please fix them or use 'allow' if appropriate." + echo "" + echo "💡 To see clippy suggestions:" + echo " cargo clippy --all --all-features" + exit 1 +fi +print_status "No clippy issues found" + +# Run basic tests on changed files +echo "" +echo "🧪 Running tests..." +if ! cargo test --all --all-features; then + print_error "Tests failed. Please fix failing tests." + exit 1 +fi +print_status "All tests pass" +exit 0 diff --git a/developer-tools/git/template/.gitmessage b/developer-tools/git/template/.gitmessage new file mode 100644 index 0000000..ae5de6d --- /dev/null +++ b/developer-tools/git/template/.gitmessage @@ -0,0 +1,41 @@ +# (): +# +# +# +#