Skip to content

Commit

Permalink
Merge pull request #145 from martinling/multi-view-rebase
Browse files Browse the repository at this point in the history
Add transaction-level and packet-level views of capture
  • Loading branch information
miek authored Oct 8, 2024
2 parents 282b54e + bb64847 commit 4295588
Show file tree
Hide file tree
Showing 14 changed files with 6,894 additions and 399 deletions.
254 changes: 213 additions & 41 deletions src/capture.rs

Large diffs are not rendered by default.

64 changes: 7 additions & 57 deletions src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use anyhow::{Context, Error, bail};
use crate::capture::prelude::*;
use crate::rcu::SingleWriterRcu;
use crate::usb::{self, prelude::*, validate_packet};
use crate::vec_map::{VecMap, Key};
use crate::vec_map::VecMap;

struct EndpointData {
device_id: DeviceId,
Expand Down Expand Up @@ -504,33 +504,9 @@ impl EndpointData {
}
}

#[derive(Copy, Clone)]
struct EndpointKey {
dev_addr: DeviceAddr,
direction: Direction,
ep_num: EndpointNum,
}

impl Key for EndpointKey {
fn id(self) -> usize {
self.dev_addr.0 as usize * 32 +
self.direction as usize * 16 +
self.ep_num.0 as usize
}

fn key(id: usize) -> EndpointKey {
EndpointKey {
dev_addr: DeviceAddr((id / 32) as u8),
direction: Direction::from(((id / 16) % 2) as u8),
ep_num: EndpointNum((id % 16) as u8),
}
}
}

