Protokołu Google Protocol Buffers nie trzeba przedstawiać, ale przy okazji analizowania gRPC, pomyślałem, że o nim wspomnę.

Proto jest protokołem przechowywania danych w ustrukturyzowany sposób i stanowi lżejszą alternatywę dla XML, czy JSON.

Definicja struktury danych rozpoczyna się od słowa kluczowego message, a dalej posiłkujemy się już dedykowanymi typami danych dla ciągów znaków, liczb, dat, własnych pól wyliczeniowych czy wcześniej utworzonymi własnymi strukturami danych.

Przykład struktury danych:

message Data {
	enum DataType {
		New = 0;
		Deleted = 1;
	}

	message Content {
		string description = 1;
	}

	int32 id = 1;
	string name = 2;
	DataType type = 3;
	Content content = 4;
	google.protobuf.Timestamp UpdateTime = 5;
}

Własne struktury danych możemy swobodnie używać w kolejnych strukturach danych.

Utworzone typy danych przechowujemy w pliku z rozszerzeniem .proto, na początku którego określamy wersję protokołu, nazwę paczki i importujemy dodatkowe przestrzenie, np.:

syntax = "proto3";
package kq.Research.Tests.Proto;

import "google/protobuf/timestamp.proto";

message Data {
    // struktura danych opisana powyżej
}
message DataContainer {
	repeated Data data = 1;
}

Zapisany plik proto, możemy zamodelować np. w postaci klasy C# i swobodnie używać w dowolnej aplikacji.

protoc.exe --csharp_out=./ data.proto

Przykład użycia w C#:

using System;
using System.IO;

using Google.Protobuf;

namespace Kq.Research.Tests.Proto
{
    class Program
    {
        static void Main(string[] args)
        {
            Data data = new Data()
            {
                Id = 12345,
                Name = "My data",
                Content = new Data.Types.Content
                {
                    Description = "important data"
                },
                Type = Data.Types.DataType.New
            };

            using (var file = File.Create("data.dat"))
                data.WriteTo(file);

            Data newData = null;

            using (var file = File.OpenRead("data.dat"))
                newData = Data.Parser.ParseFrom(file);

            newData.Id += 1;
            newData.Name = "My updated data";
            newData.Content.Description = "new important data";

            DataContainer datas = new DataContainer();

            datas.Data.Add(data);
            datas.Data.Add(newData);

            using (var file = File.Create("container.dat"))
                datas.WriteTo(file);

            DataContainer readDatas = null;

            using (var file = File.OpenRead("container.dat"))
                readDatas = DataContainer.Parser.ParseFrom(file);

            PrintMessage(readDatas);
        }

        private static void PrintMessage(IMessage message)
        {
            var descriptor = message.Descriptor;
            foreach (var field in descriptor.Fields.InDeclarationOrder())
            {
                Console.WriteLine($"Field {field.FieldNumber} ({field.Name}): {field.Accessor.GetValue(message)}");
            }
        }
    }
}

Oczywiście powyższy opis nie wyczerpuje możliwości, ale stanowi szybki start w formie jednostronicowego manuala.

Kategorie: Programowanie