rust/hedgewars-server/src/protocol.rs
author sheepluva
Mon, 05 Aug 2019 00:20:45 +0200
changeset 15316 f382ec6dba11
parent 15144 1aa3b44c0441
child 15463 a158ff8f84ef
permissions -rw-r--r--
In hindsight my emscripten-ifdef (70d416a8f63f) is nonsense. As fpcrtl_glShaderSource() would not be defined and lead to compiling issues. So either it's 3 ifdefs (in pas2cRedo, pas2cSystem and misc.c), in order to toggle between fpcrtl_ and the native function, or alternatively have no ifdef for it at all. I'm going with none at all, which means emscripten will compile with the original (const) function prototype, being wrapped by the fpcrtl_ function, same as non-emscripten builds.

use self::parser::message;
use log::*;
use netbuf;
use std::io::{Read, Result};

pub mod messages;
mod parser;
#[cfg(test)]
pub mod test;

pub struct ProtocolDecoder {
    buf: netbuf::Buf,
    is_recovering: bool,
}

impl ProtocolDecoder {
    pub fn new() -> ProtocolDecoder {
        ProtocolDecoder {
            buf: netbuf::Buf::new(),
            is_recovering: false,
        }
    }

    fn recover(&mut self) -> bool {
        self.is_recovering = match parser::malformed_message(&self.buf[..]) {
            Ok((tail, ())) => {
                self.buf.consume(self.buf.len() - tail.len());
                false
            }
            _ => {
                self.buf.consume(self.buf.len());
                true
            }
        };
        !self.is_recovering
    }

    pub fn read_from<R: Read>(&mut self, stream: &mut R) -> Result<usize> {
        let count = self.buf.read_from(stream)?;
        if count > 0 && self.is_recovering {
            self.recover();
        }
        Ok(count)
    }

    pub fn extract_messages(&mut self) -> Vec<messages::HwProtocolMessage> {
        let mut messages = vec![];
        if !self.is_recovering {
            while !self.buf.is_empty() {
                match parser::message(&self.buf[..]) {
                    Ok((tail, message)) => {
                        messages.push(message);
                        self.buf.consume(self.buf.len() - tail.len());
                    }
                    Err(nom::Err::Incomplete(_)) => break,
                    Err(nom::Err::Failure(e)) | Err(nom::Err::Error(e)) => {
                        debug!("Invalid message: {:?}", e);
                        if !self.recover() || self.buf.is_empty() {
                            break;
                        }
                    }
                }
            }
        }
        messages
    }
}