stinger-ipc 0.0.10__py3-none-any.whl → 0.0.26__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {stinger_ipc-0.0.10.dist-info → stinger_ipc-0.0.26.dist-info}/METADATA +3 -2
- {stinger_ipc-0.0.10.dist-info → stinger_ipc-0.0.26.dist-info}/RECORD +35 -29
- stingeripc/asyncapi.py +3 -0
- stingeripc/components.py +61 -10
- stingeripc/schema/schema.yaml +240 -0
- stingeripc/templates/cpp/examples/client_main.cpp.jinja2 +18 -0
- stingeripc/templates/cpp/include/broker.hpp.jinja2 +18 -10
- stingeripc/templates/cpp/include/client.hpp.jinja2 +80 -11
- stingeripc/templates/cpp/include/ibrokerconnection.hpp.jinja2 +24 -4
- stingeripc/templates/cpp/include/property_structs.hpp.jinja2 +40 -2
- stingeripc/templates/cpp/include/server.hpp.jinja2 +5 -1
- stingeripc/templates/cpp/include/structs.hpp.jinja2 +2 -0
- stingeripc/templates/cpp/partials/args.jinja2 +11 -0
- stingeripc/templates/cpp/partials/deserialize.jinja2 +42 -0
- stingeripc/templates/cpp/partials/serialize.jinja2 +18 -0
- stingeripc/templates/cpp/src/broker.cpp.jinja2 +46 -24
- stingeripc/templates/cpp/src/client.cpp.jinja2 +111 -38
- stingeripc/templates/cpp/src/property_structs.cpp.jinja2 +25 -0
- stingeripc/templates/cpp/src/server.cpp.jinja2 +17 -25
- stingeripc/templates/cpp/src/structs.cpp.jinja2 +13 -0
- stingeripc/templates/html/app.js.jinja2 +130 -29
- stingeripc/templates/html/index.html.jinja2 +96 -8
- stingeripc/templates/html/styles.css.jinja2 +135 -0
- stingeripc/templates/markdown/index.md.jinja2 +151 -10
- stingeripc/templates/python/server.py.jinja2 +138 -18
- stingeripc/templates/rust/client/src/lib.rs.jinja2 +24 -5
- stingeripc/templates/rust/server/examples/server.rs.jinja2 +59 -23
- stingeripc/templates/rust/server/src/lib.rs.jinja2 +72 -51
- stingeripc/tools/cli.py +33 -7
- stingeripc/tools/cpp_generator.py +90 -0
- stingeripc/tools/rust_generator.py +1 -1
- stingeripc/templates/rust/payloads/src/handler.rs.jinja2 +0 -0
- {stinger_ipc-0.0.10.dist-info → stinger_ipc-0.0.26.dist-info}/WHEEL +0 -0
- {stinger_ipc-0.0.10.dist-info → stinger_ipc-0.0.26.dist-info}/entry_points.txt +0 -0
- {stinger_ipc-0.0.10.dist-info → stinger_ipc-0.0.26.dist-info}/licenses/LICENSE +0 -0
- {stinger_ipc-0.0.10.dist-info → stinger_ipc-0.0.26.dist-info}/top_level.txt +0 -0
@@ -1,25 +1,113 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html>
|
3
3
|
<head>
|
4
|
-
<title>
|
4
|
+
<title>{{stinger.title}} Web Interface</title>
|
5
5
|
<meta charset="UTF-8" />
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
7
7
|
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@7.2.96/css/materialdesignicons.min.css" rel="stylesheet" />
|
8
|
-
<link rel="stylesheet" href="./
|
8
|
+
<link rel="stylesheet" href="./styles.css" />
|
9
9
|
</head>
|
10
|
+
{%macro arglist(arg_list, model_parts, read_only) -%}
|
11
|
+
{%set modelpath %}{%for part in model_parts%}{%if not loop.first%}.{%endif%}{{part|snake_case}}{%endfor%}{%endset%}
|
12
|
+
<table class="arglist">
|
13
|
+
{%for arg in arg_list %}
|
14
|
+
<tr class="argrow">
|
15
|
+
<td class="arg-name-cell">
|
16
|
+
<div class="arg-name">{{ arg.name }}</div>
|
17
|
+
{%if arg.description %}
|
18
|
+
<div class="arg-description">{{ arg.description }}</div>
|
19
|
+
{%endif%}
|
20
|
+
</td>
|
21
|
+
<td class="arg-value-cell">
|
22
|
+
{%if arg.arg_type|lower == "argtype.primitive"%}
|
23
|
+
<input {%if read_only%}disabled {%endif%}type="text" ng-model="{{modelpath}}.{{arg.name}}" />
|
24
|
+
{%elif arg.arg_type|lower == "argtype.enum"%}
|
25
|
+
<select {%if read_only%}disabled {%endif%}ng-model="{{modelpath}}.{{arg.name}}" ng-options="n.id as n.name for n in enums.{{arg.enum.name|snake_case}}">
|
26
|
+
</select>
|
27
|
+
{%elif arg.arg_type|lower == "argtype.list"%}
|
28
|
+
<input {%if read_only%}disabled {%endif%}type="text" ng-model="{{modelpath}}.{{arg.name}}" placeholder="Comma-separated values" />
|
29
|
+
{%elif arg.arg_type|lower == "argtype.struct"%}
|
30
|
+
<div class="struct-arg">
|
31
|
+
{%set new_model_parts = model_parts + [arg.name] %}
|
32
|
+
{{ arglist(arg.members, new_model_parts, read_only) }}
|
33
|
+
</div>
|
34
|
+
{%else%}
|
35
|
+
<input {%if read_only%}disabled {%endif%}type="text" ng-model="{{modelpath}}.{{arg.name}}" placeholder="(unknown type)" />
|
36
|
+
{%endif%}
|
37
|
+
</td>
|
38
|
+
</tr>
|
39
|
+
{%endfor%}
|
40
|
+
</table>
|
41
|
+
{%- endmacro %}
|
10
42
|
<body ng-app="myApp" ng-controller="myCtrl">
|
11
43
|
<div class="infobox-background" ng-show="!online || showoutput" id="offline">Connecting</div>
|
44
|
+
|
45
|
+
<div class="interface-box">
|
46
|
+
<h1>{{stinger.title}}</h1>
|
47
|
+
<p id="interface-summary"><i>{{stinger.summary}}</i></p>
|
48
|
+
<p id="interface-doc">
|
49
|
+
{%markdown%}
|
50
|
+
{{stinger.documentation}}
|
51
|
+
{%endmarkdown%}
|
52
|
+
</p>
|
53
|
+
</div>
|
54
|
+
<!------------- SIGNALS ------------->
|
12
55
|
{%for sig_name, sig in stinger.signals.items() %}
|
13
|
-
<div class="signal-box" id="signal-box-{{ sig_name }}">
|
14
|
-
<h3 class="signal-title">{{ sig_name }}</h3>
|
15
|
-
<div class="signal-doc">{%if sig.documentation %}
|
56
|
+
<div class="component-box signal-box" id="signal-box-{{ sig_name }}">
|
57
|
+
<h3 class="component-title signal-title">Signal: {{ sig_name }}</h3>
|
58
|
+
<div class="component-doc signal-doc">{%if sig.documentation %}
|
16
59
|
{%markdown%}
|
17
60
|
{{ sig.documentation }}
|
18
61
|
{%endmarkdown%}
|
19
|
-
{%endif%}
|
20
|
-
|
62
|
+
{%endif%}
|
63
|
+
</div>
|
64
|
+
<div class="last-received signal-value">
|
65
|
+
{{ arglist(sig.arg_list, ['signals', sig_name, 'received'], true) | indent(8) }}
|
66
|
+
</div>
|
67
|
+
</div>
|
68
|
+
{%endfor%}{# end signals loop #}
|
69
|
+
|
70
|
+
<!------------- PROPERTIES ------------->
|
71
|
+
{%for prop_name, prop in stinger.properties.items() %}
|
72
|
+
<div class="component-box prop-box" id="prop-box-{{ prop_name }}">
|
73
|
+
<h3 class="component-title prop-title">Property: {{ prop_name }}</h3>
|
74
|
+
<div class="component-doc prop-doc">{%if prop.documentation %}
|
75
|
+
{%markdown%}
|
76
|
+
{{ prop.documentation }}
|
77
|
+
{%endmarkdown%}
|
78
|
+
{%endif%}
|
79
|
+
</div>
|
80
|
+
<div class="last-received property-value">
|
81
|
+
{{ arglist(prop.arg_list, ['properties', prop_name, 'received'], prop.read_only) | indent(8) }}
|
82
|
+
</div>
|
83
|
+
{%if not prop.read_only %}
|
84
|
+
<input type="button" class="publish-button" value="Update" ng-click="updateProperty(properties.{{ prop_name | snake_case }})" />
|
85
|
+
{%endif%}
|
21
86
|
</div>
|
22
|
-
{%endfor%}
|
87
|
+
{%endfor%} {# end properties loop #}
|
88
|
+
|
89
|
+
<!------------- METHODS ------------->
|
90
|
+
{%for method_name, method in stinger.methods.items() %}
|
91
|
+
<div class="component-box method-box" id="method-box-{{ method_name }}">
|
92
|
+
<h3 class="component-title method-title">Method: {{ method_name }}</h3>
|
93
|
+
<div class="component-doc method-doc">{%if method.documentation %}
|
94
|
+
{%markdown%}
|
95
|
+
{{ method.documentation }}
|
96
|
+
{%endmarkdown%}
|
97
|
+
{%endif%}
|
98
|
+
</div>
|
99
|
+
<div class="method-form-box">
|
100
|
+
<form ng-submit="callMethod(methods.{{method_name|snake_case}})">
|
101
|
+
{{ arglist(method.arg_list, ['methods', method_name, 'args'], false) | indent(8) }}
|
102
|
+
<button type="submit" class="publish-button">Call {{ method_name }}</button>
|
103
|
+
</form>
|
104
|
+
</div>
|
105
|
+
<div class="last-received method-response" ng-bind="methods['{{ method_name }}'].received">
|
106
|
+
{{ arglist(method.return_values, ['methods', method_name, 'received'], true) | indent(8) }}
|
107
|
+
</div>
|
108
|
+
</div>
|
109
|
+
{%endfor%} {# end methods loop #}
|
110
|
+
|
23
111
|
{%raw%}
|
24
112
|
<div id="console" ng-class="{ 'expanded' : (console.showing) }">
|
25
113
|
<div class="top" ng-click=" console.showing = !console.showing ">Request Console <span ng-show="console.showing && console.requests.length > 0" ng-click="console.requests = []"> - Clear</span>
|
@@ -184,4 +184,139 @@ body {
|
|
184
184
|
td input.ng-invalid.ng-dirty {
|
185
185
|
background-color: rgb(255, 152, 152);
|
186
186
|
}
|
187
|
+
|
188
|
+
.component-box {
|
189
|
+
border: 1.5px solid #b3c6e0;
|
190
|
+
border-radius: 12px;
|
191
|
+
padding: 18px 20px 14px 20px;
|
192
|
+
background: #f8fbff;
|
193
|
+
margin-bottom: 24px;
|
194
|
+
box-shadow: 0 2px 8px rgba(60, 80, 120, 0.06);
|
195
|
+
/* max-width: 420px; */ /* Remove this line */
|
196
|
+
width: 100%; /* Add this line */
|
197
|
+
box-sizing: border-box; /* Ensure padding/border included in width */
|
198
|
+
}
|
199
|
+
|
200
|
+
.component-title {
|
201
|
+
background: #3a6ea5;
|
202
|
+
color: #fff;
|
203
|
+
border-radius: 8px 8px 0 0;
|
204
|
+
margin: -18px -20px 12px -20px;
|
205
|
+
padding: 10px 18px;
|
206
|
+
font-size: 1.15em;
|
207
|
+
font-weight: 600;
|
208
|
+
letter-spacing: 0.5px;
|
209
|
+
}
|
210
|
+
|
211
|
+
.component-doc {
|
212
|
+
font-size: 0.96em;
|
213
|
+
font-style: italic;
|
214
|
+
color: #4a5a6a;
|
215
|
+
margin-bottom: 8px;
|
216
|
+
}
|
217
|
+
|
218
|
+
.component-doc p {
|
219
|
+
margin: 0 0 4px 0;
|
220
|
+
line-height: 1.3;
|
221
|
+
}
|
222
|
+
|
223
|
+
.last-signal-value {
|
224
|
+
margin-top: 10px;
|
225
|
+
font-weight: 500;
|
226
|
+
color: #2d4a6a;
|
227
|
+
}
|
228
|
+
|
229
|
+
table.arglist {
|
230
|
+
display: table;
|
231
|
+
width: 100%;
|
232
|
+
border-collapse: collapse;
|
233
|
+
}
|
234
|
+
tr.argrow {
|
235
|
+
display: table-row;
|
236
|
+
}
|
237
|
+
td.arg-name-cell {
|
238
|
+
display: table-cell;
|
239
|
+
vertical-align: top;
|
240
|
+
padding: 8px 10px;
|
241
|
+
width: 150px;
|
242
|
+
}
|
243
|
+
|
244
|
+
.arg-name {
|
245
|
+
font-weight: 600;
|
246
|
+
}
|
247
|
+
|
248
|
+
.arg-description {
|
249
|
+
font-size: 0.6em;
|
250
|
+
font-style: italic;
|
251
|
+
color: #817d83ff;
|
252
|
+
margin-top: 2px;
|
253
|
+
}
|
254
|
+
|
255
|
+
tr.argrow:not(:last-child) {
|
256
|
+
border-bottom: 1px solid #d6dbe8;
|
257
|
+
}
|
258
|
+
|
259
|
+
/* Publish button styling */
|
260
|
+
.publish-button {
|
261
|
+
appearance: none;
|
262
|
+
background: linear-gradient(135deg, #3a6ea5 0%, #427bb8 100%);
|
263
|
+
color: #fff;
|
264
|
+
border: 1px solid #2f5c89;
|
265
|
+
border-radius: 6px;
|
266
|
+
padding: 6px 14px 7px 14px;
|
267
|
+
font-size: 0.85em;
|
268
|
+
font-weight: 600;
|
269
|
+
letter-spacing: 0.4px;
|
270
|
+
cursor: pointer;
|
271
|
+
box-shadow: 0 2px 4px rgba(38, 62, 92, 0.18), 0 1px 0 rgba(255,255,255,0.25) inset;
|
272
|
+
text-shadow: 0 1px 1px rgba(0,0,0,0.25);
|
273
|
+
transition: background .18s ease, box-shadow .18s ease, transform .08s ease;
|
274
|
+
position: relative;
|
275
|
+
}
|
276
|
+
.publish-button:hover:not(:disabled) {
|
277
|
+
background: linear-gradient(135deg, #427bb8 0%, #4c89c9 100%);
|
278
|
+
box-shadow: 0 3px 7px rgba(38, 62, 92, 0.28), 0 1px 0 rgba(255,255,255,0.3) inset;
|
279
|
+
}
|
280
|
+
.publish-button:active:not(:disabled) {
|
281
|
+
background: #2f5c89;
|
282
|
+
transform: translateY(1px) scale(0.985);
|
283
|
+
box-shadow: 0 2px 4px rgba(38, 62, 92, 0.25) inset;
|
284
|
+
}
|
285
|
+
.publish-button:focus-visible {
|
286
|
+
outline: none;
|
287
|
+
box-shadow: 0 0 0 3px rgba(255,255,255,0.85), 0 0 0 5px rgba(58,110,165,0.55), 0 2px 4px rgba(38, 62, 92, 0.25);
|
288
|
+
}
|
289
|
+
.publish-button:disabled {
|
290
|
+
background: #b5c8da;
|
291
|
+
border-color: #9ab1c7;
|
292
|
+
color: #eef3f8;
|
293
|
+
cursor: not-allowed;
|
294
|
+
box-shadow: none;
|
295
|
+
text-shadow: none;
|
296
|
+
opacity: 0.85;
|
297
|
+
}
|
298
|
+
/* Subtle loading / pending state */
|
299
|
+
.publish-button.pending {
|
300
|
+
position: relative;
|
301
|
+
color: #eef6ff;
|
302
|
+
animation: pulse-bright 1.1s ease-in-out infinite;
|
303
|
+
}
|
304
|
+
@keyframes pulse-bright {
|
305
|
+
0% { box-shadow: 0 0 0 0 rgba(66,123,184,0.55); }
|
306
|
+
70% { box-shadow: 0 0 0 6px rgba(66,123,184,0); }
|
307
|
+
100% { box-shadow: 0 0 0 0 rgba(66,123,184,0); }
|
308
|
+
}
|
309
|
+
/* Optional subtle variant for destructive actions (not requested but available) */
|
310
|
+
.publish-button.danger {
|
311
|
+
background: linear-gradient(135deg, #b83f3f 0%, #c64d4d 100%);
|
312
|
+
border-color: #933131;
|
313
|
+
}
|
314
|
+
.publish-button.danger:hover:not(:disabled) {
|
315
|
+
background: linear-gradient(135deg, #c64d4d 0%, #d85b5b 100%);
|
316
|
+
}
|
317
|
+
.publish-button.danger:active:not(:disabled) {
|
318
|
+
background: #933131;
|
319
|
+
}
|
320
|
+
|
321
|
+
|
187
322
|
{%endraw%}
|
@@ -1,9 +1,12 @@
|
|
1
|
-
# _{{stinger.
|
1
|
+
# _{{stinger.title}}_ API Overview
|
2
2
|
{%-if stinger.summary %}
|
3
|
-
|
3
|
+
{{stinger.summary|italics}}
|
4
4
|
{%endif-%}
|
5
5
|
{%if stinger.documentation%}
|
6
6
|
{{stinger.documentation}}
|
7
|
+
{%endif%}
|
8
|
+
|
9
|
+
[[_TOC_]]
|
7
10
|
|
8
11
|
## Connections
|
9
12
|
|
@@ -25,6 +28,19 @@ The `connection_object` will be passed to client and server constructors.
|
|
25
28
|
|
26
29
|
</details>
|
27
30
|
|
31
|
+
<details>
|
32
|
+
<summary>Rust</summary>
|
33
|
+
|
34
|
+
```rust
|
35
|
+
use mqttier::MqttierClient;
|
36
|
+
|
37
|
+
MqttierClient::new("localhost", 1883, Some("mqtt_client_id".to_string())).expect("Failed to create MQTT client");
|
38
|
+
```
|
39
|
+
|
40
|
+
The `connection_object` will be passed to client and server constructors.
|
41
|
+
|
42
|
+
</details>
|
43
|
+
|
28
44
|
<details>
|
29
45
|
<summary>C++</summary>
|
30
46
|
|
@@ -55,25 +71,47 @@ server = {{stinger.python.server_class_name}}(connection_object)
|
|
55
71
|
|
56
72
|
The `server` object provides methods for emitting signals and updating properties. It also allows for decorators to indicate method call handlers.
|
57
73
|
|
74
|
+
A full example can be viewed by looking at the `if __name__ == "__main__":` section of the generated `{{stinger.python.package_name}}.server.py` module.
|
75
|
+
|
58
76
|
</details>
|
59
77
|
|
78
|
+
|
79
|
+
|
60
80
|
<details>
|
61
81
|
<summary>C++ Server</summary>
|
62
82
|
|
63
|
-
```
|
64
|
-
from connection import {{broker.class_name}}
|
83
|
+
```c++
|
65
84
|
|
66
|
-
conn = {{broker.class_name}}({%if broker.hostname is none%}'localhost', 1883{%endif%})
|
67
|
-
server = {{stinger.python.server_class_name}}(conn)
|
68
85
|
```
|
69
86
|
|
70
87
|
The `server` object provides methods for emitting signals and updating properties. It also allows for decorators to indicate method call handlers.
|
71
88
|
|
89
|
+
A full example can be viewed by looking at the generated `examples/server_main.cpp` file.`
|
90
|
+
|
72
91
|
</details>
|
73
92
|
|
74
93
|
## Client
|
75
94
|
|
76
|
-
|
95
|
+
A client is a _utilizer_ of functionality. It receives signals, makes method calls, reads property values, or requests updates to property values.
|
96
|
+
|
97
|
+
<details>
|
98
|
+
<summary>Rust</summary>
|
99
|
+
|
100
|
+
```rust
|
101
|
+
let {%if stinger.methods|length > 0%}mut {%endif%}api_client = {{stinger.rust.client_struct_name}}::new(&mut connection).await;
|
102
|
+
```
|
103
|
+
|
104
|
+
A full example can be viewed by looking at the generated `client/examples/client.rs` file.
|
105
|
+
|
106
|
+
</details>
|
107
|
+
|
108
|
+
<details>
|
109
|
+
<summary>C++ Client</summary>
|
110
|
+
|
111
|
+
A full example can be viewed by looking at the generated `examples/client_main.cpp` file.
|
112
|
+
|
113
|
+
</details>
|
114
|
+
|
77
115
|
{%macro argrow(arg) -%}
|
78
116
|
|{{arg.name|center(15)}}|
|
79
117
|
{%-if arg.arg_type.name.lower() == "enum" or arg.arg_type.name.lower() == "struct"%}{{arg.markdown_type|center(10)}}
|
@@ -91,7 +129,7 @@ The `server` object provides methods for emitting signals and updating propertie
|
|
91
129
|
{%if stinger.signals | length > 0 %}
|
92
130
|
## Signals
|
93
131
|
|
94
|
-
Signals are messages from
|
132
|
+
Signals are messages from a server to clients.
|
95
133
|
|
96
134
|
```plantuml
|
97
135
|
@startuml
|
@@ -112,6 +150,8 @@ Client <<- Server : Signal(Parameters)
|
|
112
150
|
<details>
|
113
151
|
<summary>Python Client</summary>
|
114
152
|
|
153
|
+
The `{{sig_name}}` signal can be subscribed to by using the client's `receive_{{sig_name | snake_case }}` decorator on a callback function. The name of the function does not matter. The function is called any time the signal is received.
|
154
|
+
|
115
155
|
```python
|
116
156
|
@client.receive_{{sig_name | snake_case }}
|
117
157
|
def on_{{sig_name | snake_case }}({%for arg in signal.arg_list%}{{arg.name}}: {{arg.python_type}}{%if not loop.last%}, {%endif%}{%endfor%}):
|
@@ -120,15 +160,67 @@ def on_{{sig_name | snake_case }}({%for arg in signal.arg_list%}{{arg.name}}: {{
|
|
120
160
|
|
121
161
|
</details>
|
122
162
|
|
163
|
+
<details>
|
164
|
+
<summary>Python Server</summary>
|
165
|
+
|
166
|
+
A server can emit a `{{sig_name}}` signal simply by calling the server's `emit_{{sig_name | snake_case}}` method.
|
167
|
+
|
168
|
+
```python
|
169
|
+
server.emit_{{sig_name | snake_case}}({%for arg in signal.arg_list%}{{arg.get_random_example_value(lang="python")}}{%if not loop.last%}, {%endif%}{%endfor%})
|
170
|
+
```
|
171
|
+
|
172
|
+
</details>
|
173
|
+
|
174
|
+
<details>
|
175
|
+
<summary>Rust Client</summary>
|
176
|
+
|
177
|
+
A Rust client receives signals through a `tokio::broadcast` channel. Receiving from the channel returns a `Result<T, RecvError>` object.
|
178
|
+
|
179
|
+
Since receiving a message through the channel blocks, it may be best to put this into a separate async task.
|
180
|
+
|
181
|
+
```rust
|
182
|
+
let mut {{sig_name|snake_case}}_signal_rx = client.get_{{sig_name|snake_case}}_receiver();
|
183
|
+
print("Got a '{{sig_name}}' signal: {:?}", {{sig_name|snake_case}}_signal_rx.recv().await);
|
184
|
+
```
|
185
|
+
|
186
|
+
</details>
|
187
|
+
|
123
188
|
<details>
|
124
189
|
<summary>Rust Server</summary>
|
125
190
|
|
191
|
+
A server can emit a `{{sig_name}}` signal simply by calling the server's `emit_{{sig_name | snake_case}}` method.
|
192
|
+
|
126
193
|
```rust
|
127
194
|
server.emit_{{sig_name|snake_case}}({%for arg in signal.arg_list%}{{arg.get_random_example_value(lang="rust")}}{%if not loop.last%}, {%endif%}{%endfor%}).await;
|
128
195
|
```
|
129
196
|
|
130
197
|
</details>
|
131
198
|
|
199
|
+
<details>
|
200
|
+
<summary>C++ Client</summary>
|
201
|
+
|
202
|
+
A client can register a callback function to be called when a `{{sig_name}}` signal is received. The callback function should take the same parameters as the signal. In this example, we are using a lambda as the callback function.
|
203
|
+
|
204
|
+
```cpp
|
205
|
+
client.register{{sig_name | UpperCamelCase}}Callback([]({%for arg in signal.arg_list%}{{arg.cpp_type}} {{arg.name}}{%if not loop.last%}, {%endif%}{%endfor%}) {
|
206
|
+
std::cout << {%for arg in signal.arg_list%}"{{arg.name}}=" << {%-if arg.optional%} "None"{%else%}{%if arg.arg_type.name.lower() == 'enum'%}{{arg.enum.name | camelCase }}Strings[static_cast<int>({{arg.name}})]{%else%}{{arg.name}}{%endif%}{%endif%} << {%if not loop.last %}" | " << {%endif%}{%endfor%} std::endl;
|
207
|
+
});
|
208
|
+
```
|
209
|
+
|
210
|
+
</details>
|
211
|
+
|
212
|
+
<details>
|
213
|
+
<summary>C++ Server</summary>
|
214
|
+
|
215
|
+
A `{{sig_name}}` signal can be emitted by calling the server's `emit{{sig_name | UpperCamelCase}}Signal` method. This returns a `std::future` that can be waited on if desired. The future is resolved when the signal is sent.
|
216
|
+
|
217
|
+
```cpp
|
218
|
+
auto {{sig_name|lowerCamelCase}}Future = server.emit{{sig_name | UpperCamelCase}}Signal({%for arg in signal.arg_list%}{{arg.get_random_example_value(lang="c++")}}{%if not loop.last%}, {%endif%}{%endfor%});
|
219
|
+
{{sig_name|lowerCamelCase}}Future.wait(); // Optional, to block until signal is sent.
|
220
|
+
```
|
221
|
+
|
222
|
+
</details>
|
223
|
+
|
132
224
|
{%endfor%}{#- end for each signal -#}
|
133
225
|
{%endif%}{#- end if there are signals -#}
|
134
226
|
|
@@ -165,6 +257,55 @@ There is no return value for this method call.
|
|
165
257
|
{%else-%}
|
166
258
|
The return value type is `{{method.return_value.json_type}}`.
|
167
259
|
{%endif-%}
|
260
|
+
|
261
|
+
#### Code Examples
|
262
|
+
|
263
|
+
<details>
|
264
|
+
<summary>Python Client</summary>
|
265
|
+
|
266
|
+
The `{{method_name}}` method can be called by calling the clients's `{{method_name|snake_case}}` method.
|
267
|
+
This returns a `Future` object. In this example, we wait up to 5 seconds for the result.
|
268
|
+
|
269
|
+
```python
|
270
|
+
from futures import Future
|
271
|
+
|
272
|
+
future = client.{{method_name|snake_case}}({%for arg in method.arg_list%}{{arg.name}}={{arg.get_random_example_value()}}{%if not loop.last%}, {%endif%}{%endfor%})
|
273
|
+
try:
|
274
|
+
print(f"RESULT: {future.result(5)}")
|
275
|
+
except futures.TimeoutError:
|
276
|
+
print(f"Timed out waiting for response to '{{method_name|snake_case}}' call")
|
277
|
+
```
|
278
|
+
|
279
|
+
</details>
|
280
|
+
|
281
|
+
<details>
|
282
|
+
<summary>Python Server</summary>
|
283
|
+
|
284
|
+
The server provides an implementation for the `{{method_name}}` method by using the `@server.handle_{{method_name|snake_case}}` decorator on a function. The name of the function does not matter.
|
285
|
+
The decorated method is called everytime the a request for the method is received. In an error, the method can raise on of the exceptions found in `method_codes.py`.
|
286
|
+
|
287
|
+
```python
|
288
|
+
@server.handle_{{method_name | snake_case}}
|
289
|
+
def {{method_name | snake_case}}({%for arg in method.arg_list%}{{arg.name}}: {{arg.python_type}}{%if not loop.last%}, {%endif%}{%endfor%}) -> {{method.return_value_python_type}}:
|
290
|
+
""" This is an example handler for the '{{method_name}}' method. """
|
291
|
+
print(f"Running {{method_name | snake_case}}'({%for arg in method.arg_list %}{ {{-arg.name-}} }{%if not loop.last%}, {%endif%}{%endfor%})'")
|
292
|
+
return {{method.get_return_value_random_example_value('python')}}
|
293
|
+
```
|
294
|
+
|
295
|
+
</details>
|
296
|
+
|
297
|
+
<details>
|
298
|
+
<summary>Rust Client</summary>
|
299
|
+
|
300
|
+
The `{{stinger.rust.client_struct_name}}` provides an implementation for the `{{method_name}}` method. It will block and return a Result object of either the return payload value, or an error.
|
301
|
+
|
302
|
+
```rust
|
303
|
+
let result = api_client.{{method_name | snake_case}}({%for arg in method.arg_list%}{{arg.get_random_example_value(lang='rust')}}{%if not loop.last%}, {%endif%}{%endfor%}).await.expect("Failed to call {{method_name}}");
|
304
|
+
println!("{{method_name}} response: {:?}", result);
|
305
|
+
```
|
306
|
+
|
307
|
+
</details>
|
308
|
+
|
168
309
|
{%endfor-%}
|
169
310
|
{%endif%}
|
170
311
|
{#- ------------------------------------------------------- #}
|
@@ -198,8 +339,8 @@ This property is **read-only**. It can only be modified by the server.{%endif%}
|
|
198
339
|
|
199
340
|
{%for value in ie.values -%}
|
200
341
|
* {{value}} ({{loop.index}})
|
201
|
-
{%- if ie.
|
202
|
-
- {{ie.
|
342
|
+
{%- if ie.value_description(loop.index) %}
|
343
|
+
- {{ie.value_description(loop.index)}}{% endif %}
|
203
344
|
{%endfor%}
|
204
345
|
{%endfor%}
|
205
346
|
{#- ------------------------------------------------------- #}
|