GonetsDocs/Документация/Описание работы c сетевыми интерфейсами.md
2025-10-09 14:18:10 +05:00

24 KiB
Raw Blame History

Описание работы 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‘ и по названию определяется необходимый модуль.

Здесь

<Header/> - это верхняя панель для управления холстом

<NetWorkInterfaces/> - Сам компонент работы с сетевыми интерфейсами, в нём пропсы key - ключ компонента, будет равен текущему ip хоста, startConnection - флаг, при передачи которого начинается работа компонента, ws - передача ip текущего хоста для создания WebSocket подключения

2. Компонент NetworkInterfaces

Рассмотрение компонента логично начать с обзора его переменных состояния, которых в этом компоненте присутствует немало.

2.1. Переменные состояния компонента NetworkInterfaces

  1. initializationAttempt
    • Тип: React.useRef<number>
    • Описание: Счетчик попыток инициализации данных, хранящийся в 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

    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

    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 — Инициализация нод и эджей

    useEffect(() => {
      if (interfaces.length > 0 && !hasInited) {
        handleInit(edgeData, interfaces);
        setHasInited(true);
      }
    }, [interfaces, edgeData, hasInited]);
    
    • Условие: Срабатывает при изменении interfaces, edgeData, hasInited.
    • Логика: Если данные есть и инициализация не выполнена, вызывает handleInit для подготовки нод и эджей, затем устанавливает hasInited в true.
    • Цель: Инициализировать холст.
  4. Четвертый useEffect — Мониторинг инициализации

    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 — Обновление счетчика попыток

    useEffect(() => {
      if (nodes.length === 0) {
        initializationAttempt.current = 0;
      } else {
        initializationAttempt.current = 1;
      }
    }, [nodes]);
    
    • Условие: Срабатывает при изменении nodes.
    • Логика: Сбрасывает initializationAttempt в 0, если нод нет, иначе устанавливает 1.
    • Цель: Отслеживать состояние инициализации.
  6. Шестой useEffect — Управление загрузчиком

    useEffect(() => {
      if (nodes.length > 0 && loader == true) {
        setLoader(false);
        closeLoader();
      }
    }, [nodes, loader]);
    
    • Условие: Срабатывает при изменении nodes, loader.
    • Логика: Если ноды есть и загрузчик активен, скрывает его.
    • Цель: Убрать экран загрузки после рендера.
  7. Функция onEdgesChange

    const onEdgesChange = useCallback(
      (changes: any) => setEdges((eds) => applyEdgeChanges(changes, eds)),
      [setEdges]
    );
    
    • Тип: useCallback
    • Вход: changes — массив изменений эджей.
    • Логика: Применяет изменения к эджам через applyEdgeChanges, обновляет edges.
    • Цель: Обработать изменения связей.
  8. Функция onConnect

    const onConnect = useCallback(
      (connection: any) => setEdges((eds) => addEdge(connection, eds)),
      [setEdges]
    );
    
    • Тип: useCallback
    • Вход: connection — объект новой связи.
    • Логика: Добавляет связь через addEdge, обновляет edges.
    • Цель: Создавать новые связи на холсте.
  9. Функция handleNodesChange

    const handleNodesChange = (changes: any) => {
      onNodesChange(changes);
      const newData = processNodeChanges(changes, data);
      if (newData) {
        setChangeArray((prevArray) => [...prevArray, newData]);
      }
    };
    
    • Вход: changes — массив изменений нод.
    • Логика: Обновляет ноды через onNodesChange, извлекает изменения позиций через processNodeChanges, добавляет в changeArray.
    • Цель: Отслеживать перемещения нод.
  10. Седьмой useEffect — Автосохранение позиций

    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 — Обработка групп

    useEffect(() => {
      const sortedGroups = groupSort(groups, nodes);
      setNodes(collapseGroup(sortedGroups, nodes));
    }, [groups]);
    
    • Условие: Срабатывает при изменении groups.
    • Логика: Сортирует ноды по группам через groupSort, сворачивает/разворачивает через collapseGroup, обновляет nodes.
    • Цель: Организовать ноды по группам.
  12. Девятый useEffect — Обновление Wi-Fi

    useEffect(() => {
      if (wifiData) {
        setNodes(updateWifiData(wifiData, nodes));
      }
    }, [wifiData]);
    
    • Условие: Срабатывает при изменении wifiData.
    • Логика: Обновляет ноды с учетом Wi-Fi через updateWifiData.
    • Цель: Отобразить Wi-Fi данные.
  13. Десятый useEffect — Обработка ошибок

    useEffect(() => {
      if (requestError.status) {
        setTimeout(() => {
          openModal(ModalMap['3'], { message: requestError.message });
        }, 1000);
      }
    }, [requestError]);
    
    • Условие: Срабатывает при изменении requestError.
    • Логика: При ошибке через 1 сек открывает модальное окно с сообщением.
    • Цель: Уведомить об ошибках.
  14. Одиннадцатый useEffect — Сброс позиций

    useEffect(() => {
      if (isNullPos) {
        if (socket && socket.readyState === WebSocket.OPEN) {
          resetPosition(socket, setNullPos, nodes, setNodes);
        }
      }
    }, [isNullPos]);
    
    • Условие: Срабатывает при изменении isNullPos.
    • Логика: При истинном isNullPos сбрасывает позиции через resetPosition, обновляет ноды.
    • Цель: Вернуть исходные позиции.

2.3. Рендеринг

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