- rpc generics
- some internal types to expose from rpc
This commit is contained in:
Danya H 2024-10-03 23:11:39 +01:00
parent f8dd4d9fce
commit 67be91538b
8 changed files with 110 additions and 50 deletions

View File

@ -5,7 +5,7 @@ function App() {
const [data, setData] = useState<unknown>('')
useEffect(() => {
rpc.callClient('cefReady', [])
rpc.callClient('cefReady')
rpc.register('customCefEvent', args => setData(args))
}, [])

28
apps/rpc/index.d.ts vendored
View File

@ -1,8 +1,22 @@
import '@ragempcommunity/types-cef'
import '@ragempcommunity/types-client'
import '@ragempcommunity/types-server'
export {}
declare const mp: Mp
declare const global: Record<string, (...args: any[]) => unknown>
declare const window: Record<string, (...args: any[]) => unknown>
declare const console: { log: (...args: any[]) => void }
interface Mp {
trigger(event: string, data?: any): void
events: {
add(event: string, data: any): void
call(event: string, data: any): void
callRemote(event: string, data: any): void
}
joaat?: unknown
game: {
joaat?: unknown
}
}
declare global {
const mp: Mp
const global: Record<string, (...args: any[]) => unknown>
interface Window {
[p: string]: any
}
}

View File

@ -12,9 +12,6 @@
],
"devDependencies": {
"@microsoft/api-extractor": "^7.47.9",
"@ragempcommunity/types-client": "^2.1.8",
"@ragempcommunity/types-server": "^2.1.8",
"@ragempcommunity/types-cef": "^2.1.8",
"prettier": "^3.3.2",
"tsup": "^8.3.0"
},

View File

