lifecycle hooks better type defs & hook param fix

This commit is contained in:
Rolands 2023-07-10 10:58:24 +03:00
parent 003fca2bc6
commit 48ffcc0df6
3 changed files with 14 additions and 13 deletions

View file

@ -5,8 +5,7 @@ import * as b64 from 'base64-js';
import * as diff_lib from 'recursive-diff'; //https://www.npmjs.com/package/recursive-diff
//types
import type { id, PropKey, PropValue, CoreMessageKind, ClientMessageKind, Bit } from './types.js';
import type { Cmd_ClientHook, Msg_ClientHook, Discon_ClientHook, Timeout_ClientHook } from './types.js';
import type { id, PropKey, PropValue, CoreMessageKind, ClientMessageKind, Bit, ClientLifecycleHooks, ClientID } from './types.js';
import type { SocioFiles } from './types.js';
import type { RateLimit } from './ratelimit.js';
import { MapReplacer, MapReviver, clamp } from './utils.js';
@ -27,7 +26,7 @@ export type SocioClientOptions = { name?: string, logging?: LogHandlerOptions, k
export class SocioClient extends LogHandler {
// private:
#ws: WebSocket | null = null;
#client_id:id = '';
#client_id:ClientID = '';
#latency:number;
#is_ready: Function | boolean = false;
#authenticated=false;
@ -42,7 +41,7 @@ export class SocioClient extends LogHandler {
verbose:boolean;
key_generator: (() => number | string) | undefined;
persistent: boolean = false;
lifecycle_hooks: { [f_name: string]: Function | null; } = { discon: null as (Discon_ClientHook | null), msg: null as (Msg_ClientHook | null), cmd: null as (Cmd_ClientHook | null), timeout: null as (Timeout_ClientHook | null)};
lifecycle_hooks: ClientLifecycleHooks = { discon: undefined, msg: undefined, cmd: undefined, timeout: undefined }; //assign your function to hook on these. They will be called if they exist
//If the hook returns a truthy value, then it is assumed, that the hook handled the msg and the lib will not. Otherwise, by default, the lib handles the msg.
//discon has to be an async function, such that you may await the new ready(), but socio wont wait for it to finish.
// progs: Map<Promise<any>, number> = new Map(); //the promise is that of a socio generic data going out from client async. Number is WS send buffer payload size at the time of query
@ -102,8 +101,8 @@ export class SocioClient extends LogHandler {
switch (kind) {
case 'CON':
//@ts-ignore
this.#client_id = data;//should just be a string
//@ts-expect-error
this.#client_id = data as string;//should just be a string
this.#latency = (new Date()).getTime() - this.#latency;
if (this.persistent) {

View file

@ -18,8 +18,7 @@ import { RateLimiter } from './ratelimit.js';
//types
import type { ServerOptions, WebSocket, AddressInfo } from 'ws';
import type { IncomingMessage } from 'http';
import type { id, PropKey, PropValue, PropAssigner, CoreMessageKind, ClientMessageKind, SocioFiles, ClientID, FS_Util_Response } from './types.js';
import type { GenCLientID_Hook, Con_Hook, Msg_Hook, Sub_Hook, Upd_Hook, Auth_Hook, Blob_Hook, Serv_Hook, Admin_Hook, Unsub_Hook, Discon_Hook, GrantPerm_Hook, FileUpload_Hook, FileDownload_Hook, Endpoint_Hook } from './types.js';
import type { id, PropKey, PropValue, PropAssigner, CoreMessageKind, ClientMessageKind, SocioFiles, ClientID, FS_Util_Response, ServerLifecycleHooks } from './types.js';
import type { RateLimit } from './ratelimit.js';
import type { LogHandlerOptions } from './logging.js';
export type MessageDataObj = { id?: id, sql?: string, endpoint?: string, params?: object | null | Array<any>, verb?: string, table?: string, unreg_id?: id, prop?: string, prop_val: PropValue, data?: any, rate_limit?: RateLimit, files?: SocioFiles, sql_is_endpoint?:boolean };
@ -43,7 +42,7 @@ export class SocioServer extends LogHandler {
//rate limits server functions globally
#ratelimits: { [key: string]: RateLimiter | null } = { con: null, upd:null};
#lifecycle_hooks: { [f_name: string]: Function | null; } = { con: null as (Con_Hook | null), discon: null as (Discon_Hook | null), msg: null as (Msg_Hook | null), sub: null as (Sub_Hook | null), unsub: null as (Unsub_Hook | null), upd: null as (Upd_Hook | null), auth: null as (Auth_Hook | null), gen_client_id: null as (GenCLientID_Hook | null), grant_perm: null as (GrantPerm_Hook | null), serv: null as (Serv_Hook | null), admin: null as (Admin_Hook | null), blob: null as (Blob_Hook | null), file_upload: null as (FileUpload_Hook | null), file_download: null as (FileDownload_Hook | null), endpoint: null as (Endpoint_Hook | null) } //call the register function to hook on these. They will be called if they exist
#lifecycle_hooks: ServerLifecycleHooks = { con: undefined, discon: undefined, msg: undefined, sub: undefined, unsub: undefined, upd: undefined, auth: undefined, gen_client_id: undefined, grant_perm: undefined, serv: undefined, admin: undefined, blob: undefined, file_upload: undefined, file_download: undefined, endpoint: undefined }; //call the register function to hook on these. They will be called if they exist
//If the hook returns a truthy value, then it is assumed, that the hook handled the msg and the lib will not. Otherwise, by default, the lib handles the msg.
//msg hook receives all incomming msgs to the server.
//upd works the same as msg, but for everytime updates need to be propogated to all the sockets.
@ -54,6 +53,7 @@ export class SocioServer extends LogHandler {
//stores active reconnection tokens
#tokens: Set<string> = new Set();
//global flag to send prop obj diffs using the diff lib instead of the full object every time.
#prop_upd_diff = false;
//public:
@ -257,7 +257,7 @@ export class SocioServer extends LogHandler {
//if the client happens to want to use an endpoint keyname instead of SQL, retrieve the SQL string from a hook call and procede with that.
if (data?.sql_is_endpoint && data.sql) {
if (this.#lifecycle_hooks.endpoint)
data.sql = await this.#lifecycle_hooks.endpoint(client, data.sql_is_endpoint);
data.sql = await this.#lifecycle_hooks.endpoint(client, data.sql);
else throw new E('Client sent endpoint instead of SQL, but its hook is missing. [#no-endpoint-hook-SQL]');
}
//have to do the query in every case
@ -552,7 +552,7 @@ export class SocioServer extends LogHandler {
}
//assigner defaults to basic setter
RegisterProp(key: PropKey, val: PropValue, { assigner = this.SetPropVal, client_writable = true, send_as_diff = undefined} = {}){
RegisterProp(key: PropKey, val: PropValue, { assigner = this.SetPropVal, client_writable = true, send_as_diff = undefined }: { assigner?: PropAssigner, client_writable?: boolean, send_as_diff?: boolean | undefined} = {}){
try{
if (this.#props.has(key))
throw new E(`Prop key [${key}] has already been registered and for client continuity is forbiden to over-write at runtime. [#prop-key-exists]`)

6
core/types.d.ts vendored
View file

@ -25,11 +25,12 @@ export type CoreMessageKind = 'SUB' | 'UNSUB' | 'SQL' | 'PING' | 'AUTH' | 'GET_P
export type ClientMessageKind = 'CON' | 'UPD' | 'PONG' | 'AUTH' | 'GET_PERM' | 'RES' | 'ERR' | 'PROP_UPD' | 'CMD' | 'RECON' | 'RECV_FILES' | 'TIMEOUT';
//server hook functions
export type ServerLifecycleHooks = { con?: Con_Hook, discon?: Discon_Hook, msg?: Msg_Hook, sub?: Sub_Hook, unsub?: Unsub_Hook, upd?: Upd_Hook, auth?: Auth_Hook, gen_client_id?: GenCLientID_Hook, grant_perm?: GrantPerm_Hook, serv?: Serv_Hook, admin?: Admin_Hook, blob?: Blob_Hook, file_upload?: FileUpload_Hook, file_download?: FileDownload_Hook, endpoint?: Endpoint_Hook };
export type GenCLientID_Hook = () => ClientID | Promise<ClientID>;
export type Con_Hook = (client: SocioSession, request: IncomingMessage) => void | Promise<void>;
export type Discon_Hook = (client: SocioSession) => void | Promise<void>;
export type Blob_Hook = (client: SocioSession, request: Buffer | ArrayBuffer | Buffer[]) => boolean | Promise<boolean>;
export type Msg_Hook = (client: SocioSession, kind: CoreMessageKind, data: MessageDataObj) => boolean | Promise<boolean>;
export type Msg_Hook = (client: SocioSession, kind: CoreMessageKind, data: MessageDataObj) => boolean | void | Promise<boolean> | Promise<void>;
export type Sub_Hook = (client: SocioSession, kind: CoreMessageKind, data: MessageDataObj) => boolean | Promise<boolean>;
export type Unsub_Hook = (client: SocioSession, kind: CoreMessageKind, data: MessageDataObj) => boolean | Promise<boolean>;
export type Auth_Hook = (client: SocioSession, params: object | null) => boolean | Promise<boolean>;
@ -43,8 +44,9 @@ export type Endpoint_Hook = (client: SocioSession, endpoint:string) => string |
// export type _Hook = (client: SocioSession) => boolean;
//client hook functions
export type ClientLifecycleHooks = { discon?: Discon_ClientHook, msg?: Msg_ClientHook, cmd?: Cmd_ClientHook, timeout?: Timeout_ClientHook };
export type Discon_ClientHook = (name:string, client_id:ClientID, url:string, keep_alive:boolean, verbose:boolean, reconnect_tries:number) => void;
export type Msg_ClientHook = (name: string, client_id: ClientID, kind: ClientMessageKind, data: ClientMessageDataObj) => boolean | Promise<boolean>;
export type Msg_ClientHook = (name: string, client_id: ClientID, kind: ClientMessageKind, data: ClientMessageDataObj) => boolean | void | Promise<boolean> | Promise<void>;
export type Cmd_ClientHook = (data:ClientMessageDataObj) => void;
export type Timeout_ClientHook = (name: string, client_id: ClientID) => void;
// export type _ClientHook = (name: string, client_id: ClientID,) => boolean;