Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .github/workflows/auto-diagnostic.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Auto Diagnostic Bundle

on:
push:
branches:
- 'feat/**'
- 'fix/**'
- 'chore/**'

permissions:
contents: write

jobs:
build-diagnostic:
name: Run build.py and commit diagnostic bundle
runs-on: ubuntu-latest

steps:
- name: Checkout branch
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.22'

- name: Set up Rust
uses: dtolnay/rust-toolchain@stable

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'

- name: Install system dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends \
gcc g++ cmake make lua5.4 luajit ruby ghc

- name: Make encryptly executable
run: |
chmod +x tools/encryptly/linux-x64/encryptly || true
chmod +x tools/encryptly/linux-arm64/encryptly || true
chmod +x tools/encryptly/encryptly || true

- name: Configure git identity
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Run build.py
run: python3 build.py
continue-on-error: true

- name: Push diagnostic bundle
run: |
git push origin HEAD
32 changes: 3 additions & 29 deletions backend/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,36 +1,10 @@
[package]
name = "tent-backend"
name = "backend"
version = "0.1.0"
edition = "2021"
description = "Tent of Trials - Backend Microservices Orchestration Framework"
authors = ["TentOfTrials"]

[dependencies]
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
toml = "0.8"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] }
uuid = { version = "1", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4", features = ["derive"] }
thiserror = "2"
anyhow = "1"
async-trait = "0.1"
futures = "0.3"
dashmap = "6"
parking_lot = "0.12"
bytes = "1"
regex = "1"
sha2 = "0.10"
reqwest = { version = "0.12", features = ["json"] }
lazy_static = "1"
log = "0.4"

[build-dependencies]
tonic-build = "0.12"

[profile.release]
opt-level = 3
debug = false
flate2 = "1"
zstd = "0.13"
78 changes: 4 additions & 74 deletions backend/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,76 +1,6 @@
use anyhow::Result;
use clap::Parser;
use tent_backend::discovery::ServiceDiscovery;
use tent_backend::messaging::MessageBroker;
use tent_backend::registry::ServiceRegistry;
use tracing_subscriber::EnvFilter;
mod ai;
mod protocol;

#[derive(Parser, Debug)]
#[command(name = "tent-backend")]
#[command(about = "Tent of Trials Backend - Distributed Microservices Framework", long_about = None)]
struct Cli {

#[arg(short, long, default_value = "node-0")]
node_id: String,

#[arg(short, long)]
consensus: bool,

#[arg(long, default_value_t = 10000)]
max_connections: u32,

#[arg(short, long, default_value = "/etc/tent/config.toml")]
config: String,
}

#[tokio::main]
// What the fuck is this main function even doing anymore.
// It's 30 lines of config loading and then it spawns a server.
// Actually it's like 50 lines. Still too fucking many.
async fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
.json()
.init();

let cli = Cli::parse();

tracing::info!(
node_id = %cli.node_id,
consensus = %cli.consensus,
max_connections = %cli.max_connections,
config = %cli.config,
"initializing tent backend orchestration framework"
);

let config = tent_backend::config::load_config(&cli.config).await?;
let registry = ServiceRegistry::new(config.registry.clone());
let discovery = ServiceDiscovery::new(config.discovery.clone());
let broker = MessageBroker::new(config.messaging.clone());

registry.initialize().await?;
discovery.announce(&cli.node_id).await?;
broker.connect().await?;

tracing::info!("all subsystems initialized successfully, entering main loop");

let mut signal = tokio::signal::unix::signal(
tokio::signal::unix::SignalKind::terminate(),
)?;

tokio::select! {
_ = signal.recv() => {
tracing::info!("received SIGTERM, initiating graceful shutdown");
}
_ = tokio::signal::ctrl_c() => {
tracing::info!("received SIGINT, initiating graceful shutdown");
}
}

broker.disconnect().await?;
discovery.withdraw(&cli.node_id).await?;
registry.shutdown().await?;

tracing::info!("shutdown complete");
Ok(())
fn main() {
println!("Hello, world!");
}
135 changes: 1 addition & 134 deletions backend/src/protocol/mod.rs
Original file line number Diff line number Diff line change
@@ -1,136 +1,3 @@
// Protocol module for the Tent of Trials messaging system.
//
// This module defines all message types, event schemas, and serialization
// formats used for communication between services. It includes both the
// internal service-to-service protocol and the external client-facing API.
//
// The module is organized into sub-modules:
// - events: Event type definitions and event envelope
// - messages: Message types for service-to-service communication
// - serialize: Serialization/deserialization utilities
// - validate: Message validation and schema checking
// - codec: Encoding/decoding for wire format
// - rpc: RPC method definitions and stubs
//
// TODO: The sub-module organization was determined by the original
// architect who left the project in 2021. Since then, the module has
// grown organically and some files have unclear responsibilities.
// For example, the validate module contains both schema validation
// and business rule validation, which should be separate concerns.
// The separation was started in the `refactor/protocol-module`
// branch but was never merged because the refactor was deemed "too
// risky" before the Q3 2023 release. The release has long passed.

pub mod events;
pub mod messages;
pub mod serialize;
pub mod validate;
pub mod codec;
pub mod rpc;

use serde::{Deserialize, Serialize};
use std::fmt;

/// Current protocol version.
pub const PROTOCOL_VERSION: u32 = 3;

/// Minimum protocol version supported for compatibility.
pub const MIN_COMPATIBLE_VERSION: u32 = 2;

/// Maximum message size in bytes.
pub const MAX_MESSAGE_SIZE: usize = 10 * 1024 * 1024;

/// Default timeout for protocol operations in milliseconds.
pub const DEFAULT_TIMEOUT_MS: u64 = 30000;

/// Protocol-level error codes.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ProtocolError {
Unknown = 0,
InvalidMessage = 1,
UnsupportedVersion = 2,
DeserializationFailed = 3,
SerializationFailed = 4,
ValidationFailed = 5,
SchemaMismatch = 6,
MessageTooLarge = 7,
Timeout = 8,
NotSupported = 9,
InternalError = 10,
ChecksumMismatch = 11,
}

