From cba2dbdb75e91f1cfe9a95367d7cca585eb7b64d Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sat, 16 Oct 2021 08:30:44 +0300 Subject: [PATCH] Handle communication errors #12 --- src/IWindow.hpp | 1 + src/MsgPackRpc.cpp | 15 ++++++++++++--- src/MsgPackRpc.hpp | 5 ++++- src/Session.cpp | 18 +++++++++++++++++- src/Session.hpp | 2 ++ src/SessionSpawn.cpp | 7 ++----- src/Window.hpp | 2 +- 7 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/IWindow.hpp b/src/IWindow.hpp index ec03b1f..77dfe2a 100644 --- a/src/IWindow.hpp +++ b/src/IWindow.hpp @@ -29,4 +29,5 @@ struct IWindow virtual void Present() = 0; virtual void SessionEnd() = 0; + virtual void SetError(const char *) = 0; }; diff --git a/src/MsgPackRpc.cpp b/src/MsgPackRpc.cpp index 408002d..7d8821b 100644 --- a/src/MsgPackRpc.cpp +++ b/src/MsgPackRpc.cpp @@ -3,9 +3,11 @@ #include -MsgPackRpc::MsgPackRpc(uv_stream_t *stdin_stream, uv_stream_t *stdout_stream) +MsgPackRpc::MsgPackRpc(uv_stream_t *stdin_stream, uv_stream_t *stdout_stream, + OnErrorT on_error) : _stdin_stream{stdin_stream} , _stdout_stream{stdout_stream} + , _on_error{on_error} { _stdout_stream->data = this; @@ -17,10 +19,13 @@ MsgPackRpc::MsgPackRpc(uv_stream_t *stdin_stream, uv_stream_t *stdout_stream) }; auto read_astream = [](uv_stream_t* stream, ssize_t nread, const uv_buf_t *buf) { + MsgPackRpc *self = reinterpret_cast(stream->data); if (nread > 0) - { - MsgPackRpc *self = reinterpret_cast(stream->data); self->_handle_data(buf->base, nread); + else + { + Logger().error("Failed to read: {}", uv_strerror(nread)); + self->_on_error(uv_strerror(nread)); } }; @@ -52,7 +57,11 @@ void MsgPackRpc::Request(PackRequestT pack_request, OnResponseT on_response) auto cb = [](uv_write_t* req, int status) { Write *w = reinterpret_cast(req); if (status < 0) + { Logger().error("Failed to write {} bytes: {}", w->buffer.size(), uv_strerror(status)); + MsgPackRpc *self = reinterpret_cast(req->data); + self->_on_error(uv_strerror(status)); + } delete w; }; diff --git a/src/MsgPackRpc.hpp b/src/MsgPackRpc.hpp index 5edf0b4..6c3f0b5 100644 --- a/src/MsgPackRpc.hpp +++ b/src/MsgPackRpc.hpp @@ -9,7 +9,9 @@ class MsgPackRpc { public: - MsgPackRpc(uv_stream_t *, uv_stream_t *); + using OnErrorT = std::function; + + MsgPackRpc(uv_stream_t *, uv_stream_t *, OnErrorT); ~MsgPackRpc(); using OnNotificationT = std::function; @@ -31,6 +33,7 @@ class MsgPackRpc private: uv_stream_t *_stdin_stream; uv_stream_t *_stdout_stream; + OnErrorT _on_error; OnNotificationT _on_notification; // Capture any non msgpack-rpc output, as it may be text output from --version or alike diff --git a/src/Session.cpp b/src/Session.cpp index b1f0143..a0af402 100644 --- a/src/Session.cpp +++ b/src/Session.cpp @@ -6,7 +6,8 @@ void Session::_Init(uv_stream_t *in, uv_stream_t *out) { - _rpc.reset(new MsgPackRpc(in, out)); + auto onError = [this](const char *error) { _OnError(error); }; + _rpc.reset(new MsgPackRpc(in, out, onError)); _renderer.reset(new Renderer{uv_default_loop(), _rpc.get()}); _redraw_handler.reset(new RedrawHandler{_rpc.get(), _renderer.get()}); @@ -45,3 +46,18 @@ void Session::SetWindow(IWindow *window) _window = window; _renderer->SetWindow(window); } + +void Session::_OnError(const char *error) +{ + _Exit(); + if (_window && error) + _window->SetError(error); +} + +void Session::_Exit() +{ + _nvim_exited.store(true, std::memory_order_relaxed); + uv_stop(uv_default_loop()); + if (_window) + _window->SessionEnd(); +} diff --git a/src/Session.hpp b/src/Session.hpp index 677b9f1..e9055be 100644 --- a/src/Session.hpp +++ b/src/Session.hpp @@ -45,4 +45,6 @@ class Session IWindow *_window = nullptr; void _Init(uv_stream_t *in, uv_stream_t *out); + void _OnError(const char *); + void _Exit(); }; diff --git a/src/SessionSpawn.cpp b/src/SessionSpawn.cpp index 75a1fb6..dc4502d 100644 --- a/src/SessionSpawn.cpp +++ b/src/SessionSpawn.cpp @@ -24,12 +24,9 @@ SessionSpawn::SessionSpawn(int argc, char *argv[]) //}); auto on_exit = [](uv_process_t *proc, int64_t exit_status, int signal) { - SessionSpawn *session = reinterpret_cast(proc->data); Logger().info("Exit: status={} signal={}", exit_status, signal); - session->_nvim_exited.store(true, std::memory_order_relaxed); - uv_stop(uv_default_loop()); - if (session->_window) - session->_window->SessionEnd(); + SessionSpawn *session = reinterpret_cast(proc->data); + session->_Exit(); }; uv_process_options_t options{}; diff --git a/src/Window.hpp b/src/Window.hpp index 5f265e4..7bc5201 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -21,7 +21,7 @@ class Window void DrawCursor(cairo_t *, int row, int col, unsigned fg, std::string_view mode); void SessionEnd() override; - void SetError(const char *error); + void SetError(const char *error) override; private: GtkApplication *_app;