/*!
 * TSRPC v3.4.18
 * -----------------------------------------
 * Copyright (c) King Wang.
 * MIT License
 * https://github.com/k8w/tsrpc
 */
/// <reference types="node" />
/// <reference path="mongodb-polyfill.d.ts" />

import { ApiReturn } from 'tsrpc-proto';
import { ApiService } from 'tsrpc-base-client';
import { ApiServiceDef } from 'tsrpc-proto';
import { BaseHttpClient } from 'tsrpc-base-client';
import { BaseHttpClientOptions } from 'tsrpc-base-client';
import { BaseServiceType } from 'tsrpc-proto';
import { BaseWsClient } from 'tsrpc-base-client';
import { BaseWsClientOptions } from 'tsrpc-base-client';
import { Counter } from 'tsrpc-base-client';
import { CustomTypeSchema } from 'tsbuffer-schema';
import { Flow } from 'tsrpc-base-client';
import http from 'http';
import * as http_2 from 'http';
import https from 'https';
import { Logger } from 'tsrpc-proto';
import { LogLevel } from 'tsrpc-proto';
import { MsgService } from 'tsrpc-base-client';
import { ParsedServerInput } from 'tsrpc-base-client';
import { ServiceMap } from 'tsrpc-base-client';
import { ServiceProto } from 'tsrpc-proto';
import { TSBuffer } from 'tsbuffer';
import { TsrpcError } from 'tsrpc-proto';
import { TsrpcErrorData } from 'tsrpc-proto';
import * as WebSocket_2 from 'ws';

/**
 * A call request by `client.callApi()`
 * @typeParam Req - Type of request
 * @typeParam Res - Type of response
 * @typeParam ServiceType - The same `ServiceType` to server, it is used for code auto hint.
 */
export declare abstract class ApiCall<Req = any, Res = any, ServiceType extends BaseServiceType = any> extends BaseCall<ServiceType> {
    readonly type: "api";
    /**
     * Which `ApiService` the request is calling for
     */
    readonly service: ApiService;
    /** Only exists in long connection, it is used to associate request and response.
     * It is created by the client, and the server would return the same value in `ApiReturn`.
     */
    readonly sn?: number;
    /**
     * Request data from the client, type of it is checked by the framework already.
     */
    readonly req: Req;
    constructor(options: ApiCallOptions<Req, ServiceType>, logger?: PrefixLogger);
    protected _return?: ApiReturn<Res>;
    /**
     * Response Data that sent already.
     * `undefined` means no return data is sent yet. (Never `call.succ()` and `call.error()`)
     */
    get return(): ApiReturn<Res> | undefined;
    protected _usedTime: number | undefined;
    /** Time from received req to send return data */
    get usedTime(): number | undefined;
    /**
     * Send a successful `ApiReturn` with response data
     * @param res - Response data
     * @returns Promise resolved means the buffer is sent to kernel
     */
    succ(res: Res): Promise<void>;
    /**
     * Send a error `ApiReturn` with a `TsrpcError`
     * @returns Promise resolved means the buffer is sent to kernel
     */
    error(message: string, info?: Partial<TsrpcErrorData>): Promise<void>;
    error(err: TsrpcError): Promise<void>;
    protected _prepareReturn(ret: ApiReturn<Res>): Promise<void>;
    protected _sendReturn(ret: ApiReturn<Res>): ReturnType<SendReturnMethod<Res>>;
    static encodeApiReturn(tsbuffer: TSBuffer, service: ApiService, apiReturn: ApiReturn<any>, type: "text", sn?: number): EncodeApiReturnOutput<string>;
    static encodeApiReturn(tsbuffer: TSBuffer, service: ApiService, apiReturn: ApiReturn<any>, type: "buffer", sn?: number): EncodeApiReturnOutput<Uint8Array>;
    static encodeApiReturn(tsbuffer: TSBuffer, service: ApiService, apiReturn: ApiReturn<any>, type: "json", sn?: number): EncodeApiReturnOutput<object>;
    static encodeApiReturn(tsbuffer: TSBuffer, service: ApiService, apiReturn: ApiReturn<any>, type: "text" | "buffer" | "json", sn?: number): EncodeApiReturnOutput<Uint8Array> | EncodeApiReturnOutput<string> | EncodeApiReturnOutput<object>;
}

export declare class ApiCallHttp<Req = any, Res = any, ServiceType extends BaseServiceType = any> extends ApiCall<Req, Res, ServiceType> {
    readonly conn: HttpConnection<ServiceType>;
    constructor(options: ApiCallHttpOptions<Req, ServiceType>);
    protected _sendReturn(ret: ApiReturn<Res>): Promise<{
        isSucc: true;
    } | {
        isSucc: false;
        errMsg: string;
    }>;
}

