Skip to content

Repository files navigation

CrossPacket

CI StatusCoveragePython 3.9+License: MITVersion

Author: Serhat Güler (@sero583)
Version: 1.0.0
License: MIT

CrossPacket - Define Once, Generate Everywhere

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.

Supported Languages

LanguageIndentationJSON LibraryMessagePack LibraryCoverage
C#4 spacesSystem.Text.Json (built-in)MessagePack-CSharpCoverage
C++4 spacesyyjsonmsgpack-cCoverage
Dart2 spacesdart:convert (built-in)msgpack_dartCoverage
GoTabsencoding/json (built-in)vmihailenco/msgpackCoverage
Java4 spacesJacksonmsgpack-javaCoverage
PHP4 spacesjson (built-in)msgpack-phpCoverage
Python4 spacesjson (built-in)msgpack-pythonCoverage
Rust4 spacesserde_jsonrmp-serdeCoverage
TypeScript2 spacesJSON (built-in)@msgpack/msgpackCoverage

Features

  • 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

Generated API

All 9 supported languages provide a consistent API across packet classes:

Constructors

FeatureDescription
Default constructorEmpty constructor (Java, C++, PHP, C#) or optional parameters (Python, Dart)
Parameterized constructorConstructor accepting all fields for one-line initialization

Instance Methods

MethodDescription
toJson() / to_json()Serialize to JSON string (if JSON enabled)
toMsgPack() / to_msgpack()Serialize to MessagePack binary (if MsgPack enabled)
Getters/SettersAccess and modify individual fields (Java, C++, PHP, C#)

Static Methods

MethodDescription
fromJson() / from_json()Deserialize from JSON string
fromMsgPack() / from_msgpack()Deserialize from MessagePack binary

Method Naming by Language

LanguageSerialize JSONSerialize MsgPackDeserialize JSONDeserialize MsgPack
C#ToJson()ToMsgPack()FromJson()FromMsgPack()
C++ToJson()ToMsgPack()FromJson()FromMsgPack()
DarttoJson()toMsgPack()fromJson()fromMsgPack()
Go ¹ToJSON()ToMsgPack()MessagePacketFromJSON()MessagePacketFromMsgPack()
JavatoJson()toMsgPack()fromJson()fromMsgPack()
PHPtoJson()toMsgPack()fromJson()fromMsgPack()
Pythonto_json()to_msgpack()from_json()from_msgpack()
Rustto_json()to_msgpack()from_json()from_msgpack()
TypeScripttoJSON()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.

Installation

Clone this repository and ensure Python 3.7+ is installed:

git clone https://github.com/sero583/CrossPacket.git
cd crosspacket

Quick Start

  1. 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"
}
}
}
}
}
  1. 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
  1. Use the generated code (includes dependencies):
C#

Dependencies:

dotnet add package MessagePack

Note: System.Text.Json is 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 msgpack

Usage:

#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.1

Usage:

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/v5

Usage:

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.SenderId
Java

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.so

Or with composer (for polyfill):

composer require rybakit/msgpack

Usage:

<?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 msgpack

Usage:

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.content
Rust

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/msgpack

Usage:

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-msgpack for JSON-only code or --no-json for MessagePack-only code.

Error Handling

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);}

Packet Definition Reference

Configuration

Global Settings

{
"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:

SettingEffect
json: true (default)Generate JSON serialization methods
json: falseOmit JSON methods (equivalent to --no-json CLI flag)
msgpack: true (default)Generate MessagePack serialization methods
msgpack: falseOmit MessagePack methods (equivalent to --no-msgpack CLI flag)

Note: CLI flags (--no-json, --no-msgpack) take precedence over config file settings.

Type Field Configuration

The type_field setting controls the name of the field used to identify packet types in serialized data:

{
"config": {
"global": {
"type_field": "packetType"
}
}
}
SettingEffect
type_field: "packetType" (default)Serialized packets include "packetType": "/path/PacketName"
type_field: "customName"Use custom field name for type identification

⚠️ Important: The configured type_field name 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 named packetType. If you need a field called type, you can safely use it since type is not the reserved name.

This is useful when:

  • Your application already uses type for other purposes
  • You want a more descriptive field name like messageType or eventKind
  • You need to match an existing protocol's naming convention

Language-Specific Settings

{
"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"
}
}
}

Supported Types

