kiteconnect_async_wasm/connect/
utils.rs

1//! # Utility Functions
2//! 
3//! This module contains utility functions used throughout the KiteConnect library.
4
5#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
6use serde_json::Value as JsonValue;
7use anyhow::Result;
8use std::collections::HashMap;
9
10
11// WASM platform imports  
12#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
13use web_sys::window;
14
15#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
16use js_sys::Uint8Array;
17
18#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
19use wasm_bindgen_futures::JsFuture;
20
21#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
22use csv_core::{Reader, ReadFieldResult};
23
24#[cfg(not(test))]
25pub const URL: &str = "https://api.kite.trade";
26
27#[cfg(test)]
28pub const URL: &str = "http://127.0.0.1:1234";
29
30/// Async trait for handling HTTP requests across different platforms
31pub trait RequestHandler {
32    fn send_request(
33        &self,
34        url: reqwest::Url,
35        method: &str,
36        data: Option<HashMap<&str, &str>>,
37    ) -> impl std::future::Future<Output = Result<reqwest::Response>> + Send;
38}
39
40/// Parse CSV data using csv-core for WASM compatibility
41#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
42pub fn parse_csv_with_core(csv_data: &str) -> Result<JsonValue> {
43    let mut reader = Reader::new();
44    let mut output = vec![0; 1024];
45    let mut field = Vec::new();
46    let mut input = csv_data.as_bytes();
47    
48    let mut headers: Vec<String> = Vec::new();
49    let mut records: Vec<Vec<String>> = Vec::new();
50    let mut current_record: Vec<String> = Vec::new();
51    let mut is_first_row = true;
52    
53    loop {
54        let (result, input_consumed, output_written) = reader.read_field(input, &mut output);
55        input = &input[input_consumed..];
56        
57        match result {
58            ReadFieldResult::InputEmpty => {
59                if !current_record.is_empty() {
60                    if is_first_row {
61                        headers = current_record.clone();
62                        is_first_row = false;
63                    } else {
64                        records.push(current_record.clone());
65                    }
66                }
67                break;
68            }
69            ReadFieldResult::OutputFull => {
70                field.extend_from_slice(&output[..output_written]);
71                // Continue reading with same input
72            }
73            ReadFieldResult::Field { record_end } => {
74                field.extend_from_slice(&output[..output_written]);
75                let field_str = String::from_utf8_lossy(&field).to_string();
76                current_record.push(field_str);
77                field.clear();
78                
79                if record_end {
80                    if is_first_row {
81                        headers = current_record.clone();
82                        is_first_row = false;
83                    } else {
84                        records.push(current_record.clone());
85                    }
86                    current_record.clear();
87                }
88            }
89            ReadFieldResult::Record => {
90                // This case should not happen based on the API, but we handle it for completeness
91                continue;
92            }
93        }
94    }
95    
96    // Convert to JSON format
97    let mut result: Vec<JsonValue> = Vec::new();
98    for record in records {
99        let mut obj = serde_json::Map::new();
100        for (i, value) in record.iter().enumerate() {
101            if let Some(header) = headers.get(i) {
102                obj.insert(header.clone(), JsonValue::String(value.clone()));
103            }
104        }
105        result.push(JsonValue::Object(obj));
106    }
107    
108    Ok(JsonValue::Array(result))
109}