export declare interface ApiCallHttpOptions<Req, ServiceType extends BaseServiceType> extends ApiCallOptions<Req, ServiceType> {
    conn: HttpConnection<ServiceType>;
}

export declare interface ApiCallOptions<Req, ServiceType extends BaseServiceType> extends BaseCallOptions<ServiceType> {
    /** Which service the Call is belong to */
    service: ApiService;
    /** Only exists in long connection, it is used to associate request and response.
     * It is created by the client, and the server would return the same value in `ApiReturn`.
     */
    sn?: number;
    /** Request Data */
    req: Req;
}

export declare class ApiCallWs<Req = any, Res = any, ServiceType extends BaseServiceType = any> extends ApiCall<Req, Res, ServiceType> {
    readonly conn: WsConnection<ServiceType>;
    constructor(options: ApiCallWsOptions<Req, ServiceType>);
    protected _prepareReturn(ret: ApiReturn<Res>): Promise<void>;
}

export declare interface ApiCallWsOptions<Req, ServiceType extends BaseServiceType> extends ApiCallOptions<Req, ServiceType> {
    conn: WsConnection<ServiceType>;
}

export declare type ApiHandler<Call extends ApiCall = ApiCall> = (call: Call) => void | Promise<void>;

export declare abstract class BaseCall<ServiceType extends BaseServiceType> {
    readonly conn: BaseConnection<ServiceType>;
    readonly service: ApiService | MsgService;
    /** Time that server created the call */
    readonly startTime: number;
    readonly logger: PrefixLogger;
    constructor(options: BaseCallOptions<ServiceType>, logger: PrefixLogger);
    get server(): this["conn"]["server"];
}

export declare interface BaseCallOptions<ServiceType extends BaseServiceType> {
    /** Connection */
    conn: BaseConnection<ServiceType>;
    /** Which service the call is belong to */
    service: ApiService | MsgService;
}

export declare abstract class BaseConnection<ServiceType extends BaseServiceType = any> {
    /** It is long connection or short connection */
    abstract readonly type: "LONG" | "SHORT";
    protected abstract readonly ApiCallClass: {
        new (options: any): ApiCall;
    };
    protected abstract readonly MsgCallClass: {
        new (options: any): MsgCall;
    };
    /** Connection unique ID */
    readonly id: string;
    /** Client IP address */
    readonly ip: string;
    readonly server: BaseServer<ServiceType>;
    readonly logger: PrefixLogger;
    dataType: BaseConnectionOptions["dataType"];
    constructor(options: BaseConnectionOptions<ServiceType>, logger: PrefixLogger);
    abstract get status(): ConnectionStatus;
    /** Close the connection */
    abstract close(reason?: string): void;
    /** Send buffer (with pre-flow and post-flow) */
    sendData(data: string | Uint8Array | object, call?: ApiCall): Promise<{
        isSucc: true;
    } | {
        isSucc: false;
        errMsg: string;
        canceledByFlow?: string;
    }>;
    protected abstract doSendData(data: string | Uint8Array | object, call?: ApiCall): Promise<{
        isSucc: true;
    } | {
        isSucc: false;
        errMsg: string;
    }>;
    makeCall(input: ParsedServerInput): ApiCall | MsgCall;
    /**
     * Send message to the client, only be available when it is long connection.
     * @param msgName
     * @param msg - Message body
     * @returns Promise resolved when the buffer is sent to kernel, it not represents the server received it.
     */
    sendMsg<T extends string & keyof ServiceType["msg"]>(msgName: T, msg: ServiceType["msg"][T]): ReturnType<BaseConnection["sendData"]>;
    private _msgHandlers?;
    /**
     * Add a message handler,
     * duplicate handlers to the same `msgName` would be ignored.
     * @param msgName
     * @param handler
     */
    listenMsg<Msg extends string & keyof ServiceType["msg"], Call extends MsgCall<ServiceType["msg"][Msg]>>(msgName: Msg, handler: MsgHandler<Call>): MsgHandler<Call>;
    /**
     * Remove a message handler
     */
    unlistenMsg<Msg extends string & keyof ServiceType["msg"], Call extends MsgCall<ServiceType["msg"][Msg]>>(msgName: Msg, handler: Function): void;
    /**
     * Remove all handlers from a message
     */
    unlistenMsgAll<Msg extends string & keyof ServiceType["msg"], Call extends MsgCall<ServiceType["msg"][Msg]>>(msgName: Msg): void;
}

