Версия документа: 1.0 (сводная), 2026-10-17, UTC
Тип документа: неофициальная техническая спецификация, восстановленная по клиентам TNXLOG и наблюдаемым HTTP-ответам.
Назначение: разработка совместимого клиента, интеграция с RDA LogFlow и RDA Logger, дальнейшее исследование всех методов TNXQSO.
Граница достоверности. «Окончательная» означает единый итоговый документ по собранным к настоящему времени свидетельствам, а не доказанную полноту закрытого серверного API. Официальная OpenAPI/документация владельца TNXQSO не получена. Некоторые маршруты обнаружены в клиентском коде, но не проверены на живом сервере. Неподтверждённые поля и маршруты не должны считаться гарантированными.
1. Источники и шкала подтверждения
Код | Значение |
|---|---|
HTTP | На сервере получен фактический HTTP-ответ; известны метод, дата, статус и некоторые метаданные. |
Android | Обнаружено в Android TNXLOG 2.8 (Retrofit/DEX), включая модели запросов/ответов. |
Windows | Подтверждено IL-кодом Windows TNXLOG 0.4.16 (MSI/monodis). |
Node-RED | Реализация обнаружена в пользовательском экспорте flow; её наличие не доказывает текущий успех запроса. |
Web JS | Структура обнаружена в JavaScript сайта TNXQSO. |
Вывод | Обоснованная интерпретация источников, не измеренный серверный контракт. |
Неизвестно | Данных недостаточно. |
Исходные свидетельства: TNXLOG_2.8_APKPure.xapk, tnxlog.msi, http_methods.txt, il_focused.txt, manifest.json, экспорт Node-RED «Вставленный текст(4).txt», js_contexts.json, public_scan.json, tnxqso_api_check.json. В предыдущих отчётах содержатся точные смещения DEX и диапазоны IL. Данные авторизации и пользовательские значения из Node-RED в документ не воспроизводятся.
Реальные HTTP-проверки (2026-10-17 UTC)
Метод | URL | Факт |
|---|---|---|
GET |
| HTTP 200, JSON-объект; ключи |
GET |
| HTTP 200, JSON-массив; на момент проверки 5 элементов. |
POST |
| HTTP 200, JSON-объект с токеном и пользовательскими настройками. Пароль/токен из отчёта исключены. |
Данные проверок не включают успешную реальную отправку QSO, удаление, геолокацию, чат или аудиозаписи.
2. Базовый URL, обмен и авторизация
- Основной HTTPS-хост:
https://tnxqso.com. - Для Windows TNXLOG базовый путь API:
https://tnxqso.com/aiohttp/; URI собирается конкатенацией базового адреса и относительного пути (Windows, IL 34038–34051). - JSON: Android использует Retrofit; Windows вызывает
Newtonsoft.Json.JsonConvert.SerializeObject(data)иnew StringContent(json)(Windows, IL 33732–33747). - Особенность Windows: стандартный
StringContent(string)задаётtext/plain; charset=utf-8, а неapplication/json(вывод из .NET). Сетевые заголовки не перехватывались. Для независимого клиента предпочтителенapplication/json, но совместимость следует проверить отдельно. - Токен в большинстве моделей передаётся в теле JSON полем
token. JWT ли это, срок действия, refresh-token, logout/revoke, cookies, CORS и лимиты — неизвестно. - HTTP 401 обрабатывается в Windows как отказ авторизации; детали ниже.
- Все времена событий/QSO в интеграции необходимо хранить и передавать в UTC, хотя точное требование сервера к часовому поясу и формату
tsне подтверждено.
3. Реестр обнаруженных операций
Сокращения: S — проверено сервером; C — подтверждено клиентским кодом; U — URL/семантика частично не подтверждены.
Транспорт и метод | Адрес / путь | Назначение | Источник | Статус |
|---|---|---|---|---|
HTTPS POST |
| Авторизация, выдача токена, настроек | Android, Windows, Node-RED, HTTP | S |
HTTPS POST |
| Отправка координат / получение QTH-данных | Android, Node-RED | C |
HTTPS POST |
| Передача частоты станции | Android, Windows, Node-RED | C |
HTTPS POST |
| Отправка одного или нескольких QSO | Android, Windows, Node-RED | C |
HTTPS POST |
| Удаление QSO по серверному | Windows | C |
HTTPS POST |
| Отправка сообщения чата | Android | C |
HTTPS POST |
| Отправка аудиозаписи, multipart | Windows | C |
HTTPS GET |
| Публичная структура состояния станции | HTTP | S |
HTTPS GET |
| Данные QTHnow/локаций | HTTP | S |
HTTPS GET |
| Чат станции | Android | U |
HTTPS GET |
| Общие беседы | Android | U |
HTTPS GET |
| Статические данные выбранной станции | Web JS | U |
HTTPS GET |
| Список блокировок станции | Web JS | U |
Веб-события |
| Изменения активных станций | Web JS | C |
Веб-события |
| Изменения активных пользователей | Web JS | C |
Веб-события |
| Подписка на общий чат | Web JS | C |
Веб-события |
| Подписка на чат станции | Web JS | C |
Веб-события |
| Личные сообщения | Web JS | C |
Примечание. /exchange/... не следует запрашивать обычным GET как REST API: обычный GET /exchange/active_stations ранее отвечал 404. Точный транспорт подписки, handshake и авторизация требуют исследования. В интерфейсе также найдены административные действия над banlist; их точные методы и тела в полном виде не восстановлены.
4. POST /aiohttp/login
Назначение: получить токен и пользовательскую конфигурацию. Статус: HTTP + Android + Windows + Node-RED.
Запрос:
{
"login": "<CALLSIGN>",
"password": "<PASSWORD>"
}
Подтверждённые верхнеуровневые поля успешного ответа (из обезличенного HTTP-отчёта; значения скрыты):
{
"token": "<TOKEN>",
"callsign": "<CALLSIGN>",
"settings": {},
"chat_callsign": "<VALUE>",
"email": "<VALUE>",
"email_confirmed": false,
"name": "<VALUE>",
"pm_enabled": false,
"verified": false,
"banned_by": null,
"gallery_quotas": {},
"last_blog_entry_delete": null
}
Выше показана схема-пример ключей, а не буквальное тело ответа: конкретные типы отдельных полей, включая banned_by, gallery_quotas, last_blog_entry_delete, в обезличенном отчёте не зафиксированы. Значения false, null, {} — заполнители, не нормативные значения. В Android встречается вложенная settings.station.callsign; полнота settings неизвестна.
Обработка Windows: успешный HTTP-ответ приводит к десериализации LoginResponse, сохранению token и запуску таймера schedulePingTimer() (IL 36131–36188). При HTTP 401 токен очищается, приложение уведомляет об изменении состояния авторизации, и именно по этой ветке автоматическая попытка не планируется (IL 36255–36287). При не-401 ошибке может назначаться повторная авторизация, если активен флаг retry (IL 36289–36300); callback вызывает login(true) (IL 37095–37098). Точные интервалы и ограничения количества попыток неизвестны.
5. POST /aiohttp/location: координаты и частота
Назначение: обновление местоположения станции, получение сведений о QTH, RDA, RAFA, локаторе; либо передача текущей частоты. Статус: Android + Node-RED; ответ сервером в этой серии исследований не проверен.
Координаты:
{
"token": "<TOKEN>",
"location": [55.7525, 37.6300]
}
По Node-RED порядок элементов [latitude, longitude] (WGS84, десятичные градусы); DEX подтверждает тип Double[], но не геодезическую систему и порядок самостоятельно. Не путать с GeoJSON, где геометрия [longitude, latitude].
Частота:
{
"token": "<TOKEN>",
"freq": "14074.0"
}
freq — строка. В исследованной реализации Node-RED используется частота в кГц; Windows вызывает QSO.formatFreq(Decimal). Единицы и точность должны быть верифицированы для остальных реализаций.
Структура модели ответа Android (частичная, иллюстративная):
{
"qth": {
"fields": {
"titles": ["RDA", "RAFA", "QTH field"],
"values": ["<RDA>", null, null]
},
"loc": "<MAIDENHEAD>",
"loc8": "<LOCATOR_SUFFIX>"
}
}
Наличие qth, fields, titles, values, loc, loc8 подтверждено клиентской моделью, конкретные значения, порядок и обязательность — нет. Нужно учитывать несколько RDA около границ, пустой результат и ошибки определения. Данные о границах RDA в клиенте не найдены: наличие ответа /location не доказывает, что сервер TNXQSO предоставляет сами полигоны.
Независимый источник полигонов RDA (НЕ TNXQSO API)
Проверен отдельный сервис R1CF: https://map.r1cf.ru/geoserver/cite/wfs, OGC WFS. Успешно выполнены GetCapabilities, DescribeFeatureType и GetFeature слоя cite:RDA_2025X с OUTPUTFORMAT=application/json, получены MultiPolygon и атрибуты osm_id, name, rda, az_rating, name_en, modified. Выгруженный файл содержит 2 661 геообъект и 2 660 различных кодов RDA (из отдельного аудита). Этот внешний интерфейс не является маршрутом TNXQSO и описан здесь лишь как рекомендуемый независимый источник для офлайн-геопоиска RDA Logger / RDA LogFlow.
6. POST /aiohttp/log: отправка QSO
Статус: Android + Windows + Node-RED; HTTP-ответ от реального сервера на запись в рамках исследования не проверялся.
{
"token": "<TOKEN>",
"qso": [
{
"ts": "2026-10-17 10:00:00",
"cs": "<OTHER_CALLSIGN>",
"myCS": "<OWN_CALLSIGN>",
"band": "7",
"freq": "7010.5",
"mode": "CW",
"snt": "599",
"rcv": "599",
"loc": "<MAIDENHEAD>",
"qth": ["<RDA>", "<RAFA>", "<QTH_FIELD>"],
"no": "0"
}
]
}
Все поля объекта QSO в Android-модели, кроме qth: String[], — строковые: band, cs, freq, loc, mode, myCS, no, rcv, snt, ts. В Android TNXLOG no при отправке явно устанавливается в строку "0" (DEX classes.dex около 0x445ada). Формат ts в примере следует клиентским образцам и не подтверждён как единственно разрешённый формат. Частота в показанном формате кГц — из клиентской реализации.
В Node-RED также встречаются comments, loc_rcv и другие поля; они не входят в перечисленную Android-модель и не объявляются обязательными. Windows сериализует собственный объект QSO; его полный публичный JSON-набор не был получен как сырой сетевой запрос.
Результат отправки и серверный идентификатор
Android Retrofit ожидает Call<List<QsoResult>>; у QsoResult есть поле ts: Float. В обработчике ответа Android сохраняет в локальную запись Qso.web_id = "OK" и обновляет Room/SQLite (MainActivity$5.onResponse, DEX около 0x43ec04–0x43ec08). Это не серверный идентификатор.
Windows TNXLOG ожидает NewQsoResponse[] с полем ts: Decimal? и сохраняет полученное значение в QSO.serverTs, используемое позднее для удаления. Если ts отсутствует, Windows присваивает serverTs=0 и другое состояние синхронизации. Следовательно, массив ответов и значение ts принципиальны для корректного ведения журнала. Связь между индексами запроса и ответа строится клиентом, но серверное обещание одинаковой длины и порядка ответов отдельно не проверено.
Иллюстрация ожидаемой формы (не захваченный ответ):
[
{"ts": 1234567890.0}
]
Не установлено: значение ts при ошибках, предел batch, допустимый размер полей, поведение повторной загрузки одинаковой связи, идемпотентность, возможность upsert/редактирования уже опубликованного QSO, диапазон/точность идентификатора, случаи частичного успеха.
7. POST /aiohttp/log: удаление QSO
Статус: восстановлено из IL Windows TNXLOG; серверный вызов удаления не проводился.
Windows использует тот же endpoint /aiohttp/log, но передаёт отдельный тип QsoDeleteRequest : JSONToken с полем delete: Decimal. Конструктор берёт число из QSO.serverTs.
{
"token": "<TOKEN>",
"delete": 1234567890
}
delete — серверное значение ts, полученное при загрузке, а не локальный ID записи. Число условное. Это не HTTP DELETE и не подтверждённый путь /aiohttp/delete.
Критическая особенность клиента Windows: Tnxlog.deleteQso() сначала убирает запись из UI, затем из локальной LiteDB, затем вызывает сетевую операцию (IL 17512–17534). При потере связи возможна рассинхронизация; в собственной реализации рекомендуется хранить состояние pending_delete до подтверждения сервера.
Не установлено: тело ответа при успешном/ошибочном удалении, правила прав доступа, возможность повторного удаления, поведение отсутствующего serverTs, возврат удаления, ограничения на принадлежность QSO.
8. POST /aiohttp/chat
Статус: Android Retrofit; серверные ответы не проверены.
В Android присутствуют две модели:
Чат станции (ChatMessageData):
{
"from": "<CALLSIGN>",
"name": "<NAME>",
"station": "<STATION>",
"text": "<MESSAGE>",
"token": "<TOKEN>"
}
Общий чат (ChatMessageDataTalks):
{
"from": "<CALLSIGN>",
"name": "<NAME>",
"text": "<MESSAGE>"
}
Ожидается Call<String>. Отсутствие поля token во второй модели не доказывает отсутствие проверки авторизации на сервере: возможны cookie, другой контекст сессии или особенности конвертера.
Чтение: Android имеет относительные маршруты GET chat.json и GET static/js/talks.json, возвращающие List<ChatPost> с полями admin (Boolean), date, name, text, time, user. Полные абсолютные URL этих двух запросов не установлены из-за неизвестной настройки Retrofit baseUrl в данном месте.
9. POST /aiohttp/soundRecord
Статус: Windows IL, на сервере не проверено.
Тип отправки multipart/form-data. В _postSoundRecord формируется StreamContent(File.OpenRead(record)) и StringContent(config.token), оба включаются в MultipartFormDataContent. Предыдущий анализ несокращённого IL идентифицировал поля file (имя файла, тип audio/mp3) и token; в повторно предоставленном il_focused.txt строковые константы скрыты, поэтому данное уточнение основано на более раннем несокращённом извлечении. Путь вызывается как soundRecord относительно Windows base URL.
Успех клиентом оценивается по HttpResponseMessage.IsSuccessStatusCode (IL 33936–33944), тело ответа не интерпретируется. Ограничения на размер, формат аудио, права доступа, квоты и сопоставление с QSO — неизвестны.
10. Публичные JSON и веб-события
Проверенные ресурсы
GET /static/js/defaultStationStatus.json — HTTP 200, объект с ключами:
get, loc, online, rafa, rda, userFields, wff.
GET /static/js/qth_now_locations.json — HTTP 200, массив; на момент проверки 5 элементов. Содержание элементов без сырого ответа не следует считать документированным.
Не полностью подтверждённые URL
- GET
/static/stations/{station}/{name}.json— шаблон из Web JS, параметры и формат ответа неизвестны. - GET
/aiohttp/station/{stationAdmin}/banlist— административный маршрут из Web JS; отдельные операции модификации banlist обнаружены в клиенте, но контракт не исследован.
События /exchange/...
Код веб-клиента использует каналы active_stations, active_users, chat/talks, chat/{callsign}, pm/{callsign} под /exchange/. Они не классифицируются как обычные REST GET. Протокол событий, направление сообщений, формат payload, аутентификация и механизм подписки пока не восстановлены.
11. Поведение Windows HTTP-клиента и очередей
Статус: IL-код Windows TNXLOG 0.4.16; это поведение клиентской программы, а не обязательное правило TNXQSO API.
- JSON сериализуется в текст, затем отправляется
HttpClient.PostAsync(IL 33732–33747, 34076–34086). - Тайм-аут
HttpClient.Timeout = max(timeoutSeconds, 100)секунд (IL 34057–34070). - При HTTP 2xx вызывается
set_connected(true); при 401 —set_connected(false)иloginStateChanged(IL 34124–34153). - Сетевая очередь
logQueue—ConcurrentQueue<LogRequest>; вызываетсяTryPeek(). Еслиreq.qso != null, выбирается_postQso(..., fromQueue=true), иначе_postDeleteQso(..., fromQueue=true)(IL 35312–35367). - Извлечение из очереди (
TryDequeue) выполняется только послеtrueот отправки; приfalseэлемент остаётся и цикл прерывается (IL 35400–35419). - После очереди QSO запускается очередь аудиозаписей
processSoundRecordsQueue()(IL 35421–35423). - При успешном обычном запросе и подключённом состоянии обработка очереди может инициироваться вновь (
fromQueue=false, IL 34179–34189). - Логин может повторяться по таймеру (
scheduleLoginRetryTimer); параметры таймера и гарантированное возобновление после перезапуска не установлены.
Не доказано: сохранение очередей между перезапусками, сколько и с каким интервалом отправляются повторы, гарантия ровно однократной доставки, восстановление данных после crash и дедупликация на стороне сервера.
12. Практические примеры безопасного чтения
Примеры не содержат действующих токенов. Нельзя выполнять POST записи или удаления с рабочим журналом ради проверки протокола.
# Схема публичной конфигурации, без авторизации
curl -fsS 'https://tnxqso.com/static/js/defaultStationStatus.json'
# Список QTHnow-локаций
curl -fsS 'https://tnxqso.com/static/js/qth_now_locations.json'
Авторизация (демонстрация с фиктивными значениями):
curl -sS -X POST 'https://tnxqso.com/aiohttp/login' \
-H 'Content-Type: application/json' \
--data '{"login":"<CALLSIGN>","password":"<PASSWORD>"}'
Пароль и токен не следует указывать непосредственно в командной строке рабочего компьютера (история shell, список процессов). Для реального инструмента — интерактивное получение или защищённый конфиг. Пример нужен только для иллюстрации протокола.
13. Обработка ошибок: что известно и что нет
Условие | Подтверждённое поведение клиента | Серверная гарантия |
|---|---|---|
Успешный login HTTP 200 | Токен и настройки разбираются | Проверено на тестовом аккаунте |
HTTP 401 в Windows | Сброс токена/состояния авторизации | Формат тела ошибки неизвестен |
HTTP не-2xx | Обработка отказа, возможный повтор логина | Классы кодов и схемы ошибок неизвестны |
Timeout POST QSO | В клиенте может сохраниться элемент очереди | Неизвестно, записан ли QSO сервером |
POST QSO 2xx | Клиент интерпретирует ответ | Частичный успех, формат ошибок не проверены |
POST delete 2xx | Клиент считает операцию успешной | Семантика при повторе не проверена |
Загрузка аудио 2xx | Windows считает успешной по HTTP | Тело ответа/идентификатор неизвестны |
Неизвестны: официальные 400/403/404/409/422/429/5xx тела, rate limits, pagination для журналов, серверный поиск QSO, критерий дубликата, корреляция запрос/ответ, срок токена.
14. Рекомендации к интеграции RDA Logger / RDA LogFlow
- Локальный журнал — главный источник истины; синхронизация TNXQSO является отдельным состоянием, а не заменой локальных QSO.
- Для каждого QSO хранить
local_id,server_ts(точный decimal/string без потери точности),sync_state,last_attempt_utc,last_error, хеш/снимок переданных полей. - Для удаления использовать только подтверждённый
server_ts, сначалаpending_delete, затем подтверждённое удаление. - При тайм-ауте POST и неизвестном результате использовать состояние
uncertain, а не безусловный автоматический повтор, пока не будет верифицирован механизм сверки/дедупликации. - Пакеты ограничивать консервативно и сохранять порядок операций до выявления настоящего ограничения API.
- Никогда не выводить token/password в диагностических логах, отчётах и пользовательских ZIP.
- RDA-определение по координатам может выполняться локально по отдельной базе R1CF, но это не заменяет проверки поведения
/aiohttp/locationTNXQSO и не делает R1CF частью TNXQSO API.
15. Реестр пробелов для полного исследования серверного API
Высший приоритет
- Захват и обезличивание точных успешных/ошибочных HTTP-ответов
/aiohttp/location,/aiohttp/log,/aiohttp/chat,/aiohttp/soundRecordна специально выделенном тестовом аккаунте. - Проверка идемпотентности
POST /aiohttp/log, повторной передачи QSO и соответствия массива ответов входному массиву; без риска для существующего журнала. - Выяснение механизмов получения опубликованных QSO, исправления записи, восстановления после потери ответа, статуса синхронизации и пагинации.
- Полный маршрут и протокол GET чтения чатов и
/exchange/...(XHR/WebSocket/SSE, параметры и payload). - Типы значений и обязательность полей успешного login и
qth-ответа, включая множественные RDA.
Следующий приоритет
- Остальные JavaScript-ресурсы и операции публичного веб-клиента: пользователи, станции, приватные сообщения, статусы, модерация, геолокация, фото и прочие медиа.
- Официальные ограничения, токены, перезапуск сессии и rate limit, версии API.
- Получение и статическая проверка клиентов QTHnow, TNXPost, TNXInfo; поиск недоступных TNXLOG методов в них.
- Отдельная проверка использования и лицензирования данных TNXQSO и R1CF.
16. Привязка к исходным свидетельствам
Раздел | Источник / технические маркеры |
|---|---|
Авторизация | Android |
Геолокация | Android |
Создание QSO | Android |
| Android DEX смещения около |
Удаление | Windows |
Очередь | Windows |
Локальное удаление до сети | Windows |
Транспорт | Windows |
Аудио | Windows |
Чаты | Android Retrofit |
Публичные JSON |
|
Внешние RDA-полигоны | Отдельный GeoServer R1CF; |
17. Заключение
На данный момент достоверно реконструирован рабочий каркас интеграции: авторизация, обновление геопозиции и частоты, загрузка QSO, удаление по serverTs, отправка чата и аудио, часть публичных JSON и веб-событий. Не установлена полнота закрытого API сервера. Документ пригоден для проектирования клиента с явной обработкой неподтверждённых сценариев; его нельзя использовать как гарантию, что неизвестные методы отсутствуют.