Add some validation

This commit is contained in:
Micah Allen 2018-11-02 00:36:03 -04:00
parent 26c110f316
commit b628bb9ee9

View File

@ -3,6 +3,8 @@ const util = require('./util.js');
const environment = util.getEnvironment(); const environment = util.getEnvironment();
if(!environment) throw 'Unknown RAGE environment'; if(!environment) throw 'Unknown RAGE environment';
const ERR_NOT_FOUND = 'PROCEDURE_NOT_FOUND';
const PROCESS_EVENT = '__rpc:process'; const PROCESS_EVENT = '__rpc:process';
const PROCEDURE_EXISTS = '__rpc:exists'; const PROCEDURE_EXISTS = '__rpc:exists';
@ -13,17 +15,18 @@ const pending = {};
let passEventToBrowser, passEventToBrowsers; let passEventToBrowser, passEventToBrowsers;
if(environment === "client"){ if(environment === "client"){
passEventToBrowser = (browser, raw) => { passEventToBrowser = (browser, data) => {
browser.execute(`var process = window["${PROCESS_EVENT}"] || function(){}; process('${raw}');`); const raw = util.stringifyData(data);
browser.execute(`var process = window["${PROCESS_EVENT}"]; if(process){ process('${raw}'); }else{ mp.trigger("${PROCESS_EVENT}", '{"ret":1,"id":"${data.id}","err":"${ERR_NOT_FOUND}"}'); }`);
}; };
passEventToBrowsers = (raw) => { passEventToBrowsers = (data) => {
mp.browsers.forEach(browser => passEventToBrowser(browser, raw)); mp.browsers.forEach(browser => passEventToBrowser(browser, data));
}; };
} }
async function callProcedure(name, args, info){ async function callProcedure(name, args, info){
if(!listeners[name]) throw 'PROCEDURE_NOT_FOUND'; if(!listeners[name]) throw ERR_NOT_FOUND;
return listeners[name](args, info); return listeners[name](args, info);
} }
@ -73,15 +76,15 @@ const processEvent = (...args) => {
}); });
}else if(data.env === "cef"){ }else if(data.env === "cef"){
promise.then(res => { promise.then(res => {
passEventToBrowsers(util.stringifyData({ passEventToBrowsers({
...part, ...part,
res res
})); });
}).catch(err => { }).catch(err => {
passEventToBrowsers(util.stringifyData({ passEventToBrowsers({
...part, ...part,
err err
})); });
}); });
} }
break; break;
@ -122,7 +125,8 @@ if(environment === "cef"){
* @param {string} name - The name of the procedure. * @param {string} name - The name of the procedure.
* @param {function} cb - The procedure's callback. The return value will be sent back to the caller. * @param {function} cb - The procedure's callback. The return value will be sent back to the caller.
*/ */
rpc.register = (name, cb) => { rpc.register = function(name, cb){
if(arguments.length !== 2) throw 'register expects 2 arguments: "name" and "cb"';
listeners[name] = cb; listeners[name] = cb;
}; };
@ -130,17 +134,24 @@ rpc.register = (name, cb) => {
* Unregister a procedure. * Unregister a procedure.
* @param {string} name - The name of the procedure. * @param {string} name - The name of the procedure.
*/ */
rpc.unregister = (name) => { rpc.unregister = function(name){
if(arguments.length !== 1) throw 'unregister expects 1 argument: "name"';
listeners[name] = undefined; listeners[name] = undefined;
}; };
/** /**
* Calls a local procedure. * Calls a local procedure. Only procedures registered in the same context will be resolved.
*
* Can be called from any environment.
*
* @param {string} name - The name of the locally registered procedure. * @param {string} name - The name of the locally registered procedure.
* @param args - Any parameters for the procedure. * @param args - Any parameters for the procedure.
* @returns {Promise} - The result from the procedure. * @returns {Promise} - The result from the procedure.
*/ */
rpc.call = (name, args) => callProcedure(name, args, { environment }); rpc.call = function(name, args){
if(arguments.length !== 1 && arguments.length !== 2) return Promise.reject('call expects 1 or 2 arguments: "name" and optional "args"');
return callProcedure(name, args, { environment });
};
function callServer(name, args, extraData){ function callServer(name, args, extraData){
switch(environment){ switch(environment){
@ -172,17 +183,24 @@ function callServer(name, args, extraData){
/** /**
* Calls a remote procedure registered on the server. * Calls a remote procedure registered on the server.
*
* Can be called from any environment.
*
* @param {string} name - The name of the registered procedure. * @param {string} name - The name of the registered procedure.
* @param args - Any parameters for the procedure. * @param args - Any parameters for the procedure.
* @returns {Promise} - The result from the procedure. * @returns {Promise} - The result from the procedure.
*/ */
rpc.callServer = (name, args) => { rpc.callServer = function(name, args){
if(arguments.length !== 1 && arguments.length !== 2) return Promise.reject('callServer expects 1 or 2 arguments: "name" and optional "args"');
return callServer(name, args, {}); return callServer(name, args, {});
}; };
/** /**
* Calls a remote procedure registered on the client. * Calls a remote procedure registered on the client.
* @param [player] - The player to call the procedure on. *
* Can be called from any environment.
*
* @param player - The player to call the procedure on.
* @param {string} name - The name of the registered procedure. * @param {string} name - The name of the registered procedure.
* @param args - Any parameters for the procedure. * @param args - Any parameters for the procedure.
* @returns {Promise} - The result from the procedure. * @returns {Promise} - The result from the procedure.
@ -192,18 +210,16 @@ rpc.callServer = (name, args) => {
// //
// clientside or cef // clientside or cef
// callClient(name, args) // callClient(name, args)
rpc.callClient = (player, name, args) => { rpc.callClient = function(player, name, args){
if(typeof player === "string"){
if(environment === "server") return Promise.reject('This syntax can only be used in browser and client environments.');
args = name;
name = player;
}
switch(environment){ switch(environment){
case "client": { case "client": {
if(player === mp.players.local) return rpc.call(name, args); args = name;
else return Promise.reject('Only the server can RPC to other clients.'); name = player;
if((arguments.length !== 1 && arguments.length !== 2) || typeof name !== "string") return Promise.reject('callClient from the client expects 1 or 2 arguments: "name" and optional "args"');
return rpc.call(name, args);
} }
case "server": { case "server": {
if((arguments.length !== 2 && arguments.length !== 3) || typeof player !== "object") return Promise.reject('callClient from the server expects 2 or 3 arguments: "player", "name", and optional "args"');
const id = util.uid(); const id = util.uid();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
pending[id] = { pending[id] = {
@ -220,14 +236,10 @@ rpc.callClient = (player, name, args) => {
}); });
} }
case "cef": { case "cef": {
args = name;
name = player;
if((arguments.length !== 1 && arguments.length !== 2) || typeof name !== "string") return Promise.reject('callClient from the browser expects 1 or 2 arguments: "name" and optional "args"');
const id = util.uid(); const id = util.uid();
console.log('CEF IS CALLING THE CLIENT WITH THIS DATA: ', {
req: 1,
id,
name,
env: environment,
args
});
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
pending[id] = { pending[id] = {
resolve, resolve,
@ -251,14 +263,14 @@ function callBrowser(id, browser, name, args, extraData){
resolve, resolve,
reject reject
}; };
passEventToBrowser(browser, util.stringifyData({ passEventToBrowser(browser, {
req: 1, req: 1,
id, id,
name, name,
env: environment, env: environment,
args, args,
...extraData ...extraData
})); });
}); });
} }
async function callBrowsers(player, name, args, extraData){ async function callBrowsers(player, name, args, extraData){
@ -288,7 +300,7 @@ async function callBrowsers(player, name, args, extraData){
if(browser) break; if(browser) break;
} }
if(browser) return callBrowser(id, browser, name, args, extraData); if(browser) return callBrowser(id, browser, name, args, extraData);
throw 'PROCEDURE_NOT_FOUND'; throw ERR_NOT_FOUND;
} }
case "server": { case "server": {
return rpc.callClient(player, '__rpc:callBrowsers', [name, args]); return rpc.callClient(player, '__rpc:callBrowsers', [name, args]);
@ -311,16 +323,16 @@ async function callBrowsers(player, name, args, extraData){
* @param args - Any parameters for the procedure. * @param args - Any parameters for the procedure.
* @returns {Promise} - The result from the procedure. * @returns {Promise} - The result from the procedure.
*/ */
rpc.callBrowsers = async function(player, name, args){ rpc.callBrowsers = function(player, name, args){
switch(environment){ switch(environment){
case "client": case "client":
if(arguments.length !== 1 && arguments.length !== 2) throw 'callBrowsers from the client expects 1 or 2 arguments: "name" and optional "args"'; if(arguments.length !== 1 && arguments.length !== 2) return Promise.reject('callBrowsers from the client expects 1 or 2 arguments: "name" and optional "args"');
break; break;
case "server": case "server":
if(arguments.length !== 2 && arguments.length !== 3) throw 'callBrowsers from the server expects 2 or 3 arguments: "player", "name", and optional "args"'; if(arguments.length !== 2 && arguments.length !== 3) return Promise.reject('callBrowsers from the server expects 2 or 3 arguments: "player", "name", and optional "args"');
break; break;
case "cef": case "cef":
if(arguments.length !== 1 && arguments.length !== 2) throw 'callBrowsers from the browser expects 1 or 2 arguments: "name" and optional "args"'; if(arguments.length !== 1 && arguments.length !== 2) return Promise.reject('callBrowsers from the browser expects 1 or 2 arguments: "name" and optional "args"');
break; break;
} }
return callBrowsers(player, name, args, {}); return callBrowsers(player, name, args, {});
@ -337,8 +349,8 @@ rpc.callBrowsers = async function(player, name, args){
* @returns {Promise} - The result from the procedure. * @returns {Promise} - The result from the procedure.
*/ */
rpc.callBrowser = function(browser, name, args){ rpc.callBrowser = function(browser, name, args){
if(environment !== "client") throw 'callBrowser can only be used in the client environment'; if(environment !== "client") return Promise.reject('callBrowser can only be used in the client environment');
if(arguments.length !== 2 || arguments.length !== 3) throw 'callBrowser expects 2 or 3 arguments: "browser", "name", and optional "args"'; if(arguments.length !== 2 && arguments.length !== 3) return Promise.reject('callBrowser expects 2 or 3 arguments: "browser", "name", and optional "args"');
const id = util.uid(); const id = util.uid();
return callBrowser(id, browser, name, args, {}); return callBrowser(id, browser, name, args, {});
}; };