1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
import * as utils from "/static/utils.js";
const doFetch = async (req) => {
let res, jsonRes;
try {
res = await fetch(req);
jsonRes = await res.json();
} catch (e) {
if (e instanceof SyntaxError)
e = new Error(`status ${res.status}, empty (or invalid) response body`);
console.error(`api call ${req.method} ${req.url}: unexpected error:`, e);
throw e;
}
if (jsonRes.error) {
console.error(
`api call ${req.method} ${req.url}: application error:`,
res.status,
jsonRes.error,
);
throw jsonRes.error;
}
return jsonRes;
}
// may throw
const solvePow = async () => {
const res = await call('/api/pow/challenge');
const worker = new Worker('/static/solvePow.js');
const p = new Promise((resolve, reject) => {
worker.postMessage({seedHex: res.seed, target: res.target});
worker.onmessage = resolve;
});
const powSol = (await p).data;
worker.terminate();
return {seed: res.seed, solution: powSol};
}
const call = async (route, opts = {}) => {
const {
method = 'POST',
body = {},
requiresPow = false,
} = opts;
const reqOpts = {
method,
};
if (requiresPow) {
const {seed, solution} = await solvePow();
body.powSeed = seed;
body.powSolution = solution;
}
if (Object.keys(body).length > 0) {
const form = new FormData();
for (const key in body) form.append(key, body[key]);
reqOpts.body = form;
}
const req = new Request(route, reqOpts);
return doFetch(req);
}
const ws = async (route, opts = {}) => {
const {
requiresPow = false,
params = {},
} = opts;
const docURL = new URL(document.URL);
const protocol = docURL.protocol == "http:" ? "ws:" : "wss:";
const fullParams = new URLSearchParams(params);
if (requiresPow) {
const {seed, solution} = await solvePow();
fullParams.set("powSeed", seed);
fullParams.set("powSolution", solution);
}
const rawConn = new WebSocket(`${protocol}//${docURL.host}${route}?${fullParams.toString()}`);
const conn = {
next: () => new Promise((resolve, reject) => {
rawConn.onmessage = (m) => {
const mj = JSON.parse(m.data);
resolve(mj);
};
rawConn.onerror = reject;
rawConn.onclose = reject;
}),
close: rawConn.close,
};
return new Promise((resolve, reject) => {
rawConn.onopen = () => resolve(conn);
rawConn.onerror = reject;
});
}
export {
call,
ws
}
|