prax 0.1.1

a web penetration proxy hosted in neovim
Documentation
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

mod body;
mod conv;
mod deser;
mod encoding;

#[cfg(test)]
mod test;

pub use body::Body;
pub use encoding::Encoding;
use tokio::sync::broadcast;

use crate::bind::{Req, Res, Scribe};

use crate::store::{Append, Random, Store};

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
pub struct Request {
    pub method: String,
    pub path: String,
    pub query: HashMap<String, String>,
    pub version: String,
    pub headers: HashMap<String, String>,
    pub body: Body,
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
pub struct Response {
    pub status: u16,
    pub headers: HashMap<String, String>,
    pub body: Body,
}

#[derive(Debug, PartialEq)]
pub struct Ent<'a> {
    pub request: &'a Request,
    pub response: Option<&'a Response>,
}

#[derive(Debug)]
pub struct Entry {
    pub request: Request,
    pub response: Option<Response>,
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub enum HistoryEvent {
    Request { index: usize },
    Response { index: usize },
}

#[derive(Debug)]
pub struct Hist {
    requests: Store<Request, Append>,
    responses: Store<Response, Random>,

    events: broadcast::Sender<HistoryEvent>,
}

#[derive(Default, Debug)]
pub struct History(Vec<Entry>);

impl Scribe for Hist {
    type Ticket = usize;

    async fn report_request(&self, req: &Req<Vec<u8>>) -> usize {
        let req = Request::from(req);
        let index = self.requests.push(req);

        let _ = self.events.send(HistoryEvent::Request { index });

        index
    }

    async fn report_response(&self, index: Self::Ticket, res: &Res<Vec<u8>>) {
        let res = Response::from(res);

        if self.responses.insert(index, res) {
            let _ = self.events.send(HistoryEvent::Response { index });
        }
    }
}

impl Hist {
    pub fn entry(&self, index: usize) -> Option<Ent> {
        let request = self.requests.get(index)?;

        let response = self.responses.get(index);

        Some(Ent { request, response })
    }

    pub fn request(&self, index: usize) -> Option<&Request> {
        self.requests.get(index)
    }

    pub fn response(&self, index: usize) -> Option<&Response> {
        self.responses.get(index)
    }

    pub fn listen(&self) -> broadcast::Receiver<HistoryEvent> {
        self.events.subscribe()
    }
}

impl Default for Hist {
    fn default() -> Self {
        let requests = Store::<Request, Append>::default();
        let responses = Store::default();

        let events = broadcast::Sender::new(16);

        Hist {
            requests,
            responses,
            events,
        }
    }
}