Skip to content

Commit bbea9b6

Browse files
cursoragentscript3r
andcommitted
Refactor scanner to use producer-consumer architecture
Co-authored-by: script3r <[email protected]>
1 parent 2219720 commit bbea9b6

File tree

2 files changed

+59
-67
lines changed

2 files changed

+59
-67
lines changed

crates/scanner-core/examples/basic_usage.rs

Lines changed: 0 additions & 60 deletions
This file was deleted.

crates/scanner-core/src/lib.rs

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -938,14 +938,68 @@ impl<'a> Scanner<'a> {
938938
// Drain emitter and forward findings to main channel
939939
drop(emitter.tx); // Close the emitter sender to stop receiving
940940
for finding in emitter.rx.iter() {
941-
if let Err(_) = findings_sender.send(finding) {
941+
if findings_sender.send(finding).is_err() {
942942
break; // Main receiver has been dropped, stop sending
943943
}
944944
}
945945

946946
Ok(())
947947
}
948948

949+
/// Simple file discovery for dry-run functionality - doesn't use the full producer-consumer architecture
950+
pub fn discover_files(&self, roots: &[PathBuf]) -> Vec<PathBuf> {
951+
let mut paths = Vec::new();
952+
953+
// Build glob matcher for include patterns
954+
let include_matcher: Option<globset::GlobSet> = if !self.config.include_globs.is_empty() {
955+
let mut builder = globset::GlobSetBuilder::new();
956+
for pattern in &self.config.include_globs {
957+
if let Ok(glob) = globset::Glob::new(pattern) {
958+
builder.add(glob);
959+
}
960+
}
961+
builder.build().ok()
962+
} else {
963+
None
964+
};
965+
966+
for root in roots {
967+
let mut builder = WalkBuilder::new(root);
968+
builder
969+
.hidden(false)
970+
.git_ignore(true)
971+
.git_exclude(true)
972+
.ignore(true);
973+
974+
for entry in builder.build().flatten() {
975+
let md = match entry.metadata() {
976+
Ok(m) => m,
977+
Err(_) => continue,
978+
};
979+
if md.is_file() {
980+
if md.len() as usize > self.config.max_file_size {
981+
continue;
982+
}
983+
984+
let path = entry.into_path();
985+
986+
// Apply include glob filtering
987+
if let Some(ref matcher) = include_matcher {
988+
if !matcher.is_match(&path) {
989+
continue;
990+
}
991+
}
992+
993+
// Only include files with supported languages
994+
if Self::detect_language(&path).is_some() {
995+
paths.push(path);
996+
}
997+
}
998+
}
999+
}
1000+
paths
1001+
}
1002+
9491003
pub fn detect_language(path: &Path) -> Option<Language> {
9501004
match path
9511005
.extension()
@@ -983,10 +1037,10 @@ impl<'a> Scanner<'a> {
9831037
// Create bounded channels for work queue and findings
9841038
const WORK_QUEUE_SIZE: usize = 10_000; // Backpressure management
9851039
const FINDINGS_QUEUE_SIZE: usize = 50_000; // Large buffer for findings
986-
1040+
9871041
let (work_sender, work_receiver) = bounded::<PathBuf>(WORK_QUEUE_SIZE);
9881042
let (findings_sender, findings_receiver) = bounded::<Finding>(FINDINGS_QUEUE_SIZE);
989-
1043+
9901044
// Progress tracking
9911045
let (progress_sender, progress_receiver) = if self.config.progress_callback.is_some() {
9921046
let (tx, rx) = bounded::<usize>(1000);
@@ -1031,7 +1085,7 @@ impl<'a> Scanner<'a> {
10311085
};
10321086

10331087
// Use thread::scope to ensure all threads complete before returning
1034-
let findings = thread::scope(|s| {
1088+
let findings = thread::scope(|s| -> Result<Vec<Finding>> {
10351089
// Spawn producer thread
10361090
let producer_handle = {
10371091
let work_sender = work_sender.clone();
@@ -1063,9 +1117,7 @@ impl<'a> Scanner<'a> {
10631117
}
10641118

10651119
// Wait for producer to complete
1066-
if let Err(e) = producer_handle.join().unwrap() {
1067-
return Err(e);
1068-
}
1120+
producer_handle.join().unwrap()?;
10691121

10701122
// Check consumer result
10711123
consumer_result?;

0 commit comments

Comments
 (0)