/ src / server.rs
server.rs
  1  use std::{collections::HashSet, fs, sync::Arc, time::Duration};
  2  
  3  use axum::{
  4      extract::{ws::Message, Path, State},
  5      response::{Html, IntoResponse},
  6      routing::{get, post},
  7      Json, Router,
  8  };
  9  use base64::{prelude::BASE64_STANDARD, Engine};
 10  use rand::{thread_rng, Rng};
 11  use serde::Serialize;
 12  use tokio::{
 13      sync::{broadcast, Mutex, RwLock},
 14      time,
 15  };
 16  use tower_http::compression::CompressionLayer;
 17  
 18  use crate::{
 19      fine_grained::Grid2,
 20      grid::{Grid, SubRectInfo},
 21      state::AppState,
 22      ws,
 23  };
 24  
 25  /*
 26  async fn get_grid(
 27      Path((from_index, to_index)): Path<(usize, usize)>,
 28      State(state): State<AppState>,
 29  ) -> impl IntoResponse {
 30      let grid = state.grid.read().await;
 31      let item = grid.get_item(from_index);
 32      if let Some(item) = item {
 33          item.to_string()
 34      } else {
 35          "None".to_owned()
 36      }
 37  }
 38  */
 39  
 40  async fn set_checkbox(
 41      Path(index): Path<usize>,
 42      State(state): State<AppState>,
 43  ) -> impl IntoResponse {
 44      let toggled = state.toggle(index).await;
 45  
 46      if toggled {
 47          "1"
 48      } else {
 49          "0"
 50      }
 51  }
 52  
 53  async fn index() -> impl IntoResponse {
 54      Html(
 55          r#"""
 56      <html>
 57          <head><title>Grid shit</title></head>
 58          <body>
 59              <h1>Here'll be dynamic grid</h1>
 60          </body>
 61      </html>
 62      """#,
 63      )
 64  }
 65  
 66  async fn full_grid(State(state): State<AppState>) -> impl IntoResponse {
 67      let grid = state.grid.read().await;
 68      let full = grid.get_full().await;
 69  
 70      BASE64_STANDARD.encode(full)
 71  }
 72  
 73  async fn sub_grid(State(state): State<AppState>) -> impl IntoResponse {
 74      let grid = state.grid.read().await;
 75      let x_shift = rand::thread_rng().gen_range(0..(125 - 10));
 76      let y_shift = rand::thread_rng().gen_range(0..(1000 - 80));
 77      let subgrid = grid.get_rect(x_shift, y_shift, 10, 80).await;
 78      let subgrid2 = SubRectInfoJson::from_info(&subgrid);
 79      Json(subgrid2)
 80  }
 81  
 82  #[derive(Serialize)]
 83  pub struct SubRectInfoJson {
 84      pub data: String,
 85      pub x_shift: usize,
 86      pub y_shift: usize,
 87      pub width: usize,
 88      pub height: usize,
 89      pub canvas_width: usize,
 90  }
 91  
 92  impl SubRectInfoJson {
 93      fn from_info(info: &SubRectInfo) -> Self {
 94          Self {
 95              data: BASE64_STANDARD.encode(info.data.clone()),
 96              x_shift: info.x_shift,
 97              y_shift: info.y_shift,
 98              width: info.width,
 99              height: info.height,
100              canvas_width: info.canvas_width,
101          }
102      }
103  }
104  
105  pub fn router(state: AppState) -> Router {
106      Router::new()
107          .route("/ws", get(ws::ws_grid))
108          .route("/api/grid", get(full_grid))
109          .route("/api/subgrid", get(sub_grid))
110          .route("/set/:index", post(set_checkbox))
111          //.route("/grid/:from/:to", get(get_grid))
112          .route("/", get(index))
113          .layer(CompressionLayer::new())
114          .with_state(state)
115  }
116  
117  #[cfg(test)]
118  mod tests {
119      use image::{buffer, GenericImage, GenericImageView};
120  
121      use crate::{
122          bit_utils::{get_bit, set_bit},
123          fine_grained::Grid2,
124          grid::{Grid, MAX_SIZE},
125          state::PointQueue,
126      };
127  
128      #[test]
129      fn json_test() {
130          let mut pq = PointQueue::new();
131          pq.off.insert(1111);
132          pq.on.insert(323123);
133          let result = serde_json::to_string(&pq);
134          dbg!(result);
135      }
136  
137      #[tokio::test]
138      async fn create_png() {
139          let grid = Grid2::new();
140  
141          let buffer = grid.get_full().await;
142  
143          let mut imgbuf = image::ImageBuffer::new(1000, 1000);
144  
145          let filled_color = image::Rgb([255u8, 0u8, 0u8]);
146          let empty_color = image::Rgb([255u8, 255u8, 255u8]);
147  
148          for i in 0..MAX_SIZE * 8 {
149              let bit_index = i % 8;
150              let byte_index = i / 8;
151              let byte = buffer[byte_index];
152              let bit_value = get_bit(byte, bit_index);
153  
154              let x = i % 1000;
155              let y = i / 1000;
156              imgbuf.put_pixel(
157                  x as u32,
158                  y as u32,
159                  if bit_value { filled_color } else { empty_color },
160              );
161          }
162  
163          imgbuf.save("dump.png").unwrap();
164      }
165  
166      #[tokio::test]
167      async fn load_png() {
168          let mut grid = Grid2::new();
169  
170          let empty_color = image::Rgba([255u8, 255u8, 255u8, 255u8]);
171  
172          let img = image::open("dump.png").unwrap();
173  
174          let mut buffer: [u8; MAX_SIZE] = [0; MAX_SIZE];
175  
176          for i in 0..MAX_SIZE * 8 {
177              let bit_index = i % 8;
178              let byte_index = i / 8;
179  
180              let x = (i % 1000) as u32;
181              let y = (i / 1000) as u32;
182  
183              let byte = buffer[byte_index];
184  
185              //imgbuf.put_pixel(x as u32, y as u32, if bit_value { filled_color } else { empty_color });
186              let color = img.get_pixel(x, y);
187              let byte = if color == empty_color {
188                  set_bit(byte, bit_index, false)
189              } else {
190                  set_bit(byte, bit_index, true)
191              };
192  
193              buffer[byte_index] = byte;
194          }
195  
196          grid.set_full(buffer).await;
197      }
198  }