Skip to content

Commit dac01de

Browse files
authored
fix: change packet visibility when changing layers (#191)
Fixes #190 This PR changes the way the viewgraph changes layer by only changing device visibility and refreshing edges. Also, the `PacketManager` was simplified and packets change visibility when changing layers, so only those of the selected layer and up are shown. Network layer: ![image](https://github.com/user-attachments/assets/31200314-9dc5-49e4-b1e9-bd10308f770e) App layer: ![image](https://github.com/user-attachments/assets/631a8547-c2ed-4bd2-903f-e78bf1087449)
1 parent eb27770 commit dac01de

File tree

14 files changed

+391
-559
lines changed

14 files changed

+391
-559
lines changed

src/types/data-devices/dDevice.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ import { DataGraph, DataNode } from "../graphs/datagraph";
33
import { DeviceType } from "../view-devices/vDevice";
44
import { Position } from "../common";
55

6+
interface NetworkInterface {
7+
name: string;
8+
mac: MacAddress;
9+
// TODO: add IP address
10+
// ip?: string;
11+
}
12+
613
export abstract class DataDevice {
714
private static idCounter = 1;
815

@@ -11,6 +18,7 @@ export abstract class DataDevice {
1118
y: number;
1219
mac: MacAddress;
1320
datagraph: DataGraph;
21+
interfaces: NetworkInterface[] = [];
1422

1523
private static setIdCounter(id: number): void {
1624
if (id >= DataDevice.idCounter) {
@@ -28,6 +36,12 @@ export abstract class DataDevice {
2836
} else {
2937
this.id = DataDevice.idCounter++;
3038
}
39+
graphData.interfaces.forEach((iface) => {
40+
this.interfaces.push({
41+
name: iface.name,
42+
mac: MacAddress.parse(iface.mac),
43+
});
44+
});
3145
this.datagraph = datagraph;
3246
}
3347

@@ -42,6 +56,10 @@ export abstract class DataDevice {
4256
x: this.x,
4357
y: this.y,
4458
mac: this.mac.toString(),
59+
interfaces: this.interfaces.map((iface) => ({
60+
name: iface.name,
61+
mac: iface.mac.toString(),
62+
})),
4563
};
4664
}
4765

src/types/data-devices/dNetworkDevice.ts

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { EthernetFrame } from "../../packets/ethernet";
2-
import { EchoReply, EchoRequest } from "../../packets/icmp";
3-
import { ICMP_PROTOCOL_NUMBER, IpAddress, IPv4Packet } from "../../packets/ip";
2+
import { IpAddress, IPv4Packet } from "../../packets/ip";
43
import { DataGraph, NetworkDataNode } from "../graphs/datagraph";
5-
import { sendDataPacket } from "../packet";
64
import { DataDevice } from "./dDevice";
75

86
export abstract class DataNetworkDevice extends DataDevice {
@@ -25,41 +23,9 @@ export abstract class DataNetworkDevice extends DataDevice {
2523

2624
abstract receiveDatagram(datagram: IPv4Packet): void;
2725

28-
// TODO: Most probably it will be different for each type of device
29-
handlePacket(datagram: IPv4Packet) {
30-
console.debug("Packet has reach its destination!");
31-
const dstDevice: DataDevice = this.datagraph.getDeviceByIP(
32-
datagram.sourceAddress,
33-
);
34-
if (!(dstDevice instanceof DataNetworkDevice)) {
35-
return;
36-
}
37-
switch (datagram.payload.protocol()) {
38-
case ICMP_PROTOCOL_NUMBER: {
39-
const request: EchoRequest = datagram.payload as EchoRequest;
40-
if (dstDevice && request.type) {
41-
const path = this.datagraph.getPathBetween(this.id, dstDevice.id);
42-
let dstMac = dstDevice.mac;
43-
if (!path) return;
44-
console.log(path);
45-
for (const id of path.slice(1)) {
46-
const device = this.datagraph.getDevice(id);
47-
if (device instanceof DataNetworkDevice) {
48-
dstMac = device.mac;
49-
break;
50-
}
51-
}
52-
const echoReply = new EchoReply(0);
53-
const ipPacket = new IPv4Packet(this.ip, dstDevice.ip, echoReply);
54-
const ethernet = new EthernetFrame(this.mac, dstMac, ipPacket);
55-
console.debug(`Sending EchoReply to ${dstDevice}`);
56-
sendDataPacket(this.datagraph, this.id, ethernet);
57-
}
58-
break;
59-
}
60-
default:
61-
console.warn("Packet's type unrecognized");
62-
}
26+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
27+
handlePacket(_datagram: IPv4Packet) {
28+
// TODO: this is unused
6329
}
6430

6531
receiveFrame(frame: EthernetFrame): void {

src/types/data-devices/dRouter.ts

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ import {
77
RouterDataNode,
88
RoutingTableEntry,
99
} from "../graphs/datagraph";
10-
import { sendDataPacket } from "../packet";
1110
import { DataNetworkDevice } from "./dNetworkDevice";
12-
import { EthernetFrame } from "../../packets/ethernet";
1311
import { ROUTER_CONSTANTS } from "../../utils/constants/router_constants";
1412

1513
export class DataRouter extends DataNetworkDevice {
@@ -73,30 +71,9 @@ export class DataRouter extends DataNetworkDevice {
7371
}
7472
}
7573

76-
processPacket(ticker: Ticker) {
77-
const datagram = this.getPacketsToProcess(ticker.deltaMS);
78-
if (!datagram) {
79-
return;
80-
}
81-
const devices = this.routePacket(datagram);
82-
83-
if (!devices || devices.length === 0) {
84-
return;
85-
}
86-
for (const nextHopId of devices) {
87-
// Wrap the datagram in a new frame
88-
const nextHop = this.datagraph.getDevice(nextHopId);
89-
if (!nextHop) {
90-
console.error("Next hop not found");
91-
continue;
92-
}
93-
const newFrame = new EthernetFrame(this.mac, nextHop.mac, datagram);
94-
sendDataPacket(this.datagraph, this.id, newFrame);
95-
}
96-
97-
if (this.packetQueue.isEmpty()) {
98-
this.stopPacketProcessor();
99-
}
74+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
75+
processPacket(_ticker: Ticker) {
76+
// TODO: this is unused
10077
}
10178

10279
startPacketProcessor() {

src/types/data-devices/dSwitch.ts

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,11 @@
1-
import { IPv4Packet } from "../../packets/ip";
21
import { DeviceType } from "../view-devices/vDevice";
3-
import { sendDataPacket } from "../packet";
42
import { DataDevice } from "./dDevice";
53
import { EthernetFrame } from "../../packets/ethernet";
64

75
export class DataSwitch extends DataDevice {
6+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
87
receiveFrame(frame: EthernetFrame): void {
9-
const datagram = frame.payload;
10-
if (!(datagram instanceof IPv4Packet)) {
11-
console.warn("Switches only forward IPv4 packets");
12-
return;
13-
}
14-
const dstDevice = this.datagraph.getDeviceByIP(datagram.destinationAddress);
15-
if (!dstDevice) {
16-
console.error("Destination device not found");
17-
return null;
18-
}
19-
const path = this.datagraph.getPathBetween(this.id, dstDevice.id);
20-
if (path.length < 2) {
21-
console.error("Destination device is not reachable");
22-
return;
23-
}
24-
const nextHopId = path[1];
25-
const nextHop = this.datagraph.getDevice(nextHopId);
26-
if (!nextHop) {
27-
console.error("Next hop not found");
28-
return;
29-
}
30-
const newFrame = new EthernetFrame(this.mac, nextHop.mac, datagram);
31-
sendDataPacket(this.datagraph, this.id, newFrame);
8+
// TODO: this is unused
329
}
3310

3411
getType(): DeviceType {

src/types/edge.ts

Lines changed: 59 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,59 +6,63 @@ import { RightBar, StyledInfo } from "../graphics/right_bar";
66
import { Colors, ZIndexLevels } from "../utils/utils";
77
import { Packet } from "./packet";
88
import { RemoveEdgeMove } from "./undo-redo";
9-
import { DeviceId } from "./graphs/datagraph";
10-
11-
export interface EdgeEdges {
12-
n1: DeviceId;
13-
n2: DeviceId;
14-
}
9+
import { DataEdge, DeviceId } from "./graphs/datagraph";
1510

1611
export class Edge extends Graphics {
17-
connectedNodes: EdgeEdges;
18-
startPos: Point;
19-
endPos: Point;
12+
private data: DataEdge;
13+
private startPos: Point;
14+
private endPos: Point;
15+
2016
viewgraph: ViewGraph;
21-
rightbar: RightBar;
22-
23-
constructor(
24-
connectedNodes: EdgeEdges,
25-
device1: ViewDevice,
26-
device2: ViewDevice,
27-
viewgraph: ViewGraph,
28-
) {
17+
18+
constructor(viewgraph: ViewGraph, edgeData: DataEdge) {
2919
super();
30-
this.connectedNodes = connectedNodes;
20+
this.data = edgeData;
3121
this.viewgraph = viewgraph;
32-
this.rightbar = RightBar.getInstance();
33-
34-
this.updatePosition(device1, device2);
3522

3623
this.eventMode = "static";
3724
this.interactive = true;
3825
this.cursor = "pointer";
3926
this.on("click", () => selectElement(this));
4027
// NOTE: this is "click" for mobile devices
4128
this.on("tap", () => selectElement(this));
29+
30+
this.refresh();
31+
}
32+
33+
/**
34+
* Recomputes the edge's position based on the connected devices.
35+
*/
36+
refresh() {
37+
const n1 = this.data.from.id;
38+
const n2 = this.data.to.id;
39+
const device1 = this.viewgraph.getDevice(n1);
40+
const device2 = this.viewgraph.getDevice(n2);
41+
this.updatePosition(device1, device2);
4242
}
4343

4444
nodePosition(nodeId: DeviceId): Point | undefined {
45-
return this.connectedNodes.n1 === nodeId
45+
return this.data.from.id === nodeId
4646
? this.startPos
47-
: this.connectedNodes.n2 === nodeId
47+
: this.data.to.id === nodeId
4848
? this.endPos
4949
: undefined;
5050
}
5151

52+
getDeviceIds(): DeviceId[] {
53+
return [this.data.from.id, this.data.to.id];
54+
}
55+
5256
otherEnd(nodeId: DeviceId): DeviceId | undefined {
53-
return this.connectedNodes.n1 === nodeId
54-
? this.connectedNodes.n2
55-
: this.connectedNodes.n2 === nodeId
56-
? this.connectedNodes.n1
57+
return this.data.from.id === nodeId
58+
? this.data.to.id
59+
: this.data.to.id === nodeId
60+
? this.data.from.id
5761
: undefined;
5862
}
5963

6064
// Method to draw the line
61-
public drawEdge(startPos: Point, endPos: Point, color: number) {
65+
drawEdge(startPos: Point, endPos: Point, color: number) {
6266
this.clear();
6367
this.moveTo(startPos.x, startPos.y);
6468
this.lineTo(endPos.x, endPos.y);
@@ -93,41 +97,39 @@ export class Edge extends Graphics {
9397

9498
// Method to show the Edge information
9599
showInfo() {
100+
const rightbar = RightBar.getInstance();
101+
102+
const from = this.data.from.id;
103+
const to = this.data.to.id;
104+
105+
const fromDevice = this.viewgraph.getDataGraph().getDevice(from);
106+
const toDevice = this.viewgraph.getDataGraph().getDevice(to);
107+
if (!fromDevice || !toDevice) {
108+
console.error("One of the devices is not found in the viewgraph.");
109+
return;
110+
}
111+
const fromInterface = fromDevice.interfaces[this.data.from.iface];
112+
const toInterface = toDevice.interfaces[this.data.to.iface];
113+
96114
const info = new StyledInfo("Edge Information");
115+
info.addField("Connected Devices", `${from} <=> ${to}`);
97116
info.addField(
98-
"Connected Devices",
99-
`${this.connectedNodes.n1} <=> ${this.connectedNodes.n2}`,
100-
);
101-
info.addField(
102-
"Start Position",
103-
`x=${this.startPos.x.toFixed(2)}, y=${this.startPos.y.toFixed(2)}`,
117+
"Connected interfaces",
118+
`${fromInterface.name} <=> ${toInterface.name}`,
104119
);
105120
info.addField(
106-
"End Position",
107-
`x=${this.endPos.x.toFixed(2)}, y=${this.endPos.y.toFixed(2)}`,
121+
"Interface MAC addresses",
122+
`${fromInterface.mac} <=> ${toInterface.mac}`,
108123
);
109124

110125
// Calls renderInfo to display Edge information
111-
this.rightbar.renderInfo(info);
126+
rightbar.renderInfo(info);
112127

113-
this.rightbar.addButton(
128+
rightbar.addButton(
114129
"Delete Edge",
115130
() => {
116131
const viewgraph = this.viewgraph;
117-
// Obtener las tablas de enrutamiento antes de eliminar la conexión
118-
const routingTable1 = viewgraph.getRoutingTable(this.connectedNodes.n1);
119-
const routingTable2 = viewgraph.getRoutingTable(this.connectedNodes.n2);
120-
121-
// Crear el movimiento de eliminación de la arista con la información adicional
122-
const routingTables = new Map([
123-
[this.connectedNodes.n1, routingTable1],
124-
[this.connectedNodes.n2, routingTable2],
125-
]);
126-
const move = new RemoveEdgeMove(
127-
viewgraph.getLayer(),
128-
this.connectedNodes,
129-
routingTables,
130-
);
132+
const move = new RemoveEdgeMove(viewgraph.getLayer(), from, to);
131133

132134
urManager.push(viewgraph, move);
133135
},
@@ -138,18 +140,20 @@ export class Edge extends Graphics {
138140
// Method to delete the edge
139141
delete() {
140142
// Remove the edge from the viewgraph and datagraph
141-
const { n1, n2 } = this.connectedNodes;
143+
const n1 = this.data.from.id;
144+
const n2 = this.data.to.id;
142145
this.viewgraph.removeEdge(n1, n2);
143146
console.log(`Edge ${n1},${n2} deleted.`);
144147
this.destroy();
145148
}
146149

147-
destroy() {
150+
destroy(): DataEdge {
148151
deselectElement();
149152
super.destroy();
153+
return this.data;
150154
}
151155

152-
public updatePosition(device1: ViewDevice, device2: ViewDevice) {
156+
private updatePosition(device1: ViewDevice, device2: ViewDevice) {
153157
const dx = device2.x - device1.x;
154158
const dy = device2.y - device1.y;
155159
const angle = Math.atan2(dy, dx);

0 commit comments

Comments
 (0)