Using custom branch of miniconf
This commit is contained in:
parent
a772ccc38a
commit
702ccc231d
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -344,6 +344,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "derive_stringset"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/vertigo-designs/miniconf.git?branch=rs/cleanup#396a759356ae977d718ef6d30cfa6481f0d40b2f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -581,6 +582,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "miniconf"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/vertigo-designs/miniconf.git?branch=rs/cleanup#396a759356ae977d718ef6d30cfa6481f0d40b2f"
|
||||
dependencies = [
|
||||
"derive_stringset",
|
||||
"serde",
|
||||
@ -909,7 +911,6 @@ dependencies = [
|
||||
"panic-semihosting",
|
||||
"paste",
|
||||
"serde",
|
||||
"serde-json-core 0.1.0",
|
||||
"smoltcp",
|
||||
"stm32h7xx-hal",
|
||||
]
|
||||
|
@ -36,7 +36,6 @@ panic-semihosting = { version = "0.5", optional = true }
|
||||
panic-halt = "0.2"
|
||||
serde = { version = "1.0", features = ["derive"], default-features = false }
|
||||
heapless = { version = "0.5", features = ["serde"] }
|
||||
serde-json-core = "0.1"
|
||||
cortex-m-rtic = "0.5.5"
|
||||
embedded-hal = "0.2.4"
|
||||
nb = "1.0.0"
|
||||
@ -48,9 +47,8 @@ ad9959 = { path = "ad9959" }
|
||||
minimq = { git = "https://github.com/quartiq/minimq.git" }
|
||||
|
||||
[dependencies.miniconf]
|
||||
# git = "https://github.com/vertigo-designs/miniconf.git"
|
||||
# branch = "james/derive_stringset"
|
||||
path = "../../vertigo-designs/miniconf"
|
||||
git = "https://github.com/vertigo-designs/miniconf.git"
|
||||
branch = "rs/cleanup"
|
||||
|
||||
[dependencies.mcp23017]
|
||||
git = "https://github.com/mrd0ll4r/mcp23017.git"
|
||||
|
@ -10,9 +10,8 @@ serde = { version = "1.0", features = ["derive"], default-features = false }
|
||||
serde-json-core = "0.1"
|
||||
|
||||
[dependencies.miniconf]
|
||||
# git = "https://github.com/vertigo-designs/miniconf.git"
|
||||
# branch = "james/derive_stringset"
|
||||
path = "../../../vertigo-designs/miniconf"
|
||||
git = "https://github.com/vertigo-designs/miniconf.git"
|
||||
branch = "rs/cleanup"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3"
|
||||
|
@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize};
|
||||
use super::{abs, copysign, macc, max, min};
|
||||
use core::f32;
|
||||
|
||||
use miniconf::StringSet;
|
||||
|
||||
/// IIR state and coefficients type.
|
||||
///
|
||||
/// To represent the IIR state (input and output memory) during the filter update
|
||||
@ -38,7 +40,7 @@ pub type IIRState = [f32; 5];
|
||||
/// Therefore it can trivially implement bump-less transfer.
|
||||
/// * Cascading multiple IIR filters allows stable and robust
|
||||
/// implementation of transfer functions beyond bequadratic terms.
|
||||
#[derive(Copy, Clone, Deserialize, Serialize)]
|
||||
#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, StringSet)]
|
||||
pub struct IIR {
|
||||
pub ba: IIRState,
|
||||
pub y_offset: f32,
|
||||
|
@ -3,29 +3,36 @@
|
||||
#![no_main]
|
||||
#![cfg_attr(feature = "nightly", feature(core_intrinsics))]
|
||||
|
||||
use miniconf::StringSet;
|
||||
|
||||
use stm32h7xx_hal as hal;
|
||||
|
||||
use rtic::cyccnt::{Instant, U32Ext};
|
||||
|
||||
use stabilizer::hardware;
|
||||
|
||||
use miniconf::StringSet;
|
||||
use serde::Deserialize;
|
||||
|
||||
use dsp::iir;
|
||||
use hardware::{Adc0Input, Adc1Input, Dac0Output, Dac1Output, AFE0, AFE1, MqttAction};
|
||||
|
||||
const SCALE: f32 = ((1 << 15) - 1) as f32;
|
||||
|
||||
const TCP_RX_BUFFER_SIZE: usize = 8192;
|
||||
const TCP_TX_BUFFER_SIZE: usize = 8192;
|
||||
|
||||
// The number of cascaded IIR biquads per channel. Select 1 or 2!
|
||||
const IIR_CASCADE_LENGTH: usize = 1;
|
||||
|
||||
#[derive(Default, StringSet)]
|
||||
struct Settings {
|
||||
pub afe_gain: [hardware::AfeGain; 2],
|
||||
//iir: [[iir::IIR; IIR_CASCADE_LENGTH]; 2],
|
||||
#[derive(Debug, Deserialize, StringSet)]
|
||||
pub struct Settings {
|
||||
test: u32,
|
||||
iir: [[iir::IIR; IIR_CASCADE_LENGTH]; 2],
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
test: 5,
|
||||
iir: [[iir::IIR::default(); IIR_CASCADE_LENGTH]; 2],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[rtic::app(device = stm32h7xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
|
||||
@ -58,7 +65,7 @@ const APP: () = {
|
||||
stabilizer.adc_dac_timer.start();
|
||||
|
||||
init::LateResources {
|
||||
mqtt_interface: hardware::MqttInterface::new(stabilizer.net.stack, Settings::default()),
|
||||
mqtt_interface: hardware::MqttInterface::new(stabilizer.net.stack, Settings::new()),
|
||||
afes: stabilizer.afes,
|
||||
adcs: stabilizer.adcs,
|
||||
dacs: stabilizer.dacs,
|
||||
@ -135,11 +142,9 @@ const APP: () = {
|
||||
}
|
||||
|
||||
#[task(priority = 1, resources=[mqtt_interface, afes, iir_ch])]
|
||||
fn settings_update(c: settings_update::Context) {
|
||||
fn settings_update(mut c: settings_update::Context) {
|
||||
let settings = c.resources.mqtt_interface.settings.borrow();
|
||||
//c.resources.iir_ch.lock(|iir_ch| *iir_ch = settings.iir);
|
||||
c.resources.afes.0.set_gain(settings.afe_gain[0]);
|
||||
c.resources.afes.1.set_gain(settings.afe_gain[1]);
|
||||
c.resources.iir_ch.lock(|iir| *iir = settings.iir);
|
||||
}
|
||||
|
||||
#[task(binds = ETH, priority = 1)]
|
||||
|
@ -5,15 +5,10 @@
|
||||
|
||||
use stm32h7xx_hal as hal;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use rtic::cyccnt::{Instant, U32Ext};
|
||||
|
||||
use heapless::{consts::*, String};
|
||||
|
||||
use stabilizer::{
|
||||
hardware, server, ADC_SAMPLE_TICKS_LOG2, SAMPLE_BUFFER_SIZE_LOG2,
|
||||
hardware, ADC_SAMPLE_TICKS_LOG2, SAMPLE_BUFFER_SIZE_LOG2,
|
||||
};
|
||||
|
||||
use dsp::{iir, iir_int, lockin::Lockin, reciprocal_pll::TimestampHandler};
|
||||
@ -23,9 +18,6 @@ use hardware::{
|
||||
|
||||
const SCALE: f32 = ((1 << 15) - 1) as f32;
|
||||
|
||||
const TCP_RX_BUFFER_SIZE: usize = 8192;
|
||||
const TCP_TX_BUFFER_SIZE: usize = 8192;
|
||||
|
||||
// The number of cascaded IIR biquads per channel. Select 1 or 2!
|
||||
const IIR_CASCADE_LENGTH: usize = 1;
|
||||
|
||||
@ -35,7 +27,7 @@ const APP: () = {
|
||||
afes: (AFE0, AFE1),
|
||||
adcs: (Adc0Input, Adc1Input),
|
||||
dacs: (Dac0Output, Dac1Output),
|
||||
net_interface: hardware::Ethernet,
|
||||
stack: hardware::NetworkStack,
|
||||
|
||||
// Format: iir_state[ch][cascade-no][coeff]
|
||||
#[init([[[0.; 5]; IIR_CASCADE_LENGTH]; 2])]
|
||||
@ -80,7 +72,7 @@ const APP: () = {
|
||||
afes: stabilizer.afes,
|
||||
adcs: stabilizer.adcs,
|
||||
dacs: stabilizer.dacs,
|
||||
net_interface: stabilizer.net.interface,
|
||||
stack: stabilizer.net.stack,
|
||||
timestamper: stabilizer.timestamper,
|
||||
|
||||
pll,
|
||||
@ -165,26 +157,8 @@ const APP: () = {
|
||||
}
|
||||
}
|
||||
|
||||
#[idle(resources=[net_interface, iir_state, iir_ch, afes])]
|
||||
fn idle(mut c: idle::Context) -> ! {
|
||||
let mut socket_set_entries: [_; 8] = Default::default();
|
||||
let mut sockets =
|
||||
smoltcp::socket::SocketSet::new(&mut socket_set_entries[..]);
|
||||
|
||||
let mut rx_storage = [0; TCP_RX_BUFFER_SIZE];
|
||||
let mut tx_storage = [0; TCP_TX_BUFFER_SIZE];
|
||||
let tcp_handle = {
|
||||
let tcp_rx_buffer =
|
||||
smoltcp::socket::TcpSocketBuffer::new(&mut rx_storage[..]);
|
||||
let tcp_tx_buffer =
|
||||
smoltcp::socket::TcpSocketBuffer::new(&mut tx_storage[..]);
|
||||
let tcp_socket =
|
||||
smoltcp::socket::TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
|
||||
sockets.add(tcp_socket)
|
||||
};
|
||||
|
||||
let mut server = server::Server::new();
|
||||
|
||||
#[idle(resources=[stack, iir_state, iir_ch, afes])]
|
||||
fn idle(c: idle::Context) -> ! {
|
||||
let mut time = 0u32;
|
||||
let mut next_ms = Instant::now();
|
||||
|
||||
@ -199,118 +173,7 @@ const APP: () = {
|
||||
time += 1;
|
||||
}
|
||||
|
||||
{
|
||||
let socket =
|
||||
&mut *sockets.get::<smoltcp::socket::TcpSocket>(tcp_handle);
|
||||
if socket.state() == smoltcp::socket::TcpState::CloseWait {
|
||||
socket.close();
|
||||
} else if !(socket.is_open() || socket.is_listening()) {
|
||||
socket
|
||||
.listen(1235)
|
||||
.unwrap_or_else(|e| warn!("TCP listen error: {:?}", e));
|
||||
} else {
|
||||
server.poll(socket, |req| {
|
||||
info!("Got request: {:?}", req);
|
||||
stabilizer::route_request!(req,
|
||||
readable_attributes: [
|
||||
"stabilizer/iir/state": (|| {
|
||||
let state = c.resources.iir_state.lock(|iir_state|
|
||||
server::Status {
|
||||
t: time,
|
||||
x0: iir_state[0][0][0],
|
||||
y0: iir_state[0][0][2],
|
||||
x1: iir_state[1][0][0],
|
||||
y1: iir_state[1][0][2],
|
||||
});
|
||||
|
||||
Ok::<server::Status, ()>(state)
|
||||
}),
|
||||
// "_b" means cascades 2nd IIR
|
||||
"stabilizer/iir_b/state": (|| { let state = c.resources.iir_state.lock(|iir_state|
|
||||
server::Status {
|
||||
t: time,
|
||||
x0: iir_state[0][IIR_CASCADE_LENGTH-1][0],
|
||||
y0: iir_state[0][IIR_CASCADE_LENGTH-1][2],
|
||||
x1: iir_state[1][IIR_CASCADE_LENGTH-1][0],
|
||||
y1: iir_state[1][IIR_CASCADE_LENGTH-1][2],
|
||||
});
|
||||
|
||||
Ok::<server::Status, ()>(state)
|
||||
}),
|
||||
"stabilizer/afe0/gain": (|| c.resources.afes.0.get_gain()),
|
||||
"stabilizer/afe1/gain": (|| c.resources.afes.1.get_gain())
|
||||
],
|
||||
|
||||
modifiable_attributes: [
|
||||
"stabilizer/iir0/state": server::IirRequest, (|req: server::IirRequest| {
|
||||
c.resources.iir_ch.lock(|iir_ch| {
|
||||
if req.channel > 1 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
iir_ch[req.channel as usize][0] = req.iir;
|
||||
|
||||
Ok::<server::IirRequest, ()>(req)
|
||||
})
|
||||
}),
|
||||
"stabilizer/iir1/state": server::IirRequest, (|req: server::IirRequest| {
|
||||
c.resources.iir_ch.lock(|iir_ch| {
|
||||
if req.channel > 1 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
iir_ch[req.channel as usize][0] = req.iir;
|
||||
|
||||
Ok::<server::IirRequest, ()>(req)
|
||||
})
|
||||
}),
|
||||
"stabilizer/iir_b0/state": server::IirRequest, (|req: server::IirRequest| {
|
||||
c.resources.iir_ch.lock(|iir_ch| {
|
||||
if req.channel > 1 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
iir_ch[req.channel as usize][IIR_CASCADE_LENGTH-1] = req.iir;
|
||||
|
||||
Ok::<server::IirRequest, ()>(req)
|
||||
})
|
||||
}),
|
||||
"stabilizer/iir_b1/state": server::IirRequest,(|req: server::IirRequest| {
|
||||
c.resources.iir_ch.lock(|iir_ch| {
|
||||
if req.channel > 1 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
iir_ch[req.channel as usize][IIR_CASCADE_LENGTH-1] = req.iir;
|
||||
|
||||
Ok::<server::IirRequest, ()>(req)
|
||||
})
|
||||
}),
|
||||
"stabilizer/afe0/gain": hardware::AfeGain, (|gain| {
|
||||
c.resources.afes.0.set_gain(gain);
|
||||
Ok::<(), ()>(())
|
||||
}),
|
||||
"stabilizer/afe1/gain": hardware::AfeGain, (|gain| {
|
||||
c.resources.afes.1.set_gain(gain);
|
||||
Ok::<(), ()>(())
|
||||
})
|
||||
]
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let sleep = match c.resources.net_interface.poll(
|
||||
&mut sockets,
|
||||
smoltcp::time::Instant::from_millis(time as i64),
|
||||
) {
|
||||
Ok(changed) => !changed,
|
||||
Err(smoltcp::Error::Unrecognized) => true,
|
||||
Err(e) => {
|
||||
info!("iface poll error: {:?}", e);
|
||||
true
|
||||
}
|
||||
};
|
||||
let sleep = c.resources.stack.update(time);
|
||||
|
||||
if sleep {
|
||||
cortex_m::asm::wfi();
|
||||
|
@ -50,7 +50,7 @@ where
|
||||
match self.client.borrow_mut().poll(|client, topic, message, properties| {
|
||||
let mut split = topic.split('/');
|
||||
// TODO: Verify topic ID against our ID.
|
||||
let id = split.next().unwrap();
|
||||
let _id = split.next().unwrap();
|
||||
|
||||
// Process the command
|
||||
let command = split.next().unwrap();
|
||||
|
@ -4,7 +4,6 @@
|
||||
extern crate log;
|
||||
|
||||
pub mod hardware;
|
||||
pub mod server;
|
||||
|
||||
// The number of ticks in the ADC sampling timer. The timer runs at 100MHz, so the step size is
|
||||
// equal to 10ns per tick.
|
||||
|
278
src/server.rs
278
src/server.rs
@ -1,278 +0,0 @@
|
||||
use core::fmt::Write;
|
||||
use heapless::{consts::*, String, Vec};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json_core::{de::from_slice, ser::to_string};
|
||||
use smoltcp as net;
|
||||
|
||||
use dsp::iir;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! route_request {
|
||||
($request:ident,
|
||||
readable_attributes: [$($read_attribute:tt: $getter:tt),*],
|
||||
modifiable_attributes: [$($write_attribute:tt: $TYPE:ty, $setter:tt),*]) => {
|
||||
match $request.req {
|
||||
server::AccessRequest::Read => {
|
||||
match $request.attribute {
|
||||
$(
|
||||
$read_attribute => {
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
let value = match $getter() {
|
||||
Ok(data) => data,
|
||||
Err(_) => return server::Response::error($request.attribute,
|
||||
"Failed to read attribute"),
|
||||
};
|
||||
|
||||
let encoded_data: String<U256> = match serde_json_core::to_string(&value) {
|
||||
Ok(data) => data,
|
||||
Err(_) => return server::Response::error($request.attribute,
|
||||
"Failed to encode attribute value"),
|
||||
};
|
||||
|
||||
server::Response::success($request.attribute, &encoded_data)
|
||||
},
|
||||
)*
|
||||
_ => server::Response::error($request.attribute, "Unknown attribute")
|
||||
}
|
||||
},
|
||||
server::AccessRequest::Write => {
|
||||
match $request.attribute {
|
||||
$(
|
||||
$write_attribute => {
|
||||
let new_value = match serde_json_core::from_str::<$TYPE>(&$request.value) {
|
||||
Ok(data) => data,
|
||||
Err(_) => return server::Response::error($request.attribute,
|
||||
"Failed to decode value"),
|
||||
};
|
||||
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
match $setter(new_value) {
|
||||
Ok(_) => server::Response::success($request.attribute, &$request.value),
|
||||
Err(_) => server::Response::error($request.attribute,
|
||||
"Failed to set attribute"),
|
||||
}
|
||||
}
|
||||
)*
|
||||
_ => server::Response::error($request.attribute, "Unknown attribute")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub enum AccessRequest {
|
||||
Read,
|
||||
Write,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct Request<'a> {
|
||||
pub req: AccessRequest,
|
||||
pub attribute: &'a str,
|
||||
pub value: String<U256>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct IirRequest {
|
||||
pub channel: u8,
|
||||
pub iir: iir::IIR,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Response {
|
||||
code: i32,
|
||||
attribute: String<U256>,
|
||||
value: String<U256>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> {
|
||||
pub fn restore_value(&mut self) {
|
||||
let mut new_value: String<U256> = String::new();
|
||||
for byte in self.value.as_str().chars() {
|
||||
if byte == '\'' {
|
||||
new_value.push('"').unwrap();
|
||||
} else {
|
||||
new_value.push(byte).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
self.value = new_value;
|
||||
}
|
||||
}
|
||||
|
||||
impl Response {
|
||||
/// Remove all double quotation marks from the `value` field of a response.
|
||||
fn sanitize_value(&mut self) {
|
||||
let mut new_value: String<U256> = String::new();
|
||||
for byte in self.value.as_str().chars() {
|
||||
if byte == '"' {
|
||||
new_value.push('\'').unwrap();
|
||||
} else {
|
||||
new_value.push(byte).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
self.value = new_value;
|
||||
}
|
||||
|
||||
/// Remove all double quotation marks from the `value` field of a response and wrap it in single
|
||||
/// quotes.
|
||||
fn wrap_and_sanitize_value(&mut self) {
|
||||
let mut new_value: String<U256> = String::new();
|
||||
new_value.push('\'').unwrap();
|
||||
for byte in self.value.as_str().chars() {
|
||||
if byte == '"' {
|
||||
new_value.push('\'').unwrap();
|
||||
} else {
|
||||
new_value.push(byte).unwrap();
|
||||
}
|
||||
}
|
||||
new_value.push('\'').unwrap();
|
||||
|
||||
self.value = new_value;
|
||||
}
|
||||
|
||||
/// Construct a successful reply.
|
||||
///
|
||||
/// Note: `value` will be sanitized to convert all single quotes to double quotes.
|
||||
///
|
||||
/// Args:
|
||||
/// * `attrbute` - The attribute of the success.
|
||||
/// * `value` - The value of the attribute.
|
||||
pub fn success(attribute: &str, value: &str) -> Self {
|
||||
let mut res = Self {
|
||||
code: 200,
|
||||
attribute: String::from(attribute),
|
||||
value: String::from(value),
|
||||
};
|
||||
res.sanitize_value();
|
||||
res
|
||||
}
|
||||
|
||||
/// Construct an error reply.
|
||||
///
|
||||
/// Note: `message` will be sanitized to convert all single quotes to double quotes.
|
||||
///
|
||||
/// Args:
|
||||
/// * `attrbute` - The attribute of the success.
|
||||
/// * `message` - The message denoting the error.
|
||||
pub fn error(attribute: &str, message: &str) -> Self {
|
||||
let mut res = Self {
|
||||
code: 400,
|
||||
attribute: String::from(attribute),
|
||||
value: String::from(message),
|
||||
};
|
||||
res.wrap_and_sanitize_value();
|
||||
res
|
||||
}
|
||||
|
||||
/// Construct a custom reply.
|
||||
///
|
||||
/// Note: `message` will be sanitized to convert all single quotes to double quotes.
|
||||
///
|
||||
/// Args:
|
||||
/// * `attrbute` - The attribute of the success.
|
||||
/// * `message` - The message denoting the status.
|
||||
pub fn custom(code: i32, message: &str) -> Self {
|
||||
let mut res = Self {
|
||||
code,
|
||||
attribute: String::from(""),
|
||||
value: String::from(message),
|
||||
};
|
||||
res.wrap_and_sanitize_value();
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Status {
|
||||
pub t: u32,
|
||||
pub x0: f32,
|
||||
pub y0: f32,
|
||||
pub x1: f32,
|
||||
pub y1: f32,
|
||||
}
|
||||
|
||||
pub fn json_reply<T: Serialize>(socket: &mut net::socket::TcpSocket, msg: &T) {
|
||||
let mut u: String<U512> = to_string(msg).unwrap();
|
||||
u.push('\n').unwrap();
|
||||
socket.write_str(&u).unwrap();
|
||||
}
|
||||
|
||||
pub struct Server {
|
||||
data: Vec<u8, U256>,
|
||||
discard: bool,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
/// Construct a new server object for managing requests.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data: Vec::new(),
|
||||
discard: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Poll the server for potential data updates.
|
||||
///
|
||||
/// Args:
|
||||
/// * `socket` - The socket to check contents from.
|
||||
/// * `f` - A closure that can be called if a request has been received on the server.
|
||||
pub fn poll<F>(&mut self, socket: &mut net::socket::TcpSocket, mut f: F)
|
||||
where
|
||||
F: FnMut(&Request) -> Response,
|
||||
{
|
||||
while socket.can_recv() {
|
||||
let found = socket
|
||||
.recv(|buf| {
|
||||
let (len, found) =
|
||||
match buf.iter().position(|&c| c as char == '\n') {
|
||||
Some(end) => (end + 1, true),
|
||||
None => (buf.len(), false),
|
||||
};
|
||||
if self.data.len() + len >= self.data.capacity() {
|
||||
self.discard = true;
|
||||
self.data.clear();
|
||||
} else if !self.discard && len > 0 {
|
||||
self.data.extend_from_slice(&buf[..len]).unwrap();
|
||||
}
|
||||
(len, found)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
if found {
|
||||
if self.discard {
|
||||
self.discard = false;
|
||||
json_reply(
|
||||
socket,
|
||||
&Response::custom(520, "command buffer overflow"),
|
||||
);
|
||||
} else {
|
||||
let r = from_slice::<Request>(
|
||||
&self.data[..self.data.len() - 1],
|
||||
);
|
||||
match r {
|
||||
Ok(mut res) => {
|
||||
// Note that serde_json_core doesn't escape quotations within a string.
|
||||
// To account for this, we manually translate all single quotes to
|
||||
// double quotes. This occurs because we doubly-serialize this field in
|
||||
// some cases.
|
||||
res.restore_value();
|
||||
let response = f(&res);
|
||||
json_reply(socket, &response);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("parse error {:?}", err);
|
||||
json_reply(
|
||||
socket,
|
||||
&Response::custom(550, "parse error"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.data.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user