summaryrefslogtreecommitdiff
path: root/src/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cc')
-rw-r--r--src/main.cc127
1 files changed, 118 insertions, 9 deletions
diff --git a/src/main.cc b/src/main.cc
index 6883f30..494c49c 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -3,9 +3,11 @@
#include "cfg.hh"
#include "config.h"
#include "http.hh"
+#include "json.hh"
#include "logger.hh"
#include "looper.hh"
#include "signals.hh"
+#include "websocket.hh"
#include <cerrno>
#include <cstdint>
@@ -16,6 +18,7 @@
#include <memory>
#include <optional>
#include <string>
+#include <string_view>
#include <unistd.h>
#include <utility>
#include <vector>
@@ -26,9 +29,38 @@
namespace {
+class Api {
+ public:
+ virtual ~Api() = default;
+
+ [[nodiscard]]
+ virtual bt::Adapter* adapter() const = 0;
+
+ protected:
+ Api() = default;
+};
+
+const std::string_view kSignalUpdateAdapter("controller/update");
+
+class Signaler {
+ public:
+ virtual ~Signaler() = default;
+
+ virtual void send(std::string_view signal) = 0;
+ virtual std::unique_ptr<http::Response> handle(
+ http::Request const& request) = 0;
+
+ protected:
+ Signaler() = default;
+};
+
class HttpServerDelegate : public http::Server::Delegate {
public:
- HttpServerDelegate() = default;
+ HttpServerDelegate(Api& api, Signaler& signaler)
+ : api_(api),
+ signaler_(signaler),
+ json_writer_(json::writer(json_tmp_)),
+ json_mimetype_(http::MimeType::create("application", "json")) {}
std::unique_ptr<http::Response> handle(
http::Request const& request) override {
@@ -36,21 +68,66 @@ class HttpServerDelegate : public http::Server::Delegate {
return http::Response::status(http::StatusCode::kMethodNotAllowed);
}
- if (request.path() == "/api/v1/status") {
- return http::Response::content(
- R"({ status: "OK" })",
- *http::MimeType::create("application", "json"));
+ if (request.path().starts_with("/api/v1/")) {
+ auto path = request.path().substr(8);
+ if (path == "status") {
+ json_writer_->clear();
+ json_writer_->start_object();
+ json_writer_->key("status");
+ json_writer_->value("OK");
+ json_writer_->end_object();
+ return http::Response::content(json_tmp_, *json_mimetype_);
+ }
+
+ if (path == "controller") {
+ auto* adapter = api_.adapter();
+ json_writer_->clear();
+ json_writer_->start_object();
+ json_writer_->key("name");
+ json_writer_->value(adapter ? adapter->name() : "unknown");
+ json_writer_->key("pairable");
+ json_writer_->value(adapter ? adapter->pairable() : false);
+ json_writer_->key("pairing");
+ json_writer_->value(adapter ? adapter->pairing() : false);
+ json_writer_->end_object();
+
+ return http::Response::content(json_tmp_, *json_mimetype_);
+ }
+
+ if (path == "events") {
+ auto resp = signaler_.handle(request);
+ if (resp)
+ return resp;
+ return http::Response::status(http::StatusCode::kBadRequest);
+ }
}
return http::Response::status(http::StatusCode::kNotFound);
}
+
+ private:
+ Api& api_;
+ Signaler& signaler_;
+ std::unique_ptr<json::Writer> json_writer_;
+ std::string json_tmp_;
+ std::unique_ptr<http::MimeType> json_mimetype_;
};
-class BluetoothManagerDelegate : public bt::Manager::Delegate {
+class BluetoothManagerDelegate : public bt::Manager::Delegate, public Api {
public:
- explicit BluetoothManagerDelegate(logger::Logger& logger) : logger_(logger) {}
+ BluetoothManagerDelegate(logger::Logger& logger, Signaler& signaler)
+ : logger_(logger), signaler_(signaler) {}
+
+ [[nodiscard]]
+ bt::Adapter* adapter() const override {
+ return adapter_;
+ }
void new_adapter(bt::Adapter* adapter) override {
+ adapter_ = adapter;
+
+ signaler_.send(kSignalUpdateAdapter);
+
if (adapter) {
logger_.info(std::format("New adapter: {} [{}]", adapter->name(),
adapter->address()));
@@ -59,6 +136,11 @@ class BluetoothManagerDelegate : public bt::Manager::Delegate {
}
}
+ void updated_adapter(bt::Adapter& adapter) override {
+ if (adapter_ == &adapter)
+ signaler_.send(kSignalUpdateAdapter);
+ }
+
void added_device(bt::Device& device) override {
logger_.info(
std::format("New device: {} [{}]", device.name(), device.address()));
@@ -117,15 +199,42 @@ class BluetoothManagerDelegate : public bt::Manager::Delegate {
private:
logger::Logger& logger_;
+ Signaler& signaler_;
+ bt::Adapter* adapter_{nullptr};
+};
+
+class SignalerImpl : public Signaler, ws::Server::Delegate {
+ public:
+ SignalerImpl(logger::Logger& logger, cfg::Config const& cfg,
+ looper::Looper& looper)
+ : server_(ws::create_server(logger, cfg, looper, *this)) {}
+
+ void send(std::string_view signal) override {
+ server_->send_text_to_all(signal);
+ }
+
+ std::unique_ptr<http::Response> handle(
+ http::Request const& request) override {
+ return server_->handle(request);
+ }
+
+ std::unique_ptr<ws::Message> handle(ws::Message const& /* msg */) override {
+ // Ignore anything sent by clients
+ return nullptr;
+ }
+
+ private:
+ std::unique_ptr<ws::Server> server_;
};
bool run(logger::Logger& logger, cfg::Config const& cfg,
std::unique_ptr<http::OpenPort> port) {
auto looper = looper::create();
- HttpServerDelegate http_delegate;
+ SignalerImpl signaler(logger, cfg, *looper);
+ BluetoothManagerDelegate bt_delegate(logger, signaler);
+ HttpServerDelegate http_delegate(bt_delegate, signaler);
auto server =
http::create_server(logger, cfg, *looper, std::move(port), http_delegate);
- BluetoothManagerDelegate bt_delegate(logger);
auto manager = bt::create_manager(logger, cfg, *looper, bt_delegate);
auto sigint_handler = signals::Handler::create(
*looper, signals::Signal::INT, [&looper, &logger]() {