/// <reference types="socket.io" />
/// <reference types="node" />
import { EventEmitter } from 'events';
import { BroadcastChange, Change, ClientBroadcastChangeData, GeneralChange, QueuedBroadcastChange, Removal, Request, SnapshotsData, Subscription, Syncable } from 'syncable';
import { SyncableDefinition } from './definition';
import { ObjectQueue } from './object-queue';
export interface ResourceLock {
    release(): PromiseLike<void>;
}
export declare type Visibility = boolean | 'upon-request';
export interface SubscriptionInfo<TClientSession> {
    subscription: Subscription;
    changeEmitter: ObjectQueue<ClientBroadcastChangeData<BroadcastChange, TClientSession>>;
    visibleSet: Set<string>;
    valid: boolean;
}
export interface QueuedBroadcastChangeData<TSession> {
    change: QueuedBroadcastChange;
    session: TSession;
}
export interface Socket<TClientSession> extends SocketIO.Socket {
    subjectToSubscriptionInfoMap: Map<string, SubscriptionInfo<TClientSession>>;
    on(event: 'change', listener: (change: Change) => void): this;
    on(event: 'subscribe', listener: (subscription: Subscription) => void): this;
    on(event: 'request', listener: (request: Request) => void): this;
    on(event: 'close', listener: () => void): this;
    emit(event: 'subscribed', data: Subscription): boolean;
    emit(event: 'change', data: ClientBroadcastChangeData<BroadcastChange, TClientSession>): boolean;
    emit(event: 'snapshots', data: SnapshotsData): boolean;
}
export interface SocketServer<TClientSession> extends SocketIO.Server {
    on(event: 'connection' | 'connect', listener: (socket: Socket<TClientSession>) => void): SocketIO.Namespace;
}
export declare class ChangeEmitter<TClientSession> extends ObjectQueue<ClientBroadcastChangeData<BroadcastChange, TClientSession>> {
    private socket;
    constructor(socket: Socket<TClientSession>);
    protected emit(object: ClientBroadcastChangeData<BroadcastChange, TClientSession>): void;
    protected resolveChannel({change: {subject}}: ClientBroadcastChangeData<BroadcastChange, TClientSession>): string;
}
export declare abstract class Server<TSession, TClientSession> extends EventEmitter {
    private socketServer;
    private errorEmitter;
    private subjectToDefinitionMap;
    private subjectToSocketSetMap;
    constructor(socketServer: SocketServer<TClientSession>);
    register(subject: string, definition: SyncableDefinition<Syncable, Subscription, TSession, TClientSession, this>): void;
    spawnChange<T extends GeneralChange, U extends Syncable = Syncable>(change: T, session: TSession): Promise<U>;
    spawnChange(removal: Removal, session: TSession): Promise<void>;
    protected abstract getSession(socket: Socket<TClientSession>): TSession;
    protected abstract resolveClientSession(session: TSession): TClientSession;
    protected abstract lock(resource: string, ttl: number): Promise<ResourceLock>;
    protected abstract generateTimestamp(): Promise<number>;
    protected abstract queueChange(change: BroadcastChange, session: TSession): Promise<void>;
    private initChangeQueueListener();
    private initSocketServer();
    private initSubscription(info, socket);
    private loadAndEmitSnapshots(info, socket);
    private loadAndEmitUponRequest(request, socket);
    private loadAndEmitChanges(info, socket);
    private handleChangeFromQueue(change, session);
}
export interface Server<TSession, TClientSession> {
    on(event: 'change', listener: (data: QueuedBroadcastChangeData<TSession>) => void): this;
    on(event: 'error', listener: (error: any) => void): this;
    emit(event: 'change', data: QueuedBroadcastChangeData<TSession>): boolean;
    emit(event: 'error', error: any): boolean;
}
