2#include <ossia/network/context.hpp>
3#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
4#include <ossia/detail/variant.hpp>
5#include <ossia/network/sockets/configuration.hpp>
6#include <ossia/network/sockets/line_framing.hpp>
7#include <ossia/network/sockets/no_framing.hpp>
8#include <ossia/network/sockets/size_prefix_framing.hpp>
9#include <ossia/network/sockets/slip_framing.hpp>
10#include <ossia/network/sockets/unix_socket.hpp>
12#include <ossia-qt/protocols/utils.hpp>
18#include <nano_observer.hpp>
24class qml_unix_datagram_inbound_socket
26 ,
public Nano::Observer
28 W_OBJECT(qml_unix_datagram_inbound_socket)
32 ossia::net::unix_datagram_socket socket;
33 std::atomic_bool alive{
true};
35 state(
const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx)
41 qml_unix_datagram_inbound_socket() { }
43 ~qml_unix_datagram_inbound_socket()
47 m_state->alive =
false;
52 bool isOpen() const noexcept {
return m_state !=
nullptr; }
54 void open(
const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx)
56 m_state = std::make_shared<state>(conf, ctx);
58 if(onClose.isCallable())
59 m_state->socket.on_close.connect<&qml_unix_datagram_inbound_socket::on_close>(
this);
61 m_state->socket.open();
62 if(onOpen.isCallable())
63 onOpen.call({qjsEngine(
this)->newQObject(
this)});
66 auto self = QPointer{
this};
67 st->socket.receive([st, self](
const char* data, std::size_t sz) {
72 [self, arg = QByteArray(data, sz)] {
75 if(self->onMessage.isCallable())
77 self->onMessage.call({qjsEngine(self.get())->toScriptValue(arg)});
88 if(!m_state->socket.m_socket.is_open())
91 boost::asio::post(st->socket.m_context, [st] {
94 st->socket.m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_both);
99 st->socket.m_socket.close();
100 st->socket.on_close();
107 if(!m_state || !m_state->alive)
109 ossia::qt::run_async(
this, [=,
this] { onClose.call(); }, Qt::AutoConnection);
118 std::shared_ptr<state> m_state;
121class qml_unix_stream_connection
123 ,
public Nano::Observer
125 W_OBJECT(qml_unix_stream_connection)
127 using socket_t = boost::asio::local::stream_protocol::socket;
128 using decoder_type = ossia::slow_variant<
129 ossia::net::no_framing::decoder<socket_t>,
130 ossia::net::slip_decoder<socket_t>,
131 ossia::net::size_prefix_decoder<socket_t>,
132 ossia::net::line_framing_decoder<socket_t>>;
136 boost::asio::io_context& context;
137 ossia::net::unix_stream_listener listener;
138 std::atomic_bool alive{
true};
139 ossia::net::framing framing{ossia::net::framing::none};
140 char line_delimiter[8] = {};
141 decoder_type decoder;
144 ossia::net::unix_stream_listener l, boost::asio::io_context& ctx,
145 ossia::net::framing f = ossia::net::framing::none,
146 const std::string& delim = {})
148 , listener{std::move(l)}
149 , decoder{
ossia::in_place_index<0>, listener.m_socket}
154 auto sz = std::min(delim.size(), (
size_t)7);
155 std::copy_n(delim.begin(), sz, line_delimiter);
160 case ossia::net::framing::none:
162 case ossia::net::framing::slip:
163 decoder.template emplace<1>(listener.m_socket);
165 case ossia::net::framing::size_prefix:
166 decoder.template emplace<2>(listener.m_socket);
168 case ossia::net::framing::line_delimiter:
169 decoder.template emplace<3>(listener.m_socket);
171 auto& dec = ossia::get<3>(decoder);
172 std::copy_n(line_delimiter, 8, dec.delimiter);
178 void write_encoded(
const char* data, std::size_t sz)
183 case ossia::net::framing::none:
184 listener.write(boost::asio::const_buffer(data, sz));
186 case ossia::net::framing::slip: {
187 ossia::net::slip_encoder<socket_t> enc{listener.m_socket};
191 case ossia::net::framing::size_prefix: {
192 ossia::net::size_prefix_encoder<socket_t> enc{listener.m_socket};
196 case ossia::net::framing::line_delimiter: {
197 ossia::net::line_framing_encoder<socket_t> enc{listener.m_socket};
198 std::copy_n(line_delimiter, 8, enc.delimiter);
206 struct receive_callback
208 std::shared_ptr<state> st;
209 QPointer<qml_unix_stream_connection> self;
211 void operator()(
const unsigned char* data, std::size_t sz)
const
215 auto buf = QByteArray((
const char*)data, sz);
216 ossia::qt::run_async(
221 if(self->onMessage.isCallable())
223 self->onMessage.call({qjsEngine(self.get())->toScriptValue(buf)});
229 bool validate_stream(boost::system::error_code ec)
const
231 if(ec == boost::asio::error::operation_aborted)
233 if(ec == boost::asio::error::eof)
239 qml_unix_stream_connection(
240 ossia::net::unix_stream_listener listener, boost::asio::io_context& ctx,
241 ossia::net::framing f = ossia::net::framing::none,
242 const std::string& delim = {})
243 : m_state{std::make_shared<state>(std::move(listener), ctx, f, delim)}
247 ~qml_unix_stream_connection()
251 m_state->alive =
false;
256 bool isOpen() const noexcept {
return m_state && m_state->alive; }
258 inline boost::asio::io_context& context() noexcept {
return m_state->context; }
260 void write(QByteArray buffer)
265 boost::asio::dispatch(st->context, [st, buffer] {
267 st->write_encoded(buffer.data(), buffer.size());
272 void close(QByteArray)
277 boost::asio::dispatch(st->context, [st] { st->listener.close(); });
284 auto self = QPointer{
this};
286 [cb = receive_callback{st, self}](
auto& decoder)
mutable {
287 decoder.receive(std::move(cb));
295 std::shared_ptr<state> m_state;
298class qml_unix_stream_inbound_socket
300 ,
public Nano::Observer
302 W_OBJECT(qml_unix_stream_inbound_socket)
306 ossia::net::unix_stream_server server;
307 std::atomic_bool alive{
true};
308 ossia::net::framing framing{ossia::net::framing::none};
309 std::string framing_delimiter;
312 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
313 ossia::net::framing f = ossia::net::framing::none,
314 std::string delim = {})
317 , framing_delimiter{std::move(delim)}
322 qml_unix_stream_inbound_socket() { }
324 ~qml_unix_stream_inbound_socket()
328 m_state->alive =
false;
333 bool isOpen() const noexcept {
return m_state !=
nullptr; }
336 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
337 ossia::net::framing f = ossia::net::framing::none,
338 const std::string& delim = {})
340 m_state = std::make_shared<state>(conf, ctx, f, delim);
342 accept_impl(m_state, QPointer{
this});
343 if(onOpen.isCallable())
344 onOpen.call({qjsEngine(
this)->newQObject(
this)});
351 m_state->server.m_acceptor.close();
352 if(onClose.isCallable())
359 if(!m_state || !m_state->alive)
361 ossia::qt::run_async(
this, [=,
this] { onClose.call(); }, Qt::AutoConnection);
367 QJSValue onConnection;
370 static void accept_impl(
371 std::shared_ptr<state> st, QPointer<qml_unix_stream_inbound_socket> self)
373 st->server.m_acceptor.async_accept(
375 boost::system::error_code ec,
376 ossia::net::unix_stream_server::proto::socket socket) {
381 ossia::qt::run_async(
383 [self, st, socket = std::move(socket)]()
mutable {
386 auto conn = new qml_unix_stream_connection{
387 ossia::net::unix_stream_listener{std::move(socket)},
388 st->server.m_context, st->framing, st->framing_delimiter};
389 conn->onMessage = self->onConnection;
390 conn->startReceive();
392 if(self->onConnection.isCallable())
394 self->onConnection.call(
395 {qjsEngine(self.get())->newQObject(
static_cast<QObject*
>(conn))});
399 accept_impl(st, self);
404 std::shared_ptr<state> m_state;
Definition qml_device.cpp:43