kiteconnect_async_wasm/connect/
utils.rs

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