Add network packet classes and enums for messaging functionality

- Introduced `AttachmentType` enum to define various attachment types.
- Added `DeliveryStatus` enum to represent message delivery statuses.
- Created `MessageAttachment` data class to encapsulate message attachments.
- Implemented `OnlineState` enum to manage user online statuses.
- Developed various packet classes: `Packet`, `PacketHandshake`, `PacketResult`, `PacketSearch`, `PacketUserInfo`, `PacketOnlineState`, `PacketOnlineSubscribe`, `PacketMessage`, `PacketRead`, `PacketDelivery`, `PacketTyping`, `PacketChunk`, `PacketPushNotification`, `PacketRequestTransport`, and `PacketPushToken` for handling different messaging operations.
- Removed the old `Packets.kt` file to streamline the codebase.
- Added `SearchUser` data class for user search results.
This commit is contained in:
2026-02-16 11:22:55 +05:00
parent c92cb0779a
commit 2de2f67e46
21 changed files with 551 additions and 540 deletions

View File

@@ -0,0 +1,15 @@
package com.rosetta.messenger.network
/**
* Типы вложений
*/
enum class AttachmentType(val value: Int) {
IMAGE(0), // Изображение
MESSAGES(1), // Reply (цитата сообщения)
FILE(2), // Файл
AVATAR(3); // Аватар пользователя
companion object {
fun fromInt(value: Int) = entries.firstOrNull { it.value == value } ?: IMAGE
}
}

View File

@@ -0,0 +1,15 @@
package com.rosetta.messenger.network
/**
* Статус доставки сообщения
*/
enum class DeliveryStatus(val value: Int) {
WAITING(0), // Ожидает отправки
DELIVERED(1), // Доставлено
ERROR(2), // Ошибка
READ(3); // Прочитано
companion object {
fun fromInt(value: Int) = entries.firstOrNull { it.value == value } ?: WAITING
}
}

View File

@@ -0,0 +1,14 @@
package com.rosetta.messenger.network
/**
* Вложение к сообщению
*/
data class MessageAttachment(
val id: String,
val blob: String, // Base64 данные или пусто для CDN
val type: AttachmentType,
val preview: String = "", // Метаданные: "UUID::metadata" или "filesize::filename"
val width: Int = 0,
val height: Int = 0,
val localUri: String = "" // 🚀 Локальный URI для мгновенного отображения (optimistic UI)
)

View File

@@ -0,0 +1,13 @@
package com.rosetta.messenger.network
/**
* Online State enum
*/
enum class OnlineState(val value: Int) {
ONLINE(0),
OFFLINE(1);
companion object {
fun fromBoolean(isOnline: Boolean) = if (isOnline) ONLINE else OFFLINE
}
}

View File

@@ -0,0 +1,10 @@
package com.rosetta.messenger.network
/**
* Base class for all protocol packets
*/
abstract class Packet {
abstract fun getPacketId(): Int
abstract fun receive(stream: Stream)
abstract fun send(): Stream
}

View File

@@ -0,0 +1,34 @@
package com.rosetta.messenger.network
/**
* Chunk packet (ID: 0x09)
* Для разбиения больших пакетов на части (как в Desktop)
* ВАЖНО: chunkIndex и totalChunks - Int16, не Int32!
*/
class PacketChunk : Packet() {
var chunkId: String = ""
var chunkIndex: Int = 0
var totalChunks: Int = 0
var data: ByteArray = ByteArray(0)
override fun getPacketId(): Int = 0x09
override fun receive(stream: Stream) {
// В Desktop: readInt16 для index и total
chunkIndex = stream.readInt16()
totalChunks = stream.readInt16()
chunkId = stream.readString()
data = stream.readBytes()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
// В Desktop: writeInt16 для index и total
stream.writeInt16(chunkIndex)
stream.writeInt16(totalChunks)
stream.writeString(chunkId)
stream.writeBytes(data)
return stream
}
}