export declare interface BaseConnectionOptions<ServiceType extends BaseServiceType = any> {
    /** Created by server, each Call has a unique id. */
    id: string;
    /** Client IP address */
    ip: string;
    server: BaseServer<ServiceType>;
    dataType: "text" | "buffer" | "json";
}

/**
 * Abstract base class for TSRPC Server.
 * Implement on a transportation protocol (like HTTP WebSocket) by extend it.
 * @typeParam ServiceType - `ServiceType` from generated `proto.ts`
 */
export declare abstract class BaseServer<ServiceType extends BaseServiceType = BaseServiceType> {
    /**
     * Start the server
     * @throws
     */
    abstract start(): Promise<void>;
    /**
     * Stop server immediately, not waiting for the requests ending.
     */
    abstract stop(): Promise<void>;
    protected _status: ServerStatus;
    get status(): ServerStatus;
    readonly proto: ServiceProto<ServiceType>;
    readonly options: BaseServerOptions<ServiceType>;
    readonly tsbuffer: TSBuffer;
    readonly serviceMap: ServiceMap;
    readonly logger: Logger;
    protected _connIdCounter: Counter;
    /**
     * Flow is a specific concept created by TSRPC family.
     * All pre-flow can interrupt latter behaviours.
     * All post-flow can NOT interrupt latter behaviours.
     */
    readonly flows: {
        /** After the connection is created */
        readonly postConnectFlow: Flow<BaseConnection<ServiceType>>;
        /** After the connection is disconnected */
        readonly postDisconnectFlow: Flow<{
            conn: BaseConnection<ServiceType>;
            reason?: string | undefined;
        }>;
        /**
         * Before processing the received data, usually be used to encryption / decryption.
         * Return `null | undefined` would ignore the buffer.
         */
        readonly preRecvDataFlow: Flow<{
            conn: BaseConnection<ServiceType>;
            data: string | Uint8Array | object;
            /**
             * @deprecated use `serviceId` instead
             */
            serviceName?: string | undefined;
            /**
             * Parsed service id, you can get this by `this.serviceMap.apiName2Service[serviceName].id`
             */
            serviceId?: number | undefined;
        }>;
        /**
         * Before send out data to network, usually be used to encryption / decryption.
         * Return `null | undefined` would not send the buffer.
         */
        readonly preSendDataFlow: Flow<{
            conn: BaseConnection<ServiceType>;
            data: string | Uint8Array | object;
            call?: ApiCall<any, any, any> | undefined;
        }>;
        /**
         * @deprecated Use `preRecvDataFlow` instead.
         */
        readonly preRecvBufferFlow: Flow<{
            conn: BaseConnection<ServiceType>;
            buf: Uint8Array;
        }>;
        /**
         * @deprecated Use `preSendDataFlow` instead.
         */
        readonly preSendBufferFlow: Flow<{
            conn: BaseConnection<ServiceType>;
            buf: Uint8Array;
            call?: ApiCall<any, any, any> | undefined;
        }>;
        /**
         * Before a API request is send.
         * Return `null | undefined` would cancel the request.
         */
        readonly preApiCallFlow: Flow<ApiCall<any, any, any>>;
        /**
         * Before return the `ApiReturn` to the client.
         * It may be used to change the return value, or return `null | undefined` to abort the request.
         */
        readonly preApiReturnFlow: Flow<{
            call: ApiCall;
            return: ApiReturn<any>;
        }>;
        /**
         * After the `ApiReturn` is send.
         * return `null | undefined` would NOT interrupt latter behaviours.
         */
        readonly postApiReturnFlow: Flow<{
            call: ApiCall;
            return: ApiReturn<any>;
        }>;
        /**
         * After the api handler is executed.
         * return `null | undefined` would NOT interrupt latter behaviours.
         */
        readonly postApiCallFlow: Flow<ApiCall<any, any, any>>;
        /**
         * Before handle a `MsgCall`
         */
        readonly preMsgCallFlow: Flow<MsgCall<any, any>>;
        /**
         * After handlers of a `MsgCall` are executed.
         * return `null | undefined` would NOT interrupt latter behaviours.
         */
        readonly postMsgCallFlow: Flow<MsgCall<any, any>>;
        /**
         * Before send out a message.
         * return `null | undefined` would NOT interrupt latter behaviours.
         */
        readonly preSendMsgFlow: Flow<{
            conn: BaseConnection<ServiceType>;
            service: MsgService;
            msg: any;
        }>;
        /**
         * After send out a message.
         * return `null | undefined` would NOT interrupt latter behaviours.
         */
        readonly postSendMsgFlow: Flow<{
            conn: BaseConnection<ServiceType>;
            service: MsgService;
            msg: any;
        }>;
    };
    private _apiHandlers;
    private _msgHandlers;
    private static _isUncaughtExceptionProcessed;
    /**
     * It makes the `uncaughtException` and `unhandledRejection` not lead to the server stopping.
     * @param logger
     * @returns
     */
    static processUncaughtException(logger: Logger): void;
    constructor(proto: ServiceProto<ServiceType>, options: BaseServerOptions<ServiceType>);
    protected _setDefaultFlowOnError(): void;
    protected _pendingApiCallNum: number;
    /**
     * Process the buffer, after the `preRecvBufferFlow`.
     */
    _onRecvData(conn: BaseConnection<ServiceType>, data: string | Uint8Array | object, serviceId?: number): Promise<void>;
    protected _handleApiCall(call: ApiCall): Promise<void>;
    protected _onApiCall(call: ApiCall): Promise<void>;
    protected _onMsgCall(call: MsgCall): Promise<void>;
    /**
     * Associate a `ApiHandler` to a specific `apiName`.
     * So that when `ApiCall` is receiving, it can be handled correctly.
     * @param apiName
     * @param handler
     */
    implementApi<Api extends string & keyof ServiceType["api"], Call extends ApiCall<ServiceType["api"][Api]["req"], ServiceType["api"][Api]["res"]>>(apiName: Api, handler: ApiHandler<Call>): void;
    /** 用于延迟注册 API */
    protected _delayImplementApiPath?: string;
    /**
     * Auto call `imeplementApi` by traverse the `apiPath` and find all matched `PtlXXX` and `ApiXXX`.
     * It is matched by checking whether the relative path and name of an API is consistent to the service name in `serviceProto`.
     * Notice that the name prefix of protocol is `Ptl`, of API is `Api`.
     * For example, `protocols/a/b/c/PtlTest` is matched to `api/a/b/c/ApiTest`.
     * @param apiPath Absolute path or relative path to `process.cwd()`.
     * @returns
     */
    autoImplementApi(apiPath: string, delay?: boolean): Promise<{
        succ: string[];
        fail: string[];
    }>;
    getApiHandler(svc: ApiServiceDef, apiPath?: string, logger?: Logger): Promise<{
        handler: ApiHandler;
        errMsg?: undefined;
    } | {
        handler?: undefined;
        errMsg: string;
    }>;
    /**
     * Add a message handler,
     * duplicate handlers to the same `msgName` would be ignored.
     * @param msgName
     * @param handler
     * @returns
     */
    listenMsg<T extends keyof ServiceType["msg"], Call extends MsgCall<ServiceType["msg"][T]>>(msgName: T | RegExp, handler: MsgHandler<Call>): MsgHandler<Call>;
    /**
     * Remove a message handler
     */
    unlistenMsg<T extends keyof ServiceType["msg"]>(msgName: T | RegExp, handler: Function): void;
    /**
     * Remove all handlers from a message
     */
    unlistenMsgAll<T extends keyof ServiceType["msg"]>(msgName: T | RegExp): void;
    /**
     * Event when the server cannot parse input buffer to api/msg call.
     * By default, it will return "Input Data Error" .
     */
    onInputDataError(errMsg: string, conn: BaseConnection<ServiceType>, data: string | Uint8Array | object): Promise<void>;
    /**
     * Event when a uncaught error (except `TsrpcError`) is throwed.
     * By default, it will return a `TsrpcError` with message "Internal server error".
     * If `returnInnerError` is `true`, the original error would be returned as `innerErr` property.
     */
    onInternalServerError(err: {
        message: string;
        stack?: string;
        name?: string;
    }, call: ApiCall): void;
    protected _gracefulStop?: {
        rs: () => void;
    };
    /**
     * Stop the server gracefully.
     * Wait all API requests finished and then stop the server.
     * @param maxWaitTime - The max time(ms) to wait before force stop the server.
     * `undefined` and `0` means unlimited time.
     */
    gracefulStop(maxWaitTime?: number): Promise<void>;
    /**
     * Execute API function through the inner connection, which is useful for unit test.
     *
     * **NOTICE**
     * The `req` and return value is native JavaScript object which is not compatible to JSON. (etc. ArrayBuffer, Date, ObjectId)
     * If you are using pure JSON as transfering, you may need use `callApiByJSON`.
     * @param apiName
     * @param req
     * @param options
     */
    callApi<T extends string & keyof ServiceType["api"]>(apiName: T, req: ServiceType["api"][T]["req"]): Promise<ApiReturn<ServiceType["api"][T]["res"]>>;
    /**
     * Like `server.callApi`, but both input and output are pure JSON object,
     * which can be `JSON.stringify()` and `JSON.parse()` directly.
     * Types that not compatible to JSON, would be encoded and decoded automatically.
     * @param apiName - The same with `server.callApi`, may be parsed from the URL.
     * @param jsonReq - Request data in pure JSON
     * @returns Encoded `ApiReturn<Res>` in pure JSON
     */
    /**
     * Process JSON request by inner proxy, this is useful when you are porting to cloud function services.
     * Both the input and output is pure JSON, ArrayBuffer/Date/ObjectId are encoded to string automatically.
     * @param apiName - Parsed from URL
     * @param req - Pure JSON
     * @param logger - Custom logger
     * @returns - Pure JSON
     */
    inputJSON(apiName: string, req: object, logger?: PrefixLogger): Promise<ApiReturn<object>>;
    /**
     * Process input buffer by inner proxy, this is useful when you are porting to cloud function services.
     * @param buf Input buffer (may be sent by TSRPC client)
     * @returns Response buffer
     */
    inputBuffer(buf: Uint8Array): Promise<Uint8Array>;
    protected _parseServerInput(tsbuffer: TSBuffer, serviceMap: ServiceMap, data: string | Uint8Array | object, serviceId?: number): {
        isSucc: true;
        result: ParsedServerInput;
    } | {
        isSucc: false;
        errMsg: string;
    };
}

