Skip to content

Commit

Permalink
ipc: make client interface really an interface (#2130)
Browse files Browse the repository at this point in the history
This allows to fully replace the IPC socket with an alternative
implementation (dbus, json-rpc, whatever).
  • Loading branch information
ammen99 committed Mar 13, 2024
1 parent 84cbdc8 commit aa6d61f
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 54 deletions.
12 changes: 5 additions & 7 deletions plugins/ipc/demo-ipc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
#include <set>

#include "ipc-helpers.hpp"
#include "ipc.hpp"
#include "ipc-method-repository.hpp"
#include "wayfire/core.hpp"
#include "wayfire/object.hpp"
#include "wayfire/plugins/common/shared-core-data.hpp"
#include "wayfire/signal-definitions.hpp"
#include "wayfire/signal-provider.hpp"
Expand All @@ -23,7 +21,7 @@ class wayfire_demo_ipc : public wf::plugin_interface_t
method_repository->register_method("demo-ipc/view-info", get_view_info);
method_repository->register_method("demo-ipc/output-info", get_output_info);
method_repository->register_method("demo-ipc/view-set-geometry", set_view_geometry);
ipc_server->connect(&on_client_disconnected);
method_repository->connect(&on_client_disconnected);
wf::get_core().connect(&on_view_mapped);
}

Expand All @@ -35,9 +33,10 @@ class wayfire_demo_ipc : public wf::plugin_interface_t
method_repository->unregister_method("demo-ipc/view-set-geometry");
}

wf::ipc::method_callback on_client_watch = [=] (nlohmann::json data)
wf::ipc::method_callback_full on_client_watch =
[=] (nlohmann::json data, wf::ipc::client_interface_t *client)
{
clients.insert(ipc_server->get_current_request_client());
clients.insert(client);
return wf::ipc::json_ok();
};

Expand Down Expand Up @@ -99,8 +98,7 @@ class wayfire_demo_ipc : public wf::plugin_interface_t

private:
wf::shared_data::ref_ptr_t<wf::ipc::method_repository_t> method_repository;
wf::shared_data::ref_ptr_t<wf::ipc::server_t> ipc_server;
std::set<wf::ipc::client_t*> clients;
std::set<wf::ipc::client_interface_t*> clients;

wf::signal::connection_t<wf::ipc::client_disconnected_signal> on_client_disconnected =
[=] (wf::ipc::client_disconnected_signal *ev)
Expand Down
47 changes: 42 additions & 5 deletions plugins/ipc/ipc-method-repository.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,71 @@
#include <nlohmann/json.hpp>
#include <functional>
#include <map>
#include "wayfire/signal-provider.hpp"

