Last active
January 16, 2024 22:46
-
-
Save lwneal/a24ba363d9cc9f7a02282c3621afa43d to your computer and use it in GitHub Desktop.
#!/usr/bin/echo calm down it's just a shebang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# ^ | |
# There's nothing magical about shebang (#!) lines- they just tell the shell which executable should be used to run this script | |
# The <<EOF syntax is called a heredoc (https://en.wikipedia.org/wiki/Here_document) | |
# It allows us to conveniently cat a large amount of text | |
# Let's use a heredoc to write the Dockerfile | |
cat >Dockerfile <<'EOF' | |
# syntax = docker/dockerfile:1.4.0 | |
FROM node:20 | |
WORKDIR /root | |
RUN npm install sqlite3 | |
# We can write any text inside a heredoc- including other heredocs! | |
RUN cat >/root/schema.sql <<'EOSQL' | |
CREATE TABLE IF NOT EXISTS clicks ( | |
id INTEGER PRIMARY KEY AUTOINCREMENT, | |
time INTEGER NOT NULL | |
); | |
EOSQL | |
# The heredoc terminator doesn't need to be "EOF", it's just an arbitrary string | |
RUN cat >/root/server.js <<'BANANACAT' | |
const fs = require("fs"); | |
const http = require("http"); | |
const sqlite3 = require("sqlite3"); | |
const db = new sqlite3.Database(":memory:"); | |
db.run(fs.readFileSync("/root/schema.sql", "utf8")); | |
const html = fs.readFileSync("/root/index.html", "utf8"); | |
const server = http.createServer((req, res) => { | |
db.run("INSERT INTO clicks(time) VALUES(unixepoch())"); | |
const data = []; | |
db.each( | |
"SELECT time as t, COUNT(*) as n FROM clicks WHERE t > unixepoch()-4*60*60 GROUP BY t-t%60", | |
(_, { t, n }) => data.push([Math.floor(t/60), n]), | |
() => { | |
res.writeHead(200, { "content-type": "text/html" }); | |
res.end(html.replace("__DATA__", JSON.stringify(data))); | |
}, | |
); | |
}); | |
server.listen(8080, "", () => console.log("serving :8080...")); | |
BANANACAT | |
RUN cat >/root/index.html <<'EOHTML' | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>#!/usr/bin/env docker run</title> | |
</head> | |
<body style="font-family: monospace; font-size; 12px; "> | |
<div style="position: absolute; top: 0; left: 0; width: 100vw; height: 100vh; background-size: 5vh 5vh; background-image: linear-gradient(to right, #f0f0f0 1px, transparent 1px), linear-gradient(to bottom, #f0f0f0 1px, transparent 1px); "></div> | |
<span style="position: absolute; top: 1vh; left: 5vh;">Page loads over time (last 4 hours)</span> | |
<span id="max" style="position: absolute; top: 5vh; left: 1vh;"></span> | |
<span id="min" style="position: absolute; top: 95vh; left: 1vh;">0</span> | |
<canvas id="canvas" style="position: absolute; top: 5vh; left: 5vw; "></canvas> | |
<script> | |
(() => { | |
const el = document.getElementById("canvas"), ctx = el.getContext("2d"); | |
el.width = 0.9 * window.innerWidth * window.devicePixelRatio; | |
el.height = 0.9 * window.innerHeight * window.devicePixelRatio; | |
ctx.scale(window.devicePixelRatio, window.devicePixelRatio); | |
const data = __DATA__; | |
const max = data.reduce((prev, [_, n]) => (n > prev ? n : prev), 0); | |
document.getElementById("max").innerText = max; | |
ctx.beginPath(); | |
ctx.moveTo(0, el.height); | |
const draw = (t, n) => { | |
const [x, y] = [el.width * (t-data[0][0])/240, el.height * (1 - n/max)]; | |
ctx.lineTo(x, y); | |
ctx.moveTo(x, y); | |
} | |
let last = -1; | |
for (const [t, n] of data) { | |
if (last != -1 && t > last + 1) { | |
draw(last + 0.1, 0); | |
draw(t - 0.1, 0); | |
} | |
draw(t, n); | |
last = t; | |
} | |
ctx.stroke(); | |
})(); | |
</script> | |
</body> | |
</html> | |
EOHTML | |
CMD ["node", "/root/server.js"] | |
EOF | |
# Build the Docker image | |
docker build -t myimage . | |
# Run a Docker container from the built image | |
docker run -p 8080:8080 -it --rm myimage |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
An illustration to explain https://gist.github.com/adtac/595b5823ef73b329167b815757bbce9f