mirror of https://github.com/buster-so/buster.git
mdc
This commit is contained in:
parent
2d47c2c539
commit
977b5eb6de
|
@ -2,3 +2,142 @@
|
|||
description: These are global rules and recommendations for the rust server.
|
||||
globs:
|
||||
---
|
||||
|
||||
# Global Rules and Project Structure
|
||||
|
||||
## Project Overview
|
||||
This is a Rust web server project built with Axum, focusing on high performance, safety, and maintainability.
|
||||
|
||||
## Project Structure
|
||||
- `src/`
|
||||
- `routes/`
|
||||
- `rest/` - REST API endpoints using Axum
|
||||
- `routes/` - Individual route modules
|
||||
- `ws/` - WebSocket handlers and related functionality
|
||||
- `database/` - Database models, schema, and connection management
|
||||
- `main.rs` - Application entry point and server setup
|
||||
|
||||
## Database Connectivity
|
||||
- The primary database connection is managed through `get_pg_pool()`, which returns a lazy static `PgPool`
|
||||
- Always use this pool for database connections to ensure proper connection management
|
||||
- Example usage:
|
||||
```rust
|
||||
let mut conn = get_pg_pool().get().await?;
|
||||
```
|
||||
|
||||
## Code Style and Best Practices
|
||||
|
||||
### References and Memory Management
|
||||
- Prefer references over owned values when possible
|
||||
- Avoid unnecessary `.clone()` calls
|
||||
- Use `&str` instead of `String` for function parameters when the string doesn't need to be owned
|
||||
|
||||
### Database Operations
|
||||
- Use Diesel for database migrations and query building
|
||||
- Migrations are stored in the `migrations/` directory
|
||||
- Always use transactions for operations that modify multiple tables:
|
||||
```rust
|
||||
conn.transaction(|conn| {
|
||||
// Your database operations here
|
||||
Ok(())
|
||||
})
|
||||
```
|
||||
|
||||
### Concurrency Guidelines
|
||||
- Prioritize concurrent operations, especially for:
|
||||
- API requests
|
||||
- Database transactions
|
||||
- File operations
|
||||
- Optimize database connection usage:
|
||||
- Batch operations where possible
|
||||
- Build queries/parameters before executing database operations
|
||||
- Use bulk inserts/updates instead of individual operations
|
||||
```rust
|
||||
// Preferred: Bulk operation
|
||||
let items: Vec<_> = prepare_items();
|
||||
diesel::insert_into(table)
|
||||
.values(&items)
|
||||
.execute(conn)?;
|
||||
|
||||
// Avoid: Individual operations in a loop
|
||||
for item in items {
|
||||
diesel::insert_into(table)
|
||||
.values(&item)
|
||||
.execute(conn)?;
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
- Never use `.unwrap()` or `.expect()` in production code
|
||||
- Always handle errors appropriately using:
|
||||
- The `?` operator for error propagation
|
||||
- `match` statements when specific error cases need different handling
|
||||
- Use `anyhow` for error handling:
|
||||
- Prefer `anyhow::Result<T>` as the return type for functions that can fail
|
||||
- Use `anyhow::Error` for error types
|
||||
- Use `anyhow!` macro for creating custom errors
|
||||
```rust
|
||||
use anyhow::{Result, anyhow};
|
||||
|
||||
// Example of proper error handling
|
||||
pub async fn process_data(input: &str) -> Result<Data> {
|
||||
// Use ? for error propagation
|
||||
let parsed = parse_input(input)?;
|
||||
|
||||
// Use match when specific error cases need different handling
|
||||
match validate_data(&parsed) {
|
||||
Ok(valid_data) => Ok(valid_data),
|
||||
Err(e) => Err(anyhow!("Data validation failed: {}", e))
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid this:
|
||||
// let data = parse_input(input).unwrap(); // ❌ Never use unwrap
|
||||
```
|
||||
|
||||
### API Design
|
||||
- REST endpoints should be in `routes/rest/routes/`
|
||||
- WebSocket handlers should be in `routes/ws/`
|
||||
- Use proper HTTP status codes
|
||||
- Implement proper validation for incoming requests
|
||||
|
||||
### Testing
|
||||
- Write unit tests for critical functionality
|
||||
- Use integration tests for API endpoints
|
||||
- Mock external dependencies when appropriate
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Database Queries
|
||||
```rust
|
||||
use diesel::prelude::*;
|
||||
|
||||
// Example of a typical database query
|
||||
pub async fn get_item(id: i32) -> Result<Item> {
|
||||
let pool = get_pg_pool();
|
||||
let conn = pool.get().await?;
|
||||
|
||||
items::table
|
||||
.filter(items::id.eq(id))
|
||||
.first(&conn)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
```
|
||||
|
||||
### Concurrent Operations
|
||||
```rust
|
||||
use futures::future::try_join_all;
|
||||
|
||||
// Example of concurrent processing
|
||||
let futures: Vec<_> = items
|
||||
.into_iter()
|
||||
.map(|item| process_item(item))
|
||||
.collect();
|
||||
let results = try_join_all(futures).await?;
|
||||
```
|
||||
|
||||
Remember to always consider:
|
||||
1. Connection pool limits when designing concurrent operations
|
||||
2. Transaction boundaries for data consistency
|
||||
3. Error propagation and cleanup
|
||||
4. Memory usage and ownership
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
---
|
||||
description: This is helpful for building libs for our web server to interact with.
|
||||
globs: libs/*
|
||||
---
|
||||
|
||||
# Library Construction Guide
|
||||
|
||||
## Directory Structure
|
||||
```
|
||||
libs/
|
||||
├── my_lib/
|
||||
│ ├── Cargo.toml # Library-specific manifest
|
||||
│ ├── src/
|
||||
│ │ ├── lib.rs # Library root
|
||||
│ │ ├── models/ # Data structures and types
|
||||
│ │ ├── utils/ # Utility functions
|
||||
│ │ └── errors.rs # Custom error types
|
||||
│ └── tests/ # Integration tests
|
||||
```
|
||||
|
||||
## Cargo.toml Template
|
||||
```toml
|
||||
[package]
|
||||
name = "my_lib"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
# Inherit workspace dependencies
|
||||
# This ensures consistent versions across the project
|
||||
[dependencies]
|
||||
serde.workspace = true # If defined in workspace
|
||||
tokio.workspace = true # If defined in workspace
|
||||
thiserror.workspace = true # If defined in workspace
|
||||
|
||||
# Library-specific dependencies (not in workspace)
|
||||
some-specific-dep = "1.0"
|
||||
|
||||
# Development dependencies
|
||||
[dev-dependencies]
|
||||
tokio-test.workspace = true # If defined in workspace
|
||||
assert_matches.workspace = true # If defined in workspace
|
||||
|
||||
# Feature flags - can inherit from workspace or be lib-specific
|
||||
[features]
|
||||
default = []
|
||||
async = ["tokio"] # Example of a library-specific feature
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Workspace Integration
|
||||
- Use `.workspace = true` for common fields and dependencies
|
||||
- Only specify library-specific versions for unique dependencies
|
||||
- Inherit common development dependencies from workspace
|
||||
- Keep feature flags modular and specific to the library's needs
|
||||
|
||||
### 2. Library Structure
|
||||
- Keep the library focused on a single responsibility
|
||||
- Use clear module hierarchies
|
||||
- Export public API through `lib.rs`
|
||||
- Follow the workspace's common patterns
|
||||
|
||||
Example `lib.rs`:
|
||||
```rust
|
||||
//! My Library documentation
|
||||
//!
|
||||
//! This library provides...
|
||||
|
||||
// Re-export common workspace types if needed
|
||||
pub use common_types::{Result, Error};
|
||||
|
||||
pub mod models;
|
||||
pub mod utils;
|
||||
mod errors;
|
||||
|
||||
// Re-exports
|
||||
pub use errors::Error;
|
||||
pub use models::{ImportantType, AnotherType};
|
||||
```
|
||||
|
||||
### 3. Error Handling
|
||||
- Use the workspace's common error types where appropriate
|
||||
- Define library-specific errors only when needed
|
||||
- Implement conversions to/from workspace error types
|
||||
|
||||
Example `errors.rs`:
|
||||
```rust
|
||||
use thiserror::Error;
|
||||
use common_types::Error as WorkspaceError;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("library specific error: {0}")]
|
||||
LibrarySpecific(String),
|
||||
|
||||
#[error(transparent)]
|
||||
Workspace(#[from] WorkspaceError),
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Testing
|
||||
- Follow workspace testing conventions
|
||||
- Use shared test utilities from workspace when available
|
||||
- Keep library-specific test helpers in the library
|
||||
- Use workspace-defined test macros if available
|
||||
|
||||
### 5. Documentation
|
||||
- Follow workspace documentation style
|
||||
- Link to related workspace documentation
|
||||
- Document workspace integration points
|
||||
- Include examples showing workspace type usage
|
||||
|
||||
### 6. Integration Points
|
||||
- Define clear boundaries with other workspace crates
|
||||
- Use workspace traits and interfaces
|
||||
- Share common utilities through workspace-level crates
|
||||
- Consider cross-crate testing
|
||||
|
||||
### 7. Development Workflow
|
||||
- Run workspace-level tests when making changes
|
||||
- Update workspace documentation if needed
|
||||
- Follow workspace versioning strategy
|
||||
- Use workspace-level CI/CD pipelines
|
||||
|
||||
### 8. Dependencies
|
||||
- Prefer workspace-level dependencies
|
||||
- Only add library-specific dependencies when necessary
|
||||
- Keep dependencies minimal and focused
|
||||
- Document any deviations from workspace versions
|
Loading…
Reference in New Issue