Глава 6: Передача данных

6.1 Двунаправленный поток данных

DTP поддерживает передачу данных в обоих направлениях без взаимного влияния:

НаправлениеНазваниеОписание
Terminal → FayСбор данныхПостоянное сохранение данных, произведённых терминалом, в Personal Data Heap
Fay → TerminalИнъекция данныхМинимизированный набор данных, отфильтрованный и оценённый iFay

Оба направления используют одинаковый формат LogicalFrame и процесс обработки, но поддерживают независимые пространства порядковых номеров и состояния возобновления.

6.2 Поток сбора данных (Terminal → Fay)

Полный поток сбора данных проходит следующие этапы:

Terminal Application
  │
  ▼ Отправка данных
DTP_Slave Engine
  │ 1. Прикрепление контекстных метаданных
  │ 2. Построение LogicalFrame (Header + Payload)
  │ 3. Шифрование Payload
  │ 4. Сериализация LogicalFrame
  │
  ▼ send(binary_data)
Transport_Adapter
  │
  ▼ onReceive(binary_data)
DTP_Master Engine
  │ 1. Десериализация LogicalFrame
  │ 2. Валидация Agreement_ID
  │ 3. Дешифрование Payload
  │ 4. Валидация DAG-зависимостей
  │ 5. Обновление порядкового номера + отправка подтверждения
  │
  ▼ Сохранение
Personal Data Heap

6.3 Поток инъекции данных (Fay → Terminal)

Полный поток инъекции данных проходит следующие этапы:

Personal Data Heap
  │
  ▼ Запрос и фильтрация данных
DTP_Master Engine
  │ 1. Построение Fragment + контекстные метаданные
  │ 2. Построение LogicalFrame
  │ 3. Шифрование Payload
  │ 4. Сериализация LogicalFrame
  │
  ▼ send(binary_data)
Transport_Adapter
  │
  ▼ onReceive(binary_data)
DTP_Slave Engine
  │ 1. Десериализация LogicalFrame
  │ 2. Валидация Agreement_ID
  │ 3. Дешифрование Payload
  │ 4. Обновление порядкового номера + отправка подтверждения
  │
  ▼ Доставка данных
Terminal Application

6.4 Сжатая передача Agreement_ID

Для снижения накладных расходов на передачу DTP поддерживает сжатую передачу Agreement_ID:

  • Когда последовательные Fragment принадлежат одному соглашению, только первый Fragment в пакете несёт полный Agreement_ID в заголовке
  • У последующих Fragment поле agreementId установлено в null, что означает наследование предыдущего

Правила обработки получателем:

  1. Получен Fragment с Agreement_ID → Обновить Agreement_ID текущего контекста
  2. Получен Fragment без Agreement_ID → Ассоциировать с последним объявленным Agreement_ID в текущем контексте
  3. Получен Fragment, ссылающийся на неизвестный Agreement_ID → Отбросить и отправить уведомление об ошибке

Пример:

Fragment 1: agreementId = "abc-123"  ← Полный ID
Fragment 2: agreementId = null       ← Наследует "abc-123"
Fragment 3: agreementId = null       ← Наследует "abc-123"
Fragment 4: agreementId = "def-456"  ← Новое соглашение, полный ID
Fragment 5: agreementId = null       ← Наследует "def-456"

6.5 Управление порядковыми номерами

Монотонное возрастание

Каждый Fragment несёт порядковый номер передачи (Sequence_Number), монотонно возрастающий в рамках одной сессии.

Двунаправленная независимость

Направление сбора данных и направление инъекции данных поддерживают полностью независимые пространства порядковых номеров:

Направление сбора данных:   seq 1, 2, 3, 4, 5 ...
Направление инъекции данных: seq 1, 2, 3, 4, 5 ...

Изменения порядковых номеров в одном направлении не влияют на другое направление.

6.6 Сохранение временной метки происхождения

DTP гарантирует, что временная метка происхождения (Origin_Timestamp) каждого Fragment остаётся неизменной на протяжении всего процесса передачи:

  • Фиксирует момент фактического создания данных в источнике, а не момент передачи
  • Использует часовой пояс UTC с миллисекундной точностью
  • После сериализации, шифрования, передачи, дешифрования и десериализации временная метка остаётся идентичной значению до отправки
  • Получатель сохраняет оригинальный Origin_Timestamp без модификации

Это гарантирует, что даже при загрузке данных с задержкой (например, в офлайн-сценариях) iFay может восстановить истинную временную шкалу.

6.7 Валидация DAG-зависимостей

Получатель выполняет валидацию DAG-зависимостей при получении Fragment:

  1. Обнаружение циклов: проверяет, что зависимости нового Fragment не формируют цикл в DAG. При обнаружении цикла Fragment отклоняется
  2. Разрешение зависимостей: если целевой Fragment зависимости ещё не прибыл, текущий Fragment помечается как «зависимость ожидает разрешения» и кэшируется
  3. Отложенное разрешение: когда зависимый Fragment прибывает, ранее кэшированные Fragment автоматически разрешаются