pub struct Decoder {
capture: CaptureWriter,
device_index: VecMap<DeviceAddr, DeviceId>,
endpoint_index: VecMap<EndpointKey, EndpointId>,
endpoint_data: VecMap<EndpointId, EndpointData>,
last_endpoint_state: Vec<u8>,
last_item_endpoint: Option<EndpointId>,
Expand All @@ -543,7 +519,6 @@ impl Decoder {
let mut decoder = Decoder {
capture,
device_index: VecMap::new(),
endpoint_index: VecMap::new(),
endpoint_data: VecMap::new(),
last_endpoint_state: Vec::new(),
last_item_endpoint: None,
Expand Down Expand Up @@ -604,46 +579,21 @@ impl Decoder {
Ok(self.capture)
}

pub fn token_endpoint(&mut self, pid: PID, token: &TokenFields)
fn packet_endpoint(&mut self, pid: PID, packet: &[u8])
-> Result<EndpointId, Error>
{
let dev_addr = token.device_address();
let ep_num = token.endpoint_number();
let direction = match (ep_num.0, pid) {
(0, _) => Direction::Out,
(_, PID::SETUP) => Direction::Out,
(_, PID::IN) => Direction::In,
(_, PID::OUT) => Direction::Out,
(_, PID::PING) => Direction::Out,
_ => bail!("PID {pid} does not indicate a direction")
};
let key = EndpointKey {
dev_addr,
ep_num,
direction
};
Ok(match self.endpoint_index.get(key) {
Some(id) => *id,
None => {
Ok(match self.capture.shared.packet_endpoint(pid, packet) {
Ok(id) => id,
Err(key) => {
let id = self.add_endpoint(
key.dev_addr, key.ep_num, key.direction)?;
self.endpoint_index.set(key, id);
self.capture.shared.endpoint_index
.update(|map| map.set(key, id));
id
}
})
}

fn packet_endpoint(&mut self, pid: PID, packet: &[u8])
-> Result<EndpointId, Error>
{
Ok(match PacketFields::from_packet(packet) {
PacketFields::SOF(_) => FRAMING_EP_ID,
PacketFields::Token(token) =>
self.token_endpoint(pid, &token)?,
_ => INVALID_EP_ID,
})
}

fn transaction_update(&mut self, packet_id: PacketId, packet: &[u8])
-> Result<(), Error>
{
Expand Down
31 changes: 20 additions & 11 deletions src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,23 @@ use gtk::{gio, glib};

use anyhow::Error;

use crate::capture::{CaptureReader, TrafficItem, DeviceItem};
use crate::capture::{
CaptureReader,
TrafficItem,
TrafficViewMode,
DeviceItem,
DeviceViewMode,
};
use crate::tree_list_model::{TreeListModel, ItemNodeRc};

/// Trait implemented by each of our ListModel implementations.
pub trait GenericModel<Item> where Self: Sized {
pub trait GenericModel<Item, ViewMode> where Self: Sized {
/// Whether this model has timestamps.
const HAS_TIMES: bool;

/// Create a new model instance for the given capture.
fn new(capture: CaptureReader,
view_mode: ViewMode,
#[cfg(any(test, feature="record-ui-test"))]
on_item_update: Rc<RefCell<dyn FnMut(u32, String)>>)
-> Result<Self, Error>;
Expand Down Expand Up @@ -49,24 +56,26 @@ pub trait GenericModel<Item> where Self: Sized {

/// Define the outer type exposed to our Rust code.
macro_rules! model {
($model: ident, $item: ident, $has_times: literal) => {
($model: ident, $item: ident, $view_mode: ident, $has_times: literal) => {

glib::wrapper! {
pub struct $model(ObjectSubclass<imp::$model>)
@implements gio::ListModel;
}

impl GenericModel<$item> for $model {
impl GenericModel<$item, $view_mode> for $model {
const HAS_TIMES: bool = $has_times;

fn new(capture: CaptureReader,
view_mode: $view_mode,
#[cfg(any(test, feature="record-ui-test"))]
on_item_update: Rc<RefCell<dyn FnMut(u32, String)>>)
-> Result<Self, Error>
{
let model: $model = glib::Object::new::<$model>();
let tree = TreeListModel::new(
capture,
view_mode,
#[cfg(any(test, feature="record-ui-test"))]
on_item_update)?;
model.imp().tree.replace(Some(tree));
Expand Down Expand Up @@ -112,26 +121,26 @@ macro_rules! model {
}

// Repeat the above boilerplate for each model.
model!(TrafficModel, TrafficItem, true);
model!(DeviceModel, DeviceItem, false);
model!(TrafficModel, TrafficItem, TrafficViewMode, true);
model!(DeviceModel, DeviceItem, DeviceViewMode, false);

/// The internal implementation module.
mod imp {
use gio::subclass::prelude::*;
use gtk::{gio, glib, prelude::*};

use std::cell::RefCell;
use crate::capture::{TrafficItem, DeviceItem};
use crate::capture::{TrafficItem, TrafficViewMode, DeviceItem, DeviceViewMode};
use crate::row_data::{TrafficRowData, DeviceRowData};
use crate::tree_list_model::TreeListModel;

/// Define the inner type to be used in the GObject type system.
macro_rules! model {
($model:ident, $item:ident, $row_data:ident) => {
($model:ident, $item:ident, $row_data:ident, $view_mode: ident) => {
#[derive(Default)]
pub struct $model {
pub(super) tree: RefCell<Option<
TreeListModel<$item, super::$model, $row_data>>>,
TreeListModel<$item, super::$model, $row_data, $view_mode>>>,
}

#[glib::object_subclass]
Expand Down Expand Up @@ -168,6 +177,6 @@ mod imp {
}

// Repeat the above boilerplate for each model.
model!(TrafficModel, TrafficItem, TrafficRowData);
model!(DeviceModel, DeviceItem, DeviceRowData);
model!(TrafficModel, TrafficItem, TrafficRowData, TrafficViewMode);
model!(DeviceModel, DeviceItem, DeviceRowData, DeviceViewMode);
}
24 changes: 14 additions & 10 deletions src/record_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,18 +149,19 @@ impl Recording {
}
}

pub fn log_items_changed<Model, Item>(
pub fn log_items_changed<Model, Item, ViewMode>(
&mut self,
name: &str,
model: &Model,
position: u32,
removed: u32,
added: u32)
where
Model: ListModelExt + GenericModel<Item>,
CaptureReader: ItemSource<Item>,
Model: ListModelExt + GenericModel<Item, ViewMode>,
CaptureReader: ItemSource<Item, ViewMode>,
Object: ToGenericRowData<Item>,
Item: Copy
Item: Copy,
ViewMode: Copy,
{
if (removed, added) == (0, 0) {
return;
Expand Down Expand Up @@ -195,13 +196,16 @@ impl Recording {
}
}

fn item_text<Model, Item>(&mut self,
model: &Model,
position: u32) -> String
where Model: ListModelExt + GenericModel<Item>,
CaptureReader: ItemSource<Item>,
fn item_text<Model, Item, ViewMode>(
&mut self,
model: &Model,
position: u32
) -> String
where Model: ListModelExt + GenericModel<Item, ViewMode>,
CaptureReader: ItemSource<Item, ViewMode>,
Object: ToGenericRowData<Item>,
Item: Copy
Item: Copy,
ViewMode: Copy
{
let item = model
.item(position)
Expand Down
29 changes: 15 additions & 14 deletions src/test_replay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use gtk::prelude::*;
use itertools::assert_equal;
use serde_json::Deserializer;

use crate::capture::TrafficViewMode;
use crate::decoder::Decoder;
use crate::pcap::Loader;
use crate::model::GenericModel;
Expand Down Expand Up @@ -179,19 +180,6 @@ fn set_expanded(ui: &mut UserInterface,
expanded: bool)
{
match name {
"traffic" => {
let model = ui.traffic_model
.as_ref()
.expect("UI has no traffic model");
let node = model.item(position)
.expect("Failed to retrieve list item")
.downcast::<TrafficRowData>()
.expect("List item is not TrafficRowData")
.node()
.expect("Failed to get node from TrafficRowData");
model.set_expanded(&node, position, expanded)
.expect("Failed to expand/collapse item");
},
"devices" => {
let model = ui.device_model
.as_ref()
Expand All @@ -205,6 +193,19 @@ fn set_expanded(ui: &mut UserInterface,
model.set_expanded(&node, position, expanded)
.expect("Failed to expand/collapse item");
},
_ => panic!("Unknown model name")
log_name => {
let mode = TrafficViewMode::from_log_name(log_name);
let model = ui.traffic_models
.get(&mode)
.expect("UI has no traffic model");
let node = model.item(position)
.expect("Failed to retrieve list item")
.downcast::<TrafficRowData>()
.expect("List item is not TrafficRowData")
.node()
.expect("Failed to get node from TrafficRowData");
model.set_expanded(&node, position, expanded)
.expect("Failed to expand/collapse item");
},
}
}
26 changes: 17 additions & 9 deletions src/tree_list_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,30 +346,35 @@ impl std::fmt::Display for ModelUpdate {
}
}

pub struct TreeListModel<Item, Model, RowData> {
pub struct TreeListModel<Item, Model, RowData, ViewMode> {
_marker: PhantomData<(Model, RowData)>,
capture: RefCell<CaptureReader>,
view_mode: ViewMode,
root: RootNodeRc<Item>,
regions: RefCell<BTreeMap<u64, Region<Item>>>,
#[cfg(any(test, feature="record-ui-test"))]
on_item_update: Rc<RefCell<dyn FnMut(u32, String)>>,
}

impl<Item, Model, RowData> TreeListModel<Item, Model, RowData>
impl<Item, Model, RowData, ViewMode> TreeListModel<Item, Model, RowData, ViewMode>
where Item: 'static + Copy + Debug,
Model: GenericModel<Item> + ListModelExt,
ViewMode: Copy,
Model: GenericModel<Item, ViewMode> + ListModelExt,
RowData: GenericRowData<Item> + IsA<Object> + Cast,
CaptureReader: ItemSource<Item>,
CaptureReader: ItemSource<Item, ViewMode>,
{
pub fn new(mut capture: CaptureReader,
view_mode: ViewMode,
#[cfg(any(test, feature="record-ui-test"))]
on_item_update: Rc<RefCell<dyn FnMut(u32, String)>>)
-> Result<Self, Error>
{
let (completion, item_count) = capture.item_children(None)?;
let (completion, item_count) =
capture.item_children(None, view_mode)?;
Ok(TreeListModel {
_marker: PhantomData,
capture: RefCell::new(capture.clone()),
view_mode,
root: Rc::new(RefCell::new(RootNode {
children: Children::new(item_count),
complete: completion.is_complete(),
Expand Down Expand Up @@ -749,7 +754,8 @@ where Item: 'static + Copy + Debug,

// Check if this node had children added and/or was completed.
let mut cap = self.capture.borrow_mut();
let (completion, new_direct_count) = cap.item_children(node.item())?;
let (completion, new_direct_count) =
cap.item_children(node.item(), self.view_mode)?;
let completed = completion.is_complete();
let children_added = new_direct_count - old_direct_count;
drop(node);
Expand Down Expand Up @@ -925,8 +931,10 @@ where Item: 'static + Copy + Debug,
// Otherwise, fetch it from the database.
let mut cap = self.capture.borrow_mut();
let mut parent = parent_ref.borrow_mut();
let item = cap.item(parent.item(), relative_position)?;
let (completion, child_count) = cap.item_children(Some(&item))?;
let item =
cap.item(parent.item(), self.view_mode, relative_position)?;
let (completion, child_count) =
cap.item_children(Some(&item), self.view_mode)?;
let node = ItemNode {
item,
parent: Rc::downgrade(&parent_ref),
Expand Down Expand Up @@ -958,7 +966,7 @@ where Item: 'static + Copy + Debug,

pub fn connectors(&self, item: &Item) -> String {
let mut cap = self.capture.borrow_mut();
match cap.connectors(item) {
match cap.connectors(self.view_mode, item) {
Ok(string) => string,
Err(e) => format!("Error: {e:?}")
}
Expand Down
Loading

0 comments on commit 4295588

Please sign in to comment.