Skip to content

Commit 0d55085

Browse files
committed
message stacking, periodic saving
1 parent 977845d commit 0d55085

File tree

5 files changed

+262
-162
lines changed

5 files changed

+262
-162
lines changed

Cargo.lock

+1-15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "draw-together"
3-
version = "2.1.0"
3+
version = "2.2.0"
44
edition = "2021"
55

66
[[bin]]
@@ -10,5 +10,4 @@ path = "src/main.rs"
1010
[dependencies]
1111
tokio = { version = "1.10.0", features = ["full"] }
1212
axum = { version = "0.8.1", features = ["ws"] }
13-
tokio-util = { version = "0.7.13", features = ["io"] }
1413
futures-util = "0.3.31"

src/data.rs

+146-58
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,27 @@ use tokio::{
55
sync::Mutex,
66
};
77

8+
#[derive(Debug)]
89
pub enum Action {
9-
DrawCubeNormal,
1010
Erase,
11+
DrawCubeNormal,
1112
DrawCubeHollow,
1213
DrawCircleNormal,
1314
DrawCircleHollow,
1415
DrawTriangleNormal,
1516
DrawTriangleHollow,
1617
}
1718

19+
const RESOLUTION: usize = RESOLUTION_WIDTH * RESOLUTION_HEIGHT;
20+
const RESOLUTION_HEIGHT: usize = 1000;
21+
const RESOLUTION_WIDTH: usize = 1920;
22+
23+
// binary format:
24+
// 0-0: action (3b) + height (5b)
25+
// 1-3: x (12b) + y (12b)
26+
// 4-6: color
27+
28+
#[derive(Debug)]
1829
pub struct ClientMessage {
1930
pub action: Action,
2031

@@ -26,14 +37,50 @@ pub struct ClientMessage {
2637
}
2738

2839
impl ClientMessage {
40+
fn decode_u12(data: &[u8]) -> [u16; 2] {
41+
let mut buf: [u16; 2] = [0; 2];
42+
43+
buf[0] = (data[0] as u16) | ((data[1] as u16 & 0xf) << 8);
44+
buf[1] = ((data[1] as u16) >> 4) | ((data[2] as u16) << 4);
45+
46+
buf
47+
}
48+
49+
fn encode_u12(data: [u16; 2]) -> [u8; 3] {
50+
let mut buf = [0; 3];
51+
52+
buf[0] = (data[0] & 0xff) as u8;
53+
buf[1] = ((data[0] >> 8) | (data[1] << 4)) as u8;
54+
buf[2] = (data[1] >> 4) as u8;
55+
56+
buf
57+
}
58+
59+
fn decode_u3(data: u8) -> u8 {
60+
data & 0b111
61+
}
62+
63+
fn encode_u3(data: u8) -> u8 {
64+
data & 0b111
65+
}
66+
67+
fn decode_u5(data: u8) -> u8 {
68+
data >> 3
69+
}
70+
71+
fn encode_u5(data: u8) -> u8 {
72+
data << 3
73+
}
74+
2975
pub fn decode(data: &[u8]) -> Option<Self> {
30-
if data.len() != 9 {
76+
if data.len() != 7 {
3177
return None;
3278
}
3379

34-
let action = match data[0] {
35-
0 => Action::DrawCubeNormal,
36-
1 => Action::Erase,
80+
let action_height = data[0];
81+
let action = match Self::decode_u3(action_height) {
82+
0 => Action::Erase,
83+
1 => Action::DrawCubeNormal,
3784
2 => Action::DrawCubeHollow,
3885
3 => Action::DrawCircleNormal,
3986
4 => Action::DrawCircleHollow,
@@ -42,12 +89,12 @@ impl ClientMessage {
4289
_ => return None,
4390
};
4491

45-
let x = u16::from_le_bytes([data[1], data[2]]);
46-
let y = u16::from_le_bytes([data[3], data[4]]);
47-
let height = data[5];
48-
let color = [data[6], data[7], data[8]];
92+
let height = Self::decode_u5(action_height);
93+
94+
let [x, y] = Self::decode_u12(&data[1..4]);
95+
let color = [data[4], data[5], data[6]];
4996

50-
if height == 0 {
97+
if height == 0 || x >= RESOLUTION_WIDTH as u16 || y >= RESOLUTION_HEIGHT as u16 {
5198
return None;
5299
}
53100

@@ -60,77 +107,120 @@ impl ClientMessage {
60107
})
61108
}
62109

63-
pub fn encode(&self) -> [u8; 9] {
64-
let mut buf = [0; 9];
110+
pub fn encode(&self) -> [u8; 7] {
111+
let mut buf = [0; 7];
65112

66-
buf[0] = match self.action {
67-
Action::DrawCubeNormal => 0,
68-
Action::Erase => 1,
113+
buf[0] = Self::encode_u3(match self.action {
114+
Action::Erase => 0,
115+
Action::DrawCubeNormal => 1,
69116
Action::DrawCubeHollow => 2,
70117
Action::DrawCircleNormal => 3,
71118
Action::DrawCircleHollow => 4,
72119
Action::DrawTriangleNormal => 5,
73120
Action::DrawTriangleHollow => 6,
74-
};
121+
}) | Self::encode_u5(self.height);
122+
buf[1..4].copy_from_slice(&Self::encode_u12([self.x, self.y]));
123+
buf[4..7].copy_from_slice(&self.color);
75124

76-
buf[1..3].copy_from_slice(&self.x.to_le_bytes());
77-
buf[3..5].copy_from_slice(&self.y.to_le_bytes());
78-
buf[5] = self.height;
79-
buf[6..9].copy_from_slice(&self.color);
125+
if std::env::var("DEBUG").is_ok() {
126+
println!("encoded: {:?}", &self);
127+
}
80128

81129
buf
82130
}
131+
132+
pub fn encode_internal(&self) -> u32 {
133+
let mut buf = [0; 4];
134+
135+
buf[0] = Self::encode_u3(match self.action {
136+
Action::Erase => 0,
137+
Action::DrawCubeNormal => 1,
138+
Action::DrawCubeHollow => 2,
139+
Action::DrawCircleNormal => 3,
140+
Action::DrawCircleHollow => 4,
141+
Action::DrawTriangleNormal => 5,
142+
Action::DrawTriangleHollow => 6,
143+
}) | Self::encode_u5(self.height);
144+
buf[1..4].copy_from_slice(&self.color);
145+
146+
u32::from_le_bytes(buf)
147+
}
83148
}
84149

85150
pub struct Data {
86-
pub file: Option<File>,
87-
pub data: Option<Arc<Mutex<Vec<u8>>>>,
88-
151+
pub data: Arc<Mutex<Vec<u32>>>,
89152
pub listeners: Vec<tokio::sync::mpsc::Sender<Vec<u8>>>,
90-
save: bool,
91153
}
92154

93155
impl Data {
94156
pub async fn new(path: Option<&str>, save: bool) -> Self {
95-
let file = match path {
157+
let mut file = match path {
96158
Some(path) => Some(if save {
97159
OpenOptions::new()
98160
.read(true)
99-
.append(true)
161+
.write(true)
100162
.create(true)
101163
.open(path)
102164
.await
103165
.unwrap()
104166
} else {
105167
File::open(path).await.unwrap()
106168
}),
107-
None => {
108-
return Self {
109-
file: None,
110-
data: Some(Arc::new(Mutex::new(Vec::new()))),
111-
listeners: Vec::new(),
112-
save,
113-
}
114-
}
169+
None => None,
115170
};
116171

117-
if !save {
118-
let mut data = Vec::new();
119-
file.unwrap().read_to_end(&mut data).await.unwrap();
172+
let mut data: Vec<u32>;
173+
if file.is_some() {
174+
let mut file_data: Vec<u8> = Vec::with_capacity(RESOLUTION * 4);
175+
file.as_mut()
176+
.unwrap()
177+
.read_to_end(&mut file_data)
178+
.await
179+
.unwrap();
180+
181+
data = file_data
182+
.chunks_exact(4)
183+
.map(|chunk| {
184+
let mut buf = [0; 4];
185+
buf.copy_from_slice(chunk);
186+
187+
u32::from_le_bytes(buf)
188+
})
189+
.collect::<Vec<u32>>();
190+
data.resize(RESOLUTION, 0);
191+
} else {
192+
data = Vec::with_capacity(RESOLUTION);
193+
data.resize(RESOLUTION, 0);
120194

121-
return Self {
122-
file: None,
123-
data: Some(Arc::new(Mutex::new(data))),
124-
listeners: Vec::new(),
125-
save,
126-
};
195+
println!("data: {:?}", &data.len());
196+
}
197+
198+
let data = Arc::new(Mutex::new(data));
199+
let task_data = Arc::clone(&data);
200+
if file.is_some() && save {
201+
tokio::spawn(async move {
202+
let mut file = file.unwrap();
203+
204+
loop {
205+
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
206+
207+
println!("saving data...");
208+
209+
let data = task_data.lock().await;
210+
for chunk in data.iter() {
211+
file.write_all(&chunk.to_le_bytes()).await.unwrap();
212+
}
213+
214+
println!("saving data... done");
215+
216+
file.sync_all().await.unwrap();
217+
}
218+
});
127219
}
128220

129221
Self {
130-
file,
131-
data: None,
222+
data,
132223
listeners: Vec::new(),
133-
save,
134224
}
135225
}
136226

@@ -142,20 +232,18 @@ impl Data {
142232
self.listeners.retain(|listener| !listener.is_closed());
143233
}
144234

145-
pub async fn write(&mut self, data: &ClientMessage) {
146-
let encoded = data.encode();
147-
148-
if let Some(file) = &mut self.file {
149-
if !self.save {
150-
return;
151-
}
235+
pub async fn write(&mut self, data: &[ClientMessage]) {
236+
let self_data = Arc::clone(&self.data);
237+
let mut self_data = self_data.lock().await;
152238

153-
file.write_all(&encoded).await.unwrap();
154-
} else {
155-
let self_data = self.data.as_mut().unwrap();
239+
for message in data {
240+
let index = (message.y as usize * RESOLUTION_WIDTH) + message.x as usize;
241+
self_data[index] = message.encode_internal();
242+
}
156243

157-
let mut self_data = self_data.lock().await;
158-
self_data.extend_from_slice(&encoded);
244+
let mut encoded = Vec::with_capacity(7 * data.len());
245+
for message in data {
246+
encoded.extend_from_slice(&message.encode());
159247
}
160248

161249
for listener in &self.listeners {

0 commit comments

Comments
 (0)