Use proper buffering when reading remote messages
Messages now have their size in a header, along with their type and are only executed once fully received. We dont block anymore while trying to read a full message.
This commit is contained in:
parent
044a6ce860
commit
563497ade7
|
@ -32,6 +32,7 @@ enum class MemoryDomain
|
||||||
WordDB,
|
WordDB,
|
||||||
Selections,
|
Selections,
|
||||||
History,
|
History,
|
||||||
|
Remote,
|
||||||
Count
|
Count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,6 +60,7 @@ inline const char* domain_name(MemoryDomain domain)
|
||||||
case MemoryDomain::Client: return "Client";
|
case MemoryDomain::Client: return "Client";
|
||||||
case MemoryDomain::Selections: return "Selections";
|
case MemoryDomain::Selections: return "Selections";
|
||||||
case MemoryDomain::History: return "History";
|
case MemoryDomain::History: return "History";
|
||||||
|
case MemoryDomain::Remote: return "Remote";
|
||||||
case MemoryDomain::Count: break;
|
case MemoryDomain::Count: break;
|
||||||
}
|
}
|
||||||
kak_assert(false);
|
kak_assert(false);
|
||||||
|
|
326
src/remote.cc
326
src/remote.cc
|
@ -21,8 +21,9 @@
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
enum class MessageType
|
enum class MessageType : char
|
||||||
{
|
{
|
||||||
|
Unknown,
|
||||||
Connect,
|
Connect,
|
||||||
Command,
|
Command,
|
||||||
MenuShow,
|
MenuShow,
|
||||||
|
@ -39,18 +40,18 @@ enum class MessageType
|
||||||
|
|
||||||
struct socket_error{};
|
struct socket_error{};
|
||||||
|
|
||||||
class Message
|
class MsgWriter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Message(int sock, MessageType type) : m_socket(sock)
|
MsgWriter(int sock, MessageType type) : m_socket(sock)
|
||||||
{
|
{
|
||||||
write(type);
|
write(type);
|
||||||
|
write((uint32_t)0); // message size, to be patched on write
|
||||||
}
|
}
|
||||||
|
|
||||||
~Message() noexcept(false)
|
~MsgWriter() noexcept(false)
|
||||||
{
|
{
|
||||||
if (m_stream.size() == 0)
|
*reinterpret_cast<uint32_t*>(m_stream.data()+1) = (uint32_t)m_stream.size();
|
||||||
return;
|
|
||||||
int res = ::write(m_socket, m_stream.data(), m_stream.size());
|
int res = ::write(m_socket, m_stream.data(), m_stream.size());
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
throw peer_disconnected{};
|
throw peer_disconnected{};
|
||||||
|
@ -131,27 +132,53 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector<char> m_stream;
|
Vector<char, MemoryDomain::Remote> m_stream;
|
||||||
int m_socket;
|
int m_socket;
|
||||||
};
|
};
|
||||||
|
|
||||||
void read(int socket, char* buffer, size_t size)
|
class MsgReader
|
||||||
{
|
{
|
||||||
while (size)
|
public:
|
||||||
|
void read_available(int sock)
|
||||||
{
|
{
|
||||||
int res = ::read(socket, buffer, size);
|
if (m_write_pos < header_size)
|
||||||
if (res == 0)
|
{
|
||||||
throw peer_disconnected{};
|
m_stream.resize(header_size);
|
||||||
if (res < 0)
|
read_from_socket(sock, header_size - m_write_pos);
|
||||||
throw socket_error{};
|
if (m_write_pos == header_size)
|
||||||
|
m_stream.resize(size());
|
||||||
buffer += res;
|
|
||||||
size -= res;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
read_from_socket(sock, size() - m_write_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ready() const
|
||||||
|
{
|
||||||
|
return m_write_pos >= header_size and m_write_pos == size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t size() const
|
||||||
|
{
|
||||||
|
kak_assert(m_write_pos >= header_size);
|
||||||
|
return *reinterpret_cast<const uint32_t*>(m_stream.data()+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageType type() const
|
||||||
|
{
|
||||||
|
kak_assert(m_write_pos >= header_size);
|
||||||
|
return *reinterpret_cast<const MessageType*>(m_stream.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void read(char* buffer, size_t size)
|
||||||
|
{
|
||||||
|
if (m_stream.size() - m_read_pos < size)
|
||||||
|
throw peer_disconnected{};
|
||||||
|
memcpy(buffer, m_stream.data() + m_read_pos, size);
|
||||||
|
m_read_pos += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T read(int socket)
|
T read()
|
||||||
{
|
{
|
||||||
union U
|
union U
|
||||||
{
|
{
|
||||||
|
@ -160,84 +187,109 @@ T read(int socket)
|
||||||
U() {}
|
U() {}
|
||||||
~U() { object.~T(); }
|
~U() { object.~T(); }
|
||||||
} u;
|
} u;
|
||||||
read(socket, u.data, sizeof(T));
|
read(u.data, sizeof(T));
|
||||||
return u.object;
|
return u.object;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
|
||||||
String read<String>(int socket)
|
|
||||||
{
|
|
||||||
ByteCount length = read<ByteCount>(socket);
|
|
||||||
String res;
|
|
||||||
if (length > 0)
|
|
||||||
{
|
|
||||||
res.force_size((int)length);
|
|
||||||
read(socket, &res[0_byte], (int)length);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Vector<T> read_vector(int socket)
|
Vector<T> read_vector()
|
||||||
{
|
{
|
||||||
uint32_t size = read<uint32_t>(socket);
|
uint32_t size = read<uint32_t>();
|
||||||
Vector<T> res;
|
Vector<T> res;
|
||||||
res.reserve(size);
|
res.reserve(size);
|
||||||
while (size--)
|
while (size--)
|
||||||
res.push_back(read<T>(socket));
|
res.push_back(read<T>());
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
|
||||||
Color read<Color>(int socket)
|
|
||||||
{
|
|
||||||
Color res;
|
|
||||||
res.color = read<Color::NamedColor>(socket);
|
|
||||||
if (res.color == Color::RGB)
|
|
||||||
{
|
|
||||||
res.r = read<unsigned char>(socket);
|
|
||||||
res.g = read<unsigned char>(socket);
|
|
||||||
res.b = read<unsigned char>(socket);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
DisplayAtom read<DisplayAtom>(int socket)
|
|
||||||
{
|
|
||||||
DisplayAtom atom(read<String>(socket));
|
|
||||||
atom.face = read<Face>(socket);
|
|
||||||
return atom;
|
|
||||||
}
|
|
||||||
template<>
|
|
||||||
DisplayLine read<DisplayLine>(int socket)
|
|
||||||
{
|
|
||||||
return DisplayLine(read_vector<DisplayAtom>(socket));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
DisplayBuffer read<DisplayBuffer>(int socket)
|
|
||||||
{
|
|
||||||
DisplayBuffer db;
|
|
||||||
db.lines() = read_vector<DisplayLine>(socket);
|
|
||||||
return db;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Val, MemoryDomain domain>
|
template<typename Val, MemoryDomain domain>
|
||||||
IdMap<Val, domain> read_idmap(int socket)
|
IdMap<Val, domain> read_idmap()
|
||||||
{
|
{
|
||||||
uint32_t size = read<uint32_t>(socket);
|
uint32_t size = read<uint32_t>();
|
||||||
IdMap<Val, domain> res;
|
IdMap<Val, domain> res;
|
||||||
res.reserve(size);
|
res.reserve(size);
|
||||||
while (size--)
|
while (size--)
|
||||||
{
|
{
|
||||||
auto key = read<String>(socket);
|
auto key = read<String>();
|
||||||
auto val = read<Val>(socket);
|
auto val = read<Val>();
|
||||||
res.append({std::move(key), std::move(val)});
|
res.append({std::move(key), std::move(val)});
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
m_stream.resize(0);
|
||||||
|
m_write_pos = 0;
|
||||||
|
m_read_pos = header_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void read_from_socket(int sock, size_t size)
|
||||||
|
{
|
||||||
|
int res = ::read(sock, m_stream.data() + m_write_pos, size);
|
||||||
|
if (res == 0)
|
||||||
|
throw peer_disconnected{};
|
||||||
|
if (res < 0)
|
||||||
|
throw socket_error{};
|
||||||
|
m_write_pos += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t header_size = sizeof(MessageType) + sizeof(uint32_t);
|
||||||
|
Vector<char, MemoryDomain::Remote> m_stream;
|
||||||
|
uint32_t m_write_pos = 0;
|
||||||
|
uint32_t m_read_pos = header_size;
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
String MsgReader::read<String>()
|
||||||
|
{
|
||||||
|
ByteCount length = read<ByteCount>();
|
||||||
|
String res;
|
||||||
|
if (length > 0)
|
||||||
|
{
|
||||||
|
res.force_size((int)length);
|
||||||
|
read(&res[0_byte], (int)length);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
Color MsgReader::read<Color>()
|
||||||
|
{
|
||||||
|
Color res;
|
||||||
|
res.color = read<Color::NamedColor>();
|
||||||
|
if (res.color == Color::RGB)
|
||||||
|
{
|
||||||
|
res.r = read<unsigned char>();
|
||||||
|
res.g = read<unsigned char>();
|
||||||
|
res.b = read<unsigned char>();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
DisplayAtom MsgReader::read<DisplayAtom>()
|
||||||
|
{
|
||||||
|
DisplayAtom atom(read<String>());
|
||||||
|
atom.face = read<Face>();
|
||||||
|
return atom;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
DisplayLine MsgReader::read<DisplayLine>()
|
||||||
|
{
|
||||||
|
return DisplayLine(read_vector<DisplayAtom>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
DisplayBuffer MsgReader::read<DisplayBuffer>()
|
||||||
|
{
|
||||||
|
DisplayBuffer db;
|
||||||
|
db.lines() = read_vector<DisplayLine>();
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class RemoteUI : public UserInterface
|
class RemoteUI : public UserInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -275,14 +327,19 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FDWatcher m_socket_watcher;
|
FDWatcher m_socket_watcher;
|
||||||
|
MsgReader m_reader;
|
||||||
CharCoord m_dimensions;
|
CharCoord m_dimensions;
|
||||||
InputCallback m_input_callback;
|
InputCallback m_input_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
RemoteUI::RemoteUI(int socket, CharCoord dimensions)
|
RemoteUI::RemoteUI(int socket, CharCoord dimensions)
|
||||||
: m_socket_watcher(socket, [this](FDWatcher&, EventMode mode) {
|
: m_socket_watcher(socket, [this](FDWatcher& watcher, EventMode mode) {
|
||||||
if (m_input_callback)
|
const int sock = watcher.fd();
|
||||||
|
while (fd_readable(sock) and not m_reader.ready())
|
||||||
|
m_reader.read_available(sock);
|
||||||
|
|
||||||
|
if (m_reader.ready() and m_input_callback)
|
||||||
m_input_callback(mode);
|
m_input_callback(mode);
|
||||||
}),
|
}),
|
||||||
m_dimensions(dimensions)
|
m_dimensions(dimensions)
|
||||||
|
@ -300,7 +357,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(), MessageType::MenuShow};
|
MsgWriter msg{m_socket_watcher.fd(), MessageType::MenuShow};
|
||||||
msg.write(choices);
|
msg.write(choices);
|
||||||
msg.write(anchor);
|
msg.write(anchor);
|
||||||
msg.write(fg);
|
msg.write(fg);
|
||||||
|
@ -310,20 +367,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(), MessageType::MenuSelect};
|
MsgWriter msg{m_socket_watcher.fd(), MessageType::MenuSelect};
|
||||||
msg.write(selected);
|
msg.write(selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteUI::menu_hide()
|
void RemoteUI::menu_hide()
|
||||||
{
|
{
|
||||||
Message msg{m_socket_watcher.fd(), MessageType::MenuHide};
|
MsgWriter msg{m_socket_watcher.fd(), MessageType::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(), MessageType::InfoShow};
|
MsgWriter msg{m_socket_watcher.fd(), MessageType::InfoShow};
|
||||||
msg.write(title);
|
msg.write(title);
|
||||||
msg.write(content);
|
msg.write(content);
|
||||||
msg.write(anchor);
|
msg.write(anchor);
|
||||||
|
@ -333,14 +390,14 @@ void RemoteUI::info_show(StringView title, StringView content,
|
||||||
|
|
||||||
void RemoteUI::info_hide()
|
void RemoteUI::info_hide()
|
||||||
{
|
{
|
||||||
Message msg{m_socket_watcher.fd(), MessageType::InfoHide};
|
MsgWriter msg{m_socket_watcher.fd(), MessageType::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(), MessageType::Draw};
|
MsgWriter msg{m_socket_watcher.fd(), MessageType::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);
|
||||||
|
@ -350,7 +407,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(), MessageType::DrawStatus};
|
MsgWriter msg{m_socket_watcher.fd(), MessageType::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,31 +415,31 @@ void RemoteUI::draw_status(const DisplayLine& status_line,
|
||||||
|
|
||||||
void RemoteUI::refresh(bool force)
|
void RemoteUI::refresh(bool force)
|
||||||
{
|
{
|
||||||
Message msg{m_socket_watcher.fd(), MessageType::Refresh};
|
MsgWriter msg{m_socket_watcher.fd(), MessageType::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(), MessageType::SetOptions};
|
MsgWriter msg{m_socket_watcher.fd(), MessageType::SetOptions};
|
||||||
msg.write(options);
|
msg.write(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemoteUI::is_key_available()
|
bool RemoteUI::is_key_available()
|
||||||
{
|
{
|
||||||
return fd_readable(m_socket_watcher.fd());
|
return m_reader.ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
Key RemoteUI::get_key()
|
Key RemoteUI::get_key()
|
||||||
{
|
{
|
||||||
|
kak_assert(m_reader.ready());
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const int sock = m_socket_watcher.fd();
|
if (m_reader.type() != MessageType::Key)
|
||||||
const auto msg = read<MessageType>(sock);
|
|
||||||
if (msg != MessageType::Key)
|
|
||||||
throw client_removed{ false };
|
throw client_removed{ false };
|
||||||
|
|
||||||
Key key = read<Key>(sock);
|
Key key = m_reader.read<Key>();
|
||||||
|
m_reader.reset();
|
||||||
if (key.modifiers == Key::Modifiers::Resize)
|
if (key.modifiers == Key::Modifiers::Resize)
|
||||||
m_dimensions = key.coord();
|
m_dimensions = key.coord();
|
||||||
return key;
|
return key;
|
||||||
|
@ -444,7 +501,7 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr<UserInterface>&&
|
||||||
int sock = connect_to(session);
|
int sock = connect_to(session);
|
||||||
|
|
||||||
{
|
{
|
||||||
Message msg{sock, MessageType::Connect};
|
MsgWriter msg{sock, MessageType::Connect};
|
||||||
msg.write(init_command);
|
msg.write(init_command);
|
||||||
msg.write(m_ui->dimensions());
|
msg.write(m_ui->dimensions());
|
||||||
msg.write(env_vars);
|
msg.write(env_vars);
|
||||||
|
@ -452,46 +509,41 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr<UserInterface>&&
|
||||||
|
|
||||||
m_ui->set_input_callback([this](EventMode){ write_next_key(); });
|
m_ui->set_input_callback([this](EventMode){ write_next_key(); });
|
||||||
|
|
||||||
m_socket_watcher.reset(new FDWatcher{sock, [this](FDWatcher&, EventMode){ process_available_messages(); }});
|
MsgReader reader;
|
||||||
}
|
m_socket_watcher.reset(new FDWatcher{sock, [this, reader](FDWatcher& watcher, EventMode) mutable {
|
||||||
|
const int sock = watcher.fd();
|
||||||
|
while (fd_readable(sock) and not reader.ready())
|
||||||
|
reader.read_available(sock);
|
||||||
|
|
||||||
void RemoteClient::process_available_messages()
|
if (not reader.ready())
|
||||||
{
|
return;
|
||||||
int socket = m_socket_watcher->fd();
|
|
||||||
do {
|
|
||||||
process_next_message();
|
|
||||||
} while (fd_readable(socket));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteClient::process_next_message()
|
auto clear_reader = on_scope_end([&reader] { reader.reset(); });
|
||||||
{
|
switch (reader.type())
|
||||||
int socket = m_socket_watcher->fd();
|
|
||||||
const auto msg = read<MessageType>(socket);
|
|
||||||
switch (msg)
|
|
||||||
{
|
{
|
||||||
case MessageType::MenuShow:
|
case MessageType::MenuShow:
|
||||||
{
|
{
|
||||||
auto choices = read_vector<DisplayLine>(socket);
|
auto choices = reader.read_vector<DisplayLine>();
|
||||||
auto anchor = read<CharCoord>(socket);
|
auto anchor = reader.read<CharCoord>();
|
||||||
auto fg = read<Face>(socket);
|
auto fg = reader.read<Face>();
|
||||||
auto bg = read<Face>(socket);
|
auto bg = reader.read<Face>();
|
||||||
auto style = read<MenuStyle>(socket);
|
auto style = reader.read<MenuStyle>();
|
||||||
m_ui->menu_show(choices, anchor, fg, bg, style);
|
m_ui->menu_show(choices, anchor, fg, bg, style);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MessageType::MenuSelect:
|
case MessageType::MenuSelect:
|
||||||
m_ui->menu_select(read<int>(socket));
|
m_ui->menu_select(reader.read<int>());
|
||||||
break;
|
break;
|
||||||
case MessageType::MenuHide:
|
case MessageType::MenuHide:
|
||||||
m_ui->menu_hide();
|
m_ui->menu_hide();
|
||||||
break;
|
break;
|
||||||
case MessageType::InfoShow:
|
case MessageType::InfoShow:
|
||||||
{
|
{
|
||||||
auto title = read<String>(socket);
|
auto title = reader.read<String>();
|
||||||
auto content = read<String>(socket);
|
auto content = reader.read<String>();
|
||||||
auto anchor = read<CharCoord>(socket);
|
auto anchor = reader.read<CharCoord>();
|
||||||
auto face = read<Face>(socket);
|
auto face = reader.read<Face>();
|
||||||
auto style = read<InfoStyle>(socket);
|
auto style = reader.read<InfoStyle>();
|
||||||
m_ui->info_show(title, content, anchor, face, style);
|
m_ui->info_show(title, content, anchor, face, style);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -500,34 +552,35 @@ void RemoteClient::process_next_message()
|
||||||
break;
|
break;
|
||||||
case MessageType::Draw:
|
case MessageType::Draw:
|
||||||
{
|
{
|
||||||
auto display_buffer = read<DisplayBuffer>(socket);
|
auto display_buffer = reader.read<DisplayBuffer>();
|
||||||
auto default_face = read<Face>(socket);
|
auto default_face = reader.read<Face>();
|
||||||
auto padding_face = read<Face>(socket);
|
auto padding_face = reader.read<Face>();
|
||||||
m_ui->draw(display_buffer, default_face, padding_face);
|
m_ui->draw(display_buffer, default_face, padding_face);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MessageType::DrawStatus:
|
case MessageType::DrawStatus:
|
||||||
{
|
{
|
||||||
auto status_line = read<DisplayLine>(socket);
|
auto status_line = reader.read<DisplayLine>();
|
||||||
auto mode_line = read<DisplayLine>(socket);
|
auto mode_line = reader.read<DisplayLine>();
|
||||||
auto default_face = read<Face>(socket);
|
auto default_face = reader.read<Face>();
|
||||||
m_ui->draw_status(status_line, mode_line, default_face);
|
m_ui->draw_status(status_line, mode_line, default_face);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MessageType::Refresh:
|
case MessageType::Refresh:
|
||||||
m_ui->refresh(read<bool>(socket));
|
m_ui->refresh(reader.read<bool>());
|
||||||
break;
|
break;
|
||||||
case MessageType::SetOptions:
|
case MessageType::SetOptions:
|
||||||
m_ui->set_ui_options(read_idmap<String, MemoryDomain::Options>(socket));
|
m_ui->set_ui_options(reader.read_idmap<String, MemoryDomain::Options>());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
kak_assert(false);
|
kak_assert(false);
|
||||||
}
|
}
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteClient::write_next_key()
|
void RemoteClient::write_next_key()
|
||||||
{
|
{
|
||||||
Message msg(m_socket_watcher->fd(), MessageType::Key);
|
MsgWriter 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());
|
||||||
|
@ -537,7 +590,7 @@ 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); });
|
||||||
Message msg{sock, MessageType::Command};
|
MsgWriter msg{sock, MessageType::Command};
|
||||||
msg.write(command);
|
msg.write(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,14 +616,22 @@ private:
|
||||||
void handle_available_input()
|
void handle_available_input()
|
||||||
{
|
{
|
||||||
const int sock = m_socket_watcher.fd();
|
const int sock = m_socket_watcher.fd();
|
||||||
const auto msg = read<MessageType>(sock);
|
do
|
||||||
switch (msg)
|
{
|
||||||
|
m_reader.read_available(sock);
|
||||||
|
}
|
||||||
|
while (fd_readable(sock) and not m_reader.ready());
|
||||||
|
|
||||||
|
if (not m_reader.ready())
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (m_reader.type())
|
||||||
{
|
{
|
||||||
case MessageType::Connect:
|
case MessageType::Connect:
|
||||||
{
|
{
|
||||||
auto init_command = read<String>(sock);
|
auto init_command = m_reader.read<String>();
|
||||||
auto dimensions = read<CharCoord>(sock);
|
auto dimensions = m_reader.read<CharCoord>();
|
||||||
auto env_vars = read_idmap<String, MemoryDomain::EnvVars>(sock);
|
auto env_vars = m_reader.read_idmap<String, MemoryDomain::EnvVars>();
|
||||||
std::unique_ptr<UserInterface> ui{new RemoteUI{sock, dimensions}};
|
std::unique_ptr<UserInterface> ui{new RemoteUI{sock, dimensions}};
|
||||||
ClientManager::instance().create_client(std::move(ui),
|
ClientManager::instance().create_client(std::move(ui),
|
||||||
std::move(env_vars),
|
std::move(env_vars),
|
||||||
|
@ -580,7 +641,7 @@ private:
|
||||||
}
|
}
|
||||||
case MessageType::Command:
|
case MessageType::Command:
|
||||||
{
|
{
|
||||||
auto command = read<String>(sock);
|
auto command = m_reader.read<String>();
|
||||||
if (not command.empty()) try
|
if (not command.empty()) try
|
||||||
{
|
{
|
||||||
Context context{Context::EmptyContextFlag{}};
|
Context context{Context::EmptyContextFlag{}};
|
||||||
|
@ -605,6 +666,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
FDWatcher m_socket_watcher;
|
FDWatcher m_socket_watcher;
|
||||||
|
MsgReader m_reader;
|
||||||
};
|
};
|
||||||
|
|
||||||
Server::Server(String session_name)
|
Server::Server(String session_name)
|
||||||
|
|
|
@ -32,8 +32,6 @@ public:
|
||||||
const EnvVarMap& env_vars, StringView init_command);
|
const EnvVarMap& env_vars, StringView init_command);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void process_available_messages();
|
|
||||||
void process_next_message();
|
|
||||||
void write_next_key();
|
void write_next_key();
|
||||||
|
|
||||||
std::unique_ptr<UserInterface> m_ui;
|
std::unique_ptr<UserInterface> m_ui;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user