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 struct state
25 {
26 ossia::net::unix_datagram_socket socket;
27 std::atomic_bool alive{true};
28
29 state(const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx)
30 : socket{conf, ctx}
31 {
32 }
33 };
34
35 qml_unix_datagram_inbound_socket(
36 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx)
37 : m_state{std::make_shared<state>(conf, ctx)}
38 {
39 }
40
41 ~qml_unix_datagram_inbound_socket() { m_state->alive = false; }
42
43 inline boost::asio::io_context& context() noexcept { return m_state->socket.m_context; }
44
45 void open()
46 {
47 if(onClose.isCallable())
48 m_state->socket.on_close.connect<&qml_unix_datagram_inbound_socket::on_close>(this);
49
50 m_state->socket.open();
51 if(onOpen.isCallable())
52
53 onOpen.call({qjsEngine(this)->newQObject(this)});
54
55 auto st = m_state;
56 auto self = QPointer{this};
57 st->socket.receive([st, self](const char* data, std::size_t sz) {
58 if(!st->alive)
59 return;
60 ossia::qt::run_async(
61 self.get(),
62 [self, arg = QByteArray(data, sz)] {
63 if(!self.get())
64 return;
65 if(self->onMessage.isCallable())
66 {
67 self->onMessage.call({qjsEngine(self.get())->toScriptValue(arg)});
68 }
69 },
70 Qt::AutoConnection);
71 });
72 }
73
74 void close() { m_state->socket.close(); }
75 W_SLOT(close)
76
77 void on_close()
78 {
79 if(!m_state->alive)
80 return;
81 ossia::qt::run_async(this, [=, this] { onClose.call(); }, Qt::AutoConnection);
82 }
83
84 QJSValue onOpen;
85 QJSValue onClose;
86 QJSValue onError;
87 QJSValue onMessage;
88
89private:
90 std::shared_ptr<state> m_state;
91};
92
93class qml_unix_stream_connection
94 : public QObject
95 , public Nano::Observer
96{
97 W_OBJECT(qml_unix_stream_connection)
98public:
99 struct state
100 {
101 boost::asio::io_context& context;
102 ossia::net::unix_stream_listener listener;
103 char data[4096];
104 std::atomic_bool alive{true};
105
106 state(ossia::net::unix_stream_listener l, boost::asio::io_context& ctx)
107 : context{ctx}
108 , listener{std::move(l)}
109 {
110 }
111 };
112
113 qml_unix_stream_connection(
114 ossia::net::unix_stream_listener listener, boost::asio::io_context& ctx)
115 : m_state{std::make_shared<state>(std::move(listener), ctx)}
116 {
117 }
118
119 ~qml_unix_stream_connection() { m_state->alive = false; }
120
121 inline boost::asio::io_context& context() noexcept { return m_state->context; }
122
123 void write(QByteArray buffer)
124 {
125 auto st = m_state;
126 boost::asio::dispatch(st->context, [st, buffer] {
127 if(st->alive)
128 st->listener.write(boost::asio::buffer(buffer.data(), buffer.size()));
129 });
130 }
131 W_SLOT(write)
132
133 void startReceive() { receive_impl(m_state, QPointer{this}); }
134
135 QJSValue onMessage;
136
137private:
138 static void receive_impl(
139 std::shared_ptr<state> st, QPointer<qml_unix_stream_connection> self)
140 {
141 st->listener.m_socket.async_read_some(
142 boost::asio::buffer(st->data, sizeof(st->data)),
143 [self, st](boost::system::error_code ec, std::size_t bytes_transferred) {
144 if(!st->alive)
145 return;
146 if(!ec)
147 {
148 ossia::qt::run_async(
149 self.get(),
150 [self, arg = QString::fromUtf8(st->data, bytes_transferred)] {
151 if(!self.get())
152 return;
153 if(self->onMessage.isCallable())
154 {
155 self->onMessage.call({arg});
156 }
157 },
158 Qt::AutoConnection);
159 receive_impl(st, self);
160 }
161 });
162 }
163
164 std::shared_ptr<state> m_state;
165};
166
167class qml_unix_stream_inbound_socket
168 : public QObject
169 , public Nano::Observer
170{
171 W_OBJECT(qml_unix_stream_inbound_socket)
172public:
173 struct state
174 {
175 ossia::net::unix_stream_server server;
176 std::atomic_bool alive{true};
177
178 state(const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx)
179 : server{conf, ctx}
180 {
181 }
182 };
183
184 qml_unix_stream_inbound_socket(
185 const ossia::net::fd_configuration& conf, boost::asio::io_context& ctx)
186 : m_state{std::make_shared<state>(conf, ctx)}
187 {
188 }
189
190 ~qml_unix_stream_inbound_socket() { m_state->alive = false; }
191
192 inline boost::asio::io_context& context() noexcept { return m_state->server.m_context; }
193
194 void open()
195 {
196 accept_impl(m_state, QPointer{this});
197 if(onOpen.isCallable())
198
199 onOpen.call({qjsEngine(this)->newQObject(this)});
200 }
201
202 void close()
203 {
204 m_state->server.m_acceptor.close();
205 if(onClose.isCallable())
206 onClose.call();
207 }
208 W_SLOT(close)
209
210 void on_close()
211 {
212 if(!m_state->alive)
213 return;
214 ossia::qt::run_async(this, [=, this] { onClose.call(); }, Qt::AutoConnection);
215 }
216
217 QJSValue onOpen;
218 QJSValue onClose;
219 QJSValue onError;
220 QJSValue onConnection;
221
222private:
223 static void accept_impl(
224 std::shared_ptr<state> st, QPointer<qml_unix_stream_inbound_socket> self)
225 {
226 st->server.m_acceptor.async_accept(
227 [self, st](
228 boost::system::error_code ec,
229 ossia::net::unix_stream_server::proto::socket socket) {
230 if(!st->alive)
231 return;
232 if(!ec)
233 {
234 ossia::qt::run_async(
235 self.get(),
236 [self, st, socket = std::move(socket)]() mutable {
237 if(!self.get())
238 return;
239 auto conn = new qml_unix_stream_connection{
240 ossia::net::unix_stream_listener{std::move(socket)},
241 st->server.m_context};
242 conn->onMessage = self->onConnection;
243 conn->startReceive();
244
245 if(self->onConnection.isCallable())
246 {
247 self->onConnection.call(
248 {qjsEngine(self.get())->newQObject(static_cast<QObject*>(conn))});
249 }
250 },
251 Qt::AutoConnection);
252 accept_impl(st, self);
253 }
254 });
255 }
256
257 std::shared_ptr<state> m_state;
258};
259}
260#endif
Definition qml_device.cpp:43