better utilize caching for rpc
This commit is contained in:
parent
adee96f697
commit
6ab0eb8351
5 changed files with 52 additions and 28 deletions
|
@ -1,25 +1,26 @@
|
|||
import gateway from "./gateway";
|
||||
import { apiRoute, getItem } from "./storage";
|
||||
// TODO: circular dependency
|
||||
import { overlayStore, OverlayType } from "./stores";
|
||||
|
||||
const method = (methodId, requiresAuthentication) => ({methodId, requiresAuthentication});
|
||||
const withCacheable = (method) => ({ ...method, cacheable: true })
|
||||
|
||||
export const methods = {
|
||||
// methodName: [ methodId, requiresAuthentication ]
|
||||
createUser: [ 0, false ],
|
||||
loginUser: [ 1, false ],
|
||||
getUserSelf: [ 2, true ],
|
||||
promoteUserSelf: [ 3, true ],
|
||||
createChannel: [ 4, true ],
|
||||
updateChannelName: [ 5, true ],
|
||||
deleteChannel: [ 6, true ],
|
||||
getChannel: [ 7, true ],
|
||||
getChannels: [ 8, true ],
|
||||
createChannelMessage: [ 9, true ],
|
||||
getChannelMessages: [ 10, true ],
|
||||
putChannelTyping: [ 11, true ],
|
||||
deleteMessage: [ 12, true ],
|
||||
updateMessageContent: [ 13, true ],
|
||||
getMessage: [ 14, true ]
|
||||
createUser: method(0, false),
|
||||
loginUser: method(1, false),
|
||||
getUserSelf: withCacheable(method(2, true)),
|
||||
promoteUserSelf: method(3, true),
|
||||
createChannel: method(4, true),
|
||||
updateChannelName: method(5, true),
|
||||
deleteChannel: method(6, true),
|
||||
getChannel: withCacheable(method(7, true)),
|
||||
getChannels: withCacheable(method(8, true)),
|
||||
createChannelMessage: method(9, true),
|
||||
getChannelMessages: withCacheable(method(10, true)),
|
||||
putChannelTyping: method(11, true),
|
||||
deleteMessage: method(12, true),
|
||||
updateMessageContent: method(13, true),
|
||||
getMessage: withCacheable(method(14, true))
|
||||
};
|
||||
|
||||
export function compatibleFetch(endpoint, options) {
|
||||
|
@ -93,9 +94,9 @@ export default function doRequest(method, endpoint, auth=true, body=null) {
|
|||
});
|
||||
}
|
||||
|
||||
export async function remoteCall([methodId, requiresAuthentication], ...args) {
|
||||
export async function remoteCall({methodId, requiresAuthentication, cacheable}, ...args) {
|
||||
const calls = [[methodId, ...args]];
|
||||
if (requiresAuthentication && gateway.authenticated) {
|
||||
if (requiresAuthentication && gateway.authenticated && !cacheable) {
|
||||
const replies = await gateway.sendRPCRequest(calls);
|
||||
const ok = Array.isArray(replies) && replies[0] && !replies[0].code;
|
||||
return {
|
||||
|
@ -104,7 +105,12 @@ export async function remoteCall([methodId, requiresAuthentication], ...args) {
|
|||
};
|
||||
}
|
||||
|
||||
const response = await doRequest("POST", apiRoute("rpc"), requiresAuthentication, calls);
|
||||
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;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export const errors = {
|
||||
INVALID_RPC_CALL: { code: 6000, message: "Invalid RPC call. Please see 'detail' property." },
|
||||
INVALID_DATA: { code: 6001, message: "Invalid data" },
|
||||
BAD_REQUEST: { code: 6000, message: "Bad request, see 'detail' field for more information" },
|
||||
RPC_VALIDATION_ERROR: { code: 6001, message: "RPC validation error, see 'errors' field for more information" },
|
||||
BAD_LOGIN_CREDENTIALS: { code: 6002, message: "Bad login credentials provided" },
|
||||
BAD_AUTH: { code: 6003, message: "Bad authentication" },
|
||||
NOT_FOUND: { code: 6004, message: "Not found" },
|
||||
|
|
|
@ -13,4 +13,22 @@ router.post(
|
|||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/",
|
||||
authenticateRoute(false),
|
||||
async (req, res) => {
|
||||
const call = req.query.calls;
|
||||
if (typeof call !== "string" || !call.length || call.length > 4500) {
|
||||
return res.json({ ...errors.BAD_REQUEST, detail: "Bad 'call': expected string between 1 and 4500 characters" });
|
||||
}
|
||||
let callJson;
|
||||
try {
|
||||
callJson = JSON.parse(call);
|
||||
} catch(O_o) {
|
||||
return res.json({ ...errors.BAD_REQUEST, detail: "Bad 'call': failed to parse as JSON" });
|
||||
}
|
||||
res.json(await processMethodBatch(req.authenticated ? req.user : null, callJson));
|
||||
}
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
|
|
@ -17,7 +17,7 @@ methodButWarningDoesNotAuthenticate(
|
|||
const existingUser = await query("SELECT * FROM users WHERE username = $1", [username]);
|
||||
if (existingUser && existingUser.rowCount > 0) {
|
||||
return {
|
||||
...errors.INVALID_DATA,
|
||||
...errors.RPC_VALIDATION_ERROR,
|
||||
errors: [ { index: 0, msg: "Username already exists" } ]
|
||||
};
|
||||
}
|
||||
|
|
|
@ -56,13 +56,13 @@ export const methodButWarningDoesNotAuthenticate = (name: string, args: RPCArgum
|
|||
export const userInvokeMethod = async (user: User | null, methodId: number, args: any[]) => {
|
||||
const methodData = methods.get(methodId);
|
||||
if (!methodData) return {
|
||||
...errors.INVALID_RPC_CALL,
|
||||
...errors.BAD_REQUEST,
|
||||
detail: "The method was not found."
|
||||
};
|
||||
|
||||
const argSchema = methodData.args;
|
||||
if (argSchema.length !== args.length) return {
|
||||
...errors.INVALID_RPC_CALL,
|
||||
...errors.BAD_REQUEST,
|
||||
detail: "Invalid number of arguments provided to method."
|
||||
};
|
||||
|
||||
|
@ -107,7 +107,7 @@ export const userInvokeMethod = async (user: User | null, methodId: number, args
|
|||
|
||||
if (validationErrors.length !== 0) {
|
||||
return {
|
||||
...errors.INVALID_DATA,
|
||||
...errors.RPC_VALIDATION_ERROR,
|
||||
errors: validationErrors
|
||||
};
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ export const userInvokeMethod = async (user: User | null, methodId: number, args
|
|||
export const processMethodBatch = async (user: User | null, calls: any) => {
|
||||
if (!Array.isArray(calls) || !calls.length || calls.length > 5) {
|
||||
return {
|
||||
...errors.INVALID_RPC_CALL,
|
||||
...errors.BAD_REQUEST,
|
||||
detail: "Expected RPC batch: an array of arrays with at least a single element and at most 5 elements, where each inner array represents a method call."
|
||||
};
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ export const processMethodBatch = async (user: User | null, calls: any) => {
|
|||
calls.forEach((call, index) => {
|
||||
if (!Array.isArray(call) || !call.length || call.length > 8) {
|
||||
responses[index] = {
|
||||
...errors.INVALID_RPC_CALL,
|
||||
...errors.BAD_REQUEST,
|
||||
detail: "Invalid method call. Expected inner array with at least one element and at most 8 elements."
|
||||
};
|
||||
return;
|
||||
|
|
Loading…
Reference in a new issue