use std::io::Cursor;
use isahc::prelude::*;
use rand_core::{impls, Error, RngCore};
const WHITENOISE_URL: &str =
"https://qrng.anu.edu.au/wp-content/plugins/colours-plugin/get_audio_whiteNoise.php";
const PREFIX: &[u8] = b"data:audio/wav;base64,";
pub struct NoiseRand {
buffer: Vec<i16>,
}
impl NoiseRand {
pub fn new() -> Self {
let buffer = vec![];
Self { buffer }
}
fn fill_buffer(&mut self) {
log::trace!("trying to fill the buffer");
let mut response = isahc::get(WHITENOISE_URL).unwrap();
let mut buffer = Cursor::new(vec![]);
let len = response.copy_to(&mut buffer).unwrap();
if len <= PREFIX.len() as u64 {
panic!("didn't get enough data");
}
let buffer = buffer.into_inner();
let bytes = base64::decode(&buffer[PREFIX.len()..]).expect("not base64 encoded");
log::trace!("got a total of {} bytes", bytes.len());
let mut reader = hound::WavReader::new(Cursor::new(bytes)).unwrap();
log::trace!("WAVE file decoded, expect {} samples", reader.len());
self.buffer = reader.samples().flatten().collect();
}
}
impl RngCore for NoiseRand {
fn next_u32(&mut self) -> u32 {
log::trace!(
"4 byte requested, {} samples left in the buffer",
self.buffer.len()
);
if self.buffer.len() < 2 {
self.fill_buffer();
}
(self.buffer.pop().unwrap() as u32) << 16 | self.buffer.pop().unwrap() as u32
}
fn next_u64(&mut self) -> u64 {
impls::next_u64_via_u32(self)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_next(self, dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
Ok(self.fill_bytes(dest))
}
}