syncable-server
Version:
Syncable server.
68 lines (67 loc) • 3.72 kB
TypeScript
/// <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;
}