diff options
author | Marius Vlad <marius.vlad@collabora.com> | 2022-10-25 13:06:41 +0300 |
---|---|---|
committer | Marius Vlad <marius.vlad@collabora.com> | 2022-12-13 12:31:18 +0200 |
commit | 59375972f5642b7ec5115fdecf4828f6af02f343 (patch) | |
tree | 14912e10b5894e0d3eef773ed3306f455352b9ec /grpc-proxy/grpc-async-cb.cpp | |
parent | 0b766cf978b8b100caecd4c61464e1a683685072 (diff) |
grpc-proxy: Init gRPCsandbox/mvlad/grpc-async-cb
This brings in support for accessing agl-shell protocol indirectly by
using a gRPC interface which bridges the communication between a
particular client (the client issuing gRPC requests) and the AGL
compositor which does that by re-using the same agl-shell protocol.
In order to achieve that, and further more, to avoid having ifdefs code
in the compositor and deal with threading, we instead resorted to using
a helper client.
On one side this helper implements the gRPC server API,
and on the other, a wayland native client that implements the
agl_shell interface.
It uses the agl_shell_ext interface added
previously to communicate with the compositor that it requires access
to agl_shell interface as well. The helper expects that agl_shell interface
was already bounded to another client before starting it so it waits
until that happens and then it implements the protocol specification,
for each interface.
Launching the helper client automatically can be done by adding the
following entry to the ini file:
[shell-client-ext]
command=/path/to/agl-shell-grpc-server
The gRPC server implementation only handles the agl_shell interface
until to this point, specifically, the activate_app request, and the
events that were adedd with version 3 of the agl-shell protocol.
Also the implementation uses the Reactor pattern, with Callback service
that greatly simplifies the async version and avoids putting locks to
to handle multiple clients. This should allow multiple clients being
connected to the gRPC server and receive events / send requests.
Bug-AGL: SPEC-4503
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Change-Id: Ie870da3caa138394d8dd30f9d22a5552d585d63a
Diffstat (limited to 'grpc-proxy/grpc-async-cb.cpp')
-rw-r--r-- | grpc-proxy/grpc-async-cb.cpp | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/grpc-proxy/grpc-async-cb.cpp b/grpc-proxy/grpc-async-cb.cpp new file mode 100644 index 0000000..d0fd88d --- /dev/null +++ b/grpc-proxy/grpc-async-cb.cpp @@ -0,0 +1,166 @@ +/* + * Copyright © 2022 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <cstdio> +#include <ctime> +#include <algorithm> +#include <queue> + +#define GRPC_CALLBACK_API_NONEXPERIMENTAL + +#include <grpc/grpc.h> +#include <grpcpp/grpcpp.h> +#include <grpcpp/server.h> +#include <grpcpp/server_builder.h> +#include <grpcpp/server_context.h> + +#include <grpcpp/ext/proto_server_reflection_plugin.h> +#include <grpcpp/health_check_service_interface.h> + +#include "log.h" +#include "agl_shell.grpc.pb.h" +#include "grpc-async-cb.h" + +Lister::Lister(Shell *shell) : m_shell(shell) +{ + // don't call NextWrite() just yet we do it explicitly when getting + // the events from the compositor + m_writting = false; +} + +void +Lister::OnDone() +{ + delete this; +} + +void Lister::OnWriteDone(bool ok) +{ + LOG("got ok %d\n", ok); + if (ok) { + LOG("done writting %d\n", m_writting); + m_writting = false; + } +} + +void +Lister::NextWrite(void) +{ + if (m_writting) { + LOG(">>>>> still in writting\n"); + return; + } + m_writting = true; + StartWrite(&m_shell->m_shell_data->current_app_state); +} + +bool +Lister::Writting(void) +{ + return m_writting; +} + +grpc::ServerUnaryReactor * +GrpcServiceImpl::ActivateApp(grpc::CallbackServerContext *context, + const ::agl_shell_ipc::ActivateRequest* request, + ::agl_shell_ipc::ActivateResponse* /*response*/) +{ + LOG("activating app %s on output %s\n", request->app_id().c_str(), + request->output_name().c_str()); + + m_aglShell->ActivateApp(request->app_id(), request->output_name()); + + grpc::ServerUnaryReactor* reactor = context->DefaultReactor(); + reactor->Finish(grpc::Status::OK); + return reactor; +} + +grpc::ServerUnaryReactor * +GrpcServiceImpl::DeactivateApp(grpc::CallbackServerContext *context, + const ::agl_shell_ipc::DeactivateRequest* request, + ::agl_shell_ipc::DeactivateResponse* /*response*/) +{ + m_aglShell->DeactivateApp(request->app_id()); + + grpc::ServerUnaryReactor* reactor = context->DefaultReactor(); + reactor->Finish(grpc::Status::OK); + return reactor; +} + +grpc::ServerUnaryReactor * +GrpcServiceImpl::SetAppFloat(grpc::CallbackServerContext *context, + const ::agl_shell_ipc::FloatRequest* request, + ::agl_shell_ipc::FloatResponse* /* response */) +{ + m_aglShell->SetAppFloat(request->app_id()); + + grpc::ServerUnaryReactor* reactor = context->DefaultReactor(); + reactor->Finish(grpc::Status::OK); + return reactor; +} + +grpc::ServerUnaryReactor * +GrpcServiceImpl::SetAppSplit(grpc::CallbackServerContext *context, + const ::agl_shell_ipc::SplitRequest* request, + ::agl_shell_ipc::SplitResponse* /*response*/) +{ + m_aglShell->SetAppSplit(request->app_id(), request->tile_orientation()); + + grpc::ServerUnaryReactor* reactor = context->DefaultReactor(); + reactor->Finish(grpc::Status::OK); + return reactor; +} + +grpc::ServerUnaryReactor * +GrpcServiceImpl::GetOutputs(grpc::CallbackServerContext *context, + const ::agl_shell_ipc::OutputRequest* /* request */, + ::agl_shell_ipc::ListOutputResponse* response) +{ + struct window_output *output; + + struct wl_list *list = &m_aglShell->m_shell_data->output_list; + wl_list_for_each(output, list, link) { + auto m_output = response->add_outputs(); + m_output->set_name(output->name); + } + + grpc::ServerUnaryReactor* reactor = context->DefaultReactor(); + reactor->Finish(grpc::Status::OK); + return reactor; +} + +grpc::ServerWriteReactor<::agl_shell_ipc::AppStateResponse>* +GrpcServiceImpl::AppStatusState(grpc::CallbackServerContext* context, + const ::agl_shell_ipc::AppStateRequest* /*request */) +{ + + Lister *n = new Lister(m_aglShell); + + m_aglShell->m_shell_data->server_context_list.push_back(std::pair(context, n)); + LOG("added lister %p\n", static_cast<void *>(n)); + + // just return a Lister to keep the channel open + return n; +} |