Add week 2 materials
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
COPY requirements.txt requirements.txt
|
||||
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD ["python", "./client.py"]
|
||||
@@ -0,0 +1,33 @@
|
||||
# gRPC клиент
|
||||
|
||||
В данной директории реализован простой пример клиента на Python, обращающийся к gRPC серверу.
|
||||
|
||||
Программа запускает бесконечный цикл, в котором получает текущее значение с сервера и пытается
|
||||
установить собственное значение, после чего засыпает на случайный промежуток времени.
|
||||
Процедура повторяется в цикле.
|
||||
|
||||
Конфигурация:
|
||||
- `SERVER_ADDR` — адрес сервера для подключения.
|
||||
- `VALUE_TO_PUT` — значение, которое будет устанавливать программа.
|
||||
|
||||
## protobuf
|
||||
|
||||
protubuf спецификация хранится в директории [./proto](./proto/).
|
||||
|
||||
protobuf файл сервера должен являться надмножеством с точки зрения API относительно protobuf файла
|
||||
клиента. Особенно важно сохранять оригинальные tag versions.
|
||||
|
||||
```bash
|
||||
pip3 install grpcio-tools
|
||||
|
||||
python3 -m grpc_tools.protoc -I./proto --python_out=. --grpc_python_out=. ./proto/storage.proto
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
Сборка образа:
|
||||
```bash
|
||||
docker build -t hse-grpc-client .
|
||||
|
||||
docker run -d -e SERVER_ADDR=... -e VALUE_TO_PUT=200 hse-grpc-client
|
||||
```
|
||||
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
import random
|
||||
import time
|
||||
|
||||
import grpc
|
||||
from google.protobuf.timestamp_pb2 import Timestamp
|
||||
|
||||
import storage_pb2
|
||||
import storage_pb2_grpc
|
||||
|
||||
|
||||
SERVER_ADDR = os.getenv('SERVER_ADDR', 'localhost:51000')
|
||||
VALUE_TO_PUT = int(os.getenv('VALUE_TO_PUT', '100'))
|
||||
|
||||
|
||||
channel = grpc.insecure_channel(SERVER_ADDR)
|
||||
stub = storage_pb2_grpc.StorageStub(channel)
|
||||
|
||||
|
||||
while True:
|
||||
current = stub.GetValue(storage_pb2.GetRequest())
|
||||
payload = current.value.payload
|
||||
updated_at = current.value.updated_at.ToDatetime()
|
||||
|
||||
if payload != VALUE_TO_PUT:
|
||||
print(f'Current value: {payload} (updated at {updated_at})')
|
||||
|
||||
print(f'Putting {VALUE_TO_PUT}', flush=True)
|
||||
|
||||
stub.PutValue(storage_pb2.PutRequest(
|
||||
value=storage_pb2.Value(payload=VALUE_TO_PUT)
|
||||
))
|
||||
|
||||
delay = random.uniform(1.0, 2.0)
|
||||
time.sleep(delay)
|
||||
@@ -0,0 +1,32 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package storage;
|
||||
|
||||
option go_package = "hsegrpc/;storagepb";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
service Storage {
|
||||
rpc PutValue(PutRequest) returns (PutResponse);
|
||||
rpc GetValue(GetRequest) returns (GetResponse);
|
||||
}
|
||||
|
||||
message Value {
|
||||
uint64 payload = 1;
|
||||
optional google.protobuf.Timestamp updated_at = 2;
|
||||
}
|
||||
|
||||
message PutRequest {
|
||||
Value value = 1;
|
||||
}
|
||||
|
||||
message PutResponse {
|
||||
uint64 value = 1;
|
||||
}
|
||||
|
||||
message GetRequest {
|
||||
}
|
||||
|
||||
message GetResponse {
|
||||
Value value = 1;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
grpcio==1.66.1
|
||||
grpcio-tools==1.66.1
|
||||
protobuf==5.28.1
|
||||
@@ -0,0 +1,48 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# NO CHECKED-IN PROTOBUF GENCODE
|
||||
# source: storage.proto
|
||||
# Protobuf Python Version: 5.27.2
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import runtime_version as _runtime_version
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
_runtime_version.ValidateProtobufRuntimeVersion(
|
||||
_runtime_version.Domain.PUBLIC,
|
||||
5,
|
||||
27,
|
||||
2,
|
||||
'',
|
||||
'storage.proto'
|
||||
)
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rstorage.proto\x12\x07storage\x1a\x1fgoogle/protobuf/timestamp.proto\"\\\n\x05Value\x12\x0f\n\x07payload\x18\x01 \x01(\x04\x12\x33\n\nupdated_at\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x42\r\n\x0b_updated_at\"+\n\nPutRequest\x12\x1d\n\x05value\x18\x01 \x01(\x0b\x32\x0e.storage.Value\"\x1c\n\x0bPutResponse\x12\r\n\x05value\x18\x01 \x01(\x04\"\x0c\n\nGetRequest\",\n\x0bGetResponse\x12\x1d\n\x05value\x18\x01 \x01(\x0b\x32\x0e.storage.Value2w\n\x07Storage\x12\x35\n\x08PutValue\x12\x13.storage.PutRequest\x1a\x14.storage.PutResponse\x12\x35\n\x08GetValue\x12\x13.storage.GetRequest\x1a\x14.storage.GetResponseB\x14Z\x12hsegrpc/;storagepbb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'storage_pb2', _globals)
|
||||
if not _descriptor._USE_C_DESCRIPTORS:
|
||||
_globals['DESCRIPTOR']._loaded_options = None
|
||||
_globals['DESCRIPTOR']._serialized_options = b'Z\022hsegrpc/;storagepb'
|
||||
_globals['_VALUE']._serialized_start=59
|
||||
_globals['_VALUE']._serialized_end=151
|
||||
_globals['_PUTREQUEST']._serialized_start=153
|
||||
_globals['_PUTREQUEST']._serialized_end=196
|
||||
_globals['_PUTRESPONSE']._serialized_start=198
|
||||
_globals['_PUTRESPONSE']._serialized_end=226
|
||||
_globals['_GETREQUEST']._serialized_start=228
|
||||
_globals['_GETREQUEST']._serialized_end=240
|
||||
_globals['_GETRESPONSE']._serialized_start=242
|
||||
_globals['_GETRESPONSE']._serialized_end=286
|
||||
_globals['_STORAGE']._serialized_start=288
|
||||
_globals['_STORAGE']._serialized_end=407
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,140 @@
|
||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
import warnings
|
||||
|
||||
import storage_pb2 as storage__pb2
|
||||
|
||||
GRPC_GENERATED_VERSION = '1.66.1'
|
||||
GRPC_VERSION = grpc.__version__
|
||||
_version_not_supported = False
|
||||
|
||||
try:
|
||||
from grpc._utilities import first_version_is_lower
|
||||
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
|
||||
except ImportError:
|
||||
_version_not_supported = True
|
||||
|
||||
if _version_not_supported:
|
||||
raise RuntimeError(
|
||||
f'The grpc package installed is at version {GRPC_VERSION},'
|
||||
+ f' but the generated code in storage_pb2_grpc.py depends on'
|
||||
+ f' grpcio>={GRPC_GENERATED_VERSION}.'
|
||||
+ f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
|
||||
+ f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
|
||||
)
|
||||
|
||||
|
||||
class StorageStub(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.PutValue = channel.unary_unary(
|
||||
'/storage.Storage/PutValue',
|
||||
request_serializer=storage__pb2.PutRequest.SerializeToString,
|
||||
response_deserializer=storage__pb2.PutResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.GetValue = channel.unary_unary(
|
||||
'/storage.Storage/GetValue',
|
||||
request_serializer=storage__pb2.GetRequest.SerializeToString,
|
||||
response_deserializer=storage__pb2.GetResponse.FromString,
|
||||
_registered_method=True)
|
||||
|
||||
|
||||
class StorageServicer(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def PutValue(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetValue(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
|
||||
def add_StorageServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {
|
||||
'PutValue': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.PutValue,
|
||||
request_deserializer=storage__pb2.PutRequest.FromString,
|
||||
response_serializer=storage__pb2.PutResponse.SerializeToString,
|
||||
),
|
||||
'GetValue': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetValue,
|
||||
request_deserializer=storage__pb2.GetRequest.FromString,
|
||||
response_serializer=storage__pb2.GetResponse.SerializeToString,
|
||||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
'storage.Storage', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
server.add_registered_method_handlers('storage.Storage', rpc_method_handlers)
|
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API.
|
||||
class Storage(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
@staticmethod
|
||||
def PutValue(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/storage.Storage/PutValue',
|
||||
storage__pb2.PutRequest.SerializeToString,
|
||||
storage__pb2.PutResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetValue(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/storage.Storage/GetValue',
|
||||
storage__pb2.GetRequest.SerializeToString,
|
||||
storage__pb2.GetResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
Reference in New Issue
Block a user