# ๐ช Mudra - Currency Converter
A robust, high-performance currency converter built in Rust with real-time and historical exchange rates, intelligent caching, and a beautiful CLI interface.
[](https://github.com/AshishBagdane/mudra)
[](https://opensource.org/licenses/MIT)
[](https://www.rust-lang.org)
> **Mudra** (เคฎเฅเคฆเฅเคฐเคพ) - Sanskrit/Hindi word meaning "currency" or "money"
## โจ Features
- ๐ **Real-time exchange rates** from multiple currency providers
- ๐ **Historical data support** with date-specific conversions
- โก **High-performance caching** with configurable TTL
- ๐ฏ **Type-safe currency handling** with compile-time validation
- ๐ฅ๏ธ **Beautiful CLI interface** with colored output and progress indicators
- ๐ฑ **Interactive mode** for continuous currency conversions
- ๐ **Batch processing** for multiple conversions
- ๐งช **Comprehensive error handling** with detailed messages
- ๐ **Performance monitoring** with cache statistics
- ๐ก๏ธ **Production-ready** with extensive testing
## ๐ Quick Start
### Installation
```bash
# Install from crates.io
cargo install mudra-cli
# Or build from source
git clone https://github.com/AshishBagdane/mudra.git
cd mudra
cargo build --release
# Or download pre-built binaries from GitHub releases
# https://github.com/AshishBagdane/mudra/releases
```
> **Note**: The package name is `mudra-cli` but the binary is called `mudra`
### Get an API Key
1. Sign up for a **free account** at [exchangerate-api.com](https://exchangerate-api.com)
2. Get your API key from the dashboard (free tier: 1,500 requests/month)
3. Set your environment variable:
```bash
export EXCHANGE_API_KEY=your_api_key_here
```
### Basic Usage
```bash
# Convert 100 USD to EUR
mudra convert 100 USD EUR
# Output: 100.00 USD = 85.23 EUR
# Get current exchange rates for USD
mudra rates USD
# Historical conversion
mudra convert 100 USD EUR --date 2024-01-01
# Interactive mode
mudra interactive
# Compare across multiple currencies
mudra compare 100 USD EUR,GBP,JPY,CAD
```
## ๐ Documentation
### CLI Commands
#### Convert Currency
```bash
# Basic conversion
mudra convert <amount> <from> <to>
# With custom precision
mudra convert 100 USD EUR --precision 4
# Historical conversion
mudra convert 100 USD EUR --date 2024-01-01
# Verbose output
mudra convert 100 USD EUR --verbose
```
#### List Currencies
```bash
# Compact list
mudra list
# Extended format
mudra list --extended
# Filter currencies
mudra list --filter EUR
```
#### Exchange Rates
```bash
# All rates for USD
mudra rates USD
# Specific currencies only
mudra rates USD --currencies EUR,GBP,JPY
# Historical rates
mudra rates USD --date 2024-01-01
# Limited results
mudra rates USD --limit 10
```
#### Compare Currencies
```bash
# Compare across multiple currencies
mudra compare 100 USD EUR,GBP,JPY,CAD,AUD
# Historical comparison
mudra compare 100 USD EUR,GBP --date 2024-01-01
```
#### Cache Management
```bash
# View cache statistics
mudra cache stats
# Clear all cached data
mudra cache clear
# Clean up expired entries
mudra cache cleanup
```
#### Interactive Mode
```bash
mudra interactive
# Then use commands like:
# > 100 USD EUR
# > convert 50 GBP JPY
# > rates USD
# > list
# > help
# > quit
```
## ๐๏ธ Library Usage
### Basic Example
```rust
use currency_converter::{CurrencyConverter, ConversionRequest};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create converter (requires EXCHANGE_API_KEY environment variable)
let converter = CurrencyConverter::from_env()?;
// Convert 100 USD to EUR
let request = ConversionRequest::from_components(100.0, "USD", "EUR")?;
let result = converter.convert(request).await?;
println!("Conversion: {}", result.summary());
println!("Rate: {:.6}", result.exchange_rate);
println!("Result: {}", result.result);
Ok(())
}
```
### Advanced Example with Caching
```rust
use currency_converter::{
CurrencyConverter, ExchangeRateService, CurrencyClient,
Config, CacheConfig, ConversionRequest
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Custom configuration
let config = Config::new()
.with_api_key("your-api-key")
.with_timeout(std::time::Duration::from_secs(10));
// Custom cache configuration
let cache_config = CacheConfig {
max_capacity: 500,
latest_ttl: 600, // 10 minutes
historical_ttl: 7200, // 2 hours
enable_stats: true,
};
// Create client and service
let client = CurrencyClient::with_config(config)?;
let service = ExchangeRateService::with_cache_config(client, cache_config);
let converter = CurrencyConverter::new(service);
// Batch conversion
let requests = vec![
ConversionRequest::from_components(100.0, "USD", "EUR")?,
ConversionRequest::from_components(100.0, "USD", "GBP")?,
ConversionRequest::from_components(100.0, "USD", "JPY")?,
];
let results = converter.convert_batch(requests).await;
for (i, result) in results.iter().enumerate() {
match result {
Ok(conversion) => println!("Conversion {}: {}", i + 1, conversion.summary()),
Err(e) => println!("Error {}: {}", i + 1, e),
}
}
// Check cache performance
let stats = converter.exchange_service.get_cache_stats();
println!("Cache hit rate: {:.1}%", stats.hit_rate);
Ok(())
}
```
### Historical Data Example
```rust
use currency_converter::{ExchangeRateService, api::types::HistoricalConversionRequest};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let service = ExchangeRateService::from_env()?;
// Historical conversion
let request = HistoricalConversionRequest {
amount: 100.0,
from: "USD".to_string(),
to: "EUR".to_string(),
date: "2024-01-01".to_string(),
};
let result = service.convert_historical(request).await?;
println!("Historical rate on 2024-01-01: {:.6}", result.conversion_rate);
// Get historical rates
let rates = service.get_historical_rates("USD", "2024-01-01").await?;
println!("USD rates on {}: {:?}", rates.get_date_string(), rates.conversion_rates);
Ok(())
}
```
## ๐๏ธ Architecture
### Core Components
```
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ CLI โ โ Library โ โ API Client โ
โ (clap-based) โโโโโถโ (type-safe) โโโโโถโ (HTTP client) โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ โ
โผ โผ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ Cache โ โ External API โ
โ (in-memory) โ โ (exchangerate- โ
โโโโโโโโโโโโโโโโโโโ โ api.com) โ
โโโโโโโโโโโโโโโโโโโ
```
### Key Design Principles
1. **Type Safety**: All currency codes and amounts are validated at compile time
2. **Error Handling**: Comprehensive error types with context
3. **Performance**: Intelligent caching with configurable TTL
4. **Modularity**: Clean separation between CLI, library, and API layers
5. **Testability**: Extensive unit and integration tests with mocking
### Conversion Algorithm
1. **Same Currency**: Return input amount (no API call)
2. **Direct Conversion**: Use base currency rates directly
3. **Cross Conversion**: Convert via USD as intermediate currency
```rust
// Example: GBP โ JPY via USD
// Step 1: Get USD rates (contains both GBP and JPY)
// Step 2: Calculate cross rate: JPY_rate / GBP_rate
// Step 3: Apply rate to amount
```
## ๐งช Testing
### Run All Tests
```bash
# Unit tests
cargo test
# Integration tests (requires wiremock)
cargo test --test integration_tests
# With coverage (requires cargo-tarpaulin)
cargo tarpaulin --out html
```
### Property-Based Testing
The project includes property-based tests using `proptest`:
```bash
# Run property tests
cargo test property_tests
```
### Performance Benchmarks
```bash
# Run benchmarks (requires API key for realistic results)
EXCHANGE_API_KEY=your_key cargo run --bin benchmarks
# Memory usage analysis
## ๐ Performance
### Benchmarks
Typical performance on modern hardware:
- **Type creation**: ~10ns per Currency/Money instance
- **Cache hit**: ~1-5ms for cached conversions
- **Cache miss**: ~100-500ms (network dependent)
- **Batch conversion**: ~50-200ms for 10 currencies
- **Memory usage**: ~50KB baseline, ~1KB per cached entry
### Cache Effectiveness
- **Hit rate**: 85-95% in typical usage
- **TTL**: 5 minutes for latest rates, 1 hour for historical
- **Capacity**: 1000 entries (configurable)
- **Eviction**: LRU (Least Recently Used)
## ๐ ๏ธ Development
### Prerequisites
- Rust 1.70+
- API key from [exchangerate-api.com](https://exchangerate-api.com)
### Build from Source
```bash
git clone https://github.com/AshishBagdane/mudra.git
cd mudra
cargo build
```
### Development Commands
```bash
# Check code
cargo check
# Format code
cargo fmt
# Lint code
cargo clippy
# Run tests
cargo test
# Build release
cargo build --release
# Run mudra
./target/release/mudra --help
# Build documentation
cargo doc --open
```
### Contributing
1. Fork the repository
2. Create a feature branch: `git checkout -b feature-name`
3. Make your changes and add tests
4. Ensure all tests pass: `cargo test`
5. Format code: `cargo fmt`
6. Submit a pull request
## ๐ Supported Currencies
The converter supports 168+ currencies including:
- **Major**: USD, EUR, GBP, JPY, CHF, CAD, AUD
- **Asian**: CNY, KRW, INR, SGD, HKD, THB, MYR
- **European**: SEK, NOK, DKK, PLN, CZK, HUF
- **Americas**: BRL, MXN, ARS, CLP, COP, PEN
- **Others**: ZAR, RUB, TRY, ILS, SAR, AED
Use `currency_converter list` to see all supported currencies.
## โ๏ธ Configuration
### Environment Variables
- `EXCHANGE_API_KEY`: Your API key (required)
- `EXCHANGE_BASE_URL`: Custom API base URL (optional)
- `NO_COLOR`: Disable colored output (optional)
### Cache Configuration
```rust
CacheConfig {
max_capacity: 1000, // Maximum cached entries
latest_ttl: 300, // Latest rates TTL (seconds)
historical_ttl: 3600, // Historical rates TTL (seconds)
enable_stats: true, // Enable statistics collection
}
```
## ๐ Troubleshooting
### Common Issues
**"API key not found"**
```bash
export EXCHANGE_API_KEY=your_actual_api_key
```
**"Invalid currency code"**
- Use 3-letter ISO codes (USD, EUR, GBP)
- Check `currency_converter list` for supported currencies
**"Network timeout"**
- Check internet connection
- Increase timeout with custom configuration
**"Rate limit exceeded"**
- Free tier: 1,500 requests/month
- Upgrade plan or wait for reset
### Debug Mode
```bash
# Enable verbose logging
RUST_LOG=debug mudra convert 100 USD EUR --verbose
```
## ๐ License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## ๐ Acknowledgments
- [ExchangeRate-API](https://exchangerate-api.com) for providing free exchange rate data
- [Rust community](https://www.rust-lang.org) for excellent libraries and tools
- All contributors who help improve this project
## ๐ Links
- [Documentation](https://docs.rs/mudra-cli)
- [Crates.io](https://crates.io/crates/mudra-cli)
- [GitHub Issues](https://github.com/AshishBagdane/mudra/issues)
- [Changelog](CHANGELOG.md)
---
**Made with โค๏ธ and ๐ฆ Rust**