stinger-ipc 0.0.5__py3-none-any.whl → 0.0.8__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.5.dist-info → stinger_ipc-0.0.8.dist-info}/METADATA +2 -2
- {stinger_ipc-0.0.5.dist-info → stinger_ipc-0.0.8.dist-info}/RECORD +27 -23
- {stinger_ipc-0.0.5.dist-info → stinger_ipc-0.0.8.dist-info}/entry_points.txt +1 -0
- stingeripc/components.py +5 -5
- stingeripc/lang_symb.py +21 -4
- stingeripc/templates/html/app.js.jinja2 +125 -0
- stingeripc/templates/html/index.html.jinja2 +43 -0
- stingeripc/templates/html/styles.css.jinja2 +187 -0
- stingeripc/templates/rust/Cargo.toml.jinja2 +1 -1
- stingeripc/templates/rust/client/Cargo.toml.jinja2 +7 -5
- stingeripc/templates/rust/client/examples/client.rs.jinja2 +9 -10
- stingeripc/templates/rust/client/src/lib.rs.jinja2 +112 -55
- stingeripc/templates/rust/{connection → payloads}/Cargo.toml.jinja2 +8 -4
- stingeripc/templates/rust/{connection → payloads}/examples/pub_and_recv.rs.jinja2 +11 -11
- stingeripc/templates/rust/payloads/src/lib.rs.jinja2 +4 -0
- stingeripc/templates/rust/{connection → payloads}/src/payloads.rs.jinja2 +10 -2
- stingeripc/templates/rust/server/Cargo.toml.jinja2 +4 -4
- stingeripc/templates/rust/server/examples/server.rs.jinja2 +8 -12
- stingeripc/templates/rust/server/src/lib.rs.jinja2 +92 -69
- stingeripc/tools/cli.py +73 -0
- stingeripc/tools/markdown_generator.py +4 -2
- stingeripc/tools/python_generator.py +12 -10
- stingeripc/tools/rust_generator.py +46 -27
- stingeripc/templates/rust/connection/src/lib.rs.jinja2 +0 -262
- {stinger_ipc-0.0.5.dist-info → stinger_ipc-0.0.8.dist-info}/WHEEL +0 -0
- {stinger_ipc-0.0.5.dist-info → stinger_ipc-0.0.8.dist-info}/licenses/LICENSE +0 -0
- {stinger_ipc-0.0.5.dist-info → stinger_ipc-0.0.8.dist-info}/top_level.txt +0 -0
- /stingeripc/templates/rust/{connection → payloads}/src/handler.rs.jinja2 +0 -0
@@ -5,20 +5,20 @@ on the next generation.
|
|
5
5
|
This is the Client for the {{stinger.name}} interface.
|
6
6
|
*/
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
use json::{JsonValue};
|
8
|
+
use mqttier::{MqttierClient, ReceivedMessage};
|
9
|
+
{%if stinger.methods|length > 0 -%}
|
12
10
|
use std::collections::HashMap;
|
11
|
+
use json::JsonValue;
|
13
12
|
use uuid::Uuid;
|
13
|
+
{%endif-%}
|
14
14
|
use serde_json;
|
15
15
|
|
16
|
+
|
16
17
|
#[allow(unused_imports)]
|
17
|
-
use
|
18
|
+
use {{stinger.rust.common_package_name}}::{MethodResultCode, *};
|
18
19
|
|
19
20
|
use std::sync::{Arc, Mutex};
|
20
|
-
use tokio::sync::{
|
21
|
-
use tokio::join;
|
21
|
+
use tokio::sync::{broadcast, mpsc{%if stinger.methods|length > 0 -%}, oneshot{%endif-%}};
|
22
22
|
use tokio::task::JoinError;
|
23
23
|
|
24
24
|
/// This struct is used to store all the MQTTv5 subscription ids
|
@@ -26,16 +26,19 @@ use tokio::task::JoinError;
|
|
26
26
|
#[derive(Clone, Debug)]
|
27
27
|
struct {{stinger.name | UpperCamelCase }}SubscriptionIds {
|
28
28
|
{%for method_name, method in stinger.methods.items()-%}
|
29
|
-
{{method_name | snake_case}}_method_resp:
|
30
|
-
{
|
29
|
+
{{method_name | snake_case}}_method_resp: usize,
|
30
|
+
{%endfor%}
|
31
31
|
{%for sig_name, sig in stinger.signals.items()-%}
|
32
|
-
{{sig_name | snake_case}}_signal: Option<
|
32
|
+
{{sig_name | snake_case}}_signal: Option<usize>,
|
33
33
|
{%-endfor%}
|
34
|
+
{%for prop_name, prop in stinger.properties.items()-%}
|
35
|
+
{{prop_name | snake_case}}_property_value: usize,
|
36
|
+
{%endfor%}
|
34
37
|
}
|
35
38
|
|
36
39
|
/// This struct holds the tx side of a broadcast channels used when receiving signals.
|
37
40
|
/// The rx side of the broadcast channels can be created from the tx side later.
|
38
|
-
/// When {{stinger.
|
41
|
+
/// When {{stinger.rust.client_struct_name}} gets a message and determines that it
|
39
42
|
/// is a signal, it will send the signal payload via the tx channel that is in this struct.
|
40
43
|
#[derive(Clone)]
|
41
44
|
struct {{stinger.name | UpperCamelCase }}SignalChannels {
|
@@ -44,61 +47,90 @@ struct {{stinger.name | UpperCamelCase }}SignalChannels {
|
|
44
47
|
{%endfor%}
|
45
48
|
}
|
46
49
|
|
50
|
+
{%if stinger.properties | length > 0%}
|
51
|
+
#[derive(Clone)]
|
52
|
+
pub struct {{stinger.name | UpperCamelCase}}Properties {
|
53
|
+
{%for prop_name, prop in stinger.properties.items()-%}
|
54
|
+
{%-if prop.arg_list | length > 1%}
|
55
|
+
pub {{prop_name | snake_case}}: Arc<Mutex<Option<{{prop.rust_type}}>>>,
|
56
|
+
{%-else%}
|
57
|
+
pub {{prop_name | snake_case}}: Arc<Mutex<Option<{{prop.arg_list[0].rust_type}}>>>,
|
58
|
+
{%endif%}
|
59
|
+
{%-endfor%}
|
60
|
+
}
|
61
|
+
{%endif%}
|
62
|
+
|
47
63
|
/// This is the struct for our API client.
|
48
|
-
|
64
|
+
#[derive(Clone)]
|
65
|
+
pub struct {{stinger.rust.client_struct_name}} {
|
66
|
+
mqttier_client: MqttierClient,
|
49
67
|
{%if stinger.methods | length > 0 %}/// Temporarily holds oneshot channels for responses to method calls.
|
50
|
-
pending_responses: Arc<Mutex<HashMap
|
68
|
+
pending_responses: Arc<Mutex<HashMap<Uuid, oneshot::Sender<JsonValue>>>>,
|
51
69
|
{%endif%}
|
52
70
|
|
53
71
|
/// Temporarily holds the receiver for the MPSC channel. The Receiver will be moved
|
54
72
|
/// to a process loop when it is needed. MQTT messages will be received with this.
|
55
|
-
msg_streamer_rx: Option<mpsc::Receiver<ReceivedMessage
|
73
|
+
msg_streamer_rx: Arc<Mutex<Option<mpsc::Receiver<ReceivedMessage>>>>,
|
56
74
|
|
57
75
|
/// The Sender side of MQTT messages that are received from the broker. This tx
|
58
76
|
/// side is cloned for each subscription made.
|
77
|
+
#[allow(dead_code)]
|
59
78
|
msg_streamer_tx: mpsc::Sender<ReceivedMessage>,
|
60
|
-
|
61
|
-
|
62
|
-
|
79
|
+
{%if stinger.properties|length > 0%}
|
80
|
+
/// Struct contains all the properties.
|
81
|
+
pub properties: {{stinger.name | UpperCamelCase}}Properties,
|
63
82
|
{%endif%}
|
64
83
|
/// Contains all the MQTTv5 subscription ids.
|
65
84
|
subscription_ids: {{stinger.name | UpperCamelCase }}SubscriptionIds,
|
66
85
|
|
67
|
-
{
|
86
|
+
{%-if stinger.signals | length > 0 %}
|
87
|
+
/// Holds the channels used for sending signals to the application.
|
68
88
|
signal_channels: {{stinger.name | UpperCamelCase }}SignalChannels,
|
69
89
|
{%endif%}
|
70
90
|
/// Copy of MQTT Client ID
|
71
|
-
client_id: String,
|
91
|
+
pub client_id: String,
|
72
92
|
}
|
73
93
|
|
74
|
-
impl {{stinger.
|
94
|
+
impl {{stinger.rust.client_struct_name}} {
|
75
95
|
|
76
|
-
/// Creates a new {{stinger.
|
77
|
-
pub async fn new(connection: &mut
|
78
|
-
let _ = connection.connect().await.expect("Could not connect to MQTT broker");
|
96
|
+
/// Creates a new {{stinger.rust.client_struct_name}} that uses an MqttierClient.
|
97
|
+
pub async fn new(connection: &mut MqttierClient) -> Self {
|
79
98
|
|
80
|
-
// Create a channel for messages to get from the Connection object to this {{stinger.
|
99
|
+
// Create a channel for messages to get from the Connection object to this {{stinger.rust.client_struct_name}} object.
|
81
100
|
// The Connection object uses a clone of the tx side of the channel.
|
82
101
|
let (message_received_tx, message_received_rx) = mpsc::channel(64);
|
83
102
|
|
84
|
-
{%if stinger.methods | length > 0 %}// Create the publisher object.
|
85
|
-
let publisher = connection.get_publisher();
|
86
|
-
|
87
|
-
// Subscribe to all the topics needed for method responses.
|
88
|
-
{%endif-%}
|
89
103
|
{%for method_name, method in stinger.methods.items()-%}
|
90
104
|
let topic_{{method_name | snake_case}}_method_resp = format!("{{method.response_topic('{}')}}", connection.client_id);
|
91
|
-
let subscription_id_{{method_name | snake_case}}_method_resp = connection.subscribe(
|
92
|
-
let subscription_id_{{method_name | snake_case}}_method_resp = subscription_id_{{method_name | snake_case}}_method_resp.unwrap_or_else(|_|
|
105
|
+
let subscription_id_{{method_name | snake_case}}_method_resp = connection.subscribe(topic_{{method_name | snake_case}}_method_resp, 2, message_received_tx.clone()).await;
|
106
|
+
let subscription_id_{{method_name | snake_case}}_method_resp = subscription_id_{{method_name | snake_case}}_method_resp.unwrap_or_else(|_| usize::MAX);
|
93
107
|
{%endfor%}
|
94
108
|
|
95
109
|
// Subscribe to all the topics needed for signals.
|
96
110
|
{%for signal_name, signal in stinger.signals.items()-%}
|
97
|
-
let topic_{{signal_name | snake_case}}_signal = "{{signal.topic}}";
|
98
|
-
let subscription_id_{{signal_name | snake_case}}_signal = connection.subscribe(
|
99
|
-
let subscription_id_{{signal_name | snake_case}}_signal = subscription_id_{{signal_name | snake_case}}_signal.unwrap_or_else(|_|
|
111
|
+
let topic_{{signal_name | snake_case}}_signal = "{{signal.topic}}".to_string();
|
112
|
+
let subscription_id_{{signal_name | snake_case}}_signal = connection.subscribe(topic_{{signal_name | snake_case}}_signal, 2, message_received_tx.clone()).await;
|
113
|
+
let subscription_id_{{signal_name | snake_case}}_signal = subscription_id_{{signal_name | snake_case}}_signal.unwrap_or_else(|_| usize::MAX);
|
100
114
|
{%endfor%}
|
101
115
|
|
116
|
+
// Subscribe to all the topics needed for properties.
|
117
|
+
{% for prop_name, prop in stinger.properties.items() %}
|
118
|
+
let topic_{{prop_name | snake_case}}_property_value = "{{prop.value_topic}}".to_string();
|
119
|
+
let subscription_id_{{prop_name | snake_case}}_property_value = connection.subscribe(topic_{{prop_name | snake_case}}_property_value, 1, message_received_tx.clone()).await;
|
120
|
+
let subscription_id_{{prop_name | snake_case}}_property_value = subscription_id_{{prop_name | snake_case}}_property_value.unwrap_or_else(|_| usize::MAX);
|
121
|
+
{% endfor %}
|
122
|
+
|
123
|
+
{%if stinger.properties|length > 0%}
|
124
|
+
let property_values = {{stinger.name | UpperCamelCase}}Properties {
|
125
|
+
{%-for prop_name, prop in stinger.properties.items()%}
|
126
|
+
{%if prop.arg_list | length > 1 -%}
|
127
|
+
{{prop_name | snake_case}}: Arc::new(Mutex::new(None)),
|
128
|
+
{%else%}
|
129
|
+
{{prop_name | snake_case}}: Arc::new(Mutex::new(None)),
|
130
|
+
{%-endif%}
|
131
|
+
{%-endfor%}
|
132
|
+
};
|
133
|
+
{%endif%}
|
102
134
|
// Create structure for subscription ids.
|
103
135
|
let sub_ids = {{stinger.name | UpperCamelCase }}SubscriptionIds {
|
104
136
|
{%for method_name, method in stinger.methods.items()-%}
|
@@ -107,6 +139,9 @@ impl {{stinger.name | UpperCamelCase }}Client {
|
|
107
139
|
{%-for sig_name, sig in stinger.signals.items()-%}
|
108
140
|
{{sig_name | snake_case}}_signal: Some(subscription_id_{{sig_name | snake_case}}_signal),
|
109
141
|
{%endfor%}
|
142
|
+
{%-for prop_name, prop in stinger.properties.items()-%}
|
143
|
+
{{prop_name | snake_case}}_property_value: subscription_id_{{prop_name | snake_case}}_property_value,
|
144
|
+
{%endfor%}
|
110
145
|
};
|
111
146
|
|
112
147
|
{%if stinger.signals | length > 0 %}// Create structure for the tx side of broadcast channels for signals.
|
@@ -116,12 +151,15 @@ impl {{stinger.name | UpperCamelCase }}Client {
|
|
116
151
|
{%endfor%}
|
117
152
|
};{%endif%}
|
118
153
|
|
119
|
-
// Create {{stinger.
|
120
|
-
let inst = {{stinger.
|
154
|
+
// Create {{stinger.rust.client_struct_name}} structure.
|
155
|
+
let inst = {{stinger.rust.client_struct_name}} {
|
156
|
+
mqttier_client: connection.clone(),
|
121
157
|
{%if stinger.methods | length > 0 %}pending_responses: Arc::new(Mutex::new(HashMap::new())),{%endif%}
|
122
|
-
msg_streamer_rx: Some(message_received_rx),
|
158
|
+
msg_streamer_rx: Arc::new(Mutex::new(Some(message_received_rx))),
|
123
159
|
msg_streamer_tx: message_received_tx,
|
124
|
-
{%if stinger.
|
160
|
+
{%if stinger.properties|length > 0 %}
|
161
|
+
properties: property_values,
|
162
|
+
{%endif%}
|
125
163
|
subscription_ids: sub_ids,
|
126
164
|
{%if stinger.signals | length > 0 %}signal_channels: signal_channels,{%endif%}
|
127
165
|
client_id: connection.client_id.to_string(),
|
@@ -143,23 +181,24 @@ impl {{stinger.name | UpperCamelCase }}Client {
|
|
143
181
|
/// and published to the `{{method.topic}}` MQTT topic.
|
144
182
|
///
|
145
183
|
/// This method awaits on the response to the call before returning.
|
146
|
-
pub async fn {{method_name|snake_case}}(&mut self, {%for arg in method.arg_list%}{{arg.name|snake_case}}: {{arg.rust_type}}{%if not loop.last%}, {%endif%}{%endfor%})->Result<{{method.return_value_rust_type}}, MethodResultCode> {
|
184
|
+
pub async fn {{method_name|snake_case}}(&mut self{%if method.arg_list | length > 0 %}, {%endif%}{%for arg in method.arg_list%}{{arg.name|snake_case}}: {{arg.rust_type}}{%if not loop.last%}, {%endif%}{%endfor%})->Result<{{method.return_value_rust_type}}, MethodResultCode> {
|
147
185
|
let correlation_id = Uuid::new_v4();
|
186
|
+
let correlation_data = correlation_id.as_bytes().to_vec();
|
148
187
|
let (sender, receiver) = oneshot::channel();
|
149
188
|
{
|
150
189
|
let mut hashmap = self.pending_responses.lock().expect("Mutex was poisoned");
|
151
190
|
hashmap.insert(correlation_id.clone(), sender);
|
152
191
|
}
|
153
192
|
|
154
|
-
let data =
|
193
|
+
let data = {{method_name | UpperCamelCase}}RequestObject {
|
155
194
|
{%-for arg in method.arg_list%}
|
156
195
|
{{arg.name}}: {{arg.name|snake_case}},
|
157
196
|
{%-endfor%}
|
158
197
|
};
|
159
198
|
|
160
|
-
let response_topic = format!("{{method.response_topic('{}')}}", self.client_id);
|
161
|
-
let _ = self.
|
162
|
-
let resp_obj = receiver.await.unwrap();
|
199
|
+
let response_topic: String = format!("{{method.response_topic('{}')}}", self.client_id);
|
200
|
+
let _ = self.mqttier_client.publish_request("{{method.topic}}".to_string(), &data, response_topic, correlation_data).await;
|
201
|
+
let {%if method.return_value_type is false %}_{%endif%}resp_obj = receiver.await.unwrap();
|
163
202
|
|
164
203
|
{%-if method.return_value_type == 'primitive' %}
|
165
204
|
Ok(resp_obj["{{method.return_value_property_name}}"].as_{{method.return_value_rust_type}}().unwrap())
|
@@ -201,43 +240,61 @@ impl {{stinger.name | UpperCamelCase }}Client {
|
|
201
240
|
let oss: oneshot::Sender<JsonValue> = sender;
|
202
241
|
match oss.send(payload_object) {
|
203
242
|
Ok(_) => (),
|
204
|
-
Err(_) => ()
|
243
|
+
Err(_) => (),
|
205
244
|
}
|
206
|
-
}
|
207
|
-
None => ()
|
245
|
+
}
|
246
|
+
None => (),
|
208
247
|
}
|
209
248
|
}
|
210
249
|
}
|
211
250
|
{%endfor%}
|
212
251
|
|
213
252
|
/// Starts the tasks that process messages received.
|
214
|
-
pub async fn
|
253
|
+
pub async fn run_loop(&self) -> Result<(), JoinError> {
|
254
|
+
// Make sure the MqttierClient is connected and running.
|
255
|
+
let _ = self.mqttier_client.run_loop().await;
|
256
|
+
|
215
257
|
{%if stinger.methods | length > 0%}// Clone the Arc pointer to the map. This will be moved into the loop_task.
|
216
258
|
let resp_map: Arc<Mutex<HashMap::<Uuid, oneshot::Sender::<JsonValue>>>> = self.pending_responses.clone();
|
217
259
|
{%endif%}
|
218
260
|
// Take ownership of the RX channel that receives MQTT messages. This will be moved into the loop_task.
|
219
|
-
let mut message_receiver =
|
261
|
+
let mut message_receiver = {
|
262
|
+
let mut guard = self.msg_streamer_rx.lock().expect("Mutex was poisoned");
|
263
|
+
guard.take().expect("msg_streamer_rx should be Some")
|
264
|
+
};
|
220
265
|
|
221
266
|
let sig_chans = self.signal_channels.clone();
|
222
267
|
let sub_ids = self.subscription_ids.clone();
|
223
|
-
|
224
|
-
let
|
268
|
+
{%-if stinger.properties|length > 0%}
|
269
|
+
let props = self.properties.clone();
|
270
|
+
{%endif%}
|
271
|
+
let _loop_task = tokio::spawn(async move {
|
225
272
|
while let Some(msg) = message_receiver.recv().await {
|
226
|
-
|
227
|
-
let
|
228
|
-
let
|
273
|
+
{% if stinger.methods|length > 0 %}
|
274
|
+
let opt_corr_data: Option<Vec<u8>> = msg.correlation_data.clone();
|
275
|
+
let opt_corr_id: Option<Uuid> = opt_corr_data.and_then(|b| Uuid::from_slice(b.as_slice()).ok());
|
276
|
+
|
277
|
+
let payload = String::from_utf8_lossy(&msg.payload).to_string();
|
229
278
|
{%-for method_name, method in stinger.methods.items()%}
|
230
279
|
{%if not loop.first%}else {%endif%}if msg.subscription_id == sub_ids.{{method_name | snake_case}}_method_resp {
|
231
|
-
{{stinger.
|
280
|
+
{{stinger.rust.client_struct_name}}::handle_{{method_name|snake_case}}_response(resp_map.clone(), payload, opt_corr_id);
|
232
281
|
}
|
233
282
|
{%-endfor%}
|
283
|
+
{%endif%}
|
234
284
|
{%-for signal_name, signal in stinger.signals.items()%}
|
235
285
|
{%if not loop.first%}else {%endif%}if msg.subscription_id == sub_ids.{{signal_name | snake_case}}_signal.unwrap_or_default() {
|
236
286
|
let chan = sig_chans.{{signal_name | snake_case}}_sender.clone();
|
237
|
-
let pl:
|
287
|
+
let pl: {{signal_name | UpperCamelCase}}SignalPayload = serde_json::from_slice(&msg.payload).expect("Failed to deserialize");
|
238
288
|
let _send_result = chan.send(pl);
|
239
289
|
}
|
240
290
|
{%endfor%}
|
291
|
+
{%-for prop_name, prop in stinger.properties.items()%}
|
292
|
+
{%if not loop.first%}else {%endif%}if msg.subscription_id == sub_ids.{{prop_name | snake_case}}_property_value {
|
293
|
+
let pl: {{prop.rust_type}} = serde_json::from_slice(&msg.payload).expect("Failed to deserialize");
|
294
|
+
let mut guard = props.{{prop_name | snake_case}}.lock().expect("Mutex was poisoned");
|
295
|
+
*guard = Some(pl);
|
296
|
+
}
|
297
|
+
{%endfor%}
|
241
298
|
}
|
242
299
|
});
|
243
300
|
|
@@ -1,11 +1,11 @@
|
|
1
1
|
[package]
|
2
|
-
name = "
|
3
|
-
version = "
|
2
|
+
name = "{{stinger.rust.common_package_name}}"
|
3
|
+
version = "{{stinger.version}}"
|
4
4
|
edition = "2024"
|
5
5
|
|
6
6
|
[dependencies]
|
7
7
|
futures = "0.3.31"
|
8
|
-
|
8
|
+
mqttier = { git = "https://github.com/stinger-ipc/mqttier.git" }
|
9
9
|
serde = { version = "1.0.219", features = ["derive"] }
|
10
10
|
serde_json = "1.0.142"
|
11
11
|
tokio = { version = "1", features = ["full"] }
|
@@ -18,4 +18,8 @@ features = [
|
|
18
18
|
"v4", # Lets you generate random UUIDs
|
19
19
|
"fast-rng", # Use a faster (but still sufficiently random) RNG
|
20
20
|
"macro-diagnostics", # Enable better diagnostics for compile-time UUIDs
|
21
|
-
]
|
21
|
+
]
|
22
|
+
|
23
|
+
[[example]]
|
24
|
+
name = "{{stinger.name | snake_case}}_connection_demo"
|
25
|
+
path = "examples/pub_and_recv.rs"
|
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
use
|
2
|
+
use mqttier::MqttierClient;
|
3
3
|
use tokio::time::{sleep, Duration};
|
4
4
|
use tokio::join;
|
5
5
|
use tokio::sync::mpsc;
|
@@ -7,26 +7,26 @@ use tokio::sync::mpsc;
|
|
7
7
|
#[tokio::main]
|
8
8
|
async fn main() {
|
9
9
|
{%set broker = stinger.get_example_broker()%}
|
10
|
-
|
10
|
+
println!("Starting pub and recv example");
|
11
|
+
let client = MqttierClient::new("localhost", 1883, None).unwrap();
|
11
12
|
let (recv_chan_tx, mut recv_chan_rx) = mpsc::channel(32);
|
12
|
-
|
13
|
-
connection.subscribe("example/recv_topic", recv_chan_tx.clone()).await.expect("Failed to subscribe to topic");
|
14
|
-
let mut publisher = connection.get_publisher();
|
13
|
+
client.subscribe("example/recv_topic".to_string(), 1, recv_chan_tx.clone()).await.expect("Failed to subscribe to topic");
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
});
|
15
|
+
println!("Starting MQTT client loop");
|
16
|
+
client.run_loop().await.unwrap();
|
19
17
|
|
18
|
+
let client2 = client.clone();
|
20
19
|
let _pub_task = tokio::spawn(async move {
|
21
20
|
let mut i = 0;
|
22
21
|
loop {
|
23
22
|
i = i + 1;
|
24
23
|
sleep(Duration::from_secs(1)).await; // Simulate periodic publishing
|
25
|
-
|
24
|
+
let message = format!("Periodic message {}", i);
|
25
|
+
client2.publish_string("example/pub_topic".to_string(), message, 1, false, None).await.expect("Failed to publish periodic message");
|
26
26
|
}
|
27
27
|
});
|
28
28
|
|
29
|
-
let
|
29
|
+
let receive_task = tokio::spawn(async move {
|
30
30
|
loop {
|
31
31
|
match recv_chan_rx.recv().await {
|
32
32
|
Some(message) => {
|
@@ -40,5 +40,5 @@ async fn main() {
|
|
40
40
|
}
|
41
41
|
});
|
42
42
|
|
43
|
-
let _result = join!(
|
43
|
+
let _result = join!(receive_task);
|
44
44
|
}
|
@@ -8,7 +8,7 @@ It contains enumerations used by the {{stinger.name}} interface.
|
|
8
8
|
{%if stinger.enums | length > 0%}
|
9
9
|
use std::fmt;
|
10
10
|
use num_derive::{FromPrimitive, ToPrimitive};
|
11
|
-
use num_traits::
|
11
|
+
use num_traits::FromPrimitive;
|
12
12
|
{%endif%}
|
13
13
|
use serde::{Serialize, Deserialize};
|
14
14
|
|
@@ -74,6 +74,7 @@ pub enum MethodResultCode { {%-for rc_i, rc_name in stinger.method_return_codes.
|
|
74
74
|
|
75
75
|
#[allow(dead_code, non_snake_case)]
|
76
76
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
77
|
+
/// Request Object for `{{method_name}}`
|
77
78
|
pub struct {{method_name | UpperCamelCase}}RequestObject {
|
78
79
|
{%-for arg in method.arg_list%}
|
79
80
|
{%-if arg.arg_type.name.lower() == 'primitive'%}
|
@@ -83,9 +84,11 @@ pub struct {{method_name | UpperCamelCase}}RequestObject {
|
|
83
84
|
{%endif-%}
|
84
85
|
{%endfor%}
|
85
86
|
}
|
86
|
-
|
87
|
+
|
88
|
+
{%if method.return_value_type == 'struct' %}
|
87
89
|
#[allow(dead_code)]
|
88
90
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
91
|
+
/// Return Object for `{{method_name}}`
|
89
92
|
pub struct {{method.return_value_name | UpperCamelCase}} {
|
90
93
|
{%-for arg in method.return_value %}
|
91
94
|
pub {{arg.name}}: {{arg.rust_local_type}},
|
@@ -96,6 +99,11 @@ pub struct {{method.return_value_name | UpperCamelCase}} {
|
|
96
99
|
pub struct {{method.return_value_name | UpperCamelCase}} {
|
97
100
|
pub {{method.return_value_property_name}}: {{method.return_value.rust_local_type}},
|
98
101
|
}
|
102
|
+
{%else%}
|
103
|
+
#[derive(Debug, Clone, Serialize)]
|
104
|
+
/// Empty (no parameters) return structure for the `{{method_name}}` method.
|
105
|
+
pub struct {{method.return_value_name | UpperCamelCase}} {
|
106
|
+
}
|
99
107
|
{%endif-%}
|
100
108
|
{%-endfor%}
|
101
109
|
{%for sig_name, sig in stinger.signals.items()%}
|
@@ -1,13 +1,13 @@
|
|
1
1
|
[package]
|
2
|
-
name = "{{stinger.
|
2
|
+
name = "{{stinger.rust.server_package_name}}"
|
3
3
|
version = "{{stinger.version}}"
|
4
4
|
edition = "2024"
|
5
5
|
|
6
6
|
[dependencies]
|
7
|
-
|
7
|
+
{{stinger.rust.common_package_name}} = { path = "../payloads" }
|
8
8
|
futures = "0.3"
|
9
9
|
json = "0.12.4"
|
10
|
-
|
10
|
+
mqttier = { git = "https://github.com/stinger-ipc/mqttier.git" }
|
11
11
|
num-derive = "0.4.2"
|
12
12
|
num-traits = "0.2.19"
|
13
13
|
tokio = { version = "1", features = ["full"] }
|
@@ -15,5 +15,5 @@ serde = { version = "1.0.219", features = ["derive"] }
|
|
15
15
|
serde_json = "1.0.142"
|
16
16
|
|
17
17
|
[[example]]
|
18
|
-
name = "{{stinger.name | snake_case}}
|
18
|
+
name = "{{stinger.name | snake_case}}_server_demo"
|
19
19
|
path = "examples/server.rs"
|
@@ -5,11 +5,12 @@ on the next generation.
|
|
5
5
|
It contains enumerations used by the {{stinger.name}} interface.
|
6
6
|
*/
|
7
7
|
use futures::{executor::block_on};
|
8
|
-
use
|
9
|
-
use
|
8
|
+
use mqttier::MqttierClient;
|
9
|
+
use {{stinger.rust.server_package_name}}::{{stinger.rust.server_struct_name}};
|
10
10
|
use tokio::time::{sleep, Duration};
|
11
|
-
|
12
|
-
|
11
|
+
|
12
|
+
#[allow(unused_imports)]
|
13
|
+
use {{stinger.rust.common_package_name}}::payloads::{MethodResultCode, *};
|
13
14
|
|
14
15
|
{%for method_name, method in stinger.methods.items()%}
|
15
16
|
fn {{method_name|snake_case}}_handler({%for arg in method.arg_list%}_{{arg.name|snake_case}}: {{arg.rust_type}}{%if not loop.last%}, {%endif%}{%endfor%}) -> Result<{{method.return_value_rust_type}}, MethodResultCode> {
|
@@ -34,13 +35,9 @@ fn {{method_name|snake_case}}_handler({%for arg in method.arg_list%}_{{arg.name|
|
|
34
35
|
async fn main() {
|
35
36
|
block_on(async {
|
36
37
|
{%set broker = stinger.get_example_broker()%}
|
37
|
-
let mut connection =
|
38
|
+
let mut connection = MqttierClient::new("localhost", 1883, None).unwrap();
|
38
39
|
let mut server = {{stinger.rust.server_struct_name}}::new(&mut connection).await;
|
39
|
-
|
40
|
-
let loop_task = tokio::spawn(async move {
|
41
|
-
println!("Making call to start connection loop");
|
42
|
-
let _conn_loop = connection.start_loop().await;
|
43
|
-
});
|
40
|
+
|
44
41
|
{%for prop_name, prop in stinger.properties.items()%}
|
45
42
|
println!("Setting initial value for property '{{prop_name}}'");
|
46
43
|
{%-if prop.arg_list | length == 1 %}
|
@@ -76,8 +73,7 @@ async fn main() {
|
|
76
73
|
server.set_{{prop_name | snake_case}}(new_value).await;
|
77
74
|
{%endif%}
|
78
75
|
{%endfor%}{# property initialization -#}
|
79
|
-
server.receive_loop().await;
|
80
|
-
join!(loop_task);
|
76
|
+
let _server_loop_task = server.receive_loop().await;
|
81
77
|
});
|
82
78
|
// Ctrl-C to stop
|
83
79
|
}
|