View File

@@ -0,0 +1,28 @@
package com.rosetta.messenger.network
/**
* Delivery packet (ID: 0x08)
* Уведомление о доставке сообщения
* Порядок полей как в React Native: toPublicKey, messageId
*/
class PacketDelivery : Packet() {
var messageId: String = ""
var toPublicKey: String = ""
override fun getPacketId(): Int = 0x08
override fun receive(stream: Stream) {
// React Native читает: toPublicKey, messageId
toPublicKey = stream.readString()
messageId = stream.readString()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
// React Native пишет: toPublicKey, messageId
stream.writeString(toPublicKey)
stream.writeString(messageId)
return stream
}
}

View File

@@ -0,0 +1,31 @@
package com.rosetta.messenger.network
/**
* Handshake packet (ID: 0x00)
* First packet sent by client to authenticate with the server
*/
class PacketHandshake : Packet() {
var privateKey: String = ""
var publicKey: String = ""
var protocolVersion: Int = 1
var heartbeatInterval: Int = 15
override fun getPacketId(): Int = 0x00
override fun receive(stream: Stream) {
privateKey = stream.readString()
publicKey = stream.readString()
protocolVersion = stream.readInt8()
heartbeatInterval = stream.readInt8()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(privateKey)
stream.writeString(publicKey)
stream.writeInt8(protocolVersion)
stream.writeInt8(heartbeatInterval)
return stream
}
}

View File

@@ -0,0 +1,62 @@
package com.rosetta.messenger.network
/**
* Message packet (ID: 0x06)
* Отправка и получение сообщений
*/
class PacketMessage : Packet() {
var fromPublicKey: String = ""
var toPublicKey: String = ""
var content: String = "" // Зашифрованный текст
var chachaKey: String = "" // RSA зашифрованный ключ
var timestamp: Long = 0
var privateKey: String = "" // Hash приватного ключа (для авторизации)
var messageId: String = ""
var attachments: List<MessageAttachment> = emptyList()
override fun getPacketId(): Int = 0x06
override fun receive(stream: Stream) {
fromPublicKey = stream.readString()
toPublicKey = stream.readString()
content = stream.readString()
chachaKey = stream.readString()
timestamp = stream.readInt64()
privateKey = stream.readString()
messageId = stream.readString()
val attachmentCount = stream.readInt8()
val attachmentsList = mutableListOf<MessageAttachment>()
for (i in 0 until attachmentCount) {
attachmentsList.add(MessageAttachment(
id = stream.readString(),
preview = stream.readString(),
blob = stream.readString(),
type = AttachmentType.fromInt(stream.readInt8())
))
}
attachments = attachmentsList
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(fromPublicKey)
stream.writeString(toPublicKey)
stream.writeString(content)
stream.writeString(chachaKey)
stream.writeInt64(timestamp)
stream.writeString(privateKey)
stream.writeString(messageId)
stream.writeInt8(attachments.size)
for (attachment in attachments) {
stream.writeString(attachment.id)
stream.writeString(attachment.preview)
stream.writeString(attachment.blob)
stream.writeInt8(attachment.type.value)
}
return stream
}
}

View File

@@ -0,0 +1,41 @@
package com.rosetta.messenger.network
/**
* Public key with online state
*/
data class PublicKeyOnlineState(
val publicKey: String,
val state: OnlineState
)
/**
* Online State packet (ID: 0x05)
* Notify about user online status
* Формат как в React Native: массив {publicKey, state}
*/
class PacketOnlineState : Packet() {
var publicKeysState: MutableList<PublicKeyOnlineState> = mutableListOf()
override fun getPacketId(): Int = 0x05
override fun receive(stream: Stream) {
val count = stream.readInt8()
publicKeysState.clear()
repeat(count) {
val publicKey = stream.readString()
val isOnline = stream.readBoolean()
publicKeysState.add(PublicKeyOnlineState(publicKey, OnlineState.fromBoolean(isOnline)))
}
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeInt8(publicKeysState.size)
publicKeysState.forEach { item ->
stream.writeString(item.publicKey)
stream.writeBoolean(item.state == OnlineState.ONLINE)
}
return stream
}
}

