Add initial client<-->server RPC
This commit is contained in:
		
							parent
							
								
									1edbf7ffa4
								
							
						
					
					
						commit
						dc0d914b27
					
				
							
								
								
									
										10
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								package.json
									
									
									
									
									
								
							| @ -1,20 +1,20 @@ | |||||||
| { | { | ||||||
|   "name": "rage-eventbus", |   "name": "rage-rpc", | ||||||
|   "version": "0.0.1", |   "version": "0.0.1", | ||||||
|   "description": "An asynchronous event bus for RAGE Multiplayer", |   "description": "An asynchronous RPC implementation for RAGE Multiplayer", | ||||||
|   "main": "index.js", |   "main": "index.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "test": "echo \"Error: no test specified\" && exit 1" |     "test": "echo \"Error: no test specified\" && exit 1" | ||||||
|   }, |   }, | ||||||
|   "repository": { |   "repository": { | ||||||
|     "type": "git", |     "type": "git", | ||||||
|     "url": "git+https://github.com/micaww/rage-eventbus.git" |     "url": "git+https://github.com/micaww/rage-rpc.git" | ||||||
|   }, |   }, | ||||||
|   "author": "micaww", |   "author": "micaww", | ||||||
|   "license": "ISC", |   "license": "ISC", | ||||||
|   "bugs": { |   "bugs": { | ||||||
|     "url": "https://github.com/micaww/rage-eventbus/issues" |     "url": "https://github.com/micaww/rage-rpc/issues" | ||||||
|   }, |   }, | ||||||
|   "homepage": "https://github.com/micaww/rage-eventbus#readme", |   "homepage": "https://github.com/micaww/rage-rpc#readme", | ||||||
|   "dependencies": {} |   "dependencies": {} | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										178
									
								
								src/index.js
									
									
									
									
									
								
							
							
						
						
									
										178
									
								
								src/index.js
									
									
									
									
									
								
							| @ -1,63 +1,163 @@ | |||||||
| const util  = require('./util.js'); | const util  = require('./util.js'); | ||||||
| 
 | 
 | ||||||
| //const isClient = !!mp.game.joaat;
 | const environment = util.getEnvironment(); | ||||||
| //const isCEF = !!mp.trigger;
 | if(!environment) throw 'Unknown RAGE environment'; | ||||||
|  | 
 | ||||||
|  | const PROCESS_EVENT = '__rpc:process'; | ||||||
|  | 
 | ||||||
|  | const rpc = {}; | ||||||
| 
 | 
 | ||||||
| const listeners = {}; | const listeners = {}; | ||||||
|  | const pending = {}; | ||||||
| 
 | 
 | ||||||
