Protocol buffer dosyaları oluşturmak için normal olarak ana bilgisayar işletim sisteminize protobuf ve protoc paketleri kurabilirsiniz. Ancak, bu çözümdeki sorun, her mühendisin komutları kullanmaya başlamadan önce kurulumdan geçmesi gerektiğidir. İşletim sisteminin Linux, Windows veya Mac olabileceği göz önüne alındığında, protocol buffer dosyaları oluşturulduktan sonra diğer sorunların yanı sıra kesinlikle sürüm farklılıkları olacaktır. Bu örnek, her şeyin yapılma şeklini standartlaştırmaktadır. Tek yapmanız gereken, sizin için tüm dosyaları oluşturacak olan docker komutunu çalıştırmak. Ayrıca işletim sisteminize Docker dışında hiçbir şey yüklemezsiniz. Burada Dockerfile ve docker-compose.yaml dosyalarına dikkat edin. *.pb.go dosyaları, make proto-compile komutunu çalıştırdıktan sonra eklenecek/güncellenecektir. Uygulamanızda çalıştırmanız gereken tek şey go get -u google.golang.org/grpc komutudur.


Yapı


├── Makefile
├── cmd
│   ├── client
│   │   └── main.go
│   └── server
│   └── main.go
├── docker
│   ├── Dockerfile
│   └── docker-compose.yaml
├── go.mod
├── go.sum
└── protobuf
├── league.pb.go
├── league.proto
├── team.pb.go
└── team.proto

Dosyalar


docker-compose.yaml


services:
protogen:
build:
context: "."
args:
PLATFORM: ${PLATFORM}
working_dir: "/source"
volumes:
- "../protobuf:/source"
command: bash -c "protoc --go_out=plugins=grpc:. --go_opt=paths=source_relative *.proto"

Dockerfile


FROM golang:1.18.2-buster

ARG PLATFORM

RUN apt-get update && apt-get install -y unzip

# By default Intel chipset (x86_64) is assumed but if the host device is an Apple
# silicon (arm) chipset based then a relevant (aarch_64) release file is used.

RUN export ZIP=x86_64 && \
if [ ${PLATFORM} = "arm64" ]; then export ZIP=aarch_64; fi && \
wget --quiet https://github.com/protocolbuffers/protobuf/releases/download/v3.15.8/protoc-3.15.8-linux-${ZIP}.zip && \
unzip -o protoc-3.15.8-linux-${ZIP}.zip -d /usr/local bin/protoc && \
unzip -o protoc-3.15.8-linux-${ZIP}.zip -d /usr/local 'include/*' && \
go install github.com/golang/protobuf/protoc-gen-go@v1.5.2

league.proto


syntax = "proto3";

package football;

option go_package = "github.com/you/football/protobuf;footballpb";

message CreateLeagueRequest {
string name = 1;
}

message CreateLeagueResponse {
string id = 1;
}

service LeagueService {
rpc CreateLeague(CreateLeagueRequest) returns (CreateLeagueResponse) {}
}

team.proto


syntax = "proto3";

package football;

option go_package = "github.com/you/football/protobuf;footballpb";

message CreateTeamRequest {
string name = 1;
}

message CreateTeamResponse {
string id = 1;
}

service TeamService {
rpc CreateTeam(CreateTeamRequest) returns (CreateTeamResponse) {}
}

Makefile


.PHONY: help
help: ## Display available commands.
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

.PHONY: server-run
server-run: ## Run server.
go run --race cmd/server/main.go

.PHONY: client-run
client-run: ## Run client.
go run --race cmd/client/main.go

.PHONY: proto-compile
proto-compile: ## Compile protobuf files.
PLATFORM=$(shell uname -m) docker-compose -f docker/docker-compose.yaml run --rm protogen

.PHONY: docker-config
docker-config: ## Dump docker-compose configuration.
PLATFORM=$(shell uname -m) docker-compose -f docker/docker-compose.yaml config

.PHONY: docker-down
docker-down: ## Clean up docker artefacts.
PLATFORM=$(shell uname -m) docker-compose -f docker/docker-compose.yaml down
@-docker rmi docker_protogen
docker system prune --volumes --force

client/main.go


package main

import (
"context"
"log"
"time"

"google.golang.org/grpc"

footballpb "github.com/you/football/protobuf"
)

func main() {
// Initialise TCP connection.
con, err := grpc.Dial(":50051", grpc.WithInsecure())
if err != nil {
log.Fatalln(err)
}
defer con.Close()

// Initialise league client.
clt := footballpb.NewLeagueServiceClient(con)

// Create league client request.
req := &footballpb.CreateLeagueRequest{Name: "Super League"}

ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

// Send create league request.
res, err := clt.CreateLeague(ctx, req)
if err != nil {
log.Fatalln(err)
}

log.Println(res.GetId())
}

server/main.go


package main

import (
"context"
"log"
"net"

"google.golang.org/grpc"

footballpb "github.com/you/football/protobuf"
)

func main() {
// Initialise TCP listener.
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatal(err)
}
defer lis.Close()

// Initialise GRPC server.
grpcSrv := grpc.NewServer()

footballpb.RegisterLeagueServiceServer(grpcSrv, &LeagueServer{})

log.Fatalln(grpcSrv.Serve(lis))
}

type LeagueServer struct{}

func (l *LeagueServer) CreateLeague(ctx context.Context, req *footballpb.CreateLeagueRequest) (*footballpb.CreateLeagueResponse, error) {
log.Println(req.GetName())

return &footballpb.CreateLeagueResponse{Id: "ID"}, nil
}