Skip to content

Commit

Permalink
ipc: make client interface really an interface
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 Feb 9, 2024
1 parent d94fab8 commit 9b83751
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 9b83751

Please sign in to comment.