happypandax-client
Version:
A javascript client library for communicating with HappyPanda X servers
389 lines (388 loc) • 12.1 kB
TypeScript
/// <reference types="node" />
import * as net from 'net';
import { CustomError } from 'ts-custom-error';
export declare const exception_codes: {
AuthRequiredError: number;
AuthWrongCredentialsError: number;
AuthMissingCredentials: number;
ServerError: number;
AuthError: number;
ClientError: number;
ConnectionError: number;
ServerDisconnectError: number;
};
export interface CustomLogger {
debug: (m: string) => void;
info: (m: string) => void;
warning: (m: string) => void;
error: (m: string) => void;
}
/**
* The logger
* @group Logging
*/
export declare const log: {
/**
* Enable or disable logging
*/
enabled: boolean;
/**
* Can be set to a custom logger that will be used instead of console
*/
logger: CustomLogger;
d: (msg: string) => void;
i: (msg: string) => void;
w: (msg: string) => void;
e: (msg: string) => void;
};
declare class EError extends CustomError {
code: number;
constructor(message: string);
}
/**
* Base class for all server errors
* @extends Error
* @category Errors
*/
export declare class ServerError extends EError {
constructor(message: string);
}
/**
* Base class for all authentication errors
* @extends ServerError
* @category Errors
*/
export declare class AuthError extends ServerError {
constructor(message: string);
}
/**
* Wrong credentials error
* @extends AuthError
* @category Errors
*/
export declare class AuthWrongCredentialsError extends AuthError {
constructor(message: string);
}
/**
* Authentication required error
* @extends AuthError
* @category Errors
*/
export declare class AuthRequiredError extends AuthError {
constructor(message: string);
}
/**
* Missing credentials error
* @extends AuthError
* @category Errors
*/
export declare class AuthMissingCredentials extends AuthError {
constructor(message: string);
}
/**
* Base class for all client errors
* @extends ServerError
* @category Errors
*/
export declare class ClientError extends ServerError {
constructor(message: string);
}
/**
* Timeout error
* @extends ClientError
* @category Errors
*/
export declare class TimeoutError extends ClientError {
constructor(message: string);
}
/**
* Base class for all connection errors
* @extends ClientError
* @category Errors
*/
export declare class ConnectionError extends ClientError {
constructor(message: string);
}
/**
* Server disconnect error
* @extends ConnectionError
* @category Errors
*/
export declare class ServerDisconnectError extends ConnectionError {
}
export type AnyJson = boolean | number | string | null | JsonArray | JsonMap;
export type JsonMap = {
[key: string]: AnyJson;
};
export interface JsonArray extends Array<AnyJson> {
}
export type Msg = JsonMap;
export type JsonMapCompatible<TKeys extends string = string> = {
[Key in TKeys]: AnyJson;
};
export type ServerCommand = "handshake" | "call" | "requestauth" | "dropauth" | "serverquit" | "serverrestart" | 1 | 2 | 3 | 4 | 5 | 6;
/**
* A helper function that will wrap your message up like this:
* ```
* msg = {
* 'session': session_id,
* 'name': name,
* 'command': command, <--- your command is put here
* 'data': data, # <--- your message is put here
* }
* ```
* @param {ServerCommand} command - message to wrap
* @param {AnyJson} data - message to wrap
* @param {string} session_id - optional, session id
* @param {string} name - name of client
* @param {AnyJson} msg_id - optional message id
* @return {ServerMsg}
*/
export declare function finalize<C extends ServerCommand>(command: C, data: ClientMsg<C>["data"], session_id?: string | null, name?: string, msg_id?: ClientMsg<C>["__id__"]): ClientMsg<C>;
type Version = {
core: [number, number, number];
db: [number, number, number];
torrent: [number, number, number];
};
export type ServerErrorMsg = {
code: number;
msg: string;
};
export interface ClientMsgBase<D = AnyJson> {
__id__?: string | number;
session: string;
command: ServerCommand | AnyJson;
name: string;
data?: D;
}
export interface ClientMsg<C extends ServerCommand = "call"> extends ClientMsgBase {
command: C;
data: C extends "call" ? ClientFunctionMsg[] : C extends "handshake" ? {
username: string;
password: string;
} | {} | undefined : AnyJson;
}
type ServerInfo = {
version: Version;
guest_allowed: boolean;
};
export interface ServerMsgBase<D = AnyJson> {
__id__?: string | number;
session: string;
name: string;
data: D;
error?: ServerErrorMsg;
}
export interface ServerMsg<C extends ServerCommand> extends ServerMsgBase {
data: C extends "call" ? ServerFunctionMsg[] : C extends "handshake" ? "Authenticated" | null : C extends "requestauth" | "dropauth" ? ServerInfo | null : C extends "serverquit" | "serverrestart" ? "ok" | null : AnyJson;
}
export type ServerFunctionMsg = {
fname: string;
data: AnyJson;
error?: ServerErrorMsg;
};
export type ClientFunctionMsg = {
fname: string;
[arg: string]: AnyJson;
};
/**
* A class representing a HappyPanda X client
*/
export declare class Client {
name: string;
endpoint: [string, number];
/**
* Whether to resolve localhost to IPv4 (default: true), see https://github.com/nodejs/node/issues/40702
*/
resolve_IPV4_localhost: boolean;
version: Version | null;
guest_allowed: boolean;
session: string;
private _id_counter;
private _alive;
private _disconnected;
private _ready;
private _last_user;
private _last_pass;
private _stream;
private _timeout;
private _sock;
private _encoder;
private _decoder;
private _connecting;
private __data_promises_order;
private __data_promises;
/**
* @param {Object} params - optional params
* @param [params.name=js-client] {string} - name of client
* @param [params.host] {string} - server host
* @param [params.port] {integer} - server port
* @param [params.user] {string} - username
* @param [params.password] {string} - password
* @param [params.session_id] {string} - a server session id
* @param [params.timeout] {integer} - connection timeout
*/
constructor({ name, host, port, session_id, timeout, user, password, }: Partial<{
name: string;
host: string;
user: string | null;
password: string | null;
port: number;
session_id: string;
timeout: number;
}>);
private _create_socket;
/**
* Add a listener to the underlying socket
* @param {string} event - event name
* @param {Function} listener - listener function
* @return {Client}
*/
on(event: 'connect' | 'close' | 'end' | 'error' | 'timeout', listener: (...args: any[]) => void): this;
/**
* Add a listener to the underlying socket
* @param {string} event - event name
* @param {Function} listener - listener function
* @return {Client}
*/
once(...args: Parameters<net.Socket["once"]>): this;
/**
* Remove a listener from the underlying socket
* @param {string} event - event name
* @param {Function} listener - listener function
* @return {Client}
*/
off(...args: Parameters<net.Socket["off"]>): this;
/**
* Check if server is still alive
* @return {boolean}
*/
alive(): boolean;
/**
* Check if client is ready to exchange messages with server
* @return {boolean}
*/
ready(): boolean;
/**
* Get the timeout value
* @return {number}
*/
get timeout(): number;
set timeout(t: number);
private get _connect_msg_id();
private get _close_msg_id();
private _next_id;
private _add_data_promise;
private _get_data_promise;
private _get_earliest_data_promise;
private _server_info;
/**
* Set server address
* @param {string} host - server host
* @param {integer} port - server port
*/
set_endpoint(host: string, port: number): void;
/**
* Perfom a handshake with the HPX server
* @category async
* @param {object} params - optinal params
* @param [params.user] {string} - username
* @param [params.password] {integer} - password
* @param [params.ignore_err] {boolean} - ignore error
* @throws {AuthError}
* @returns {Promise}
*/
handshake(params: Partial<{
user: string | null;
password: string | null;
ignore_err: boolean;
}>): Promise<boolean>;
/**
* Forces client to request a new handshake, but doesn't invalidate previous session
* @category async
* @returns {Promise}
*/
request_auth(): Promise<void>;
/**
* Logout and invalidates the session
* @category async
* @returns {Promise}
*/
drop_auth(): Promise<void>;
/**
* Send the serverquit command
* @category async
* @returns {Promise}
*/
server_quit(): Promise<ServerMsg<"serverquit">>;
/**
* Send the serverrestart command
* @category async
* @returns {Promise}
*/
server_restart(): Promise<ServerMsg<"serverrestart">>;
/**
* Call a single function, this is even more of a shortcut than send
* @category async
* @param {ClientMsg<'call'>['data']} data - data
* @returns {Promise}
*/
call(data: ClientMsg<'call'>['data']): Promise<ServerMsg<"call">>;
/**
* Call a single function, this is even more of a shortcut than send
* @category async
* @param {string} fname - function name
* @param [args] {object} - function arguments
* @returns {Promise}
*/
call_function(fname: string, args?: Record<string, AnyJson>): Promise<ServerMsg<"call">>;
/**
* Check if the client is still connected to the server
* @return {boolean}
*/
is_connected(): boolean;
/**
* Connect to HPX server
* @category async
* @param {object} params - optional params
* @param [params.host] {string} - server host
* @param [params.port] {integer} - server port
* @returns {Promise}
*/
connect(params?: {
host?: string;
port?: number;
}): Promise<ServerMsgBase<ServerInfo> | undefined>;
private _on_timeout;
private _on_connect;
private _on_error;
private _on_disconnect;
private _disconnect;
/**
* Like {@link send_raw}, but as a convenience, this method will wrap your message into the required message structure HPX expects and automatically sets the session and name
* @category async
* @param {JsonMap} data - the data part of the message
* @param {ServerCommand} command - the command, defaults to 'call'
* @returns {Promise}
* @fullfil {Object} - message from server
*/
send<C extends ServerCommand>(command: C, data: ClientMsg<C>["data"]): Promise<ServerMsg<C>>;
/**
* Send json-compatible Object to server. Receive json-compatible Object from server.
*
* Note that this method will not modify your message and expects you to add the name and session yourself. See the {@link finalize} function.
* @category async
* @param {Object} msg - message to send to the server
* @returns {Promise}
* @fullfil {Object} - message from server
*/
send_raw<C extends ServerCommand>(msg: ClientMsg<C>): Promise<ServerMsg<C>>;
private _send;
private _recv;
/**
* Close the connection
* @returns {Promise}
*/
close(): Promise<void>;
}
export default Client;