@@ -101,7 +101,8 @@ class ApiService {
101101 StreamSubscription ? _socketSubscription;
102102 Timer ? _pingTimer;
103103 Timer ? _analyticsTimer;
104- int _seq = 0 ;
104+ // Начинаем с 1, чтобы seq=0 (которым обычно приходят server pushes) никогда не совпал с pending request.
105+ int _seq = 1 ;
105106
106107 late final PendingRequestsManager _pendingManager;
107108 bool _socketConnected = false ;
@@ -359,7 +360,7 @@ class ApiService {
359360
360361 // Проверяем ответ
361362 final cmd = response['cmd' ] as int ? ;
362- if (cmd != 0x100 && cmd != 256 ) {
363+ if (cmd != 1 ) {
363364 return null ;
364365 }
365366
@@ -762,11 +763,13 @@ class ApiService {
762763 // Отправляем в стрим
763764 _emitLocal (message);
764765
765- // Завершаем pending только для пакетов-ответов (cmd ∈ {256/0x100=ok, 512/0x200=notFound, 768/0x300=error}).
766- // Пуши от сервера приходят с cmd=0/request и могут случайно совпасть по seq c нашим pending,
767- // что и приводило к крешам типа `payload=40` — pending получал чужой push вместо ответа.
766+ // Завершаем pending только для пакетов-ответов (ok/notFound/error).
767+ // Push'и от сервера (cmd=push) имеют то же значение, что и ok, и тоже могут совпасть
768+ // по seq с нашим pending. Их фильтрация делается на уровне seq: server pushes обычно
769+ // приходят с seq=0 (мы свой counter стартуем с 1+) либо seq, не выданным нашим клиентом.
770+ // Здесь же отсеиваем только request-пакеты (cmd=0), которых от сервера быть не должно.
768771 final cmd = parsed.cmd;
769- final isResponse = cmd == 256 || cmd == 512 || cmd == 768 ;
772+ final isResponse = cmd == CmdType .ok || cmd == CmdType .notFound || cmd == CmdType .error ;
770773 if (isResponse) {
771774 // Передаем ВЕСЬ message (включая cmd), а не только payload
772775 _pendingManager.complete (parsed.seq, message);
@@ -810,7 +813,7 @@ class ApiService {
810813 }
811814 }
812815
813- final seq = _seq++ % 256 ;
816+ final seq = _seq++ & 0xFFFF ;
814817
815818 final completer = _pendingManager.register (
816819 seq,
@@ -856,7 +859,7 @@ class ApiService {
856859 }
857860 }
858861
859- final seq = _seq++ % 256 ;
862+ final seq = _seq++ & 0xFFFF ;
860863
861864 final completer = _pendingManager.register (
862865 seq,
@@ -883,21 +886,18 @@ class ApiService {
883886 int opcode,
884887 Map <String , dynamic > payload,
885888 ) {
886- final verB = Uint8List (1 )..[ 0 ] = ver;
887- final cmdB = Uint8List ( 2 )
888- ..buffer. asByteData (). setUint16 ( 0 , cmd, Endian .big );
889- final seqB = Uint8List ( 1 )..[ 0 ] = seq ;
890- final opcodeB = Uint8List ( 2 )
891- ..buffer. asByteData (). setUint16 (0 , opcode, Endian .big);
889+ // Заголовок: ver(1) + cmd (1) + seq(2 BE) + opcode(2 BE) + packedLen(4 BE) = 10 байт
890+ final header = ByteData ( 10 );
891+ header. setUint8 ( 0 , ver );
892+ header. setUint8 ( 1 , cmd) ;
893+ header. setUint16 ( 2 , seq & 0xFFFF , Endian .big);
894+ header. setUint16 (4 , opcode, Endian .big);
892895
893896 final payloadBytes = msgpack.serialize (payload);
894897 final payloadLen = payloadBytes.length & 0xFFFFFF ;
895- final payloadLenB = Uint8List (4 )
896- ..buffer.asByteData ().setUint32 (0 , payloadLen, Endian .big);
898+ header.setUint32 (6 , payloadLen, Endian .big);
897899
898- return Uint8List .fromList (
899- verB + cmdB + seqB + opcodeB + payloadLenB + payloadBytes,
900- );
900+ return Uint8List .fromList (header.buffer.asUint8List () + payloadBytes);
901901 }
902902
903903 Future <int > _sendMessage (
@@ -937,7 +937,7 @@ class ApiService {
937937 }
938938 }
939939
940- final seq = _seq++ % 256 ;
940+ final seq = _seq++ & 0xFFFF ;
941941
942942 // Регистрируем pending request ДО отправки
943943 _pendingManager.register (
@@ -1087,7 +1087,7 @@ class ApiService {
10871087
10881088 final resp64 = await messages.firstWhere ((m) => m['seq' ] == seq64);
10891089 final cmd = resp64['cmd' ] as int ? ;
1090- if (cmd == 0x300 || cmd == 768 ) {
1090+ if (cmd == 3 ) {
10911091 final err = resp64['payload' ];
10921092 if (err is Map && err['error' ] == 'attachment.not.ready' ) {
10931093 throw err;
0 commit comments