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>
30class qml_unix_datagram_outbound_socket
32 ,
public Nano::Observer
33 ,
public protocols_sender
35 W_OBJECT(qml_unix_datagram_outbound_socket)
39 ossia::net::unix_datagram_socket socket;
40 std::atomic_bool alive{
true};
41 ossia::net::encoding enc{ossia::net::encoding::none};
44 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
45 ossia::net::encoding e = ossia::net::encoding::none)
52 ossia::net::unix_datagram_socket* socket =
nullptr;
54 qml_unix_datagram_outbound_socket() { }
56 ~qml_unix_datagram_outbound_socket()
60 m_state->alive =
false;
65 bool isOpen() const noexcept {
return m_state !=
nullptr; }
68 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
69 ossia::net::encoding e = ossia::net::encoding::none)
71 m_state = std::make_shared<state>(conf, ctx, e);
72 socket = &m_state->socket;
74 if(onClose.isCallable())
75 m_state->socket.on_close.connect<&qml_unix_datagram_outbound_socket::on_close>(
this);
77 m_state->socket.connect();
79 if(onOpen.isCallable())
80 onOpen.call({qjsEngine(
this)->newQObject(
this)});
87 if(!m_state->socket.m_socket.is_open())
90 boost::asio::post(st->socket.m_context, [st] {
93 st->socket.m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_both);
98 st->socket.m_socket.close();
99 st->socket.on_close();
106 if(!m_state || !m_state->alive)
108 ossia::qt::run_async(
this, [=,
this] { onClose.call(); }, Qt::AutoConnection);
111 void write(QByteArray buffer)
116 if(st->enc != ossia::net::encoding::none)
117 buffer = apply_encoding(st->enc, buffer);
118 boost::asio::dispatch(st->socket.m_context, [st, buffer = std::move(buffer)] {
120 st->socket.write(buffer.data(), buffer.size());
125 void osc(QByteArray address, QJSValueList values)
128 this->send_osc(address, values);
137 std::shared_ptr<state> m_state;
140class qml_unix_stream_outbound_socket :
public QObject
142 W_OBJECT(qml_unix_stream_outbound_socket)
144 using socket_t = boost::asio::local::stream_protocol::socket;
145 using decoder_type = ossia::slow_variant<
146 ossia::net::no_framing::decoder<socket_t>,
147 ossia::net::slip_decoder<socket_t>,
148 ossia::net::size_prefix_decoder<socket_t>,
149 ossia::net::line_framing_decoder<socket_t>,
150 ossia::net::cobs_decoder<socket_t>,
151 ossia::net::stx_etx_framing::decoder<socket_t>,
152 ossia::net::size_prefix_1byte_framing::decoder<socket_t>,
153 ossia::net::size_prefix_2byte_be_framing::decoder<socket_t>,
154 ossia::net::size_prefix_2byte_le_framing::decoder<socket_t>,
155 ossia::net::size_prefix_4byte_le_framing::decoder<socket_t>,
156 ossia::net::fixed_length_decoder<socket_t>>;
164 struct state : Nano::Observer
166 ossia::net::unix_stream_client socket;
167 std::atomic_bool alive{
true};
170 std::atomic_bool closed{
false};
171 ossia::net::framing framing{ossia::net::framing::none};
172 ossia::net::encoding enc{ossia::net::encoding::none};
173 char line_delimiter[8] = {};
174 decoder_type decoder;
177 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
178 ossia::net::framing f = ossia::net::framing::none,
179 const std::string& delim = {},
180 ossia::net::encoding e = ossia::net::encoding::none)
182 , decoder{
ossia::in_place_index<0>, socket.m_socket}
188 auto sz = std::min(delim.size(), (
size_t)7);
189 std::copy_n(delim.begin(), sz, line_delimiter);
194 case ossia::net::framing::none:
196 case ossia::net::framing::slip:
197 decoder.template emplace<1>(socket.m_socket);
199 case ossia::net::framing::size_prefix:
200 decoder.template emplace<2>(socket.m_socket);
202 case ossia::net::framing::line_delimiter:
203 decoder.template emplace<3>(socket.m_socket);
205 auto& dec = ossia::get<3>(decoder);
206 std::copy_n(line_delimiter, 8, dec.delimiter);
209 case ossia::net::framing::cobs:
210 decoder.template emplace<4>(socket.m_socket);
212 case ossia::net::framing::stx_etx:
213 decoder.template emplace<5>(socket.m_socket);
215 case ossia::net::framing::size_prefix_1byte:
216 decoder.template emplace<6>(socket.m_socket);
218 case ossia::net::framing::size_prefix_2byte_be:
219 decoder.template emplace<7>(socket.m_socket);
221 case ossia::net::framing::size_prefix_2byte_le:
222 decoder.template emplace<8>(socket.m_socket);
224 case ossia::net::framing::size_prefix_4byte_le:
225 decoder.template emplace<9>(socket.m_socket);
227 case ossia::net::framing::fixed_length:
228 decoder.template emplace<10>(socket.m_socket);
230 ossia::get<10>(decoder).frame_size = std::stoul(delim);
235 void write_encoded(
const char* data, std::size_t sz)
240 case ossia::net::framing::none:
241 socket.write(data, sz);
243 case ossia::net::framing::slip:
244 ossia::net::slip_encoder<socket_t>{socket.m_socket}.write(data, sz);
246 case ossia::net::framing::size_prefix:
247 ossia::net::size_prefix_encoder<socket_t>{socket.m_socket}.write(data, sz);
249 case ossia::net::framing::line_delimiter: {
250 ossia::net::line_framing_encoder<socket_t> enc{socket.m_socket};
251 std::copy_n(line_delimiter, 8, enc.delimiter);
255 case ossia::net::framing::cobs:
256 ossia::net::cobs_encoder<socket_t>{socket.m_socket}.write(data, sz);
258 case ossia::net::framing::stx_etx:
259 ossia::net::stx_etx_framing::encoder<socket_t>{socket.m_socket}.write(data, sz);
261 case ossia::net::framing::size_prefix_1byte:
262 ossia::net::size_prefix_1byte_framing::encoder<socket_t>{socket.m_socket}.write(
265 case ossia::net::framing::size_prefix_2byte_be:
266 ossia::net::size_prefix_2byte_be_framing::encoder<socket_t>{socket.m_socket}
269 case ossia::net::framing::size_prefix_2byte_le:
270 ossia::net::size_prefix_2byte_le_framing::encoder<socket_t>{socket.m_socket}
273 case ossia::net::framing::size_prefix_4byte_le:
274 ossia::net::size_prefix_4byte_le_framing::encoder<socket_t>{socket.m_socket}
277 case ossia::net::framing::fixed_length:
278 ossia::net::fixed_length_encoder<socket_t>{socket.m_socket}.write(data, sz);
286 qml_unix_stream_outbound_socket* self{};
290 std::lock_guard g{qt_mutex};
294 template <
typename F>
295 void post_to_qt(F&& f)
297 std::lock_guard g{qt_mutex};
299 ossia::qt::run_async(self, std::forward<F>(f), Qt::AutoConnection);
310 if(alive && !closed.exchange(
true))
315 struct receive_callback
317 std::shared_ptr<state> st;
318 QPointer<qml_unix_stream_outbound_socket> self;
324 void operator()(
const unsigned char* data, std::size_t sz)
const
326 if(!st->alive || !target)
328 auto buf = apply_decoding(st->enc, data, sz);
330 st->post_to_qt([self = self, buf, cb] {
335 auto engine = qjsEngine(self.get());
337 cb->call({engine->toScriptValue(buf)});
342 bool validate_stream(boost::system::error_code ec)
const
346 if(ec == boost::asio::error::operation_aborted)
357 qml_unix_stream_outbound_socket() { }
359 ~qml_unix_stream_outbound_socket()
363 m_state->alive =
false;
371 bool isOpen() const noexcept {
return m_state !=
nullptr; }
374 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
375 ossia::net::framing f = ossia::net::framing::none,
376 const std::string& delim = {},
377 ossia::net::encoding e = ossia::net::encoding::none)
379 m_state = std::make_shared<state>(conf, ctx, f, delim, e);
380 m_state->self =
this;
384 if(onOpen.isCallable())
385 m_state->socket.on_open.connect<&state::fire_open>(m_state.get());
386 if(onClose.isCallable())
387 m_state->socket.on_close.connect<&state::fire_close>(m_state.get());
388 if(onError.isCallable())
389 m_state->socket.on_fail.connect<&state::fire_fail>(m_state.get());
390 m_state->socket.connect();
392 catch(
const std::exception& e)
394 if(onError.isCallable())
396 onError.call({QString::fromStdString(e.what())});
401 void write(QByteArray buffer)
406 if(st->enc != ossia::net::encoding::none)
407 buffer = apply_encoding(st->enc, buffer);
408 boost::asio::dispatch(st->socket.m_context, [st, buffer = std::move(buffer)] {
410 st->write_encoded(buffer.data(), buffer.size());
420 boost::asio::post(st->socket.m_context, [st] {
423 st->socket.m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_both);
428 st->socket.m_socket.close();
438 if(!m_state || !m_state->alive)
442 auto self = QPointer{
this};
445 if(onMessage.isCallable())
448 [cb = receive_callback{st, self, &self.data()->onMessage}](
449 auto& decoder)
mutable { decoder.receive(std::move(cb)); },
454 QJSValue* target = onBytes.isCallable() ? &self.data()->onBytes :
nullptr;
455 st->decoder.template emplace<0>(st->socket.m_socket);
456 ossia::get<0>(st->decoder).receive(receive_callback{st, self, target});
459 ossia::qt::run_async(
460 this, [=,
this] { onOpen.call({qjsEngine(
this)->newQObject(
this)}); },
465 if(!m_state || !m_state->alive)
467 ossia::qt::run_async(
this, [=,
this] { onError.call(); }, Qt::AutoConnection);
471 if(!m_state || !m_state->alive)
473 ossia::qt::run_async(
this, [=,
this] { onClose.call(); }, Qt::AutoConnection);
476 void osc(QByteArray address, QJSValueList values)
481 buffer_writer bw{packet};
482 using send_visitor = ossia::net::osc_value_send_visitor<
486 const std::string addr = address.toStdString();
488 switch(values.size())
491 ossia::value{ossia::impulse{}}.apply(send_visitor{p, addr, bw});
495 auto v = ossia::qt::value_from_js(values[0]);
496 v.apply(send_visitor{p, addr, bw});
500 std::vector<ossia::value> vec;
501 vec.reserve(values.size());
502 for(
const auto& v : values)
503 vec.push_back(
ossia::qt::value_from_js(v));
505 vvec.apply(send_visitor{p, addr, bw});
519 std::shared_ptr<state> m_state;
522inline void qml_unix_stream_outbound_socket::state::fire_open()
524 std::lock_guard g{qt_mutex};
529inline void qml_unix_stream_outbound_socket::state::fire_fail()
531 std::lock_guard g{qt_mutex};
536inline void qml_unix_stream_outbound_socket::state::fire_close()
538 std::lock_guard g{qt_mutex};
The value class.
Definition value.hpp:173
Definition qml_device.cpp:43
Full information about a parameter.
Definition parameter_data.hpp:61