Skip to content

Commit

Permalink
adjust RPC code flow
Browse files Browse the repository at this point in the history
  • Loading branch information
Rolands-Laucis committed Dec 16, 2024
1 parent 5cb16de commit 70c63b2
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 28 deletions.
8 changes: 5 additions & 3 deletions Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -657,14 +657,16 @@ sc.rpc_dict.Hello = (origin_client:client_id, ...args:any[]) => {
}
```

Hooks on both server and client side.
Hooks on both server and client side. They both get executed before anything else, and if they return anything other than ``undefined``, then that will be sent back to the caller.

In the server hook, however, right after the hook check, it also checks if the target_client === ``null``, in which case it will assume the RPC is for the SocioServer instance itself, and try to call a function on it and return that. Otherwise it will pass the call onto the target client and return its result.
```ts
//server code
socserv.lifecycle_hooks.rpc = () => {
socserv.lifecycle_hooks.rpc = (target_client: ClientID | string | null, f_name: string, args: any[]) => {
}

//browser code
sc.lifecycle_hooks.rpc = () => {
sc.lifecycle_hooks.rpc = (client: SocioClient, caller_id: ClientID | string, f_name: string, args: any[]) => {
}
```

Expand Down
43 changes: 25 additions & 18 deletions core/core-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,24 +319,31 @@ export class SocioClient extends LogHandler {
break;
}
case ClientMessageKind.RPC: {
// this.#HandleBasicPromiseMessage(kind, data);
if(this.config.allow_rpc === true){
// let the hook handle it
if(this.lifecycle_hooks.rpc)
if (await this.lifecycle_hooks.rpc(this, (data as S_RPC_data).f_name, (data as S_RPC_data).args))
return;

// run the remote procedure call
let result = undefined;
if ((data as S_RPC_data).f_name in this.rpc_dict) //first on the dict of registered functions
result = this.rpc_dict[(data as S_RPC_data).f_name]((data as S_RPC_data).origin_client, ...(data as S_RPC_data).args);
else if ((data as S_RPC_data).target_client === null && (data as S_RPC_data).f_name in this) //secondly on the client class functions if target is null, bcs thats from the server
result = this[(data as S_RPC_data).f_name](...(data as S_RPC_data).args);
else this.HandleDebug('Received RPC, but the function name doesnt exist on this client. [#rpc-client-no-function]', data);

// return the result back to the server, so it can return it back to the origin client
this.Send(ServerMessageKind.OK, { id: data.id, return: result });
} else this.HandleDebug('Received RPC, but the client hasnt enabled it. [#rpc-client-not-enabled]', data);
if(this.config.allow_rpc !== true){
this.HandleDebug('Received RPC, but the client hasnt enabled it. [#rpc-client-not-enabled]', data);
return;
}

// let the hook handle it
if(this.lifecycle_hooks.rpc){
const res = await this.lifecycle_hooks.rpc(this, (data as S_RPC_data).origin_client, (data as S_RPC_data).f_name, (data as S_RPC_data).args)
if (res !== undefined){
this.Send(ServerMessageKind.OK, { id: data.id, return: res });
return;
}
}

// run the remote procedure call
let result = undefined;
if ((data as S_RPC_data).f_name in this.rpc_dict) //first on the dict of registered functions
result = await this.rpc_dict[(data as S_RPC_data).f_name]((data as S_RPC_data).origin_client, ...(data as S_RPC_data).args);
else if ((data as S_RPC_data).target_client === null && (data as S_RPC_data).f_name in this) //secondly on the client class functions if target is null, bcs thats from the server
result = await this[(data as S_RPC_data).f_name](...(data as S_RPC_data).args);
else
this.HandleDebug('Received RPC, but the function name doesnt exist on this client. [#rpc-client-no-function]', data);

// return the result back to the server, so it can return it back to the origin client
this.Send(ServerMessageKind.OK, { id: data.id, return: result });
break;
}
// case ClientMessageKind.: { break; }
Expand Down
22 changes: 17 additions & 5 deletions core/core-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -618,12 +618,24 @@ export class SocioServer extends LogHandler {
return;
}

// if its null, then assume its meant for the server rpc hook
// let the RPC hook handle it. If it returns anything other than undefined, that will be sent back as the result early
if (this.lifecycle_hooks.rpc) {
const res = await this.lifecycle_hooks.rpc((data as S_RPC_data).target_client, (data as S_RPC_data).f_name, (data as S_RPC_data).args);
if(res !== undefined){
client.Send(ClientMessageKind.RES, { id: data.id, result: { success: 1, res } });
return;
}
}

// hook didnt handle it, so do some magic
// if its null, then assume its meant for the server functions
if ((data as S_RPC_data).target_client === null){
if(this.lifecycle_hooks.rpc){
if (this.lifecycle_hooks.rpc((data as S_RPC_data).target_client, (data as S_RPC_data).f_name, (data as S_RPC_data).args))
return;
}else throw new E('Client RPC to server, but the hook isnt defined on the server! [#missing-server-rpc-hook]', client.id, data);
if ((data as S_RPC_data).f_name in this){
const res = this[(data as S_RPC_data).f_name](...(data as S_RPC_data).args);
client.Send(ClientMessageKind.RES, { id: data.id, result: { success: 1, res } });
return;
}
else throw new E(`Client RPC to server, but there is no [${(data as S_RPC_data).f_name}] function on the SocioServer class instance! [#unknown-server-func-rpc]`, { client_id: client.id, data });
}else{
const target_c = this.#sessions.get((data as S_RPC_data).target_client!);
if (!target_c) {
Expand Down
4 changes: 2 additions & 2 deletions core/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type ServerHookDefinitions = {
gen_prop_name?: () => string | Promise<string>,
identify?: (caller_client: SocioSession, name: string) => void,
discovery?: (caller_client: SocioSession) => { [client_id: string]: { name?: string, ip: string, [key: string]: any } } | any,
rpc?: (target_client: ClientID | string | null, f_name: string, args: any[]) => boolean,
rpc?: (target_client: ClientID | string | null, f_name: string, args: any[]) => Promise<any> | any,
};
// Use a mapped type to define individual importable types. Import this and use like ServerLifecycleHooks['con']
type ServerLifecycleHooks = {
Expand All @@ -63,7 +63,7 @@ type ClientHookDefinitions = {
timeout: (client: SocioClient) => void,
prop_drop: (client: SocioClient, prop_key: PropKey, sub_id: id) => void,
server_error: (client: SocioClient, error_msgs: string[]) => void,
rpc: (client: SocioClient, f_name: string, args: any[]) => Promise<boolean> | boolean,
rpc: (client: SocioClient, caller_id: ClientID | string, f_name: string, args: any[]) => Promise<any> | any,
};
// Use a mapped type to define individual importable types. Import this and use like ClientLifecycleHooks['con']
type ClientLifecycleHooks = {
Expand Down

0 comments on commit 70c63b2

Please sign in to comment.