export declare interface BaseServerOptions<ServiceType extends BaseServiceType> {
    /**
     * Whether to enable JSON compatible mode.
     * When it is true, it can be compatible with typical HTTP JSON request (like RESTful API).
     *
     * @remarks
     * The JSON request methods are:
     *
     * 1. Add `Content-type: application/json` to request header.
     * 2. HTTP request is: `POST /{jsonUrlPath}/{apiName}`.
     * 3. POST body is JSON string.
     * 4. The response body is JSON string also.
     *
     * NOTICE: Buffer type are not supported due to JSON not support them.
     * For security and efficient reason, we strongly recommend you use binary encoded transportation.
     *
     * @defaultValue `false`
     */
    json: boolean;
    /** @deprecated Use `json` instead. */
    jsonEnabled?: boolean;
    /**
     * Whether to strictly distinguish between `null` and `undefined` when encoding, decoding, and type checking.
     * @defaultValue false
     */
    strictNullChecks: boolean;
    /**
     * Timeout for processing an `ApiCall`(ms)
     * `0` and `undefined` means unlimited time
     * @defaultValue 30000
     */
    apiTimeout: number | undefined;
    /**
     * Logger for processing log
     * @defaultValue `new TerminalColorLogger()` (print to console with color)
     */
    logger: Logger;
    /**
     * The minimum log level of `logger`
     * @defaultValue `debug`
     */
    logLevel: LogLevel;
    /**
     * Whether to print API request body into log (may increase log size)
     * @defaultValue `true`
     */
    logReqBody: boolean;
    /**
     * Whether to print API response body into log (may increase log size)
     * @defaultValue `true`
     */
    logResBody: boolean;
    /**
     * Whether to print `[SendMsg]` and `[RecvMsg]` log into log
     * @defaultValue `true`
     */
    logMsg: boolean;
    /**
     * If `true`, all sent and received raw buffer would be print into the log.
     * It may be useful when you do something for buffer encryption/decryption, and want to debug them.
     */
    debugBuf?: boolean;
    /**
     * When uncaught error throwed,
     * whether to return the original error as a property `innerErr`.
     * (May include some sensitive information, suggests set to `false` in production environment.)
     * @defaultValue It depends on environment variable `NODE_ENV`.
     * If `NODE_ENV` equals to `production`, the default value is `false`, otherwise is `true`.
     */
    returnInnerError: boolean;
    /**
     * Customize the protocol data type
     */
    customTypes?: {
        [schemaId: string]: CustomTypeSchema;
    };
}

