Menu
Public repository / 201cd99cd1b691e2b367445d3d56f76bf64c998a
AkurAI-Router / src/util.rs
Latest change 2dd2d00c6817eb1b911329d8d967799060dfbd37 - feat(opencode-go): load-balance + failover across multiple keys by Ólafur Búi Ólafsson
use std::fs::File;
use std::io::Read;
use std::time::{SystemTime, UNIX_EPOCH};
pub fn now_secs() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs()
}
pub fn random_hex(bytes: usize) -> String {
let mut buf = vec![0u8; bytes];
if File::open("/dev/urandom")
.and_then(|mut f| f.read_exact(&mut buf))
.is_err()
{
let mut seed = now_secs() ^ (std::process::id() as u64);
for b in &mut buf {
seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1);
*b = (seed >> 32) as u8;
}
}
let mut out = String::with_capacity(bytes * 2);
for b in buf {
out.push_str(&format!("{b:02x}"));
}
out
}
pub fn html_escape(input: &str) -> String {
input
.replace('&', "&")
.replace('<', "<")
.replace('>', ">")
.replace('"', """)
.replace('\'', "'")
}
pub fn percent_encode(input: &str) -> String {
let mut out = String::new();
for b in input.bytes() {
match b {
b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
out.push(b as char)
}
b' ' => out.push_str("%20"),
_ => out.push_str(&format!("%{b:02X}")),
}
}
out
}
pub fn percent_decode(input: &str) -> String {
let bytes = input.as_bytes();
let mut out = Vec::with_capacity(bytes.len());
let mut i = 0;
while i < bytes.len() {
if bytes[i] == b'%'
&& i + 2 < bytes.len()
&& let Ok(v) = u8::from_str_radix(&input[i + 1..i + 3], 16)
{
out.push(v);
i += 3;
continue;
}
if bytes[i] == b'+' {
out.push(b' ');
} else {
out.push(bytes[i]);
}
i += 1;
}
String::from_utf8_lossy(&out).into_owned()
}
pub fn parse_query(query: &str) -> Vec<(String, String)> {
query
.split('&')
.filter(|part| !part.is_empty())
.map(|part| {
let mut pieces = part.splitn(2, '=');
let key = percent_decode(pieces.next().unwrap_or(""));
let value = percent_decode(pieces.next().unwrap_or(""));
(key, value)
})
.collect()
}
pub fn query_get(query: &[(String, String)], key: &str) -> Option<String> {
query
.iter()
.find(|(k, _)| k == key)
.map(|(_, v)| v.to_string())
}
const B64_URL: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
pub fn base64_url_decode(input: &str) -> Option<Vec<u8>> {
let mut bits = 0u32;
let mut bit_count = 0u8;
let mut out = Vec::new();
for ch in input.bytes().filter(|b| *b != b'=') {
let val = B64_URL.iter().position(|b| *b == ch)? as u32;
bits = (bits << 6) | val;
bit_count += 6;
while bit_count >= 8 {
bit_count -= 8;
out.push(((bits >> bit_count) & 0xff) as u8);
}
}
Some(out)
}
pub fn env_quote(value: &str) -> String {
if value
.bytes()
.all(|b| b.is_ascii_alphanumeric() || b"-_./:@,".contains(&b))
{
value.to_string()
} else {
format!("\"{}\"", value.replace('\\', "\\\\").replace('"', "\\\""))
}
}