/**
 * @author Nathan Pennie <kb1rd@kb1rd.net>
 */
/** */
import EventEmitter from 'eventemitter3';
import { MultistringAddress, WildcardMultistringAddress, AddressMap } from './addrmap';
import { ChainedAccessController, AccessController, OptAccessPolicy, CanCallFunction, RequiresPermissions, PermissionedAccessCanFunction, CanCallOpts } from './accesscontrol';
import { SerializableData, SerializedData } from './serializer';
export declare const RpcFunctionAddress: unique symbol;
export declare const RpcRemappedFunction: unique symbol;
interface WithValidAddressKey {
    [RpcFunctionAddress]?: WildcardMultistringAddress;
}
declare type RpcResult = SerializableData | Promise<SerializableData> | AsyncGenerator<SerializableData, void, void>;
/**
 * A destination function for Remote Procedure Calls (RPCs).
 * @param src The source `RpcChannel`
 * @param wildcards Any wildcards that were used in resolution of this function
 */
export interface RpcFunction extends WithValidAddressKey {
    (src: RpcChannel, wildcards: string[], ...args: SerializedData[]): RpcResult;
    [RpcRemappedFunction]?: RpcFunction;
    [CanCallFunction]?: PermissionedAccessCanFunction;
    [RequiresPermissions]?: Iterable<string>;
}
export declare function RpcAddress(address: WildcardMultistringAddress): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export declare function RemapArguments(mapping: ('pass' | 'drop' | 'expand')[], key?: string | symbol | number): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
/**
 * Sent between threads/workers/tabs/domains/whatever to carry RPCs and
 * associated data.
 */
export interface RpcMessage {
    to: MultistringAddress;
    args: SerializedData[];
    return_addr?: MultistringAddress;
    return_type?: 'promise' | 'generator';
}
export declare namespace RpcMessage {
    const Schema: {
        type: string;
        properties: {
            to: {
                type: string;
                items: {
                    type: string;
                };
            };
            args: {
                type: string;
            };
            return_addr: {
                type: string;
                items: {
                    type: string;
                };
            };
            return_type: {
                type: string;
                enum: string[];
            };
        };
        required: string[];
    };
}
export declare type BaseRegisteredObject = {
    [key: string]: WithValidAddressKey;
};
/**
 * Anything where RPC functions can be registered and unregistered.
 */
interface HandleRegistry {
    /**
     * Registers a handler for incoming data
     * @param address Address for the handle
     * @param func Function to call when triggered
     */
    register(address: WildcardMultistringAddress, func: RpcFunction): void;
    /**
     * Unregisters a handler for incoming data
     * @param address Address for the handle
     */
    unregister(address: WildcardMultistringAddress): void;
    /**
     * Registers member functions of a class (marked with the `RpcAddress`
     * decorator)
     */
    registerAll(obj: BaseRegisteredObject): void;
    /**
     * Unregisters member functions of a class (marked with the `RpcAddress`
     * decorator). Note that if any functions were removed from the class after
     * it was registered, those will not be unregistered.
     */
    unregisterAll(obj: BaseRegisteredObject): void;
}
/**
 * Where RPC handles are registered to a particular address. This can be
 * re-used between different `RpcChannel`s.
 */
export declare class RpcHandlerRegistry extends ChainedAccessController implements HandleRegistry {
    map: AddressMap<RpcFunction>;
    return_seq_id: number;
    constructor();
    register(address: WildcardMultistringAddress, func: RpcFunction): void;
    unregister(address: WildcardMultistringAddress): void;
    registerAll(base: BaseRegisteredObject): void;
    unregisterAll(base: BaseRegisteredObject): void;
    clear(): void;
    nextSeqAddr(): MultistringAddress;
}
export interface RpcAccessor {
    (...args: SerializableData[]): Promise<SerializedData>;
    [key: string]: RpcAccessor;
}
/**
 * Thrown when a return from a function call reaches a different RpcChannel
 * than it was sent from. This **may** indicate a security issue due to re-used
 * recieve callbacks.
 */
