Skip to content

Commit

Permalink
feat: implemented keyboard REST events
Browse files Browse the repository at this point in the history
  • Loading branch information
ABeltramo committed Apr 17, 2024
1 parent e4d4c9e commit d6eeb34
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 2 deletions.
22 changes: 20 additions & 2 deletions src/server/server/rest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ static void handle_error(httplib::Response &res, const std::string &message) {
}

template <typename T>
static bool
handle_device(inputtino::Result<T> &result, httplib::Response &response, LocalDevice &device) {
static bool handle_device(inputtino::Result<T> &result, httplib::Response &response, LocalDevice &device) {
if (!result) {
handle_error(response, result.getErrorMessage());
return false;
Expand Down Expand Up @@ -191,6 +190,25 @@ std::unique_ptr<httplib::Server> setup_rest_server(std::shared_ptr<immer::atom<S
res.set_content(json{{"success", true}}.dump(), "application/json");
});

/* Keyboard handlers */
svr->Post("/api/v1.0/devices/keyboard/:id/press", [state](const httplib::Request &req, httplib::Response &res) {
std::size_t id = std::stoul(req.path_params.at("id"));
auto payload = json::parse(req.body);
auto device = state->load()->devices.at(id);
auto keyboard = std::get<std::shared_ptr<inputtino::Keyboard>>(device->device);
keyboard->press(payload.at("key"));
res.set_content(json{{"success", true}}.dump(), "application/json");
});

svr->Post("/api/v1.0/devices/keyboard/:id/release", [state](const httplib::Request &req, httplib::Response &res) {
std::size_t id = std::stoul(req.path_params.at("id"));
auto payload = json::parse(req.body);
auto device = state->load()->devices.at(id);
auto keyboard = std::get<std::shared_ptr<inputtino::Keyboard>>(device->device);
keyboard->release(payload.at("key"));
res.set_content(json{{"success", true}}.dump(), "application/json");
});

/* Default error handling */
svr->set_exception_handler([](const auto &req, auto &res, std::exception_ptr ep) {
std::string error_msg = "Internal server error";
Expand Down
52 changes: 52 additions & 0 deletions tests/testServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,58 @@ TEST_CASE_METHOD(HTTPServerFixture, "Test REST server", "[server]") {
}
}

{ // Test keyboard
// Test POST /devices/add (keyboard)
auto res = client.Post("/api/v1.0/devices/add", json{{"type", "KEYBOARD"}}.dump(), "application/json");
REQUIRE(res);
REQUIRE(res->status == 200);
auto new_device = json::parse(res->body);
std::string device_id = new_device["device_id"];
REQUIRE_THAT(new_device["client_id"], Equals("127.0.0.1"));
REQUIRE(new_device["device_nodes"].size() == 1);
REQUIRE_THAT(new_device["type"], Equals("KEYBOARD"));
REQUIRE(!device_id.empty());
// Are the nodes actually created on the host?
for (auto node : new_device["device_nodes"]) {
REQUIRE(std::filesystem::exists(node));
}

// Test that GET /devices lists the new device
res = client.Get("/api/v1.0/devices");
REQUIRE(res);
REQUIRE(res->status == 200);
auto devices = json::parse(res->body);
REQUIRE(devices["devices"].size() == 1);
devices = devices["devices"][0];
REQUIRE_THAT((std::vector<std::string>)devices["device_nodes"],
Equals((std::vector<std::string>)new_device["device_nodes"]));
REQUIRE_THAT(devices["client_id"], Equals(new_device["client_id"]));
REQUIRE_THAT(devices["type"], Equals(new_device["type"]));
REQUIRE(devices["device_id"] == new_device["device_id"]);

// Test that we can move the mouse
res = client.Post("/api/v1.0/devices/keyboard/" + device_id + "/press",
json{{"key", 41}} // Pressing A
.dump(),
"application/json");
REQUIRE(res);
REQUIRE(res->status == 200);
// TODO: check with libinput that the keyboard pressed A

// Test that DELETE /devices/<device_id> removes the device
res = client.Delete("/api/v1.0/devices/" + device_id);
REQUIRE(res);
REQUIRE(res->status == 200);
res = client.Get("/api/v1.0/devices");
REQUIRE(json::parse(res->body)["devices"].empty());
// Are the nodes actually removed from the host?
// This might take a few millis since it's stopping the background thread
std::this_thread::sleep_for(std::chrono::milliseconds(100));
for (auto node : new_device["device_nodes"]) {
REQUIRE(!std::filesystem::exists(node));
}
}

{ // Test POST /devices/add without type
auto res = client.Post("/api/v1.0/devices/add", "{}", "application/json");
REQUIRE(res);
Expand Down

0 comments on commit d6eeb34

Please sign in to comment.