export declare enum ConnectionStatus {
    Opened = "OPENED",
    Closing = "CLOSING",
    Closed = "CLOSED"
}

export declare const defaultBaseServerOptions: BaseServerOptions<any>;

export declare const defaultHttpServerOptions: HttpServerOptions<any>;

export declare type EncodeApiReturnOutput<T> = {
    isSucc: true;
    /** Encoded binary buffer */
    output: T;
    errMsg?: undefined;
} | {
    isSucc: false;
    /** Error message */
    errMsg: string;
    output?: undefined;
};

/**
 * Client for TSRPC HTTP Server.
 * It uses native http module of NodeJS.
 * @typeParam ServiceType - `ServiceType` from generated `proto.ts`
 */
export declare class HttpClient<ServiceType extends BaseServiceType> extends BaseHttpClient<ServiceType> {
    readonly options: Readonly<HttpClientOptions>;
    constructor(proto: ServiceProto<ServiceType>, options?: Partial<HttpClientOptions>);
}

export declare interface HttpClientOptions extends BaseHttpClientOptions {
    /** NodeJS HTTP Agent */
    agent?: http.Agent | https.Agent;
}

export declare class HttpConnection<ServiceType extends BaseServiceType = any> extends BaseConnection<ServiceType> {
    readonly type = "SHORT";
    protected readonly ApiCallClass: typeof ApiCallHttp;
    protected readonly MsgCallClass: typeof MsgCallHttp;
    readonly httpReq: http_2.IncomingMessage & {
        rawBody?: Buffer;
    };
    readonly httpRes: http_2.ServerResponse;
    readonly server: HttpServer<ServiceType>;
    /**
     * Whether the transportation of the connection is JSON encoded instead of binary encoded.
     */
    readonly isJSON: boolean | undefined;
    /**
     * In short connection, one connection correspond one call.
     * It may be `undefined` when the request data is not fully received yet.
     */
    call?: ApiCallHttp | MsgCallHttp;
    constructor(options: HttpConnectionOptions<ServiceType>);
    get status(): ConnectionStatus;
    protected doSendData(data: string | Uint8Array, call?: ApiCall): Promise<{
        isSucc: true;
    } | {
        isSucc: false;
        errMsg: string;
    }>;
    /**
     * Close the connection, the reason would be attached to response header `X-TSRPC-Close-Reason`.
     */
    close(reason?: string): void;
    makeCall(input: ParsedServerInput): ApiCallHttp | MsgCallHttp;
}

