OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
qml_unix_inbound_socket.hpp
1#pragma once
2#include <ossia/network/context.hpp>
3#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
4#include <ossia/network/sockets/unix_socket.hpp>
5
6#include <ossia-qt/protocols/utils.hpp>
7
8#include <QJSValue>
9#include <QObject>
10#include <QQmlEngine>
11
12#include <nano_observer.hpp>
13
14#include <verdigris>
15
16namespace ossia::qt
17{
18class qml_unix_datagram_inbound_socket
19 : public QObject
20 , public Nano::Observer
21{
22 W_OBJECT(qml_unix_datagram_inbound_socket)
23public:
24 qml_unix_datagram_inbound_socket(
25 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx)
26 : socket{conf, ctx}
27 {
28 }
29 inline boost::asio::io_context& context() noexcept { return socket.m_context; }
30
31 void open()
32 {
33 if(onClose.isCallable())
34 socket.on_close.connect<&qml_unix_datagram_inbound_socket::on_close>(this);
35
36 socket.open();
37 if(onOpen.isCallable())
38
39 onOpen.call({qjsEngine(this)->newQObject(this)});
40
41 socket.receive([self = QPointer{this}](const char* data, std::size_t sz) {
42 ossia::qt::run_async(self.data(), [self, arg = QString::fromUtf8(data, sz)] {
43 if(!self)
44 return;
45 if(self->onMessage.isCallable())
46 {
47 self->onMessage.call({arg});
48 }
49 }, Qt::AutoConnection);
50 });
51 }
52
53 void close() { socket.close(); }
54 W_SLOT(close)
55
56 void on_close()
57 {
58 run_on_qt_thread({ onClose.call(); });
59 }
60
61 QJSValue onOpen;
62 QJSValue onClose;
63 QJSValue onError;
64 QJSValue onMessage;
65
66 ossia::net::unix_datagram_socket socket;
67};
68
69// FIXME apply same logic than tcp inbound
70class qml_unix_stream_connection
71 : public QObject
72 , public Nano::Observer
73{
74 W_OBJECT(qml_unix_stream_connection)
75public:
76 qml_unix_stream_connection(
77 ossia::net::unix_stream_listener listener, boost::asio::io_context& ctx)
78 : m_context{ctx}
79 , m_listener{std::move(listener)}
80 {
81 }
82 inline boost::asio::io_context& context() noexcept { return m_context; }
83
84 void write(QByteArray buffer)
85 {
86 run_on_asio_thread(
87 { m_listener.write(boost::asio::buffer(buffer.data(), buffer.size())); });
88 }
89 W_SLOT(write)
90
91 void startReceive()
92 {
93 auto& socket = m_listener.m_socket;
94 socket.async_read_some(
95 boost::asio::buffer(m_data, sizeof(m_data)),
96 [self
97 = QPointer{this}](boost::system::error_code ec, std::size_t bytes_transferred) {
98 if(!ec)
99 {
100 ossia::qt::run_async(
101 self.get(),
102 [self, arg = QString::fromUtf8(self->m_data, bytes_transferred)] {
103 if(!self)
104 return;
105 if(self->onMessage.isCallable())
106 {
107 self->onMessage.call({arg});
108 }
109 });
110 self->startReceive();
111 }
112 });
113 }
114
115 QJSValue onMessage;
116
117private:
118 boost::asio::io_context& m_context;
119 ossia::net::unix_stream_listener m_listener;
120 char m_data[4096];
121};
122
123class qml_unix_stream_inbound_socket
124 : public QObject
125 , public Nano::Observer
126{
127 W_OBJECT(qml_unix_stream_inbound_socket)
128public:
129 qml_unix_stream_inbound_socket(
130 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx)
131 : server{conf, ctx}
132 {
133 }
134 inline boost::asio::io_context& context() noexcept { return server.m_context; }
135
136 void open()
137 {
138 accept();
139 if(onOpen.isCallable())
140
141 onOpen.call({qjsEngine(this)->newQObject(this)});
142 }
143
144 void close()
145 {
146 server.m_acceptor.close();
147 if(onClose.isCallable())
148 onClose.call();
149 }
150 W_SLOT(close)
151
152 void on_close()
153 {
154 run_on_qt_thread({ onClose.call(); });
155 }
156
157 QJSValue onOpen;
158 QJSValue onClose;
159 QJSValue onError;
160 QJSValue onConnection;
161
162 ossia::net::unix_stream_server server;
163
164private:
165 void accept()
166 {
167 server.m_acceptor.async_accept(
168 [self = QPointer{this}](
169 boost::system::error_code ec,
170 ossia::net::unix_stream_server::proto::socket socket) {
171 if(!ec)
172 {
173 ossia::qt::run_async(self.get(), [self, socket = std::move(socket)]() mutable {
174 auto conn = new qml_unix_stream_connection{
175 ossia::net::unix_stream_listener{std::move(socket)},
176 self->server.m_context};
177 conn->onMessage = self->onConnection;
178 conn->startReceive();
179
180 if(self->onConnection.isCallable())
181 {
182 self->onConnection.call(
183 {qjsEngine(self)->newQObject(static_cast<QObject*>(conn))});
184 }
185 });
186 self->accept();
187 }
188 });
189 }
190};
191}
192#endif
Definition qml_device.cpp:43