tangled
alpha
login
or
join now
buttplug.io
/
buttplug
20
fork
atom
Buttplug sex toy control library
20
fork
atom
overview
issues
pulls
pipelines
feat: Add events via sse
qdot.tngl.sh
6 months ago
ffc0dc94
ed2f5d56
+66
-21
1 changed file
expand all
collapse all
unified
split
crates
intiface_engine
src
rest_server.rs
+66
-21
crates/intiface_engine/src/rest_server.rs
···
1
1
-
use std::{collections::BTreeMap, io, net::SocketAddr, str::FromStr, sync::Arc};
1
1
+
use std::{collections::BTreeMap, convert::Infallible, io, net::SocketAddr, str::FromStr, sync::Arc};
2
2
3
3
use axum::{
4
4
-
Json, Router,
5
5
-
extract::{Path, State, rejection::JsonRejection},
6
6
-
http::StatusCode,
7
7
-
response::{IntoResponse, Response},
8
8
-
routing::{get, put},
4
4
+
extract::{rejection::JsonRejection, Path, State}, http::StatusCode, response::{sse::{Event, KeepAlive}, IntoResponse, Response, Sse}, routing::{get, put}, Json, Router
9
5
};
10
6
use buttplug_client::{
11
11
-
ButtplugClient, ButtplugClientDevice, ButtplugClientError, device::ClientDeviceOutputCommand,
7
7
+
device::{ClientDeviceFeature, ClientDeviceOutputCommand}, ButtplugClient, ButtplugClientDevice, ButtplugClientError, ButtplugClientEvent
12
8
};
13
9
use buttplug_client_in_process::ButtplugInProcessClientConnectorBuilder;
14
10
use buttplug_core::message::{DeviceFeature, OutputType};
15
11
use buttplug_server::ButtplugServer;
12
12
+
use futures::{Stream, StreamExt};
16
13
use serde::Serialize;
17
14
use strum::IntoEnumIterator;
18
15
use thiserror::Error;
···
102
99
.cloned()
103
100
}
104
101
102
102
+
fn get_feature(
103
103
+
client: &ButtplugClient,
104
104
+
index: u32,
105
105
+
feature_index: u32
106
106
+
) -> Result<ClientDeviceFeature, IntifaceRestError> {
107
107
+
get_device(client, index)?
108
108
+
.device_features()
109
109
+
.get(&feature_index)
110
110
+
.ok_or(IntifaceRestError::InvalidFeature(index, feature_index))
111
111
+
.cloned()
112
112
+
}
113
113
+
105
114
async fn start_scanning(
106
115
State(client): State<Arc<ButtplugClient>>,
107
116
) -> Result<(), IntifaceRestError> {
···
141
150
142
151
async fn set_device_output(
143
152
State(client): State<Arc<ButtplugClient>>,
144
144
-
Path((index, command, level)): Path<(u32, String, f64)>,
153
153
+
Path((index, command, level)): Path<(u32, OutputType, f64)>,
145
154
) -> Result<(), IntifaceRestError> {
146
146
-
let command_type = OutputType::from_str(&command).map_err(|_| {
147
147
-
IntifaceRestError::InvalidOutputType(command, OutputType::iter().collect::<Vec<OutputType>>())
148
148
-
})?;
155
155
+
let cmd = ClientDeviceOutputCommand::from_command_value_float(command, level)
156
156
+
.map_err(|e| IntifaceRestError::ButtplugClientError(e))?;
157
157
+
158
158
+
Ok(
159
159
+
get_device(&client, index)?
160
160
+
.send_command(&cmd)
161
161
+
.await
162
162
+
.map_err(|e| IntifaceRestError::ButtplugClientError(e))?,
163
163
+
)
164
164
+
}
149
165
150
150
-
let cmd = ClientDeviceOutputCommand::from_command_value_float(command_type, level)
166
166
+
async fn set_feature_output(
167
167
+
State(client): State<Arc<ButtplugClient>>,
168
168
+
Path((index, feature_index, command, level)): Path<(u32, u32, OutputType, f64)>,
169
169
+
) -> Result<(), IntifaceRestError> {
170
170
+
let cmd = ClientDeviceOutputCommand::from_command_value_float(command, level)
151
171
.map_err(|e| IntifaceRestError::ButtplugClientError(e))?;
152
172
153
173
Ok(
154
154
-
get_device(&client, index)?
174
174
+
get_feature(&client, index, feature_index)?
155
175
.send_command(&cmd)
156
176
.await
157
177
.map_err(|e| IntifaceRestError::ButtplugClientError(e))?,
···
198
218
)
199
219
}
200
220
201
201
-
async fn get_feature(
221
221
+
async fn get_feature_info(
202
222
State(client): State<Arc<ButtplugClient>>,
203
223
Path((index, feature_index)): Path<(u32, u32)>,
204
224
) -> Result<Json<DeviceFeature>, IntifaceRestError> {
···
213
233
)
214
234
}
215
235
236
236
+
async fn feature_input_command(
237
237
+
State(client): State<Arc<ButtplugClient>>,
238
238
+
Path((index, feature_index, input_type, command)): Path<(u32, u32, String, String)>,
239
239
+
) -> Result<(), IntifaceRestError> {
240
240
+
/*
241
241
+
let cmd = convert_output_command(&command, level)?;
242
242
+
243
243
+
Ok(
244
244
+
get_feature(&client, index, feature_index)?
245
245
+
.send_command(&cmd)
246
246
+
.await
247
247
+
.map_err(|e| IntifaceRestError::ButtplugClientError(e))?,
248
248
+
)
249
249
+
*/
250
250
+
Ok(())
251
251
+
}
252
252
+
253
253
+
async fn server_sse(State(client): State<Arc<ButtplugClient>>,) -> Sse<impl Stream<Item = Result<Event, Infallible>>> {
254
254
+
let stream = client.event_stream().map(|e| Ok(Event::default().data(format!("{:?}", e))));
255
255
+
256
256
+
Sse::new(stream).keep_alive(KeepAlive::default())
257
257
+
}
258
258
+
216
259
impl IntifaceRestServer {
217
260
pub async fn run(server: ButtplugServer) -> Result<(), io::Error> {
218
261
let connector = ButtplugInProcessClientConnectorBuilder::default()
···
232
275
.route("/devices/{index}", get(get_device_info))
233
276
.route("/devices/{index}/stop", put(stop_device))
234
277
.route("/devices/{index}/features", get(get_features))
235
235
-
.route("/devices/{index}/features/{index}/", put(get_feature))
278
278
+
.route("/devices/{index}/features/{index}/", put(get_feature_info))
236
279
.route(
237
237
-
"/devices/{index}/outputs/{output_type}/",
280
280
+
"/devices/{index}/outputs/{command}/{level}",
238
281
put(set_device_output),
239
282
)
240
240
-
/*
241
283
.route(
242
242
-
"/devices/{index}/features/{index}/outputs/{output_type}/",
284
284
+
"/devices/{index}/features/{index}/outputs/{output_type}/{level}",
243
285
put(set_feature_output),
244
286
)
287
287
+
/*
245
288
.route(
246
289
"/devices/{index}/inputs/{input_type}/{input_command}",
247
247
-
put(set_device_input),
290
290
+
put(device_input_command),
248
291
)
292
292
+
*/
249
293
.route(
250
294
"/devices/{index}/features/{index}/inputs/{input_type}/{input_command}",
251
251
-
put(set_feature_input),
295
295
+
put(feature_input_command),
252
296
)
297
297
+
/*
253
298
.route("/devices/{index}/events", get(device_sse))
254
254
-
.route("/events", get(server_sse))
255
299
*/
300
300
+
.route("/events", get(server_sse))
256
301
//.route("/devices/{*index}/vibrate", post(set_feature_vibrate_speed))
257
302
.with_state(Arc::new(client)),
258
303
);