1
1
use crate :: config:: AppConfig ;
2
2
use crate :: config:: SharedConfig ;
3
+ use crate :: ev:: EV_MODEL_FILE ;
3
4
use axum:: {
4
5
body:: Body ,
5
- extract:: { Query , State } ,
6
- http:: { header, Response , StatusCode } ,
6
+ extract:: { Query , RawBody , State } ,
7
+ http:: { header, HeaderMap , Response , StatusCode } ,
7
8
response:: { Html , IntoResponse } ,
8
- routing:: get,
9
+ routing:: { get, post } ,
9
10
Json , Router ,
10
11
} ;
11
12
use chrono:: Local ;
13
+ use hyper:: body:: to_bytes;
12
14
use std:: collections:: HashMap ;
13
15
use std:: path:: PathBuf ;
14
16
use std:: sync:: Arc ;
15
17
use tokio:: fs;
18
+ use tokio:: io:: AsyncWriteExt ;
16
19
17
20
const TEMPLATE : & str = include_str ! ( "../static/index.html" ) ;
18
21
const PICO_CSS : & str = include_str ! ( "../static/pico.min.css" ) ;
@@ -29,6 +32,7 @@ pub fn app(state: Arc<AppState>) -> Router {
29
32
. route ( "/config" , get ( get_config) . post ( set_config) )
30
33
. route ( "/download" , get ( download_handler) )
31
34
. route ( "/restart" , get ( restart_handler) )
35
+ . route ( "/upload-hex-model" , post ( upload_hex_model_handler) )
32
36
. with_state ( state)
33
37
}
34
38
@@ -83,6 +87,66 @@ async fn download_handler(
83
87
}
84
88
}
85
89
90
+ async fn upload_hex_model_handler (
91
+ State ( state) : State < Arc < AppState > > ,
92
+ headers : HeaderMap ,
93
+ RawBody ( body) : RawBody ,
94
+ ) -> impl IntoResponse {
95
+ // read body as bytes
96
+ let body_bytes = match to_bytes ( body) . await {
97
+ Ok ( bytes) => bytes,
98
+ Err ( err) => {
99
+ return (
100
+ StatusCode :: BAD_REQUEST ,
101
+ format ! ( "Unable to read body: {}" , err) ,
102
+ )
103
+ }
104
+ } ;
105
+
106
+ // convert to UTF-8 string
107
+ let hex_str = match std:: str:: from_utf8 ( & body_bytes) {
108
+ Ok ( s) => s. trim ( ) , // remove whitespaces
109
+ Err ( err) => {
110
+ return (
111
+ StatusCode :: BAD_REQUEST ,
112
+ format ! ( "Unable to parse body to UTF-8: {}" , err) ,
113
+ )
114
+ }
115
+ } ;
116
+
117
+ // decode into Vec<u8>
118
+ let binary_data = match hex:: decode ( hex_str) {
119
+ Ok ( data) => data,
120
+ Err ( err) => {
121
+ return (
122
+ StatusCode :: BAD_REQUEST ,
123
+ format ! ( "Invalid hex data: {}" , err) ,
124
+ )
125
+ }
126
+ } ;
127
+
128
+ // save to model file
129
+ let path: PathBuf = PathBuf :: from ( EV_MODEL_FILE ) ;
130
+ match fs:: File :: create ( & path) . await {
131
+ Ok ( mut file) => {
132
+ if let Err ( err) = file. write_all ( & binary_data) . await {
133
+ return (
134
+ StatusCode :: INTERNAL_SERVER_ERROR ,
135
+ format ! ( "Error saving model file: {}" , err) ,
136
+ ) ;
137
+ }
138
+ (
139
+ StatusCode :: OK ,
140
+ format ! ( "File saved correctly as {:?}" , path) ,
141
+ )
142
+ }
143
+ Err ( err) => (
144
+ StatusCode :: INTERNAL_SERVER_ERROR ,
145
+ format ! ( "File create error: {}" , err) ,
146
+ ) ,
147
+ }
148
+ }
149
+
86
150
async fn get_config ( State ( state) : State < Arc < AppState > > ) -> impl IntoResponse {
87
151
let cfg = state. config . read ( ) . await . clone ( ) ;
88
152
Json ( cfg)
0 commit comments