namespace wf
{
namespace ipc
{
/**
* A client_interface_t represents a client which has connected to the IPC socket.
* It can be used by plugins to send back data to a specific client.
*/
class client_interface_t
{
public:
virtual void send_json(nlohmann::json json) = 0;
};

/**
* A signal emitted on the ipc method repository when a client disconnects.
*/
struct client_disconnected_signal
{
client_interface_t *client;
};

/**
* An IPC method has a name and a callback. The callback is a simple function which takes a json object which
* contains the method's parameters and returns the result of the operation.
*/
using method_callback = std::function<nlohmann::json(nlohmann::json)>;

/**
* Same as @method_callback, but also supports getting information about the connected ipc client.
*/
using method_callback_full = std::function<nlohmann::json(nlohmann::json, client_interface_t*)>;

/**
* The IPC method repository keeps track of all registered IPC methods. It can be used even without the IPC
* plugin itself, as it facilitates inter-plugin calls similarly to signals.
*
* The method_repository_t is a singleton and is accessed by creating a shared_data::ref_ptr_t to it.
*/
class method_repository_t
class method_repository_t : public wf::signal::provider_t
{
public:
/**
* Register a new method to the method repository. If the method already exists, the old handler will be
* overwritten.
*/
void register_method(std::string method, method_callback handler)
void register_method(std::string method, method_callback_full handler)
{
this->methods[method] = handler;
}

/**
* Register a new method to the method repository. If the method already exists, the old handler will be
* overwritten.
*/
void register_method(std::string method, method_callback handler)
{
this->methods[method] = [handler] (const nlohmann::json& data, client_interface_t*)
{
return handler(data);
};
}

/**
* Remove the last registered handler for the given method.
*/
Expand All @@ -44,11 +80,12 @@ class method_repository_t
* Call an IPC method with the given name and given parameters.
* If the method was not registered, a JSON object containing an error will be returned.
*/
nlohmann::json call_method(std::string method, nlohmann::json data)
nlohmann::json call_method(std::string method, nlohmann::json data,
client_interface_t *client = nullptr)
{
if (this->methods.count(method))
{
return this->methods[method](std::move(data));
return this->methods[method](std::move(data), client);
}

return {
Expand All @@ -72,7 +109,7 @@ class method_repository_t
}

private:
std::map<std::string, method_callback> methods;
std::map<std::string, method_callback_full> methods;
};

// A few helper definitions for IPC method implementations.
Expand Down
6 changes: 2 additions & 4 deletions plugins/ipc/ipc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ void wf::ipc::server_t::client_disappeared(client_t *client)

client_disconnected_signal ev;
ev.client = client;
this->emit(&ev);
method_repository->emit(&ev);

auto it = std::remove_if(clients.begin(), clients.end(),
[&] (const auto& cl) { return cl.get() == client; });
Expand All @@ -133,9 +133,7 @@ void wf::ipc::server_t::client_disappeared(client_t *client)
void wf::ipc::server_t::handle_incoming_message(
client_t *client, nlohmann::json message)
{
this->current_client = client;
client->send_json(method_repository->call_method(message["method"], message["data"]));
this->current_client = nullptr;
client->send_json(method_repository->call_method(message["method"], message["data"], client));
}

/* --------------------------- Per-client code ------------------------------*/
Expand Down
27 changes: 3 additions & 24 deletions plugins/ipc/ipc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
#include <nlohmann/json.hpp>
#include <sys/un.h>
#include <wayfire/object.hpp>
#include <variant>
#include <wayland-server.h>
#include <wayfire/plugins/common/shared-core-data.hpp>
#include "ipc-method-repository.hpp"
#include "wayfire/signal-provider.hpp"

namespace wf
{
Expand All @@ -17,12 +15,12 @@ namespace ipc
* Represents a single connected client to the IPC socket.
*/
class server_t;
class client_t
class client_t : public client_interface_t
{
public:
client_t(server_t *server, int client_fd);
~client_t();
void send_json(nlohmann::json json);
void send_json(nlohmann::json json) override;

private:
int fd;
Expand All @@ -38,40 +36,21 @@ class client_t
void handle_fd_incoming(uint32_t);
};

/**
* A signal emitted on the ipc server when a client disconnects.
*/
struct client_disconnected_signal
{
client_t *client;
};

/**
* The IPC server is a singleton object accessed via shared_data::ref_ptr_t.
* It represents the IPC socket used for communication with clients.
*/
class server_t : public wf::signal::provider_t
class server_t
{
public:
server_t();
void init(std::string socket_path);
~server_t();

/**
* While a method call is being executed, this function may be called to determine the client which
* called it.
*/
client_t *get_current_request_client()
{
return current_client;
}

private:
friend class client_t;
wf::shared_data::ref_ptr_t<wf::ipc::method_repository_t> method_repository;

// Valid only during a method call!
client_t *current_client = nullptr;
void handle_incoming_message(client_t *client, nlohmann::json message);

void client_disappeared(client_t *client);
Expand Down
2 changes: 1 addition & 1 deletion plugins/ipc/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ demoipc = shared_module('demo-ipc',
install: true,
install_dir: conf_data.get('PLUGIN_PATH'))

install_headers(['ipc-method-repository.hpp', 'ipc.hpp', 'ipc-helpers.hpp', 'ipc-activator.hpp'], subdir: 'wayfire/plugins/ipc')
install_headers(['ipc-method-repository.hpp', 'ipc-helpers.hpp', 'ipc-activator.hpp'], subdir: 'wayfire/plugins/ipc')
6 changes: 1 addition & 5 deletions plugins/ipc/stipc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,17 @@
#include "wayfire/plugin.hpp"
#include "wayfire/plugins/common/shared-core-data.hpp"
#include "wayfire/toplevel-view.hpp"
#include "wayfire/unstable/wlr-surface-node.hpp"
#include "wayfire/util.hpp"
#include "wayfire/view-helpers.hpp"
#include <wayfire/view.hpp>
#include <wayfire/output.hpp>
#include <wayfire/workspace-set.hpp>
#include <wayfire/output-layout.hpp>
#include <wayfire/txn/transaction-manager.hpp>
#include "src/view/view-impl.hpp"
#include <variant>

#define WAYFIRE_PLUGIN
#include <wayfire/debug.hpp>

#include "ipc.hpp"
#include "ipc-helpers.hpp"
#include <wayfire/touch/touch.hpp>

extern "C" {
Expand Down
13 changes: 5 additions & 8 deletions plugins/single_plugins/ipc-rules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
#include <set>

#include "plugins/ipc/ipc-helpers.hpp"
#include "plugins/ipc/ipc.hpp"
#include "plugins/ipc/ipc-method-repository.hpp"
#include "wayfire/core.hpp"
#include "wayfire/object.hpp"
#include "wayfire/plugins/common/util.hpp"
#include "wayfire/unstable/wlr-surface-node.hpp"
#include "wayfire/plugins/common/shared-core-data.hpp"
Expand All @@ -20,7 +18,6 @@
#include "wayfire/view-helpers.hpp"
#include "wayfire/window-manager.hpp"
#include "wayfire/workarea.hpp"
#include "wayfire/workspace-set.hpp"
#include "config.h"
#include <wayfire/nonstd/wlroots-full.hpp>

Expand Down Expand Up @@ -141,7 +138,7 @@ class ipc_rules_t : public wf::plugin_interface_t, public wf::per_output_tracker
method_repository->register_method("window-rules/configure-view", configure_view);
method_repository->register_method("window-rules/focus-view", focus_view);
method_repository->register_method("window-rules/get-focused-view", get_focused_view);
ipc_server->connect(&on_client_disconnected);
method_repository->connect(&on_client_disconnected);
wf::get_core().connect(&on_view_mapped);
wf::get_core().connect(&on_kbfocus_changed);
init_output_tracking();
Expand Down Expand Up @@ -346,14 +343,14 @@ class ipc_rules_t : public wf::plugin_interface_t, public wf::per_output_tracker

private:
wf::shared_data::ref_ptr_t<wf::ipc::method_repository_t> method_repository;
wf::shared_data::ref_ptr_t<wf::ipc::server_t> ipc_server;

// Track a list of clients which have requested watch
std::set<wf::ipc::client_t*> clients;
std::set<wf::ipc::client_interface_t*> clients;

wf::ipc::method_callback on_client_watch = [=] (nlohmann::json data)
wf::ipc::method_callback_full on_client_watch =
[=] (nlohmann::json data, wf::ipc::client_interface_t *client)
{
clients.insert(ipc_server->get_current_request_client());
clients.insert(client);
return wf::ipc::json_ok();
};

Expand Down

0 comments on commit aa6d61f

Please sign in to comment.