@ -1,6 +1,12 @@
import { Wrapper } from './wrapper'
import type { Player, PlayerServer } from './utils'
import { Environment, Errors, Events, RPCState, Utils } from './utils'
import {
Environment,
Errors,
Events,
RPCState,
Utils,
type PlayerMp,
} from './utils'
import { server } from './server'
import { client } from './client'
@ -19,10 +25,13 @@ class Rpc extends Wrapper {
mp.events.add(
Events.LOCAL_EVENT_LISTENER,
async (player: Player, dataRaw: string) => {
async (player: PlayerMp | string, dataRaw: string) => {
switch (this.environment_) {
case Environment.SERVER:
server.resolveEmitDestination(player, dataRaw)
server.resolveEmitDestination(
player as PlayerMp,
dataRaw,
)
break
case Environment.CLIENT:
@ -43,28 +52,49 @@ class Rpc extends Wrapper {
)
}
public register(
eventName: string,
cb: (...args: unknown[]) => unknown,
public register<
CallbackArguments extends unknown[] = unknown[],
CallbackReturn extends unknown = unknown,
EventName extends string = string,
>(
eventName: EventName,
cb: (...args: CallbackArguments) => CallbackReturn,
): void {
Utils.errorUnknownEnvironment(this.environment_)
this.state_[eventName] = cb
}
public unregister(eventName: string): void {
public unregister<EventName extends string = string>(
eventName: EventName,
): void {
Utils.errorUnknownEnvironment(this.environment_)
delete this.state_[eventName]
}
public callClient<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
>(eventName: EventName, args?: Arguments): void
public callClient<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
>(player: PlayerMp, eventName: EventName, args?: Arguments): void
public callClient(
playerOrEventName: Player,
eventNameOrArgs: string | unknown[],
playerOrEventName: PlayerMp | string,
eventNameOrArgs?: string | unknown[],
args?: unknown[],
) {
): void {
Utils.errorUnknownEnvironment(this.environment_)
function _is1StParamPlayer(x: unknown): x is PlayerMp {
return typeof x === 'object'
}
function _is2NdParamEventName(x: unknown): x is string {
return !Array.isArray(x) && typeof x === 'string'
}
// client
if (this.environment_ === Environment.CLIENT) {
this.call(playerOrEventName as string, args as unknown[])
@ -72,10 +102,14 @@ class Rpc extends Wrapper {
}
// server
if (this.environment_ === Environment.SERVER) {
if (
this.environment_ === Environment.SERVER &&
_is1StParamPlayer(playerOrEventName) &&
_is2NdParamEventName(eventNameOrArgs)
) {
const state: RPCState = {
uuid: Utils.generateUUID(),
eventName: eventNameOrArgs as string,
eventName: eventNameOrArgs,
calledTo: Environment.CLIENT,
calledFrom: this.environment_,
knownError: undefined,
@ -84,22 +118,23 @@ class Rpc extends Wrapper {
const dataRaw = Utils.prepareTransfer(state)
;(playerOrEventName as PlayerServer).call(
Events.LOCAL_EVENT_LISTENER,
[dataRaw],
)
playerOrEventName.call(Events.LOCAL_EVENT_LISTENER, [dataRaw])
return
}
// browser
if (this.environment_ === Environment.BROWSER) {
if (
this.environment_ === Environment.BROWSER &&
!_is1StParamPlayer(playerOrEventName) &&
!_is2NdParamEventName(eventNameOrArgs)
) {
const state: RPCState = {
uuid: Utils.generateUUID(),
eventName: playerOrEventName as string,
eventName: playerOrEventName,
calledTo: Environment.CLIENT,
calledFrom: this.environment_,
knownError: undefined,
data: eventNameOrArgs as unknown[],
data: eventNameOrArgs,
}
const dataRaw = Utils.prepareTransfer(state)
@ -109,7 +144,10 @@ class Rpc extends Wrapper {
}
}
public callServer(eventName: string, args: unknown[]) {
public callServer<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
>(eventName: EventName, args?: Arguments) {
Utils.errorUnknownEnvironment(this.environment_)
const state: RPCState = {
@ -130,7 +168,10 @@ class Rpc extends Wrapper {
}
}
public callBrowser(eventName: string, args: unknown[]) {
public callBrowser<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
>(eventName: EventName, args?: Arguments) {
Utils.errorUnknownEnvironment(this.environment_)
const state: RPCState = {
@ -151,7 +192,10 @@ class Rpc extends Wrapper {
}
}
public call(eventName: string, args: unknown[]) {
public call<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
>(eventName: EventName, args?: Arguments) {
Utils.errorUnknownEnvironment(this.environment_)
let state: RPCState = {

View File

@ -1,6 +1,5 @@
import { Wrapper } from './wrapper'
import type { Player, PlayerServer } from './utils'
import { Environment, Events, Utils } from './utils'
import { Environment, Events, Utils, type PlayerMp } from './utils'
class Server extends Wrapper {
constructor() {
@ -8,13 +7,13 @@ class Server extends Wrapper {
mp.events.add(
Events.SERVER_EVENT_LISTENER,
async (player: PlayerServer, dataRaw: string) => {
async (player: PlayerMp, dataRaw: string) => {
this.emit(player, dataRaw)
},
)
}
public resolveEmitDestination(player: Player, dataRaw: string) {
public resolveEmitDestination(player: PlayerMp, dataRaw: string) {
let state = Utils.prepareExecution(dataRaw)
switch (state.calledTo) {
@ -23,16 +22,16 @@ class Server extends Wrapper {
break
default:
this.emitClient(player as PlayerServer, dataRaw)
this.emitClient(player as PlayerMp, dataRaw)
break
}
}
private emitClient(player: PlayerServer, dataRaw: string) {
private emitClient(player: PlayerMp, dataRaw: string) {
player.call(Events.LOCAL_EVENT_LISTENER, [dataRaw])
}
private emit(player: Player, dataRaw: string) {
private emit(player: PlayerMp, dataRaw: string) {
let state = Utils.prepareExecution(dataRaw)
state = this.verifyEvent_(state)

View File

@ -22,9 +22,12 @@ export enum Errors {
export class Utils {
public static getEnvironment(): Environment {
if ('joaat' in mp) return Environment.SERVER
if ('game' in mp && 'joaat' in (mp.game as { joaat?: unknown }))
if (
'game' in mp &&
'joaat' in (mp as { game: { joaat?: unknown } }).game
)
return Environment.CLIENT
if ('mp' in window) return Environment.BROWSER
if (window && 'mp' in window) return Environment.BROWSER
return Environment.UNKNOWN
}
@ -74,7 +77,6 @@ export type RPCState = {
calledTo: Environment
}
export interface Player {}
export interface PlayerServer extends Player {
call(eventName: string, args: unknown[]): void
export type PlayerMp = {
call(event: string, args?: unknown[]): void
}

View File

@ -3,7 +3,10 @@
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"lib": ["ES6"],
"lib": [
"ES6",
"dom"
],
"declaration": true,
"declarationMap": true,
"sourceMap": true,
@ -20,6 +23,7 @@
"./index.d.ts"
],
"exclude": [
"node_modules"
"node_modules",
"dist"
]
}

View File

@ -1,10 +1,10 @@
import { rpc } from 'rpc'
rpc.register('playerJoin', async player => {
rpc.register('playerJoin', async (player: PlayerMp) => {
console.log(`Connected: ${player.socialClub}`)
})
rpc.register('customServerEvent', (player, data) => {
rpc.register('customServerEvent', (player: PlayerMp, data) => {
console.log(player, data)
rpc.callClient(player, 'customClientEvent', ['server to client'])