Skip to content

Device Discovery & Peer Lifecycle

Система обнаружения устройств в локальной сети работает на трёх уровнях, каждый из которых надстраивается над предыдущим:

УровеньМеханизмФайлЧто делает
1. ТранспортныйmDNS (libp2p)p2p/network.rsОбнаружение IP-адресов в LAN
2. ИдентификационныйAnnounce (sharing)sharing/libp2p_sharing.rsОбмен identity + device info
3. LivenessPing/Pong heartbeatsharing/manager.rsOnline/offline статус (30s/90s)

Уровень 1: mDNS Discovery

backend/src/p2p/network.rs — базовый P2P слой на libp2p.

При старте приложение слушает на /ip4/0.0.0.0/tcp/0 (все интерфейсы, случайный порт) и запускает mDNS behaviour. Когда новый пир появляется в сети, libp2p генерирует mdns::Event::Discovered, а при исчезновении (таймаут ~120с) — mdns::Event::Expired.

На этом уровне эмитятся низкоуровневые события peer_added / peer_removed и обновляется счётчик пиров в SharedState.peers.

plantuml Diagram

Уровень 2: Announce — идентификация пира

backend/src/sharing/libp2p_sharing.rs + backend/src/sharing/manager.rs

После установки TCP-соединения (libp2p dial), инициатор отправляет сообщение SharingMessage::Announce с полной информацией о себе: identity_id, display_name, public_key, device_id, device_name, storage info, IP. Получатель сохраняет информацию в known_peers HashMap и генерирует SharingServiceEvent::PeerDiscovered.

Менеджер обрабатывает PeerDiscovered:

  • Сохраняет KnownPeerInfo в known_peers
  • Обновляет storage и IP в БД через DeviceManager
  • Эмитит peer_online для фронтенда
  • Если пир с той же identity — запускает автосинхронизацию (StateDigest + DeviceSync + auto-publish spaces)
plantuml Diagram

Уровень 3: Heartbeat — online/offline статус

backend/src/sharing/manager.rs — каждые 30 секунд отправляет Ping всем known peers, ожидает Pong. Если пир не отвечает 90 секунд — считается offline.

plantuml Diagram

Pairing Discovery — обнаружение для спаривания

Помимо sharing-уровня, существует отдельный Discovery Service для процесса паринга — backend/src/pairing/manager.rs + backend/src/pairing/libp2p_pairing.rs.

Он использует свой собственный libp2p swarm с request-response протоколом. Три типа сообщений:

СообщениеНазначение
DiscoveryОбъявление identity + device name
InitiateЗапрос на паринг (PIN + полные данные identity/device)
ConfirmПодтверждение паринга с данными подтверждающей стороны
plantuml Diagram

Полный жизненный цикл пира

plantuml Diagram

Таймауты

ПараметрЗначениеГде
mDNS announce interval~20s (libp2p default)libp2p mdns config
mDNS expiration~120slibp2p mdns
Ping interval30ssharing/manager.rs
Stale peer threshold90ssharing/manager.rs
Idle connection timeout (sharing)120ssharing/libp2p_sharing.rs
Idle connection timeout (pairing)60-300spairing/libp2p_pairing.rs
Pairing session timeout5 минpairing/manager.rs

События для фронтенда

СобытиеКогдаДанные
peer_addedmDNS обнаружил пир{peer_id, count}
peer_removedmDNS таймаут пира{peer_id}
peer_onlineAnnounce/Pong получен{device_id, device_name, identity_id, storage}
peer_offline90s без Pong{device_id, device_name}
sharing_peer_discoveredПервый AnnounceПолная информация о пире
devices_updatedDeviceSync полученСписок устройств обновлён

Структуры данных

KnownPeerInfo (in-memory)

rust
pub struct KnownPeerInfo {
    peer_id: String,                // libp2p PeerId
    identity_id: String,
    identity_display_name: String,
    identity_public_key: Vec<u8>,
    device_name: String,
    device_id: String,              // Hash of public key
}

DiscoveredDevice (pairing)

rust
pub struct DiscoveredDevice {
    pub peer_id: String,
    pub device_name: String,
    pub identity_id: String,
    pub identity_display_name: String,
    pub address: String,            // IP from mDNS
    pub port: u16,
    pub discovered_at: u64,         // Unix timestamp
}

devices table (SQLite)

sql
CREATE TABLE devices (
    id TEXT PRIMARY KEY,        -- device_id (hash of public key)
    name TEXT,
    device_type TEXT,
    identity_id TEXT,
    public_key BLOB,
    peer_id TEXT,
    last_seen INTEGER,          -- updated on peer_online
    ip TEXT,                    -- from Announce message
    storage_used INTEGER,
    storage_total INTEGER,
    storage_unit TEXT,
    os TEXT,
    is_current INTEGER
);