Author: Serhat Güler (@sero583)
Version: 1.0.0
License: MIT
A cross-platform data packet generator for multi-language projects. Generate type-safe packet classes from a single JSON definition.
Supports both JSON and MessagePack serialization formats.
| Language | Indentation | JSON Library | MessagePack Library | Coverage |
|---|---|---|---|---|
| 4 spaces | System.Text.Json (built-in) | MessagePack-CSharp | ||
| 4 spaces | yyjson | msgpack-c | ||
| 2 spaces | dart:convert (built-in) | msgpack_dart | ||
| Tabs | encoding/json (built-in) | vmihailenco/msgpack | ||
| 4 spaces | Jackson | msgpack-java | ||
| 4 spaces | json (built-in) | msgpack-php | ||
| 4 spaces | json (built-in) | msgpack-python | ||
| 4 spaces | serde_json | rmp-serde | ||
| 2 spaces | JSON (built-in) | @msgpack/msgpack |
- JSON-based packet definitions - Define once, generate everywhere
- Dual format support - JSON for debugging, MessagePack for performance
- Deep map conversion - Safe handling of nested structures from msgpack
- Timezone-aware datetime - ISO 8601 format with timezone offset
- Documentation generation - Auto-generate doc comments from descriptions
- Idiomatic code - Follows each language's official style guidelines
- Consistent API - All languages support getters/setters AND parameterized constructors
All 9 supported languages provide a consistent API across packet classes:
| Feature | Description |
|---|---|
| Default constructor | Empty constructor (Java, C++, PHP, C#) or optional parameters (Python, Dart) |
| Parameterized constructor | Constructor accepting all fields for one-line initialization |
| Method | Description |
|---|---|
toJson() / to_json() | Serialize to JSON string (if JSON enabled) |
toMsgPack() / to_msgpack() | Serialize to MessagePack binary (if MsgPack enabled) |
| Getters/Setters | Access and modify individual fields (Java, C++, PHP, C#) |
| Method | Description |
|---|---|
fromJson() / from_json() | Deserialize from JSON string |
fromMsgPack() / from_msgpack() | Deserialize from MessagePack binary |
| Language | Serialize JSON | Serialize MsgPack | Deserialize JSON | Deserialize MsgPack |
|---|---|---|---|---|
| C# | ToJson() | ToMsgPack() | FromJson() | FromMsgPack() |
| C++ | ToJson() | ToMsgPack() | FromJson() | FromMsgPack() |
| Dart | toJson() | toMsgPack() | fromJson() | fromMsgPack() |
| Go ¹ | ToJSON() | ToMsgPack() | MessagePacketFromJSON() | MessagePacketFromMsgPack() |
| Java | toJson() | toMsgPack() | fromJson() | fromMsgPack() |
| PHP | toJson() | toMsgPack() | fromJson() | fromMsgPack() |
| Python | to_json() | to_msgpack() | from_json() | from_msgpack() |
| Rust | to_json() | to_msgpack() | from_json() | from_msgpack() |
| TypeScript | toJSON() | toMsgPack() | fromJSON() | fromMsgPack() |
¹ Go Note: Deserialize functions are standalone (not methods):
MessagePacketFromJSON(data),MessagePacketFromMsgPack(data), etc.
See Quick Start for complete usage examples in all 9 languages.
Clone this repository and ensure Python 3.7+ is installed:
git clone https://github.com/sero583/CrossPacket.git
cd crosspacket- Define your packets in
packets.json:
{
"packets": {
"/chat/MessagePacket": {
"description": "Chat message packet for communication",
"fields": {
"sender_id": {
"type": "string",
"description": "ID of the message sender"
},
"content": {
"type": "string",
"description": "Message content"
},
"timestamp": {
"type": "datetime",
"description": "When the message was sent"
}
}
}
}
}- Generate code:
# Generate all platforms
python generate.py --all
# Generate specific languages
python generate.py --dart --java --typescript
# Override existing files
python generate.py --all --override- Use the generated code (includes dependencies):
C#
Dependencies:
dotnet add package MessagePackNote:
System.Text.Jsonis built-in for .NET 6+.
Usage:
usingSystem;// === CONSTRUCTION ===// Option 1: Object initializer (recommended)varpacket=newMessagePacket{SenderId="user123",Content="Hello, world!",Timestamp=DateTimeOffset.Now};// Option 2: Parameterized constructorvarpacket2=newMessagePacket("user123","Hello, world!",DateTimeOffset.Now);// === SERIALIZATION ===// To JSON (human-readable)stringjson=packet.ToJson();// To MessagePack (compact binary)byte[]binary=packet.ToMsgPack();// === DESERIALIZATION ===// From JSONvarfromJson=MessagePacket.FromJson(json);Console.WriteLine(fromJson.SenderId);// "user123"// From MessagePackvarfromBinary=MessagePacket.FromMsgPack(binary);Console.WriteLine(fromBinary.Content);// "Hello, world!"// === ROUND-TRIP EXAMPLE ===varoriginal=newMessagePacket("alice","Hi!",DateTimeOffset.Now);byte[]binaryData=original.ToMsgPack();varrestored=MessagePacket.FromMsgPack(binaryData);Debug.Assert(original.SenderId==restored.SenderId);Debug.Assert(original.Content==restored.Content);C++
Dependencies:
# CMakeLists.txtfind_package(yyjsonREQUIRED)
find_package(msgpack-cxxREQUIRED)
target_link_libraries(your_targetyyjsonmsgpack-cxx)Or with vcpkg:
vcpkg install yyjson msgpackUsage:
#include"message_packet.hpp"
#include<chrono>// === CONSTRUCTION ===// Option 1: Default constructor + setters
MessagePacket packet;
packet.SetSenderId("user123");
packet.SetContent("Hello, world!");
packet.SetTimestamp(std::chrono::system_clock::now());
// === SERIALIZATION ===// To JSON (human-readable)
std::string json = packet.ToJson();
// To MessagePack (compact binary)
std::vector<uint8_t> binary = packet.ToMsgPack();
// === DESERIALIZATION ===// From JSONauto fromJson = MessagePacket::FromJson(json);
std::cout << fromJson.GetSenderId() << std::endl; // "user123"// From MessagePackauto fromBinary = MessagePacket::FromMsgPack(binary);
std::cout << fromBinary.GetContent() << std::endl; // "Hello, world!"// === ROUND-TRIP EXAMPLE ===
MessagePacket original;
original.SetSenderId("alice");
original.SetContent("Hi!");
auto binaryData = original.ToMsgPack();
auto restored = MessagePacket::FromMsgPack(binaryData);
assert(original.GetSenderId() == restored.GetSenderId());Dart
Dependencies:
# pubspec.yamldependencies:
msgpack_dart: ^1.0.1Usage:
import'dart:typed_data';
import'message_packet.dart';
// === CONSTRUCTION ===// Option 1: Parameterized constructor (named parameters, all optional)final packet =MessagePacket.create(
senderId:'user123',
content:'Hello, world!',
timestamp:DateTime.now(),
);
// Option 2: Default constructor + settersfinal packet2 =MessagePacket();
packet2.senderId ='user123';
packet2.content ='Hello, world!';
packet2.timestamp =DateTime.now();
// === SERIALIZATION ===// To JSON (human-readable)String json = packet.toJson();
// To MessagePack (compact binary)Uint8List binary = packet.toMsgPack();
// === DESERIALIZATION ===// From JSONfinal fromJson =MessagePacket.fromJson(json);
print(fromJson.content); // 'Hello, world!'// From MessagePackfinal fromBinary =MessagePacket.fromMsgPack(binary);
print(fromBinary.timestamp);
// === ROUND-TRIP EXAMPLE ===final original =MessagePacket.create(
senderId:'alice',
content:'Hi!',
timestamp:DateTime.now(),
);
final binaryData = original.toMsgPack();
final restored =MessagePacket.fromMsgPack(binaryData);
assert(original.content == restored.content);Go
Dependencies:
go get github.com/vmihailenco/msgpack/v5Usage:
import"time"// === CONSTRUCTION ===// Struct literal (Go's standard pattern)packet:=&MessagePacket{
SenderId: "user123",
Content: "Hello, world!",
Timestamp: time.Now(),
}
// === SERIALIZATION ===// To JSON (human-readable)jsonBytes, err:=packet.ToJSON()
// To MessagePack (compact binary)binary, err:=packet.ToMsgPack()
// === DESERIALIZATION ===// From JSONfromJson, err:=MessagePacketFromJSON(jsonBytes)
fmt.Println(fromJson.SenderId) // "user123"// From MessagePackfromBinary, err:=MessagePacketFromMsgPack(binary)
fmt.Println(fromBinary.Content) // "Hello, world!"// === ROUND-TRIP EXAMPLE ===original:=&MessagePacket{
SenderId: "alice",
Content: "Hi!",
Timestamp: time.Now(),
}
binaryData, _:=original.ToMsgPack()
restored, _:=MessagePacketFromMsgPack(binaryData)
// original.SenderId == restored.SenderIdJava
Dependencies (Maven):
<!-- pom.xml -->
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>msgpack-core</artifactId>
<version>0.9.11</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>Or with Gradle:
implementation 'org.msgpack:msgpack-core:0.9.11'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'Usage:
importjava.time.ZonedDateTime;
// === CONSTRUCTION ===// Option 1: Parameterized constructorMessagePacketpacket = newMessagePacket(
"user123",
"Hello, world!",
ZonedDateTime.now()
);
// Option 2: Default constructor + settersMessagePacketpacket2 = newMessagePacket();
packet2.setSenderId("user123");
packet2.setContent("Hello, world!");
packet2.setTimestamp(ZonedDateTime.now());
// === SERIALIZATION ===// To JSON (human-readable)Stringjson = packet.toJson();
// To MessagePack (compact binary)byte[] binary = packet.toMsgPack();
// === DESERIALIZATION ===// From JSONMessagePacketfromJson = MessagePacket.fromJson(json);
System.out.println(fromJson.getSenderId()); // "user123"// From MessagePackMessagePacketfromBinary = MessagePacket.fromMsgPack(binary);
System.out.println(fromBinary.getContent()); // "Hello, world!"// === ROUND-TRIP EXAMPLE ===MessagePacketoriginal = newMessagePacket("alice", "Hi!", ZonedDateTime.now());
byte[] binaryData = original.toMsgPack();
MessagePacketrestored = MessagePacket.fromMsgPack(binaryData);
assertoriginal.getSenderId().equals(restored.getSenderId());
assertoriginal.getContent().equals(restored.getContent());PHP
Dependencies:
# Install msgpack extension
pecl install msgpack
# Add to php.ini
extension=msgpack.soOr with composer (for polyfill):
composer require rybakit/msgpackUsage:
<?phpuseApp\DataPackets\MessagePacket;
// === CONSTRUCTION ===// Option 1: Parameterized constructor$packet = newMessagePacket(
'user123',
'Hello, world!',
newDateTimeImmutable()
);
// Option 2: Default constructor + setters$packet2 = newMessagePacket();
$packet2->setSenderId('user123');
$packet2->setContent('Hello, world!');
$packet2->setTimestamp(newDateTimeImmutable());
// === SERIALIZATION ===// To JSON (human-readable)$json = $packet->toJson();
// To MessagePack (compact binary)$binary = $packet->toMsgPack();
// === DESERIALIZATION ===// From JSON$fromJson = MessagePacket::fromJson($json);
echo$fromJson->getSenderId(); // 'user123'// From MessagePack$fromBinary = MessagePacket::fromMsgPack($binary);
echo$fromBinary->getContent(); // 'Hello, world!'// === ROUND-TRIP EXAMPLE ===$original = newMessagePacket('alice', 'Hi!', newDateTimeImmutable());
$binaryData = $original->toMsgPack();
$restored = MessagePacket::fromMsgPack($binaryData);
assert($original->getSenderId() === $restored->getSenderId());
assert($original->getContent() === $restored->getContent());Python
Dependencies:
pip install msgpackUsage:
fromdatetimeimportdatetime, timezonefrommessage_packetimportMessagePacket# === CONSTRUCTION ===# Option 1: Parameterized constructor (all params optional with None defaults)packet=MessagePacket(
sender_id='user123',
content='Hello, world!',
timestamp=datetime.now(timezone.utc),
)
# Option 2: Default constructor + setterspacket=MessagePacket()
packet.sender_id='user123'packet.content='Hello, world!'packet.timestamp=datetime.now(timezone.utc)
# === SERIALIZATION ===# To JSON (human-readable, for debugging/logging)json_str: str=packet.to_json()
# '{"packetType": "/chat/MessagePacket", "sender_id": "user123", "content": "Hello, world!", ...}'# To MessagePack (compact binary, for network transmission)binary: bytes=packet.to_msgpack()
# === DESERIALIZATION ===# From JSONreceived=MessagePacket.from_json(json_str)
print(received.content) # 'Hello, world!'# From MessagePackreceived=MessagePacket.from_msgpack(binary)
print(received.timestamp) # datetime object# === ROUND-TRIP EXAMPLE ===original=MessagePacket(sender_id='alice', content='Hi!', timestamp=datetime.now(timezone.utc))
binary_data=original.to_msgpack()
restored=MessagePacket.from_msgpack(binary_data)
assertoriginal.content==restored.contentRust
Dependencies:
# Cargo.toml
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"rmp-serde = "1.3"chrono = { version = "0.4", features = ["serde"] }Usage:
use chrono::Utc;// === CONSTRUCTION ===// Struct initialization (Rust's standard pattern)let packet = MessagePacket{sender_id:"user123".to_string(),content:"Hello, world!".to_string(),timestamp:Utc::now(),};// === SERIALIZATION ===// To JSON (human-readable)let json:String = packet.to_json()?;// To MessagePack (compact binary)let binary:Vec<u8> = packet.to_msgpack()?;// === DESERIALIZATION ===// From JSONlet from_json = MessagePacket::from_json(&json)?;println!("{}", from_json.sender_id);// "user123"// From MessagePacklet from_binary = MessagePacket::from_msgpack(&binary)?;println!("{}", from_binary.content);// "Hello, world!"// === ROUND-TRIP EXAMPLE ===let original = MessagePacket{sender_id:"alice".to_string(),content:"Hi!".to_string(),timestamp:Utc::now(),};let binary_data = original.to_msgpack()?;let restored = MessagePacket::from_msgpack(&binary_data)?;assert_eq!(original.sender_id, restored.sender_id);assert_eq!(original.content, restored.content);TypeScript
Dependencies:
npm install @msgpack/msgpackUsage:
import{MessagePacket}from"./message_packet";// === CONSTRUCTION ===// Option 1: Object initializer (recommended)constpacket=newMessagePacket({senderId: "user123",content: "Hello, world!",timestamp: newDate(),});// Option 2: Empty constructor + property assignmentconstpacket2=newMessagePacket({});packet2.senderId="user123";packet2.content="Hello, world!";packet2.timestamp=newDate();// === SERIALIZATION ===// To JSON (returns string)constjson: string=packet.toJSON();// To MessagePack (compact binary)constbinary: Uint8Array=packet.toMsgPack();// === DESERIALIZATION ===// From JSON (accepts string)constfromJson=MessagePacket.fromJSON(json);console.log(fromJson.senderId);// 'user123'// From MessagePackconstfromBinary=MessagePacket.fromMsgPack(binary);console.log(fromBinary.content);// 'Hello, world!'// === ROUND-TRIP EXAMPLE ===constoriginal=newMessagePacket({senderId: "alice",content: "Hi!",timestamp: newDate(),});constbinaryData=original.toMsgPack();constrestored=MessagePacket.fromMsgPack(binaryData);console.assert(original.senderId===restored.senderId);Note: Both serialization formats are optional. Use
--no-msgpackfor JSON-only code or--no-jsonfor MessagePack-only code.
All generated packets throw exceptions when deserialization fails. Here's how to handle errors in each language:
C#
try{varpacket=MessagePacket.FromJson(invalidJson);}catch(JsonExceptionex){Console.WriteLine($"JSON parse error: {ex.Message}");}catch(MessagePackSerializationExceptionex){Console.WriteLine($"MsgPack error: {ex.Message}");}C++
try {
auto packet = MessagePacket::FromJson(invalidJson);
} catch (const std::runtime_error& e) {
std::cerr << "Parse error: " << e.what() << std::endl;
}Dart
try {
final packet =MessagePacket.fromJson(invalidJson);
} onFormatExceptioncatch (e) {
print('JSON parse error: ${e.message}');
}Go
packet, err:=MessagePacketFromJSON(invalidJson)
iferr!=nil {
log.Printf("Parse error: %v", err)
return
}Java
try {
MessagePacketpacket = MessagePacket.fromJson(invalidJson);
} catch (JsonProcessingExceptione) {
System.err.println("JSON parse error: " + e.getMessage());
} catch (IOExceptione) {
System.err.println("MsgPack error: " + e.getMessage());
}PHP
try {
$packet = MessagePacket::fromJson($invalidJson);
} catch (JsonException$e) {
echo"JSON parse error: " . $e->getMessage();
}Python
try:
packet=MessagePacket.from_json(invalid_json)
exceptjson.JSONDecodeErrorase:
print(f"JSON parse error: {e}")
exceptExceptionase:
print(f"Deserialization error: {e}")Rust
matchMessagePacket::from_json(&invalid_json){Ok(packet) => println!("Parsed: {:?}", packet),Err(e) => eprintln!("Parse error: {}", e),}// Or with ? operatorlet packet = MessagePacket::from_json(&json)?;TypeScript
try{constpacket=MessagePacket.fromJSON(invalidJson);}catch(error){console.error("Parse error:",errorinstanceofError ? error.message : error);}{
"config": {
"global": {
"strict_validation": true,
"generate_security_utils": true,
"schema_version": "1.0.0",
"type_field": "packetType",
"serialization": {
"json": true,
"msgpack": true
}
}
}
}The serialization setting controls which serialization formats are generated:
| Setting | Effect |
|---|---|
json: true (default) | Generate JSON serialization methods |
json: false | Omit JSON methods (equivalent to --no-json CLI flag) |
msgpack: true (default) | Generate MessagePack serialization methods |
msgpack: false | Omit MessagePack methods (equivalent to --no-msgpack CLI flag) |
Note: CLI flags (
--no-json,--no-msgpack) take precedence over config file settings.
The type_field setting controls the name of the field used to identify packet types in serialized data:
{
"config": {
"global": {
"type_field": "packetType"
}
}
}| Setting | Effect |
|---|---|
type_field: "packetType" (default) | Serialized packets include "packetType": "/path/PacketName" |
type_field: "customName" | Use custom field name for type identification |
⚠️ Important: The configuredtype_fieldname is reserved and cannot be used as a field name in any packet definition. The generator will exit with an error if you attempt to use a reserved field name.Example: With default settings (
type_field: "packetType"), you cannot create a field namedpacketType. If you need a field calledtype, you can safely use it sincetypeis not the reserved name.
This is useful when:
- Your application already uses
typefor other purposes - You want a more descriptive field name like
messageTypeoreventKind - You need to match an existing protocol's naming convention
{
"config": {
"dart": {
"output_dir": "./output/dart",
"base_package": "your_package"
},
"java": {
"output_dir": "./output/java",
"package": "com.example.packets"
},
"typescript": {
"output_dir": "./output/typescript"
},
"rust": {
"output_dir": "./output/rust"
},
"go": {
"output_dir": "./output/go",
"package": "packets"
},
"python": {
"output_dir": "./output/python"
},
"cpp": {
"output_dir": "./output/cpp",
"namespace": "packets"
},
"csharp": {
"output_dir": "./output/csharp",
"namespace": "CrossPacket.Packets"
},
"php": {
"output_dir": "./output/php",
"namespace": "App\\DataPackets"
}
}
}| Type | Dart | Java | TypeScript | Rust | Go | Python | C++ | C# | PHP |
|---|---|---|---|---|---|---|---|---|---|
int | int | long | number | i64 | int64 | int | int64_t | long | int |
float | double | double | number | f64 | float64 | float | double | double | float |
double | double | double | number | f64 | float64 | float | double | double | float |
bool | bool | boolean | boolean | bool | bool | bool | bool | bool | bool |
string | String | String | string | String | string | str | std::string | string | string |
datetime | DateTime | ZonedDateTime | Date | DateTime<Utc> | time.Time | datetime | std::string | DateTimeOffset | DateTimeImmutable |
time | Duration | LocalTime | string | String | string | time | std::string | TimeSpan | string |
bytes | Uint8List | byte[] | Uint8Array | Vec<u8> | []byte | bytes | vector<uint8_t> | byte[] | string |
list | List<dynamic> | List<Object> | any[] | Vec<Value> | []interface{} | List[Any] | std::string (JSON) | List<object> | array |
list_int | List<int> | List<Long> | number[] | Vec<i64> | []int64 | List[int] | vector<int64_t> | List<long> | array |
list_string | List<String> | List<String> | string[] | Vec<String> | []string | List[str] | vector<string> | List<string> | array |
map | Map<String, dynamic> | Map<String, Object> | Record<string, any> | HashMap | map[string]interface{} | Dict[str, Any] | std::string (JSON) | Dictionary<string, object> | array |
embedded_map | Map<dynamic, dynamic> | Map<Object, Object> | Map<any, any> | HashMap | map[string]interface{} | Dict[Any, Any] | std::string (JSON) | Dictionary<string, object> | array |
map_string_dynamic | Map<String, dynamic> | Map<String, Object> | Record<string, any> | HashMap<String, Value> | map[string]interface{} | Dict[str, Any] | std::string (JSON) | Dictionary<string, object?> | array |
Note: For
embedded_mapin C#, keys are converted to strings for JSON compatibility. MsgPack supports any key type.
{
"fields": {
"required_field": {
"type": "string",
"description": "This field is required"
},
"optional_field": {
"type": "int",
"description": "This field is optional",
"optional": true
}
}
}CrossPacket supports granular field-level validation that can override global settings. This enables fine-tuned control for security-critical applications.
Define global validation limits in the config section:
{
"config": {
"global": {
"strict_validation": true,
"generate_security_utils": true,
"schema_version": "1.0.0"
},
"validation": {
"max_int": 9007199254740991,
"min_int": -9007199254740991,
"max_list_size": 100000,
"max_map_size": 100000,
"max_string_length": 10000000,
"max_bytes_length": 104857600
}
}
}Override global settings for individual fields:
{
"packets": {
"/user/ProfilePacket": {
"description": "User profile with strict validation",
"fields": {
"username": {
"type": "string",
"description": "Unique username",
"validation": {
"required": true,
"min": 3,
"max": 50,
"pattern": "^[a-zA-Z0-9_]+$",
"allow_empty": false
}
},
"age": {
"type": "int",
"description": "User age",
"validation": {
"required": true,
"min": 0,
"max": 150
}
},
"balance": {
"type": "float",
"description": "Account balance",
"validation": {
"required": true,
"min": 0.0,
"max": 1000000.0,
"allow_nan": false,
"allow_infinity": false
}
},
"friends_list": {
"type": "list_string",
"description": "List of friend IDs",
"validation": {
"max": 1000
}
},
"nested_data": {
"type": "map",
"description": "Nested configuration",
"validation": {
"max_depth": 3
}
}
}
}
}
}| Property | Applies To | Description |
|---|---|---|
required | All types | Field must be present (default: false) |
min | int, float, string, list, bytes | Minimum value or length |
max | int, float, string, list, bytes | Maximum value or length |
pattern | string | Regex pattern for validation |
allow_empty | string | Allow empty strings (default: true) |
allow_nan | float, double | Allow NaN values (default: true) |
allow_infinity | float, double | Allow Infinity values (default: true) |
max_depth | map, embedded_map | Maximum nesting depth |
For high-security applications:
⚠️ Security Note: This example demonstrates how to structure a packet that contains encrypted data and cryptographic fields. CrossPacket does not implement encryption — it only handles serialization. You must implement the actual encryption/decryption, key management, and HMAC verification in your application code using appropriate cryptographic libraries (e.g., OpenSSL, libsodium, BouncyCastle).
{
"/secure/MessagePacket": {
"description": "Security-hardened message packet",
"version": "2.1.0",
"fields": {
"message_id": {
"type": "string",
"description": "Unique message identifier (UUID v4)",
"validation": {
"required": true,
"min": 36,
"max": 36,
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
}
},
"encryption_key": {
"type": "bytes",
"description": "256-bit AES key",
"validation": {
"required": true,
"min": 32,
"max": 32
}
},
"payload": {
"type": "bytes",
"description": "Encrypted payload",
"validation": {
"required": true,
"max": 1048576
}
},
"timestamp": {
"type": "datetime",
"description": "Message timestamp",
"validation": {
"required": true
}
},
"hmac_signature": {
"type": "bytes",
"description": "HMAC-SHA256 signature",
"validation": {
"required": true,
"min": 32,
"max": 32
}
}
}
}
}Add version information to packets for API compatibility:
{
"/api/UserPacket": {
"description": "User data packet",
"version": "2.0.0",
"deprecated": false,
"fields": { ... }
}
}The version field follows semantic versioning and is embedded in generated code comments. Set deprecated: true to mark packets that should be phased out.
MessagePack is a binary serialization format that provides:
- Smaller payloads - More compact than JSON (actual savings vary by data structure)
- Faster parsing - Binary parsing outperforms text parsing
- Type-rich - Native support for binary data, maps, arrays
- Cross-platform - Libraries available for all major languages
Ideal for:
- WebSocket communication
- Real-time applications
- Mobile apps with bandwidth constraints
- High-performance servers
CrossPacket includes optional security utilities for hardening generated packets in security-critical applications.
The generated code includes security utility modules for Python and C#:
Python (output/python/security_utils.py):
fromsecurity_utilsimport (
ValidationError,
SecurityLimits,
validate_int,
validate_string,
validate_list,
validate_map,
validate_required_fields,
)
# Configure custom limits for your applicationlimits=SecurityLimits(
max_int=2**31, # 32-bit rangemax_list_size=10000,
max_map_size=10000,
max_string_length=1000000,
)
# Validate incoming data before creating packetstry:
validate_required_fields(data, ["user_id", "amount", "timestamp"], "TransactionPacket")
user_id=validate_string(data["user_id"], "user_id", limits, min_length=1)
amount=validate_int(data["amount"], "amount", limits)
items=validate_list(data["items"], "items", limits)
exceptValidationErrorase:
logger.error(f"Validation failed: {e.field} - {e.message}")
raiseC# (output/csharp/SecurityUtils.cs):
usingCrossPacket;// Use strict limits for high-security applicationsvarlimits=SecurityLimits.Strict;try{PacketValidator.ValidateRequiredFields(data,new[]{"user_id","amount"},"TransactionPacket");varuserId=PacketValidator.ValidateString(data["user_id"],"user_id",limits,minLength:1);varamount=PacketValidator.ValidateInt(data["amount"],"amount",limits);varitems=PacketValidator.ValidateList<object>(data["items"],"items",limits);}catch(ValidationExceptionex){logger.Error($"Validation failed: {ex.FieldName} - {ex.Message}");throw;}| Feature | Description |
|---|---|
| Bounds Checking | Integer overflow/underflow detection |
| Size Limits | Configurable max sizes for lists, maps, strings, bytes |
| Required Fields | Explicit validation of mandatory fields |
| Type Validation | Strict type checking (no implicit coercion) |
| NaN/Infinity | Float validation with configurable handling |
| Error Context | Detailed error messages with field names and values |
- Always validate untrusted input using the security utilities before creating packets
- Set appropriate limits based on your application's needs
- Log validation failures for security monitoring
- Consider HMAC signing for packet integrity (implement as wrapper)
- Use schema versioning for backward/forward compatibility
usage: generate.py [-h] [--config CONFIG] [--dart] [--python] [--java]
[--typescript] [--rust] [--go] [--cpp] [--csharp] [--php] [--all]
[--override] [--clean] [--no-msgpack] [--no-json] [--version]
Options:
--config FILE Path to packets.json (default: ./packets.json)
--dart Generate Dart code
--python Generate Python code
--java Generate Java code
--typescript Generate TypeScript code
--rust Generate Rust code
--go Generate Go code
--cpp Generate C++ code
--csharp Generate C# code
--php Generate PHP code
--all Generate all platforms
--override Override existing files
--clean Remove old generated files first
--no-msgpack Generate JSON-only code (no MessagePack dependency)
--no-json Generate MessagePack-only code (no JSON dependency)
--version Show version
All 9 supported languages have comprehensive test suites in their respective tests/{language}/ folders.
# Python (pytest)
python -m pytest tests/ -v
# Dartcd tests/dart && dart run test_comprehensive.dart
# Gocd tests/go && go run test_comprehensive.go
# TypeScriptcd tests/typescript && npx ts-node test_comprehensive.ts
# Rustcd tests/rust && cargo run
# Java (via Maven)cd tests/java && mvn compile exec:java
# C# (.NET 9)cd tests/csharp && dotnet run
# PHP
php tests/php/test_comprehensive.php| Category | Test Cases |
|---|---|
| Integers | 0, 1, -1, INT_MAX, INT_MIN, powers of 2, Fibonacci, primes |
| Floats | Zero, precision (pi, euler, golden ratio), scientific notation |
| Strings | Empty, whitespace, escape sequences, URLs, paths, JSON/XML/HTML embedded |
| Lists | Empty, nested 2D/3D, irregular, 10-level deep, mixed types, sparse |
| Maps | Empty, nested 4 levels, arrays in maps, special keys, null values |
| Complex | User profiles, API responses, graph/tree structures, config files |
python -m pytest tests/ -vcrosspacket/
├── generate.py # Main generator
├── packets.json # Packet definitions
├── packets.schema.json # JSON Schema validation
├── tests/
│ ├── test_generator.py # Generator unit tests
│ ├── test_serialization.py # Serialization tests
│ ├── test_data.json # Shared test data
│ ├── python/ # Python tests
│ ├── dart/ # Dart tests
│ ├── typescript/ # TypeScript tests
│ ├── java/ # Java tests (Maven)
│ ├── go/ # Go tests
│ ├── rust/ # Rust tests (Cargo)
│ ├── csharp/ # C# tests (.NET)
│ ├── cpp/ # C++ tests
│ └── php/ # PHP tests
└── output/ # Generated code (gitignored)
See CONTRIBUTING.md for guidelines.
CrossPacket has comprehensive test coverage across all 9 languages. See TESTING.md for:
- Test suite documentation for each language
- Coverage targets and current status
- How to run tests locally
- Edge cases and error handling coverage
Core Features:
- Cross-platform data packet generator supporting 9 languages
- JSON and MessagePack dual serialization formats
- Field-level validation with configurable strictness
- Security utilities for Python and C#
Supported Languages:
- C#, C++, Dart, Go, Java, PHP, Python, Rust, TypeScript
Testing & Coverage:
- Comprehensive test suites for all 9 languages
- Integrated Codecov for dynamic coverage tracking
- CI workflows for automated testing across all languages
Generator Features:
- Configurable
type_fieldfor packet type identification - Proper handling of all field types including bytes, maps, and nested structures
- Idiomatic code generation following each language's style guide
MIT License - see LICENSE for details.
