Update pages 🚀
This commit is contained in:
commit
35ce6de561
20 changed files with 822 additions and 0 deletions
1
.domains
Normal file
1
.domains
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ok-ready-go.speedclimbing.org
|
79
index.css
Normal file
79
index.css
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
@keyframes blinker {
|
||||||
|
50% {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
font-size: 2em;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timer {
|
||||||
|
font-size: 8em;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timer.over {
|
||||||
|
color: #0f0;
|
||||||
|
animation: blinker 2s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timer.sending {
|
||||||
|
color: #ff0;
|
||||||
|
animation: blinker 2s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timer-container-div {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timer-div {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tap-area {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide-before-init {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remote-connection-card {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 0;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
details {
|
||||||
|
border-bottom: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
104
index.html
Normal file
104
index.html
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
|
||||||
|
|
||||||
|
<script src="lib/crypto_helper.js"></script>
|
||||||
|
<script src="js/index.js"></script>
|
||||||
|
<script src="js/localState.js"></script>
|
||||||
|
<script src="js/mqtt.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css" />
|
||||||
|
<link rel="stylesheet" href="index.css" />
|
||||||
|
|
||||||
|
<audio id="sound-0" src="sound/0.mp3" preload="auto"></audio>
|
||||||
|
<audio id="sound-1" src="sound/1.mp3" preload="auto"></audio>
|
||||||
|
<audio id="sound-2" src="sound/2.mp3" preload="auto"></audio>
|
||||||
|
<audio id="sound-3" src="sound/3.mp3" preload="auto"></audio>
|
||||||
|
<audio id="sound-4" src="sound/4.mp3" preload="auto"></audio>
|
||||||
|
<audio id="sound-5" src="sound/5.mp3" preload="auto"></audio>
|
||||||
|
<audio id="sound-6" src="sound/6.mp3" preload="auto"></audio>
|
||||||
|
<audio id="sound-7" src="sound/7.mp3" preload="auto"></audio>
|
||||||
|
<audio id="sound-8" src="sound/8.mp3" preload="auto"></audio>
|
||||||
|
<audio id="sound-9" src="sound/9.mp3" preload="auto"></audio>
|
||||||
|
<audio id="sound-ok-ready-go" src="sound/ok-ready-go.mp3" preload="auto"></audio>
|
||||||
|
<audio id="sound-silence" src="sound/silence.mp3" preload="auto"></audio>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="timer-container-div hide-after-init">
|
||||||
|
<h1 class="loading" aria-busy="true">Initializing...</h1>
|
||||||
|
</div>
|
||||||
|
<main class="container hide-before-init" x-data>
|
||||||
|
<div class="timer-container-div" x-show="$store.localState._state !== 5">
|
||||||
|
<div @click="$store.localState.next()" class="tap-area" x-show="$store.localState._state === 2"></div>
|
||||||
|
<div @click="$store.localState.next()" class="timer-div">
|
||||||
|
<hgroup>
|
||||||
|
<h1>OK! .. READY! ... GO!</h1>
|
||||||
|
<h2><span x-text="$store.localState.stateHint"></span> <b x-show="$store.mqtt.connected">(connected)</b></h2>
|
||||||
|
</hgroup>
|
||||||
|
|
||||||
|
<div x-data="Timer">
|
||||||
|
<p :class="'timer' + (over ? ($store.localState._state === 3 ? ' sending':' over'):'')"
|
||||||
|
x-text="time + 's'"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div x-show="$store.localState._state === 0" class="remote-connection-card">
|
||||||
|
<div class="container">
|
||||||
|
<details>
|
||||||
|
<div class="container">
|
||||||
|
<p>If you want to automatically transfer the time to a computer, follow these steps:</p>
|
||||||
|
|
||||||
|
<div x-show="!$store.mqtt.connected">
|
||||||
|
<ul>
|
||||||
|
<li>Enter a password and press tap connect</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<form x-data="PasswordForm()" @submit.prevent="submitForm">
|
||||||
|
<label for="passwordForm_password">Password:</label>
|
||||||
|
<input id="passwordForm_password" type="text" x-model="formData.password"
|
||||||
|
placeholder="Password" />
|
||||||
|
<small>Make sure, this is exactly the same on your computer!</small>
|
||||||
|
<button type="submit">Connect</button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
<li>Download the receiver tool from <a
|
||||||
|
href="https://itsblue.dev/dorian/ok-ready-go/releases/latest">here</a> to your computer
|
||||||
|
</li>
|
||||||
|
<li>Start the receiver tool on your computer</li>
|
||||||
|
<li>Enter the same password on the receiver tool and click connect</li>
|
||||||
|
<li>Done!</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div x-show="$store.mqtt.connected">
|
||||||
|
<ul>
|
||||||
|
<li>Download the receiver tool from <a
|
||||||
|
href="https://itsblue.dev/dorian/ok-ready-go/releases/latest">here</a> to your computer
|
||||||
|
</li>
|
||||||
|
<li>Start the receiver tool on your computer</li>
|
||||||
|
<li>Enter the password '<b x-text="$store.localState.password"></b>' on the receiver tool and click connect</li>
|
||||||
|
<li>Done!</li>
|
||||||
|
<li>
|
||||||
|
<p>If you no longer want to send the time, tap Disconnect</p>
|
||||||
|
<button @click="$store.localState.password = ''">Disconnect</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<summary role="button">Remote connection</summary>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="timer-container-div" x-show="$store.localState._state === 5">
|
||||||
|
<h1 class="loading" aria-busy="true">Connecting...</h1>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
72
js/index.js
Normal file
72
js/index.js
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
async function sayNumber(number) {
|
||||||
|
console.log(number);
|
||||||
|
number = number.toString();
|
||||||
|
number = number.replace(/[^0-9]/, "");
|
||||||
|
for (let i = 0; i < number.length; i++) {
|
||||||
|
await playAudio(document.getElementById(`sound-${number[i]}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function playAudio(audio) {
|
||||||
|
return new Promise((res) => {
|
||||||
|
audio.play();
|
||||||
|
audio.onended = res;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function uuidv4() {
|
||||||
|
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
|
||||||
|
(
|
||||||
|
c ^
|
||||||
|
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
|
||||||
|
).toString(16)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function PasswordForm() {
|
||||||
|
return {
|
||||||
|
formData: {
|
||||||
|
password: "",
|
||||||
|
},
|
||||||
|
submitForm() {
|
||||||
|
Alpine.store("localState").password = this.formData.password;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function Timer() {
|
||||||
|
return {
|
||||||
|
time: 0,
|
||||||
|
over: false,
|
||||||
|
init() {
|
||||||
|
setInterval(() => {
|
||||||
|
const startedAt = Alpine.store("localState").startedAt;
|
||||||
|
const resultTime = Alpine.store("localState").time;
|
||||||
|
|
||||||
|
let time;
|
||||||
|
if (!startedAt && !resultTime) {
|
||||||
|
time = 0;
|
||||||
|
this.over = false;
|
||||||
|
} else if (resultTime) {
|
||||||
|
time = resultTime / 1000;
|
||||||
|
this.over = true;
|
||||||
|
} else {
|
||||||
|
this.over = false;
|
||||||
|
time = (new Date().getTime() - startedAt) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.time = time.toFixed(2);
|
||||||
|
}, 10);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = new Event('wasm-loaded');
|
||||||
|
wasm_bindgen('lib/crypto_helper_bg.wasm').then(() => {
|
||||||
|
document.dispatchEvent(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("alpine:init", () => {
|
||||||
|
document.getElementsByClassName("hide-after-init").item(0).outerHTML = ""
|
||||||
|
document.getElementsByClassName("hide-before-init").item(0).classList.remove("hide-before-init")
|
||||||
|
});
|
105
js/localState.js
Normal file
105
js/localState.js
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
document.addEventListener("alpine:init", () => {
|
||||||
|
Alpine.store("localState", {
|
||||||
|
_state: 0,
|
||||||
|
// 0: idle
|
||||||
|
// 1: starting
|
||||||
|
// 2: running
|
||||||
|
// 3: sending time to mqtt
|
||||||
|
// 4: stopped
|
||||||
|
// 5: connecting to mqtt
|
||||||
|
|
||||||
|
startedAt: null,
|
||||||
|
time: null,
|
||||||
|
stateHint: "",
|
||||||
|
password: null,
|
||||||
|
|
||||||
|
init() {
|
||||||
|
Alpine.effect(() => {
|
||||||
|
if (this.password == null) {
|
||||||
|
this.password = localStorage.getItem("password");
|
||||||
|
} else {
|
||||||
|
localStorage.setItem("password", this.password);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mqtt = Alpine.store("mqtt");
|
||||||
|
if (!mqtt) return;
|
||||||
|
if (this.password == null || this.password == "") {
|
||||||
|
mqtt.disconnect();
|
||||||
|
} else {
|
||||||
|
mqtt.connect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Alpine.effect(() => {
|
||||||
|
switch (this._state) {
|
||||||
|
case 0:
|
||||||
|
this.stateHint = "Tap here to start";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
this.stateHint = "Get ready...";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this.stateHint = "Tap anywhere to stop";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
this.stateHint = "Sending time to MQTT...";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
this.stateHint = "Tap here to reset";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
next() {
|
||||||
|
playAudio(document.getElementById("sound-silence"));
|
||||||
|
|
||||||
|
if (this._state == 1 || this._state == 3) return;
|
||||||
|
|
||||||
|
this._setState((this._state + 1) % 5);
|
||||||
|
},
|
||||||
|
|
||||||
|
_setState(state) {
|
||||||
|
switch (state) {
|
||||||
|
case 0: {
|
||||||
|
this.startedAt = null;
|
||||||
|
this.time = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
playAudio(document.getElementById("sound-ok-ready-go")).then(() => {
|
||||||
|
Alpine.store("localState")._setState(2);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
this.startedAt = new Date().getTime() - 200;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
this.time =
|
||||||
|
Math.floor(((new Date().getTime() - this.startedAt) / 1000).toFixed(2) * 1000);
|
||||||
|
this.startedAt = null;
|
||||||
|
sayNumber(this.time / 10);
|
||||||
|
|
||||||
|
if (Alpine.store("mqtt").connected) {
|
||||||
|
Alpine.store("mqtt")
|
||||||
|
.sendTime(this.time)
|
||||||
|
.then(() => {
|
||||||
|
Alpine.store("localState")._setState(4);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._state = state;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
132
js/mqtt.js
Normal file
132
js/mqtt.js
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
let wasm_inited_resolve;
|
||||||
|
const wasm_inited = new Promise((resolve) => {
|
||||||
|
wasm_inited_resolve = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("wasm-loaded", () => {
|
||||||
|
wasm_inited_resolve(wasm_bindgen);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("alpine:init", () => {
|
||||||
|
Alpine.store("mqtt", {
|
||||||
|
connected: false,
|
||||||
|
_client: null,
|
||||||
|
_topics: null,
|
||||||
|
_c: null,
|
||||||
|
|
||||||
|
_pendingPromises: {},
|
||||||
|
|
||||||
|
sendTime(time) {
|
||||||
|
if (!this.connected) return null;
|
||||||
|
|
||||||
|
const id = uuidv4();
|
||||||
|
const promise = new Promise((resolve, reject) => {
|
||||||
|
this._pendingPromises[id] = [resolve, reject];
|
||||||
|
});
|
||||||
|
this._publish({
|
||||||
|
id: id, // used to prevent replay attacks and to identify confirm messages
|
||||||
|
kind: "Time", // can be "time" or "confirm"
|
||||||
|
time: time, // only used for "time"
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
},
|
||||||
|
|
||||||
|
async connect() {
|
||||||
|
if (this.connected) return;
|
||||||
|
|
||||||
|
const password = Alpine.store("localState").password;
|
||||||
|
const that = this;
|
||||||
|
const brokerDomain = "broker.emqx.io";
|
||||||
|
const url = `wss://${brokerDomain}:8084/mqtt`;
|
||||||
|
|
||||||
|
if (!password) return false;
|
||||||
|
|
||||||
|
const { Crypto } = await wasm_inited;
|
||||||
|
|
||||||
|
Alpine.store("localState")._state = 5;
|
||||||
|
|
||||||
|
// derive key from password
|
||||||
|
this._c = new Crypto(password, brokerDomain);
|
||||||
|
|
||||||
|
console.log("Test", this._encrypt("test"));
|
||||||
|
|
||||||
|
this._topics = {
|
||||||
|
time: Crypto.sha256(
|
||||||
|
this._encrypt(`org.speedclimbing.ok-ready-go.${password}.time`)
|
||||||
|
).toString(),
|
||||||
|
confirmation: Crypto.sha256(
|
||||||
|
this._encrypt(
|
||||||
|
`org.speedclimbing.ok-ready-go.${password}.confirmation`
|
||||||
|
)
|
||||||
|
).toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("Connecting to MQTT broker...");
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
// Clean session
|
||||||
|
clean: true,
|
||||||
|
connectTimeout: 4000,
|
||||||
|
};
|
||||||
|
|
||||||
|
this._client = mqtt.connect(url, options);
|
||||||
|
|
||||||
|
this._client.on("connect", () => {
|
||||||
|
Alpine.store("localState")._state = 0;
|
||||||
|
|
||||||
|
that._client.subscribe(that._topics.confirmation);
|
||||||
|
this.connected = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._client.on("message", (topic, message) => {
|
||||||
|
// message is Buffer
|
||||||
|
message = that._decrypt(message.toString());
|
||||||
|
const data = JSON.parse(message);
|
||||||
|
|
||||||
|
if (
|
||||||
|
topic !== that._topics.confirmation ||
|
||||||
|
data.kind !== "Confirm" ||
|
||||||
|
Object.keys(this._pendingPromises).indexOf(data.id) === -1
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
console.log("<<< ", data);
|
||||||
|
this._pendingPromises[data.id][0]();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
if (!this.connected) return;
|
||||||
|
|
||||||
|
this._client.end(true);
|
||||||
|
|
||||||
|
this._client = null;
|
||||||
|
this.connected = false;
|
||||||
|
this._topics = null;
|
||||||
|
|
||||||
|
for (const promiseId in this._pendingPromises) {
|
||||||
|
this._pendingPromises[promiseId][1]();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._pendingPromises = {};
|
||||||
|
},
|
||||||
|
|
||||||
|
_publish(data) {
|
||||||
|
const encryptedData = this._encrypt(JSON.stringify(data));
|
||||||
|
console.log(">>> ", data);
|
||||||
|
this._client.publish(this._topics.time, encryptedData, {
|
||||||
|
qos: 1,
|
||||||
|
retain: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_encrypt(data) {
|
||||||
|
return this._c.encrypt(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
_decrypt(data) {
|
||||||
|
return this._c.decrypt(data);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
329
lib/crypto_helper.js
Normal file
329
lib/crypto_helper.js
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
let wasm_bindgen;
|
||||||
|
(function() {
|
||||||
|
const __exports = {};
|
||||||
|
let script_src;
|
||||||
|
if (typeof document === 'undefined') {
|
||||||
|
script_src = location.href;
|
||||||
|
} else {
|
||||||
|
script_src = new URL(document.currentScript.src, location.href).toString();
|
||||||
|
}
|
||||||
|
let wasm;
|
||||||
|
|
||||||
|
const heap = new Array(128).fill(undefined);
|
||||||
|
|
||||||
|
heap.push(undefined, null, true, false);
|
||||||
|
|
||||||
|
function getObject(idx) { return heap[idx]; }
|
||||||
|
|
||||||
|
let heap_next = heap.length;
|
||||||
|
|
||||||
|
function dropObject(idx) {
|
||||||
|
if (idx < 132) return;
|
||||||
|
heap[idx] = heap_next;
|
||||||
|
heap_next = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
function takeObject(idx) {
|
||||||
|
const ret = getObject(idx);
|
||||||
|
dropObject(idx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
||||||
|
|
||||||
|
cachedTextDecoder.decode();
|
||||||
|
|
||||||
|
let cachedUint8Memory0 = null;
|
||||||
|
|
||||||
|
function getUint8Memory0() {
|
||||||
|
if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
|
||||||
|
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
|
||||||
|
}
|
||||||
|
return cachedUint8Memory0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStringFromWasm0(ptr, len) {
|
||||||
|
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
|
||||||
|
}
|
||||||
|
|
||||||
|
let WASM_VECTOR_LEN = 0;
|
||||||
|
|
||||||
|
const cachedTextEncoder = new TextEncoder('utf-8');
|
||||||
|
|
||||||
|
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
|
||||||
|
? function (arg, view) {
|
||||||
|
return cachedTextEncoder.encodeInto(arg, view);
|
||||||
|
}
|
||||||
|
: function (arg, view) {
|
||||||
|
const buf = cachedTextEncoder.encode(arg);
|
||||||
|
view.set(buf);
|
||||||
|
return {
|
||||||
|
read: arg.length,
|
||||||
|
written: buf.length
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function passStringToWasm0(arg, malloc, realloc) {
|
||||||
|
|
||||||
|
if (realloc === undefined) {
|
||||||
|
const buf = cachedTextEncoder.encode(arg);
|
||||||
|
const ptr = malloc(buf.length);
|
||||||
|
getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
|
||||||
|
WASM_VECTOR_LEN = buf.length;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
let len = arg.length;
|
||||||
|
let ptr = malloc(len);
|
||||||
|
|
||||||
|
const mem = getUint8Memory0();
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
for (; offset < len; offset++) {
|
||||||
|
const code = arg.charCodeAt(offset);
|
||||||
|
if (code > 0x7F) break;
|
||||||
|
mem[ptr + offset] = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset !== len) {
|
||||||
|
if (offset !== 0) {
|
||||||
|
arg = arg.slice(offset);
|
||||||
|
}
|
||||||
|
ptr = realloc(ptr, len, len = offset + arg.length * 3);
|
||||||
|
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
|
||||||
|
const ret = encodeString(arg, view);
|
||||||
|
|
||||||
|
offset += ret.written;
|
||||||
|
}
|
||||||
|
|
||||||
|
WASM_VECTOR_LEN = offset;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cachedInt32Memory0 = null;
|
||||||
|
|
||||||
|
function getInt32Memory0() {
|
||||||
|
if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) {
|
||||||
|
cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);
|
||||||
|
}
|
||||||
|
return cachedInt32Memory0;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
__exports.greet = function() {
|
||||||
|
wasm.greet();
|
||||||
|
};
|
||||||
|
|
||||||
|
function addHeapObject(obj) {
|
||||||
|
if (heap_next === heap.length) heap.push(heap.length + 1);
|
||||||
|
const idx = heap_next;
|
||||||
|
heap_next = heap[idx];
|
||||||
|
|
||||||
|
heap[idx] = obj;
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
class Crypto {
|
||||||
|
|
||||||
|
static __wrap(ptr) {
|
||||||
|
const obj = Object.create(Crypto.prototype);
|
||||||
|
obj.ptr = ptr;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
__destroy_into_raw() {
|
||||||
|
const ptr = this.ptr;
|
||||||
|
this.ptr = 0;
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
free() {
|
||||||
|
const ptr = this.__destroy_into_raw();
|
||||||
|
wasm.__wbg_crypto_free(ptr);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {string} password
|
||||||
|
* @param {string} salt
|
||||||
|
*/
|
||||||
|
constructor(password, salt) {
|
||||||
|
const ptr0 = passStringToWasm0(password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
const len0 = WASM_VECTOR_LEN;
|
||||||
|
const ptr1 = passStringToWasm0(salt, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
const len1 = WASM_VECTOR_LEN;
|
||||||
|
const ret = wasm.crypto_new(ptr0, len0, ptr1, len1);
|
||||||
|
return Crypto.__wrap(ret);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
static sha256(input) {
|
||||||
|
try {
|
||||||
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||||
|
const ptr0 = passStringToWasm0(input, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
const len0 = WASM_VECTOR_LEN;
|
||||||
|
wasm.crypto_sha256(retptr, ptr0, len0);
|
||||||
|
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||||
|
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||||
|
return getStringFromWasm0(r0, r1);
|
||||||
|
} finally {
|
||||||
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
||||||
|
wasm.__wbindgen_free(r0, r1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {string} plaintext
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
encrypt(plaintext) {
|
||||||
|
try {
|
||||||
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||||
|
const ptr0 = passStringToWasm0(plaintext, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
const len0 = WASM_VECTOR_LEN;
|
||||||
|
wasm.crypto_encrypt(retptr, this.ptr, ptr0, len0);
|
||||||
|
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||||
|
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||||
|
return getStringFromWasm0(r0, r1);
|
||||||
|
} finally {
|
||||||
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
||||||
|
wasm.__wbindgen_free(r0, r1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {string} ciphertext
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
decrypt(ciphertext) {
|
||||||
|
try {
|
||||||
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||||
|
const ptr0 = passStringToWasm0(ciphertext, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
const len0 = WASM_VECTOR_LEN;
|
||||||
|
wasm.crypto_decrypt(retptr, this.ptr, ptr0, len0);
|
||||||
|
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||||
|
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||||
|
return getStringFromWasm0(r0, r1);
|
||||||
|
} finally {
|
||||||
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
||||||
|
wasm.__wbindgen_free(r0, r1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__exports.Crypto = Crypto;
|
||||||
|
|
||||||
|
async function load(module, imports) {
|
||||||
|
if (typeof Response === 'function' && module instanceof Response) {
|
||||||
|
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||||
|
try {
|
||||||
|
return await WebAssembly.instantiateStreaming(module, imports);
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
if (module.headers.get('Content-Type') != 'application/wasm') {
|
||||||
|
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bytes = await module.arrayBuffer();
|
||||||
|
return await WebAssembly.instantiate(bytes, imports);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const instance = await WebAssembly.instantiate(module, imports);
|
||||||
|
|
||||||
|
if (instance instanceof WebAssembly.Instance) {
|
||||||
|
return { instance, module };
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getImports() {
|
||||||
|
const imports = {};
|
||||||
|
imports.wbg = {};
|
||||||
|
imports.wbg.__wbg_alert_0cc0cb8b17d72dde = function(arg0, arg1) {
|
||||||
|
alert(getStringFromWasm0(arg0, arg1));
|
||||||
|
};
|
||||||
|
imports.wbg.__wbg_new_abda76e883ba8a5f = function() {
|
||||||
|
const ret = new Error();
|
||||||
|
return addHeapObject(ret);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbg_stack_658279fe44541cf6 = function(arg0, arg1) {
|
||||||
|
const ret = getObject(arg1).stack;
|
||||||
|
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
const len0 = WASM_VECTOR_LEN;
|
||||||
|
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||||
|
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbg_error_f851667af71bcfc6 = function(arg0, arg1) {
|
||||||
|
try {
|
||||||
|
console.error(getStringFromWasm0(arg0, arg1));
|
||||||
|
} finally {
|
||||||
|
wasm.__wbindgen_free(arg0, arg1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
|
||||||
|
takeObject(arg0);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
|
||||||
|
throw new Error(getStringFromWasm0(arg0, arg1));
|
||||||
|
};
|
||||||
|
|
||||||
|
return imports;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initMemory(imports, maybe_memory) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function finalizeInit(instance, module) {
|
||||||
|
wasm = instance.exports;
|
||||||
|
init.__wbindgen_wasm_module = module;
|
||||||
|
cachedInt32Memory0 = null;
|
||||||
|
cachedUint8Memory0 = null;
|
||||||
|
|
||||||
|
|
||||||
|
return wasm;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initSync(module) {
|
||||||
|
const imports = getImports();
|
||||||
|
|
||||||
|
initMemory(imports);
|
||||||
|
|
||||||
|
if (!(module instanceof WebAssembly.Module)) {
|
||||||
|
module = new WebAssembly.Module(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
const instance = new WebAssembly.Instance(module, imports);
|
||||||
|
|
||||||
|
return finalizeInit(instance, module);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function init(input) {
|
||||||
|
if (typeof input === 'undefined') {
|
||||||
|
input = script_src.replace(/\.js$/, '_bg.wasm');
|
||||||
|
}
|
||||||
|
const imports = getImports();
|
||||||
|
|
||||||
|
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
|
||||||
|
input = fetch(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
initMemory(imports);
|
||||||
|
|
||||||
|
const { instance, module } = await load(await input, imports);
|
||||||
|
|
||||||
|
return finalizeInit(instance, module);
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_bindgen = Object.assign(init, { initSync }, __exports);
|
||||||
|
|
||||||
|
})();
|
BIN
lib/crypto_helper_bg.wasm
Normal file
BIN
lib/crypto_helper_bg.wasm
Normal file
Binary file not shown.
BIN
sound/0.mp3
Normal file
BIN
sound/0.mp3
Normal file
Binary file not shown.
BIN
sound/1.mp3
Normal file
BIN
sound/1.mp3
Normal file
Binary file not shown.
BIN
sound/2.mp3
Normal file
BIN
sound/2.mp3
Normal file
Binary file not shown.
BIN
sound/3.mp3
Normal file
BIN
sound/3.mp3
Normal file
Binary file not shown.
BIN
sound/4.mp3
Normal file
BIN
sound/4.mp3
Normal file
Binary file not shown.
BIN
sound/5.mp3
Normal file
BIN
sound/5.mp3
Normal file
Binary file not shown.
BIN
sound/6.mp3
Normal file
BIN
sound/6.mp3
Normal file
Binary file not shown.
BIN
sound/7.mp3
Normal file
BIN
sound/7.mp3
Normal file
Binary file not shown.
BIN
sound/8.mp3
Normal file
BIN
sound/8.mp3
Normal file
Binary file not shown.
BIN
sound/9.mp3
Normal file
BIN
sound/9.mp3
Normal file
Binary file not shown.
BIN
sound/ok-ready-go.mp3
Normal file
BIN
sound/ok-ready-go.mp3
Normal file
Binary file not shown.
BIN
sound/silence.mp3
Normal file
BIN
sound/silence.mp3
Normal file
Binary file not shown.
Loading…
Reference in a new issue