1use crate::types::{Event, Function};
11use dashmap::DashMap;
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14use std::sync::Arc;
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct EventField {
22 pub name: String,
23 #[serde(default)]
24 pub description: String,
25}
26
27#[derive(Debug, Clone)]
29pub struct MetadataSource {
30 pub extension: String,
31 pub functions_url: Option<String>,
32 pub enums_url: Option<String>,
33 pub events_url: Option<String>,
34}
35
36impl MetadataSource {
37 pub fn new(extension: impl Into<String>) -> Self {
39 Self {
40 extension: extension.into(),
41 functions_url: None,
42 enums_url: None,
43 events_url: None,
44 }
45 }
46
47 pub fn with_functions(mut self, url: impl Into<String>) -> Self {
49 self.functions_url = Some(url.into());
50 self
51 }
52
53 pub fn with_enums(mut self, url: impl Into<String>) -> Self {
55 self.enums_url = Some(url.into());
56 self
57 }
58
59 pub fn with_events(mut self, url: impl Into<String>) -> Self {
61 self.events_url = Some(url.into());
62 self
63 }
64}
65
66#[derive(Debug, Clone)]
71pub enum MetadataError {
72 NetworkError(String),
73 ParseError(String),
74 NotFound(String),
75 InvalidData(String),
76 CacheError(String),
77}
78
79impl std::fmt::Display for MetadataError {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 match self {
82 Self::NetworkError(e) => write!(f, "Network error: {}", e),
83 Self::ParseError(e) => write!(f, "Parse error: {}", e),
84 Self::NotFound(e) => write!(f, "Not found: {}", e),
85 Self::InvalidData(e) => write!(f, "Invalid data: {}", e),
86 Self::CacheError(e) => write!(f, "Cache error: {}", e),
87 }
88 }
89}
90
91impl std::error::Error for MetadataError {}
92
93pub type Result<T> = std::result::Result<T, MetadataError>;
94
95#[derive(Default)]
100struct TrieNode {
101 children: HashMap<char, Box<TrieNode>>,
102 value: Option<Arc<Function>>,
103}
104
105#[derive(Default)]
107pub struct FunctionTrie {
108 root: TrieNode,
109 count: usize,
110}
111
112impl FunctionTrie {
113 #[inline]
115 pub fn new() -> Self {
116 Self::default()
117 }
118
119 pub fn insert(&mut self, key: &str, func: Arc<Function>) {
121 let mut node = &mut self.root;
122
123 for ch in key.to_lowercase().chars() {
125 node = node
126 .children
127 .entry(ch)
128 .or_insert_with(|| Box::new(TrieNode::default()));
129 }
130
131 if node.value.is_none() {
132 self.count += 1;
133 }
134 node.value = Some(func);
135 }
136
137 pub fn get_exact(&self, key: &str) -> Option<Arc<Function>> {
139 let mut node = &self.root;
140
141 for ch in key.to_lowercase().chars() {
142 match node.children.get(&ch) {
143 Some(next) => node = next,
144 None => return None,
145 }
146 }
147
148 node.value.clone()
149 }
150
151 pub fn get_prefix(&self, text: &str) -> Option<(String, Arc<Function>)> {
162 let mut node = &self.root;
163 let mut last_match: Option<(String, Arc<Function>)> = None;
164 let mut matched = String::with_capacity(text.len());
165
166 for ch in text.to_lowercase().chars() {
167 match node.children.get(&ch) {
168 Some(next) => {
169 matched.push(ch);
170 node = next;
171 if let Some(func) = &node.value {
172 last_match = Some((matched.clone(), func.clone()));
173 }
174 }
175 None => break,
177 }
178 }
179
180 last_match
181 }
182
183 pub fn get_completions(&self, prefix: &str) -> Vec<Arc<Function>> {
185 let mut node = &self.root;
186
187 for ch in prefix.to_lowercase().chars() {
189 match node.children.get(&ch) {
190 Some(next) => node = next,
191 None => return Vec::new(),
192 }
193 }
194
195 let mut results = Vec::new();
197 self.collect_all(node, &mut results);
198 results
199 }
200
201 fn collect_all(&self, node: &TrieNode, results: &mut Vec<Arc<Function>>) {
202 if let Some(func) = &node.value {
203 results.push(func.clone());
204 }
205
206 for child in node.children.values() {
207 self.collect_all(child, results);
208 }
209 }
210
211 pub fn all_functions(&self) -> Vec<Arc<Function>> {
213 let mut results = Vec::with_capacity(self.count);
214 self.collect_all(&self.root, &mut results);
215 results
216 }
217
218 #[inline]
220 pub fn len(&self) -> usize {
221 self.count
222 }
223
224 #[inline]
226 pub fn is_empty(&self) -> bool {
227 self.count == 0
228 }
229
230 pub fn clear(&mut self) {
232 self.root = TrieNode::default();
233 self.count = 0;
234 }
235}
236
237pub struct Fetcher {
243 client: reqwest::Client,
244}
245
246impl Fetcher {
247 pub fn new() -> Self {
249 #[cfg(not(target_arch = "wasm32"))]
250 let client = reqwest::Client::builder()
251 .timeout(std::time::Duration::from_secs(30))
252 .build()
253 .unwrap_or_else(|_| reqwest::Client::new());
254
255 #[cfg(target_arch = "wasm32")]
256 let client = reqwest::Client::builder()
257 .build()
258 .unwrap_or_else(|_| reqwest::Client::new());
259
260 Self { client }
261 }
262
263 pub async fn fetch_json<T: serde::de::DeserializeOwned>(&self, url: &str) -> Result<T> {
265 let response =
267 self.client.get(url).send().await.map_err(|e| {
268 MetadataError::NetworkError(format!("Failed to fetch {}: {}", url, e))
269 })?;
270
271 let status = response.status();
273 if status == reqwest::StatusCode::NOT_FOUND {
274 return Err(MetadataError::NotFound(format!("URL not found: {}", url)));
275 }
276
277 if !status.is_success() {
278 return Err(MetadataError::NetworkError(format!(
279 "HTTP {}: {}",
280 status, url
281 )));
282 }
283
284 let text = response.text().await.map_err(|e| {
286 MetadataError::NetworkError(format!("Failed to read response from {}: {}", url, e))
287 })?;
288
289 serde_json::from_str(&text).map_err(|e| {
290 let preview: String = text.chars().take(200).collect();
292 MetadataError::ParseError(format!(
293 "Failed to parse JSON from {}: {}\nJSON preview: {}…",
294 url, e, preview
295 ))
296 })
297 }
298
299 pub async fn fetch_functions(&self, url: &str, extension: String) -> Result<Vec<Function>> {
302 let response =
303 self.client.get(url).send().await.map_err(|e| {
304 MetadataError::NetworkError(format!("Failed to fetch {}: {}", url, e))
305 })?;
306
307 let status = response.status();
308 if status == reqwest::StatusCode::NOT_FOUND {
309 return Err(MetadataError::NotFound(format!("URL not found: {}", url)));
310 }
311 if !status.is_success() {
312 return Err(MetadataError::NetworkError(format!(
313 "HTTP {}: {}",
314 status, url
315 )));
316 }
317
318 let text = response.text().await.map_err(|e| {
319 MetadataError::NetworkError(format!("Failed to read response from {}: {}", url, e))
320 })?;
321
322 let raw_items: Vec<serde_json::Value> = serde_json::from_str(&text).map_err(|e| {
324 let preview: String = text.chars().take(200).collect();
325 MetadataError::ParseError(format!(
326 "Failed to parse JSON array from {}: {}\nJSON preview: {}…",
327 url, e, preview
328 ))
329 })?;
330
331 let mut functions = Vec::with_capacity(raw_items.len());
332 for (i, raw) in raw_items.into_iter().enumerate() {
333 match serde_json::from_value::<Function>(raw) {
334 Ok(mut func) => {
335 func.extension = Some(extension.clone());
336 func.source_url = Some(url.to_string());
337 functions.push(func);
338 }
339 Err(e) => {
340 eprintln!("[forge-kit] Skipping function #{} from {}: {}", i, url, e);
342 }
343 }
344 }
345
346 Ok(functions)
347 }
348
349 pub async fn fetch_enums(&self, url: &str) -> Result<HashMap<String, Vec<String>>> {
351 self.fetch_json(url).await
352 }
353
354 pub async fn fetch_events(&self, url: &str) -> Result<Vec<Event>> {
356 self.fetch_json(url).await
357 }
358}
359
360impl Default for Fetcher {
361 fn default() -> Self {
362 Self::new()
363 }
364}
365
366pub struct MetadataManager {
372 trie: std::sync::RwLock<FunctionTrie>,
373 enums: DashMap<String, Vec<String>>,
374 events: DashMap<String, Event>,
375 sources: std::sync::RwLock<Vec<MetadataSource>>,
376 fetcher: Fetcher,
377}
378
379impl MetadataManager {
380 pub fn new() -> Self {
382 Self {
383 trie: std::sync::RwLock::new(FunctionTrie::new()),
384 enums: DashMap::new(),
385 events: DashMap::new(),
386 sources: std::sync::RwLock::new(Vec::new()),
387 fetcher: Fetcher::new(),
388 }
389 }
390
391 pub fn add_source(&self, source: MetadataSource) {
393 self.sources.write().unwrap().push(source);
394 }
395
396 pub async fn fetch_all(&self) -> Result<FetchStats> {
398 let sources = self.sources.read().unwrap().clone();
399
400 let mut total_functions = 0;
401 let mut total_enums = 0;
402 let mut total_events = 0;
403 let mut errors = Vec::new();
404
405 for source in sources {
406 if let Some(url) = &source.functions_url {
408 match self
409 .fetcher
410 .fetch_functions(url, source.extension.clone())
411 .await
412 {
413 Ok(functions) => {
414 total_functions += functions.len();
415 self.add_functions(functions);
416 }
417 Err(MetadataError::NotFound(_)) => {
418 }
420 Err(e) => {
421 errors.push(format!("Functions from {}: {}", source.extension, e));
422 }
423 }
424 }
425
426 if let Some(url) = &source.enums_url {
428 match self.fetcher.fetch_enums(url).await {
429 Ok(enums) => {
430 total_enums += enums.len();
431 for (name, values) in enums {
432 self.enums.insert(name, values);
433 }
434 }
435 Err(e) => {
436 if !matches!(e, MetadataError::NotFound(_)) {
437 errors.push(format!("Enums from {}: {}", source.extension, e));
438 }
439 }
440 }
441 }
442
443 if let Some(url) = &source.events_url {
445 match self.fetcher.fetch_events(url).await {
446 Ok(events) => {
447 total_events += events.len();
448 for event in events {
449 self.events.insert(event.name.clone(), event);
450 }
451 }
452 Err(e) => {
453 if !matches!(e, MetadataError::NotFound(_)) {
454 errors.push(format!("Events from {}: {}", source.extension, e));
455 }
456 }
457 }
458 }
459 }
460
461 Ok(FetchStats {
462 functions: total_functions,
463 enums: total_enums,
464 events: total_events,
465 errors,
466 })
467 }
468
469 fn add_functions(&self, functions: Vec<Function>) {
471 let mut trie = self.trie.write().unwrap();
472
473 for func in functions {
474 let arc_func = Arc::new(func.clone());
475
476 trie.insert(&func.name, arc_func.clone());
478
479 if let Some(aliases) = &func.aliases {
481 for alias in aliases {
482 let alias_name = if alias.starts_with('$') {
483 alias.clone()
484 } else {
485 format!("${}", alias)
486 };
487
488 let mut alias_func = (*arc_func).clone();
490 alias_func.name = alias_name.clone();
491 trie.insert(&alias_name, Arc::new(alias_func));
492 }
493 }
494 }
495 }
496
497 #[inline]
499 pub fn get_exact(&self, name: &str) -> Option<Arc<Function>> {
500 self.trie.read().unwrap().get_exact(name)
501 }
502
503 #[inline]
506 pub fn get_prefix(&self, text: &str) -> Option<(String, Arc<Function>)> {
507 self.trie.read().unwrap().get_prefix(text)
508 }
509
510 pub fn get(&self, name: &str) -> Option<Arc<Function>> {
514 let trie = self.trie.read().unwrap();
515
516 if let Some(func) = trie.get_exact(name) {
518 return Some(func);
519 }
520
521 trie.get_prefix(name).map(|(_, func)| func)
523 }
524
525 pub fn get_with_match(&self, name: &str) -> Option<(String, Arc<Function>)> {
527 let trie = self.trie.read().unwrap();
528
529 if let Some(func) = trie.get_exact(name) {
531 return Some((name.to_string(), func));
532 }
533
534 trie.get_prefix(name)
536 }
537
538 pub fn get_many(&self, names: &[&str]) -> Vec<Option<Arc<Function>>> {
540 names.iter().map(|name| self.get(name)).collect()
541 }
542
543 #[inline]
545 pub fn get_completions(&self, prefix: &str) -> Vec<Arc<Function>> {
546 self.trie.read().unwrap().get_completions(prefix)
547 }
548
549 #[inline]
551 pub fn all_functions(&self) -> Vec<Arc<Function>> {
552 self.trie.read().unwrap().all_functions()
553 }
554
555 #[inline]
557 pub fn get_enum(&self, name: &str) -> Option<Vec<String>> {
558 self.enums.get(name).map(|v| v.clone())
559 }
560
561 pub fn all_enums(&self) -> HashMap<String, Vec<String>> {
563 self.enums
564 .iter()
565 .map(|e| (e.key().clone(), e.value().clone()))
566 .collect()
567 }
568
569 #[inline]
571 pub fn get_event(&self, name: &str) -> Option<Event> {
572 self.events.get(name).map(|v| v.clone())
573 }
574
575 pub fn all_events(&self) -> Vec<Event> {
577 self.events.iter().map(|e| e.value().clone()).collect()
578 }
579
580 #[inline]
582 pub fn function_count(&self) -> usize {
583 self.trie.read().unwrap().len()
584 }
585
586 #[inline]
588 pub fn enum_count(&self) -> usize {
589 self.enums.len()
590 }
591
592 #[inline]
594 pub fn event_count(&self) -> usize {
595 self.events.len()
596 }
597
598 pub fn clear(&self) {
600 self.trie.write().unwrap().clear();
601 self.enums.clear();
602 self.events.clear();
603 }
604}
605
606impl Default for MetadataManager {
607 fn default() -> Self {
608 Self::new()
609 }
610}
611
612#[derive(Debug, Clone)]
614pub struct FetchStats {
615 pub functions: usize,
616 pub enums: usize,
617 pub events: usize,
618 pub errors: Vec<String>,
619}
620
621impl std::fmt::Display for FetchStats {
622 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
623 write!(
624 f,
625 "Fetched {} functions, {} enums, {} events",
626 self.functions, self.enums, self.events
627 )?;
628
629 if !self.errors.is_empty() {
630 write!(f, " ({} errors)", self.errors.len())?;
631 }
632
633 Ok(())
634 }
635}
636
637#[derive(Debug, Serialize, Deserialize)]
643pub struct MetadataCache {
644 pub functions: Vec<Function>,
645 pub enums: HashMap<String, Vec<String>>,
646 pub events: Vec<Event>,
647 pub version: u32,
648}
649
650impl MetadataCache {
651 const VERSION: u32 = 1;
652
653 pub fn new(
655 functions: Vec<Function>,
656 enums: HashMap<String, Vec<String>>,
657 events: Vec<Event>,
658 ) -> Self {
659 Self {
660 functions,
661 enums,
662 events,
663 version: Self::VERSION,
664 }
665 }
666}
667
668impl MetadataManager {
669 pub fn export_cache(&self) -> MetadataCache {
671 MetadataCache::new(
672 self.all_functions().iter().map(|f| (**f).clone()).collect(),
673 self.all_enums(),
674 self.all_events(),
675 )
676 }
677
678 pub fn import_cache(&self, cache: MetadataCache) -> Result<()> {
680 if cache.version != MetadataCache::VERSION {
681 return Err(MetadataError::CacheError(format!(
682 "Incompatible cache version: expected {}, got {}",
683 MetadataCache::VERSION,
684 cache.version
685 )));
686 }
687
688 self.clear();
690
691 self.add_functions(cache.functions);
693
694 for (name, values) in cache.enums {
696 self.enums.insert(name, values);
697 }
698
699 for event in cache.events {
701 self.events.insert(event.name.clone(), event);
702 }
703
704 Ok(())
705 }
706
707 pub fn cache_to_json(&self) -> Result<String> {
709 let cache = self.export_cache();
710 serde_json::to_string(&cache)
711 .map_err(|e| MetadataError::CacheError(format!("Serialization failed: {}", e)))
712 }
713
714 pub fn cache_from_json(&self, json: &str) -> Result<()> {
716 let cache: MetadataCache = serde_json::from_str(json)
717 .map_err(|e| MetadataError::CacheError(format!("Deserialization failed: {}", e)))?;
718 self.import_cache(cache)
719 }
720}
721
722#[cfg(not(target_arch = "wasm32"))]
727impl MetadataManager {
728 pub fn save_cache_to_file(&self, path: impl AsRef<std::path::Path>) -> Result<()> {
730 use std::io::Write;
731
732 let json = self.cache_to_json()?;
733 let mut file = std::fs::File::create(path)
734 .map_err(|e| MetadataError::CacheError(format!("Failed to create file: {}", e)))?;
735
736 file.write_all(json.as_bytes())
737 .map_err(|e| MetadataError::CacheError(format!("Failed to write file: {}", e)))?;
738
739 Ok(())
740 }
741
742 pub fn load_cache_from_file(&self, path: impl AsRef<std::path::Path>) -> Result<()> {
744 let json = std::fs::read_to_string(path)
745 .map_err(|e| MetadataError::CacheError(format!("Failed to read file: {}", e)))?;
746
747 self.cache_from_json(&json)
748 }
749}
750
751pub fn github_source(extension: impl Into<String>, repo: &str, branch: &str) -> MetadataSource {
757 let base = format!("https://raw.githubusercontent.com/{}/{}/", repo, branch);
758
759 MetadataSource::new(extension)
760 .with_functions(format!("{}functions.json", base))
761 .with_enums(format!("{}enums.json", base))
762 .with_events(format!("{}events.json", base))
763}
764
765pub fn custom_source(extension: impl Into<String>) -> MetadataSource {
767 MetadataSource::new(extension)
768}