ping_viewer_next/server/protocols/v1/
rest.rs

1use crate::device::manager::{ManagerActorHandler, UuidWrapper};
2use crate::server::protocols::v1::errors::Error;
3use actix_web::Responder;
4use mime_guess::from_path;
5use paperclip::actix::{
6    api_v2_operation, get, post,
7    web::{self, HttpResponse, Json},
8    Apiv2Schema,
9};
10use serde::{Deserialize, Serialize};
11use serde_json::json;
12use uuid::Uuid;
13
14#[cfg(not(feature = "embed-frontend"))]
15#[derive(rust_embed::RustEmbed)]
16#[folder = "src/server/protocols/v1/frontend"]
17struct Asset;
18
19#[cfg(feature = "embed-frontend")]
20#[derive(rust_embed::RustEmbed)]
21#[folder = "ping-viewer-next-frontend/dist"]
22struct Asset;
23
24fn handle_embedded_file(path: &str) -> HttpResponse {
25    match Asset::get(path) {
26        Some(content) => HttpResponse::Ok()
27            .content_type(from_path(path).first_or_octet_stream().as_ref())
28            .body(content.data.into_owned()),
29        None => HttpResponse::NotFound().body("404 Not Found"),
30    }
31}
32
33#[api_v2_operation(skip)]
34#[get("/")]
35async fn index() -> impl Responder {
36    handle_embedded_file("index.html")
37}
38
39#[api_v2_operation(skip)]
40#[get("/{file_path:.*}")]
41async fn index_files(file_path: web::Path<String>) -> impl Responder {
42    handle_embedded_file(&file_path)
43}
44
45/// The "register_service" route is used by BlueOS extensions manager
46#[api_v2_operation]
47#[get("register_service")]
48async fn server_metadata() -> Result<Json<ServerMetadata>, Error> {
49    let package = ServerMetadata::default();
50    Ok(Json(package))
51}
52
53pub fn register_services(cfg: &mut web::ServiceConfig) {
54    cfg.service(index)
55        .service(post_request)
56        .service(device_manager_get)
57        .service(device_manager_post)
58        .service(post_create)
59        .service(device_manager_device_get)
60        .service(device_manager_device_ping1d_get)
61        .service(device_manager_device_ping360_get)
62        .service(device_manager_device_common_get)
63        .service(index_files);
64}
65
66async fn send_request_and_broadcast(
67    manager_handler: &web::Data<ManagerActorHandler>,
68    request: crate::device::manager::Request,
69) -> Result<Json<crate::device::manager::Answer>, Error> {
70    let answer = manager_handler.send(request).await?;
71    crate::server::protocols::v1::websocket::send_to_websockets(json!(answer), None);
72    Ok(Json(answer))
73}
74
75#[api_v2_operation(tags("Device Manager"))]
76#[post("device_manager/request")]
77async fn post_request(
78    manager_handler: web::Data<ManagerActorHandler>,
79    json: web::Json<crate::device::manager::Request>,
80) -> Result<Json<crate::device::manager::Answer>, Error> {
81    let request = json.into_inner();
82
83    send_request_and_broadcast(&manager_handler, request).await
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize, Apiv2Schema)]
87pub enum DeviceManagerGetOptionsV1 {
88    AutoCreate,
89    List,
90    Search,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize, Apiv2Schema)]
94pub enum DeviceManagerPostOptionsV1 {
95    Delete,
96    Info,
97    EnableContinuousMode,
98    DisableContinuousMode,
99}
100
101#[api_v2_operation(tags("Device Manager"))]
102#[get("device_manager/{selection}")]
103async fn device_manager_get(
104    manager_handler: web::Data<ManagerActorHandler>,
105    selection: web::Path<DeviceManagerGetOptionsV1>,
106) -> Result<Json<crate::device::manager::Answer>, Error> {
107    let request = match selection.into_inner() {
108        DeviceManagerGetOptionsV1::AutoCreate => crate::device::manager::Request::AutoCreate,
109        DeviceManagerGetOptionsV1::List => crate::device::manager::Request::List,
110        DeviceManagerGetOptionsV1::Search => crate::device::manager::Request::Search,
111    };
112
113    send_request_and_broadcast(&manager_handler, request).await
114}
115
116#[api_v2_operation(tags("Device Manager"))]
117#[post("device_manager/create")]
118async fn post_create(
119    manager_handler: web::Data<ManagerActorHandler>,
120    info: web::Json<crate::device::manager::CreateStruct>,
121) -> Result<Json<crate::device::manager::Answer>, Error> {
122    let create_struct = info.into_inner();
123
124    let request = crate::device::manager::Request::Create(create_struct);
125
126    send_request_and_broadcast(&manager_handler, request).await
127}
128
129#[api_v2_operation(tags("Device Manager : Device"))]
130#[post("device_manager/{device}/{selection}")]
131async fn device_manager_post(
132    manager_handler: web::Data<ManagerActorHandler>,
133    info: web::Path<(Uuid, DeviceManagerPostOptionsV1)>,
134) -> Result<Json<crate::device::manager::Answer>, Error> {
135    let info = info.into_inner();
136    let uuid = info.0;
137    let request = info.1;
138
139    let request = match request {
140        DeviceManagerPostOptionsV1::Delete => {
141            crate::device::manager::Request::Delete(UuidWrapper { uuid })
142        }
143        DeviceManagerPostOptionsV1::Info => {
144            crate::device::manager::Request::Info(UuidWrapper { uuid })
145        }
146        DeviceManagerPostOptionsV1::EnableContinuousMode => {
147            crate::device::manager::Request::EnableContinuousMode(UuidWrapper { uuid })
148        }
149        DeviceManagerPostOptionsV1::DisableContinuousMode => {
150            crate::device::manager::Request::DisableContinuousMode(UuidWrapper { uuid })
151        }
152    };
153
154    send_request_and_broadcast(&manager_handler, request).await
155}
156
157#[api_v2_operation(tags("Device Manager : Device"))]
158#[get("device_manager/{device}/{request}")]
159async fn device_manager_device_get(
160    manager_handler: web::Data<ManagerActorHandler>,
161    info: web::Path<(Uuid, crate::device::devices::PingRequest)>,
162) -> Result<Json<crate::device::manager::Answer>, Error> {
163    let info = info.into_inner();
164    let uuid = info.0;
165    let request = info.1;
166
167    let request =
168        crate::device::manager::Request::Ping(crate::device::manager::DeviceRequestStruct {
169            uuid,
170            device_request: request,
171        });
172
173    send_request_and_broadcast(&manager_handler, request).await
174}
175
176#[api_v2_operation(tags("Device Manager : Device"))]
177#[get("device_manager/{device}/ping1d/{request}")]
178async fn device_manager_device_ping1d_get(
179    manager_handler: web::Data<ManagerActorHandler>,
180    info: web::Path<(Uuid, crate::device::devices::Ping1DRequest)>,
181) -> Result<Json<crate::device::manager::Answer>, Error> {
182    let info = info.into_inner();
183    let uuid = info.0;
184    let request = info.1;
185
186    let request = crate::device::devices::PingRequest::Ping1D(request);
187
188    let request =
189        crate::device::manager::Request::Ping(crate::device::manager::DeviceRequestStruct {
190            uuid,
191            device_request: request,
192        });
193
194    send_request_and_broadcast(&manager_handler, request).await
195}
196
197#[api_v2_operation(tags("Device Manager : Device"))]
198#[get("device_manager/{device}/ping360/{request}")]
199async fn device_manager_device_ping360_get(
200    manager_handler: web::Data<ManagerActorHandler>,
201    info: web::Path<(Uuid, crate::device::devices::Ping360Request)>,
202) -> Result<Json<crate::device::manager::Answer>, Error> {
203    let info = info.into_inner();
204    let uuid = info.0;
205    let request = info.1;
206
207    let request = crate::device::devices::PingRequest::Ping360(request);
208
209    let request =
210        crate::device::manager::Request::Ping(crate::device::manager::DeviceRequestStruct {
211            uuid,
212            device_request: request,
213        });
214
215    send_request_and_broadcast(&manager_handler, request).await
216}
217
218#[api_v2_operation(tags("Device Manager : Device"))]
219#[get("device_manager/{device}/common/{request}")]
220async fn device_manager_device_common_get(
221    manager_handler: web::Data<ManagerActorHandler>,
222    info: web::Path<(Uuid, crate::device::devices::PingCommonRequest)>,
223) -> Result<Json<crate::device::manager::Answer>, Error> {
224    let info = info.into_inner();
225    let uuid = info.0;
226    let request = info.1;
227
228    let request = crate::device::devices::PingRequest::Common(request);
229
230    let request =
231        crate::device::manager::Request::Ping(crate::device::manager::DeviceRequestStruct {
232            uuid,
233            device_request: request,
234        });
235
236    send_request_and_broadcast(&manager_handler, request).await
237}
238
239#[derive(Debug, Serialize, Deserialize, Apiv2Schema)]
240pub struct ServerMetadata {
241    pub name: &'static str,
242    pub description: &'static str,
243    pub icon: &'static str,
244    pub company: &'static str,
245    pub version: &'static str,
246    pub new_page: bool,
247    pub webpage: &'static str,
248    pub api: &'static str,
249}
250
251impl Default for ServerMetadata {
252    fn default() -> Self {
253        Self {
254            name: "Ping Viewer Next",
255            description: "A ping protocol extension for expose devices to web.",
256            icon: "mdi-compass-outline",
257            company: "BlueRobotics",
258            version: "0.0.0",
259            new_page: false,
260            webpage: "https://github.com/RaulTrombin/navigator-assistant",
261            api: "/docs",
262        }
263    }
264}