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_outbound_socket
30 ,
public Nano::Observer
31 ,
public protocols_sender
33 W_OBJECT(qml_unix_datagram_outbound_socket)
37 ossia::net::unix_datagram_socket socket;
38 std::atomic_bool alive{
true};
39 ossia::net::encoding enc{ossia::net::encoding::none};
42 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
43 ossia::net::encoding e = ossia::net::encoding::none)
50 ossia::net::unix_datagram_socket* socket =
nullptr;
52 qml_unix_datagram_outbound_socket() { }
54 ~qml_unix_datagram_outbound_socket()
58 m_state->alive =
false;
63 bool isOpen() const noexcept {
return m_state !=
nullptr; }
66 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
67 ossia::net::encoding e = ossia::net::encoding::none)
69 m_state = std::make_shared<state>(conf, ctx, e);
70 socket = &m_state->socket;
72 if(onClose.isCallable())
73 m_state->socket.on_close.connect<&qml_unix_datagram_outbound_socket::on_close>(
this);
75 m_state->socket.connect();
77 if(onOpen.isCallable())
78 onOpen.call({qjsEngine(
this)->newQObject(
this)});
85 if(!m_state->socket.m_socket.is_open())
88 boost::asio::post(st->socket.m_context, [st] {
91 st->socket.m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_both);
96 st->socket.m_socket.close();
97 st->socket.on_close();
104 if(!m_state || !m_state->alive)
106 ossia::qt::run_async(
this, [=,
this] { onClose.call(); }, Qt::AutoConnection);
109 void write(QByteArray buffer)
114 if(st->enc != ossia::net::encoding::none)
115 buffer = apply_encoding(st->enc, buffer);
116 boost::asio::dispatch(st->socket.m_context, [st, buffer = std::move(buffer)] {
118 st->socket.write(buffer.data(), buffer.size());
123 void osc(QByteArray address, QJSValueList values)
126 this->send_osc(address, values);
135 std::shared_ptr<state> m_state;
138class qml_unix_stream_outbound_socket
140 ,
public Nano::Observer
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>>;
160 ossia::net::unix_stream_client socket;
161 std::atomic_bool alive{
true};
162 ossia::net::framing framing{ossia::net::framing::none};
163 ossia::net::encoding enc{ossia::net::encoding::none};
164 char line_delimiter[8] = {};
165 decoder_type decoder;
168 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
169 ossia::net::framing f = ossia::net::framing::none,
170 const std::string& delim = {},
171 ossia::net::encoding e = ossia::net::encoding::none)
173 , decoder{
ossia::in_place_index<0>, socket.m_socket}
179 auto sz = std::min(delim.size(), (
size_t)7);
180 std::copy_n(delim.begin(), sz, line_delimiter);
185 case ossia::net::framing::none:
187 case ossia::net::framing::slip:
188 decoder.template emplace<1>(socket.m_socket);
190 case ossia::net::framing::size_prefix:
191 decoder.template emplace<2>(socket.m_socket);
193 case ossia::net::framing::line_delimiter:
194 decoder.template emplace<3>(socket.m_socket);
196 auto& dec = ossia::get<3>(decoder);
197 std::copy_n(line_delimiter, 8, dec.delimiter);
200 case ossia::net::framing::cobs:
201 decoder.template emplace<4>(socket.m_socket);
203 case ossia::net::framing::stx_etx:
204 decoder.template emplace<5>(socket.m_socket);
206 case ossia::net::framing::size_prefix_1byte:
207 decoder.template emplace<6>(socket.m_socket);
209 case ossia::net::framing::size_prefix_2byte_be:
210 decoder.template emplace<7>(socket.m_socket);
212 case ossia::net::framing::size_prefix_2byte_le:
213 decoder.template emplace<8>(socket.m_socket);
215 case ossia::net::framing::size_prefix_4byte_le:
216 decoder.template emplace<9>(socket.m_socket);
218 case ossia::net::framing::fixed_length:
219 decoder.template emplace<10>(socket.m_socket);
221 ossia::get<10>(decoder).frame_size = std::stoul(delim);
226 void write_encoded(
const char* data, std::size_t sz)
231 case ossia::net::framing::none:
232 socket.write(data, sz);
234 case ossia::net::framing::slip:
235 ossia::net::slip_encoder<socket_t>{socket.m_socket}.write(data, sz);
237 case ossia::net::framing::size_prefix:
238 ossia::net::size_prefix_encoder<socket_t>{socket.m_socket}.write(data, sz);
240 case ossia::net::framing::line_delimiter: {
241 ossia::net::line_framing_encoder<socket_t> enc{socket.m_socket};
242 std::copy_n(line_delimiter, 8, enc.delimiter);
246 case ossia::net::framing::cobs:
247 ossia::net::cobs_encoder<socket_t>{socket.m_socket}.write(data, sz);
249 case ossia::net::framing::stx_etx:
250 ossia::net::stx_etx_framing::encoder<socket_t>{socket.m_socket}.write(data, sz);
252 case ossia::net::framing::size_prefix_1byte:
253 ossia::net::size_prefix_1byte_framing::encoder<socket_t>{socket.m_socket}.write(
256 case ossia::net::framing::size_prefix_2byte_be:
257 ossia::net::size_prefix_2byte_be_framing::encoder<socket_t>{socket.m_socket}
260 case ossia::net::framing::size_prefix_2byte_le:
261 ossia::net::size_prefix_2byte_le_framing::encoder<socket_t>{socket.m_socket}
264 case ossia::net::framing::size_prefix_4byte_le:
265 ossia::net::size_prefix_4byte_le_framing::encoder<socket_t>{socket.m_socket}
268 case ossia::net::framing::fixed_length:
269 ossia::net::fixed_length_encoder<socket_t>{socket.m_socket}.write(data, sz);
275 struct receive_callback
277 std::shared_ptr<state> st;
278 QPointer<qml_unix_stream_outbound_socket> self;
281 void operator()(
const unsigned char* data, std::size_t sz)
const
285 auto buf = apply_decoding(st->enc, data, sz);
287 ossia::qt::run_async(
289 [self = self, buf, cb] {
294 auto engine = qjsEngine(self.get());
296 cb->call({engine->toScriptValue(buf)});
302 bool validate_stream(boost::system::error_code ec)
const
304 if(ec == boost::asio::error::operation_aborted)
306 if(ec == boost::asio::error::eof)
312 qml_unix_stream_outbound_socket() { }
314 ~qml_unix_stream_outbound_socket()
318 m_state->alive =
false;
323 bool isOpen() const noexcept {
return m_state !=
nullptr; }
326 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
327 ossia::net::framing f = ossia::net::framing::none,
328 const std::string& delim = {},
329 ossia::net::encoding e = ossia::net::encoding::none)
331 m_state = std::make_shared<state>(conf, ctx, f, delim, e);
335 if(onOpen.isCallable())
336 m_state->socket.on_open.connect<&qml_unix_stream_outbound_socket::on_open>(
this);
337 if(onClose.isCallable())
338 m_state->socket.on_close.connect<&qml_unix_stream_outbound_socket::on_close>(
340 if(onError.isCallable())
341 m_state->socket.on_fail.connect<&qml_unix_stream_outbound_socket::on_fail>(
this);
342 m_state->socket.connect();
344 catch(
const std::exception& e)
346 if(onError.isCallable())
348 onError.call({QString::fromStdString(e.what())});
353 void write(QByteArray buffer)
358 if(st->enc != ossia::net::encoding::none)
359 buffer = apply_encoding(st->enc, buffer);
360 boost::asio::dispatch(st->socket.m_context, [st, buffer = std::move(buffer)] {
362 st->write_encoded(buffer.data(), buffer.size());
372 boost::asio::post(st->socket.m_context, [st] {
375 st->socket.m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_both);
380 st->socket.m_socket.close();
381 st->socket.on_close();
388 if(!m_state || !m_state->alive)
392 auto self = QPointer{
this};
393 if(onMessage.isCallable())
396 [cb = receive_callback{st, self, &self.data()->onMessage}](
397 auto& decoder)
mutable { decoder.receive(std::move(cb)); },
400 else if(onBytes.isCallable())
402 st->decoder.template emplace<0>(st->socket.m_socket);
403 ossia::get<0>(st->decoder)
404 .receive(receive_callback{st, self, &self.data()->onBytes});
407 ossia::qt::run_async(
408 this, [=,
this] { onOpen.call({qjsEngine(
this)->newQObject(
this)}); },
413 if(!m_state || !m_state->alive)
415 ossia::qt::run_async(
this, [=,
this] { onError.call(); }, Qt::AutoConnection);
419 if(!m_state || !m_state->alive)
421 ossia::qt::run_async(
this, [=,
this] { onClose.call(); }, Qt::AutoConnection);
424 void osc(QByteArray address, QJSValueList values)
429 buffer_writer bw{packet};
430 using send_visitor = ossia::net::osc_value_send_visitor<
434 const std::string addr = address.toStdString();
436 switch(values.size())
439 ossia::value{ossia::impulse{}}.apply(send_visitor{p, addr, bw});
443 auto v = ossia::qt::value_from_js(values[0]);
444 v.apply(send_visitor{p, addr, bw});
448 std::vector<ossia::value> vec;
449 vec.reserve(values.size());
450 for(
const auto& v : values)
451 vec.push_back(
ossia::qt::value_from_js(v));
453 vvec.apply(send_visitor{p, addr, bw});
467 std::shared_ptr<state> m_state;
The value class.
Definition value.hpp:173
Definition qml_device.cpp:43
Full information about a parameter.
Definition parameter_data.hpp:61