export declare interface HttpConnectionOptions<ServiceType extends BaseServiceType> extends BaseConnectionOptions<ServiceType> {
    server: HttpServer<ServiceType>;
    httpReq: http_2.IncomingMessage;
    httpRes: http_2.ServerResponse;
}

/**
 * TSRPC Server, based on HTTP connection.
 * @typeParam ServiceType - `ServiceType` from generated `proto.ts`
 */
export declare class HttpServer<ServiceType extends BaseServiceType = any> extends BaseServer<ServiceType> {
    readonly options: HttpServerOptions<ServiceType>;
    constructor(proto: ServiceProto<ServiceType>, options?: Partial<HttpServerOptions<ServiceType>>);
    /** Native `http.Server` of NodeJS */
    httpServer?: http_2.Server | https.Server;
    /**
     * {@inheritDoc BaseServer.start}
     */
    start(): Promise<void>;
    /**
     * {@inheritDoc BaseServer.stop}
     */
    stop(): Promise<void>;
}

export declare interface HttpServerOptions<ServiceType extends BaseServiceType> extends BaseServerOptions<ServiceType> {
    /** Which port the HTTP server listen to */
    port: number;
    /**
     * HTTPS options, the server would use https instead of http if this value is defined.
     * NOTICE: Once you enabled https, you CANNOT visit the server via `http://` anymore.
     * If you need visit the server via both `http://` and `https://`, you can start 2 HttpServer (one with `https` and another without).
     * @defaultValue `undefined`
     */
    https?: {
        /**
         * @example
         * fs.readFileSync('xxx-key.pem');
         */
        key: https.ServerOptions["key"];
        /**
         * @example
         * fs.readFileSync('xxx-cert.pem');
         */
        cert: https.ServerOptions["cert"];
    };
    /**
     * Passed to the `timeout` property to the native `http.Server` of NodeJS, in milliseconds.
     * `0` and `undefined` will disable the socket timeout behavior.
     * NOTICE: this `socketTimeout` be `undefined` only means disabling of the socket timeout, the `apiTimeout` is still working.
     * `socketTimeout` should always greater than `apiTimeout`.
     * @defaultValue `undefined`
     * @see {@link https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_server_timeout}
     */
    socketTimeout?: number;
    /**
     * Passed to the `keepAliveTimeout` property to the native `http.Server` of NodeJS, in milliseconds.
     * It means keep-alive timeout of HTTP socket connection.
     * @defaultValue 5000 (from NodeJS)
     * @see {@link https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_server_keepalivetimeout}
     */
    keepAliveTimeout?: number;
    /**
     * Response header value of `Access-Control-Allow-Origin`.
     * If this has any value, it would also set `Access-Control-Allow-Headers` as `*`.
     * `undefined` means no CORS header.
     * @defaultValue `*`
     */
    cors?: string;
    /**
     * Response header value of `Access-Control-Allow-Origin`.
     * @defaultValue `3600`
     */
    corsMaxAge?: number;
    /**
     * Actual URL path is `${jsonHostPath}/${apiName}`.
     * For example, if `jsonHostPath` is `'/api'`, then you can send `POST /api/a/b/c/Test` to call API `a/b/c/Test`.
     * @defaultValue `'/'`
     */
    jsonHostPath: string;
}

