GonetsDocs/ПРИЛОЖЕНИЕ ГоNETS Материалы/Описание работы c сетевыми интерфейсами.md
2025-10-09 14:10:56 +05:00

387 lines
No EOL
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Описание работы 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 (кнопки для управления зумом).