GonetsDocs/Documentation/Описание работы c сетевыми интерфейсами.md

387 lines
24 KiB
Markdown
Raw Normal View History

2025-10-09 14:10:56 +05:00
# Описание работы c сетевыми интерфейсами
На данный момент главным рабочим модулем приложения является модуль работы с сетевыми интерфейсами. Данный модуль позволяет отображать сетевые интерфейсы хоста в графическом виде и управлять IP адресами интерфейсов. В основе работы модуля лежит достаточно большая библиотека ReactFlow, которая позволяет строить различные графы по средством блоков и связей между ними. Далее для удобства блоки будут называться нодами (node), связи эджами (edge), а само поле ReactFlow холстом
### 1\. Подключение модуля в рабочее пространство
Работа модуля начинается с файла /src/components/workSpace/workspace.tsx, здесь в рабочее пространство приложения подключаются сами модули.
```
{workModule === workSpaceNames[3] &&
<WorkSection>
<Header />
<ReactFlowProvider>
<NetworkInterfaces
key={currentWs}
startConnection={true}
ws={currentWs}
/>
</ReactFlowProvider>
</WorkSection>
}
```
В данном блоке этого файла подключается модуль сетевых интерфейсов в рабочее пространство. Из localstorage берётся название текущего модуля, который должен быть подключён, в этом случаи это ‘networkInterfaces‘ и по названию определяется необходимый модуль.
Здесь
&lt;Header/&gt; - это верхняя панель для управления холстом
&lt;NetWorkInterfaces/&gt; - Сам компонент работы с сетевыми интерфейсами, в нём пропсы key - ключ компонента, будет равен текущему ip хоста, startConnection - флаг, при передачи которого начинается работа компонента, ws - передача ip текущего хоста для создания WebSocket подключения
### 2\. Компонент NetworkInterfaces
Рассмотрение компонента логично начать с обзора его переменных состояния, которых в этом компоненте присутствует немало.
#### 2.1. Переменные состояния компонента NetworkInterfaces
1. initializationAttempt
- Тип: React.useRef&lt;number&gt;
- Описание: Счетчик попыток инициализации данных, хранящийся в useRef. Используется для отслеживания статуса начальной загрузки нод и эджей. Начальное значение — 0. После успешной инициализации устанавливается в 1. Позволяет избежать повторных попыток инициализации или перезагрузки страницы при сбоях.
2. requestError
- Тип: { status: boolean, message: string }
- Описание: Состояние для отслеживания ошибок при установлении WebSocket-соединения или загрузке данных. Содержит флаг status (true, если ошибка произошла) и поле message с текстом ошибки (например, "Соединение с сервером разорвано" или "Превышено время ожидания"). Используется для отображения ошибок через модальное окно.
3. { openModal, closeLoader }
- Тип: Методы из useModalContext
- Описание: Функции, полученные из контекста ModalWindowContext, для управления модальными окнами. openModal открывает модальное окно с указанным типом и параметрами (например, для отображения ошибок или уведомлений о загрузке). closeLoader закрывает экран загрузки после завершения инициализации данных.
4. loader
- Тип: boolean
- Описание: Флаг, управляющий отображением экрана загрузки. Изначально установлен в true, что указывает на процесс загрузки данных. После успешной инициализации нод и эджей устанавливается в false, и экран загрузки скрывается с помощью closeLoader.
5. socket
- Тип: WebSocket | null
- Описание: Состояние для хранения объекта WebSocket, используемого для связи с сервером по адресу ws://192.168.1.147:8001/api/v1. Изначально null. После успешного подключения сохраняет экземпляр WebSocket, позволяя отправлять и получать данные о сетевых интерфейсах.
6. data
- Тип: ResponseData\[\]
- Описание: Массив данных, полученных через WebSocket. Содержит два элемента: данные об активных (activation) и неактивных (deactivation) сетевых интерфейсах. Используется как источник для преобразования в ноды и эджи для отображения на холсте ReactFlow.
7. wifiData
- Тип: ResponseNetwork | undefined
- Описание: Состояние для хранения информации о Wi-Fi интерфейсе, извлеченной из активных данных (activation). Обновляется, если в полученных данных присутствует интерфейс с типом WIFI. Используется для специфической обработки и отображения Wi-Fi нод на холсте.
8. hasInited
- Тип: boolean
- Описание: Флаг, указывающий, были ли данные (ноды и эджи) успешно инициализированы. Изначально false. Устанавливается в true после первичной обработки данных и вызова handleInit из useInitCanvas, чтобы предотвратить повторную инициализацию.
9. { initedNodes, initedEdges, handleInit }
- Тип: Значения и метод из useInitCanvas
- Описание: Данные и функция из пользовательского хука useInitCanvas. initedNodes и initedEdges содержат инициализированные ноды и эджи, подготовленные для отображения на холсте. handleInit выполняет начальную обработку edgeData и interfaces для создания этих структур.
10. interfaces
- Тип: Interfaces\[\]
- Описание: Состояние для хранения преобразованных данных о сетевых интерфейсах, полученных из data с помощью функции initNetworkIntData. Содержит структурированные объекты, описывающие интерфейсы, в формате, удобном для построения нод на холсте ReactFlow.
11. edgeData
- Тип: IEdge\[\]
- Описание: Состояние для хранения преобразованных данных о связях (эджи) между сетевыми интерфейсами, полученных из data с помощью initNetworkIntData. Используется как промежуточный формат перед финальной инициализацией эджей для отображения.
12. nodes
- Тип: Массив нод для ReactFlow
- Описание: Состояние, управляемое хуком useNodesState, для хранения и отображения нод (блоков) на холсте ReactFlow. Инициализируется пустым массивом и заполняется данными из initedNodes после обработки. Обновляется при изменении позиций, групп или Wi-Fi данных.
13. edges
- Тип: Массив эджей для ReactFlow
- Описание: Состояние, управляемое хуком useEdgesState, для хранения и отображения связей (эджей) между нодами на холсте ReactFlow. Изначально пустой массив, заполняется из initedEdges после инициализации и обновляется при добавлении новых связей.
14. isPanDisabled
- Тип: boolean
- Описание: Флаг, полученный из хука usePannableStore, определяющий, отключена ли возможность перемещения (прокрутки) холста ReactFlow. Если true, пользователь не может перемещать холст, что полезно для фиксации вида при определенных действиях.
15. changeArray
- Тип: any\[\]
- Описание: Массив для временного хранения изменений позиций нод, полученных через processNodeChanges. Накапливает данные о перемещениях, которые затем отправляются на сервер через autosavePosition с интервалом в 1 секунду для сохранения позиций.
16. groups
- Тип: Данные из useGroupStore
- Описание: Состояние, полученное из хука useGroupStore, содержащее информацию о группах сетевых интерфейсов (например, активные и неактивные). Используется для сортировки и сворачивания/разворачивания групп нод на холсте с помощью groupSort и collapseGroup.
17. { isNullPos, setNullPos }
- Тип: Значения и метод из usePosStore
- Описание: Состояние и функция из хука usePosStore. isNullPos — флаг, указывающий, нужно ли сбросить позиции нод. setNullPos — метод для управления этим флагом. При активации сбрасывает позиции нод через resetPosition, отправляя запрос по WebSocket.
#### 2.2. Методы
Функции и эффекты
1. Первый useEffect — Подключение к WebSocket
```jsx
useEffect(() => {
if (startConnection) {
openModal(ModalMap['2'], 'Идет загрузка данных');
setNodes([]);
setEdges([]);
setHasInited(false);
initializationAttempt.current = 0;
const newSocket = new WebSocket(`ws://192.168.1.147:8001/api/v1`);
let connectionTimeout;
setSocket(newSocket);
connectionTimeout = setTimeout(() => {
if (newSocket.readyState !== WebSocket.OPEN) {
newSocket.close();
}
}, 5000);
newSocket.onopen = () => {
console.log('WebSocket connection established');
};
newSocket.onmessage = (event) => {
const newData = JSON.parse(event.data);
setData(() => [newData.activation, newData.deactivation]);
};
newSocket.onerror = (error) => {
console.error('WebSocket error:', error);
};
newSocket.onclose = () => {
console.log('WebSocket connection closed');
setRequestError({ status: true, message: 'Соединение с сервером разорвано' });
};
return () => {
newSocket.close();
closeLoader();
};
}
}, [startConnection, ws]);
```
- Условие: Срабатывает при изменении startConnection или ws.
- Логика: Открывает модальное окно загрузки, сбрасывает ноды, эджи и флаги. Создает WebSocket, устанавливает тайм-аут (5 сек) для проверки соединения. Обрабатывает открытие, получение данных, ошибки и закрытие.
- Очистка: Закрывает WebSocket и загрузчик.
- Цель: Установить связь с сервером и получить данные.
2. Второй useEffect — Обработка данных из WebSocket
```jsx
useEffect(() => {
if (data.length > 0) {
const { interfaces: newInterfaces, edgeData: newEdgeData } = initNetworkIntData(data);
const activationData = data[0].interfaces;
const wifi = activationData.find((el: any) => el.type === 'WIFI');
setInterfaces(newInterfaces);
setEdgeData(newEdgeData);
if (wifi) { setWifi(wifi); }
}
}, [data]);
```
- Условие: Срабатывает при изменении data.
- Логика: Преобразует data в interfaces и edgeData через initNetworkIntData. Ищет Wi-Fi интерфейс в активных данных, обновляет состояния.
- Цель: Подготовить данные для холст.
3. Третий useEffect — Инициализация нод и эджей
```jsx
useEffect(() => {
if (interfaces.length > 0 && !hasInited) {
handleInit(edgeData, interfaces);
setHasInited(true);
}
}, [interfaces, edgeData, hasInited]);
```
- Условие: Срабатывает при изменении interfaces, edgeData, hasInited.
- Логика: Если данные есть и инициализация не выполнена, вызывает handleInit для подготовки нод и эджей, затем устанавливает hasInited в true.
- Цель: Инициализировать холст.
4. Четвертый useEffect — Мониторинг инициализации
```jsx
useEffect(() => {
if (initializationAttempt.current === 0 && !requestError.status) {
const checkInterval = setInterval(() => {
setTimeout(() => {
if (!initedNodes.some(node => node.id === 'g0_nw0_rx0_ip0')) {
window.location.reload();
}
}, 500);
if (initedNodes.length > 0 && initedEdges.length > 0) {
setNodes(initedNodes);
setEdges(initedEdges);
console.log("Ноды и эджи успешно инициализированы");
initializationAttempt.current = 1;
clearInterval(checkInterval);
clearTimeout(timeoutId);
} else {
console.log("Попытка инициализации нод и эджей...");
}
}, 1000);
const timeoutId = setTimeout(() => {
console.error("Ошибка: слишком долгая загрузка данных");
clearInterval(checkInterval);
setRequestError({ status: true, message: 'Превышено время ожидания' });
}, 30000);
return () => {
clearInterval(checkInterval);
clearTimeout(timeoutId);
};
}
}, [initedNodes, initedEdges, requestError]);
```
- Условие: Срабатывает при изменении initedNodes, initedEdges, requestError.
- Логика: Проверяет каждую секунду наличие инициализированных данных. Через 500 мс проверяет ключевую ноду; если нет — перезагрузка. При успехе обновляет nodes, edges, логирует, останавливает проверки. Тайм-аут (30 сек) фиксирует ошибку.
- Очистка: Удаляет интервал и тайм-аут.
- Цель: Гарантировать успешную инициализацию.
5. Пятый useEffect — Обновление счетчика попыток
```jsx
useEffect(() => {
if (nodes.length === 0) {
initializationAttempt.current = 0;
} else {
initializationAttempt.current = 1;
}
}, [nodes]);
```
- Условие: Срабатывает при изменении nodes.
- Логика: Сбрасывает initializationAttempt в 0, если нод нет, иначе устанавливает 1.
- Цель: Отслеживать состояние инициализации.
6. Шестой useEffect — Управление загрузчиком
```jsx
useEffect(() => {
if (nodes.length > 0 && loader == true) {
setLoader(false);
closeLoader();
}
}, [nodes, loader]);
```
- Условие: Срабатывает при изменении nodes, loader.
- Логика: Если ноды есть и загрузчик активен, скрывает его.
- Цель: Убрать экран загрузки после рендера.
7. Функция onEdgesChange
```jsx
const onEdgesChange = useCallback(
(changes: any) => setEdges((eds) => applyEdgeChanges(changes, eds)),
[setEdges]
);
```
- Тип: useCallback
- Вход: changes — массив изменений эджей.
- Логика: Применяет изменения к эджам через applyEdgeChanges, обновляет edges.
- Цель: Обработать изменения связей.
8. Функция onConnect
```jsx
const onConnect = useCallback(
(connection: any) => setEdges((eds) => addEdge(connection, eds)),
[setEdges]
);
```
- Тип: useCallback
- Вход: connection — объект новой связи.
- Логика: Добавляет связь через addEdge, обновляет edges.
- Цель: Создавать новые связи на холсте.
9. Функция handleNodesChange
```jsx
const handleNodesChange = (changes: any) => {
onNodesChange(changes);
const newData = processNodeChanges(changes, data);
if (newData) {
setChangeArray((prevArray) => [...prevArray, newData]);
}
};
```
- Вход: changes — массив изменений нод.
- Логика: Обновляет ноды через onNodesChange, извлекает изменения позиций через processNodeChanges, добавляет в changeArray.
- Цель: Отслеживать перемещения нод.
10. Седьмой useEffect — Автосохранение позиций
```jsx
useEffect(() => {
const interval = setInterval(() => {
if (socket && socket.readyState === WebSocket.OPEN) {
autosavePosition(changeArray, socket);
}
setChangeArray([]);
}, 1000);
return () => {
clearInterval(interval);
};
}, [changeArray, socket]);
```
- Условие: Срабатывает при изменении changeArray, socket.
- Логика: Каждую секунду отправляет изменения позиций через autosavePosition, очищает changeArray.
- Очистка: Удаляет интервал.
- Цель: Сохранять позиции на сервере.
11. Восьмой useEffect — Обработка групп
```jsx
useEffect(() => {
const sortedGroups = groupSort(groups, nodes);
setNodes(collapseGroup(sortedGroups, nodes));
}, [groups]);
```
- Условие: Срабатывает при изменении groups.
- Логика: Сортирует ноды по группам через groupSort, сворачивает/разворачивает через collapseGroup, обновляет nodes.
- Цель: Организовать ноды по группам.
12. Девятый useEffect — Обновление Wi-Fi
```jsx
useEffect(() => {
if (wifiData) {
setNodes(updateWifiData(wifiData, nodes));
}
}, [wifiData]);
```
- Условие: Срабатывает при изменении wifiData.
- Логика: Обновляет ноды с учетом Wi-Fi через updateWifiData.
- Цель: Отобразить Wi-Fi данные.
13. Десятый useEffect — Обработка ошибок
```jsx
useEffect(() => {
if (requestError.status) {
setTimeout(() => {
openModal(ModalMap['3'], { message: requestError.message });
}, 1000);
}
}, [requestError]);
```
- Условие: Срабатывает при изменении requestError.
- Логика: При ошибке через 1 сек открывает модальное окно с сообщением.
- Цель: Уведомить об ошибках.
14. Одиннадцатый useEffect — Сброс позиций
```jsx
useEffect(() => {
if (isNullPos) {
if (socket && socket.readyState === WebSocket.OPEN) {
resetPosition(socket, setNullPos, nodes, setNodes);
}
}
}, [isNullPos]);
```
- Условие: Срабатывает при изменении isNullPos.
- Логика: При истинном isNullPos сбрасывает позиции через resetPosition, обновляет ноды.
- Цель: Вернуть исходные позиции.
#### 2.3. Рендеринг
```jsx
return (
<>
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={handleNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
style={{ background: '#F7F9FB' }}
minZoom={0}
maxZoom={4}
fitView
fitViewOptions={{ padding: 0.1 }}
attributionPosition="bottom-left"
snapToGrid
snapGrid={[20, 20]}
panOnDrag={!isPanDisabled}
nodeTypes={nodeTypes}
proOptions={proOptions}
>
<Background gap={20} size={1} bgColor={theme.background} />
<Controls fitViewOptions={{ padding: 0.1 }} />
</ReactFlow>
</>
);
```
- Компонент: ReactFlow рендерит холст.
- Параметры: Ноды, эджи, обработчики, фон, зум (0–4), сетка (20x20), перетаскивание по isPanDisabled, кастомные ноды.
- Дочерние: Background (сетка), Controls (кнопки для управления зумом).