summaryrefslogtreecommitdiff
path: root/server/src
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2024-08-09 16:04:09 -0400
committerpommicket <pommicket@gmail.com>2024-08-09 16:04:09 -0400
commit359603fbfe4e1405b0e98f1efa34768fc38805be (patch)
tree77490bc71c1e63b86bf160ac2ce467e27be00199 /server/src
parent39d0135b0fd9c67d673c958b4eaf4fecc5f1358c (diff)
random featrued picture
Diffstat (limited to 'server/src')
-rw-r--r--server/src/main.rs56
1 files changed, 35 insertions, 21 deletions
diff --git a/server/src/main.rs b/server/src/main.rs
index 2693d5b..4e397f1 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -5,6 +5,7 @@ use std::net::SocketAddr;
use std::sync::LazyLock;
use tokio::io::AsyncWriteExt;
use tungstenite::protocol::Message;
+use std::io::prelude::*;
const PUZZLE_ID_CHARSET: &[u8] = b"23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
const PUZZLE_ID_LEN: usize = 6;
@@ -14,18 +15,19 @@ fn generate_puzzle_id() -> [u8; PUZZLE_ID_LEN] {
[(); 6].map(|()| PUZZLE_ID_CHARSET[rng.gen_range(0..PUZZLE_ID_CHARSET.len())])
}
-struct Database {
+struct Server {
puzzles: sled::Tree,
pieces: sled::Tree,
connectivity: sled::Tree,
+ wikimedia_featured: Vec<String>,
}
-fn get_puzzle_info(database: &Database, id: &[u8]) -> anyhow::Result<Vec<u8>> {
+fn get_puzzle_info(server: &Server, id: &[u8]) -> anyhow::Result<Vec<u8>> {
if id.len() != PUZZLE_ID_LEN {
return Err(anyhow!("bad puzzle ID"));
}
let mut data = vec![1, 0, 0, 0, 0, 0, 0, 0]; // opcode + padding
- let puzzle = database
+ let puzzle = server
.puzzles
.get(id)?
.ok_or_else(|| anyhow!("bad puzzle ID"))?;
@@ -34,12 +36,12 @@ fn get_puzzle_info(database: &Database, id: &[u8]) -> anyhow::Result<Vec<u8>> {
// padding
data.push(0);
}
- let pieces = database
+ let pieces = server
.pieces
.get(id)?
.ok_or_else(|| anyhow!("bad puzzle ID"))?;
data.extend_from_slice(&pieces);
- let connectivity = database
+ let connectivity = server
.connectivity
.get(id)?
.ok_or_else(|| anyhow!("bad puzzle ID"))?;
@@ -48,7 +50,7 @@ fn get_puzzle_info(database: &Database, id: &[u8]) -> anyhow::Result<Vec<u8>> {
}
async fn handle_connection(
- database: &Database,
+ server: &Server,
conn: &mut tokio::net::TcpStream,
) -> anyhow::Result<()> {
let mut ws = tokio_tungstenite::accept_async_with_config(
@@ -98,7 +100,7 @@ async fn handle_connection(
loop {
id = generate_puzzle_id();
let data = std::mem::take(&mut puzzle_data);
- if database
+ if server
.puzzles
.compare_and_swap(id, None::<&'static [u8; 0]>, Some(&data[..]))?
.is_ok()
@@ -124,7 +126,7 @@ async fn handle_connection(
*it.next().unwrap() = d;
}
}
- database.pieces.insert(id, pieces_data)?;
+ server.pieces.insert(id, pieces_data)?;
let mut connectivity_data = Vec::new();
connectivity_data.resize((width as usize) * (height as usize) * 2, 0);
let mut it = connectivity_data.iter_mut();
@@ -133,15 +135,15 @@ async fn handle_connection(
*it.next().unwrap() = a;
*it.next().unwrap() = b;
}
- database.connectivity.insert(id, connectivity_data)?;
+ server.connectivity.insert(id, connectivity_data)?;
ws.send(Message::Text(format!("id: {}", std::str::from_utf8(&id)?)))
.await?;
- let info = get_puzzle_info(&database, &id)?;
+ let info = get_puzzle_info(&server, &id)?;
ws.send(Message::Binary(info)).await?;
} else if let Some(id) = text.strip_prefix("join ") {
let id = id.as_bytes().try_into()?;
puzzle_id = Some(id);
- let info = get_puzzle_info(&database, &id)?;
+ let info = get_puzzle_info(&server, &id)?;
ws.send(Message::Binary(info)).await?;
} else if text.starts_with("move ") {
let puzzle_id = puzzle_id.ok_or_else(|| anyhow!("move without puzzle ID"))?;
@@ -162,7 +164,7 @@ async fn handle_connection(
motions.push(Motion { piece, x, y });
}
loop {
- let curr_pieces = database
+ let curr_pieces = server
.pieces
.get(&puzzle_id)?
.ok_or_else(|| anyhow!("bad puzzle ID"))?;
@@ -177,7 +179,7 @@ async fn handle_connection(
.ok_or_else(|| anyhow!("bad piece ID"))?
.copy_from_slice(&y.to_le_bytes());
}
- if database
+ if server
.pieces
.compare_and_swap(&puzzle_id, Some(curr_pieces), Some(new_pieces))?
.is_ok()
@@ -193,7 +195,7 @@ async fn handle_connection(
let piece1: usize = parts.next().ok_or_else(|| anyhow!("bad syntax"))?.parse()?;
let piece2: usize = parts.next().ok_or_else(|| anyhow!("bad syntax"))?.parse()?;
loop {
- let curr_connectivity = database
+ let curr_connectivity = server
.connectivity
.get(&puzzle_id)?
.ok_or_else(|| anyhow!("bad puzzle ID"))?;
@@ -219,7 +221,7 @@ async fn handle_connection(
new_connectivity[piece * 2 + 1] = b;
}
}
- if database
+ if server
.connectivity
.compare_and_swap(
&puzzle_id,
@@ -234,11 +236,11 @@ async fn handle_connection(
}
} else if text == "poll" {
let puzzle_id = puzzle_id.ok_or_else(|| anyhow!("poll without puzzle ID"))?;
- let pieces = database
+ let pieces = server
.pieces
.get(&puzzle_id)?
.ok_or_else(|| anyhow!("bad puzzle ID"))?;
- let connectivity = database
+ let connectivity = server
.connectivity
.get(&puzzle_id)?
.ok_or_else(|| anyhow!("bad puzzle ID"))?;
@@ -246,12 +248,22 @@ async fn handle_connection(
data.extend_from_slice(&pieces);
data.extend_from_slice(&connectivity);
ws.send(Message::Binary(data)).await?;
+ } else if text == "randomFeaturedWikimedia" {
+ let choice = rand::thread_rng().gen_range(0..server.wikimedia_featured.len());
+ ws.send(Message::Text(format!("wikimediaImage {}", server.wikimedia_featured[choice]))).await?;
}
}
}
Ok(())
}
+
+fn read_to_lines(path: &str) -> std::io::Result<Vec<String>> {
+ let file = std::fs::File::open(path)?;
+ let reader = std::io::BufReader::new(file);
+ reader.lines().collect()
+}
+
#[tokio::main]
async fn main() {
let port = 3000;
@@ -269,20 +281,22 @@ async fn main() {
tokio::time::sleep(std::time::Duration::from_secs(3600)).await;
}
});
- static DATABASE_VALUE: LazyLock<Database> = LazyLock::new(|| {
+ static SERVER_VALUE: LazyLock<Server> = LazyLock::new(|| {
+ let wikimedia_featured = read_to_lines("featuredpictures.txt").expect("Couldn't read featuredpictures.txt");
let db = sled::open("database.sled").expect("error opening database");
let puzzles = db.open_tree("PUZZLES").expect("error opening puzzles tree");
let pieces = db.open_tree("PIECES").expect("error opening pieces tree");
let connectivity = db
.open_tree("CONNECTIVITY")
.expect("error opening connectivity tree");
- Database {
+ Server {
puzzles,
pieces,
connectivity,
+ wikimedia_featured,
}
});
- let database: &Database = &DATABASE_VALUE;
+ let server: &Server = &SERVER_VALUE;
loop {
let (mut stream, addr) = match listener.accept().await {
Ok(result) => result,
@@ -292,7 +306,7 @@ async fn main() {
}
};
tokio::task::spawn(async move {
- match handle_connection(database, &mut stream).await {
+ match handle_connection(server, &mut stream).await {
Ok(()) => {}
Err(e) => {
eprintln!("Error handling connection to {addr}: {e}");