diff options
author | Gunnar Beutner <gbeutner@serenityos.org> | 2021-05-03 08:46:40 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-03 21:14:06 +0200 |
commit | 78803ce384d62c40958cc8191a036307f5d8bc9f (patch) | |
tree | e8ae0a6a50f307e92a2074967417c1bc845e6d31 | |
parent | 065040872f62f608374da6709502033720442882 (diff) | |
download | serenity-78803ce384d62c40958cc8191a036307f5d8bc9f.zip |
Userland: Split IPC endpoints into proxies and stubs
This enables support for automatically generating client methods.
With this added the user gets code completion support for all
IPC methods which are available on a connection object.
20 files changed, 175 insertions, 53 deletions
diff --git a/Userland/DevTools/HackStudio/LanguageServers/ClientConnection.h b/Userland/DevTools/HackStudio/LanguageServers/ClientConnection.h index 563d317ac5..cba8fadb94 100644 --- a/Userland/DevTools/HackStudio/LanguageServers/ClientConnection.h +++ b/Userland/DevTools/HackStudio/LanguageServers/ClientConnection.h @@ -20,8 +20,7 @@ namespace LanguageServers { class ClientConnection : public IPC::ClientConnection<LanguageClientEndpoint, LanguageServerEndpoint> - , public LanguageServerEndpoint { - +{ public: explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id); ~ClientConnection() override; diff --git a/Userland/DevTools/IPCCompiler/main.cpp b/Userland/DevTools/IPCCompiler/main.cpp index 82d77fd2f2..5b35a4942b 100644 --- a/Userland/DevTools/IPCCompiler/main.cpp +++ b/Userland/DevTools/IPCCompiler/main.cpp @@ -60,6 +60,25 @@ static String snake_case(String const& identifier) return builder.to_string(); } +bool is_primitive_type(String const& type) +{ + return (type == "u8" || type == "i8" || type == "u16" || type == "i16" + || type == "u32" || type == "i32" || type == "bool" || type == "double" + || type == "float" || type == "int" || type == "unsigned" || type == "unsigned int"); +} + +String message_name(String const& endpoint, String& message, bool is_response) +{ + StringBuilder builder; + builder.append("Messages::"); + builder.append(endpoint); + builder.append("::"); + builder.append(message); + if (is_response) + builder.append("Response"); + return builder.to_string(); +} + int main(int argc, char** argv) { if (argc != 2) { @@ -231,10 +250,11 @@ int main(int argc, char** argv) #include <LibGfx/Color.h> #include <LibGfx/Rect.h> #include <LibGfx/ShareableBitmap.h> +#include <LibIPC/Connection.h> #include <LibIPC/Decoder.h> #include <LibIPC/Dictionary.h> #include <LibIPC/Encoder.h> -#include <LibIPC/Endpoint.h> +#include <LibIPC/Stub.h> #include <LibIPC/File.h> #include <LibIPC/Message.h> )~~~"); @@ -329,6 +349,9 @@ public: message_generator.append(R"~~~( @message.name@(decltype(nullptr)) : m_ipc_message_valid(false) { } + @message.name@(@message.name@ const&) = default; + @message.name@(@message.name@&&) = default; + @message.name@& operator=(@message.name@ const&) = default; @message.constructor@ virtual ~@message.name@() override {} @@ -452,15 +475,109 @@ private: )~~~"); endpoint_generator.append(R"~~~( -class @endpoint.name@Endpoint : public IPC::Endpoint { +template<typename LocalEndpoint, typename PeerEndpoint> +class @endpoint.name@Proxy { public: - @endpoint.name@Endpoint() { } - virtual ~@endpoint.name@Endpoint() override { } + // Used to disambiguate the constructor call. + struct Tag { }; + + @endpoint.name@Proxy(IPC::Connection<LocalEndpoint, PeerEndpoint>& connection, Tag) + : m_connection(connection) + { } +)~~~"); + + for (auto& message : endpoint.messages) { + auto message_generator = endpoint_generator.fork(); + + auto do_implement_proxy = [&](String const& name, Vector<Parameter> const& parameters, bool is_synchronous) { + String return_type = "void"; + if (is_synchronous && !message.outputs.is_empty()) + return_type = message_name(endpoint.name, message.name, true); + message_generator.set("message.name", message.name); + message_generator.set("message.complex_return_type", return_type); + message_generator.set("async_prefix_maybe", is_synchronous ? "" : "async_"); + + message_generator.set("handler_name", snake_case(name)); + message_generator.append(R"~~~( + @message.complex_return_type@ @async_prefix_maybe@@handler_name@()~~~"); + + for (size_t i = 0; i < parameters.size(); ++i) { + auto& parameter = parameters[i]; + auto argument_generator = message_generator.fork(); + argument_generator.set("argument.type", parameter.type); + argument_generator.set("argument.name", parameter.name); + argument_generator.append("@argument.type@ @argument.name@"); + if (i != parameters.size() - 1) + argument_generator.append(", "); + } + + message_generator.append(") {"); + + if (is_synchronous) { + if (return_type != "void") { + message_generator.append(R"~~~( + return move(*)~~~"); + } else{ + message_generator.append(R"~~~( + )~~~"); + } + + message_generator.append("m_connection.template send_sync<Messages::@endpoint.name@::@message.name@>("); + } else { + message_generator.append(R"~~~( + m_connection.post_message(Messages::@endpoint.name@::@message.name@ { )~~~"); + } + + for (size_t i = 0; i < parameters.size(); ++i) { + auto& parameter = parameters[i]; + auto argument_generator = message_generator.fork(); + argument_generator.set("argument.name", parameter.name); + if (is_primitive_type(parameters[i].type)) + argument_generator.append("@argument.name@"); + else + argument_generator.append("move(@argument.name@)"); + if (i != parameters.size() - 1) + argument_generator.append(", "); + } + + if (is_synchronous) { + if (return_type != "void") { + message_generator.append(")"); + } + + message_generator.append(R"~~~(); + } +)~~~"); + } else { + message_generator.append(R"~~~( }); + } +)~~~"); + } + }; + + do_implement_proxy(message.name, message.inputs, message.is_synchronous); + if (message.is_synchronous) + do_implement_proxy(message.name, message.inputs, false); + } + + endpoint_generator.append(R"~~~( +private: + IPC::Connection<LocalEndpoint, PeerEndpoint>& m_connection; +}; +)~~~"); + + endpoint_generator.append(R"~~~( +template<typename LocalEndpoint, typename PeerEndpoint> +class @endpoint.name@Proxy; +class @endpoint.name@Stub; + +class @endpoint.name@Endpoint { +public: + template<typename LocalEndpoint> + using Proxy = @endpoint.name@Proxy<LocalEndpoint, @endpoint.name@Endpoint>; + using Stub = @endpoint.name@Stub; static u32 static_magic() { return @endpoint.magic@; } - virtual u32 magic() const override { return @endpoint.magic@; } - static String static_name() { return "@endpoint.name@"; } - virtual String name() const override { return "@endpoint.name@"; } static OwnPtr<IPC::Message> decode_message(ReadonlyBytes buffer, int sockfd) { @@ -550,6 +667,16 @@ public: return message; } +}; + +class @endpoint.name@Stub : public IPC::Stub { +public: + @endpoint.name@Stub() { } + virtual ~@endpoint.name@Stub() override { } + + virtual u32 magic() const override { return @endpoint.magic@; } + virtual String name() const override { return "@endpoint.name@"; } + virtual OwnPtr<IPC::MessageBuffer> handle(const IPC::Message& message) override { switch (message.message_id()) { @@ -619,15 +746,8 @@ public: auto do_handle_message_decl = [&](String const& name, Vector<Parameter> const& parameters, bool is_response) { String return_type = "void"; - if (message.is_synchronous && !message.outputs.is_empty() && !is_response) { - StringBuilder builder; - builder.append("Messages::"); - builder.append(endpoint.name); - builder.append("::"); - builder.append(message.name); - builder.append("Response"); - return_type = builder.to_string(); - } + if (message.is_synchronous && !message.outputs.is_empty() && !is_response) + return_type = message_name(endpoint.name, message.name, true); message_generator.set("message.complex_return_type", return_type); message_generator.set("handler_name", snake_case(name)); @@ -637,11 +757,7 @@ public: auto make_argument_type = [](String const& type) { StringBuilder builder; - bool const_ref = true; - if (type == "u8" || type == "i8" || type == "u16" || type == "i16" - || type == "u32" || type == "i32" || type == "bool" || type == "double" - || type == "float" || type == "int" || type == "unsigned" || type == "unsigned int") - const_ref = false; + bool const_ref = !is_primitive_type(type); builder.append(type); if (const_ref) diff --git a/Userland/Libraries/LibIPC/CMakeLists.txt b/Userland/Libraries/LibIPC/CMakeLists.txt index ea1a23640e..d72e4d7fb5 100644 --- a/Userland/Libraries/LibIPC/CMakeLists.txt +++ b/Userland/Libraries/LibIPC/CMakeLists.txt @@ -1,8 +1,8 @@ set(SOURCES Decoder.cpp Encoder.cpp - Endpoint.cpp Message.cpp + Stub.cpp ) serenity_lib(LibIPC ipc) diff --git a/Userland/Libraries/LibIPC/ClientConnection.h b/Userland/Libraries/LibIPC/ClientConnection.h index 6d507e79ac..77eea2548a 100644 --- a/Userland/Libraries/LibIPC/ClientConnection.h +++ b/Userland/Libraries/LibIPC/ClientConnection.h @@ -17,10 +17,13 @@ NonnullRefPtr<T> new_client_connection(Args&&... args) } template<typename ClientEndpoint, typename ServerEndpoint> -class ClientConnection : public Connection<ServerEndpoint, ClientEndpoint> { +class ClientConnection : public Connection<ServerEndpoint, ClientEndpoint>, public ServerEndpoint::Stub { public: - ClientConnection(ServerEndpoint& endpoint, NonnullRefPtr<Core::LocalSocket> socket, int client_id) - : IPC::Connection<ServerEndpoint, ClientEndpoint>(endpoint, move(socket)) + using ClientProxy = typename ClientEndpoint::Proxy; + using ServerStub = typename ServerEndpoint::Stub; + + ClientConnection(ServerStub& stub, NonnullRefPtr<Core::LocalSocket> socket, int client_id) + : IPC::Connection<ServerEndpoint, ClientEndpoint>(stub, move(socket)) , m_client_id(client_id) { VERIFY(this->socket().is_connected()); diff --git a/Userland/Libraries/LibIPC/Connection.h b/Userland/Libraries/LibIPC/Connection.h index 260919ad7b..a859037ca8 100644 --- a/Userland/Libraries/LibIPC/Connection.h +++ b/Userland/Libraries/LibIPC/Connection.h @@ -28,8 +28,11 @@ namespace IPC { template<typename LocalEndpoint, typename PeerEndpoint> class Connection : public Core::Object { public: - Connection(LocalEndpoint& local_endpoint, NonnullRefPtr<Core::LocalSocket> socket) - : m_local_endpoint(local_endpoint) + using LocalStub = typename LocalEndpoint::Stub; + using PeerProxy = typename PeerEndpoint::Proxy; + + Connection(LocalStub& local_stub, NonnullRefPtr<Core::LocalSocket> socket) + : m_local_stub(local_stub) , m_socket(move(socket)) , m_notifier(Core::Notifier::construct(m_socket->fd(), Core::Notifier::Read, this)) { @@ -248,13 +251,13 @@ protected: auto messages = move(m_unprocessed_messages); for (auto& message : messages) { if (message.endpoint_magic() == LocalEndpoint::static_magic()) - if (auto response = m_local_endpoint.handle(message)) + if (auto response = m_local_stub.handle(message)) post_message(*response); } } protected: - LocalEndpoint& m_local_endpoint; + LocalStub& m_local_stub; NonnullRefPtr<Core::LocalSocket> m_socket; RefPtr<Core::Timer> m_responsiveness_timer; diff --git a/Userland/Libraries/LibIPC/ServerConnection.h b/Userland/Libraries/LibIPC/ServerConnection.h index 20010a9f82..bd6cc0dbcd 100644 --- a/Userland/Libraries/LibIPC/ServerConnection.h +++ b/Userland/Libraries/LibIPC/ServerConnection.h @@ -11,9 +11,12 @@ namespace IPC { template<typename ClientEndpoint, typename ServerEndpoint> -class ServerConnection : public IPC::Connection<ClientEndpoint, ServerEndpoint> { +class ServerConnection : public IPC::Connection<ClientEndpoint, ServerEndpoint>, public ClientEndpoint::Stub { public: - ServerConnection(ClientEndpoint& local_endpoint, const StringView& address) + using ClientStub = typename ClientEndpoint::Stub; + using ServerProxy = typename ServerEndpoint::Proxy; + + ServerConnection(ClientStub& local_endpoint, const StringView& address) : Connection<ClientEndpoint, ServerEndpoint>(local_endpoint, Core::LocalSocket::construct()) { // We want to rate-limit our clients diff --git a/Userland/Libraries/LibIPC/Endpoint.cpp b/Userland/Libraries/LibIPC/Stub.cpp index 77976eee8e..4eca25a720 100644 --- a/Userland/Libraries/LibIPC/Endpoint.cpp +++ b/Userland/Libraries/LibIPC/Stub.cpp @@ -4,15 +4,15 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include <LibIPC/Endpoint.h> +#include <LibIPC/Stub.h> namespace IPC { -Endpoint::Endpoint() +Stub::Stub() { } -Endpoint::~Endpoint() +Stub::~Stub() { } diff --git a/Userland/Libraries/LibIPC/Endpoint.h b/Userland/Libraries/LibIPC/Stub.h index 74184c8a80..a4ac5aec21 100644 --- a/Userland/Libraries/LibIPC/Endpoint.h +++ b/Userland/Libraries/LibIPC/Stub.h @@ -18,16 +18,16 @@ namespace IPC { class Message; class MessageBuffer; -class Endpoint { +class Stub { public: - virtual ~Endpoint(); + virtual ~Stub(); virtual u32 magic() const = 0; virtual String name() const = 0; virtual OwnPtr<MessageBuffer> handle(const Message&) = 0; protected: - Endpoint(); + Stub(); private: String m_name; diff --git a/Userland/Services/AudioServer/ClientConnection.h b/Userland/Services/AudioServer/ClientConnection.h index 5d79155e25..1a66f4bf70 100644 --- a/Userland/Services/AudioServer/ClientConnection.h +++ b/Userland/Services/AudioServer/ClientConnection.h @@ -21,7 +21,7 @@ class BufferQueue; class Mixer; class ClientConnection final : public IPC::ClientConnection<AudioClientEndpoint, AudioServerEndpoint> - , public AudioServerEndpoint { +{ C_OBJECT(ClientConnection) public: explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id, Mixer& mixer); diff --git a/Userland/Services/Clipboard/ClientConnection.h b/Userland/Services/Clipboard/ClientConnection.h index 70d33da56d..1bf0055b2d 100644 --- a/Userland/Services/Clipboard/ClientConnection.h +++ b/Userland/Services/Clipboard/ClientConnection.h @@ -15,8 +15,7 @@ namespace Clipboard { class ClientConnection final : public IPC::ClientConnection<ClipboardClientEndpoint, ClipboardServerEndpoint> - , public ClipboardServerEndpoint { - +{ C_OBJECT(ClientConnection); public: diff --git a/Userland/Services/ImageDecoder/ClientConnection.h b/Userland/Services/ImageDecoder/ClientConnection.h index 950b799bac..89d6ef856d 100644 --- a/Userland/Services/ImageDecoder/ClientConnection.h +++ b/Userland/Services/ImageDecoder/ClientConnection.h @@ -17,7 +17,7 @@ namespace ImageDecoder { class ClientConnection final : public IPC::ClientConnection<ImageDecoderClientEndpoint, ImageDecoderServerEndpoint> - , public ImageDecoderServerEndpoint { +{ C_OBJECT(ClientConnection); public: diff --git a/Userland/Services/LaunchServer/ClientConnection.h b/Userland/Services/LaunchServer/ClientConnection.h index e14c2a61b9..c4e7c6ad57 100644 --- a/Userland/Services/LaunchServer/ClientConnection.h +++ b/Userland/Services/LaunchServer/ClientConnection.h @@ -13,7 +13,7 @@ namespace LaunchServer { class ClientConnection final : public IPC::ClientConnection<LaunchClientEndpoint, LaunchServerEndpoint> - , public LaunchServerEndpoint { +{ C_OBJECT(ClientConnection) public: ~ClientConnection() override; diff --git a/Userland/Services/LookupServer/ClientConnection.h b/Userland/Services/LookupServer/ClientConnection.h index 3289e36be0..50f7316c50 100644 --- a/Userland/Services/LookupServer/ClientConnection.h +++ b/Userland/Services/LookupServer/ClientConnection.h @@ -15,8 +15,7 @@ namespace LookupServer { class ClientConnection final : public IPC::ClientConnection<LookupClientEndpoint, LookupServerEndpoint> - , public LookupServerEndpoint { - +{ C_OBJECT(ClientConnection); public: diff --git a/Userland/Services/NotificationServer/ClientConnection.h b/Userland/Services/NotificationServer/ClientConnection.h index faf2090737..2abe843cce 100644 --- a/Userland/Services/NotificationServer/ClientConnection.h +++ b/Userland/Services/NotificationServer/ClientConnection.h @@ -13,7 +13,7 @@ namespace NotificationServer { class ClientConnection final : public IPC::ClientConnection<NotificationClientEndpoint, NotificationServerEndpoint> - , public NotificationServerEndpoint { +{ C_OBJECT(ClientConnection) public: ~ClientConnection() override; diff --git a/Userland/Services/RequestServer/ClientConnection.h b/Userland/Services/RequestServer/ClientConnection.h index 877c92e628..6bfcd6e172 100644 --- a/Userland/Services/RequestServer/ClientConnection.h +++ b/Userland/Services/RequestServer/ClientConnection.h @@ -16,7 +16,7 @@ namespace RequestServer { class ClientConnection final : public IPC::ClientConnection<RequestClientEndpoint, RequestServerEndpoint> - , public RequestServerEndpoint { +{ C_OBJECT(ClientConnection); public: diff --git a/Userland/Services/SymbolServer/ClientConnection.h b/Userland/Services/SymbolServer/ClientConnection.h index 900aaf3301..ea6132983c 100644 --- a/Userland/Services/SymbolServer/ClientConnection.h +++ b/Userland/Services/SymbolServer/ClientConnection.h @@ -17,7 +17,7 @@ namespace SymbolServer { class ClientConnection final : public IPC::ClientConnection<SymbolClientEndpoint, SymbolServerEndpoint> - , public SymbolServerEndpoint { +{ C_OBJECT(ClientConnection); public: diff --git a/Userland/Services/WebContent/ClientConnection.h b/Userland/Services/WebContent/ClientConnection.h index f9cf68fb2c..cfc0ea691d 100644 --- a/Userland/Services/WebContent/ClientConnection.h +++ b/Userland/Services/WebContent/ClientConnection.h @@ -20,7 +20,7 @@ namespace WebContent { class ClientConnection final : public IPC::ClientConnection<WebContentClientEndpoint, WebContentServerEndpoint> - , public WebContentServerEndpoint { +{ C_OBJECT(ClientConnection); public: diff --git a/Userland/Services/WebSocket/ClientConnection.h b/Userland/Services/WebSocket/ClientConnection.h index e9b6f327ac..65720e2f99 100644 --- a/Userland/Services/WebSocket/ClientConnection.h +++ b/Userland/Services/WebSocket/ClientConnection.h @@ -16,7 +16,7 @@ namespace WebSocket { class ClientConnection final : public IPC::ClientConnection<WebSocketClientEndpoint, WebSocketServerEndpoint> - , public WebSocketServerEndpoint { +{ C_OBJECT(ClientConnection); public: diff --git a/Userland/Services/WindowServer/ClientConnection.h b/Userland/Services/WindowServer/ClientConnection.h index d04cf2f309..3d8a32a2a2 100644 --- a/Userland/Services/WindowServer/ClientConnection.h +++ b/Userland/Services/WindowServer/ClientConnection.h @@ -29,7 +29,7 @@ class WMClientConnection; class ClientConnection final : public IPC::ClientConnection<WindowClientEndpoint, WindowServerEndpoint> - , public WindowServerEndpoint { +{ C_OBJECT(ClientConnection) public: ~ClientConnection() override; diff --git a/Userland/Services/WindowServer/WMClientConnection.h b/Userland/Services/WindowServer/WMClientConnection.h index 561acd6f77..1e7ff649fc 100644 --- a/Userland/Services/WindowServer/WMClientConnection.h +++ b/Userland/Services/WindowServer/WMClientConnection.h @@ -16,7 +16,7 @@ namespace WindowServer { class WMClientConnection final : public IPC::ClientConnection<WindowManagerClientEndpoint, WindowManagerServerEndpoint> - , public WindowManagerServerEndpoint { +{ C_OBJECT(WMClientConnection) public: |