View File

@@ -0,0 +1,37 @@
package com.rosetta.messenger.network
/**
* Online Subscribe packet (ID: 0x04)
* Subscribe to user online status updates
* Формат как в React Native: privateKey + array of publicKeys
*/
class PacketOnlineSubscribe : Packet() {
var privateKey: String = ""
var publicKeys: MutableList<String> = mutableListOf()
override fun getPacketId(): Int = 0x04
override fun receive(stream: Stream) {
privateKey = stream.readString()
val keysCount = stream.readInt16()
publicKeys.clear()
repeat(keysCount) {
publicKeys.add(stream.readString())
}
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(privateKey)
stream.writeInt16(publicKeys.size)
publicKeys.forEach { key ->
stream.writeString(key)
}
return stream
}
fun addPublicKey(publicKey: String) {
publicKeys.add(publicKey)
}
}

View File

@@ -0,0 +1,37 @@
package com.rosetta.messenger.network
/**
* Push Notification Action
*/
enum class PushNotificationAction(val value: Int) {
SUBSCRIBE(0),
UNSUBSCRIBE(1)
}
/**
* Push Notification packet (ID: 0x10)
* Отправка FCM/APNS токена на сервер для push-уведомлений (новый формат)
* Совместим с React Native версией
*/
class PacketPushNotification : Packet() {
var notificationsToken: String = ""
var action: PushNotificationAction = PushNotificationAction.SUBSCRIBE
override fun getPacketId(): Int = 0x10
override fun receive(stream: Stream) {
notificationsToken = stream.readString()
action = when (stream.readInt8()) {
1 -> PushNotificationAction.UNSUBSCRIBE
else -> PushNotificationAction.SUBSCRIBE
}
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(notificationsToken)
stream.writeInt8(action.value)
return stream
}
}

View File

@@ -0,0 +1,31 @@
package com.rosetta.messenger.network
/**
* Push Token packet (ID: 0x0A) - DEPRECATED
* Старый формат, заменен на PacketPushNotification (0x10)
*/
class PacketPushToken : Packet() {
var privateKey: String = ""
var publicKey: String = ""
var pushToken: String = ""
var platform: String = "android" // "android" или "ios"
override fun getPacketId(): Int = 0x0A
override fun receive(stream: Stream) {
privateKey = stream.readString()
publicKey = stream.readString()
pushToken = stream.readString()
platform = stream.readString()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(privateKey)
stream.writeString(publicKey)
stream.writeString(pushToken)
stream.writeString(platform)
return stream
}
}

View File

@@ -0,0 +1,31 @@
package com.rosetta.messenger.network
/**
* Read packet (ID: 0x07)
* Уведомление о прочтении сообщения
* Порядок полей как в Desktop: privateKey, fromPublicKey, toPublicKey
*/
class PacketRead : Packet() {
var privateKey: String = ""
var fromPublicKey: String = ""
var toPublicKey: String = ""
override fun getPacketId(): Int = 0x07
override fun receive(stream: Stream) {
// Desktop: privateKey, fromPublicKey, toPublicKey
privateKey = stream.readString()
fromPublicKey = stream.readString()
toPublicKey = stream.readString()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
// Desktop: privateKey, fromPublicKey, toPublicKey
stream.writeString(privateKey)
stream.writeString(fromPublicKey)
stream.writeString(toPublicKey)
return stream
}
}

View File

@@ -0,0 +1,22 @@
package com.rosetta.messenger.network
/**
* Request Transport packet (ID: 0x0F)
* Запрос адреса транспортного сервера для загрузки/скачивания файлов
*/
class PacketRequestTransport : Packet() {
var transportServer: String = ""
override fun getPacketId(): Int = 0x0F
override fun receive(stream: Stream) {
transportServer = stream.readString()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(transportServer)
return stream
}
}

View File

@@ -0,0 +1,24 @@
package com.rosetta.messenger.network
/**
* Result packet (ID: 0x02)
* Server response for various operations
* Desktop uses: readInt16() for resultCode only
*/
class PacketResult : Packet() {
var resultCode: Int = 0
override fun getPacketId(): Int = 0x02
override fun receive(stream: Stream) {
// Desktop: this.resultCode = stream.readInt16();
resultCode = stream.readInt16()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeInt16(resultCode)
return stream
}
}

View File

@@ -0,0 +1,40 @@
package com.rosetta.messenger.network
/**
* Search packet (ID: 0x03)
* Search for users by username or public key
*/
class PacketSearch : Packet() {
var privateKey: String = ""
var search: String = ""
var users: List<SearchUser> = emptyList()
override fun getPacketId(): Int = 0x03
override fun receive(stream: Stream) {
privateKey = stream.readString()
search = stream.readString()
val userCount = stream.readInt16() // Int16, not Int32!
val usersList = mutableListOf<SearchUser>()
for (i in 0 until userCount) {
// Order: username, title, publicKey, verified, online (matching React Native)
val user = SearchUser(
username = stream.readString(),
title = stream.readString(),
publicKey = stream.readString(),
verified = stream.readInt8(),
online = stream.readInt8()
)
usersList.add(user)
}
users = usersList
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(privateKey)
stream.writeString(search)
return stream
}
}

View File

@@ -0,0 +1,28 @@
package com.rosetta.messenger.network
/**
* Typing packet (ID: 0x0B)
* Порядок полей как в React Native: privateKey, fromPublicKey, toPublicKey
*/
class PacketTyping : Packet() {
var privateKey: String = ""
var fromPublicKey: String = ""
var toPublicKey: String = ""
override fun getPacketId(): Int = 0x0B
override fun receive(stream: Stream) {
privateKey = stream.readString()
fromPublicKey = stream.readString()
toPublicKey = stream.readString()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(privateKey)
stream.writeString(fromPublicKey)
stream.writeString(toPublicKey)
return stream
}
}

View File

@@ -0,0 +1,29 @@
package com.rosetta.messenger.network
/**
* User Info packet (ID: 0x01)
* Get/Set user information
* Protocol order: username, title, privateKey (matching TypeScript version)
*/
class PacketUserInfo : Packet() {
var privateKey: String = ""
var username: String = ""
var title: String = ""
override fun getPacketId(): Int = 0x01
override fun receive(stream: Stream) {
username = stream.readString()
title = stream.readString()
privateKey = stream.readString()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(username)
stream.writeString(title)
stream.writeString(privateKey)
return stream
}
}

View File

