use std::collections::HashMap;
use tokio::io::{AsyncBufReadExt, AsyncReadExt};
#[derive(Debug, Clone)]
pub struct AgiRequest {
variables: HashMap<String, String>,
}
impl AgiRequest {
pub async fn parse_from_reader<R: tokio::io::AsyncBufRead + Unpin>(
reader: &mut R,
) -> crate::error::Result<Self> {
let mut variables = HashMap::new();
let mut line = String::new();
loop {
line.clear();
let bytes_read = (&mut *reader).take(8193).read_line(&mut line).await?;
if bytes_read == 0 || line.trim().is_empty() {
break;
}
if line.len() >= 8193 && !line.ends_with('\n') {
return Err(crate::error::AgiError::Io(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"agi prelude line exceeds 8192 bytes",
)));
}
let trimmed = line.trim();
if let Some((key, value)) = trimmed.split_once(':') {
let key = key.trim();
let value = value.trim();
let key = key.strip_prefix("agi_").unwrap_or(key);
variables.insert(key.to_owned(), value.to_owned());
}
}
Ok(Self { variables })
}
pub fn network(&self) -> Option<&str> {
self.variables.get("network").map(String::as_str)
}
pub fn network_script(&self) -> Option<&str> {
self.variables.get("network_script").map(String::as_str)
}
pub fn request(&self) -> Option<&str> {
self.variables.get("request").map(String::as_str)
}
pub fn channel(&self) -> Option<&str> {
self.variables.get("channel").map(String::as_str)
}
pub fn language(&self) -> Option<&str> {
self.variables.get("language").map(String::as_str)
}
pub fn channel_type(&self) -> Option<&str> {
self.variables.get("type").map(String::as_str)
}
pub fn unique_id(&self) -> Option<&str> {
self.variables.get("uniqueid").map(String::as_str)
}
pub fn caller_id(&self) -> Option<&str> {
self.variables.get("callerid").map(String::as_str)
}
pub fn caller_id_name(&self) -> Option<&str> {
self.variables.get("calleridname").map(String::as_str)
}
pub fn context(&self) -> Option<&str> {
self.variables.get("context").map(String::as_str)
}
pub fn extension(&self) -> Option<&str> {
self.variables.get("extension").map(String::as_str)
}
pub fn priority(&self) -> Option<&str> {
self.variables.get("priority").map(String::as_str)
}
pub fn get(&self, key: &str) -> Option<&str> {
self.variables.get(key).map(String::as_str)
}
}