waffle/frontend/src/request.js

144 lines
4.8 KiB
JavaScript

import gateway from "./gateway";
import { apiRoute, getItem } from "./storage";
const method = (methodId, requiresAuthentication) => ({methodId, requiresAuthentication});
const withCacheable = (method) => ({ ...method, cacheable: true })
export const methods = {
createUser: method(100, false),
loginUser: method(101, false),
getUserSelf: withCacheable(method(102, true)),
promoteUserSelf: method(103, true),
putUserAvatar: method(104, true),
createChannel: method(200, true),
updateChannelName: method(201, true),
deleteChannel: method(202, true),
getChannel: withCacheable(method(203, true)),
getChannels: withCacheable(method(204, true)),
createChannelMessage: method(205, true),
getChannelMessages: withCacheable(method(206, true)),
putChannelTyping: method(207, true),
deleteMessage: method(300, true),
updateMessageContent: method(301, true),
getMessage: withCacheable(method(302, true)),
createCommunity: method(400, true),
updateCommunityName: method(401, true),
deleteCommunity: method(402, true),
getCommunity: withCacheable(method(403, true)),
getCommunities: withCacheable(method(404, true)),
getCommunityChannels: withCacheable(method(405, true)),
};
export function compatibleFetch(endpoint, options) {
if (window.fetch && typeof window.fetch === "function") {
return fetch(endpoint, options);
} else {
return new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
req.addEventListener("load", () => {
resolve({
status: req.status,
ok: [200, 201, 204].includes(req.status),
json() {
return JSON.parse(req.responseText);
}
});
});
req.addEventListener("error", (e) => {
reject(e);
});
req.open(options.method || "GET", endpoint);
if (options.headers) {
for (const [header, value] of Object.entries(options.headers)) {
req.setRequestHeader(header, value);
}
}
req.send(options.body);
});
}
}
export default function doRequest(method, endpoint, auth=true, body=null) {
return new Promise(async (resolve, _reject) => {
const options = {
method,
};
if (body) {
options.body = JSON.stringify(body);
options.headers = {
...options.headers || {},
"Content-Type": "application/json"
};
}
if (auth) {
const token = getItem("auth:token");
if (token) {
options.headers = {
...options.headers || {},
"Authorization": `Bearer ${token}`
};
}
}
try {
const res = await compatibleFetch(endpoint, options);
const json = res.status === 204 ? {} : await res.json();
return resolve({
json,
ok: res.ok,
});
} catch (e) {
return resolve({
json: null,
ok: false,
});
}
});
}
export async function remoteCall({methodId, requiresAuthentication, cacheable, _isSignal=false}, ...args) {
const calls = [[methodId, ...args]];
if (requiresAuthentication && gateway.authenticated && !cacheable) {
const replies = await gateway.sendRPCRequest(calls, _isSignal);
const ok = Array.isArray(replies) && !(replies[0] && replies[0].code);
return {
json: ok ? replies[0] : null,
ok
};
}
let response;
if (cacheable) {
response = await doRequest("GET", apiRoute(`rpc?calls=${encodeURI(JSON.stringify(calls))}`), requiresAuthentication);
} else {
response = await doRequest("POST", apiRoute("rpc"), requiresAuthentication, calls);
}
response.ok = response.ok && Array.isArray(response.json) && !(response.json[0] && response.json[0].code);
response.json = response.ok ? response.json[0] : null;
return response;
}
export async function remoteSignal(method, ...args) {
return await remoteCall({
...method,
_isSignal: true
}, ...args);
}
export async function remoteBlobUpload({methodId, requiresAuthentication, _isSignal=false}, blob) {
const calls = [[methodId, [0, blob.size]]];
if (requiresAuthentication && gateway.authenticated) {
const replies = await gateway.sendRPCRequest(calls, _isSignal, blob);
const ok = Array.isArray(replies) && !(replies[0] && replies[0].code);
return {
json: ok ? replies[0] : null,
ok
};
} else {
return { json: null, ok: false };
}
}