Rework binary network protocol to be more message based

We cannot just write to Kakoune socket from any application anymore,
use of kak -p is mandatory, as we now have an introduction to write.
This commit is contained in:
Maxime Coste 2016-08-31 09:24:07 +01:00
parent 4d13e6fb88
commit 044a6ce860

View File

@ -21,8 +21,10 @@
namespace Kakoune namespace Kakoune
{ {
enum class RemoteUIMsg enum class MessageType
{ {
Connect,
Command,
MenuShow, MenuShow,
MenuSelect, MenuSelect,
MenuHide, MenuHide,
@ -31,7 +33,8 @@ enum class RemoteUIMsg
Draw, Draw,
DrawStatus, DrawStatus,
Refresh, Refresh,
SetOptions SetOptions,
Key
}; };
struct socket_error{}; struct socket_error{};
@ -39,7 +42,11 @@ struct socket_error{};
class Message class Message
{ {
public: public:
Message(int sock) : m_socket(sock) {} Message(int sock, MessageType type) : m_socket(sock)
{
write(type);
}
~Message() noexcept(false) ~Message() noexcept(false)
{ {
if (m_stream.size() == 0) if (m_stream.size() == 0)
@ -293,8 +300,7 @@ void RemoteUI::menu_show(ConstArrayView<DisplayLine> choices,
CharCoord anchor, Face fg, Face bg, CharCoord anchor, Face fg, Face bg,
MenuStyle style) MenuStyle style)
{ {
Message msg(m_socket_watcher.fd()); Message msg{m_socket_watcher.fd(), MessageType::MenuShow};
msg.write(RemoteUIMsg::MenuShow);
msg.write(choices); msg.write(choices);
msg.write(anchor); msg.write(anchor);
msg.write(fg); msg.write(fg);
@ -304,23 +310,20 @@ void RemoteUI::menu_show(ConstArrayView<DisplayLine> choices,
void RemoteUI::menu_select(int selected) void RemoteUI::menu_select(int selected)
{ {
Message msg(m_socket_watcher.fd()); Message msg{m_socket_watcher.fd(), MessageType::MenuSelect};
msg.write(RemoteUIMsg::MenuSelect);
msg.write(selected); msg.write(selected);
} }
void RemoteUI::menu_hide() void RemoteUI::menu_hide()
{ {
Message msg(m_socket_watcher.fd()); Message msg{m_socket_watcher.fd(), MessageType::MenuHide};
msg.write(RemoteUIMsg::MenuHide);
} }
void RemoteUI::info_show(StringView title, StringView content, void RemoteUI::info_show(StringView title, StringView content,
CharCoord anchor, Face face, CharCoord anchor, Face face,
InfoStyle style) InfoStyle style)
{ {
Message msg(m_socket_watcher.fd()); Message msg{m_socket_watcher.fd(), MessageType::InfoShow};
msg.write(RemoteUIMsg::InfoShow);
msg.write(title); msg.write(title);
msg.write(content); msg.write(content);
msg.write(anchor); msg.write(anchor);
@ -330,16 +333,14 @@ void RemoteUI::info_show(StringView title, StringView content,
void RemoteUI::info_hide() void RemoteUI::info_hide()
{ {
Message msg(m_socket_watcher.fd()); Message msg{m_socket_watcher.fd(), MessageType::InfoHide};
msg.write(RemoteUIMsg::InfoHide);
} }
void RemoteUI::draw(const DisplayBuffer& display_buffer, void RemoteUI::draw(const DisplayBuffer& display_buffer,
const Face& default_face, const Face& default_face,
const Face& padding_face) const Face& padding_face)
{ {
Message msg(m_socket_watcher.fd()); Message msg{m_socket_watcher.fd(), MessageType::Draw};
msg.write(RemoteUIMsg::Draw);
msg.write(display_buffer); msg.write(display_buffer);
msg.write(default_face); msg.write(default_face);
msg.write(padding_face); msg.write(padding_face);
@ -349,8 +350,7 @@ void RemoteUI::draw_status(const DisplayLine& status_line,
const DisplayLine& mode_line, const DisplayLine& mode_line,
const Face& default_face) const Face& default_face)
{ {
Message msg(m_socket_watcher.fd()); Message msg{m_socket_watcher.fd(), MessageType::DrawStatus};
msg.write(RemoteUIMsg::DrawStatus);
msg.write(status_line); msg.write(status_line);
msg.write(mode_line); msg.write(mode_line);
msg.write(default_face); msg.write(default_face);
@ -358,15 +358,13 @@ void RemoteUI::draw_status(const DisplayLine& status_line,
void RemoteUI::refresh(bool force) void RemoteUI::refresh(bool force)
{ {
Message msg(m_socket_watcher.fd()); Message msg{m_socket_watcher.fd(), MessageType::Refresh};
msg.write(RemoteUIMsg::Refresh);
msg.write(force); msg.write(force);
} }
void RemoteUI::set_ui_options(const Options& options) void RemoteUI::set_ui_options(const Options& options)
{ {
Message msg(m_socket_watcher.fd()); Message msg{m_socket_watcher.fd(), MessageType::SetOptions};
msg.write(RemoteUIMsg::SetOptions);
msg.write(options); msg.write(options);
} }
@ -379,7 +377,12 @@ Key RemoteUI::get_key()
{ {
try try
{ {
Key key = read<Key>(m_socket_watcher.fd()); const int sock = m_socket_watcher.fd();
const auto msg = read<MessageType>(sock);
if (msg != MessageType::Key)
throw client_removed{ false };
Key key = read<Key>(sock);
if (key.modifiers == Key::Modifiers::Resize) if (key.modifiers == Key::Modifiers::Resize)
m_dimensions = key.coord(); m_dimensions = key.coord();
return key; return key;
@ -441,9 +444,8 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr<UserInterface>&&
int sock = connect_to(session); int sock = connect_to(session);
{ {
Message msg(sock); Message msg{sock, MessageType::Connect};
msg.write(init_command.data(), (int)init_command.length()); msg.write(init_command);
msg.write((char)0);
msg.write(m_ui->dimensions()); msg.write(m_ui->dimensions());
msg.write(env_vars); msg.write(env_vars);
} }
@ -464,10 +466,10 @@ void RemoteClient::process_available_messages()
void RemoteClient::process_next_message() void RemoteClient::process_next_message()
{ {
int socket = m_socket_watcher->fd(); int socket = m_socket_watcher->fd();
RemoteUIMsg msg = read<RemoteUIMsg>(socket); const auto msg = read<MessageType>(socket);
switch (msg) switch (msg)
{ {
case RemoteUIMsg::MenuShow: case MessageType::MenuShow:
{ {
auto choices = read_vector<DisplayLine>(socket); auto choices = read_vector<DisplayLine>(socket);
auto anchor = read<CharCoord>(socket); auto anchor = read<CharCoord>(socket);
@ -477,13 +479,13 @@ void RemoteClient::process_next_message()
m_ui->menu_show(choices, anchor, fg, bg, style); m_ui->menu_show(choices, anchor, fg, bg, style);
break; break;
} }
case RemoteUIMsg::MenuSelect: case MessageType::MenuSelect:
m_ui->menu_select(read<int>(socket)); m_ui->menu_select(read<int>(socket));
break; break;
case RemoteUIMsg::MenuHide: case MessageType::MenuHide:
m_ui->menu_hide(); m_ui->menu_hide();
break; break;
case RemoteUIMsg::InfoShow: case MessageType::InfoShow:
{ {
auto title = read<String>(socket); auto title = read<String>(socket);
auto content = read<String>(socket); auto content = read<String>(socket);
@ -493,10 +495,10 @@ void RemoteClient::process_next_message()
m_ui->info_show(title, content, anchor, face, style); m_ui->info_show(title, content, anchor, face, style);
break; break;
} }
case RemoteUIMsg::InfoHide: case MessageType::InfoHide:
m_ui->info_hide(); m_ui->info_hide();
break; break;
case RemoteUIMsg::Draw: case MessageType::Draw:
{ {
auto display_buffer = read<DisplayBuffer>(socket); auto display_buffer = read<DisplayBuffer>(socket);
auto default_face = read<Face>(socket); auto default_face = read<Face>(socket);
@ -504,7 +506,7 @@ void RemoteClient::process_next_message()
m_ui->draw(display_buffer, default_face, padding_face); m_ui->draw(display_buffer, default_face, padding_face);
break; break;
} }
case RemoteUIMsg::DrawStatus: case MessageType::DrawStatus:
{ {
auto status_line = read<DisplayLine>(socket); auto status_line = read<DisplayLine>(socket);
auto mode_line = read<DisplayLine>(socket); auto mode_line = read<DisplayLine>(socket);
@ -512,18 +514,20 @@ void RemoteClient::process_next_message()
m_ui->draw_status(status_line, mode_line, default_face); m_ui->draw_status(status_line, mode_line, default_face);
break; break;
} }
case RemoteUIMsg::Refresh: case MessageType::Refresh:
m_ui->refresh(read<bool>(socket)); m_ui->refresh(read<bool>(socket));
break; break;
case RemoteUIMsg::SetOptions: case MessageType::SetOptions:
m_ui->set_ui_options(read_idmap<String, MemoryDomain::Options>(socket)); m_ui->set_ui_options(read_idmap<String, MemoryDomain::Options>(socket));
break; break;
default:
kak_assert(false);
} }
} }
void RemoteClient::write_next_key() void RemoteClient::write_next_key()
{ {
Message msg(m_socket_watcher->fd()); Message msg(m_socket_watcher->fd(), MessageType::Key);
// do that before checking dimensions as get_key may // do that before checking dimensions as get_key may
// handle a resize event. // handle a resize event.
msg.write(m_ui->get_key()); msg.write(m_ui->get_key());
@ -533,7 +537,8 @@ void send_command(StringView session, StringView command)
{ {
int sock = connect_to(session); int sock = connect_to(session);
auto close_sock = on_scope_end([sock]{ close(sock); }); auto close_sock = on_scope_end([sock]{ close(sock); });
write(sock, command); Message msg{sock, MessageType::Command};
msg.write(command);
} }
@ -557,46 +562,48 @@ public:
private: private:
void handle_available_input() void handle_available_input()
{ {
const int socket = m_socket_watcher.fd(); const int sock = m_socket_watcher.fd();
do const auto msg = read<MessageType>(sock);
switch (msg)
{ {
char c; case MessageType::Connect:
int res = ::read(socket, &c, 1);
if (res <= 0)
{ {
if (not m_buffer.empty()) try auto init_command = read<String>(sock);
auto dimensions = read<CharCoord>(sock);
auto env_vars = read_idmap<String, MemoryDomain::EnvVars>(sock);
std::unique_ptr<UserInterface> ui{new RemoteUI{sock, dimensions}};
ClientManager::instance().create_client(std::move(ui),
std::move(env_vars),
init_command);
Server::instance().remove_accepter(this);
return;
}
case MessageType::Command:
{
auto command = read<String>(sock);
if (not command.empty()) try
{ {
Context context{Context::EmptyContextFlag{}}; Context context{Context::EmptyContextFlag{}};
CommandManager::instance().execute(m_buffer, context); CommandManager::instance().execute(command, context);
} }
catch (runtime_error& e) catch (runtime_error& e)
{ {
write_to_debug_buffer(format("error running command '{}': {}", write_to_debug_buffer(format("error running command '{}': {}",
m_buffer, e.what())); command, e.what()));
} }
catch (client_removed&) {} catch (client_removed&) {}
close(socket); close(sock);
Server::instance().remove_accepter(this); Server::instance().remove_accepter(this);
return; return;
} }
if (c == 0) // end of initial command stream, go to interactive ui default:
{ write_to_debug_buffer("Invalid introduction message received");
CharCoord dimensions = read<CharCoord>(socket); close(sock);
EnvVarMap env_vars = read_idmap<String, MemoryDomain::EnvVars>(socket);
std::unique_ptr<UserInterface> ui{new RemoteUI{socket, dimensions}};
ClientManager::instance().create_client(std::move(ui),
std::move(env_vars),
m_buffer);
Server::instance().remove_accepter(this); Server::instance().remove_accepter(this);
return; break;
}
else
m_buffer += c;
} }
while (fd_readable(socket));
} }
String m_buffer;
FDWatcher m_socket_watcher; FDWatcher m_socket_watcher;
}; };