waffle/frontend/src/request.js
2023-07-23 05:06:07 +03:00

215 lines
7.4 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 const RPCError = {
BAD_REQUEST: { code: 6000, message: "Bad request" },
RPC_VALIDATION_ERROR: { code: 6001, message: "We couldn't validate this request" },
BAD_LOGIN_CREDENTIALS: { code: 6002, message: "Incorrect login credentials" },
BAD_AUTH: { code: 6003, message: "You're not authenticated" },
NOT_FOUND: { code: 6004, message: "Not found" },
FORBIDDEN_DUE_TO_MISSING_PERMISSIONS: { code: 6005, message: "You don't have the required permissions to perform this action" },
BAD_REQUEST_KEY: { code: 6006, message: "This request requires a special password, however, the password you provided was incorrect" },
GOT_NO_DATABASE_DATA: { code: 7001, message: "Sorry, we couldn't process this request (server expected data from database, however got none)" },
FEATURE_DISABLED: { code: 7002, message: "This feature is disabled" },
INTERNAL_ERROR: { code: 7003, message: "Sorry, we couldn't process this request (internal server error)" },
};
export const RequestStatus = {
OK: 0,
NETWORK_EXCEPTION: 1,
JSON_EXCEPTION: 2,
FAILURE_STATUS: 3,
RPC_ERROR: 4,
INVARIANT_RPC_RESPONSE_COUNT: 5,
};
export const RequestStatusToMessage = {
[RequestStatus.OK]: "",
[RequestStatus.NETWORK_EXCEPTION]: "We couldn't reach the server right now",
[RequestStatus.JSON_EXCEPTION]: "We couldn't process this request right now (server gave an invalid response, failed to parse as JSON)",
[RequestStatus.FAILURE_STATUS]: "We couldn't process this request right now (server gave a failure status code)",
[RequestStatus.RPC_ERROR]: "We couldn't process this request right now (RPC error)",
[RequestStatus.INVARIANT_RPC_RESPONSE_COUNT]: "We couldn't process this request right now (invalid RPC response)",
};
export function getErrorFromResponse(response) {
if (!response) return;
if (response.status === RequestStatus.OK) return;
console.log(response);
let message = RequestStatusToMessage[response.status];
if (!message) message = "Something went wrong (unknown request error)";
if (response.status === RequestStatus.RPC_ERROR) {
let rpcErrorMessage = Object.values(RPCError).find(({ code }) => code === response.data.code);
if (rpcErrorMessage) {
rpcErrorMessage = rpcErrorMessage.message;
} else {
rpcErrorMessage = "Something went wrong (unknown RPC error)";
}
if (response.data.code === RPCError.RPC_VALIDATION_ERROR.code) {
return { message: rpcErrorMessage, validationErrors: response.data.errors };
}
return { message: rpcErrorMessage };
}
return { message };
}
export function getMessageFromResponse(response) {
return getErrorFromResponse(response).message || "Something went wrong";
}
export function responseOk(response) {
if (response.status !== RequestStatus.OK) return false;
return true;
}
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}`
};
}
}
let res;
try {
res = await fetch(endpoint, options);
} catch(o_O) {
return resolve({
status: RequestStatus.NETWORK_EXCEPTION
});
}
let json;
try {
json = res.status === 204 ? {} : await res.json();
} catch(o_O) {
return resolve({
status: RequestStatus.JSON_EXCEPTION
});
}
resolve({
data: json,
status: res.ok ? RequestStatus.OK : RequestStatus.FAILURE_STATUS
});
});
}
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);
if (!Array.isArray(replies) || replies.length !== 1) {
return { status: RequestStatus.INVARIANT_RPC_RESPONSE_COUNT };
}
const reply = replies[0];
return {
data: reply,
status: reply && reply.code ? RequestStatus.RPC_ERROR : RequestStatus.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);
}
if (response.status !== RequestStatus.OK) {
return { status: response.status };
}
if (!Array.isArray(response.data) || response.data.length !== 1) {
return { status: RequestStatus.INVARIANT_RPC_RESPONSE_COUNT };
}
const reply = response.data[0];
return {
data: reply,
status: reply && reply.code ? RequestStatus.RPC_ERROR : RequestStatus.OK
};
}
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);
if (!Array.isArray(replies) || replies.length !== 1) {
return { status: RequestStatus.INVARIANT_RPC_RESPONSE_COUNT };
}
const reply = replies[0];
return {
data: reply,
status: reply && reply.code ? RequestStatus.RPC_ERROR : RequestStatus.OK
};
} else {
return {
status: RequestStatus.NETWORK_EXCEPTION
};
}
}