{"id":323232,"date":"2021-05-17T09:00:48","date_gmt":"2021-05-17T09:00:48","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=323232"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=323232","title":{"rendered":"\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432 gRPC \u043d\u0430 Rust"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c <a href=\"https:\/\/grpc.io\/\" rel=\"nofollow noopener noreferrer\">gRPC<\/a> \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430 Rust. \u0414\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u0436\u0435 Telegram \u0431\u043e\u0442\u043e\u043c. \u0412 \u0438\u0442\u043e\u0433\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430:<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/c6\/t2\/vi\/c6t2viupfrra-wv5w5n4q026wu0.png\"><\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<p>\u0421\u0442\u0430\u0442\u044c\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435 \u0432\u0441\u0435\u043e\u0431\u044a\u0435\u043c\u043b\u044e\u0449\u0438\u043c \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e\u043c \u043f\u043e gRPC \u0432 Rust, \u0430 \u0441\u043a\u043e\u0440\u0435\u0435 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0433\u0430\u0439\u0434\u043e\u043c, \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u044e\u0449\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u044b \u0438 \u043a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 gRPC.<\/p>\n<p>  <\/p>\n<p>\u0414\u043e\u043c\u0435\u043d\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u043f\u043b\u0430\u043d\u0435\u0442\u0430\u0445 \u0421\u043e\u043b\u043d\u0435\u0447\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438 \u0438\u0445 \u0441\u043f\u0443\u0442\u043d\u0438\u043a\u0430\u0445.<\/p>\n<p>  <\/p>\n<h1 id=\"implementaciya\">\u0418\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/h1>\n<p>  <\/p>\n<p>\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0439 gRPC \u043d\u0430 Rust. \u0412 \u044d\u0442\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u044b\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d <a href=\"https:\/\/github.com\/hyperium\/tonic\" rel=\"nofollow noopener noreferrer\"><code>tonic<\/code><\/a>.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u0438:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/tree\/master\/grpc-telegram-bot\/server\" rel=\"nofollow noopener noreferrer\">gRPC \u0441\u0435\u0440\u0432\u0435\u0440<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/tree\/master\/grpc-telegram-bot\/bot\" rel=\"nofollow noopener noreferrer\">gRPC \u043a\u043b\u0438\u0435\u043d\u0442<\/a> (\u0442\u0430\u043a\u0436\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f Telegram \u0431\u043e\u0442\u043e\u043c)<\/li>\n<li>\u043e\u0431\u0449\u0438\u0439 \u043c\u043e\u0434\u0443\u043b\u044c <a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/tree\/master\/grpc-telegram-bot\/rpc\" rel=\"nofollow noopener noreferrer\">rpc<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 gRPC \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0438 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e gRPC \u043a\u043e\u0434\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0433\u043e \u0438 \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0438 \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<p>  <\/p>\n<h2 id=\"opredelenie-servisa-i-generaciya-koda\">\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043a\u043e\u0434\u0430<\/h2>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u0438 <strong>proto3<\/strong> <a href=\"https:\/\/developers.google.com\/protocol-buffers\" rel=\"nofollow noopener noreferrer\">Protocol Buffers<\/a> \u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 <code>.proto<\/code> \u0444\u0430\u0439\u043b\u0435:<\/p>\n<p>  <\/p>\n<p><em><a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/rpc\/proto\/solar-system-info\/solar-system-info.proto\" rel=\"nofollow noopener noreferrer\"><code>solar-system-info.proto<\/code><\/a><\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">syntax = &quot;proto3&quot;;  package solar_system_info;  import &quot;google\/protobuf\/timestamp.proto&quot;; import &quot;google\/protobuf\/empty.proto&quot;;  service SolarSystemInfo {   rpc GetPlanetsList (google.protobuf.Empty) returns (PlanetsListResponse);   rpc GetPlanet (PlanetRequest) returns (PlanetResponse);   rpc GetPlanets (google.protobuf.Empty) returns (stream PlanetResponse); }  message PlanetsListResponse {   repeated string list = 1; }  message PlanetRequest {   string name = 1; }  message PlanetResponse {   Planet planet = 1; }  message Planet {   uint64 id = 1;   string name = 2;   Type type = 3;   float meanRadius = 4;   float mass = 5;   repeated Satellite satellites = 6;   bytes image = 7; }  enum Type {   TERRESTRIAL_PLANET = 0;   GAS_GIANT = 1;   ICE_GIANT = 2;   DWARF_PLANET = 3; }  message Satellite {   uint64 id = 1;   string name = 2;   google.protobuf.Timestamp first_spacecraft_landing_date = 3; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u043f\u0440\u043e\u0441\u0442\u044b\u0435 (<code>unary<\/code>) RPC (<code>GetPlanetsList<\/code> \u0438 <code>GetPlanet<\/code>), server-side streaming RPC (<code>GetPlanets<\/code>) \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u043f\u043e\u043b\u044f \u043a\u0430\u043a \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 <em>\u043e\u0431\u044b\u0447\u043d\u044b\u0445<\/em> \u0442\u0438\u043f\u043e\u0432 (<code>uint64<\/code>, <code>string<\/code>, etc.), \u0442\u0430\u043a \u0438:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 (<code>Planet.type<\/code>)<\/li>\n<li>\u0441\u043f\u0438\u0441\u043e\u043a (<code>Planet.satellites<\/code>)<\/li>\n<li>\u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 (<code>Planet.image<\/code>)<\/li>\n<li>\u0442\u0438\u043f date\/timestamp (<code>Satellite.first_spacecraft_landing_date<\/code>)<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0433\u043e \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0433\u043e gRPC \u043a\u043e\u0434\u0430 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<p>  <\/p>\n<p><em><a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/rpc\/Cargo.toml\" rel=\"nofollow noopener noreferrer\"><code>Cargo.toml<\/code><\/a><\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">[package] name = &quot;solar-system-info-rpc&quot; version = &quot;0.1.0&quot; edition = &quot;2018&quot;  [dependencies] tonic = &quot;0.4.2&quot; # Rust gRPC implementation prost = &quot;0.7.0&quot; # Rust Protocol Buffers implementation prost-types = &quot;0.7.0&quot; # Contains definitions of Protocol Buffers well-known types  [build-dependencies] tonic-build = &quot;0.4.2&quot;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <code>prost-types<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 <a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/reference\/google.protobuf\" rel=\"nofollow noopener noreferrer\">well-known<\/a> \u0442\u0438\u043f\u043e\u0432 Protobuf, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a <code>Empty<\/code> \u0438 <code>Timestamp<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0412 \u043a\u043e\u0440\u043d\u0435 \u043c\u043e\u0434\u0443\u043b\u044f \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<p>  <\/p>\n<p><em><a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/rpc\/build.rs\" rel=\"nofollow noopener noreferrer\"><code>build.rs<\/code><\/a><\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"rust\">fn main() -&gt; Result&lt;(), Box&lt;dyn std::error::Error&gt;&gt; {     tonic_build::compile_protos(&quot;proto\/solar-system-info\/solar-system-info.proto&quot;)?;     Ok(()) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u043e\u0434\u0443\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u043c \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438:<\/p>\n<p>  <\/p>\n<p><em><a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/rpc\/src\/lib.rs\" rel=\"nofollow noopener noreferrer\"><code>lib.rs<\/code><\/a><\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"rust\">pub mod solar_system_info {     tonic::include_proto!(&quot;solar_system_info&quot;); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438\u043b\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>\/target\/debug\/build\/solar-system-info-rpc\/out\/solar_system_info.rs<\/code>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0442\u0440\u0435\u0439\u0442 <code>SolarSystemInfo<\/code>:<\/p>\n<p>  <\/p>\n<p><em>\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0442\u0440\u0435\u0439\u0442 <code>SolarSystemInfo<\/code><\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"rust\">#[doc = r&quot; Generated server implementations.&quot;] pub mod solar_system_info_server {     #![allow(unused_variables, dead_code, missing_docs)]     use tonic::codegen::*;     #[doc = &quot;Generated trait containing gRPC methods that should be implemented for use with SolarSystemInfoServer.&quot;]     #[async_trait]     pub trait SolarSystemInfo: Send + Sync + 'static {         async fn get_planets_list(             &amp;self,             request: tonic::Request&lt;()&gt;,         ) -&gt; Result&lt;tonic::Response&lt;super::PlanetsListResponse&gt;, tonic::Status&gt;;         async fn get_planet(             &amp;self,             request: tonic::Request&lt;super::PlanetRequest&gt;,         ) -&gt; Result&lt;tonic::Response&lt;super::PlanetResponse&gt;, tonic::Status&gt;;         #[doc = &quot;Server streaming response type for the GetPlanets method.&quot;]         type GetPlanetsStream: futures_core::Stream&lt;Item = Result&lt;super::PlanetResponse, tonic::Status&gt;&gt;             + Send             + Sync             + 'static;         async fn get_planets(             &amp;self,             request: tonic::Request&lt;()&gt;,         ) -&gt; Result&lt;tonic::Response&lt;Self::GetPlanetsStream&gt;, tonic::Status&gt;;     }     #[derive(Debug)]     pub struct SolarSystemInfoServer&lt;T: SolarSystemInfo&gt; {         inner: _Inner&lt;T&gt;,     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 <code>get_planet<\/code>, \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<p><em>\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u043b\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>get_planet<\/code><\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"rust\">#[derive(Clone, PartialEq, ::prost::Message)] pub struct PlanetRequest {     #[prost(string, tag = &quot;1&quot;)]     pub name: ::prost::alloc::string::String, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct PlanetResponse {     #[prost(message, optional, tag = &quot;1&quot;)]     pub planet: ::core::option::Option&lt;Planet&gt;, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct Planet {     #[prost(uint64, tag = &quot;1&quot;)]     pub id: u64,     #[prost(string, tag = &quot;2&quot;)]     pub name: ::prost::alloc::string::String,     #[prost(enumeration = &quot;Type&quot;, tag = &quot;3&quot;)]     pub r#type: i32,     #[prost(float, tag = &quot;4&quot;)]     pub mean_radius: f32,     #[prost(float, tag = &quot;5&quot;)]     pub mass: f32,     #[prost(message, repeated, tag = &quot;6&quot;)]     pub satellites: ::prost::alloc::vec::Vec&lt;Satellite&gt;,     #[prost(bytes = &quot;vec&quot;, tag = &quot;7&quot;)]     pub image: ::prost::alloc::vec::Vec&lt;u8&gt;, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct Satellite {     #[prost(uint64, tag = &quot;1&quot;)]     pub id: u64,     #[prost(string, tag = &quot;2&quot;)]     pub name: ::prost::alloc::string::String,     #[prost(message, optional, tag = &quot;3&quot;)]     pub first_spacecraft_landing_date: ::core::option::Option&lt;::prost_types::Timestamp&gt;, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum Type {     TerrestrialPlanet = 0,     GasGiant = 1,     IceGiant = 2,     DwarfPlanet = 3, }<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"grpc-server\">gRPC \u0441\u0435\u0440\u0432\u0435\u0440<\/h2>\n<p>  <\/p>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f <code>main<\/code> \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u043d\u0438\u0436\u0435:<\/p>\n<p>  <\/p>\n<p><em><a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/server\/src\/main.rs\" rel=\"nofollow noopener noreferrer\"><code>\u0424\u0443\u043d\u043a\u0446\u0438\u044f main<\/code><\/a><\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"rust\">#[tokio::main] async fn main() -&gt; Result&lt;(), Box&lt;dyn std::error::Error&gt;&gt; {     dotenv().ok();     env_logger::init();      info!(&quot;Starting Solar System info server&quot;);      let addr = std::env::var(&quot;GRPC_SERVER_ADDRESS&quot;)?.parse()?;      let pool = create_connection_pool();     run_migrations(&amp;pool);      let solar_system_info = SolarSystemInfoService { pool };     let svc = SolarSystemInfoServer::new(solar_system_info);      Server::builder().add_service(svc).serve(addr).await?;      Ok(()) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0442\u0440\u0435\u0439\u0442\u0430 <code>SolarSystemInfo<\/code> (\u0431\u044b\u043b \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435) \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<p><em><a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/server\/src\/main.rs\" rel=\"nofollow noopener noreferrer\">\u0418\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/a> gRPC \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"rust\">struct SolarSystemInfoService {     pool: PgPool, }  #[tonic::async_trait] impl SolarSystemInfo for SolarSystemInfoService {     type GetPlanetsStream =         Pin&lt;Box&lt;dyn Stream&lt;Item = Result&lt;PlanetResponse, Status&gt;&gt; + Send + Sync + 'static&gt;&gt;;      async fn get_planets_list(         &amp;self,         request: Request&lt;()&gt;,     ) -&gt; Result&lt;Response&lt;PlanetsListResponse&gt;, Status&gt; {         debug!(&quot;Got a request: {:?}&quot;, request);          let names_of_planets = persistence::repository::get_names(&amp;get_connection(&amp;self.pool))             .expect(&quot;Can't get names of the planets&quot;);          let reply = PlanetsListResponse {             list: names_of_planets,         };          Ok(Response::new(reply))     }      async fn get_planets(         &amp;self,         request: Request&lt;()&gt;,     ) -&gt; Result&lt;Response&lt;Self::GetPlanetsStream&gt;, Status&gt; {         debug!(&quot;Got a request: {:?}&quot;, request);          let (tx, rx) = mpsc::channel(4);          let planets: Vec&lt;Planet&gt; = persistence::repository::get_all(&amp;get_connection(&amp;self.pool))             .expect(&quot;Can't load planets&quot;)             .into_iter()             .map(|p| {                 PlanetWrapper {                     planet: p.0,                     satellites: p.1,                 }                 .into()             })             .collect();          tokio::spawn(async move {             let mut stream = tokio_stream::iter(&amp;planets);              while let Some(planet) = stream.next().await {                 tx.send(Ok(PlanetResponse {                     planet: Some(planet.clone()),                 }))                 .await                 .unwrap();             }         });          Ok(Response::new(Box::pin(             tokio_stream::wrappers::ReceiverStream::new(rx),         )))     }      async fn get_planet(         &amp;self,         request: Request&lt;PlanetRequest&gt;,     ) -&gt; Result&lt;Response&lt;PlanetResponse&gt;, Status&gt; {         debug!(&quot;Got a request: {:?}&quot;, request);          let planet_name = request.into_inner().name;          let planet =             persistence::repository::get_by_name(&amp;planet_name, &amp;get_connection(&amp;self.pool));          match planet {             Ok(planet) =&gt; {                 let planet = PlanetWrapper {                     planet: planet.0,                     satellites: planet.1,                 }                 .into();                  let reply = PlanetResponse {                     planet: Some(planet),                 };                  Ok(Response::new(reply))             }             Err(e) =&gt; {                 error!(                     &quot;There was an error while getting a planet {}: {}&quot;,                     &amp;planet_name, e                 );                 match e {                     Error::NotFound =&gt; Err(Status::not_found(format!(                         &quot;Planet with name {} not found&quot;,                         &amp;planet_name                     ))),                     _ =&gt; Err(Status::unknown(format!(                         &quot;There was an error while getting a planet {}: {}&quot;,                         &amp;planet_name, e                     ))),                 }             }         }     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u0430\u044f <code>SolarSystemInfoService<\/code> \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0438\u043c\u0435\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0411\u0414 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Diesel ORM.<\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e <code>get_planets_list<\/code> \u0438 <code>get_planet<\/code> \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 RPC, \u0430 <code>get_planets<\/code> \u2014 server-side streaming RPC.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/tree\/master\/grpc-telegram-bot\/server\/images\" rel=\"nofollow noopener noreferrer\">\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f<\/a> \u043f\u043b\u0430\u043d\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u0432 \u0431\u0438\u043d\u0430\u0440\u043d\u0438\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <a href=\"https:\/\/github.com\/pyros2097\/rust-embed\" rel=\"nofollow noopener noreferrer\">rust_embed<\/a> (\u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043e\u043d\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b).<\/p>\n<p>  <\/p>\n<h2 id=\"grpc-klient\">gRPC \u043a\u043b\u0438\u0435\u043d\u0442<\/h2>\n<p>  <\/p>\n<p>gRPC \u043a\u043b\u0438\u0435\u043d\u0442 \u0432 \u043c\u043e\u0434\u0443\u043b\u0435 <code>bot<\/code> \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<p><em><a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/bot\/src\/main.rs\" rel=\"nofollow noopener noreferrer\">\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435<\/a> gRPC \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"rust\">async fn create_grpc_client() -&gt; SolarSystemInfoClient&lt;tonic::transport::Channel&gt; {     let channel = tonic::transport::Channel::from_static(&amp;GRPC_SERVER_ADDRESS)         .connect()         .await         .expect(&quot;Can't create a channel&quot;);      SolarSystemInfoClient::new(channel) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<p><em><a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/bot\/src\/main.rs\" rel=\"nofollow noopener noreferrer\">\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435<\/a> gRPC \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"rust\">let response = get_planets_list(grpc_client).await?;<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"telegram-bot\">Telegram \u0431\u043e\u0442<\/h3>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u0431\u044b\u043b\u043e \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043e \u0440\u0430\u043d\u0435\u0435, \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 gRPC \u043a\u043b\u0438\u0435\u043d\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u0436\u0435 \u0438 Telegram \u0431\u043e\u0442\u043e\u043c. \u0414\u043b\u044f \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0431\u043e\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <a href=\"https:\/\/github.com\/teloxide\/teloxide\" rel=\"nofollow noopener noreferrer\">teloxide<\/a>.<\/p>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u0441\u0440\u0430\u0437\u0443 \u043a <code>main.rs<\/code>:<\/p>\n<p>  <\/p>\n<p><em><a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/bot\/src\/main.rs\" rel=\"nofollow noopener noreferrer\">main.rs<\/a><\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"rust\">#[tokio::main] async fn main() {     dotenv().ok();     teloxide::enable_logging!();     log::info!(&quot;Starting Solar System info bot&quot;);      let api_url = std::env::var(&quot;TELEGRAM_API_URL&quot;).expect(&quot;Can't get Telegram API URL&quot;);     let api_url = Url::parse(&amp;api_url).expect(&quot;Can't parse Telegram API URL&quot;);      let bot = Bot::from_env()         .set_api_url(api_url)         .parse_mode(Html)         .auto_send();      let bot = Arc::new(bot);      let grpc_client = create_grpc_client().await;      teloxide::commands_repl(bot, &quot;solar-system-info-bot&quot;, move |cx, command| {         answer(cx, command, grpc_client.clone())     })     .await; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 SSL\/TLS \u0432 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432\u043a\u043b\u044e\u0447\u0451\u043d \u043c\u043e\u0434\u0443\u043b\u044c <a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/tree\/master\/grpc-telegram-bot\/nginx\" rel=\"nofollow noopener noreferrer\"><code>nginx<\/code><\/a>. \u041e\u043d \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u0430\u043a <em>forward proxy<\/em>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 HTTP \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043e\u0442 \u0431\u043e\u0442\u0430 \u0438 <a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/nginx\/nginx.conf\" rel=\"nofollow noopener noreferrer\">\u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442<\/a> \u0438\u0445 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u044b Telegram API.<\/p>\n<p>  <\/p>\n<h1 id=\"zapusk-i-testirovanie\">\u0417\u0430\u043f\u0443\u0441\u043a \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h1>\n<p>  <\/p>\n<p>\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0434\u0432\u0443\u043c\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Docker Compose (<a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/docker-compose.yml\" rel=\"nofollow noopener noreferrer\"><code>docker-compose.yml<\/code><\/a>):<br \/>  <code>docker-compose up<\/code><\/li>\n<li>\u0431\u0435\u0437 Docker<br \/>  \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 gRPC \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>cargo run<\/code><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e gRPC \u043a\u043b\u0438\u0435\u043d\u0442 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/github.com\/uw-labs\/bloomrpc\" rel=\"nofollow noopener noreferrer\">BloomRPC<\/a>):<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/_y\/qv\/ow\/_yqvowa5fyp_enfdypquss0d23u.png\"><\/p>\n<p>  <\/p>\n<p>\u0438\u043b\u0438 \u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u043a\u043e\u0441\u0432\u0435\u043d\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Telegram \u0431\u043e\u0442\u0430:<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/6u\/x0\/f1\/6ux0f1ikefaqiw6uetzblp0hraw.gif\"><\/p>\n<p>  <\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438 \u0431\u043e\u0442\u0430 \u0438 RPC \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>\/list<\/code> \u2192 <code>GetPlanetsList<\/code><\/li>\n<li><code>\/planets<\/code> \u2192 <code>GetPlanets<\/code><\/li>\n<li><code>\/planet<\/code> \u2192 <code>GetPlanet<\/code><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u043e\u0442\u0430 \u0432\u0430\u043c \u043d\u0443\u0436\u0435\u043d Telegram \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0431\u043e\u0442 (\u0432\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443 <a href=\"https:\/\/core.telegram.org\/bots\" rel=\"nofollow noopener noreferrer\">\u0437\u0434\u0435\u0441\u044c<\/a>). \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430, \u0442\u043e\u043a\u0435\u043d \u0431\u043e\u0442\u0430 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u043d <a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/.env\" rel=\"nofollow noopener noreferrer\">\u0437\u0434\u0435\u0441\u044c<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/grpc-telegram-bot\/bot\/.env\" rel=\"nofollow noopener noreferrer\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>  <\/p>\n<h1 id=\"cicd\">CI\/CD<\/h1>\n<p>  <\/p>\n<p>CI\/CD \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c GitHub Actions (<a href=\"https:\/\/github.com\/rkudryashov\/exploring-rust-ecosystem\/blob\/master\/.github\/workflows\/workflow.yml\" rel=\"nofollow noopener noreferrer\">workflow<\/a>), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 Docker \u043e\u0431\u0440\u0430\u0437\u044b gRPC \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 (\u0442\u043e \u0435\u0441\u0442\u044c Telegram \u0431\u043e\u0442\u0430) \u0438 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0438\u0445 \u043d\u0430 Google Cloud Platform.<\/p>\n<p>  <\/p>\n<p>\u0411\u043e\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/t.me\/solarsysteminfobot\" rel=\"nofollow noopener noreferrer\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>  <\/p>\n<h1 id=\"zaklyuchenie\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h1>\n<p>  <\/p>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u043a\u0430\u0437\u0430\u043b \u043a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c gRPC \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430 Rust \u0438 \u043f\u0440\u0438\u0432\u0451\u043b \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043a\u0430\u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f Telegram \u0431\u043e\u0442\u0430. \u041d\u0435 \u0441\u0442\u0435\u0441\u043d\u044f\u0439\u0442\u0435\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043c\u043d\u0435, \u0435\u0441\u043b\u0438 \u043d\u0430\u0448\u043b\u0438 \u043a\u0430\u043a\u0438\u0435-\u043b\u0438\u0431\u043e \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u0438\u043b\u0438 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u043a\u043e\u0434\u0435. \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435!<\/p>\n<p>  <\/p>\n<h1 id=\"poleznye-ssylki\">\u041f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438<\/h1>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3\" rel=\"nofollow noopener noreferrer\">\u0413\u0430\u0439\u0434 \u043f\u043e Protocol Buffers<\/a><\/li>\n<li><a href=\"https:\/\/grpc.io\/docs\/what-is-grpc\/introduction\/\" rel=\"nofollow noopener noreferrer\">\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432 gRPC<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/hyperium\/tonic\" rel=\"nofollow noopener noreferrer\">Tonic<\/a><\/li>\n<\/ul>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/557600\/\"> https:\/\/habr.com\/ru\/post\/557600\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c <a href=\"https:\/\/grpc.io\/\" rel=\"nofollow noopener noreferrer\">gRPC<\/a> \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430 Rust. \u0414\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u0436\u0435 Telegram \u0431\u043e\u0442\u043e\u043c. \u0412 \u0438\u0442\u043e\u0433\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430:<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/c6\/t2\/vi\/c6t2viupfrra-wv5w5n4q026wu0.png\"><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-323232","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/323232","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=323232"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/323232\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=323232"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=323232"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=323232"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}