diff --git a/backend/deploy/mosquitto.local.conf b/backend/deploy/mosquitto.local.conf new file mode 100644 index 0000000..e57745d --- /dev/null +++ b/backend/deploy/mosquitto.local.conf @@ -0,0 +1,4 @@ +listener 1883 +allow_anonymous true +password_file mqtt_users + diff --git a/backend/src/event_loop.cpp b/backend/src/event_loop.cpp index 2909ba9..fa1dbd3 100644 --- a/backend/src/event_loop.cpp +++ b/backend/src/event_loop.cpp @@ -1,11 +1,36 @@ #include "event_loop.hpp" #include "errno_shim.hpp" #include "server.hpp" +#include +#include +#include #include #include -#include + +#define CHECK(EXPR) \ + do { \ + if (!(EXPR).has_value()) [[unlikely]] { \ + return std::unexpected((EXPR).error()); \ + } \ + } while (false) namespace mst::event { +auto Event::fd() -> int +{ + switch (this->kind) { + case mst::event::EventKind::Server: { + auto& ref = std::get>(this->data); + return ref->fd(); + break; + } + case mst::event::EventKind::Client: { + auto& ref = std::get>(this->data); + return ref->fd(); + } + default: + std::unreachable(); + } +} auto Manager::start() -> Result { epoll_event events[128] = { }; @@ -16,22 +41,22 @@ auto Manager::start() -> Result } for (int i = 0; i < events_len; ++i) { auto event = (mst::event::Event*)events[i].data.ptr; - switch (event->data.index()) { - case 0: { + switch (event->kind) { + case mst::event::EventKind::Server: { auto& ref = std::get>(event->data); auto res = ref->wake(*this); - if (!res) { - return std::unexpected(res.error()); - } + CHECK(res); break; } - case 1: { + case mst::event::EventKind::Client: { auto& ref = std::get>(event->data); auto res = ref->wake(); - if (!res) { - return std::unexpected(res.error()); + CHECK(res); + auto do_now = res.value(); + if (do_now == Client::lllll::Disconnect) { + CHECK(this->deregister_event(ref->fd())); } break; } @@ -42,6 +67,31 @@ auto Manager::start() -> Result } } +auto Manager::deregister_event(int fd) -> Result +{ + auto poll_event = epoll_event { .events = EPOLLIN, .data = { } }; + if (::epoll_ctl(this->epoll_fd, EPOLL_CTL_DEL, fd, &poll_event) < 0) { + return std::unexpected( + errno_shim("could not remove listener to epoll")); + } + size_t idx = this->events.size(); + for (size_t i = 0; i < this->events.size(); ++i) { + if (this->events[i]->fd() == fd) { + idx = i; + } + } + + if (idx == this->events.size()) { + throw std::runtime_error("contract broken"); + } + + this->events.erase(std::find_if(this->events.begin(), + this->events.end(), + [&](auto& e) { return e->fd() == fd; })); + + return { }; +} + auto Manager::create() -> Result { auto epoll_fd = ::epoll_create1(0); diff --git a/backend/src/event_loop.hpp b/backend/src/event_loop.hpp index 69d1b53..283149b 100644 --- a/backend/src/event_loop.hpp +++ b/backend/src/event_loop.hpp @@ -2,8 +2,10 @@ #include "errno_shim.hpp" #include "result.hpp" #include "server.hpp" +#include #include #include +#include #include #include @@ -11,9 +13,23 @@ namespace mst { class Server; class Client; namespace event { - struct Event { + enum class EventKind { + Server, + Client, + }; + class Event { + public: + Event(std::variant, + std::unique_ptr> data) + : data(std::move(data)) + , kind(data.index() == 0 ? EventKind::Server : EventKind::Client) + { + } + auto fd() -> int; + std::variant, std::unique_ptr> data; + EventKind kind; }; template @@ -41,6 +57,7 @@ namespace event { } return { }; } + auto deregister_event(int fd) -> Result; static auto create() -> Result; private: diff --git a/backend/src/server.cpp b/backend/src/server.cpp index d22336d..1946109 100644 --- a/backend/src/server.cpp +++ b/backend/src/server.cpp @@ -5,7 +5,7 @@ namespace mst { -auto Client::wake() -> Result +auto Client::wake() -> Result { uint8_t buffer[128] = { }; auto x = this->connection.read(buffer, 128); @@ -13,11 +13,14 @@ auto Client::wake() -> Result return std::unexpected(x.error()); } auto bytes_read = x.value(); + if (bytes_read == 0) { + return { Client::lllll::Disconnect }; + } for (size_t i = 0; i < bytes_read; ++i) { std::println("{:c}", buffer[i]); } - return { }; + return { Client::lllll::Ok }; } auto Server::bind( diff --git a/backend/src/server.hpp b/backend/src/server.hpp index 8d79f5d..54af2f7 100644 --- a/backend/src/server.hpp +++ b/backend/src/server.hpp @@ -15,6 +15,10 @@ public: static auto bind( mst::event::Manager& mgr, const std::string& host, uint16_t port) -> Result; + auto fd() -> int + { + return this->listener.fd; + }; private: TcpListener listener; @@ -26,8 +30,17 @@ private: }; class Client { + public: - auto wake() -> Result; + enum class lllll { + Ok, + Disconnect, + }; + auto wake() -> Result; + auto fd() -> int + { + return this->connection.fd; + }; Client(Server&, TcpConnection connection) : connection(connection)