@@ -1,540 +0,0 @@
package com.rosetta.messenger.network
/**
* Base class for all protocol packets
*/
abstract class Packet {
abstract fun getPacketId(): Int
abstract fun receive(stream: Stream)
abstract fun send(): Stream
}
/**
* Handshake packet (ID: 0x00)
* First packet sent by client to authenticate with the server
*/
class PacketHandshake : Packet() {
var privateKey: String = ""
var publicKey: String = ""
var protocolVersion: Int = 1
var heartbeatInterval: Int = 15
override fun getPacketId(): Int = 0x00
override fun receive(stream: Stream) {
privateKey = stream.readString()
publicKey = stream.readString()
protocolVersion = stream.readInt8()
heartbeatInterval = stream.readInt8()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(privateKey)
stream.writeString(publicKey)
stream.writeInt8(protocolVersion)
stream.writeInt8(heartbeatInterval)
return stream
}
}
/**
* Result packet (ID: 0x02)
* Server response for various operations
* Desktop uses: readInt16() for resultCode only
*/
class PacketResult : Packet() {
var resultCode: Int = 0
override fun getPacketId(): Int = 0x02
override fun receive(stream: Stream) {
// Desktop: this.resultCode = stream.readInt16();
resultCode = stream.readInt16()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeInt16(resultCode)
return stream
}
}
/**
* Search packet (ID: 0x03)
* Search for users by username or public key
*/
class PacketSearch : Packet() {
var privateKey: String = ""
var search: String = ""
var users: List<SearchUser> = emptyList()
override fun getPacketId(): Int = 0x03
override fun receive(stream: Stream) {
privateKey = stream.readString()
search = stream.readString()
val userCount = stream.readInt16() // Int16, not Int32!
val usersList = mutableListOf<SearchUser>()
for (i in 0 until userCount) {
// Order: username, title, publicKey, verified, online (matching React Native)
val user = SearchUser(
username = stream.readString(),
title = stream.readString(),
publicKey = stream.readString(),
verified = stream.readInt8(),
online = stream.readInt8()
)
usersList.add(user)
}
users = usersList
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(privateKey)
stream.writeString(search)
return stream
}
}
data class SearchUser(
val publicKey: String,
val title: String,
val username: String,
val verified: Int,
val online: Int
)
/**
* User Info packet (ID: 0x01)
* Get/Set user information
* Protocol order: username, title, privateKey (matching TypeScript version)
*/
class PacketUserInfo : Packet() {
var privateKey: String = ""
var username: String = ""
var title: String = ""
override fun getPacketId(): Int = 0x01
override fun receive(stream: Stream) {
username = stream.readString()
title = stream.readString()
privateKey = stream.readString()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(username)
stream.writeString(title)
stream.writeString(privateKey)
return stream
}
}
/**
* Online State enum
*/
enum class OnlineState(val value: Int) {
ONLINE(0),
OFFLINE(1);
companion object {
fun fromBoolean(isOnline: Boolean) = if (isOnline) ONLINE else OFFLINE
}
}
/**
* Public key with online state
*/
data class PublicKeyOnlineState(
val publicKey: String,
val state: OnlineState
)
/**
* Online State packet (ID: 0x05)
* Notify about user online status
* Формат как в React Native: массив {publicKey, state}
*/
class PacketOnlineState : Packet() {
var publicKeysState: MutableList<PublicKeyOnlineState> = mutableListOf()
override fun getPacketId(): Int = 0x05
override fun receive(stream: Stream) {
val count = stream.readInt8()
publicKeysState.clear()
repeat(count) {
val publicKey = stream.readString()
val isOnline = stream.readBoolean()
publicKeysState.add(PublicKeyOnlineState(publicKey, OnlineState.fromBoolean(isOnline)))
}
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeInt8(publicKeysState.size)
publicKeysState.forEach { item ->
stream.writeString(item.publicKey)
stream.writeBoolean(item.state == OnlineState.ONLINE)
}
return stream
}
}
/**
* Online Subscribe packet (ID: 0x04)
* Subscribe to user online status updates
* Формат как в React Native: privateKey + array of publicKeys
*/
class PacketOnlineSubscribe : Packet() {
var privateKey: String = ""
var publicKeys: MutableList<String> = mutableListOf()
override fun getPacketId(): Int = 0x04
override fun receive(stream: Stream) {
privateKey = stream.readString()
val keysCount = stream.readInt16()
publicKeys.clear()
repeat(keysCount) {
publicKeys.add(stream.readString())
}
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(privateKey)
stream.writeInt16(publicKeys.size)
publicKeys.forEach { key ->
stream.writeString(key)
}
return stream
}
fun addPublicKey(publicKey: String) {
publicKeys.add(publicKey)
}
}
// ============================================================================
// MESSAGE PACKETS - Как в React Native версии
// ============================================================================
/**
* Типы вложений
*/
enum class AttachmentType(val value: Int) {
IMAGE(0), // Изображение
MESSAGES(1), // Reply (цитата сообщения)
FILE(2), // Файл
AVATAR(3); // Аватар пользователя
companion object {
fun fromInt(value: Int) = entries.firstOrNull { it.value == value } ?: IMAGE
}
}
/**
* Статус доставки сообщения
*/
enum class DeliveryStatus(val value: Int) {
WAITING(0), // Ожидает отправки
DELIVERED(1), // Доставлено
ERROR(2), // Ошибка
READ(3); // Прочитано
companion object {
fun fromInt(value: Int) = entries.firstOrNull { it.value == value } ?: WAITING
}
}
/**
* Вложение к сообщению
*/
data class MessageAttachment(
val id: String,
val blob: String, // Base64 данные или пусто для CDN
val type: AttachmentType,
val preview: String = "", // Метаданные: "UUID::metadata" или "filesize::filename"
val width: Int = 0,
val height: Int = 0,
val localUri: String = "" // 🚀 Локальный URI для мгновенного отображения (optimistic UI)
)
/**
* Message packet (ID: 0x06)
* Отправка и получение сообщений
*/
class PacketMessage : Packet() {
var fromPublicKey: String = ""
var toPublicKey: String = ""
var content: String = "" // Зашифрованный текст
var chachaKey: String = "" // RSA зашифрованный ключ
var timestamp: Long = 0
var privateKey: String = "" // Hash приватного ключа (для авторизации)
var messageId: String = ""
var attachments: List<MessageAttachment> = emptyList()
override fun getPacketId(): Int = 0x06
override fun receive(stream: Stream) {
fromPublicKey = stream.readString()
toPublicKey = stream.readString()
content = stream.readString()
chachaKey = stream.readString()
timestamp = stream.readInt64()
privateKey = stream.readString()
messageId = stream.readString()
val attachmentCount = stream.readInt8()
val attachmentsList = mutableListOf<MessageAttachment>()
for (i in 0 until attachmentCount) {
attachmentsList.add(MessageAttachment(
id = stream.readString(),
preview = stream.readString(),
blob = stream.readString(),
type = AttachmentType.fromInt(stream.readInt8())
))
}
attachments = attachmentsList
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(fromPublicKey)
stream.writeString(toPublicKey)
stream.writeString(content)
stream.writeString(chachaKey)
stream.writeInt64(timestamp)
stream.writeString(privateKey)
stream.writeString(messageId)
stream.writeInt8(attachments.size)
for (attachment in attachments) {
stream.writeString(attachment.id)
stream.writeString(attachment.preview)
stream.writeString(attachment.blob)
stream.writeInt8(attachment.type.value)
}
return stream
}
}
/**
* Read packet (ID: 0x07)
* Уведомление о прочтении сообщения
* Порядок полей как в Desktop: privateKey, fromPublicKey, toPublicKey
*/
class PacketRead : Packet() {
var privateKey: String = ""
var fromPublicKey: String = ""
var toPublicKey: String = ""
override fun getPacketId(): Int = 0x07
override fun receive(stream: Stream) {
// Desktop: privateKey, fromPublicKey, toPublicKey
privateKey = stream.readString()
fromPublicKey = stream.readString()
toPublicKey = stream.readString()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
// Desktop: privateKey, fromPublicKey, toPublicKey
stream.writeString(privateKey)
stream.writeString(fromPublicKey)
stream.writeString(toPublicKey)
return stream
}
}
/**
* Delivery packet (ID: 0x08)
* Уведомление о доставке сообщения
* Порядок полей как в React Native: toPublicKey, messageId
*/
class PacketDelivery : Packet() {
var messageId: String = ""
var toPublicKey: String = ""
override fun getPacketId(): Int = 0x08
override fun receive(stream: Stream) {
// React Native читает: toPublicKey, messageId
toPublicKey = stream.readString()
messageId = stream.readString()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
// React Native пишет: toPublicKey, messageId
stream.writeString(toPublicKey)
stream.writeString(messageId)
return stream
}
}
/**
* Typing packet (ID: 0x0B)
* Уведомление "печатает..."
*/
/**
* Typing packet (ID: 0x0B)
* Порядок полей как в React Native: privateKey, fromPublicKey, toPublicKey
*/
class PacketTyping : Packet() {
var privateKey: String = ""
var fromPublicKey: String = ""
var toPublicKey: String = ""
override fun getPacketId(): Int = 0x0B
override fun receive(stream: Stream) {
privateKey = stream.readString()
fromPublicKey = stream.readString()
toPublicKey = stream.readString()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(privateKey)
stream.writeString(fromPublicKey)
stream.writeString(toPublicKey)
return stream
}
}
/**
* Chunk packet (ID: 0x09)
* Для разбиения больших пакетов на части (как в Desktop)
* ВАЖНО: chunkIndex и totalChunks - Int16, не Int32!
*/
class PacketChunk : Packet() {
var chunkId: String = ""
var chunkIndex: Int = 0
var totalChunks: Int = 0
var data: ByteArray = ByteArray(0)
override fun getPacketId(): Int = 0x09
override fun receive(stream: Stream) {
// В Desktop: readInt16 для index и total
chunkIndex = stream.readInt16()
totalChunks = stream.readInt16()
chunkId = stream.readString()
data = stream.readBytes()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
// В Desktop: writeInt16 для index и total
stream.writeInt16(chunkIndex)
stream.writeInt16(totalChunks)
stream.writeString(chunkId)
stream.writeBytes(data)
return stream
}
}
/**
* Push Token packet (ID: 0x0A) - DEPRECATED
* Старый формат, заменен на PacketPushNotification (0x10)
*/
class PacketPushToken : Packet() {
var privateKey: String = ""
var publicKey: String = ""
var pushToken: String = ""
var platform: String = "android" // "android" или "ios"
override fun getPacketId(): Int = 0x0A
override fun receive(stream: Stream) {
privateKey = stream.readString()
publicKey = stream.readString()
pushToken = stream.readString()
platform = stream.readString()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(privateKey)
stream.writeString(publicKey)
stream.writeString(pushToken)
stream.writeString(platform)
return stream
}
}
/**
* Push Notification Action
*/
enum class PushNotificationAction(val value: Int) {
SUBSCRIBE(0),
UNSUBSCRIBE(1)
}
/**
* Push Notification packet (ID: 0x10)
* Отправка FCM/APNS токена на сервер для push-уведомлений (новый формат)
* Совместим с React Native версией
*/
class PacketPushNotification : Packet() {
var notificationsToken: String = ""
var action: PushNotificationAction = PushNotificationAction.SUBSCRIBE
override fun getPacketId(): Int = 0x10
override fun receive(stream: Stream) {
notificationsToken = stream.readString()
action = when (stream.readInt8()) {
1 -> PushNotificationAction.UNSUBSCRIBE
else -> PushNotificationAction.SUBSCRIBE
}
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(notificationsToken)
stream.writeInt8(action.value)
return stream
}
}
/**
* Request Transport packet (ID: 0x0F)
* Запрос адреса транспортного сервера для загрузки/скачивания файлов
*/
class PacketRequestTransport : Packet() {
var transportServer: String = ""
override fun getPacketId(): Int = 0x0F
override fun receive(stream: Stream) {
transportServer = stream.readString()
}
override fun send(): Stream {
val stream = Stream()
stream.writeInt16(getPacketId())
stream.writeString(transportServer)
return stream
}
}

View File

@@ -0,0 +1,9 @@
package com.rosetta.messenger.network
data class SearchUser(
val publicKey: String,
val title: String,
val username: String,
val verified: Int,
val online: Int
)