• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nogipx / rpc_dart / 23169302222

16 Mar 2026 10:40PM UTC coverage: 76.365% (+0.2%) from 76.156%
23169302222

push

github

nogipx
update deps

3887 of 5090 relevant lines covered (76.37%)

8.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.59
/packages/rpc_dart/lib/src/core/protocol.dart
1
// SPDX-FileCopyrightText: 2025 Karim "nogipx" Mamatkazin <nogipx@gmail.com>
2
// SPDX-FileCopyrightText: 2026 Karim "nogipx" Mamatkazin <nogipx@gmail.com>
3
//
4
// SPDX-License-Identifier: MIT
5

6
import 'dart:typed_data';
7

8
import 'errors.dart';
9

10
/// gRPC message framing constants.
11
///
12
/// Centralizes fixed values for the 5-byte gRPC message prefix.
13
/// Header name constants have moved to [RpcHeaders].
14
abstract interface class RpcConstants {
15
  /// Message prefix size in bytes (1 byte flag + 4 bytes length).
16
  static const int messagePrefixSize = 5;
17

18
  /// Compression-flag index inside the prefix.
19
  static const int compressionFlagIndex = 0;
20

21
  /// Start index of the message-length field.
22
  static const int messageLengthIndex = 1;
23

24
  /// Flag value for uncompressed message.
25
  static const int noCompression = 0;
26

27
  /// Flag value for compressed message.
28
  static const int compressed = 1;
29
}
30

31
/// Standard gRPC status codes.
32
///
33
/// Enumerates completion statuses such as:
34
/// - OK (0): success
35
/// - CANCELLED (1): operation cancelled
36
/// - DEADLINE_EXCEEDED (4): timeout
37
/// - INTERNAL (13): server internal error
38
/// - UNAVAILABLE (14): service unavailable
39
abstract interface class RpcStatus {
40
  /// Successful completion.
41
  static const int ok = 0;
42

43
  /// Operation cancelled.
44
  static const int cancelled = 1;
45

46
  /// Unknown error.
47
  static const int unknown = 2;
48

49
  /// Invalid argument.
50
  static const int invalidArgument = 3;
51

52
  /// Deadline exceeded.
53
  static const int deadlineExceeded = 4;
54

55
  /// Resource not found.
56
  static const int notFound = 5;
57

58
  /// Resource already exists.
59
  static const int alreadyExists = 6;
60

61
  /// Permission denied.
62
  static const int permissionDenied = 7;
63

64
  /// Resource exhausted.
65
  static const int resourceExhausted = 8;
66

67
  /// Precondition failed.
68
  static const int failedPrecondition = 9;
69

70
  /// Operation aborted.
71
  static const int aborted = 10;
72

73
  /// Out of range.
74
  static const int outOfRange = 11;
75

76
  /// Not implemented.
77
  static const int unimplemented = 12;
78

79
  /// Internal error.
80
  static const int internal = 13;
81

82
  /// Service unavailable.
83
  static const int unavailable = 14;
84

85
  /// Data loss.
86
  static const int dataLoss = 15;
87

88
  /// Unauthenticated.
89
  static const int unauthenticated = 16;
90
}
91

92
/// Utilities for gRPC message framing.
93
///
94
/// Handles packing/unpacking messages with the 5-byte prefix required by gRPC
95
/// and extracting compression and length information.
96
///
97
/// Prefix format:
98
/// - Byte 1: compression flag (0 or 1)
99
/// - Bytes 2-5: message length (uint32, big-endian)
100
abstract interface class RpcMessageFrame {
101
  /// Packs a message with the gRPC 5-byte prefix.
102
  ///
103
  /// Prepends the standard prefix describing compression and payload length.
104
  ///
105
  /// [messageBytes] Serialized message bytes.
106
  /// [compressed] Whether the payload is compressed.
107
  /// Returns the fully framed message.
108
  static Uint8List encode(Uint8List messageBytes, {bool compressed = false}) {
17✔
109
    final result = List<int>.filled(
17✔
110
      RpcConstants.messagePrefixSize + messageBytes.length,
34✔
111
      0,
112
    );
113

114
    // Write compression flag.
115
    result[RpcConstants.compressionFlagIndex] =
17✔
116
        compressed ? RpcConstants.compressed : RpcConstants.noCompression;
117

118
    // Write message length (big-endian).
119
    final length = messageBytes.length;
17✔
120
    result[RpcConstants.messageLengthIndex] = (length >> 24) & 0xFF;
51✔
121
    result[RpcConstants.messageLengthIndex + 1] = (length >> 16) & 0xFF;
68✔
122
    result[RpcConstants.messageLengthIndex + 2] = (length >> 8) & 0xFF;
68✔
123
    result[RpcConstants.messageLengthIndex + 3] = length & 0xFF;
51✔
124

125
    // Copy payload bytes.
126
    for (int i = 0; i < messageBytes.length; i++) {
51✔
127
      result[RpcConstants.messagePrefixSize + i] = messageBytes[i];
51✔
128
    }
129

130
    return Uint8List.fromList(result);
17✔
131
  }
132

133
  /// Parses the message header extracting compression and length info.
134
  ///
135
  /// Expects the 5-byte gRPC prefix.
136
  ///
137
  /// [headerBytes] Prefix bytes (length must be >= 5).
138
  /// Returns header info or throws on invalid input length.
139
  static RpcMessageHeader parseHeader(Uint8List headerBytes) {
18✔
140
    if (headerBytes.length < RpcConstants.messagePrefixSize) {
36✔
141
      throw RpcException('Invalid gRPC message header length');
1✔
142
    }
143

144
    final compressionFlag = headerBytes[RpcConstants.compressionFlagIndex];
18✔
145
    if (compressionFlag != RpcConstants.noCompression &&
18✔
146
        compressionFlag != RpcConstants.compressed) {
13✔
147
      throw RpcException(
×
148
        'Invalid compression flag in gRPC message: $compressionFlag',
×
149
      );
150
    }
151

152
    final isCompressed = compressionFlag == RpcConstants.compressed;
18✔
153

154
    final length = (headerBytes[RpcConstants.messageLengthIndex] << 24) |
54✔
155
        (headerBytes[RpcConstants.messageLengthIndex + 1] << 16) |
72✔
156
        (headerBytes[RpcConstants.messageLengthIndex + 2] << 8) |
72✔
157
        headerBytes[RpcConstants.messageLengthIndex + 3];
36✔
158

159
    return RpcMessageHeader(isCompressed, length);
18✔
160
  }
161
}
162

163
/// Information extracted from the 5-byte gRPC message prefix.
164
///
165
/// Holds compression and length details parsed from the prefix.
166
final class RpcMessageHeader {
167
  /// Whether the message is compressed.
168
  final bool isCompressed;
169

170
  /// Payload length in bytes.
171
  final int messageLength;
172

173
  /// Creates a header description.
174
  RpcMessageHeader(this.isCompressed, this.messageLength);
18✔
175
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc