method definitions + more about errors + core points mentioned

rilaxik 2024-10-28 08:30:16 +00:00
parent 3d45758eef
commit e58653d821

@ -45,7 +45,61 @@ Inspired by usage of [rage-rpc](https://github.com/micaww/rage-rpc)
# Points
Before reading docs you should at least barely be acknowledged about the patterns used and how ``rage-fw-rpc`` is different in usage than community favorite ``rage-rpc``
**todo**
- Arguments when calling any event must be wrapped in an array. This is done for proper argument typing. Be aware that as of now arguments in ``register`` are SPREAD and not wrapped in array. It is recommended to at least loosely type events, that require passing arrays as arguments to avoid unwanted outcomes.
```ts
// client-side
rpc.callServer('event', [2, 3])
```
```ts
// server-side expects number[], but gets two separate numbers as arguments instead
rpc.register('event', (player, argument1: number[] /* (actual: number), argument2 (actual: number) */) => {})
```
```ts
// this will save the day
rpc.callServer<[number[]]>('event', [2, 3]) // type-error
rpc.callServer<[number[]]>('event', [[2, 3]]) // ✓
```
- Keep in mind that chaining events this way -
```ts
// eg. client called server
rpc.register('customServerEvent', async (args: string) => {
const response: string = await rpc.callBrowser('customCefEvent', [
'hello from server',
])
// do something with response
return 'response from server'
})
```
has two major issues:
1. Events are marked as timed out after 10s and are throwing if no response was received. This can occur when player has high ping or browser delays the response in any way. Means your event chain may not continue in those cases. Your codebase is entirely up to you, but avoid such issues try not to chain events inside one another
2. await stops function execution. This means any operations in place of ``do something with res`` that do not rely on response are unnecessarily stopped. This can be avoided using ``.then(response => ...)`` giving function an opportunity to execute side-operations in parallel with promises
[Ref: await docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#description)
[Ref: in detail](https://dev.to/masteringjs/using-then-vs-async-await-in-javascript-2pma)
- Every environment can call any environment and get a response via Promise
```ts
server <-> client <-> browser as well as server <-> browser
```
You can still use ``call<env>`` methods to refer to environment itself
```ts
// server
rpc.callServer(...)
// client
rpc.callClient(...)
// browser
rpc.callBrowser(...)
```
It will behave the same way as using ``call`` by just being redirected to it. For better code clearance we do recommend using ``call`` instead of ``call<env>`` to also same a tiny bit of computation resources
- (Extra) Due to async-based logic some IDEs or tools like ESlint can soft-warn you for ignoring promises on events you do not want response from. In that cases you can either
```ts
// await it, but you will have to mark parent function as async
await rpc.callServer('event')
// or use .then() to just remove the noisy underline in rare cases you do not want/unable to mark it as async (eg. React.useEffect)
rpc.callServer('event').then()
```
# Docs
@ -72,8 +126,17 @@ export const rpc = new Rpc({
## register
Registers a callback function for a specified event
**todo** describe generics
```ts
register<
CallbackArguments extends unknown[] = unknown[],
CallbackReturn extends unknown = unknown,
EventName extends string = string,
>(
eventName: EventName,
cb: (...args: CallbackArguments) => CallbackReturn,
): void
```
Example
```ts
rpc.register('playerJoin', (player) => {
console.log(`Connected: ${player.socialClub}`)
@ -81,21 +144,33 @@ rpc.register('playerJoin', (player) => {
```
## unregister
Unregisters callback function for a specified event
Cancels callback function for a specified event
```ts
unregister<EventName extends string = string>(
eventName: EventName,
): void
```
Example
```ts
rpc.unregister('playerDamage')
```
## callClient
Calls a client-side event from server or browser (or client, but better use [call](#call))
From browser:
```ts
async callClient<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
Return extends unknown = unknown,
>(eventName: EventName, args?: Arguments): Promise<Return>
```
Example from browser:
```ts
rpc.callClient('updatePlayerData', ['argument']).then(response => {
console.log(`Received: ${response}`)
})
```
From server (requires player):
Example from server (requires player):
```ts
rpc.callClient(player, 'updatePlayerData', ['argument']).then(response => {
console.log(`Received: ${response}`)
@ -105,6 +180,14 @@ rpc.callClient(player, 'updatePlayerData', ['argument']).then(response => {
## callServer
Calls a server-side event from browser or client (or server, but better use [call](#call))
```ts
async callServer<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
Return extends unknown = unknown,
>(eventName: EventName, args?: Arguments): Promise<Return>
```
Example
```ts
rpc.callServer('updatePlayerData', ['argument']).then(response => {
console.log(`Received: ${response}`)
})
@ -112,14 +195,20 @@ rpc.callServer('updatePlayerData', ['argument']).then(response => {
## callBrowser
Calls a browser-side event from server or client (or browser, but better use [call](#call))
From client:
```ts
async callBrowser<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
Return extends unknown = unknown,
>(eventName: EventName, args?: Arguments): Promise<Return>
```
Example from client:
```ts
rpc.callBrowser('updatePlayerData', ['argument']).then(response => {
console.log(`Received: ${response}`)
})
```
From server (requires player):
Example from server (requires player):
```ts
rpc.callBrowser(player, 'updatePlayerData', ['argument']).then(response => {
console.log(`Received: ${response}`)
@ -129,15 +218,36 @@ rpc.callBrowser(player, 'updatePlayerData', ['argument']).then(response => {
## call
Calls an event in current environment
```ts
async call<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
Return extends unknown = unknown,
>(eventName: EventName, args?: Arguments): Promise<Return>
```
Example
```ts
rpc.call('triggerSomething').then(response => {
console.log(`Received: ${response}`)
})
```
# Errors
- When error is thrown you will get a message of such form
```ts
`${rpcData.knownError}\n` + // error message
`Caller: ${rpcData.calledFrom}\n` + // server/client/browser
`Receiver: ${this.environment_}\n` + // server/client/browser
`Event: ${rpcData.eventName}\n` +
`Additional Info: ${error}` // actual error object, could be more than one
```
Hopefully this will give you enough information about the event which throws. Error information is definitely subject to change in future
- Keep in mind that event timeouts are throwing with almost no information due to their current implementation (at least your console can show line number)
- Under the hood we use ``JSON.stringify`` to pass data between environments, but in JS there are a few which [cannot be serialized](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description)
## Codes
These should be clear enough themselves, in other cases refer to here
- ``EVENT_NOT_REGISTERED`` - throws in Promise (rejects) in called environment when event is either already unregistered or not registered yet. If you see this its almost always calling an event before registering
- ``UNKNOWN_ENVIRONMENT`` - throws in any environment that is not recognized as server/client/browser in Rage. Unlike ``rage-rpc`` this is not thrown in browser when launched without mp context IF you specify it in browser rpc options (see Options)
- ``UNKNOWN_ENVIRONMENT`` - throws in any environment that is not recognized as server/client/browser in Rage. Unlike ``rage-rpc`` this is not thrown in browser when launched without mp context IF you specify it in browser [Rpc Config](#rpc-config)
- ``NO_BROWSER`` - throws on client if you failed to specify valid browser for it to refer to when calling browser
- ``EVENT_RESPONSE_TIMEOUT`` - throws in Promise (rejects) when failed to receive a response data from called environment. You may not always want to receive it at all, for now it just works like this. Prefer adding ``catch`` on your events