215 lines
7.4 KiB
JavaScript
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
|
|
};
|
|
}
|
|
}
|