Files
coapwithudp/static/index.html

167 lines
7.7 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CoAP Hello — UDP Reference</title>
<style>
:root {
color-scheme: light dark;
--bg: #fbfbfa; --fg: #1a1a19; --muted: #6b6b68;
--card: #ffffff; --border: #e4e4e1; --accent: #b05730;
--ok: #2f7d4f; --err: #b3402f; --code-bg: #f4f4f2;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a19; --fg: #edecea; --muted: #9a9a96;
--card: #232322; --border: #353533; --accent: #e08a5f;
--ok: #6bbd8a; --err: #e8806c; --code-bg: #2b2b29;
}
}
* { box-sizing: border-box; }
body {
margin: 0; padding: 2rem 1.25rem; background: var(--bg); color: var(--fg);
font: 15px/1.55 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}
main { max-width: 680px; margin: 0 auto; }
h1 { font-size: 1.4rem; margin: 0 0 .35rem; letter-spacing: -.01em; }
.sub { color: var(--muted); margin: 0 0 1.75rem; font-size: .9rem; }
.card {
background: var(--card); border: 1px solid var(--border);
border-radius: 10px; padding: 1.25rem; margin-bottom: 1rem;
}
h2 { font-size: .82rem; text-transform: uppercase; letter-spacing: .06em;
color: var(--muted); margin: 0 0 .7rem; }
label { display: block; font-weight: 600; font-size: .82rem; margin-bottom: .4rem; }
input {
width: 100%; padding: .6rem .7rem; font: inherit; border-radius: 7px;
border: 1px solid var(--border); background: var(--bg); color: var(--fg);
}
input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.hint { color: var(--muted); font-size: .82rem; margin: .8rem 0 0; }
.cmd { display: flex; gap: .5rem; align-items: stretch; margin-top: .55rem; }
.cmd pre { flex: 1; margin: 0; }
pre {
background: var(--code-bg); border: 1px solid var(--border); border-radius: 7px;
padding: .7rem .8rem; overflow-x: auto; margin: 0;
font: 13px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
}
button {
font: inherit; font-size: .8rem; font-weight: 600; padding: .35rem .7rem;
border-radius: 7px; border: 1px solid var(--border);
background: var(--bg); color: var(--muted); cursor: pointer; white-space: nowrap;
}
button:hover { border-color: var(--accent); color: var(--accent); }
button.copied { color: var(--ok); border-color: var(--ok); }
.what { font-size: .8rem; color: var(--muted); margin: 1rem 0 .1rem; }
.what:first-of-type { margin-top: 0; }
table { width: 100%; border-collapse: collapse; font-size: .87rem; }
th, td { text-align: left; padding: .4rem .5rem; border-bottom: 1px solid var(--border); }
th { font-size: .74rem; text-transform: uppercase; letter-spacing: .05em;
color: var(--muted); font-weight: 600; }
tr:last-child td { border-bottom: none; }
td.code { font: 13px ui-monospace, SFMono-Regular, Menlo, monospace; white-space: nowrap; }
.ok { color: var(--ok); font-weight: 600; }
.err { color: var(--err); font-weight: 600; }
code { background: var(--code-bg); padding: .1em .35em; border-radius: 4px;
font: 13px ui-monospace, SFMono-Regular, Menlo, monospace; }
a { color: var(--accent); }
</style>
</head>
<body>
<main>
<h1>CoAP Hello — UDP Reference</h1>
<p class="sub">This server speaks CoAP over UDP only, so there is nothing here
for a browser to call. Type a name and copy the command for the client you
use — the page is static and works straight off disk.</p>
<div class="card">
<label for="name">Name</label>
<input id="name" value="Imran" autocomplete="off" spellcheck="false"
placeholder="leave blank for &quot;World&quot;">
<p class="what">Bundled client — <code>cargo build --release</code> first</p>
<div class="cmd"><pre id="c-get"></pre><button data-copy="c-get">Copy</button></div>
<div class="cmd"><pre id="c-post"></pre><button data-copy="c-post">Copy</button></div>
<div class="cmd"><pre id="c-json"></pre><button data-copy="c-json">Copy</button></div>
<div class="cmd"><pre id="c-health"></pre><button data-copy="c-health">Copy</button></div>
<p class="what">Any other CoAP client, e.g. <a href="https://www.npmjs.com/package/coap-cli">coap-cli</a></p>
<div class="cmd"><pre id="c-cli"></pre><button data-copy="c-cli">Copy</button></div>
<p class="hint">Set <code>COAP_HOST</code> / <code>COAP_PORT</code> to point at
another server; both default to <code>127.0.0.1:5683</code>.</p>
</div>
<div class="card">
<h2>Routes</h2>
<table>
<thead><tr><th>Request</th><th>Code</th><th>Response</th></tr></thead>
<tbody>
<tr><td class="code">GET /hello</td><td class="code ok">2.05</td><td class="code">Hello, World!</td></tr>
<tr><td class="code">GET /hello?name=…</td><td class="code ok">2.05</td><td class="code">Hello, …!</td></tr>
<tr><td class="code">POST /hello</td><td class="code ok">2.01</td><td class="code">Hello, &lt;payload&gt;!</td></tr>
<tr><td class="code">GET /health</td><td class="code ok">2.05</td><td class="code">{"status":"ok","uptime":12}</td></tr>
<tr><td class="code">POST /hello (empty)</td><td class="code err">4.00</td><td class="code">Bad Request</td></tr>
<tr><td class="code">GET /nope</td><td class="code err">4.04</td><td class="code">Not Found</td></tr>
<tr><td class="code">PUT /hello</td><td class="code err">4.05</td><td class="code">Method Not Allowed</td></tr>
</tbody>
</table>
<p class="hint">CoAP writes response codes as <code>class.detail</code>:
<code>2.05</code> is HTTP's 200, <code>4.04</code> its 404.
<code>POST /hello</code> takes raw text or <code>{"name":"…"}</code>.</p>
</div>
<div class="card">
<h2>Scripts</h2>
<p class="what">Full request/response suite against a running server</p>
<div class="cmd"><pre id="c-test">./test-coap.sh</pre><button data-copy="c-test">Copy</button></div>
<p class="what">Liveness check — exit 0 healthy, 1 not</p>
<div class="cmd"><pre id="c-health-sh">./healthcheck.sh -v</pre><button data-copy="c-health-sh">Copy</button></div>
<p class="what">Start the server</p>
<div class="cmd"><pre id="c-run">cargo run --release</pre><button data-copy="c-run">Copy</button></div>
</div>
</main>
<script>
const $ = (id) => document.getElementById(id);
const shell = (s) => "'" + String(s).replace(/'/g, `'\\''`) + "'";
function render() {
const name = $('name').value.trim();
const q = name ? '/hello?name=' + encodeURIComponent(name) : '/hello';
const who = name || 'Imran';
$('c-get').textContent = `./target/release/client get ${shell(q)}`;
$('c-post').textContent = `./target/release/client post /hello ${shell(who)}`;
$('c-json').textContent = `./target/release/client post /hello ${shell(JSON.stringify({ name: who }))}`;
$('c-health').textContent = `./target/release/client get /health`;
$('c-cli').textContent = `coap get ${shell('coap://localhost:5683' + q)}`;
}
document.querySelectorAll('button[data-copy]').forEach((btn) => {
btn.addEventListener('click', async () => {
const text = $(btn.dataset.copy).textContent;
try {
await navigator.clipboard.writeText(text);
} catch {
// file:// and non-secure origins deny the clipboard API; fall back.
const ta = document.createElement('textarea');
ta.value = text;
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
ta.remove();
}
btn.textContent = 'Copied';
btn.classList.add('copied');
setTimeout(() => { btn.textContent = 'Copy'; btn.classList.remove('copied'); }, 1200);
});
});
$('name').addEventListener('input', render);
render();
</script>
</body>
</html>