Глава 4: Структура логического фрейма

4.1 Состав фрейма

LogicalFrame — это структура фрейма прикладного уровня DTP, состоящая из двух частей:

┌─────────────────────────────────────────┐
│              Logical_Frame               │
├─────────────────────────────────────────┤
│  Header                                  │
│  ┌─────────────────────────────────────┐│
│  │ protocolVersion   Версия протокола   ││
│  │ frameType         ID типа фрейма     ││
│  │ fragmentId        Уникальный ID      ││
│  │                   Fragment           ││
│  │ agreementId       ID соглашения      ││
│  │                   (сжимаемый)        ││
│  │ originTimestamp   Временная метка    ││
│  │                   происхождения      ││
│  │ dagDependencies   Список             ││
│  │                   DAG-зависимостей   ││
│  │ encryptionMetadata Метаданные        ││
│  │                   шифрования         ││
│  │ sequenceNumber    Порядковый номер   ││
│  └─────────────────────────────────────┘│
├─────────────────────────────────────────┤
│  Payload                                 │
│  ┌─────────────────────────────────────┐│
│  │ Зашифрованное фактическое           ││
│  │ содержимое данных                    ││
│  └─────────────────────────────────────┘│
└─────────────────────────────────────────┘

Ключевые проектные решения:

  • Метаданные шифрования в заголовке не шифруются, чтобы получатель мог определить метод дешифрования
  • LogicalFrame использует одну и ту же структуру фрейма в обоих направлениях: Terminal→Fay и Fay→Terminal
  • Когда физический транспорт требует фрагментации, операция фрагментации делегируется нижележащему Transport_Adapter; LogicalFrame сохраняет свою целостность

4.2 Типы фреймов

DTP определяет четыре типа фреймов:

Тип фреймаИдентификаторНазначение
Data FramedataПереносит фактические данные Fragment
Request FramerequestИнициирует запросы данных или корректирует соглашения о передаче
Response FrameresponseОтвечает на запросы данных, содержит результаты принятия, отклонения или переговоров
Control FramecontrolПередаёт уведомления об ошибках, завершение соглашений и другую управляющую информацию

4.3 Детали полей заголовка

Версия протокола (protocolVersion)

{ major: number, minor: number }

Идентифицирует версию протокола, используемую текущим фреймом. Получатель использует это для определения совместимости.

Идентификатор типа фрейма (frameType)

Идентифицирует тип фрейма, определяя способ разбора payload.

Уникальный идентификатор Fragment (fragmentId)

Глобально уникальный идентификатор UUID v4, используемый для ссылок и отслеживания в DAG.

ID соглашения (agreementId)

Идентифицирует соглашение, к которому принадлежит данный Fragment. Поддерживает сжатую передачу: когда последовательные Fragment принадлежат одному соглашению, только первый Fragment в пакете несёт полный Agreement_ID в заголовке; последующие Fragment могут его опускать (устанавливая в null).

Правила для получателя:

  • При получении Fragment без Agreement_ID он ассоциируется с последним объявленным Agreement_ID в текущем контексте
  • При получении Fragment, ссылающегося на неизвестный Agreement_ID, Fragment отбрасывается и отправляется уведомление об ошибке «соглашение не найдено»

Временная метка происхождения (originTimestamp)

Момент фактического создания данных в источнике, в часовом поясе UTC с миллисекундной точностью. Хранится отдельно от временной метки передачи и не подвержена влиянию задержек передачи.

Пример: пользователь записывает 30 минут данных о пульсе в офлайн-режиме в метро. После выхода со станции данные загружаются массово — каждая запись сохраняет временную метку фактического момента измерения, а не момента загрузки.

Список DAG-зависимостей (dagDependencies)

Объявляет зависимости от других Fragment. Каждая зависимость включает:

  • Целевой Fragment_ID
  • Тип связи (derived_from / annotates / supersedes)

Поддерживает объявление нуля или более зависимостей.

Метаданные шифрования (encryptionMetadata)

{ algorithm: string, keyVersion: number }
  • algorithm: идентификатор алгоритма шифрования (например, "AES-256-GCM")
  • keyVersion: номер версии ключа

Сами метаданные шифрования не шифруются, чтобы получатель мог определить параметры дешифрования.

Порядковый номер (sequenceNumber)

Порядковый номер передачи, монотонно возрастающий в рамках одной сессии, используемый для механизма возобновления. Каждое направление передачи поддерживает независимое пространство порядковых номеров.

4.4 Сериализация и десериализация

DTP_Engine сериализует объекты LogicalFrame в двоичный формат для передачи; получатель десериализует двоичные данные обратно в объекты LogicalFrame.

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

DTP_Engine также предоставляет функцию форматированного вывода (Pretty Printer), преобразующую объекты LogicalFrame в человекочитаемый текстовый формат для целей отладки и логирования.

4.5 Контекстные метаданные

Каждый Fragment несёт структурированные контекстные метаданные (ContextMetadata), включающие:

  • Идентификатор типа данных (dataType): описывает тип данных
  • Источник данных (source): различает аппаратные и программные источники
  • Пользовательские поля (customFields): расширяемая структура пар ключ-значение

Аппаратный источник

Когда данные поступают от аппаратного датчика, метаданные включают:

  • Тип датчика (sensorType)
  • Точность датчика (precision)
  • Частота дискретизации (samplingRate, в Гц)

Программный источник

Когда данные поступают от программного обмена, метаданные включают:

  • Идентификатор исходного приложения (appIdentifier)
  • Описание метода обмена (sharingMethod)