OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
osc/detail/bundle.hpp
1#pragma once
2#include <ossia/detail/buffer_pool.hpp>
4#include <ossia/network/base/bundle.hpp>
5#include <ossia/network/base/osc_address.hpp>
6#include <ossia/network/osc/detail/osc_1_0_policy.hpp>
7#include <ossia/network/osc/detail/osc_messages.hpp>
8#include <ossia/network/value/value.hpp>
9
10#include <oscpack/osc/OscOutboundPacketStream.h>
11
12#include <optional>
13
14namespace ossia::net
15{
16
17// Default case
18template <typename OscPolicy>
19struct bundle_common_policy
20{
21 template <typename Addr_T>
22 void
23 operator()(oscpack::OutboundPacketStream& str, ossia::value& val, const Addr_T& addr)
24 {
25 if(val = bound_value(addr, std::move(val)); val.valid())
26 {
27 str << oscpack::BeginMessageN(osc_address(addr));
28 val.apply(typename OscPolicy::dynamic_policy{{str, addr.get_unit()}});
29 str << oscpack::EndMessage();
30 }
31 }
32};
33
34template <typename OscPolicy>
35struct bundle_client_policy
36{
37 template <typename Addr_T>
38 void
39 operator()(oscpack::OutboundPacketStream& str, ossia::value& val, const Addr_T& addr)
40 {
41 if(addr.get_access() == ossia::access_mode::GET)
42 return;
43
44 bundle_common_policy<OscPolicy>{}(str, val, addr);
45 }
46};
47
48template <typename OscPolicy>
49using bundle_server_policy = bundle_common_policy<OscPolicy>;
50
51// Pre-bounded case
52template <typename OscPolicy>
53struct bundle_bounded_common_policy
54{
55 template <typename Addr_T>
56 void
57 operator()(oscpack::OutboundPacketStream& str, ossia::value& val, const Addr_T& addr)
58 {
59 if(val.valid())
60 {
61 str << oscpack::BeginMessageN(osc_address(addr));
62 val.apply(typename OscPolicy::dynamic_policy{{str, addr.get_unit()}});
63 str << oscpack::EndMessage();
64 }
65 }
66};
67
68template <typename OscPolicy>
69struct bundle_bounded_client_policy
70{
71 template <typename Addr_T>
72 void
73 operator()(oscpack::OutboundPacketStream& str, ossia::value& val, const Addr_T& addr)
74 {
75 if(addr.get_access() == ossia::access_mode::GET)
76 return;
77
78 bundle_bounded_common_policy<OscPolicy>{}(str, val, addr);
79 }
80};
81
82template <typename OscPolicy>
83using bundle_bounded_server_policy = bundle_bounded_common_policy<OscPolicy>;
84
85static inline auto& access_parameter(const ossia::net::parameter_base* p)
86{
87 return *p;
88}
89static inline auto& access_parameter(const ossia::net::full_parameter_data& p)
90{
91 return p;
92}
93static inline auto& access_parameter(const ossia::bundle_element& p)
94{
95 return *p.parameter;
96}
97
98struct bundle
99{
100 ossia::buffer_pool::buffer data;
101 bool critical{};
102};
103
104template <typename NetworkPolicy, typename Addresses>
105std::optional<bundle>
106make_bundle(NetworkPolicy add_element_to_bundle, const Addresses& addresses)
107try
108{
109 bundle ret{ossia::buffer_pool::instance().acquire(max_osc_message_size), false};
110 {
111 oscpack::OutboundPacketStream str(ret.data.data(), max_osc_message_size);
112 str << oscpack::BeginBundleImmediate();
113
114 static thread_local ossia::value val;
115 for(const auto& a : addresses)
116 {
117 auto& param = access_parameter(a);
118 ret.critical |= param.get_critical();
119
120 if constexpr(requires {
121 { a.value } -> std::same_as<ossia::value>;
122 })
123 add_element_to_bundle(str, val = a.value, param);
124 else
125 add_element_to_bundle(str, val = param.value(), param);
126 }
127 str << oscpack::EndBundle();
128 ret.data.resize(str.Size());
129
130 // TODO useless condition for now.
131 // But if we know that we are going through ws we can increase the size
132 // beyond 65k. ret.critical |= str.Size() > max_osc_message_size;
133 }
134 return ret;
135}
136catch(const oscpack::OutOfBufferMemoryException&)
137{
138 ossia::logger().error(
139 "make_bundle_client: message too large (limit is {} bytes)", max_osc_message_size);
140 return {};
141}
142catch(const std::runtime_error& e)
143{
144 ossia::logger().error("make_bundle_client: {}", e.what());
145 return {};
146}
147catch(...)
148{
149 ossia::logger().error("make_bundle_client: unknown error");
150 return {};
151}
152
153template <typename NetworkPolicy>
154std::optional<bundle> make_bundle(
155 NetworkPolicy add_element_to_bundle, const ossia::net::full_parameter_data& param)
156try
157{
158 static thread_local ossia::value val;
159 bundle ret{
160 ossia::buffer_pool::instance().acquire(max_osc_message_size), param.critical};
161 {
162 oscpack::OutboundPacketStream str(ret.data.data(), max_osc_message_size);
163 str << oscpack::BeginBundleImmediate();
164 add_element_to_bundle(str, val = param.value(), param);
165 str << oscpack::EndBundle();
166 ret.data.resize(str.Size());
167
168 // TODO useless condition for now.
169 // But if we know that we are going through ws we can increase the size
170 // beyond 65k. ret.critical |= str.Size() > max_osc_message_size;
171 }
172 return ret;
173}
174catch(const oscpack::OutOfBufferMemoryException&)
175{
176 ossia::logger().error(
177 "make_bundle_client: message too large (limit is {} bytes)", max_osc_message_size);
178 return {};
179}
180catch(const std::runtime_error& e)
181{
182 ossia::logger().error("make_bundle_client: {}", e.what());
183 return {};
184}
185catch(...)
186{
187 ossia::logger().error("make_bundle_client: unknown error");
188 return {};
189}
190
191template <typename NetworkPolicy>
192std::optional<bundle> make_bundle(
193 NetworkPolicy add_element_to_bundle, const ossia::net::parameter_base& param,
194 ossia::value& v)
195try
196{
197 bundle ret{
198 ossia::buffer_pool::instance().acquire(max_osc_message_size),
199 param.get_critical()};
200 {
201 oscpack::OutboundPacketStream str(ret.data.data(), max_osc_message_size);
202 str << oscpack::BeginBundleImmediate();
203 add_element_to_bundle(str, v, param);
204 str << oscpack::EndBundle();
205 ret.data.resize(str.Size());
206
207 // TODO useless condition for now.
208 // But if we know that we are going through ws we can increase the size
209 // beyond 65k. ret.critical |= str.Size() > max_osc_message_size;
210 }
211 return ret;
212}
213catch(const oscpack::OutOfBufferMemoryException&)
214{
215 ossia::logger().error(
216 "make_bundle_client: message too large (limit is {} bytes)", max_osc_message_size);
217 return {};
218}
219catch(const std::runtime_error& e)
220{
221 ossia::logger().error("make_bundle_client: {}", e.what());
222 return {};
223}
224catch(...)
225{
226 ossia::logger().error("make_bundle_client: unknown error");
227 return {};
228}
229
230template <typename NetworkPolicy>
231std::optional<bundle> make_bundle(
232 NetworkPolicy add_element_to_bundle,
233 const std::span<ossia::bundle_element>& addresses)
234try
235{
236 bundle ret{ossia::buffer_pool::instance().acquire(max_osc_message_size), false};
237 {
238 oscpack::OutboundPacketStream str(ret.data.data(), max_osc_message_size);
239 str << oscpack::BeginBundleImmediate();
240
241 for(auto& [p, v] : addresses)
242 {
243 auto& param = *p;
244 ret.critical |= param.get_critical();
245 add_element_to_bundle(str, v, param);
246 }
247 str << oscpack::EndBundle();
248 ret.data.resize(str.Size());
249
250 // TODO useless condition for now.
251 // But if we know that we are going through ws we can increase the size
252 // beyond 65k. ret.critical |= str.Size() > max_osc_message_size;
253 }
254 return ret;
255}
256catch(const oscpack::OutOfBufferMemoryException&)
257{
258 ossia::logger().error(
259 "make_bundle_client: message too large (limit is {} bytes)", max_osc_message_size);
260 return {};
261}
262catch(const std::runtime_error& e)
263{
264 ossia::logger().error("make_bundle_client: {}", e.what());
265 return {};
266}
267catch(...)
268{
269 ossia::logger().error("make_bundle_client: unknown error");
270 return {};
271}
272
273template <typename NetworkPolicy>
274bool make_bundle_bounded(
275 NetworkPolicy add_element_to_bundle,
276 const std::span<ossia::bundle_element>& addresses, auto callback)
277{
278 bundle ret{ossia::buffer_pool::instance().acquire(max_osc_message_size), false};
279 try
280 {
281 // FIXME iterate until the size is enough
282 oscpack::OutboundPacketStream str(ret.data.data(), max_osc_message_size);
283 str << oscpack::BeginBundleImmediate();
284
285 for(auto& [p, v] : addresses)
286 {
287 auto& param = *p;
288 ret.critical |= param.get_critical();
289 add_element_to_bundle(str, v, param);
290 }
291 str << oscpack::EndBundle();
292 ret.data.resize(str.Size());
293
294 callback(ret);
295
296 // TODO useless condition for now.
297 // But if we know that we are going through ws we can increase the size
298 // beyond 65k. ret.critical |= str.Size() > max_osc_message_size;
299 }
300 catch(const oscpack::OutOfBufferMemoryException&)
301 {
302 ossia::logger().error(
303 "make_bundle_client: message too large (limit is {} bytes)",
304 max_osc_message_size);
305 }
306 catch(const std::runtime_error& e)
307 {
308 ossia::logger().error("make_bundle_client: {}", e.what());
309 }
310 catch(...)
311 {
312 ossia::logger().error("make_bundle_client: unknown error");
313 }
314 ossia::buffer_pool::instance().release(std::move(ret.data));
315 return true;
316}
317}
The parameter_base class.
Definition ossia/network/base/parameter.hpp:48
The value class.
Definition value.hpp:173
spdlog::logger & logger() noexcept
Where the errors will be logged. Default is stderr.
Definition context.cpp:118
@ GET
The value can be retrieved and changed.
bool critical
Means that the node is very important, e.g. a "play" message.
Definition node_attributes.hpp:92
Full information about a parameter.
Definition parameter_data.hpp:61