Глава 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 Frame | data | Переносит фактические данные Fragment |
| Request Frame | request | Инициирует запросы данных или корректирует соглашения о передаче |
| Response Frame | response | Отвечает на запросы данных, содержит результаты принятия, отклонения или переговоров |
| Control Frame | control | Передаёт уведомления об ошибках, завершение соглашений и другую управляющую информацию |
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)
