ساحة Protocol Buffers: تجميع واختبار Protobufs في المتصفح
العمل مع Protocol Buffers عادة يعني إعداد protoc والمكونات الإضافية الخاصة باللغة وخطوط بناء الأكواد. ماذا لو كان بإمكانك فقط تحميل ملف .proto والبدء فوراً في تسلسل الرسائل وإلغاء تسلسلها؟
اليوم سنريك كيفية استخدام unsandbox كـ ساحة لعب protobuf - مثالية للتعلم وتصحيح الأخطاء والنماذج الأولية السريعة.
الإعداد: لا يلزم تثبيت أي شيء
تأتي حاويات unsandbox مع:
-
protoc3.21.12 (مترجم protobuf) -
مكتبة Python
protobuf -
Ruby
google-protobufgem - دعم Go protobuf
- دعم كامل لملفات الإدخال
هذا يعني أنه يمكنك تحميل مخطط .proto والعمل معه فوراً - دون الحاجة إلى تثبيت محلي.
مثال 1: أول Protobuf لك في Python
لنحدد رسالة Person بسيطة ونسلسلها:
person.proto:
syntax = "proto3";
message Person {
string name = 1;
int32 age = 2;
}
طلب API:
{
"language": "python",
"code": "import subprocess, sys, os\nos.chdir('/tmp/input')\nsubprocess.run(['protoc', '--python_out=.', 'person.proto'], check=True)\nsys.path.insert(0, '.')\nimport person_pb2\n\n# Create a Person message\nperson = person_pb2.Person(name='Alice', age=30)\nprint(f'Created: {person}')\n\n# Serialize to binary\ndata = person.SerializeToString()\nprint(f'Serialized ({len(data)} bytes): {data.hex()}')\n\n# Deserialize back\nperson2 = person_pb2.Person()\nperson2.ParseFromString(data)\nprint(f'Deserialized: name={person2.name}, age={person2.age}')",
"input_files": [
{"filename": "person.proto", "content": "c3ludGF4ID0gInByb3RvMyI7CgptZXNzYWdlIFBlcnNvbiB7CiAgc3RyaW5nIG5hbWUgPSAxOwogIGludDMyIGFnZSA9IDI7Cn0K"}
]
}
الناتج:
Created: name: "Alice"
age: 30
Serialized (9 bytes): 0a05416c696365101e
Deserialized: name=Alice, age=30
ماذا حدث للتو:
-
تحميل
person.protoبصيغة base64 -
قام
protocبتجميعه إلىperson_pb2.py - إنشاء رسالة Person
-
التسلسل إلى 9 بايتات:
0a05416c696365101e - إلغاء التسلسل مرة أخرى
مثال 2: فك تشفير Binary Protobuf مجهول
لديك ملف .bin غامض ومخططه؟ قم بتحميل كليهما وفك التشفير:
{
"language": "python",
"code": "import subprocess, sys, os\nos.chdir('/tmp/input')\nsubprocess.run(['protoc', '--python_out=.', 'person.proto'], check=True)\nsys.path.insert(0, '.')\nimport person_pb2\n\n# Read the binary protobuf data\nwith open('data.bin', 'rb') as f:\n data = f.read()\nprint(f'Binary data: {data.hex()}')\n\n# Decode it\nperson = person_pb2.Person()\nperson.ParseFromString(data)\nprint(f'Decoded: name={person.name}, age={person.age}')",
"input_files": [
{"filename": "person.proto", "content": "c3ludGF4ID0gInByb3RvMyI7CgptZXNzYWdlIFBlcnNvbiB7CiAgc3RyaW5nIG5hbWUgPSAxOwogIGludDMyIGFnZSA9IDI7Cn0K"},
{"filename": "data.bin", "content": "CgVBbGljZRAe"}
]
}
الناتج:
Binary data: 0a05416c696365101e
Decoded: name=Alice, age=30
هذا مثالي لتصحيح الأخطاء - الصق تفريغك السداسي عشري، وحوله إلى base64، وشاهد ما بداخله!
مثال 3: الرسائل المتداخلة والحقول المتكررة
لنجرب شيئاً أكثر تعقيداً:
addressbook.proto:
syntax = "proto3";
message Person {
string name = 1;
int32 id = 2;
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
كود Python لملء وتسلسل:
import subprocess, sys, os
os.chdir('/tmp/input')
subprocess.run(['protoc', '--python_out=.', 'addressbook.proto'], check=True)
sys.path.insert(0, '.')
import addressbook_pb2
# Create an address book
book = addressbook_pb2.AddressBook()
# Add first person
alice = book.people.add()
alice.name = "Alice"
alice.id = 1234
alice.email = "alice@example.com"
phone = alice.phones.add()
phone.number = "555-1234"
phone.type = addressbook_pb2.Person.MOBILE
# Add second person
bob = book.people.add()
bob.name = "Bob"
bob.id = 5678
bob.email = "bob@example.com"
phone = bob.phones.add()
phone.number = "555-5678"
phone.type = addressbook_pb2.Person.WORK
# Serialize
data = book.SerializeToString()
print(f"Address book ({len(data)} bytes):")
print(f"Hex: {data.hex()}")
# Show the text format
print("\nText format:")
print(book)
الناتج:
Address book (62 bytes):
Hex: 0a1e0a05416c696365...
Text format:
people {
name: "Alice"
id: 1234
email: "alice@example.com"
phones {
number: "555-1234"
}
}
people {
name: "Bob"
id: 5678
email: "bob@example.com"
phones {
number: "555-5678"
type: WORK
}
}
مثال 4: فحص Wire Format الخام
تريد فهم تنسيق سلك protobuf؟ لنفك تشفيره بايت بعد بايت:
import subprocess, sys, os
os.chdir('/tmp/input')
subprocess.run(['protoc', '--python_out=.', 'person.proto'], check=True)
sys.path.insert(0, '.')
import person_pb2
person = person_pb2.Person(name="Alice", age=30)
data = person.SerializeToString()
print("Wire format breakdown:")
print(f"Raw bytes: {data.hex()}")
print()
# Decode wire format manually
i = 0
while i < len(data):
tag_byte = data[i]
field_number = tag_byte >> 3
wire_type = tag_byte & 0x07
wire_type_names = {0: 'varint', 1: '64-bit', 2: 'length-delimited', 5: '32-bit'}
print(f"Field {field_number}, Wire type {wire_type} ({wire_type_names.get(wire_type, 'unknown')})")
i += 1
if wire_type == 0: # Varint
value = 0
shift = 0
while data[i] & 0x80:
value |= (data[i] & 0x7f) << shift
shift += 7
i += 1
value |= data[i] << shift
i += 1
print(f" Value: {value}")
elif wire_type == 2: # Length-delimited
length = data[i]
i += 1
content = data[i:i+length]
i += length
print(f" Length: {length}, Content: {content} ({content.hex()})")
الناتج:
Wire format breakdown:
Raw bytes: 0a05416c696365101e
Field 1, Wire type 2 (length-delimited)
Length: 5, Content: b'Alice' (416c696365)
Field 2, Wire type 0 (varint)
Value: 30
الآن يمكنك أن ترى بالضبط كيف يقوم protobuf بترميز البيانات!
مثال 5: اختبار تطور المخطط
يشتهر Protobuf بالتوافق للخلف/للأمام. اختبره:
v1.proto (الأصلي):
syntax = "proto3";
package v1;
message User {
string name = 1;
int32 age = 2;
}
v2.proto (حقل جديد مضاف):
syntax = "proto3";
package v2;
message User {
string name = 1;
int32 age = 2;
string email = 3; // New field!
}
اختبار التوافق للأمام:
import subprocess, sys, os
os.chdir('/tmp/input')
# Compile both versions
subprocess.run(['protoc', '--python_out=.', 'v1.proto'], check=True)
subprocess.run(['protoc', '--python_out=.', 'v2.proto'], check=True)
sys.path.insert(0, '.')
import v1_pb2
import v2_pb2
# Create v2 message with new field
user_v2 = v2_pb2.User(name="Alice", age=30, email="alice@example.com")
data = user_v2.SerializeToString()
print(f"v2 serialized: {data.hex()}")
# Read with v1 (old code reading new data)
user_v1 = v1_pb2.User()
user_v1.ParseFromString(data)
print(f"v1 reads: name={user_v1.name}, age={user_v1.age}")
print("Email field? v1 ignores unknown fields - forward compatible!")
مرجع سريع: ترميز Base64 لملفات Proto الخاصة بك
لتحميل الملفات، تحتاج إلى base64. إليك كيفية القيام بذلك:
Linux/Mac:
base64 -w 0 person.proto
Python:
import base64
with open('person.proto', 'rb') as f:
print(base64.b64encode(f.read()).decode())
JavaScript:
const content = "syntax = \"proto3\";\n\nmessage Person {\n string name = 1;\n int32 age = 2;\n}\n";
console.log(btoa(content));
حالات الاستخدام
1. تعلم Protobufs
تخطى متاعب التثبيت. فقط اكتب .proto، قم بتحميله، وجرب.
2. تصحيح أخطاء Wire Format
حصلت على تفريغ سداسي عشري من التقاط الشبكة؟ الصقه، فك تشفيره، افهمه.
3. التحقق من صحة المخطط
اختبر ما إذا كان مخططك يتم تجميعه قبل الالتزام. تحقق من أن أرقام الحقول لا تتعارض.
4. اختبار متعدد اللغات
سلسل في Python، ألغ التسلسل في Go. تحقق من أن رسائلك تعمل عبر اللغات.
5. توثيق API
أظهر أمثلة عملية لرسائل protobuf الخاصة بك مع ناتج مسلسل فعلي.
القيود
- حجم الملف: حد أقصى 5 ميجابايت لكل ملف (كافي للمخططات)
- وقت التنفيذ: مهلة 30 ثانية
- إصدار protoc: 3.21.12 (دعم كامل لـ proto3)
جربه الآن
- انتقل إلى unsandbox.com
- اختر Python
- الصق كود protobuf الخاص بك
-
قم بتحميل ملف
.protoالخاص بك (أو استخدم معامل input_files بصيغة base64) - شغّل!
لا تثبيت. لا خط بناء. فقط protobufs.
تسلسل سعيد!