- added all non-jumping calls (cef <=> client, client <=> server)
- added @ragempcommunity types (todo)
This commit is contained in:
Danya H 2024-10-03 18:59:41 +01:00
parent 092693acb5
commit f8dd4d9fce
14 changed files with 163 additions and 104 deletions

1
.gitignore vendored
View File

@ -18,3 +18,4 @@ server/ragemp-server.exe
# Development # Development
node_modules node_modules
pnpm-lock.yaml pnpm-lock.yaml
dist

View File

@ -1,20 +1,18 @@
import { fw } from 'rage-fw-cef'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { rpc } from 'rpc'
function App() { function App() {
const [data, setData] = useState('') const [data, setData] = useState<unknown>('')
useEffect(() => { useEffect(() => {
fw.event.register('customCefEvent', async ([test]) => { rpc.callClient('cefReady', [])
setData(p => p + ' ' + test) rpc.register('customCefEvent', args => setData(args))
return 'from cef'
})
}, []) }, [])
return ( return (
<div style={{ width: '100%', color: 'white', textAlign: 'center' }}> <div style={{ width: '100%', color: 'white', textAlign: 'center' }}>
<h1>Hello World!</h1> <h1>Hello World!</h1>
<h2>{data}</h2> <h2>{data!.toString()}</h2>
</div> </div>
) )
} }

View File

@ -1,14 +1,15 @@
import { fw } from 'rage-fw-client' import { rpc, client } from 'rpc'
fw.player.browser = mp.browsers.new('package://cef/index.html') client.browser = mp.browsers.new('package://cef/index.html')
fw.event.register('cefReady', async () => { rpc.register('cefReady', async () => {
fw.system.log.info('cefReady') mp.console.logInfo('cef to client')
const responseCef = await fw.player.triggerBrowser('customCefEvent', [ rpc.callServer('customServerEvent', ['client to server'])
'from client', })
])
fw.system.log.info(responseCef) rpc.register('customClientEvent', async data => {
mp.console.logInfo(JSON.stringify(data))
await fw.player.triggerServer('customServerEvent', ['from client'])
rpc.callBrowser('customCefEvent', ['client to cef'])
}) })

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

@ -1,9 +1,8 @@
declare const mp: any import '@ragempcommunity/types-cef'
import '@ragempcommunity/types-client'
import '@ragempcommunity/types-server'
declare const global: { declare const mp: Mp
rpcEvents: Record<string, (...args: any[]) => unknown> declare const global: Record<string, (...args: any[]) => unknown>
} declare const window: Record<string, (...args: any[]) => unknown>
declare const console: { log: (...args: any[]) => void }
declare const window: {
rpcEvents: Record<string, (...args: any[]) => unknown>
}

View File

@ -1,7 +1,7 @@
{ {
"name": "rpc", "name": "rpc",
"version": "0.1.0", "version": "0.1.0",
"main": "dist/index.js", "main": "src/index.ts",
"types": "dist/src/index.d.ts", "types": "dist/src/index.d.ts",
"scripts": { "scripts": {
"build": "tsup", "build": "tsup",
@ -11,7 +11,12 @@
"dist/**/*" "dist/**/*"
], ],
"devDependencies": { "devDependencies": {
"prettier": "^3.3.2" "@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"
}, },
"peerDependencies": { "peerDependencies": {
"typescript": "^5.0.0" "typescript": "^5.0.0"
@ -19,10 +24,12 @@
"description": "RageFW RPC", "description": "RageFW RPC",
"keywords": [], "keywords": [],
"author": "SashaGoncharov19", "author": "SashaGoncharov19",
"contributors": [{ "contributors": [
{
"name": "rilaxik", "name": "rilaxik",
"email": "dev.rilaxik@gmail.com", "email": "dev.rilaxik@gmail.com",
"url": "https://github.com/rilaxik" "url": "https://github.com/rilaxik"
}], }
],
"license": "MIT" "license": "MIT"
} }

View File

@ -23,7 +23,7 @@ class Browser extends Wrapper {
} }
private emitClient(dataRaw: string) { private emitClient(dataRaw: string) {
mp.trigger(Events.EVENT_LISTENER, dataRaw) mp.trigger(Events.LOCAL_EVENT_LISTENER, dataRaw)
} }
private emit(dataRaw: string) { private emit(dataRaw: string) {

View File

@ -44,11 +44,13 @@ class Client extends Wrapper {
return return
} }
this.state_[state.eventName](...state.data) this.state_[state.eventName](
...(Array.isArray(state.data) ? state.data : []),
)
} }
private emitServer(dataRaw: string) { private emitServer(dataRaw: string) {
mp.events.callRemote(Events.EVENT_LISTENER, dataRaw) mp.events.callRemote(Events.SERVER_EVENT_LISTENER, dataRaw)
} }
private emitBrowser(dataRaw: string, state: RPCState) { private emitBrowser(dataRaw: string, state: RPCState) {
@ -57,7 +59,7 @@ class Client extends Wrapper {
return return
} }
this._browser.call(Events.EVENT_LISTENER, dataRaw) this._browser.call(Events.LOCAL_EVENT_LISTENER, dataRaw)
} }
} }

