Skip to content

Commit

Permalink
Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
joerivanruth committed Apr 25, 2024
1 parent b50f659 commit 3b3ab35
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 94 deletions.
45 changes: 16 additions & 29 deletions src/mapi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,23 @@ impl State {
event: &MapiEvent,
renderer: &mut Renderer,
) -> io::Result<()> {
renderer.set_timestamp(timestamp);
renderer.timestamp(timestamp);
match event {
MapiEvent::BoundPort(port) => {
renderer.message(None, None, format_args!("LISTEN on port {port}"))?;
renderer.message((None, None), format_args!("LISTEN on port {port}"))?;
}

MapiEvent::Incoming { id, local, peer } => {
renderer.message(
Some(*id),
None,
format_args!("INCOMING on {local} from {peer}"),
)?;
renderer.message(id, format_args!("INCOMING on {local} from {peer}"))?;
self.add_connection(id, peer.is_unix());
}

MapiEvent::Connecting { id, remote } => {
renderer.message(Some(*id), None, format_args!("CONNECTING to {remote}"))?;
renderer.message(id, format_args!("CONNECTING to {remote}"))?;
}

MapiEvent::Connected { id, .. } => {
renderer.message(Some(*id), None, "CONNECTED")?;
renderer.message(id, "CONNECTED")?;
}

MapiEvent::ConnectFailed {
Expand All @@ -66,19 +62,18 @@ impl State {
} => {
let immediately = if *immediately { " immediately" } else { "" };
renderer.message(
Some(*id),
None,
id,
format_args!("CONNECT FAILED{immediately}: {remote}: {error}"),
)?;
}

MapiEvent::End { id } => {
renderer.message(Some(*id), None, "ENDED")?;
renderer.message(id, "ENDED")?;
self.remove_connection(id);
}

MapiEvent::Aborted { id, error } => {
renderer.message(Some(*id), None, format_args!("ABORTED: {error}"))?;
renderer.message(id, format_args!("ABORTED: {error}"))?;
self.remove_connection(id);
}

Expand All @@ -100,11 +95,7 @@ impl State {
MapiEvent::ShutdownRead { id, direction } => {
self.check_incomplete(*id, *direction, renderer)?;
let sender = direction.sender();
renderer.message(
Some(*id),
Some(*direction),
format_args!("{sender} stopped sending"),
)?;
renderer.message((*id, *direction), format_args!("{sender} stopped sending"))?;
}

MapiEvent::ShutdownWrite {
Expand All @@ -114,17 +105,15 @@ impl State {
} => {
let receiver = direction.receiver();
renderer.message(
Some(*id),
Some(*direction),
(*id, *direction),
format_args!("{receiver} has stopped receiving data, discarding {n} bytes"),
)?;
}

MapiEvent::Oob(id, direction, byte) => {
let sender = direction.sender();
renderer.message(
Some(*id),
Some(*direction),
(*id, *direction),
format_args!("{sender} sent an Out-Of-Band message: {byte}"),
)?;
}
Expand Down Expand Up @@ -172,7 +161,7 @@ impl State {
Direction::Downstream => downstream,
};
if let Err(e) = acc.check_incomplete() {
renderer.message(Some(id), Some(direction), e)?;
renderer.message((id, direction), e)?;
};
Ok(())
}
Expand Down Expand Up @@ -219,8 +208,7 @@ impl Accumulator {

fn handle_raw(&mut self, renderer: &mut Renderer, mut data: &[u8]) -> Result<(), io::Error> {
renderer.header(
self.id,
self.direction,
(self.id, self.direction),
&[&format_args!("{n} bytes", n = data.len())],
)?;
let mut n = 0;
Expand Down Expand Up @@ -267,13 +255,13 @@ impl Accumulator {
} else {
"incomplete block before error"
};
renderer.header(self.id, self.direction, &[&kind])?;
renderer.header((self.id, self.direction), &[&kind])?;
self.dump_frame_as_binary(&self.buf, renderer)?;
renderer.footer(&[])?;
self.buf.clear();
self.level = Level::Raw;
}
renderer.message(Some(self.id), Some(self.direction), "mapi protocol error")?;
renderer.message((self.id, self.direction), "mapi protocol error")?;
self.error_reported = true;
self.level = Level::Raw;
return self.handle_raw(renderer, whole);
Expand Down Expand Up @@ -319,8 +307,7 @@ impl Accumulator {
"block"
};
renderer.header(
self.id,
self.direction,
(self.id, self.direction),
&[&format, &kind, &format_args!("{len} bytes")],
)?;

Expand Down
150 changes: 85 additions & 65 deletions src/render.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::fmt;
use std::{
borrow::Borrow,
fmt::Display,
io::{self, BufWriter, Write},
mem,
Expand All @@ -15,7 +16,8 @@ pub struct Renderer {
timing: TrackTime,
out: BufWriter<Box<dyn io::Write + 'static + Send>>,
current_style: Style,
at_start: Option<Style>, // if Some(s), we're at line start, style to be reset to s
desired_style: Style,
at_start: bool,
}

impl Renderer {
Expand All @@ -25,123 +27,129 @@ impl Renderer {
colored,
out: buffered,
current_style: Style::Normal,
at_start: Some(Style::Normal),
desired_style: Style::Normal,
at_start: true,
timing: TrackTime::new(),
}
}

fn show_elapsed_time(&mut self) -> io::Result<()> {
let print_sep = self.timing.activity();
if print_sep {
writeln!(self.out)?;
}
if let Some(announcement) = self.timing.announcement() {
let message = format!("TIME is {announcement}");
self.message_no_check_time(None, None, &message)?;
writeln!(self.out)?;
}
Ok(())
}

pub fn set_timestamp(&mut self, timestamp: &Timestamp) {
pub fn timestamp(&mut self, timestamp: &Timestamp) {
self.timing.set_time(timestamp);
}

pub fn message(
&mut self,
id: Option<ConnectionId>,
direction: Option<Direction>,
context: impl Into<Context>,
message: impl Display,
) -> io::Result<()> {
self.show_elapsed_time()?;
self.message_no_check_time(id, direction, &message)
self.render_timing()?;
self.render_message(&context.into(), &message)
}

fn render_timing(&mut self) -> io::Result<()> {
let print_sep = self.timing.register_activity();
if print_sep {
self.nl()?;
}
if let Some(announcement) = self.timing.announcement() {
self.render_message(&Context::empty(), &(format_args!("TIME is {announcement}")))?;
self.nl()?;
}
Ok(())
}

fn message_no_check_time(
fn render_message(
&mut self,
id: Option<ConnectionId>,
direction: Option<Direction>,
context: &Context,
message: &dyn Display,
) -> Result<(), io::Error> {
self.style(Style::Frame)?;
writeln!(self.out, "‣{} {message}", IdStream::from((id, direction)))?;
self.style(Style::Normal)?;
self.style(Style::Frame);
self.fix_style()?;
write!(self.out, "‣{} {message}", context)?;
self.nl()?;
self.out.flush()?;
Ok(())
}

pub fn header(
&mut self,
id: ConnectionId,
direction: Direction,
context: impl Into<Context>,
items: &[&dyn fmt::Display],
) -> io::Result<()> {
self.show_elapsed_time()?;
let old_style = self.style(Style::Frame)?;
write!(self.out, "┌{}", IdStream::from((id, direction)))?;
self.render_timing()?;
self.style(Style::Frame);
self.fix_style()?;
write!(self.out, "┌{}", context.into())?;
let mut sep = " ";
for item in items {
write!(self.out, "{sep}{item}")?;
sep = ", ";
}
writeln!(self.out)?;
self.at_start = Some(old_style);
assert_eq!(self.current_style, Style::Frame);
self.nl()?;
self.at_start = true;
Ok(())
}

pub fn footer(&mut self, items: &[&dyn fmt::Display]) -> io::Result<()> {
self.clear_line()?;
assert_eq!(self.current_style, Style::Frame);
if !self.at_start {
self.nl()?;
}
self.style(Style::Frame);
self.fix_style()?;
write!(self.out, "└")?;
let mut sep = " ";
for item in items {
write!(self.out, "{sep}{item}")?;
sep = ", ";
}
writeln!(self.out)?;
self.style(Style::Normal)?;
self.nl()?;
self.out.flush()?;
Ok(())
}

pub fn put(&mut self, data: impl AsRef<[u8]>) -> io::Result<()> {
if let Some(style) = self.at_start {
assert_eq!(self.current_style, Style::Frame);
if self.at_start {
let old_style = self.style(Style::Frame);
self.fix_style()?;
self.out.write_all("│".as_bytes())?;
self.style(style)?;
self.at_start = None;
self.style(old_style);
self.at_start = false;
}
self.fix_style()?;
self.out.write_all(data.as_ref())?;
Ok(())
}

pub fn clear_line(&mut self) -> io::Result<()> {
if self.at_start.is_none() {
self.nl()?;
}
Ok(())
}

pub fn nl(&mut self) -> io::Result<()> {
let old_style = self.style(Style::Frame)?;
let old_style = self.style(Style::Normal);
self.fix_style()?;
writeln!(self.out)?;
self.at_start = Some(old_style);
self.style(old_style);
self.at_start = true;
Ok(())
}

pub fn style(&mut self, mut style: Style) -> io::Result<Style> {
if style == self.current_style {
return Ok(style);
pub fn at_start(&self) -> bool {
self.at_start
}

pub fn style(&mut self, mut style: Style) -> Style {
mem::swap(&mut self.desired_style, &mut style);
style
}

fn fix_style(&mut self) -> io::Result<()> {
if self.current_style == self.desired_style {
return Ok(());
}
if self.colored {
self.write_style(style)?;
self.write_escape_sequence(self.desired_style)?;
}
mem::swap(&mut self.current_style, &mut style);
Ok(style)
self.current_style = self.desired_style;
Ok(())
}

fn write_style(&mut self, style: Style) -> io::Result<()> {
fn write_escape_sequence(&mut self, style: Style) -> io::Result<()> {
// Black=30 Red=31 Green=32 Yellow=33 Blue=34 Magenta=35 Cyan=36 White=37

let escape_sequence = match style {
Expand All @@ -159,9 +167,15 @@ impl Renderer {
}
}

pub struct IdStream(Option<ConnectionId>, Option<Direction>);
pub struct Context(Option<ConnectionId>, Option<Direction>);

impl fmt::Display for IdStream {
impl Context {
pub fn empty() -> Self {
(None, None).into()
}
}

impl fmt::Display for Context {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(id) = self.0 {
write!(f, " {id}")?;
Expand All @@ -173,17 +187,23 @@ impl fmt::Display for IdStream {
}
}

impl From<(ConnectionId, Direction)> for IdStream {
impl<C: Borrow<ConnectionId>> From<C> for Context {
fn from(value: C) -> Self {
Context(Some(*value.borrow()), None)
}
}

impl From<(ConnectionId, Direction)> for Context {
fn from(value: (ConnectionId, Direction)) -> Self {
let (id, dir) = value;
IdStream(Some(id), Some(dir))
Context(Some(id), Some(dir))
}
}

impl From<(Option<ConnectionId>, Option<Direction>)> for IdStream {
impl From<(Option<ConnectionId>, Option<Direction>)> for Context {
fn from(value: (Option<ConnectionId>, Option<Direction>)) -> Self {
let (id, dir) = value;
IdStream(id, dir)
Context(id, dir)
}
}

Expand Down Expand Up @@ -215,7 +235,7 @@ impl TrackTime {
}

/// There has been activity, return true if a separator line must be printed.
fn activity(&mut self) -> bool {
fn register_activity(&mut self) -> bool {
let now = self.now().clone();
let Some(prev) = self.last_activity.replace(now) else {
return false;
Expand Down

0 comments on commit 3b3ab35

Please sign in to comment.