/**
 * A call request by `client.sendMsg()`
 * @typeParam Msg - Type of the message
 * @typeParam ServiceType - The same `ServiceType` to server, it is used for code auto hint.
 */
export declare abstract class MsgCall<Msg = any, ServiceType extends BaseServiceType = any> extends BaseCall<ServiceType> {
    readonly type: "msg";
    readonly service: MsgService;
    readonly msg: Msg;
    constructor(options: MsgCallOptions<Msg, ServiceType>, logger?: PrefixLogger);
}

export declare class MsgCallHttp<Msg = any, ServiceType extends BaseServiceType = any> extends MsgCall<Msg, ServiceType> {
    readonly conn: HttpConnection<ServiceType>;
    constructor(options: MsgCallHttpOptions<Msg, ServiceType>);
}

export declare interface MsgCallHttpOptions<Msg, ServiceType extends BaseServiceType> extends MsgCallOptions<Msg, ServiceType> {
    conn: HttpConnection<ServiceType>;
}

export declare interface MsgCallOptions<Msg, ServiceType extends BaseServiceType> extends BaseCallOptions<ServiceType> {
    service: MsgService;
    msg: Msg;
}

export declare class MsgCallWs<Msg = any, ServiceType extends BaseServiceType = any> extends MsgCall<Msg, ServiceType> {
    readonly conn: WsConnection<ServiceType>;
    constructor(options: MsgCallWsOptions<Msg, ServiceType>);
}

export declare interface MsgCallWsOptions<Msg, ServiceType extends BaseServiceType> extends MsgCallOptions<Msg, ServiceType> {
    conn: WsConnection<ServiceType>;
}

export declare type MsgHandler<Call extends MsgCall = MsgCall> = (call: Call) => void | Promise<void>;

/**
 * Auto add prefix using existed `Logger`
 */
export declare class PrefixLogger implements Logger {
    readonly logger: PrefixLoggerOptions["logger"];
    readonly prefixs: PrefixLoggerOptions["prefixs"];
    constructor(options: PrefixLoggerOptions);
    getPrefix(): string[];
    log(...args: any[]): void;
    debug(...args: any[]): void;
    warn(...args: any[]): void;
    error(...args: any[]): void;
}

export declare interface PrefixLoggerOptions {
    logger: Logger;
    prefixs: (string | (() => string))[];
}

export declare type SendReturnMethod<Res> = (ret: ApiReturn<Res>) => ReturnType<BaseConnection["sendData"]>;

export declare enum ServerStatus {
    Opening = "OPENING",
    Opened = "OPENED",
    Closing = "CLOSING",
    Closed = "CLOSED"
}

/**
 * Print log to terminal, with color.
 */
export declare class TerminalColorLogger implements Logger {
    options: TerminalColorLoggerOptions;
    private _pid;
    constructor(options?: Partial<TerminalColorLoggerOptions>);
    private _time;
    debug(...args: any[]): void;
    log(...args: any[]): void;
    warn(...args: any[]): void;
    error(...args: any[]): void;
}

export declare interface TerminalColorLoggerOptions {
    /**
     * Process ID prefix
     * @defaultValue `process.pid`
     */
    pid: string;
    /**
     * `undefined` represents not print time
     * @defaultValue 'yyyy-MM-dd hh:mm:ss'
     */
    timeFormat?: string;
}

/** Version of TSRPC */
export declare const TSRPC_VERSION = "__TSRPC_VERSION__";

/**
 * Client for TSRPC WebSocket Server.
 * @typeParam ServiceType - `ServiceType` from generated `proto.ts`
 */
export declare class WsClient<ServiceType extends BaseServiceType> extends BaseWsClient<ServiceType> {
    readonly options: Readonly<WsClientOptions>;
    constructor(proto: ServiceProto<ServiceType>, options?: Partial<WsClientOptions>);
}