TypeDartJavaTypeScriptRustGoPythonC++C#PHP
intintlongnumberi64int64intint64_tlongint
floatdoubledoublenumberf64float64floatdoubledoublefloat
doubledoubledoublenumberf64float64floatdoubledoublefloat
boolboolbooleanbooleanboolboolboolboolboolbool
stringStringStringstringStringstringstrstd::stringstringstring
datetimeDateTimeZonedDateTimeDateDateTime<Utc>time.Timedatetimestd::stringDateTimeOffsetDateTimeImmutable
timeDurationLocalTimestringStringstringtimestd::stringTimeSpanstring
bytesUint8Listbyte[]Uint8ArrayVec<u8>[]bytebytesvector<uint8_t>byte[]string
listList<dynamic>List<Object>any[]Vec<Value>[]interface{}List[Any]std::string (JSON)List<object>array
list_intList<int>List<Long>number[]Vec<i64>[]int64List[int]vector<int64_t>List<long>array
list_stringList<String>List<String>string[]Vec<String>[]stringList[str]vector<string>List<string>array
mapMap<String, dynamic>Map<String, Object>Record<string, any>HashMapmap[string]interface{}Dict[str, Any]std::string (JSON)Dictionary<string, object>array
embedded_mapMap<dynamic, dynamic>Map<Object, Object>Map<any, any>HashMapmap[string]interface{}Dict[Any, Any]std::string (JSON)Dictionary<string, object>array
map_string_dynamicMap<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_map in C#, keys are converted to strings for JSON compatibility. MsgPack supports any key type.

Field Options

{
"fields": {
"required_field": {
"type": "string",
"description": "This field is required"
},
"optional_field": {
"type": "int",
"description": "This field is optional",
"optional": true
}
}
}

Field-Level Validation

CrossPacket supports granular field-level validation that can override global settings. This enables fine-tuned control for security-critical applications.

Global Validation Settings

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
}
}
}

Per-Field Validation Overrides

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
}
}
}
}
}
}

Validation Properties Reference

PropertyApplies ToDescription
requiredAll typesField must be present (default: false)
minint, float, string, list, bytesMinimum value or length
maxint, float, string, list, bytesMaximum value or length
patternstringRegex pattern for validation
allow_emptystringAllow empty strings (default: true)
allow_nanfloat, doubleAllow NaN values (default: true)
allow_infinityfloat, doubleAllow Infinity values (default: true)
max_depthmap, embedded_mapMaximum nesting depth

Example: Secure Message Packet

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
}
}
}
}
}

Packet Versioning

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.

Why MessagePack?

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

Security Features

CrossPacket includes optional security utilities for hardening generated packets in security-critical applications.

Security Utilities

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}")
raise

C# (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;}

Includes:

FeatureDescription
Bounds CheckingInteger overflow/underflow detection
Size LimitsConfigurable max sizes for lists, maps, strings, bytes
Required FieldsExplicit validation of mandatory fields
Type ValidationStrict type checking (no implicit coercion)
NaN/InfinityFloat validation with configurable handling
Error ContextDetailed error messages with field names and values

Security Recommendations for Critical Applications

  1. Always validate untrusted input using the security utilities before creating packets
  2. Set appropriate limits based on your application's needs
  3. Log validation failures for security monitoring
  4. Consider HMAC signing for packet integrity (implement as wrapper)
  5. Use schema versioning for backward/forward compatibility

Command Line Options

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

Running Tests

All 9 supported languages have comprehensive test suites in their respective tests/{language}/ folders.

Quick Test Commands

# 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

Test Coverage

CategoryTest Cases
Integers0, 1, -1, INT_MAX, INT_MIN, powers of 2, Fibonacci, primes
FloatsZero, precision (pi, euler, golden ratio), scientific notation
StringsEmpty, whitespace, escape sequences, URLs, paths, JSON/XML/HTML embedded
ListsEmpty, nested 2D/3D, irregular, 10-level deep, mixed types, sparse
MapsEmpty, nested 4 levels, arrays in maps, special keys, null values
ComplexUser profiles, API responses, graph/tree structures, config files

Pytest Suite

python -m pytest tests/ -v

Project Structure

crosspacket/
├── 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)

Contributing

See CONTRIBUTING.md for guidelines.

Testing

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

Changelog

v1.0.0 (2026-01-09)

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_field for packet type identification
  • Proper handling of all field types including bytes, maps, and nested structures
  • Idiomatic code generation following each language's style guide

License

MIT License - see LICENSE for details.

About

Generate type-safe data packets for 9 languages from JSON definitions. Dual serialization (JSON + MessagePack) optimized for WebSocket communication, with built-in validation and security utilities.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Packages

Contributors

Languages