View File

@ -1,9 +1,15 @@
import { Wrapper } from './wrapper' import { Wrapper } from './wrapper'
import type { Player, PlayerServer } from './utils'
import { Environment, Errors, Events, RPCState, Utils } from './utils' import { Environment, Errors, Events, RPCState, Utils } from './utils'
import { server } from './server' import { server } from './server'
import { client } from './client' import { client } from './client'
import { browser } from './browser' import { browser } from './browser'
export { server } from './server'
export { client } from './client'
export { browser } from './browser'
class Rpc extends Wrapper { class Rpc extends Wrapper {
constructor() { constructor() {
super() super()
@ -12,22 +18,20 @@ class Rpc extends Wrapper {
throw new Error(Errors.UNKNOWN_ENVIRONMENT) throw new Error(Errors.UNKNOWN_ENVIRONMENT)
mp.events.add( mp.events.add(
Events.EVENT_LISTENER, Events.LOCAL_EVENT_LISTENER,
async (player: any, dataRaw: string) => { async (player: Player, dataRaw: string) => {
if (!dataRaw) throw new Error(Errors.NO_DATA)
switch (this.environment_) { switch (this.environment_) {
case Environment.SERVER: case Environment.SERVER:
server.resolveEmitDestination(player, dataRaw) server.resolveEmitDestination(player, dataRaw)
break break
case Environment.CLIENT: case Environment.CLIENT:
dataRaw = player dataRaw = player as string
client.resolveEmitDestination(dataRaw) client.resolveEmitDestination(dataRaw)
break break
case Environment.BROWSER: case Environment.BROWSER:
dataRaw = player dataRaw = player as string
browser.resolveEmitDestination(dataRaw) browser.resolveEmitDestination(dataRaw)
break break
@ -48,29 +52,61 @@ class Rpc extends Wrapper {
this.state_[eventName] = cb this.state_[eventName] = cb
} }
public unregister( public unregister(eventName: string): void {
eventName: string
): void {
Utils.errorUnknownEnvironment(this.environment_) Utils.errorUnknownEnvironment(this.environment_)
delete this.state_[eventName] delete this.state_[eventName]
} }
public callClient(eventName: string, args: unknown[]) { public callClient(
playerOrEventName: Player,
eventNameOrArgs: string | unknown[],
args?: unknown[],
) {
Utils.errorUnknownEnvironment(this.environment_) Utils.errorUnknownEnvironment(this.environment_)
// client
if (this.environment_ === Environment.CLIENT) {
this.call(playerOrEventName as string, args as unknown[])
return
}
// server
if (this.environment_ === Environment.SERVER) {
const state: RPCState = { const state: RPCState = {
uuid: Utils.generateUUID(), uuid: Utils.generateUUID(),
eventName, eventName: eventNameOrArgs as string,
calledTo: Environment.CLIENT, calledTo: Environment.CLIENT,
calledFrom: this.environment_, calledFrom: this.environment_,
knownError: undefined, knownError: undefined,
data: args, data: args as unknown[],
} }
const dataRaw = Utils.prepareTransfer(state) const dataRaw = Utils.prepareTransfer(state)
mp.events.call(Events.EVENT_LISTENER, dataRaw) ;(playerOrEventName as PlayerServer).call(
Events.LOCAL_EVENT_LISTENER,
[dataRaw],
)
return
}
// browser
if (this.environment_ === Environment.BROWSER) {
const state: RPCState = {
uuid: Utils.generateUUID(),
eventName: playerOrEventName as string,
calledTo: Environment.CLIENT,
calledFrom: this.environment_,
knownError: undefined,
data: eventNameOrArgs as unknown[],
}
const dataRaw = Utils.prepareTransfer(state)
mp.trigger(Events.LOCAL_EVENT_LISTENER, dataRaw)
return
}
} }
public callServer(eventName: string, args: unknown[]) { public callServer(eventName: string, args: unknown[]) {
@ -85,9 +121,13 @@ class Rpc extends Wrapper {
data: args, data: args,
} }
if (state.calledFrom === Environment.SERVER) {
this.callSelf(state)
} else {
const dataRaw = Utils.prepareTransfer(state) const dataRaw = Utils.prepareTransfer(state)
mp.events.call(Events.EVENT_LISTENER, dataRaw) mp.events.call(Events.LOCAL_EVENT_LISTENER, dataRaw)
}
} }
public callBrowser(eventName: string, args: unknown[]) { public callBrowser(eventName: string, args: unknown[]) {
@ -102,9 +142,13 @@ class Rpc extends Wrapper {
data: args, data: args,
} }
if (state.calledFrom === Environment.BROWSER) {
this.callSelf(state)
} else {
const dataRaw = Utils.prepareTransfer(state) const dataRaw = Utils.prepareTransfer(state)
mp.events.call(Events.EVENT_LISTENER, dataRaw) mp.events.call(Events.LOCAL_EVENT_LISTENER, dataRaw)
}
} }
public call(eventName: string, args: unknown[]) { public call(eventName: string, args: unknown[]) {
@ -119,11 +163,17 @@ class Rpc extends Wrapper {
data: args, data: args,
} }
this.callSelf(state)
}
private callSelf(state: RPCState) {
state = this.verifyEvent_(state) state = this.verifyEvent_(state)
if (state.knownError) { if (state.knownError) {
this.triggerError_(state, state.knownError) this.triggerError_(state, state.knownError)
return return
} }
this.state_[state.eventName](...state.data)
} }
} }

View File

@ -1,14 +1,20 @@
import { Wrapper } from './wrapper' import { Wrapper } from './wrapper'
import { Environment, Errors, Events, Utils } from './utils' import type { Player, PlayerServer } from './utils'
import { Environment, Events, Utils } from './utils'
class Server extends Wrapper { class Server extends Wrapper {
constructor() { constructor() {
super() super()
mp.events.add(
Events.SERVER_EVENT_LISTENER,
async (player: PlayerServer, dataRaw: string) => {
this.emit(player, dataRaw)
},
)
} }
public resolveEmitDestination(player: any, dataRaw: string) { public resolveEmitDestination(player: Player, dataRaw: string) {
if (!dataRaw) throw new Error(Errors.NO_DATA)
let state = Utils.prepareExecution(dataRaw) let state = Utils.prepareExecution(dataRaw)
switch (state.calledTo) { switch (state.calledTo) {
@ -17,16 +23,16 @@ class Server extends Wrapper {
break break
default: default:
this.emitClient(player, dataRaw) this.emitClient(player as PlayerServer, dataRaw)
break break
} }
} }
private emitClient(player: any, dataRaw: string) { private emitClient(player: PlayerServer, dataRaw: string) {
player.call(Events.EVENT_LISTENER, dataRaw) player.call(Events.LOCAL_EVENT_LISTENER, [dataRaw])
} }
private emit(player: any, dataRaw: string) { private emit(player: Player, dataRaw: string) {
let state = Utils.prepareExecution(dataRaw) let state = Utils.prepareExecution(dataRaw)
state = this.verifyEvent_(state) state = this.verifyEvent_(state)
@ -36,7 +42,7 @@ class Server extends Wrapper {
} }
const { eventName, data } = Utils.prepareExecution(dataRaw) const { eventName, data } = Utils.prepareExecution(dataRaw)
this.state_[eventName](...data) this.state_[eventName](player, ...data)
} }
} }

View File

@ -6,7 +6,9 @@ export enum Environment {
} }
export enum Events { export enum Events {
EVENT_LISTENER = '__rpc:listener', LOCAL_EVENT_LISTENER = '__rpc:listener',
CLIENT_EVENT_LISTENER = '__rpc:clientListener',
SERVER_EVENT_LISTENER = '__rpc:serverListener',
EVENT_RESPONSE = '__rpc:response', EVENT_RESPONSE = '__rpc:response',
} }
@ -17,15 +19,6 @@ export enum Errors {
NO_BROWSER = 'You need to initialize browser first', NO_BROWSER = 'You need to initialize browser first',
} }
export type RPCState = {
eventName: string
uuid: string
knownError?: string
data?: any
calledFrom: Environment
calledTo: Environment
}
export class Utils { export class Utils {
public static getEnvironment(): Environment { public static getEnvironment(): Environment {
if ('joaat' in mp) return Environment.SERVER if ('joaat' in mp) return Environment.SERVER
@ -71,3 +64,17 @@ export class Utils {
throw new Error(Errors.UNKNOWN_ENVIRONMENT) throw new Error(Errors.UNKNOWN_ENVIRONMENT)
} }
} }
export type RPCState = {
eventName: string
uuid: string
knownError?: string
data?: any
calledFrom: Environment
calledTo: Environment
}
export interface Player {}
export interface PlayerServer extends Player {
call(eventName: string, args: unknown[]): void
}

View File

@ -3,15 +3,7 @@ import { Environment, Errors, RPCState, Utils } from './utils'
export class Wrapper { export class Wrapper {
protected environment_ = Utils.getEnvironment() protected environment_ = Utils.getEnvironment()
protected state_ = protected state_ =
this.environment_ === Environment.BROWSER this.environment_ === Environment.BROWSER ? window : global
? (window.rpcEvents = {} as Record<
string,
(...args: any[]) => unknown
>)
: (global.rpcEvents = {} as Record<
string,
(...args: any[]) => unknown
>)
protected verifyEvent_(data: string | RPCState): RPCState { protected verifyEvent_(data: string | RPCState): RPCState {
let rpcData = let rpcData =

View File

@ -1,18 +1,11 @@
import { fw } from 'rage-fw-server' import { rpc } from 'rpc'
fw.event.register('playerJoin', async ([player]) => { rpc.register('playerJoin', async player => {
fw.system.log.info(`Connected: ${player.socialClub}`) console.log(`Connected: ${player.socialClub}`)
}) })
fw.event.register('customServerEvent', async ([player, msg]) => { rpc.register('customServerEvent', (player, data) => {
fw.system.log.info(player.socialClub + ' ' + msg) console.log(player, data)
const resFromCef = await fw.player.triggerBrowser( rpc.callClient(player, 'customClientEvent', ['server to client'])
player,
'customCefEvent',
['from server'],
)
fw.system.log.info(player.socialClub + ' ' + resFromCef)
return 'from server'
}) })

View File

@ -1,6 +1,7 @@
{ {
"extends": "../../tsconfig.json", "extends": "../../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"lib": ["DOM", "ESNext"],
"resolveJsonModule": true, "resolveJsonModule": true,
"baseUrl": "./src", "baseUrl": "./src",
"types": [ "types": [

View File

@ -1,11 +1,13 @@
declare module 'rage-fw-shared-types' { declare module 'rage-fw-shared-types' {
export interface RageFW_ICustomClientEvent {} export interface RageFW_ICustomClientEvent {
customClientEvent(greetings: string): void
}
export interface RageFW_ICustomServerEvent { export interface RageFW_ICustomServerEvent {
customServerEvent(greetings: string): string customServerEvent(greetings: string): void
} }
export interface RageFW_ICustomCefEvent { export interface RageFW_ICustomCefEvent {
customCefEvent(greetings: string): string customCefEvent(greetings: string): void
} }
} }