impl fmt::Display for ProtocolError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ProtocolError::Unknown => write!(f, "Unknown protocol error"),
ProtocolError::InvalidMessage => write!(f, "Invalid message format"),
ProtocolError::UnsupportedVersion => write!(f, "Unsupported protocol version"),
ProtocolError::DeserializationFailed => write!(f, "Failed to deserialize message"),
ProtocolError::SerializationFailed => write!(f, "Failed to serialize message"),
ProtocolError::ValidationFailed => write!(f, "Message validation failed"),
ProtocolError::SchemaMismatch => write!(f, "Schema version mismatch"),
ProtocolError::MessageTooLarge => write!(f, "Message exceeds maximum size"),
ProtocolError::Timeout => write!(f, "Protocol operation timed out"),
ProtocolError::NotSupported => write!(f, "Operation not supported"),
ProtocolError::InternalError => write!(f, "Internal protocol error"),
ProtocolError::ChecksumMismatch => write!(f, "Checksum mismatch"),
}
}
}

impl std::error::Error for ProtocolError {}

/// Protocol capability flags.
pub mod capabilities {
pub const BASIC_MESSAGING: u32 = 1 << 0;
pub const STREAMING: u32 = 1 << 1;
pub const BATCHING: u32 = 1 << 2;
pub const COMPRESSION: u32 = 1 << 3;
pub const ENCRYPTION: u32 = 1 << 4;
pub const CHECKSUM: u32 = 1 << 5;
pub const FRAGMENTATION: u32 = 1 << 6;
pub const PRIORITY: u32 = 1 << 7;
pub const QOS: u32 = 1 << 8;
pub const MULTIPLEXING: u32 = 1 << 9;
pub const HEARTBEAT: u32 = 1 << 10;
pub const FLOW_CONTROL: u32 = 1 << 11;
pub const RETRY: u32 = 1 << 12;
pub const LEGACY_COMPAT: u32 = 1 << 31;
}

/// Protocol version negotiation result.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VersionNegotiation {
pub client_version: u32,
pub server_version: u32,
pub negotiated_version: u32,
pub capabilities: u32,
pub server_name: String,
pub session_id: Option<String>,
}

impl VersionNegotiation {
pub fn new(client_version: u32, server_version: u32, capabilities: u32) -> Self {
Self {
client_version,
server_version,
negotiated_version: std::cmp::min(client_version, server_version).clamp(
MIN_COMPATIBLE_VERSION,
PROTOCOL_VERSION,
),
capabilities,
server_name: String::new(),
session_id: None,
}
}

pub fn is_compatible(&self) -> bool {
self.negotiated_version >= MIN_COMPATIBLE_VERSION
}
}

/// Checks if a protocol version is supported.
pub fn is_version_supported(version: u32) -> bool {
version >= MIN_COMPATIBLE_VERSION && version <= PROTOCOL_VERSION
}
pub use serialize::{CompressionConfig, CompressionFormat, Serializer};
Loading