summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md95
-rw-r--r--TODO.txt0
-rw-r--r--game.js6
-rw-r--r--index.html6
-rwxr-xr-xserver/getfeaturedpictures.py2
-rwxr-xr-xserver/potd.py2
-rw-r--r--server/src/main.rs6
-rw-r--r--style.css4
-rwxr-xr-xupload.sh2
9 files changed, 115 insertions, 8 deletions
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:
+
+```
+<VirtualHost *:443>
+ ServerName <your subdomain>
+ ProxyPass "/" "ws://localhost:54472/"
+ ProxyPassReverse "/" "ws://localhost:54472/"
+Include /etc/letsencrypt/options-ssl-apache.conf
+SSLCertificateFile /etc/letsencrypt/live/<your domain>/fullchain.pem
+SSLCertificateKeyFile /etc/letsencrypt/live/<your domain>/privkey.pem
+</VirtualHost>
+```
+
+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
--- a/TODO.txt
+++ /dev/null
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 @@
<meta charset="utf-8">
<meta content="width=device-width,initial-scale=1" name="viewport">
<link rel="icon" href="favicon.png">
- <link rel="stylesheet" href="style.css">
+ <link rel="stylesheet" href="style.css?v=1">
<script src="index.js?v=3"></script>
</head>
<body class="margined">
@@ -30,5 +30,9 @@
</div>
<input value="Host puzzle" type="submit">
</form>
+ <br>
+ <footer>
+ <a href="https://github.com/pommicket/jigsaw">Source code</a>
+ </footer>
</body>
</html>
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