From 7c91b96395e325af144e571fe4d28615a75d2c8f Mon Sep 17 00:00:00 2001 From: pommicket Date: Wed, 11 Sep 2024 14:15:20 -0400 Subject: prepare for release --- README.md | 95 +++++++++++++++++++++++++++++++++++++++++++ TODO.txt | 0 game.js | 6 ++- index.html | 6 ++- server/getfeaturedpictures.py | 2 +- server/potd.py | 2 +- server/src/main.rs | 6 +-- style.css | 4 ++ upload.sh | 2 +- 9 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 README.md delete mode 100644 TODO.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..17fb261 --- /dev/null +++ b/README.md @@ -0,0 +1,95 @@ +# jigsaw + +online cooperative jigsaw puzzles + +https://s.pommicket.com/jigsaw/index.html + +## about + +this is the source code for a website where you can complete jigsaw puzzles with your friends. +it includes the ability to choose a random picture from the wikimedia commons, +or to use the picture of the day. + +## running locally + +you can run this website locally by installing [rust](https://rust-lang.org), +then running + +``` +cargo run --release +``` + +in the `server` directory. you will now be able to access the website via file:///.../jigsaw/index.html + +## contributing + +please contribute ! +you can also report bugs you find or improvmenets you want to the [github issues page](https://github.com/pommicket/jigsaw/issues). + +## hosting your own instance + +this website consists of a backend written in rust, and a frontend which is just static files. + +to host it, first create a `jigsaw` user (`useradd jigsaw`), and install `postgresql`. then run +`sudo -u postgres psql`, and enter + +``` +CREATE USER jigsaw; +GRANT ALL PRIVILEGES ON DATABASE jigsaw TO jigsaw; +GRANT CREATE ON SCHEMA public TO jigsaw; +\q +``` + +run `cargo build --release` in the `server` directory +either on the server or on your computer, and copy `target/release/jigsaw-server` to the jigsaw user's home directory (or any directory they +have access to). +now you can run it to start the backend, or create a systemd service to run it for you, e.g.: + +``` +[Unit] +Description=Jigsaw puzzle server +After=network.target + +[Service] +User=jigsaw +WorkingDirectory=/home/jigsaw/server +ExecStart=/home/jigsaw/server/jigsaw-server +Type=simple +Restart=always + +[Install] +WantedBy=default.target +RequiredBy=network.target +``` + +now for the front-end, first change the `WEBSOCKET_URL_REMOTE` constant in `game.js` to a subdomain of your domain. +run a proxy on your server to forward websocket traffic from that subdomain to port 54472 (this port can be configured in `server/src/main.rs`). +with apache2 this can be done as follows: + +``` + + ServerName + ProxyPass "/" "ws://localhost:54472/" + ProxyPassReverse "/" "ws://localhost:54472/" +Include /etc/letsencrypt/options-ssl-apache.conf +SSLCertificateFile /etc/letsencrypt/live//fullchain.pem +SSLCertificateKeyFile /etc/letsencrypt/live//privkey.pem + +``` + +and that's it! you can update the files with the `upload.sh` script, modifying the `RCLONE_DEST` variable to point to where +your static files are stored, and `REMOTE` to point to the jigsaw user of your server. to use this script you will also need to add +the following to your sudoers file: + +``` +jigsaw ALL= NOPASSWD: /bin/systemctl start jigsaw-server.service +jigsaw ALL= NOPASSWD: /bin/systemctl stop jigsaw-server.service +jigsaw ALL= NOPASSWD: /bin/systemctl restart jigsaw-server.service +``` + +to allow the jigsaw user to manage the jigsaw-server service. + +## license + +WTFPL + diff --git a/TODO.txt b/TODO.txt deleted file mode 100644 index e69de29..0000000 diff --git a/game.js b/game.js index 5853e21..875068c 100644 --- a/game.js +++ b/game.js @@ -1,5 +1,9 @@ 'use strict'; window.addEventListener('load', function () { + const WEBSOCKET_URL_REMOTE = "wss://jigsaw.pommicket.com"; + const WEBSOCKET_URL = location.protocol === "file:" || location.hostname === "localhost" ? "ws://localhost:54472" : WEBSOCKET_URL_REMOTE; + + const ACTION_MOVE = 3; const ACTION_CONNECT = 4; let socket; @@ -802,7 +806,7 @@ window.addEventListener('load', function () { }, 1000); requestAnimationFrame(everyFrame); function openSocket() { - socket = new WebSocket(location.protocol === "file:" || location.hostname === "localhost" ? "ws://localhost:54472" : "wss://jigsaw.pommicket.com"); + socket = new WebSocket(WEBSOCKET_URL); socket.binaryType = "arraybuffer"; socket.addEventListener('open', onSocketOpen); socket.addEventListener('close', onSocketClose); diff --git a/index.html b/index.html index d34cdbc..0a994a8 100644 --- a/index.html +++ b/index.html @@ -13,7 +13,7 @@ - + @@ -30,5 +30,9 @@ +
+ diff --git a/server/getfeaturedpictures.py b/server/getfeaturedpictures.py index af534d7..e5dd8fd 100755 --- a/server/getfeaturedpictures.py +++ b/server/getfeaturedpictures.py @@ -4,7 +4,7 @@ import json import time from urllib.parse import quote -headers = {'Accept-Encoding':'gzip', 'User-Agent': 'contact pommicket+jigsaw @ gmail.com '} +headers = {'Accept-Encoding':'gzip', 'User-Agent': 'https://github.com/pommicket/jigsaw / contact pommicket+jigsaw @ gmail.com '} def make_file_request(cmcontinue): URL = 'https://commons.wikimedia.org/w/api.php?action=query&format=json&list=categorymembers&cmlimit=500&cmtitle=Category:Featured_pictures_on_Wikimedia_Commons&cmtype=file&cmprop=title&maxlag=5' while True: diff --git a/server/potd.py b/server/potd.py index 8c31c76..d7abc4e 100755 --- a/server/potd.py +++ b/server/potd.py @@ -4,7 +4,7 @@ from xml.etree import ElementTree from getfeaturedpictures import get_urls_of_images from urllib.parse import unquote -headers = {'Accept-Encoding':'gzip', 'User-Agent': 'contact pommicket+jigsaw @ gmail.com '} +headers = {'Accept-Encoding':'gzip', 'User-Agent': 'https://github.com/pommicket/jigsaw / contact pommicket+jigsaw @ gmail.com '} URL = 'https://commons.wikimedia.org/w/api.php?action=featuredfeed&feed=potd&feedformat=rss&maxlag=5' diff --git a/server/src/main.rs b/server/src/main.rs index c019a2a..e5c9848 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -13,6 +13,7 @@ use tokio::io::AsyncWriteExt; use tokio::sync::{Mutex, RwLock}; use tungstenite::protocol::Message; +const PORT: u16 = 54472; const PUZZLE_ID_CHARSET: &[u8] = b"23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; const PUZZLE_ID_LEN: usize = 7; const MAX_PLAYERS: u32 = 20; @@ -524,12 +525,11 @@ async fn create_table_if_doesnt_exist(database: &tokio_postgres::Client) -> Resu #[tokio::main] async fn main() { - let port = 54472; - let host_addr = SocketAddr::from(([127, 0, 0, 1], port)); + let host_addr = SocketAddr::from(([127, 0, 0, 1], PORT)); let listener = match tokio::net::TcpListener::bind(host_addr).await { Ok(l) => l, Err(e) => { - eprintln!("Couldn't bind to localhost:{port}: {e}"); + eprintln!("Couldn't bind to localhost:{PORT}: {e}"); return; } }; diff --git a/style.css b/style.css index 122cd0a..9c6f935 100644 --- a/style.css +++ b/style.css @@ -92,3 +92,7 @@ a, a:visited { color: white; transition: opacity 3s; } + +footer { + font-size: 0.8em; +} diff --git a/upload.sh b/upload.sh index 0fdc6b4..f470d61 100755 --- a/upload.sh +++ b/upload.sh @@ -6,7 +6,7 @@ RCLONE_DEST=${RCLONE_DEST:-linode:/s.pommicket.com/jigsaw} # server user+hostname REMOTE=${REMOTE:-jigsaw@pommicket.com} -for file in *.html *.js *.css *.mp3 favicon.png; do +for file in *.html *.js *.css *.mp3 *.png; do echo "upload $file" rclone copy --s3-acl=public-read $file $RCLONE_DEST || exit 1 done -- cgit v1.2.3