| /*mp.events.add('rbus:process', (data) => { | async function callProcedure(name, args, info){ | ||||||
|  |     if(!listeners[name]) throw 'PROCEDURE_NOT_FOUND'; | ||||||
|  |     return listeners[name](args, info); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| });*/ | const processEvent = (...args) => { | ||||||
|  |     let data = args[0]; | ||||||
|  |     if(environment === "server") data = args[1]; | ||||||
|  |     data = util.parseData(data); | ||||||
| 
 | 
 | ||||||
| const rbus = {}; |     if(data.req){ // someone is trying to remotely call a procedure
 | ||||||
|  |         const info = { | ||||||
|  |             id: data.id, | ||||||
|  |             environment: data.env | ||||||
|  |         }; | ||||||
|  |         if(environment === "server") info.player = args[0]; | ||||||
|  |         const promise = callProcedure(data.name, data.args, info); | ||||||
|  |         switch(environment){ | ||||||
|  |             case "server": { | ||||||
|  |                 promise.then(res => { | ||||||
|  |                     info.player.call(PROCESS_EVENT, [util.stringifyData({ | ||||||
|  |                         ret: 1, | ||||||
|  |                         id: data.id, | ||||||
|  |                         res | ||||||
|  |                     })]); | ||||||
|  |                 }).catch(err => { | ||||||
|  |                     info.player.call(PROCESS_EVENT, [util.stringifyData({ | ||||||
|  |                         ret: 1, | ||||||
|  |                         id: data.id, | ||||||
|  |                         err | ||||||
|  |                     })]); | ||||||
|  |                 }); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             case "client": { | ||||||
|  |                 promise.then(res => { | ||||||
|  |                     mp.events.callRemote(PROCESS_EVENT, util.stringifyData({ | ||||||
|  |                         ret: 1, | ||||||
|  |                         id: data.id, | ||||||
|  |                         res | ||||||
|  |                     })); | ||||||
|  |                 }).catch(err => { | ||||||
|  |                     mp.events.callRemote(PROCESS_EVENT, util.stringifyData({ | ||||||
|  |                         ret: 1, | ||||||
|  |                         id: data.id, | ||||||
|  |                         err | ||||||
|  |                     })); | ||||||
|  |                 }); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }else if(data.ret){ // a previously called remote procedure has returned
 | ||||||
|  |         const info = pending[data.id]; | ||||||
|  |         if(info){ | ||||||
|  |             if(data.err) info.reject(data.err); | ||||||
|  |             else info.resolve(data.res); | ||||||
|  |             pending[data.id] = undefined; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | mp.events.add(PROCESS_EVENT, processEvent); | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Register an event listener. |  * Register a procedure. | ||||||
|  * @param {string} eventName - The name of the event. |  * @param {string} name - The name of the procedure. | ||||||
|  * @param {function} cb - The event'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. | ||||||
|  */ |  */ | ||||||
| rbus.on = (eventName, cb) => { | rpc.register = (name, cb) => { | ||||||
|     if(!listeners[eventName]) listeners[eventName] = []; |     listeners[name] = cb; | ||||||
|     listeners[eventName].push(cb); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Unregister an event listener. |  * Unregister a procedure. | ||||||
|  * @param {string} eventName - The name of the event. |  * @param {string} name - The name of the procedure. | ||||||
|  * @param {function} cb - The callback that was registered with `on`. |  | ||||||
|  */ |  */ | ||||||
| rbus.off = (eventName, cb) => { | rpc.unregister = (name) => { | ||||||
|     if(!listeners[eventName]) return; |     listeners[name] = undefined; | ||||||
|     listeners[eventName] = listeners[eventName].filter(listener => listener !== cb); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Calls a local event listener. |  * Calls a local procedure. | ||||||
|  * @param {string} eventName - The name of the event. |  * @param {string} name - The name of the locally registered procedure. | ||||||
|  * @returns {Promise} - The result from the local event listener. |  * @param args - Any parameters for the procedure. | ||||||
|  |  * @returns {Promise} - The result from the procedure. | ||||||
|  */ |  */ | ||||||
| rbus.send = (eventName) => { | rpc.call = (name, args) => callProcedure(name, args, { environment }); | ||||||
|     if(!listeners[eventName] || !listeners[eventName].length) return Promise.reject('NO_LISTENERS'); | 
 | ||||||
|     return Promise.resolve(listeners[eventName][0]()); | /** | ||||||
|  |  * Calls a remote procedure registered on the server. | ||||||
|  |  * @param {string} name - The name of the registered procedure. | ||||||
|  |  * @param args - Any parameters for the procedure. | ||||||
|  |  * @returns {Promise} - The result from the procedure. | ||||||
|  |  */ | ||||||
|  | rpc.callServer = (name, args) => { | ||||||
|  |     switch(environment){ | ||||||
|  |         case "server": { | ||||||
|  |             return rpc.call(name, args); | ||||||
|  |         } | ||||||
|  |         case "client": { | ||||||
|  |             const id = util.uid(); | ||||||
|  |             return new Promise((resolve, reject) => { | ||||||
|  |                 pending[id] = { | ||||||
|  |                     resolve, | ||||||
|  |                     reject | ||||||
|  |                 }; | ||||||
|  |                 mp.events.callRemote(PROCESS_EVENT, util.stringifyData({ | ||||||
|  |                     req: 1, | ||||||
|  |                     id, | ||||||
|  |                     name, | ||||||
|  |                     env: environment, | ||||||
|  |                     args | ||||||
|  |                 })); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Calls a remote event listener residing on the server. |  * Calls a remote procedure registered on the client. | ||||||
|  * @param {string} eventName - The name of the event. |  * @param player - The player to call the procedure on. | ||||||
|  * @returns {Promise} - The result from the remote event listener. |  * @param {string} name - The name of the registered procedure. | ||||||
|  |  * @param args - Any parameters for the procedure. | ||||||
|  |  * @returns {Promise} - The result from the procedure. | ||||||
|  */ |  */ | ||||||
| rbus.sendServer = (eventName) => { | rpc.callClient = (player, name, args) => { | ||||||
| 
 |     switch(environment){ | ||||||
|  |         case "client": { | ||||||
|  |             if(player === mp.players.local) return rpc.call(name, args); | ||||||
|  |             else return Promise.reject('Only the server can RPC to other clients.'); | ||||||
|  |         } | ||||||
|  |         case "server": { | ||||||
|  |             const id = util.uid(); | ||||||
|  |             return new Promise((resolve, reject) => { | ||||||
|  |                 pending[id] = { | ||||||
|  |                     resolve, | ||||||
|  |                     reject | ||||||
|  |                 }; | ||||||
|  |                 player.call(PROCESS_EVENT, [util.stringifyData({ | ||||||
|  |                     req: 1, | ||||||
|  |                     id, | ||||||
|  |                     name, | ||||||
|  |                     env: environment, | ||||||
|  |                     args | ||||||
|  |                 })]); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /** | module.exports = rpc; | ||||||
|  * Calls a remote event listener residing on the client. |  | ||||||
|  * @param player - The player to send to |  | ||||||
|  * @param {string} eventName - The name of the event |  | ||||||
|  * @returns {Promise} - The result from the remote event listener |  | ||||||
|  */ |  | ||||||
| rbus.sendClient = (player, eventName) => { |  | ||||||
| 
 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| module.exports = rbus; |  | ||||||
							
								
								
									
										19
									
								
								src/util.js
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/util.js
									
									
									
									
									
								
							| @ -3,9 +3,24 @@ const util = {}; | |||||||
| util.uid = () => { | util.uid = () => { | ||||||
|     let firstPart = (Math.random() * 46656) | 0; |     let firstPart = (Math.random() * 46656) | 0; | ||||||
|     let secondPart = (Math.random() * 46656) | 0; |     let secondPart = (Math.random() * 46656) | 0; | ||||||
|     firstPart = ("000" + firstPart.toString(36)).slice(-3); |     firstPart = ('000' + firstPart.toString(36)).slice(-3); | ||||||
|     secondPart = ("000" + secondPart.toString(36)).slice(-3); |     secondPart = ('000' + secondPart.toString(36)).slice(-3); | ||||||
|     return firstPart + secondPart; |     return firstPart + secondPart; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | util.getEnvironment = () => { | ||||||
|  |     if(!mp) return undefined; | ||||||
|  |     if(mp.joaat) return 'server'; | ||||||
|  |     else if(mp.game && mp.game.joaat) return 'client'; | ||||||
|  |     else if(mp.trigger) return 'cef'; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | util.stringifyData = (data) => { | ||||||
|  |     return JSON.stringify(data); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | util.parseData = (data) => { | ||||||
|  |     return JSON.parse(data); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| module.exports = util; | module.exports = util; | ||||||
		Reference in New Issue
	
	Block a user