diff --git a/tensorboard/data/server/BUILD b/tensorboard/data/server/BUILD index 8f39fad7c8..6c4d8a4647 100644 --- a/tensorboard/data/server/BUILD +++ b/tensorboard/data/server/BUILD @@ -6,7 +6,10 @@ licenses(["notice"]) # Protocol buffer packages (as in `package foo.bar;` directives) that we need # to compile to Rust bindings. -_proto_packages = ["tensorboard"] +_proto_packages = [ + "demo", + "tensorboard", +] # Generated files with Rust protobuf bindings. These only exist in the build # graph, not in the source tree. The file name pattern is specified by Prost @@ -69,11 +72,17 @@ rust_binary( name = "server", srcs = ["main.rs"], edition = "2018", + deps = [ + ":rustboard_core", + "//third_party/rust:tokio", + "//third_party/rust:tonic", + ], ) genrule( name = "gen_protos", srcs = [ + ":demo.proto", "//tensorboard/compat/proto:proto_srcs", ], outs = _genproto_files, diff --git a/tensorboard/data/server/demo.pb.rs b/tensorboard/data/server/demo.pb.rs new file mode 100644 index 0000000000..68a8d4a81c --- /dev/null +++ b/tensorboard/data/server/demo.pb.rs @@ -0,0 +1,26 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddRequest { + #[prost(int32, repeated, tag="1")] + pub term: ::std::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddResponse { + #[prost(int32, tag="1")] + pub sum: i32, +} +# [doc = r" Generated client implementations."] pub mod demo_client { # ! [allow (unused_variables , dead_code , missing_docs)] use tonic :: codegen :: * ; pub struct DemoClient < T > { inner : tonic :: client :: Grpc < T > , } impl DemoClient < tonic :: transport :: Channel > { # [doc = r" Attempt to create a new client by connecting to a given endpoint."] pub async fn connect < D > (dst : D) -> Result < Self , tonic :: transport :: Error > where D : std :: convert :: TryInto < tonic :: transport :: Endpoint > , D :: Error : Into < StdError > , { let conn = tonic :: transport :: Endpoint :: new (dst) ? . connect () . await ? ; Ok (Self :: new (conn)) } } impl < T > DemoClient < T > where T : tonic :: client :: GrpcService < tonic :: body :: BoxBody > , T :: ResponseBody : Body + HttpBody + Send + 'static , T :: Error : Into < StdError > , < T :: ResponseBody as HttpBody > :: Error : Into < StdError > + Send , { pub fn new (inner : T) -> Self { let inner = tonic :: client :: Grpc :: new (inner) ; Self { inner } } pub fn with_interceptor (inner : T , interceptor : impl Into < tonic :: Interceptor >) -> Self { let inner = tonic :: client :: Grpc :: with_interceptor (inner , interceptor) ; Self { inner } } pub async fn add (& mut self , request : impl tonic :: IntoRequest < super :: AddRequest > ,) -> Result < tonic :: Response < super :: AddResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/demo.Demo/Add") ; self . inner . unary (request . into_request () , path , codec) . await } } impl < T : Clone > Clone for DemoClient < T > { fn clone (& self) -> Self { Self { inner : self . inner . clone () , } } } impl < T > std :: fmt :: Debug for DemoClient < T > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "DemoClient {{ ... }}") } } }# [doc = r" Generated server implementations."] pub mod demo_server { # ! [allow (unused_variables , dead_code , missing_docs)] use tonic :: codegen :: * ; # [doc = "Generated trait containing gRPC methods that should be implemented for use with DemoServer."] # [async_trait] pub trait Demo : Send + Sync + 'static { async fn add (& self , request : tonic :: Request < super :: AddRequest >) -> Result < tonic :: Response < super :: AddResponse > , tonic :: Status > ; } # [derive (Debug)] pub struct DemoServer < T : Demo > { inner : _Inner < T > , } struct _Inner < T > (Arc < T > , Option < tonic :: Interceptor >) ; impl < T : Demo > DemoServer < T > { pub fn new (inner : T) -> Self { let inner = Arc :: new (inner) ; let inner = _Inner (inner , None) ; Self { inner } } pub fn with_interceptor (inner : T , interceptor : impl Into < tonic :: Interceptor >) -> Self { let inner = Arc :: new (inner) ; let inner = _Inner (inner , Some (interceptor . into ())) ; Self { inner } } } impl < T , B > Service < http :: Request < B >> for DemoServer < T > where T : Demo , B : HttpBody + Send + Sync + 'static , B :: Error : Into < StdError > + Send + 'static , { type Response = http :: Response < tonic :: body :: BoxBody > ; type Error = Never ; type Future = BoxFuture < Self :: Response , Self :: Error > ; fn poll_ready (& mut self , _cx : & mut Context < '_ >) -> Poll < Result < () , Self :: Error >> { Poll :: Ready (Ok (())) } fn call (& mut self , req : http :: Request < B >) -> Self :: Future { let inner = self . inner . clone () ; match req . uri () . path () { "/demo.Demo/Add" => { # [allow (non_camel_case_types)] struct AddSvc < T : Demo > (pub Arc < T >) ; impl < T : Demo > tonic :: server :: UnaryService < super :: AddRequest > for AddSvc < T > { type Response = super :: AddResponse ; type Future = BoxFuture < tonic :: Response < Self :: Response > , tonic :: Status > ; fn call (& mut self , request : tonic :: Request < super :: AddRequest >) -> Self :: Future { let inner = self . 0 . clone () ; let fut = async move { (* inner) . add (request) . await } ; Box :: pin (fut) } } let inner = self . inner . clone () ; let fut = async move { let interceptor = inner . 1 . clone () ; let inner = inner . 0 ; let method = AddSvc (inner) ; let codec = tonic :: codec :: ProstCodec :: default () ; let mut grpc = if let Some (interceptor) = interceptor { tonic :: server :: Grpc :: with_interceptor (codec , interceptor) } else { tonic :: server :: Grpc :: new (codec) } ; let res = grpc . unary (method , req) . await ; Ok (res) } ; Box :: pin (fut) } _ => Box :: pin (async move { Ok (http :: Response :: builder () . status (200) . header ("grpc-status" , "12") . body (tonic :: body :: BoxBody :: empty ()) . unwrap ()) }) , } } } impl < T : Demo > Clone for DemoServer < T > { fn clone (& self) -> Self { let inner = self . inner . clone () ; Self { inner } } } impl < T : Demo > Clone for _Inner < T > { fn clone (& self) -> Self { Self (self . 0 . clone () , self . 1 . clone ()) } } impl < T : std :: fmt :: Debug > std :: fmt :: Debug for _Inner < T > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{:?}" , self . 0) } } impl < T : Demo > tonic :: transport :: NamedService for DemoServer < T > { const NAME : & 'static str = "demo.Demo" ; } } \ No newline at end of file diff --git a/tensorboard/data/server/demo.proto b/tensorboard/data/server/demo.proto new file mode 100644 index 0000000000..e5292315d2 --- /dev/null +++ b/tensorboard/data/server/demo.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package demo; + +service Demo { + rpc Add(AddRequest) returns (AddResponse); +} + +message AddRequest { + repeated int32 term = 1; +} + +message AddResponse { + int32 sum = 1; +} diff --git a/tensorboard/data/server/gen_protos_tool.rs b/tensorboard/data/server/gen_protos_tool.rs index 84e28a3f08..7720f5d149 100644 --- a/tensorboard/data/server/gen_protos_tool.rs +++ b/tensorboard/data/server/gen_protos_tool.rs @@ -29,7 +29,13 @@ fn main() -> std::io::Result<()> { tonic_build::configure() .out_dir(&out_dir) .format(false) // don't run `rustfmt`; shouldn't be needed to build - .compile(&["tensorboard/compat/proto/event.proto"], &["."]) + .compile( + &[ + "tensorboard/compat/proto/event.proto", + "tensorboard/data/server/demo.proto", + ], + &["."], + ) .expect("compile_protos"); Ok(()) } diff --git a/tensorboard/data/server/lib.rs b/tensorboard/data/server/lib.rs index 7dbe906eef..ffd56b4c6c 100644 --- a/tensorboard/data/server/lib.rs +++ b/tensorboard/data/server/lib.rs @@ -25,6 +25,10 @@ mod scripted_reader; /// Protocol buffer bindings. #[allow(clippy::all)] pub mod proto { + /// Bindings for `package demo`, used for a demo Tonic server. + pub mod demo { + include!("demo.pb.rs"); + } /// Bindings for `package tensorboard`, containing standard TensorFlow protos. pub mod tensorboard { include!("tensorboard.pb.rs"); diff --git a/tensorboard/data/server/main.rs b/tensorboard/data/server/main.rs index 609d8b4fe1..86dc2c7be8 100644 --- a/tensorboard/data/server/main.rs +++ b/tensorboard/data/server/main.rs @@ -13,4 +13,38 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -fn main() {} +#![allow(clippy::needless_update)] // https://github.com/rust-lang/rust-clippy/issues/6323 + +use tonic::{transport::Server, Request, Response}; + +use rustboard_core::proto::demo as pb; + +#[derive(Debug, Default)] +struct DemoHandler; + +#[tonic::async_trait] +impl pb::demo_server::Demo for DemoHandler { + async fn add( + &self, + request: Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let sum: i32 = request.term.into_iter().sum(); + let response = pb::AddResponse { + sum, + ..Default::default() + }; + Ok(Response::new(response)) + } +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let addr = "[::0]:6789".parse::()?; + let handler = DemoHandler::default(); + Server::builder() + .add_service(pb::demo_server::DemoServer::new(handler)) + .serve(addr) + .await?; + Ok(()) +}