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/cobs_framing.hpp>
7#include <ossia/network/sockets/fixed_length_framing.hpp>
8#include <ossia/network/sockets/line_framing.hpp>
9#include <ossia/network/sockets/no_framing.hpp>
10#include <ossia/network/sockets/size_prefix_framing.hpp>
11#include <ossia/network/sockets/slip_framing.hpp>
12#include <ossia/network/sockets/stx_etx_framing.hpp>
13#include <ossia/network/sockets/unix_socket.hpp>
14#include <ossia/network/sockets/var_size_prefix_framing.hpp>
16#include <ossia-qt/protocols/utils.hpp>
22#include <nano_observer.hpp>
28class qml_unix_datagram_inbound_socket
30 ,
public Nano::Observer
32 W_OBJECT(qml_unix_datagram_inbound_socket)
36 ossia::net::unix_datagram_socket socket;
37 std::atomic_bool alive{
true};
38 ossia::net::encoding enc{ossia::net::encoding::none};
41 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
42 ossia::net::encoding e = ossia::net::encoding::none)
49 qml_unix_datagram_inbound_socket() { }
51 ~qml_unix_datagram_inbound_socket()
55 m_state->alive =
false;
60 bool isOpen() const noexcept {
return m_state !=
nullptr; }
63 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
64 ossia::net::encoding e = ossia::net::encoding::none)
66 m_state = std::make_shared<state>(conf, ctx, e);
68 if(onClose.isCallable())
69 m_state->socket.on_close.connect<&qml_unix_datagram_inbound_socket::on_close>(
this);
71 m_state->socket.open();
72 if(onOpen.isCallable())
73 onOpen.call({qjsEngine(
this)->newQObject(
this)});
76 auto self = QPointer{
this};
77 st->socket.receive([st, self](
const char* data, std::size_t sz) {
82 [self, arg = apply_decoding(st->enc, data, sz)] {
85 if(self->onMessage.isCallable())
87 self->onMessage.call({qjsEngine(self.get())->toScriptValue(arg)});
98 if(!m_state->socket.m_socket.is_open())
101 boost::asio::post(st->socket.m_context, [st] {
104 st->socket.m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_both);
109 st->socket.m_socket.close();
110 st->socket.on_close();
117 if(!m_state || !m_state->alive)
119 ossia::qt::run_async(
this, [=,
this] { onClose.call(); }, Qt::AutoConnection);
128 std::shared_ptr<state> m_state;
131class qml_unix_stream_connection
133 ,
public Nano::Observer
135 W_OBJECT(qml_unix_stream_connection)
137 using socket_t = boost::asio::local::stream_protocol::socket;
138 using decoder_type = ossia::slow_variant<
139 ossia::net::no_framing::decoder<socket_t>,
140 ossia::net::slip_decoder<socket_t>,
141 ossia::net::size_prefix_decoder<socket_t>,
142 ossia::net::line_framing_decoder<socket_t>,
143 ossia::net::cobs_decoder<socket_t>,
144 ossia::net::stx_etx_framing::decoder<socket_t>,
145 ossia::net::size_prefix_1byte_framing::decoder<socket_t>,
146 ossia::net::size_prefix_2byte_be_framing::decoder<socket_t>,
147 ossia::net::size_prefix_2byte_le_framing::decoder<socket_t>,
148 ossia::net::size_prefix_4byte_le_framing::decoder<socket_t>,
149 ossia::net::fixed_length_decoder<socket_t>>;
153 boost::asio::io_context& context;
154 ossia::net::unix_stream_listener listener;
155 std::atomic_bool alive{
true};
156 ossia::net::framing framing{ossia::net::framing::none};
157 ossia::net::encoding enc{ossia::net::encoding::none};
158 char line_delimiter[8] = {};
159 decoder_type decoder;
162 ossia::net::unix_stream_listener l, boost::asio::io_context& ctx,
163 ossia::net::framing f = ossia::net::framing::none,
164 const std::string& delim = {},
165 ossia::net::encoding e = ossia::net::encoding::none)
167 , listener{std::move(l)}
168 , decoder{
ossia::in_place_index<0>, listener.m_socket}
174 auto sz = std::min(delim.size(), (
size_t)7);
175 std::copy_n(delim.begin(), sz, line_delimiter);
180 case ossia::net::framing::none:
182 case ossia::net::framing::slip:
183 decoder.template emplace<1>(listener.m_socket);
185 case ossia::net::framing::size_prefix:
186 decoder.template emplace<2>(listener.m_socket);
188 case ossia::net::framing::line_delimiter:
189 decoder.template emplace<3>(listener.m_socket);
191 auto& dec = ossia::get<3>(decoder);
192 std::copy_n(line_delimiter, 8, dec.delimiter);
195 case ossia::net::framing::cobs:
196 decoder.template emplace<4>(listener.m_socket);
198 case ossia::net::framing::stx_etx:
199 decoder.template emplace<5>(listener.m_socket);
201 case ossia::net::framing::size_prefix_1byte:
202 decoder.template emplace<6>(listener.m_socket);
204 case ossia::net::framing::size_prefix_2byte_be:
205 decoder.template emplace<7>(listener.m_socket);
207 case ossia::net::framing::size_prefix_2byte_le:
208 decoder.template emplace<8>(listener.m_socket);
210 case ossia::net::framing::size_prefix_4byte_le:
211 decoder.template emplace<9>(listener.m_socket);
213 case ossia::net::framing::fixed_length:
214 decoder.template emplace<10>(listener.m_socket);
216 ossia::get<10>(decoder).frame_size = std::stoul(delim);
221 void write_encoded(
const char* data, std::size_t sz)
226 case ossia::net::framing::none:
227 listener.write(boost::asio::const_buffer(data, sz));
229 case ossia::net::framing::slip:
230 ossia::net::slip_encoder<socket_t>{listener.m_socket}.write(data, sz);
232 case ossia::net::framing::size_prefix:
233 ossia::net::size_prefix_encoder<socket_t>{listener.m_socket}.write(data, sz);
235 case ossia::net::framing::line_delimiter: {
236 ossia::net::line_framing_encoder<socket_t> enc{listener.m_socket};
237 std::copy_n(line_delimiter, 8, enc.delimiter);
241 case ossia::net::framing::cobs:
242 ossia::net::cobs_encoder<socket_t>{listener.m_socket}.write(data, sz);
244 case ossia::net::framing::stx_etx:
245 ossia::net::stx_etx_framing::encoder<socket_t>{listener.m_socket}.write(
248 case ossia::net::framing::size_prefix_1byte:
249 ossia::net::size_prefix_1byte_framing::encoder<socket_t>{listener.m_socket}
252 case ossia::net::framing::size_prefix_2byte_be:
253 ossia::net::size_prefix_2byte_be_framing::encoder<socket_t>{listener.m_socket}
256 case ossia::net::framing::size_prefix_2byte_le:
257 ossia::net::size_prefix_2byte_le_framing::encoder<socket_t>{listener.m_socket}
260 case ossia::net::framing::size_prefix_4byte_le:
261 ossia::net::size_prefix_4byte_le_framing::encoder<socket_t>{listener.m_socket}
264 case ossia::net::framing::fixed_length:
265 ossia::net::fixed_length_encoder<socket_t>{listener.m_socket}.write(data, sz);
271 struct receive_callback
273 std::shared_ptr<state> st;
274 QPointer<qml_unix_stream_connection> self;
276 void operator()(
const unsigned char* data, std::size_t sz)
const
280 auto buf = apply_decoding(st->enc, data, sz);
281 ossia::qt::run_async(
286 if(self->onMessage.isCallable())
288 self->onMessage.call({qjsEngine(self.get())->toScriptValue(buf)});
294 bool validate_stream(boost::system::error_code ec)
const
296 if(ec == boost::asio::error::operation_aborted)
298 if(ec == boost::asio::error::eof)
300 ossia::qt::run_async(
305 if(self->onClose.isCallable())
306 self->onClose.call();
317 qml_unix_stream_connection(
318 ossia::net::unix_stream_listener listener, boost::asio::io_context& ctx,
319 ossia::net::framing f = ossia::net::framing::none,
320 const std::string& delim = {},
321 ossia::net::encoding e = ossia::net::encoding::none)
322 : m_state{std::make_shared<state>(std::move(listener), ctx, f, delim, e)}
326 ~qml_unix_stream_connection()
330 m_state->alive =
false;
335 bool isOpen() const noexcept {
return m_state && m_state->alive; }
337 inline boost::asio::io_context& context() noexcept {
return m_state->context; }
339 void write(QByteArray buffer)
344 if(st->enc != ossia::net::encoding::none)
345 buffer = apply_encoding(st->enc, buffer);
346 boost::asio::dispatch(st->context, [st, buffer = std::move(buffer)] {
348 st->write_encoded(buffer.data(), buffer.size());
353 void close(QByteArray)
358 boost::asio::dispatch(st->context, [st] { st->listener.close(); });
365 auto self = QPointer{
this};
367 [cb = receive_callback{st, self}](
auto& decoder)
mutable {
368 decoder.receive(std::move(cb));
375 W_PROPERTY(QJSValue, onClose MEMBER onClose);
378 std::shared_ptr<state> m_state;
381class qml_unix_stream_inbound_socket
383 ,
public Nano::Observer
385 W_OBJECT(qml_unix_stream_inbound_socket)
389 ossia::net::unix_stream_server server;
390 std::atomic_bool alive{
true};
391 ossia::net::framing framing{ossia::net::framing::none};
392 std::string framing_delimiter;
393 ossia::net::encoding enc{ossia::net::encoding::none};
396 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
397 ossia::net::framing f = ossia::net::framing::none,
398 std::string delim = {},
399 ossia::net::encoding e = ossia::net::encoding::none)
402 , framing_delimiter{std::move(delim)}
408 qml_unix_stream_inbound_socket() { }
410 ~qml_unix_stream_inbound_socket()
414 m_state->alive =
false;
419 bool isOpen() const noexcept {
return m_state !=
nullptr; }
422 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
423 ossia::net::framing f = ossia::net::framing::none,
424 const std::string& delim = {},
425 ossia::net::encoding e = ossia::net::encoding::none)
427 m_state = std::make_shared<state>(conf, ctx, f, delim, e);
429 accept_impl(m_state, QPointer{
this});
430 if(onOpen.isCallable())
431 onOpen.call({qjsEngine(
this)->newQObject(
this)});
438 m_state->server.m_acceptor.close();
439 if(onClose.isCallable())
446 if(!m_state || !m_state->alive)
448 ossia::qt::run_async(
this, [=,
this] { onClose.call(); }, Qt::AutoConnection);
454 QJSValue onConnection;
457 static void accept_impl(
458 std::shared_ptr<state> st, QPointer<qml_unix_stream_inbound_socket> self)
460 st->server.m_acceptor.async_accept(
462 boost::system::error_code ec,
463 ossia::net::unix_stream_server::proto::socket socket) {
468 ossia::qt::run_async(
470 [self, st, socket = std::move(socket)]()
mutable {
473 auto conn = new qml_unix_stream_connection{
474 ossia::net::unix_stream_listener{std::move(socket)},
475 st->server.m_context, st->framing, st->framing_delimiter, st->enc};
476 conn->setParent(self.get());
477 conn->onMessage = self->onConnection;
478 conn->startReceive();
480 if(self->onConnection.isCallable())
482 self->onConnection.call(
483 {qjsEngine(self.get())->newQObject(
static_cast<QObject*
>(conn))});
487 accept_impl(st, self);
492 std::shared_ptr<state> m_state;
Definition qml_device.cpp:43