mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 13:27:35 +00:00
SpiceAgent: Let's start rewriting the messaging system :^)
The old message system was very dependent on syscalls, and the overall structure made it hard to implement new features. The new message system is pretty expandible, where each message has its own dedicated class. As well as this, we now use Core::File and AK::Stream for reading and writing messages. Using AK::Stream also allows us to change the actual data source (in this case, Core::File) without having to update a whole lot of code in the future.
This commit is contained in:
parent
fd4f00ee91
commit
79c73dd260
7 changed files with 320 additions and 370 deletions
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Kyle Pereira <kyle@xylepereira.me>
|
||||
* Copyright (c) 2023, Caoimhe Byrne <caoimhebyrne06@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -7,123 +8,65 @@
|
|||
#pragma once
|
||||
|
||||
#include "ConnectionToClipboardServer.h"
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include "Message.h"
|
||||
#include "MessageHeader.h"
|
||||
#include <AK/Vector.h>
|
||||
#include <LibCore/Notifier.h>
|
||||
|
||||
namespace SpiceAgent {
|
||||
|
||||
class SpiceAgent {
|
||||
public:
|
||||
SpiceAgent(int fd, ConnectionToClipboardServer&);
|
||||
|
||||
static constexpr u32 AGENT_PROTOCOL = 1;
|
||||
enum class Port {
|
||||
// Indicates where the message has come from.
|
||||
enum class Port : u32 {
|
||||
Client = 1,
|
||||
|
||||
// There are currently no messages which are meant for the server, so all messages sent by the agent (us) with this port are discarded.
|
||||
Server
|
||||
};
|
||||
|
||||
struct [[gnu::packed]] ChunkHeader {
|
||||
u32 port {};
|
||||
u32 size {};
|
||||
};
|
||||
static ErrorOr<NonnullOwnPtr<SpiceAgent>> create(StringView device_path);
|
||||
SpiceAgent(NonnullOwnPtr<Core::File> spice_device, ConnectionToClipboardServer& clipboard_connection, Vector<Capability> const& capabilities);
|
||||
|
||||
struct [[gnu::packed]] Message {
|
||||
u32 protocol;
|
||||
u32 type;
|
||||
u64 opaque;
|
||||
u32 size;
|
||||
u8 data[];
|
||||
};
|
||||
ErrorOr<void> start();
|
||||
|
||||
enum class MessageType {
|
||||
MouseState = 1, // server -> client
|
||||
MonitorsConfig, // client -> agent|server
|
||||
Reply, // agent -> client
|
||||
Clipboard, // both directions
|
||||
DisplayConfig, // client -> agent
|
||||
AnnounceCapabilities, // both directions
|
||||
ClipboardGrab, // both directions
|
||||
ClipboardRequest, // both directions
|
||||
ClipboardRelease, // both directions
|
||||
FileTransferStart,
|
||||
FileTransferStatus,
|
||||
FileTransferData,
|
||||
Disconnected,
|
||||
MaxClipboard,
|
||||
VolumeSync,
|
||||
GraphicsDeviceInfo,
|
||||
};
|
||||
template<typename T>
|
||||
ErrorOr<void> send_message(T message)
|
||||
{
|
||||
// Attempt to write the message's data to a stream.
|
||||
auto message_stream = AK::AllocatingMemoryStream();
|
||||
TRY(message.write_to_stream(message_stream));
|
||||
|
||||
enum class Capability {
|
||||
MouseState = 0,
|
||||
MonitorsConfig,
|
||||
Reply,
|
||||
Clipboard,
|
||||
DisplayConfig,
|
||||
ClipboardByDemand,
|
||||
ClipboardSelection,
|
||||
SparseMonitorsConfig,
|
||||
GuestLineEndLF,
|
||||
GuestLineEndCRLF,
|
||||
MaxClipboard,
|
||||
AudioVolumeSync,
|
||||
MonitorsConfigPosition,
|
||||
FileTransferDisabled,
|
||||
FileTransferDetailedErrors,
|
||||
GraphicsCardInfo,
|
||||
ClipboardNoReleaseOnRegrab,
|
||||
ClipboardGrabSerial,
|
||||
__End,
|
||||
};
|
||||
// Create a header to be sent.
|
||||
auto header_stream = AK::AllocatingMemoryStream();
|
||||
auto header = MessageHeader(message.type(), message_stream.used_buffer_size());
|
||||
TRY(header_stream.write_value(header));
|
||||
|
||||
enum class ClipboardType {
|
||||
None = 0,
|
||||
Text,
|
||||
PNG,
|
||||
BMP,
|
||||
TIFF,
|
||||
JPEG,
|
||||
FileList,
|
||||
__Count
|
||||
};
|
||||
// Currently, there are no messages from the agent which are meant for the server.
|
||||
// So, all messages sent by the agent with a port of Port::Server get dropped silently.
|
||||
TRY(m_spice_device->write_value(Port::Client));
|
||||
|
||||
constexpr static size_t CAPABILITIES_SIZE = ((size_t)Capability::__End + 31) / 32;
|
||||
// The length of the subsequent data.
|
||||
auto length = header_stream.used_buffer_size() + message_stream.used_buffer_size();
|
||||
TRY(m_spice_device->write_value<u32>(length));
|
||||
|
||||
struct [[gnu::packed]] AnnounceCapabilities {
|
||||
u32 request;
|
||||
u32 caps[CAPABILITIES_SIZE];
|
||||
// The message's header.
|
||||
TRY(m_spice_device->write_until_depleted(TRY(header_stream.read_until_eof())));
|
||||
|
||||
static ByteBuffer make_buffer(bool request, Vector<Capability> const& capabilities);
|
||||
};
|
||||
// The message content.
|
||||
TRY(m_spice_device->write_until_depleted(TRY(message_stream.read_until_eof())));
|
||||
|
||||
struct [[gnu::packed]] ClipboardGrab {
|
||||
u32 types[0];
|
||||
|
||||
static ByteBuffer make_buffer(Vector<ClipboardType> const&);
|
||||
};
|
||||
|
||||
struct [[gnu::packed]] Clipboard {
|
||||
u32 type;
|
||||
u8 data[];
|
||||
|
||||
static ByteBuffer make_buffer(ClipboardType, ReadonlyBytes);
|
||||
};
|
||||
|
||||
struct [[gnu::packed]] ClipboardRequest {
|
||||
u32 type;
|
||||
|
||||
static ByteBuffer make_buffer(ClipboardType);
|
||||
};
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
int m_fd { -1 };
|
||||
RefPtr<Core::Notifier> m_notifier;
|
||||
NonnullOwnPtr<Core::File> m_spice_device;
|
||||
ConnectionToClipboardServer& m_clipboard_connection;
|
||||
Vector<Capability> m_capabilities;
|
||||
|
||||
RefPtr<Core::Notifier> m_notifier;
|
||||
|
||||
ErrorOr<void> on_message_received();
|
||||
|
||||
void send_message(ByteBuffer const& buffer);
|
||||
bool m_just_set_clip { false };
|
||||
void read_n(void* dest, size_t n);
|
||||
static Message* initialize_headers(u8* data, size_t additional_data_size, MessageType type);
|
||||
static Optional<ClipboardType> mime_type_to_clipboard_type(DeprecatedString const& mime);
|
||||
ErrorOr<ByteBuffer> read_message_buffer();
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue