venerdì 11 marzo 2022

Protocol Buffers in Golang

 Protocol Buffers (protobuf) e' una libreria di Google per la serializzazione di dati. Con il termine serializzazione si intende il processo di tradurre una "data structure" (array, struttura, albero binario.....) in un file che conservi oltre che i dati anche la struttura. Una forma tipica di serializzazione sono i file in formato JSON

Per utilizzare protobuf con GoLang si parte dalla definizione della struttura in file .proto. Un semplice modello puo' essere il seguente

syntax = "proto3";

package main;
import "google/protobuf/timestamp.proto";


message Person {
string name = 1;
int32 id = 2;
string email = 3;
google.protobuf.Timestamp last_updated = 5;
}

da notare che il file .proto deve avere lo stesso package del codice che lo utilizzera'

i numeri di fianco ai vari campi sono univoci

il file .proto deve essere compilato tramite il compilatore protoc. Su Debian l'installazione del compilatore avviene mediante

apt install protobuf-compiler
apt install golang-goprotobuf-dev

si crea il file .proto nella stessa directory del sorgente Go e si compila con

protoc --go_out=. *.proto

questo genera un nuovo file con estensione .go. Se si apre il file con editor di testo si osserva che oltre alla struttura dei dati sono state create delle funzioni tipo helper che facilitano l'immissione e gestione della struttura dati

per gestire i dati all'interno del progetto Go, nel caso si usino tipo dati di uso comune tipo datetime gia' formalizzati in protobuf si deve scaricare la loro definizione per esempio

go get github.com/golang/protobuf/ptypes/timestamp

i dati di un protobuf possono essere salvati su un file ma questo sara' binario e non immediatamente human readable

package main

import (
"fmt"
"io/ioutil"
"log"

proto "github.com/golang/protobuf/proto"
)

// apt install protobuf-compiler

// per compilare il file proto
// protoc --go_out=. *.proto

// go get github.com/golang/protobuf/ptypes/timestamp

func main() {
dati_persona := &Person{
Name: "Luca",
Id: 51, //per poco ancora
}

data, err := proto.Marshal(dati_persona)
if err != nil {
log.Fatal("marshaling error: ", err)
}

fmt.Println(data)

out, err := proto.Marshal(dati_persona)
if err != nil {
log.Fatalf("Serialization error: %s", err.Error())
}
if err := ioutil.WriteFile("dati.bin", out, 0644); err != nil {
log.Fatalf("Write File Error: %s ", err.Error())
}
fmt.Println("Write Success")

//Read from file
in, err := ioutil.ReadFile("dati.bin")
if err != nil {
log.Fatalf("Read File Error: %s ", err.Error())
}
dati_persona2 := &Person{}
err2 := proto.Unmarshal(in, dati_persona2)
if err2 != nil {
log.Fatalf("DeSerialization error: %s", err.Error())
}

fmt.Println("Read Success")
fmt.Printf("Nome %s\n", dati_persona2.GetName())
}




Nessun commento:

Posta un commento

Dockerizza Flask

Un esempio semplice per inserire in un container Docker una applicazione Flask Partiamo da una semplice applicazione che ha un file app.py ...