# 06. Channels Read API ## Человеко-читаемое объяснение Эти функции — это **чтение данных каналов** для UI: 1. `ListSubscriptionsFeed` — отдает данные для экрана списка каналов: - ваши каналы (личный + созданные вами), - каналы пользователей, на кого вы подписаны, - отдельные каналы, на которые вы подписаны напрямую. 2. `GetChannelMessages` — отдает полную ленту одного канала (пока без курсоров, загружается сразу целиком), включая версии сообщений, лайки и ответы. 3. `GetMessageThread` — отдает дерево обсуждения вокруг конкретного сообщения: предки, фокус-сообщение, потомки. 4. `GetPersonalDiary` — отдает виртуальную ленту `Личный дневник`, собранную из `STATUS_ACTION` текущего пользователя. 5. `GetChannelsCounters` — отдает счетчики разделов каналов для пользователя. 6. `ListGroupChats200` — отдает список групповых чатов типа `200`. 7. `GetGroupDialog` — отдает сообщения конкретного группового чата типа `200`. > На первом этапе мы **не используем курсоры** (`nextCursor`) и загружаем полные списки. --- ## 1) ListSubscriptionsFeed ### Request ```json { "op": "ListSubscriptionsFeed", "requestId": "req-1", "payload": { "login": "Alice", "limit": 200 } } ``` ### Response (success) ```json { "op": "ListSubscriptionsFeed", "requestId": "req-1", "status": 200, "ok": true, "payload": { "login": "Alice", "ownedChannels": [ { "channel": { "ownerLogin": "Alice", "ownerBlockchainName": "alice-001", "channelName": "0", "displayName": "Мой канал", "channelDescription": "Короткое описание", "avaAr": "ArweaveTxId...", "avaSha256": "0123...", "avaSize": 248193, "metaUpdatedAtMs": 1760000000000, "personal": true, "channelRoot": { "blockNumber": 0, "blockHash": "..." } }, "messagesCount": 120, "lastMessage": { "messageRef": { "blockNumber": 921, "blockHash": "..." }, "text": "последняя версия текста", "createdAtMs": 1760000000000, "authorLogin": "Alice", "authorBlockchainName": "alice-001" } } ], "followedUsersChannels": [ { "channel": { "ownerLogin": "Bob", "ownerBlockchainName": "bob-001", "channelName": "0", "personal": true, "channelRoot": { "blockNumber": 0, "blockHash": "..." } }, "messagesCount": 540, "lastMessage": { "messageRef": { "blockNumber": 922, "blockHash": "..." }, "text": "последняя версия текста", "createdAtMs": 1760000100000, "authorLogin": "Bob", "authorBlockchainName": "bob-001" } } ], "followedChannels": [ { "channel": { "ownerLogin": "Carl", "ownerBlockchainName": "carl-001", "channelName": "market", "personal": false, "channelRoot": { "blockNumber": 456, "blockHash": "..." } }, "messagesCount": 90, "lastMessage": { "messageRef": { "blockNumber": 1002, "blockHash": "..." }, "text": "актуальный текст", "createdAtMs": 1760001000000, "authorLogin": "Carl", "authorBlockchainName": "carl-001" } } ] } } ``` --- ## 2) GetChannelMessages ### Request ```json { "op": "GetChannelMessages", "requestId": "req-2", "payload": { "channel": { "ownerBlockchainName": "bob-001", "channelRootBlockNumber": 123, "channelRootBlockHash": "..." }, "limit": 200, "sort": "asc" } } ``` ### Response (success) ```json { "op": "GetChannelMessages", "requestId": "req-2", "status": 200, "ok": true, "payload": { "channel": { "ownerLogin": "Bob", "ownerBlockchainName": "bob-001", "channelName": "news", "displayName": "Новости Bob", "channelDescription": "Канал о новостях", "avaAr": "ArweaveTxId...", "avaSha256": "0123...", "avaSize": 248193, "metaUpdatedAtMs": 1760000000000, "channelRoot": { "blockNumber": 123, "blockHash": "..." } }, "metaEvents": [ { "kind": "created", "messageRef": { "blockNumber": 123, "blockHash": "..." }, "authorLogin": "Bob", "authorBlockchainName": "bob-001", "lineStep": 1, "createdAtMs": 1760000000000, "title": "news", "description": "", "avaAr": "", "avaSha256": "", "avaSize": 0 }, { "kind": "profile_updated", "messageRef": { "blockNumber": 130, "blockHash": "..." }, "authorLogin": "Bob", "authorBlockchainName": "bob-001", "lineStep": 2, "createdAtMs": 1760000500000, "title": "Новости Bob", "description": "Канал о новостях", "avaAr": "ArweaveTxId...", "avaSha256": "0123...", "avaSize": 248193 } ], "messages": [ { "messageRef": { "blockNumber": 140, "blockHash": "..." }, "authorLogin": "Bob", "authorBlockchainName": "bob-001", "createdAtMs": 1760000000000, "text": "текущая версия", "likesCount": 12, "repliesCount": 3, "ratingsCount": 2, "versionsTotal": 4, "versions": [ { "versionIndex": 1, "blockNumber": 140, "blockHash": "...", "text": "v1", "createdAtMs": 1760000000000 }, { "versionIndex": 2, "blockNumber": 155, "blockHash": "...", "text": "v2", "createdAtMs": 1760001000000 }, { "versionIndex": 3, "blockNumber": 170, "blockHash": "...", "text": "v3", "createdAtMs": 1760002000000 }, { "versionIndex": 4, "blockNumber": 199, "blockHash": "...", "text": "v4", "createdAtMs": 1760003000000 } ] } ] } } ``` --- ## 3) GetMessageThread ### Request ```json { "op": "GetMessageThread", "requestId": "req-3", "payload": { "message": { "blockchainName": "bob-001", "blockNumber": 333, "blockHash": "..." }, "depthUp": 20, "depthDown": 2, "limitChildrenPerNode": 50 } } ``` ### Response (success) ```json { "op": "GetMessageThread", "requestId": "req-3", "status": 200, "ok": true, "payload": { "ancestors": [MessageNode], "focus": MessageNode, "descendants": [MessageNodeTree] } } ``` ### MessageNode (дополнение) - `MessageNode` расширяет формат сообщения из `GetChannelMessages` и дополнительно содержит: - `channelInfo` — мета-информация о канале (если применимо); - `rawBlockB64` — сырой `block_bytes` текущего блока в Base64. - Поле `rawBlockB64` присутствует у узлов во всех частях ответа `GetMessageThread`: `focus`, `ancestors[]`, `descendants[]`. - В `GetChannelMessages` поле `rawBlockB64` **не добавляется** (лента канала без сырого блока, чтобы не раздувать ответ). - И в `GetChannelMessages`, и в `GetMessageThread` каждое сообщение теперь содержит: - `repliesCount` — число дочерних сообщений типа `TEXT_REPLY`; - `ratingsCount` — число дочерних сообщений типа `TEXT_RATING`. - В `descendants[]` операции `GetMessageThread` возвращаются оба типа дочерних текстовых сообщений: - `TEXT_REPLY`; - `TEXT_RATING`. Они идут в одной общей ветке обсуждения и сортируются по времени создания. --- ## 4) GetPersonalDiary Возвращает виртуальный канал `Личный дневник` для самого пользователя. - Вызов доступен только владельцу дневника. - Сообщения в ответе строятся из блоков `STATUS_ACTION`. - Поля `targetMsgSubType`, `targetText`, `targetAuthorLogin`, `targetAuthorBlockchainName`, `targetCreatedAtMs` описывают исходный материал, к которому относится действие. ### Request ```json { "op": "GetPersonalDiary", "requestId": "req-4", "payload": { "login": "Alice", "limit": 200, "sort": "asc" } } ``` --- ## 4) GetChannelsCounters ### Request ```json { "op": "GetChannelsCounters", "requestId": "req-4", "payload": { "login": "Alice" } } ``` ### Response (success) ```json { "op": "GetChannelsCounters", "requestId": "req-4", "status": 200, "ok": true, "payload": { "login": "Alice", "feedCount": 12, "dialogs100Count": 3, "groupChats200Count": 4, "myChannelsCount": 2 } } ``` --- ## 5) ListGroupChats200 ### Request ```json { "op": "ListGroupChats200", "requestId": "req-5", "payload": { "login": "Alice" } } ``` ### Response (success) ```json { "op": "ListGroupChats200", "requestId": "req-5", "status": 200, "ok": true, "payload": { "login": "Alice", "chats": [ { "ownerLogin": "Alice", "ownerBlockchainName": "alice-001", "channelRootBlockNumber": 123, "channelRootBlockHash": "...", "channelName": "team", "chatTitle": "Team chat", "membersCount": 3, "updatedAtMs": 1760000000000 } ] } } ``` --- ## 6) GetGroupDialog ### Request ```json { "op": "GetGroupDialog", "requestId": "req-6", "payload": { "login": "Alice", "group": { "ownerBlockchainName": "alice-001", "channelRootBlockNumber": 123 } } } ``` ### Response (success) ```json { "op": "GetGroupDialog", "requestId": "req-6", "status": 200, "ok": true, "payload": { "group": { "ownerLogin": "Alice", "ownerBlockchainName": "alice-001", "channelRootBlockNumber": 123, "channelName": "team", "chatTitle": "Team chat" }, "messages": [ { "authorLogin": "Bob", "authorBlockchainName": "bob-001", "blockNumber": 140, "blockHash": "...", "createdAtMs": 1760000000000, "text": "Привет" } ] } } ``` --- ## Reason codes - `bad_fields` - `user_not_found` - `channel_not_found` - `message_not_found` - `limit_too_large` - `channel_name_already_exists` - `internal_error`