export declare class InvalidChannelError extends Error {
    readonly name = "InvalidChannelError";
}
export declare class AccessDeniedError extends Error {
    readonly name = "AccessDeniedError";
}
export declare class ForwardedError extends Error {
}
interface RpcChannelOpts {
    /**
     * If a keepalive has not been received for this much time, assume that this
     * `RpcChannel` has been closed.
     */
    timeout?: number;
    /**
     * The interval with which to send keep-alives. This must be shorter than the
     * timeout interval on the receiving end.
     */
    keep_alive_interval?: number;
    /**
     * Waits to start the channel until a message is received. This should only
     * be used on the end that is started first: Such as an `iframe` parent, a
     * worker's host, or a tab's creator.
     */
    await_first_msg?: boolean;
}
export declare enum RpcState {
    INACTIVE = 0,
    ACTIVE = 1,
    CLOSED = 2
}
/**
 * A wrapper class for functions to perform remote procedure calls.
 */
export declare class RpcChannel extends EventEmitter implements HandleRegistry, AccessController {
    protected readonly c_send: (msg: RpcMessage, xfer: Transferable[]) => void;
    protected readonly default_policy: boolean;
    reg: RpcHandlerRegistry;
    protected readonly _opts: RpcChannelOpts;
    readonly _i_reg: RpcHandlerRegistry;
    access_controller?: AccessController;
    active_timeout?: number;
    active_keepalive?: number;
    protected _state: RpcState;
    /**
     * @param c_send The function to send over whatever transport is used.
     * @param reg The handle registry. This can be changed later.
     */
    constructor(c_send: (msg: RpcMessage, xfer: Transferable[]) => void, default_policy?: boolean, reg?: RpcHandlerRegistry, _opts?: RpcChannelOpts);
    get opts(): Readonly<NonNullable<RpcChannelOpts>>;
    get state(): RpcState;
    resetTimeout(): void;
    sendKeepAlive(): void;
    resetKeepAlive(): void;
    setTimeout(timeout?: number, keep_alive_interval?: number): void;
    setAwaitFirstMsg(should: boolean): void;
    _stateChange(state: RpcState): void;
    start(): Promise<void>;
    close(send?: boolean): void;
    stop: () => void;
    register(address: WildcardMultistringAddress, func: RpcFunction): void;
    unregister(address: WildcardMultistringAddress): void;
    registerAll(obj: BaseRegisteredObject): void;
    unregisterAll(obj: BaseRegisteredObject): void;
    can(addr: MultistringAddress, opts: CanCallOpts): OptAccessPolicy;
    /**
     * Sends data to a particular handle. Because there is no `await` for the
     * other side to process this, the `send` function should be used for pushing
     * data only since multiple messages may be sent before the other side gets
     * around to processing them.
     * @param to Address to send data to
     * @param args Data to send
     * @param return_addr The address of the return field. This is used for full
     * transactions, such as function calls
     */
    send(to: MultistringAddress, args?: SerializableData[], return_addr?: MultistringAddress, return_type?: 'promise' | 'generator'): void;
    /**
     * Calls a handle and awaits the return value.
     * @param to Handle to call
     * @param args Arguments to pass through
     * @returns A promise that will return when the call is completed. This will
     * throw an error with the message `Channel closed` if the channel is closed
     * before a response is received.
     */
    call(to: MultistringAddress, args?: SerializableData[]): Promise<SerializedData>;
    /**
     * Returns an async generator. This supports only `yield`ing values: ATM,
     * returned values and `yield`ed arguments are not supported. **You also must
     * manually deallocate the generator once you're done!** Yes, manual memory
     * management. If you don't manually deallocate, the listeners on both ends
     * will remain allocated leading to memory leaks. To deallocate, call the
     * `return` or `throw` functions on the generator.
     */
    generate(to: MultistringAddress, args?: SerializableData[]): AsyncGenerator<SerializedData, void, void>;
    get call_obj(): RpcAccessor;
    /**
     * Call this when a new message is recieved to process it.
     * @param val Incoming message
     */
    receive(val: RpcMessage): void;
}
export {};
