@webwriter/network
Version:
Visualization of network topologies. Can represent different kinds of networks.
923 lines (843 loc) • 43.3 kB
text/typescript
import SlColorPicker from '@shoelace-style/shoelace/dist/components/color-picker/color-picker.component.js';
import SlDialog from '@shoelace-style/shoelace/dist/components/dialog/dialog.component.js';
import SlInput from '@shoelace-style/shoelace/dist/components/input/input.component.js';
import SlSelect from '@shoelace-style/shoelace/dist/components/select/select.component.js';
import { SlChangeEvent } from '@shoelace-style/shoelace';
import { names } from 'konva/types/Node';
import { html, TemplateResult } from 'lit';
import { NetworkComponent } from 'src';
import { Ipv4Address } from '../adressing/Ipv4Address';
import { Ipv6Address } from '../adressing/Ipv6Address';
import { MacAddress } from '../adressing/MacAddress';
import { Net } from '../components/logicalNodes/Net';
import { Router } from '../components/physicalNodes/Connector';
import { GraphNodeFactory } from '../event-handlers/component-manipulation';
import { biAlphabet, biDashSquare, biEthernet, biPCICardNetwork, biPlusSquare, biTrash, biWifi } from '../styles/icons';
import { EdgeController } from '../event-handlers/edge-controller';
import { styleMap } from 'lit/directives/style-map.js';
import { GraphEdge } from '../components/GraphEdge';
import { SubnettingController } from '../event-handlers/subnetting-controller';
import { AlertHelper } from '../utils/AlertHelper';
import { AddressingHelper } from '../utils/AdressingHelper';
import { Host } from 'src/components/physicalNodes/Host';
import { msg } from '@lit/localize';
export function contextMenuTemplate(this: NetworkComponent): TemplateResult {
const type = this.selectedObject?.isNode()
? this.selectedObject.data('cssClass').includes('net-node')
? 'network'
: 'node'
: 'edge';
if (this.mode === 'simulate' && type === 'node') return nodeRoutingTableTemplate.bind(this)();
if (this.mode === 'simulate')
return html`<div
id="contextMenu"
class="contextmenu"
@contextmenu=${(e: Event) => e.preventDefault()}
style="display:none"
></div>`;
return html`
${type === 'network' ? networkContextDialogTemplate.bind(this)() : ''}
${type === 'node' ? nodeContextDialogTemplate.bind(this)() : ''}
${type === 'edge' ? edgeContextDialogTemplate.bind(this)() : ''}
<div id="contextMenu" class="contextmenu" @contextmenu=${(e: Event) => e.preventDefault()} style="display:none">
${type === 'network' ? networkContextMenuTemplate.bind(this)() : ''}
${type === 'node' ? nodeContextMenuTemplate.bind(this)() : ''}
${type === 'edge' ? edgeContextMenuTemplate.bind(this)() : ''}
</div>
`;
}
function nodeContextMenuTemplate(this: NetworkComponent): TemplateResult {
return html`
<div class="contextmenu__header">
<sl-input
type="text"
placeholder="${msg('Name')}"
@sl-input=${(e: SlChangeEvent) => {
this.selectedObject?.data('name', (e.target as HTMLInputElement).value);
}}
value=${this.selectedObject?.data('name')}
>
<span slot="prefix">${biAlphabet}</span>
</sl-input>
<sl-button
class="contextmenu__delete"
circle
@click="${() => {
GraphNodeFactory.removeNode(this.selectedObject, this);
this.selectedObject.remove();
this.contextMenu.style.display = 'none';
}}"
>${biTrash}</sl-button
>
</div>
<hr />
<sl-button
@click="${() => {
(this.shadowRoot?.querySelector('#nodeContextDialog') as SlDialog).show();
}}"
>${msg('Change Port Config')}</sl-button
>
<sl-color-picker
id="color-picker"
swatches=${this.colors.join('; ')}
@sl-change="${(e: SlChangeEvent) => {
const color = (e.target as SlColorPicker).value;
this.selectedObject?.data('color', color);
}}"
value=${this.selectedObject?.data('color')}
></sl-color-picker>
${this.selectedObject.data().constructor.name == '_Host' &&
this.selectedObject.isChild() &&
this.selectedObject.parent().data('gateways')?.size > 0
? html`
<sl-select
label="${msg('Default Gateway')}"
@sl-change=${(e: Event) => {
const key = (e.target as HTMLSelectElement).value;
const port = this.selectedObject.parent().data('gateways')?.get(key);
this.selectedObject.data('defaultGateway', [key, port]);
}}
value=${this.selectedObject.data('defaultGateway')
? this.selectedObject.data('defaultGateway')[0]
: ''}
>
${Array.from(this.selectedObject.parent().data('gateways')?.keys()).map((key) => {
return html`<sl-option value=${key as string}>${key}</sl-option>`;
})}
</sl-select>
`
: ''}
`;
}
function edgeContextMenuTemplate(this: NetworkComponent): TemplateResult {
return html`
<div class="contextmenu__header">
<sl-button
class="contextmenu__delete"
circle
@click="${() => {
EdgeController.removeConnection(this.selectedObject.data(), this._graph);
this.selectedObject.remove();
this.contextMenu.style.display = 'none';
}}"
>${biTrash}</sl-button
>
</div>
<hr />
<sl-button
@click="${() => {
(this.shadowRoot?.querySelector('#edgeContextDialog') as SlDialog).show();
}}"
>${msg('Define Interfaces')}</sl-button
>
<sl-color-picker
id="color-picker"
swatches=${this.colors.join('; ')}
@sl-change="${(e: SlChangeEvent) => {
const color = (e.target as SlColorPicker).value;
this.selectedObject?.data('color', color);
}}"
value=${this.selectedObject?.data('color')}
></sl-color-picker>
`;
}
function networkContextMenuTemplate(this: NetworkComponent): TemplateResult {
return html`
<div class="contextmenu__header">
<sl-button
class="contextmenu__delete"
circle
@click="${() => {
GraphNodeFactory.removeNode(this.selectedObject, this);
this.selectedObject.remove();
this.contextMenu.style.display = 'none';
}}"
>${biTrash}</sl-button
>
</div>
<hr />
<sl-button
@click="${() => {
(this.shadowRoot?.querySelector('#networkContextDialog') as SlDialog).show();
}}"
>${msg('Define Network')}</sl-button
>
<sl-color-picker
id="color-picker"
swatches=${this.colors.join('; ')}
@sl-change="${(e: SlChangeEvent) => {
const color = (e.target as SlColorPicker).value;
this.selectedObject?.data('color', color);
}}"
value=${this.selectedObject?.data('color')}
></sl-color-picker>
${this.selectedObject?.data('gateways')?.size > 1
? html`
${msg('Default Gateway')}:
<sl-select
@sl-change=${(e: SlChangeEvent) => {
const gateway = (e.target as SlSelect).value;
const port = this.selectedObject?.data('gateways')?.get(gateway);
this.selectedObject?.data('currentDefaultGateway', [gateway, port]);
}}
value=${this.selectedObject?.data('currentDefaultGateway')
? this.selectedObject?.data('currentDefaultGateway')[0]
: ''}
>
${Array.from(this.selectedObject?.data('gateways')?.keys()).map((key) => {
return html`<sl-option value=${key as string}>${key}</sl-option>`;
})}
</sl-select>
`
: this.selectedObject?.data('gateways')?.size > 0
? html` ${msg('Default Gateway')}: ${this.selectedObject?.data('currentDefaultGateway')} `
: ''}
`;
}
function nodeContextDialogTemplate(this: NetworkComponent) {
const node: any = this.selectedObject;
const ports: Map<string, Map<string, any>> = node?.data('portData');
const columns = ports?.size > 0 ? Array.from(Array.from(ports?.values())[0].keys()) : [];
return html`
<sl-dialog
id="nodeContextDialog"
label=${msg('Details of the ports ') + node?.data('name')}
@sl-hide=${() => this.requestUpdate()}
>
${ports?.size > 0
? html`
<table>
<tr>
<th>Index</th>
${columns.includes('Name') ? html`<th>${msg('Name')}</th>` : ''}
${columns.includes('Connection Type') ? html`<th>${msg('Connection Type')}</th>` : ''}
${columns.includes('MAC') ? html`<th>MAC</th>` : ''}
${columns.includes('IPv4') ? html`<th>IPv4</th>` : ''}
${columns.includes('IPv6') ? html`<th>IPv6</th>` : ''}
<th></th>
</tr>
${Array.from(ports?.entries()).map((port, index) => {
return html`
<tr>
<td>${index}</td>
${columns.includes('Name')
? html`<td>
<sl-input
value=${port[1].get('Name')}
@sl-input=${(e: SlChangeEvent) => {
const v = (e.target as SlInput).value;
const portData = node.data('portData');
portData.get(port[0]).set('Name', v);
node.data('portData', portData);
}}
></sl-input>
</td>`
: ''}
${columns.includes('Connection Type')
? html`<td>
<sl-select
@sl-change=${handlePortTypeChangeGenerator
.bind(this)(port[0])
.bind(this)}
value=${port[1].get('Connection Type')}
?disabled=${isPortConnected.bind(this)(node, port[0])}
>
<sl-option value="ethernet">${msg('Ethernet')}</sl-option>
<sl-option value="wireless">${msg('Wireless')}</sl-option>
</sl-select>
</td>`
: ''}
${columns.includes('MAC')
? html`<td>
<sl-input
value=${port[1].get('MAC')?.address}
@sl-input=${handleMacAddressChangeGenerator
.bind(this)(port[0])
.bind(this)}
></sl-input>
</td>`
: ''}
${columns.includes('IPv4')
? html`<td>
<sl-input
value=${port[1].get('IPv4')?.address}
@sl-input=${handleIPv4AddressChangeGenerator
.bind(this)(port[0])
.bind(this)}
></sl-input>
</td>`
: ''}
${columns.includes('IPv6')
? html`<td>
<sl-input
value=${port[1].get('IPv6')?.address}
@sl-input=${handleIPv6AddressChangeGenerator
.bind(this)(port[0])
.bind(this)}
></sl-input>
</td>`
: ''}
<td>
<sl-button
circle
@click=${() => {
removePort.bind(this)(node, port[0]);
}}
>${biDashSquare}</sl-button
>
</td>
</tr>
`;
})}
</table>
`
: html`<p>${msg('No port available.')}</p>`}
<sl-button @click="${addPort.bind(this, node)}">
<span slot="prefix">${biPlusSquare}</span>
${msg('Add Port')}</sl-button
>
</sl-dialog>
`;
}
function edgeContextDialogTemplate(this: NetworkComponent) {
const edge: any = this.selectedObject;
if (!edge) return html``;
const source: any = edge.source();
const target: any = edge.target();
let availableSourcePorts: number[] = [];
let availableTargetPorts: number[] = [];
source.data('portLinkMapping').forEach((link: any, port: any) => {
if (link == null || link == undefined || link == '' || link === edge.data('id')) {
availableSourcePorts.push(port);
}
});
target.data('portLinkMapping').forEach((link: any, port: any) => {
if (link == null || link == undefined || link == '' || link === edge.data('id')) {
availableTargetPorts.push(port);
}
});
return html`
<sl-dialog
id="edgeContextDialog"
label=${msg('Details of the connection between ') + source.data('name') + msg(' and ') + target.data('name')}
@sl-hide=${() => {
this.requestUpdate();
}}
>
<div class="contextmenu__edgedisplay">
<div class="contextmenu__edgedisplay__node">
<div
class="contextmenu__edgedisplay__nodeImage"
style=${styleMap({
backgroundColor: source.data('color'),
backgroundImage: `url("${source.data('backgroundPath')}")`,
})}
></div>
<div class="contextmenu__edgedisplay__nodeTitle">${source.data('name')}</div>
</div>
<div class="contextmenu__edgedisplay__edge">
<sl-select
style="align-self: flex-start"
placeholder="${msg('Source Port')}"
@sl-change=${(e: SlChangeEvent) => {
const port = parseInt((e.target as SlSelect).value as string);
if (Number.isNaN(port)) {
this.selectedPorts['source'].connectionType = null;
this.selectedPorts['source'].port = null;
} else {
const cv = source.data('portData').get(port).get('Connection Type');
this.selectedPorts['source'].connectionType = cv;
this.selectedPorts['source'].port = port;
}
if (this.selectedPorts['source'].port && this.selectedPorts['target'].port)
updatePortLink.bind(this)();
this.requestUpdate();
}}
value=${edge.data('inPort')?.toString() || ''}
clearable
>
<span slot="prefix">${biPCICardNetwork}</span>
${availableSourcePorts.map(
(port) => html`
<sl-option
value=${port}
?disabled=${this.selectedPorts['target'].connectionType &&
this.selectedPorts['target'].connectionType !==
source.data('portData').get(port).get('Connection Type')}
?selected=${port === edge.data('inPort')}
>
<span slot="prefix"
>${source.data('portData').get(port).get('Connection Type') === 'ethernet'
? biEthernet
: biWifi}</span
>
<span slot="suffix">
${`MAC: ${source.data('portData').get(port).get('MAC').address}`}
</span>
${source.data('portData').get(port).get('Name') || port}
</sl-option>
`
)}
</sl-select>
<hr style=${`border-top: 3px dashed ${edge.data('color')}`} />
<sl-select
style="align-self: flex-end"
placeholder="${msg('Target Port')}"
@sl-change=${(e: SlChangeEvent) => {
const port = parseInt((e.target as SlSelect).value as string);
if (Number.isNaN(port)) {
this.selectedPorts['target'].connectionType = null;
this.selectedPorts['target'].port = null;
} else {
const cv = target.data('portData').get(port).get('Connection Type');
this.selectedPorts['target'].connectionType = cv;
this.selectedPorts['target'].port = port;
}
if (this.selectedPorts['source'].port && this.selectedPorts['target'].port)
updatePortLink.bind(this)();
this.requestUpdate();
}}
value=${edge.data('outPort')?.toString() || ''}
clearable
>
<span slot="prefix">${biEthernet}</span>
${availableTargetPorts.map(
(port) => html`
<sl-option
value=${port}
?disabled=${this.selectedPorts['source'].connectionType &&
this.selectedPorts['source'].connectionType !==
target.data('portData').get(port).get('Connection Type')}
?selected=${port === edge.data('outPort')}
>
<span slot="prefix"
>${target.data('portData').get(port).get('Connection Type') === 'ethernet'
? biEthernet
: biWifi}</span
>
<span slot="suffix">
${`MAC: ${target.data('portData').get(port).get('MAC').address}`}
</span>
${target.data('portData').get(port).get('Name') || port}
</sl-option>
`
)}
</sl-select>
</div>
<div class="contextmenu__edgedisplay__node">
<div
class="contextmenu__edgedisplay__nodeImage"
style=${styleMap({
backgroundColor: target.data('color'),
backgroundImage: `url("${target.data('backgroundPath')}")`,
})}
></div>
<div class="contextmenu__edgedisplay__nodeTitle">${target.data('name')}</div>
</div>
</div>
</sl-dialog>
`;
}
function networkContextDialogTemplate(this: NetworkComponent) {
const network: any = this.selectedObject;
const subnet: any = network.data('subnet');
return html`
<sl-dialog
id="networkContextDialog"
label=${msg('Details of the network ') + network?.data('id')}
@sl-hide=${() => this.requestUpdate()}
>
<sl-input
type="text"
placeholder="NetId"
value=${network?.data('networkAddress')?.address}
@sl-input=${(e: SlChangeEvent) => {
const value = (e.target as SlInput).value;
const subnet: Net = this.selectedObject.data();
if (Ipv4Address.validateAddress(value, this.ipv4Database) == null) {
(e.target as SlInput).classList.add('danger');
(e.target as SlInput).classList.remove('success');
(e.target as SlInput).setAttribute('help-text', msg('IPv4 address is invalid.'));
return;
} else {
(e.target as SlInput).classList.remove('danger');
(e.target as SlInput).classList.add('success');
(e.target as SlInput).setAttribute('help-text', '');
}
const success = subnet.handleChangesOnNewNetInfo(value, subnet.netmask, subnet.bitmask, this);
if (success) {
this.selectedObject.toggleClass('unconfigured-net', false);
const name = this.selectedObject.data('name');
this.selectedObject.data('name', name);
} else {
(e.target as SlInput).classList.add('danger');
(e.target as SlInput).classList.remove('success');
(e.target as SlInput).setAttribute('help-text', msg('Invalid net id.'));
}
}}
></sl-input>
<sl-input
type="text"
placeholder="${msg('Network Mask')}"
id="netmask"
value=${network?.data('netmask')}
@sl-input=${(e: SlChangeEvent) => {
const value = (e.target as SlInput).value;
const subnet: Net = this.selectedObject.data();
if (Ipv4Address.validateAddress(value, this.ipv4Database) == null) {
(e.target as SlInput).classList.add('danger');
(e.target as SlInput).classList.remove('success');
(e.target as SlInput).setAttribute('help-text', msg('IPv4 address is invalid.'));
return;
} else {
(e.target as SlInput).classList.remove('danger');
(e.target as SlInput).classList.add('success');
(e.target as SlInput).setAttribute('help-text', '');
}
const success = subnet.handleChangesOnNewNetInfo(
subnet.networkAddress.address,
value,
subnet.bitmask,
this
);
if (success) {
this.selectedObject.toggleClass('unconfigured-net', false);
const name = this.selectedObject.data('name');
this.selectedObject.data('name', name);
const bitmask = (
AddressingHelper.decimalStringWithDotToBinary(value).match(new RegExp('1', 'g')) || []
).length;
this.shadowRoot?.querySelector('#bitmask')?.setAttribute('value', bitmask.toString());
} else {
(e.target as SlInput).classList.add('danger');
(e.target as SlInput).classList.remove('success');
(e.target as SlInput).setAttribute('help-text', msg('Invalid netmask.'));
}
}}
></sl-input>
<sl-input
type="number"
max="32"
min="0"
placeholder="${msg('Bitmask')}"
id="bitmask"
value=${network?.data('bitmask')}
@sl-change=${(e: SlChangeEvent) => {
const value = parseInt((e.target as SlInput).value);
const subnet: Net = this.selectedObject.data();
const netmask = AddressingHelper.binaryToDecimalOctets(''.padStart(value, '1').padEnd(32, '0'));
const success = subnet.handleChangesOnNewNetInfo(
subnet.networkAddress.address,
netmask.join('.'),
value,
this
);
this.shadowRoot?.querySelector('#netmask')?.setAttribute('value', netmask.join('.'));
if (success) {
this.selectedObject.toggleClass('unconfigured-net', false);
const name = this.selectedObject.data('name');
this.selectedObject.data('name', name);
(e.target as SlInput).classList.remove('danger');
(e.target as SlInput).classList.add('success');
(e.target as SlInput).setAttribute('help-text', '');
} else {
(e.target as SlInput).classList.add('danger');
(e.target as SlInput).classList.remove('success');
(e.target as SlInput).setAttribute('help-text', msg('Invalid bitmask.'));
}
}}
></sl-input>
</sl-dialog>
`;
}
function handleMacAddressChangeGenerator(this: NetworkComponent, index: string) {
return function handleMacAddressChange(this: NetworkComponent, e: SlChangeEvent) {
const v = (e.target as SlInput).value;
const mac = MacAddress.validateAddress(v, this.macDatabase);
if (mac != null) {
MacAddress.removeAddressFromDatabase(
this.selectedObject.data('portData').get(index).get('MAC'),
this.macDatabase
);
const portData = this.selectedObject.data('portData');
portData.get(index).set('MAC', mac);
this.selectedObject.data('portData', portData);
MacAddress.addAddressToDatabase(mac, this.macDatabase, this.selectedObject.id);
(e.target as SlInput).classList.remove('danger');
(e.target as SlInput).classList.add('success');
(e.target as SlInput).setAttribute('help-text', '');
} else {
(e.target as SlInput).classList.add('danger');
(e.target as SlInput).classList.remove('success');
(e.target as SlInput).setAttribute('help-text', msg('MAC address is invalid.'));
}
};
}
function handleIPv4AddressChangeGenerator(this: NetworkComponent, index: string) {
const subnet = this.selectedObject.isChild() ? this.selectedObject.parent().data() : null;
const gateway: boolean = this.selectedObject.hasClass('gateway-node');
return function handleIPv4AddressChange(this: NetworkComponent, e: SlChangeEvent) {
const v = (e.target as SlInput).value;
const ipv4 = Ipv4Address.validateAddress(v, this.ipv4Database);
if (ipv4 != null) {
if (subnet != null && Net.mode == 'HOST_BASED') {
Net.calculateCIDRGivenNewHost(subnet, ipv4, this.ipv4Database);
this.selectedObject.parent().classes(subnet.cssClass);
}
if (subnet != null && Net.mode == 'NET_BASED' && !ipv4.matchesNetworkCidr(subnet)) {
(e.target as SlInput).classList.add('danger');
(e.target as SlInput).classList.remove('success');
(e.target as SlInput).setAttribute('help-text', msg("Inserted IPv4 doesn't match the subnet mask."));
return;
}
if (gateway) {
// console.log('gateway', this.selectedObject.data(), index);
const affectedNetwork: Net | undefined = (this.selectedObject.data() as Router).portNetMapping.get(
parseInt(index)
);
if (Net.mode == 'HOST_BASED' && affectedNetwork) {
Net.calculateCIDRGivenNewHost(affectedNetwork, ipv4, this.ipv4Database);
this._graph.$('#' + affectedNetwork.id).classes(affectedNetwork.cssClass);
}
if (Net.mode == 'NET_BASED' && affectedNetwork && !ipv4.matchesNetworkCidr(affectedNetwork)) {
(e.target as SlInput).classList.add('danger');
(e.target as SlInput).classList.remove('success');
(e.target as SlInput).setAttribute(
'help-text',
msg("Inserted IPv4 for gateway doesn't match the subnet mask or the network is not configured.")
);
return;
}
}
Ipv4Address.removeAddressFromDatabase(
this.selectedObject.data('portData').get(index).get('IPv4'),
this.ipv4Database
);
const portData = this.selectedObject.data('portData');
portData.get(index).set('IPv4', ipv4);
this.selectedObject.data('portData', portData);
Ipv4Address.addAddressToDatabase(ipv4, this.ipv4Database, this.selectedObject.data('id'));
(e.target as SlInput).classList.remove('danger');
(e.target as SlInput).classList.add('success');
(e.target as SlInput).setAttribute('help-text', '');
} else {
(e.target as SlInput).classList.add('danger');
(e.target as SlInput).classList.remove('success');
(e.target as SlInput).setAttribute('help-text', msg('IPv4 address is invalid.'));
}
};
}
function handleIPv6AddressChangeGenerator(this: NetworkComponent, index: string) {
return function handleIPv6AddressChange(this: NetworkComponent, e: SlChangeEvent) {
const v = (e.target as SlInput).value;
const ipv6 = Ipv6Address.validateAddress(v, this.ipv6Database);
if (ipv6 != null) {
Ipv6Address.removeAddressFromDatabase(
this.selectedObject.data('portData').get(index).get('IPv6'),
this.ipv6Database
);
const portData = this.selectedObject.data('portData');
portData.get(index).set('IPv6', ipv6);
this.selectedObject.data('portData', portData);
Ipv6Address.addAddressToDatabase(ipv6, this.ipv6Database, this.selectedObject.data('id'));
(e.target as SlInput).classList.remove('danger');
(e.target as SlInput).classList.add('success');
(e.target as SlInput).setAttribute('help-text', '');
} else {
(e.target as SlInput).classList.add('danger');
(e.target as SlInput).classList.remove('success');
(e.target as SlInput).setAttribute('help-text', msg('IPv6 address is invalid.'));
}
};
}
function handlePortTypeChangeGenerator(this: NetworkComponent, index: string) {
return function handlePortTypeChange(this: NetworkComponent, e: SlChangeEvent) {
const v = (e.target as SlSelect).value;
const portData = this.selectedObject.data('portData');
portData.get(index).set('Connection Type', v);
this.selectedObject.data('portData', portData);
};
}
function addPort(this: NetworkComponent, node: any) {
const portInfo = new Map();
if (
node.data('cssClass').includes('access-point-node') ||
node.data('cssClass').includes('switch-node') ||
node.data('cssClass').includes('bridge-node')
) {
const mac = MacAddress.generateRandomAddress(this.macDatabase);
portInfo.set('MAC', mac);
}
if (node.data('cssClass').includes('bridge-node') || node.data('cssClass').includes('repeater-node')) {
portInfo.set('Connection Type', 'ethernet');
}
if (node.data('cssClass').includes('router-node') || node.data('cssClass').includes('host-node')) {
const mac = MacAddress.generateRandomAddress(this.macDatabase);
const ipv4 = Ipv4Address.getLoopBackAddress();
const ipv6 = Ipv6Address.getLoopBackAddress();
const name = 'port-' + (node.data('portData').size + 1);
const connectionType = 'ethernet';
portInfo.set('MAC', mac);
portInfo.set('IPv4', ipv4);
portInfo.set('IPv6', ipv6);
portInfo.set('Name', name);
portInfo.set('Connection Type', connectionType);
}
node.data('portData').set(node.data('portData').size + 1, portInfo);
node.data('portLinkMapping').set(node.data('portLinkMapping').size + 1, null);
node.data('numberOfInterfacesOrPorts', node.data('numberOfInterfacesOrPorts') + 1);
this.requestUpdate();
}
function removePort(this: NetworkComponent, node: any, index: string) {
const ipv4 = node.data('portData').get(index).get('IPv4');
if (ipv4 != null) Ipv4Address.removeAddressFromDatabase(ipv4, this.ipv4Database);
const ipv6 = node.data('portData').get(index).get('IPv6');
if (ipv6 != null) Ipv6Address.removeAddressFromDatabase(ipv6, this.ipv6Database);
const mac = node.data('portData').get(index).get('MAC');
if (mac != null) MacAddress.removeAddressFromDatabase(mac, this.macDatabase);
node.data('portData').delete(index);
node.data('portLinkMapping').delete(index);
node.data('numberOfInterfacesOrPorts', node.data('numberOfInterfacesOrPorts') - 1);
this.requestUpdate();
}
function updatePortLink(this: NetworkComponent) {
const edge = this.selectedObject;
const inPort = this.selectedPorts['source'].port || 0;
const outPort = this.selectedPorts['target'].port || 0;
const sourceNode = edge.source().data();
const targetNode = edge.target().data();
const newData = configurePorts.bind(this)(edge.data(), inPort, outPort);
console.log(newData);
if (newData != null) {
edge.removeClass('unconfigured-edge');
edge.addClass(newData.cssClass);
} //set new format-display for this connection if no error appears
SubnettingController.setUpGateway(
this._graph.$('#' + sourceNode.id),
this._graph.$('#' + targetNode.id),
inPort,
this.ipv4Database
);
SubnettingController.setUpGateway(
this._graph.$('#' + targetNode.id),
this._graph.$('#' + sourceNode.id),
outPort,
this.ipv4Database
);
}
function configurePorts(this: NetworkComponent, edge: GraphEdge, inPort: number, outPort: number): GraphEdge {
let inPortData: Map<string, any> = edge.from.portData.get(inPort);
let outPortData: Map<string, any> = edge.to.portData.get(outPort);
if (inPortData.get('Connection Type') == 'wireless' && outPortData.get('Connection Type') == 'wireless') {
edge.cssClass.push('wireless-edge');
} else if (
(inPortData.get('Connection Type') == 'wireless' && outPortData.get('Connection Type') == 'ethernet') ||
(inPortData.get('Connection Type') == 'ethernet' && outPortData.get('Connection Type') == 'wireless')
) {
AlertHelper.toastAlert(
'danger',
'exclamation-triangle',
msg('The connection type of assigned ports are not compatible!'),
msg('Please re-assign your ports or dismiss this connection.')
);
return null;
} else {
edge.cssClass.push('wired-edge');
}
edge.cssClass.push('labelled-edge');
let index;
if ((index = edge.cssClass.indexOf('unconfigured-edge')) > -1) edge.cssClass.splice(index, 1);
console.log(edge);
const nodeFrom = this._graph.getElementById(edge.source);
const nodeTo = this._graph.getElementById(edge.target);
const fromMap = new Map(nodeFrom.data('portLinkMapping'));
const toMap = new Map(nodeTo.data('portLinkMapping'));
fromMap.set(inPort, edge.id);
toMap.set(outPort, edge.id);
nodeFrom.data('portLinkMapping', fromMap);
nodeTo.data('portLinkMapping', toMap);
const netEdge = this._graph.getElementById(edge.id);
netEdge.data('inPort', inPort);
netEdge.data('outPort', outPort);
return edge;
//check if one node belongs to a net, if yes --> other node must be a router
}
function isPortConnected(this: NetworkComponent, node: any, port: string): boolean {
return node.data('portLinkMapping').get(port) != null;
}
function nodeRoutingTableTemplate(this: NetworkComponent): TemplateResult {
const node: any = this.selectedObject;
const routingTable = node.data('routingTable');
const arpTable = node.data('arpTableIpMac');
const macAddressTable = node.data('macAddressTable');
console.log(node);
return html`
<div id="contextMenu" class="contextmenu" @contextmenu=${(e: Event) => e.preventDefault()} style="display:none">
<sl-tab-group>
${arpTable ? html`<sl-tab slot="nav" panel="arp">${msg('Arp Table')}</sl-tab>` : ''}
${routingTable ? html`<sl-tab slot="nav" panel="routing">${msg('Routing Table')}</sl-tab>` : ''}
${macAddressTable ? html`<sl-tab slot="nav" panel="mac">${msg('Mac Address Table')}</sl-tab>` : ''}
${arpTable
? html`
<sl-tab-panel name="arp">
<table>
<tr>
<th>IP</th>
<th>MAC</th>
</tr>
${Array.from(arpTable.entries()).map((entry) => {
return html`
<tr>
<td>${entry[0]}</td>
<td>${entry[1]}</td>
</tr>
`;
})}
</table>
</sl-tab-panel>
`
: html``}
${routingTable
? html`
<sl-tab-panel name="routing">
<table>
<tr>
<th>${msg('Net')}</th>
<th>${msg('Gateway')}</th>
</tr>
${Array.from(routingTable.entries()).map((entry) => {
return html`
<tr>
<td>${entry[0]}</td>
<td>${entry[1].gateway}</td>
</tr>
`;
})}
</table>
</sl-tab-panel>
`
: html``}
${macAddressTable
? html`
<sl-tab-panel name="mac">
<table>
<tr>
<th>MAC</th>
<th>Port</th>
</tr>
${Array.from(macAddressTable.entries()).map((entry) => {
return html`
<tr>
<td>${entry[0]}</td>
<td>${entry[1]}</td>
</tr>
`;
})}
</table>
</sl-tab-panel>
`
: html``}
</sl-tab-group>
</div>
`;
}