export declare interface WsClientOptions extends BaseWsClientOptions {
}

/**
 * Connected client
 */
export declare class WsConnection<ServiceType extends BaseServiceType = any> extends BaseConnection<ServiceType> {
    readonly type = "LONG";
    protected readonly ApiCallClass: typeof ApiCallWs;
    protected readonly MsgCallClass: typeof MsgCallWs;
    readonly ws: WebSocket_2;
    readonly httpReq: http_2.IncomingMessage;
    readonly server: WsServer<ServiceType>;
    dataType: "text" | "buffer";
    isDataTypeConfirmed?: boolean;
    constructor(options: WsConnectionOptions<ServiceType>);
    private _lastHeartbeatTime;
    private _heartbeatInterval?;
    get status(): ConnectionStatus;
    protected doSendData(data: string | Uint8Array, call?: ApiCallWs): Promise<{
        isSucc: true;
    } | {
        isSucc: false;
        errMsg: string;
    }>;
    protected _rsClose?: () => void;
    /** Close WebSocket connection */
    close(reason?: string, code?: number, closeTimeout?: number): Promise<void>;
}

export declare interface WsConnectionOptions<ServiceType extends BaseServiceType> extends BaseConnectionOptions<ServiceType> {
    server: WsServer<ServiceType>;
    ws: WebSocket_2;
    httpReq: http_2.IncomingMessage;
    onClose: (conn: WsConnection<ServiceType>, code: number, reason: string) => Promise<void>;
    dataType: "text" | "buffer";
    isDataTypeConfirmed?: boolean;
}

/**
 * TSRPC Server, based on WebSocket connection.
 * It can support realtime cases.
 * @typeParam ServiceType - `ServiceType` from generated `proto.ts`
 */
export declare class WsServer<ServiceType extends BaseServiceType = any> extends BaseServer<ServiceType> {
    readonly options: WsServerOptions<ServiceType>;
    readonly connections: WsConnection<ServiceType>[];
    private readonly _id2Conn;
    constructor(proto: ServiceProto<ServiceType>, options?: Partial<WsServerOptions<ServiceType>>);
    private _wsServer?;
    private _httpServer?;
    /**
     * {@inheritDoc BaseServer.start}
     */
    start(): Promise<void>;
    /**
     * {@inheritDoc BaseServer.stop}
     */
    stop(): Promise<void>;
    private _onClientConnect;
    private _onClientClose;
    /**
     * Send the same message to many connections.
     * No matter how many target connections are, the message would be only encoded once.
     * @param msgName
     * @param msg - Message body
     * @param connIds - `id` of target connections, `undefined` means broadcast to every connections.
     * @returns Send result, `isSucc: true` means the message buffer is sent to kernel, not represents the clients received.
     */
    broadcastMsg<T extends string & keyof ServiceType["msg"]>(msgName: T, msg: ServiceType["msg"][T], conns?: WsConnection<ServiceType>[]): Promise<{
        isSucc: true;
    } | {
        isSucc: false;
        errMsg: string;
    }>;
}

export declare interface WsServerOptions<ServiceType extends BaseServiceType> extends BaseServerOptions<ServiceType> {
    /** Which port the WebSocket server is listen to */
    port: number;
    /** Whether to print `[Connected]` and `[Disconnected]` into log */
    logConnect: boolean;
    /**
     * HTTPS options, the server would use wss instead of http if this value is defined.
     * NOTICE: Once you enabled wss, you CANNOT visit the server via `ws://` anymore.
     * If you need visit the server via both `ws://` and `wss://`, you can start 2 HttpServer (one with `wss` and another without).
     * @defaultValue `undefined`
     */
    wss?: {
        /**
         * @example
         * fs.readFileSync('xxx-key.pem');
         */
        key: https.ServerOptions["key"];
        /**
         * @example
         * fs.readFileSync('xxx-cert.pem');
         */
        cert: https.ServerOptions["cert"];
    };
    /**
     * Close a connection if not receive heartbeat after the time (ms).
     * This value should be greater than `client.heartbeat.interval`, for exmaple 2x of it.
     * `undefined` or `0` represent disable this feature.
     * @defaultValue `undefined`
     */
    heartbeatWaitTime?: number;
    /**
     * WebSocket server options, transfer to 'ws' package.
     */
    wsOptions?: WebSocket_2.ServerOptions;
}


export * from "tsrpc-base-client";
export * from "tsrpc-proto";

export { }
