sgcProtoBuf: .proto Dosyalarından Delphi Unit'lerine | eSeGeCe Blog

sgcProtoBuf: .proto Dosyalarından Delphi Unit'lerine

· Bileşenler
sgcProtoBuf kod üreticisi

Bir iş ortağı size bir gRPC servisi verdiğinde, aslında size bir klasör dolusu .proto dosyası verir. Bu dosyalar sözleşmedir ve içlerindeki her mesajın, Delphi kodunuzun okuyup yazabileceği bir şeye dönüşmesi gerekir. Bunu elle yapmak zahmetlidir ve hata yapması kolaydır, üstelik karşı taraf sözleşmenin yeni bir sürümünü yayınladığı her seferinde baştan yapılması gerekir.

sgcProtoBuf, bu işi sizin yerinize yapan kod üreticisidir. Onu bir .proto dosyasına yöneltin, her mesaj için bir sınıf içeren, serileştirmeye ve serileştirmeyi geri almaya hazır Delphi unit'leri üretsin. proto2 ve proto3 okur ve söz dizimi sürümünü dosyanın kendisinden alır. Hem bir sihirbaz hem de bir komut satırı aracı olarak gelir.

Ona tek bir dosya verin, tüm ağacı alın

Gerçek proto ağaçları asla tek bir dosyadan oluşmaz. Birbirlerini import ederler, üstüne bir de Google tanımlarını import ederler. Tipik bir servis dosyası şöyle başlar:

syntax = "proto3";

package acme.telemetry.v1;

import "acme/common/v1/device.proto";
import "google/protobuf/timestamp.proto";

message Reading {
  string device_id = 1;
  double value = 2;
  google.protobuf.Timestamp taken_at = 3;
}

Import'ları çözümle seçeneği etkinken, o tek dosyayı seçersiniz ve sgcProtoBuf import ifadelerini özyinelemeli olarak izler, bulduğu her bağımlılığı üretir ve üretilen unit'leri uses yan tümcesine ekler. Proto ağacınızın kök klasörü, seçtiğiniz dosyadan otomatik olarak keşfedilir, dolayısıyla genellikle yapılandırılacak bir şey kalmaz.

Bir tanım diskte bulunamazsa, derlenmeyen bir unit sessizce üretilmek yerine durum mesaj listesinde raporlanır. Bir derleyici hatasının peşinden koşmak yerine hangi dosyanın eksik olduğunu tam olarak görürsünüz.

Unit adları package'tan gelir

Üretilen unit, package ifadesine göre adlandırılır, dolayısıyla package acme.telemetry.v1; ifadesi, acme.telemetry.v1.pas olarak kaydedilen unit acme.telemetry.v1; üretir. Dosya adı her zaman unit adıyla eşleşir, bu da önlenebilir derleme hatalarının koca bir kategorisini ortadan kaldırır.

Bu aynı zamanda, aynı package'ı bildiren birden fazla .proto dosyasının, sözleşmenin yazarlarının tam olarak amaçladığı gibi tek bir unit içinde toplanması anlamına gelir. Hepsi acme.common.v1 bildiren device.proto, device_service.proto ve units.proto dosyalarından oluşan bir klasör, tek bir acme.common.v1.pas dosyasına dönüşür.

Google türleri zaten kutunun içinde

Gerçek hayattaki neredeyse her proto dosyası google.protobuf içinden bir şey import eder. Bunları üretmenize gerek yok. sgcWebSockets bunları zaten sgcProtoBuf_WellKnownTypes unit'i içinde sunar ve üretici bunları otomatik olarak eşler: Timestamp, Duration, Any, Empty, FieldMask, Struct ve StringValue ile Int32Value gibi sarmalayıcı türler.

Böylece yukarıdaki google.protobuf.Timestamp alanı, ToDateTime ve FromDateTime metotları zaten uygulanmış bir TsgcProtoBufTimestamp hâline gelir. Google'ın .proto dosyalarının hiçbir zaman çevrilmesi gerekmez.

Gerçek Delphi türleri olarak enum'lar

Varsayılan olarak bir enum, sabitlerden oluşan bir blok hâlinde üretilir. Enum'ları Delphi numaralandırılmış türleri olarak üret seçeneğini açın, bunun yerine okuması daha kısa olan ve ilgisiz bir tam sayıyla karıştırılamayacak düzgün bir tür elde edin:

CountryCodeDto = (
  COUNTRY_CODE_DTO_NONE = 0,
  COUNTRY_CODE_DTO_NL = 1,
  COUNTRY_CODE_DTO_DE = 2,
  COUNTRY_CODE_DTO_CH = 3
);

Bilinmeye değer dürüst bir kısıtlama var. Bir Protocol Buffers enum'u, bir Delphi numaralandırılmış türünün yapamayacağı şeyleri yapabilir: negatif değerler tutabilir, iki adı aynı sayıya takma ad olarak bağlayabilir ve aynı package içindeki iki enum aynı değer adını bildirebilir. Üretici bunlardan biriyle karşılaştığında, yalnızca o enum için sabit biçimine geri döner ve nedenini açıklayan bir yorum yazar. Dosyadaki diğer her enum bundan etkilenmez, böylece mümkün olan her yerde gerçek türler, geri kalan her yerde de çalışan bir unit elde edersiniz.

Üretilen kod

Her mesaj sınıfı, üretilen bir taban sınıftan türer ve her alan için bir property ile birlikte LoadFromBytes, LoadFromStream ve ToBytes sunar. Aşağıdaki örnek, Tsgc önekini kaldıran ve adları sözleşmede göründükleri gibi koruyan Orijinal proto öğe adlarını koru seçeneğini kullanır:

uses
  acme.telemetry.v1;

var
  oReading: Reading;
begin
  oReading := Reading.Create;
  Try
    oReading.LoadFromBytes(vBytes);

    ShowMessage(oReading.DeviceId);
    ShowMessage(FloatToStr(oReading.Value));
    ShowMessage(DateTimeToStr(oReading.TakenAt.ToDateTime));

    vBytes := oReading.ToBytes;
  Finally
    oReading.Free;
  End;
end;

Komut satırında

Sihirbaz ilk bakış için kullanışlıdır, ancak bir proto ağacı değişir ve onu yeniden üretmek derleme sürecinizin bir parçası olmalıdır. Aynı üretici komut satırından da çalışır:

sgcProtoBuf.exe --input=protos\acme\telemetry\v1\telemetry.proto --resolve-imports --output-dir=units --enum-as-type

Anahtarlar sihirbaz seçeneklerini yansıtır: --resolve-imports, --import-root (birden fazla köke yayılmış ağaçlar için tekrarlanabilir), --output-dir, --enum-as-type, --original-names, --short-enum-consts, ayrıca --no-classes, --no-services ve --no-docs. Tam liste için --help ile çalıştırın.

Nasıl edinilir

sgcProtoBuf, TsgcGRPCClient ve sgcProtoBuf çalışma zamanı unit'leriyle birlikte sgcWebSockets ile gelir. En son sürümü sgcWebSockets indirme sayfasından indirin ve tüm seçeneklerin referansı için yardım dosyasındaki sgcProtoBuf konusuna bakın.

Sorularınız, geri bildiriminiz veya düzgün üretilmeyen bir proto ağacınız mı var? Bize ulaşın, kodu yazan kişilerden yanıt alacaksınız.