@akin01/mailgen 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +260 -0
- package/bin/mailgen.js +20 -0
- package/package.json +39 -0
- package/scripts/benchmark.sh +153 -0
- package/scripts/generate.sh +36 -0
- package/scripts/install.js +103 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Akin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# mailgen
|
|
2
|
+
|
|
3
|
+
High-performance email generator using Markov chains and Bloom filters.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/akin01/emailgen/actions)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🚀 **High Performance** - Generate 250K+ emails per second (Fast Mode)
|
|
11
|
+
- 🎯 **Realistic Names** - Markov chain-based name generation
|
|
12
|
+
- ✅ **Uniqueness Guaranteed** - Bloom filter for efficient duplicate detection
|
|
13
|
+
- 📝 **Custom Wordlists** - Support for custom name and domain lists
|
|
14
|
+
- 🔧 **Configurable** - Multiple email patterns and generation options
|
|
15
|
+
- 💾 **Memory Efficient** - ~1.2 MB for 1 million unique emails
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
### Binary Installation (Recommended)
|
|
20
|
+
|
|
21
|
+
Quickly install the latest binary for your system (Linux, macOS, or Windows):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Linux/macOS (using install script)
|
|
25
|
+
curl -fsSL https://raw.githubusercontent.com/akin01/emailgen/main/install.sh | sudo bash
|
|
26
|
+
|
|
27
|
+
# Windows PowerShell (one-liner, no file download needed)
|
|
28
|
+
powershell -ExecutionPolicy Bypass -Command "iwr -useb https://raw.githubusercontent.com/akin01/emailgen/main/install.ps1 | iex"
|
|
29
|
+
|
|
30
|
+
# Alternative PowerShell syntax
|
|
31
|
+
Invoke-WebRequest -Uri https://raw.githubusercontent.com/akin01/emailgen/main/install.ps1 -UseBasicParsing | Invoke-Expression
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Build from Source
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
### Generate Emails
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Generate 1000 emails to stdout
|
|
42
|
+
./target/release/mailgen --count 1000
|
|
43
|
+
|
|
44
|
+
# Generate 1 million emails to file (Fast Mode)
|
|
45
|
+
./target/release/mailgen --count 1000000 --output emails.txt --fast
|
|
46
|
+
|
|
47
|
+
# Use custom wordlists
|
|
48
|
+
./target/release/mailgen --count 10000 \
|
|
49
|
+
--names data/example_names.txt \
|
|
50
|
+
--domains data/example_domains.txt \
|
|
51
|
+
--output emails.txt
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### As a Library
|
|
55
|
+
|
|
56
|
+
Add to your `Cargo.toml`:
|
|
57
|
+
|
|
58
|
+
```toml
|
|
59
|
+
[dependencies]
|
|
60
|
+
emailgen = { git = "https://github.com/akin01/emailgen" }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```rust
|
|
64
|
+
use mailgen::EmailGenerator;
|
|
65
|
+
|
|
66
|
+
fn main() {
|
|
67
|
+
// Basic usage
|
|
68
|
+
let mut generator = EmailGenerator::new();
|
|
69
|
+
let email = generator.generate();
|
|
70
|
+
println!("Generated: {}", email);
|
|
71
|
+
|
|
72
|
+
// Generate many emails
|
|
73
|
+
let emails = generator.generate_many(1000);
|
|
74
|
+
|
|
75
|
+
// With custom wordlists
|
|
76
|
+
let names = vec!["John Doe".to_string(), "Jane Smith".to_string()];
|
|
77
|
+
let domains = vec!["example.com".to_string()];
|
|
78
|
+
let mut generator = EmailGenerator::with_names_and_domains(names, domains);
|
|
79
|
+
let emails = generator.generate_many(10000);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Performance
|
|
84
|
+
|
|
85
|
+
### Generation Speed (Actual Benchmarks)
|
|
86
|
+
|
|
87
|
+
| Mode | 10K | 100K | 1M |
|
|
88
|
+
|------|-----|------|-----|
|
|
89
|
+
| **Fast Mode** (`--fast`) | 0.04s | 0.38s | 7.5s |
|
|
90
|
+
| **Default Mode** | 3.9s | 39s | ~6.5 min |
|
|
91
|
+
|
|
92
|
+
**💡 Tip:** Use `--fast` mode for bulk generation (>10K emails) for best performance.
|
|
93
|
+
|
|
94
|
+
### Memory Usage
|
|
95
|
+
|
|
96
|
+
- **~1.2 MB** for 1 million unique emails (Bloom filter)
|
|
97
|
+
|
|
98
|
+
### Usage
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Fast mode for bulk generation (~250K emails/sec)
|
|
102
|
+
./target/release/mailgen --count 1000000 --output emails.txt --fast
|
|
103
|
+
|
|
104
|
+
# Default mode with 30% Markov for variety (~2.6K emails/sec)
|
|
105
|
+
./target/release/mailgen --count 100000 --output emails.txt
|
|
106
|
+
|
|
107
|
+
# Generate to stdout
|
|
108
|
+
./target/release/mailgen --count 1000 --fast
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
See [PERFORMANCE.md](PERFORMANCE.md) for detailed benchmarks.
|
|
112
|
+
|
|
113
|
+
## Usage
|
|
114
|
+
|
|
115
|
+
### Direct Command Line
|
|
116
|
+
|
|
117
|
+
After installing via the script, `uv`, or `npm`, the `mailgen` command is available directly in your terminal:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# Basic usage
|
|
121
|
+
mailgen --count 1000
|
|
122
|
+
|
|
123
|
+
# Fast mode
|
|
124
|
+
mailgen -c 1000000 --fast
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Command Line Options
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
USAGE:
|
|
131
|
+
emailgen [OPTIONS]
|
|
132
|
+
|
|
133
|
+
OPTIONS:
|
|
134
|
+
-c, --count <COUNT> Number of emails to generate [default: 1000]
|
|
135
|
+
-o, --output <OUTPUT> Output file path (stdout if not specified)
|
|
136
|
+
-n, --names <NAMES> Path to names wordlist file
|
|
137
|
+
-d, --domains <DOMAINS> Path to domains file
|
|
138
|
+
--min-length <MIN> Minimum username length [default: 5]
|
|
139
|
+
--max-length <MAX> Maximum username length [default: 30]
|
|
140
|
+
--capacity <CAP> Bloom filter capacity [default: 1000000]
|
|
141
|
+
--fpr <FPR> Bloom filter false positive rate [default: 0.01]
|
|
142
|
+
--fast Fast mode (100% wordlist/cached, no Markov)
|
|
143
|
+
--wordlist-percent <PCT> Wordlist name percentage (0-100, default: auto)
|
|
144
|
+
--cache-percent <PCT> Cached name percentage (0-100, default: auto)
|
|
145
|
+
--markov-percent <PCT> Markov generation percentage (0-100, default: 30)
|
|
146
|
+
--stats Show statistics after generation
|
|
147
|
+
-q, --quiet Quiet mode (no output except errors)
|
|
148
|
+
-h, --help Print help
|
|
149
|
+
-V, --version Print version
|
|
150
|
+
|
|
151
|
+
**Features:**
|
|
152
|
+
- **TUI Progress Bar**: Animated text-based progress bar with spinner, percentage, speed, and ETA
|
|
153
|
+
- **Parallel Generation**: Multi-threaded generation (always enabled)
|
|
154
|
+
- **Async I/O**: Asynchronous file writing (always enabled)
|
|
155
|
+
|
|
156
|
+
**Note:** The TUI progress bar animation works best in interactive terminals. When output is redirected, you'll see the final progress state.
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Name Source Ratios
|
|
160
|
+
|
|
161
|
+
Control the balance between speed and variety:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# Specify all three (must add up to 100)
|
|
165
|
+
./target/release/mailgen --count 100000 --wordlist-percent 35 --cache-percent 35 --markov-percent 30
|
|
166
|
+
|
|
167
|
+
# Specify only one - others auto-calculated
|
|
168
|
+
./target/release/mailgen --count 100000 --markov-percent 20
|
|
169
|
+
# Auto-calculates: 40% wordlist, 40% cached, 20% Markov
|
|
170
|
+
|
|
171
|
+
./target/release/mailgen --count 100000 --wordlist-percent 80
|
|
172
|
+
# Auto-calculates: 80% wordlist, 15% cached, 5% Markov
|
|
173
|
+
|
|
174
|
+
./target/release/mailgen --count 100000 --cache-percent 70
|
|
175
|
+
# Auto-calculates: 25% wordlist, 70% cached, 5% Markov
|
|
176
|
+
|
|
177
|
+
# Specify two - third auto-calculated
|
|
178
|
+
./target/release/mailgen --count 100000 --wordlist-percent 50 --markov-percent 10
|
|
179
|
+
# Auto-calculates: 50% wordlist, 40% cached, 10% Markov
|
|
180
|
+
|
|
181
|
+
# Fast mode shortcut (50% wordlist, 50% cached, 0% Markov)
|
|
182
|
+
./target/release/mailgen --count 100000 --fast
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
| Ratio (wordlist/cache/markov) | Speed | Variety | Use Case |
|
|
186
|
+
|-------------------------------|-------|---------|----------|
|
|
187
|
+
| 100/0/0 | ~260K/sec | Low | Bulk test data |
|
|
188
|
+
| 50/50/0 (--fast) | ~260K/sec | Medium | Fast generation |
|
|
189
|
+
| 35/35/30 (default) | ~2.6K/sec | High | General use with variety |
|
|
190
|
+
| 25/25/50 | ~1.5K/sec | Very High | Maximum variety |
|
|
191
|
+
|
|
192
|
+
### Examples
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# Generate 10K emails with stats
|
|
196
|
+
./target/release/mailgen -c 10000 --stats
|
|
197
|
+
|
|
198
|
+
# Generate with custom wordlists
|
|
199
|
+
./target/release/mailgen -c 100000 \
|
|
200
|
+
-n names.txt \
|
|
201
|
+
-d domains.txt \
|
|
202
|
+
-o output.txt
|
|
203
|
+
|
|
204
|
+
# Generate with specific constraints
|
|
205
|
+
./target/release/mailgen -c 50000 \
|
|
206
|
+
--min-length 6 \
|
|
207
|
+
--max-length 20 \
|
|
208
|
+
--capacity 100000 \
|
|
209
|
+
--fpr 0.001
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Architecture
|
|
213
|
+
|
|
214
|
+
### Markov Chain Name Generation
|
|
215
|
+
|
|
216
|
+
The email generator uses character-level Markov chains to generate realistic names:
|
|
217
|
+
|
|
218
|
+
1. **Training**: Names from wordlist are converted to character sequences
|
|
219
|
+
2. **Generation**: New names are generated by walking the Markov chain
|
|
220
|
+
3. **Patterns**: Multiple email patterns create variety (first.last, firstlast, etc.)
|
|
221
|
+
|
|
222
|
+
### Bloom Filter Uniqueness
|
|
223
|
+
|
|
224
|
+
Bloom filters provide space-efficient uniqueness checking:
|
|
225
|
+
|
|
226
|
+
- **Space Efficient**: ~1.14 MB for 1M elements at 1% false positive rate
|
|
227
|
+
- **Fast Operations**: O(k) where k is number of hash functions
|
|
228
|
+
- **No False Negatives**: If it says "not seen", it's definitely unique
|
|
229
|
+
- **Configurable FPR**: Trade memory for accuracy
|
|
230
|
+
|
|
231
|
+
## Wordlist Format
|
|
232
|
+
|
|
233
|
+
### Names File
|
|
234
|
+
|
|
235
|
+
One name per line (first + last):
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
John Smith
|
|
239
|
+
Jane Doe
|
|
240
|
+
Bob Johnson
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Domains File
|
|
244
|
+
|
|
245
|
+
One domain per line:
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
gmail.com
|
|
249
|
+
yahoo.com
|
|
250
|
+
example.com
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## License
|
|
254
|
+
|
|
255
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
256
|
+
|
|
257
|
+
## Acknowledgments
|
|
258
|
+
|
|
259
|
+
- [markovify-rs](https://crates.io/crates/markovify-rs) - Markov chain implementation
|
|
260
|
+
- [bloomfilter](https://crates.io/crates/bloomfilter) - Bloom filter implementation
|
package/bin/mailgen.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const { spawnSync } = require('child_process');
|
|
7
|
+
|
|
8
|
+
const binName = os.platform() === 'win32' ? 'emailgen.exe' : 'emailgen';
|
|
9
|
+
const binPath = path.join(__dirname, binName);
|
|
10
|
+
|
|
11
|
+
if (!fs.existsSync(binPath)) {
|
|
12
|
+
console.error('emailgen binary not found. Please reinstall the package.');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const result = spawnSync(binPath, process.argv.slice(2), {
|
|
17
|
+
stdio: 'inherit'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
process.exit(result.status);
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@akin01/mailgen",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "High-performance email generator using Markov chains and Bloom filters",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mailgen": "bin/mailgen.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
11
|
+
"postinstall": "node scripts/install.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"bin/",
|
|
15
|
+
"scripts/",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/akin01/emailgen.git"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"email",
|
|
25
|
+
"generator",
|
|
26
|
+
"markov",
|
|
27
|
+
"bloom-filter",
|
|
28
|
+
"cli"
|
|
29
|
+
],
|
|
30
|
+
"author": "Akin <akinpasha82@gmail.com>",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/akin01/emailgen/issues"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/akin01/emailgen#readme",
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=12"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Email Generator Benchmark Script
|
|
3
|
+
#
|
|
4
|
+
# This script runs comprehensive benchmarks for the emailgen project,
|
|
5
|
+
# comparing different generation sizes and measuring performance.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# ./scripts/benchmark.sh
|
|
9
|
+
# ./scripts/benchmark.sh --quick # Run quick benchmarks only
|
|
10
|
+
# ./scripts/benchmark.sh --full # Run full benchmarks including 1M generation
|
|
11
|
+
|
|
12
|
+
set -e
|
|
13
|
+
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
16
|
+
cd "$PROJECT_DIR"
|
|
17
|
+
|
|
18
|
+
# Colors for output
|
|
19
|
+
RED='\033[0;31m'
|
|
20
|
+
GREEN='\033[0;32m'
|
|
21
|
+
YELLOW='\033[1;33m'
|
|
22
|
+
BLUE='\033[0;34m'
|
|
23
|
+
NC='\033[0m' # No Color
|
|
24
|
+
|
|
25
|
+
# Default settings
|
|
26
|
+
QUICK_MODE=false
|
|
27
|
+
FULL_MODE=false
|
|
28
|
+
|
|
29
|
+
# Parse arguments
|
|
30
|
+
while [[ $# -gt 0 ]]; do
|
|
31
|
+
case $1 in
|
|
32
|
+
--quick|-q)
|
|
33
|
+
QUICK_MODE=true
|
|
34
|
+
shift
|
|
35
|
+
;;
|
|
36
|
+
--full|-f)
|
|
37
|
+
FULL_MODE=true
|
|
38
|
+
shift
|
|
39
|
+
;;
|
|
40
|
+
--help|-h)
|
|
41
|
+
echo "Usage: $0 [options]"
|
|
42
|
+
echo ""
|
|
43
|
+
echo "Options:"
|
|
44
|
+
echo " --quick, -q Run quick benchmarks only (no 1M generation)"
|
|
45
|
+
echo " --full, -f Run full benchmarks including 1M email generation"
|
|
46
|
+
echo " --help, -h Show this help message"
|
|
47
|
+
exit 0
|
|
48
|
+
;;
|
|
49
|
+
*)
|
|
50
|
+
echo "Unknown option: $1"
|
|
51
|
+
exit 1
|
|
52
|
+
;;
|
|
53
|
+
esac
|
|
54
|
+
done
|
|
55
|
+
|
|
56
|
+
echo -e "${BLUE}============================================${NC}"
|
|
57
|
+
echo -e "${BLUE} Email Generator Performance Benchmarks ${NC}"
|
|
58
|
+
echo -e "${BLUE}============================================${NC}"
|
|
59
|
+
echo ""
|
|
60
|
+
|
|
61
|
+
# Ensure release build exists
|
|
62
|
+
echo -e "${YELLOW}Building release binary...${NC}"
|
|
63
|
+
cargo build --release --quiet 2>/dev/null || cargo build --release
|
|
64
|
+
|
|
65
|
+
echo ""
|
|
66
|
+
echo -e "${YELLOW}Running Criterion benchmarks...${NC}"
|
|
67
|
+
cargo bench --quiet 2>/dev/null || cargo bench
|
|
68
|
+
|
|
69
|
+
echo ""
|
|
70
|
+
echo -e "${BLUE}============================================${NC}"
|
|
71
|
+
echo -e "${BLUE} CLI Generation Benchmarks ${NC}"
|
|
72
|
+
echo -e "${BLUE}============================================${NC}"
|
|
73
|
+
echo ""
|
|
74
|
+
|
|
75
|
+
# Function to run generation benchmark
|
|
76
|
+
run_generation_benchmark() {
|
|
77
|
+
local count=$1
|
|
78
|
+
local label=$2
|
|
79
|
+
|
|
80
|
+
echo -e "${YELLOW}Generating $count emails ($label)...${NC}"
|
|
81
|
+
|
|
82
|
+
local start_time=$(date +%s.%N)
|
|
83
|
+
|
|
84
|
+
# Generate to /dev/null for performance measurement
|
|
85
|
+
cargo run --release --quiet -- --count $count --output /dev/null 2>/dev/null
|
|
86
|
+
|
|
87
|
+
local end_time=$(date +%s.%N)
|
|
88
|
+
local elapsed=$(echo "$end_time - $start_time" | bc)
|
|
89
|
+
local rate=$(echo "scale=0; $count / $elapsed" | bc)
|
|
90
|
+
|
|
91
|
+
echo -e " ${GREEN}✓${NC} Generated $count emails in ${elapsed}s (${rate} emails/sec)"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Quick benchmarks
|
|
95
|
+
echo -e "${BLUE}Quick Benchmarks:${NC}"
|
|
96
|
+
echo "----------------------------------------"
|
|
97
|
+
|
|
98
|
+
run_generation_benchmark 1000 "1K emails"
|
|
99
|
+
run_generation_benchmark 10000 "10K emails"
|
|
100
|
+
run_generation_benchmark 100000 "100K emails"
|
|
101
|
+
|
|
102
|
+
# Full benchmarks
|
|
103
|
+
if [ "$FULL_MODE" = true ] || [ "$QUICK_MODE" = false ]; then
|
|
104
|
+
echo ""
|
|
105
|
+
echo -e "${BLUE}Full Benchmarks:${NC}"
|
|
106
|
+
echo "----------------------------------------"
|
|
107
|
+
|
|
108
|
+
run_generation_benchmark 500000 "500K emails"
|
|
109
|
+
|
|
110
|
+
if [ "$FULL_MODE" = true ]; then
|
|
111
|
+
run_generation_benchmark 1000000 "1M emails"
|
|
112
|
+
fi
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
echo ""
|
|
116
|
+
echo -e "${BLUE}============================================${NC}"
|
|
117
|
+
echo -e "${BLUE} Memory Usage Analysis ${NC}"
|
|
118
|
+
echo -e "${BLUE}============================================${NC}"
|
|
119
|
+
echo ""
|
|
120
|
+
|
|
121
|
+
# Memory usage test
|
|
122
|
+
echo -e "${YELLOW}Testing memory usage for different capacities:${NC}"
|
|
123
|
+
|
|
124
|
+
for capacity in 10000 100000 1000000; do
|
|
125
|
+
echo ""
|
|
126
|
+
echo "Bloom filter capacity: $capacity"
|
|
127
|
+
cargo run --release --quiet -- --count 1000 --capacity $capacity --stats 2>&1 | grep "Memory usage" || true
|
|
128
|
+
done
|
|
129
|
+
|
|
130
|
+
echo ""
|
|
131
|
+
echo -e "${BLUE}============================================${NC}"
|
|
132
|
+
echo -e "${BLUE} Benchmark Summary ${NC}"
|
|
133
|
+
echo -e "${BLUE}============================================${NC}"
|
|
134
|
+
echo ""
|
|
135
|
+
|
|
136
|
+
# Generate summary
|
|
137
|
+
echo "Performance Targets:"
|
|
138
|
+
echo " ✓ 1K emails: < 0.1 seconds"
|
|
139
|
+
echo " ✓ 10K emails: < 1 second"
|
|
140
|
+
echo " ✓ 100K emails: < 10 seconds"
|
|
141
|
+
echo " ✓ 1M emails: < 100 seconds"
|
|
142
|
+
echo ""
|
|
143
|
+
|
|
144
|
+
echo "Memory Efficiency:"
|
|
145
|
+
echo " ✓ Bloom filter uses ~10-15 MB for 1M emails"
|
|
146
|
+
echo " ✓ False positive rate: 1% (configurable)"
|
|
147
|
+
echo ""
|
|
148
|
+
|
|
149
|
+
echo -e "${GREEN}Benchmarks complete!${NC}"
|
|
150
|
+
echo ""
|
|
151
|
+
echo "For detailed results, see:"
|
|
152
|
+
echo " - target/criterion/report/index.html"
|
|
153
|
+
echo ""
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Quick Email Generation Script
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# ./scripts/generate.sh [count] [output_file]
|
|
6
|
+
#
|
|
7
|
+
# Examples:
|
|
8
|
+
# ./scripts/generate.sh # Generate 100 emails to stdout
|
|
9
|
+
# ./scripts/generate.sh 1000 # Generate 1K emails to stdout
|
|
10
|
+
# ./scripts/generate.sh 10000 emails.txt # Generate 10K to file
|
|
11
|
+
|
|
12
|
+
set -e
|
|
13
|
+
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
16
|
+
cd "$PROJECT_DIR"
|
|
17
|
+
|
|
18
|
+
# Default values
|
|
19
|
+
COUNT=${1:-100}
|
|
20
|
+
OUTPUT=${2:-""}
|
|
21
|
+
|
|
22
|
+
# Build if needed
|
|
23
|
+
if [ ! -f "target/release/emailgen" ]; then
|
|
24
|
+
echo "Building emailgen..."
|
|
25
|
+
cargo build --release --quiet
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Generate
|
|
29
|
+
if [ -n "$OUTPUT" ]; then
|
|
30
|
+
echo "Generating $COUNT emails to $OUTPUT..."
|
|
31
|
+
./target/release/emailgen --count $COUNT --output "$OUTPUT" --progress
|
|
32
|
+
echo "Done! Generated $COUNT emails."
|
|
33
|
+
echo "File size: $(ls -lh "$OUTPUT" | awk '{print $5}')"
|
|
34
|
+
else
|
|
35
|
+
./target/release/emailgen --count $COUNT --quiet
|
|
36
|
+
fi
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const https = require('https');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const REPO = "akin01/emailgen";
|
|
8
|
+
const BIN_NAME = os.platform() === 'win32' ? 'emailgen.exe' : 'emailgen';
|
|
9
|
+
const DEST_DIR = path.join(__dirname, '..', 'bin');
|
|
10
|
+
|
|
11
|
+
if (!fs.existsSync(DEST_DIR)) {
|
|
12
|
+
fs.mkdirSync(DEST_DIR, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const getPlatformAsset = () => {
|
|
16
|
+
const platform = os.platform();
|
|
17
|
+
const arch = os.arch();
|
|
18
|
+
|
|
19
|
+
if (platform === 'darwin') {
|
|
20
|
+
if (arch === 'arm64') return `emailgen-macos-aarch64.tar.gz`;
|
|
21
|
+
if (arch === 'x64') return `emailgen-macos-x86_64.tar.gz`;
|
|
22
|
+
}
|
|
23
|
+
if (platform === 'linux') {
|
|
24
|
+
if (arch === 'x64') return `emailgen-linux-x86_64.tar.gz`;
|
|
25
|
+
}
|
|
26
|
+
if (platform === 'win32') {
|
|
27
|
+
if (arch === 'x64') return `emailgen-windows-x86_64.zip`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
throw new Error(`Unsupported platform/architecture: ${platform}/${arch}`);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const download = (url, dest) => {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
const file = fs.createWriteStream(dest);
|
|
36
|
+
https.get(url, (response) => {
|
|
37
|
+
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
38
|
+
download(response.headers.location, dest).then(resolve).catch(reject);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (response.statusCode !== 200) {
|
|
42
|
+
reject(new Error(`Download failed with status code ${response.statusCode}`));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
response.pipe(file);
|
|
46
|
+
file.on('finish', () => {
|
|
47
|
+
file.close(resolve);
|
|
48
|
+
});
|
|
49
|
+
}).on('error', (err) => {
|
|
50
|
+
fs.unlink(dest, () => {});
|
|
51
|
+
reject(err);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const install = async () => {
|
|
57
|
+
try {
|
|
58
|
+
const assetName = getPlatformAsset();
|
|
59
|
+
console.log(`Getting latest release for ${REPO}...`);
|
|
60
|
+
|
|
61
|
+
const apiUrl = `https://api.github.com/repos/${REPO}/releases/latest`;
|
|
62
|
+
const options = {
|
|
63
|
+
headers: { 'User-Agent': 'node.js' }
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const release = await new Promise((resolve, reject) => {
|
|
67
|
+
https.get(apiUrl, options, (res) => {
|
|
68
|
+
let data = '';
|
|
69
|
+
res.on('data', chunk => data += chunk);
|
|
70
|
+
res.on('end', () => resolve(JSON.parse(data)));
|
|
71
|
+
res.on('error', reject);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const tag = release.tag_name;
|
|
76
|
+
const downloadUrl = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
|
|
77
|
+
const tempPath = path.join(os.tmpdir(), assetName);
|
|
78
|
+
|
|
79
|
+
console.log(`Downloading ${assetName} from ${tag}...`);
|
|
80
|
+
await download(downloadUrl, tempPath);
|
|
81
|
+
|
|
82
|
+
console.log(`Extracting to ${DEST_DIR}...`);
|
|
83
|
+
if (assetName.endsWith('.zip')) {
|
|
84
|
+
const extractCmd = `powershell Expand-Archive -Path "${tempPath}" -DestinationPath "${DEST_DIR}" -Force`;
|
|
85
|
+
execSync(extractCmd);
|
|
86
|
+
} else {
|
|
87
|
+
const extractCmd = `tar -xzf "${tempPath}" -C "${DEST_DIR}"`;
|
|
88
|
+
execSync(extractCmd);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (os.platform() !== 'win32') {
|
|
92
|
+
fs.chmodSync(path.join(DEST_DIR, BIN_NAME), 0o755);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log(`Successfully installed emailgen!`);
|
|
96
|
+
fs.unlinkSync(tempPath);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
console.error(`Error during installation: ${err.message}`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
install();
|