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_outbound_socket
26 ,
public Nano::Observer
27 ,
public protocols_sender
29 W_OBJECT(qml_unix_datagram_outbound_socket)
33 ossia::net::unix_datagram_socket socket;
34 std::atomic_bool alive{
true};
36 state(
const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx)
42 ossia::net::unix_datagram_socket* socket =
nullptr;
44 qml_unix_datagram_outbound_socket() { }
46 ~qml_unix_datagram_outbound_socket()
50 m_state->alive =
false;
55 bool isOpen() const noexcept {
return m_state !=
nullptr; }
57 void open(
const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx)
59 m_state = std::make_shared<state>(conf, ctx);
60 socket = &m_state->socket;
62 if(onClose.isCallable())
63 m_state->socket.on_close.connect<&qml_unix_datagram_outbound_socket::on_close>(
this);
65 m_state->socket.connect();
67 if(onOpen.isCallable())
68 onOpen.call({qjsEngine(
this)->newQObject(
this)});
75 if(!m_state->socket.m_socket.is_open())
78 boost::asio::post(st->socket.m_context, [st] {
81 st->socket.m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_both);
86 st->socket.m_socket.close();
87 st->socket.on_close();
94 if(!m_state || !m_state->alive)
96 ossia::qt::run_async(
this, [=,
this] { onClose.call(); }, Qt::AutoConnection);
99 void write(QByteArray buffer)
104 boost::asio::dispatch(st->socket.m_context, [st, buffer] {
106 st->socket.write(buffer.data(), buffer.size());
111 void osc(QByteArray address, QJSValueList values)
114 this->send_osc(address, values);
123 std::shared_ptr<state> m_state;
126class qml_unix_stream_outbound_socket
128 ,
public Nano::Observer
130 W_OBJECT(qml_unix_stream_outbound_socket)
132 using socket_t = boost::asio::local::stream_protocol::socket;
133 using decoder_type = ossia::slow_variant<
134 ossia::net::no_framing::decoder<socket_t>,
135 ossia::net::slip_decoder<socket_t>,
136 ossia::net::size_prefix_decoder<socket_t>,
137 ossia::net::line_framing_decoder<socket_t>>;
141 ossia::net::unix_stream_client socket;
142 std::atomic_bool alive{
true};
143 ossia::net::framing framing{ossia::net::framing::none};
144 char line_delimiter[8] = {};
145 decoder_type decoder;
148 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
149 ossia::net::framing f = ossia::net::framing::none,
150 const std::string& delim = {})
152 , decoder{
ossia::in_place_index<0>, socket.m_socket}
157 auto sz = std::min(delim.size(), (
size_t)7);
158 std::copy_n(delim.begin(), sz, line_delimiter);
163 case ossia::net::framing::none:
165 case ossia::net::framing::slip:
166 decoder.template emplace<1>(socket.m_socket);
168 case ossia::net::framing::size_prefix:
169 decoder.template emplace<2>(socket.m_socket);
171 case ossia::net::framing::line_delimiter:
172 decoder.template emplace<3>(socket.m_socket);
174 auto& dec = ossia::get<3>(decoder);
175 std::copy_n(line_delimiter, 8, dec.delimiter);
181 void write_encoded(
const char* data, std::size_t sz)
186 case ossia::net::framing::none:
187 socket.write(data, sz);
189 case ossia::net::framing::slip: {
190 ossia::net::slip_encoder<socket_t> enc{socket.m_socket};
194 case ossia::net::framing::size_prefix: {
195 ossia::net::size_prefix_encoder<socket_t> enc{socket.m_socket};
199 case ossia::net::framing::line_delimiter: {
200 ossia::net::line_framing_encoder<socket_t> enc{socket.m_socket};
201 std::copy_n(line_delimiter, 8, enc.delimiter);
209 struct receive_callback
211 std::shared_ptr<state> st;
212 QPointer<qml_unix_stream_outbound_socket> self;
215 void operator()(
const unsigned char* data, std::size_t sz)
const
219 auto buf = QByteArray((
const char*)data, sz);
221 ossia::qt::run_async(
223 [self = self, buf, cb] {
228 auto engine = qjsEngine(self.get());
230 cb->call({engine->toScriptValue(buf)});
236 bool validate_stream(boost::system::error_code ec)
const
238 if(ec == boost::asio::error::operation_aborted)
240 if(ec == boost::asio::error::eof)
246 qml_unix_stream_outbound_socket() { }
248 ~qml_unix_stream_outbound_socket()
252 m_state->alive =
false;
257 bool isOpen() const noexcept {
return m_state !=
nullptr; }
260 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx,
261 ossia::net::framing f = ossia::net::framing::none,
262 const std::string& delim = {})
264 m_state = std::make_shared<state>(conf, ctx, f, delim);
268 if(onOpen.isCallable())
269 m_state->socket.on_open.connect<&qml_unix_stream_outbound_socket::on_open>(
this);
270 if(onClose.isCallable())
271 m_state->socket.on_close.connect<&qml_unix_stream_outbound_socket::on_close>(
273 if(onError.isCallable())
274 m_state->socket.on_fail.connect<&qml_unix_stream_outbound_socket::on_fail>(
this);
275 m_state->socket.connect();
277 catch(
const std::exception& e)
279 if(onError.isCallable())
281 onError.call({QString::fromStdString(e.what())});
286 void write(QByteArray buffer)
291 boost::asio::dispatch(st->socket.m_context, [st, buffer] {
293 st->write_encoded(buffer.data(), buffer.size());
303 boost::asio::post(st->socket.m_context, [st] {
306 st->socket.m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_both);
311 st->socket.m_socket.close();
312 st->socket.on_close();
319 if(!m_state || !m_state->alive)
323 auto self = QPointer{
this};
324 if(onMessage.isCallable())
327 [cb = receive_callback{st, self, &self.data()->onMessage}](
328 auto& decoder)
mutable { decoder.receive(std::move(cb)); },
331 else if(onBytes.isCallable())
333 st->decoder.template emplace<0>(st->socket.m_socket);
334 ossia::get<0>(st->decoder)
335 .receive(receive_callback{st, self, &self.data()->onBytes});
338 ossia::qt::run_async(
339 this, [=,
this] { onOpen.call({qjsEngine(
this)->newQObject(
this)}); },
344 if(!m_state || !m_state->alive)
346 ossia::qt::run_async(
this, [=,
this] { onError.call(); }, Qt::AutoConnection);
350 if(!m_state || !m_state->alive)
352 ossia::qt::run_async(
this, [=,
this] { onClose.call(); }, Qt::AutoConnection);
355 void osc(QByteArray address, QJSValueList values)
360 buffer_writer bw{packet};
361 using send_visitor = ossia::net::osc_value_send_visitor<
365 const std::string addr = address.toStdString();
367 switch(values.size())
370 ossia::value{ossia::impulse{}}.apply(send_visitor{p, addr, bw});
374 auto v = ossia::qt::value_from_js(values[0]);
375 v.apply(send_visitor{p, addr, bw});
379 std::vector<ossia::value> vec;
380 vec.reserve(values.size());
381 for(
const auto& v : values)
382 vec.push_back(
ossia::qt::value_from_js(v));
384 vvec.apply(send_visitor{p, addr, bw});
398 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