Merge pull request #30944 from DanielRose/socketcluster

Adds type definitions for packages: sc-auth, socketcluster, socketclu…
This commit is contained in:
Andrew Casey
2018-12-05 10:38:53 -08:00
committed by GitHub
45 changed files with 2004 additions and 0 deletions
@@ -0,0 +1,19 @@
import { ExpiryManager } from "expirymanager";
const expiryManager = new ExpiryManager();
const keys = ['1', '2'];
expiryManager.expire(keys, 1);
expiryManager.unexpire(keys);
const expiry: number = expiryManager.getExpiry(keys[0]);
let expiredKeys = expiryManager.getExpiredKeys();
expiredKeys = expiryManager.getExpiredKeys(expiryManager.now());
expiredKeys = expiryManager.extractExpiredKeys();
expiredKeys = expiryManager.extractExpiredKeys(expiryManager.now());
expiryManager.clear();
+25
View File
@@ -0,0 +1,25 @@
// Type definitions for expirymanager 0.9
// Project: https://github.com/SocketCluster/expirymanager
// Definitions by: Daniel Rose <https://github.com/DanielRose>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
export type Key = any;
export type Keys = Key[];
export class ExpiryManager {
constructor();
now(): number;
expire(keys: Keys, seconds: number): void;
unexpire(keys: Keys): void;
getExpiry(key: Key): number;
getKeysByExpiry(expiry: number): Keys;
getExpiredKeys(time?: number): Keys;
extractExpiredKeys(time?: number): Keys;
clear(): void;
}
+23
View File
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"expirymanager-tests.ts"
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"extends": "dtslint/dt.json"
}
+27
View File
@@ -0,0 +1,27 @@
import { FlexiMap } from "fleximap";
let flexiMap = new FlexiMap();
flexiMap = new FlexiMap({ arr: [] });
flexiMap = new FlexiMap([{ arr: [] }, { obj: {} }]);
flexiMap.set('keyA', {arr: [], obj: {}});
let result = flexiMap.get(['keyA', 'arr']);
flexiMap.add(['keyB1', 'keyB2', 'keyB3'], 123);
result = flexiMap.get(['keyB1', 'keyB2']);
const arr = [];
arr[5] = 'Hello world';
flexiMap.set(['keyC1', 'keyC2'], arr);
result = flexiMap.get(['keyC1', 'keyC2']);
flexiMap.set(['itemsA', 0], 'hello');
flexiMap.set(['itemsA', 2], 'world');
flexiMap.remove(['itemsA', 0]);
flexiMap.set(['itemsB', 0], 'a');
flexiMap.set(['itemsB', 1], 'b');
flexiMap.set(['itemsB', 2], 'c');
let splicedItems = flexiMap.splice(['itemsB'], 1, 1);
splicedItems = flexiMap.splice(['itemsB'], 1, 0, 'b2');
+38
View File
@@ -0,0 +1,38 @@
// Type definitions for fleximap 0.9
// Project: https://github.com/SocketCluster/fleximap
// Definitions by: Daniel Rose <https://github.com/DanielRose>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.4
export type KeyChain = any;
export class FlexiMap {
constructor(object?: any[] | object);
get(keyChain: KeyChain): any;
getRange(keyChain: KeyChain, fromIndex: number, toIndex: number): any;
getRaw(keyChain: KeyChain): any;
getAll(): any[] | object;
count(keyChain: KeyChain): number;
hasImmediateKey(key: string): boolean;
hasKey(keyChain: KeyChain): boolean;
hasType(keyChain: KeyChain, type: any): boolean;
hasValue(keyChain: KeyChain, value: any): boolean;
hasObject(keyChain: KeyChain, object: object): boolean;
set(keyChain: KeyChain, value: any): any;
add(keyChain: KeyChain, value: any): number;
concat(keyChain: KeyChain, value: any): any;
remove(keyChain: KeyChain): any;
removeRange(keyChain: KeyChain, fromIndex: number, toIndex: number): any[];
removeAll(): void;
splice(keyChain: KeyChain, index: number, count: number, ...items: any[]): any[];
pop(keyChain: KeyChain): any[];
}
+23
View File
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"fleximap-tests.ts"
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"extends": "dtslint/dt.json"
}
+19
View File
@@ -0,0 +1,19 @@
// Type definitions for sc-auth 5.0
// Project: https://github.com/SocketCluster/sc-auth
// Definitions by: Daniel Rose <https://github.com/DanielRose>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.2
import { VerifyOptions, VerifyCallback, Secret, SignCallback, SignOptions } from "jsonwebtoken";
export interface SCAuthEngine {
verifyToken(signedToken: string, key: string | Buffer, options?: VerifyOptions, callback?: VerifyCallback): void;
signToken(token: string | object | Buffer, key: Secret, options?: SignOptions, callback?: SignCallback): void;
}
export class AuthEngine implements SCAuthEngine {
constructor();
verifyToken(signedToken: string, key: string | Buffer, options?: VerifyOptions, callback?: VerifyCallback): void;
signToken(token: string | object | Buffer, key: Secret, options?: SignOptions, callback?: SignCallback): void;
}
+102
View File
@@ -0,0 +1,102 @@
/**
* This mostly delegates to jwt, so using its tests as base
*/
import scAuth = require("sc-auth");
import fs = require("fs");
let signedToken = "";
let cert: Buffer;
interface TestObject {
foo: string;
}
const testObject = { foo: "bar" };
const authEngine = new scAuth.AuthEngine();
// sign with default (HMAC SHA256)
authEngine.signToken(testObject, "shhhhh");
// sign with default (HMAC SHA256) and single audience
authEngine.signToken(testObject, "shhhhh", { audience: "theAudience" });
// sign with default (HMAC SHA256) and multiple audiences
authEngine.signToken(testObject, "shhhhh", {
audience: ["audience1", "audience2"]
});
// sign with default (HMAC SHA256) and a keyid
authEngine.signToken(testObject, "shhhhh", { keyid: "theKeyId" });
// sign with RSA SHA256
cert = fs.readFileSync("private.key"); // get private key
authEngine.signToken(testObject, cert, { algorithm: "RS256" });
// sign with encrypted RSA SHA256 private key (only PEM encoding is supported)
const privKey: Buffer = fs.readFileSync("encrypted_private.key"); // get private key
const secret = { key: privKey.toString(), passphrase: "keypwd" };
authEngine.signToken(testObject, secret, { algorithm: "RS256" }); // the algorithm option is mandatory in this case
// sign asynchronously
authEngine.signToken(testObject, cert, { algorithm: "RS256" }, (err, token) => {
signedToken = token;
});
// verify a token symmetric
authEngine.verifyToken(signedToken, "shhhhh", {}, (err, decoded) => {
const result = decoded as TestObject;
console.log(result.foo); // bar
});
// use external time for verifying
authEngine.verifyToken(signedToken, "shhhhh", { clockTimestamp: 1 }, (err, decoded) => {
const result = decoded as TestObject;
console.log(result.foo); // bar
});
// invalid token
authEngine.verifyToken(signedToken, "wrong-secret", {}, (err, decoded) => {
console.log(err);
// decoded undefined
});
// verify a token asymmetric
cert = fs.readFileSync("public.pem"); // get public key
authEngine.verifyToken(signedToken, cert, {}, (err, decoded) => {
const result = decoded as TestObject;
console.log(result.foo); // bar
});
// verify audience
cert = fs.readFileSync("public.pem"); // get public key
authEngine.verifyToken(signedToken, cert, { audience: "urn:foo" }, (err, decoded) => {
// if audience mismatch, err == invalid audience
console.log(err);
});
// verify issuer
cert = fs.readFileSync("public.pem"); // get public key
authEngine.verifyToken(signedToken, cert, { audience: "urn:foo", issuer: "urn:issuer" }, (err, decoded) => {
// if issuer mismatch, err == invalid issuer
console.log(err);
});
// verify algorithm
cert = fs.readFileSync("public.pem"); // get public key
authEngine.verifyToken(signedToken, cert, { algorithms: ["RS256"] }, (err, decoded) => {
// if algorithm mismatch, err == invalid algorithm
console.log(err);
});
// verify without expiration check
cert = fs.readFileSync("public.pem"); // get public key
authEngine.verifyToken(signedToken, cert, { ignoreExpiration: true }, (err, decoded) => {
// if ignoreExpration == false and token is expired, err == expired token
console.log(err);
});
+23
View File
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"sc-auth-tests.ts"
]
}
+1
View File
@@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }
+10
View File
@@ -0,0 +1,10 @@
import { EventEmitter } from "events";
import { SCBrokerClient } from "sc-broker";
import { mapperFunction } from ".";
export class ClientCluster extends EventEmitter {
constructor(clients: SCBrokerClient[]);
setMapper(mapper: mapperFunction): void;
getMapper(): mapperFunction;
}
+160
View File
@@ -0,0 +1,160 @@
// Type definitions for sc-broker-cluster 6.1
// Project: https://github.com/SocketCluster/sc-broker-cluster
// Definitions by: Daniel Rose <https://github.com/DanielRose>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.4
import { SCServerSocket, SCServer } from "socketcluster-server";
import { BrokerStartInfo, BrokerExitInfo } from "socketcluster";
import { SpliceOptions, QueryOptions } from "sc-broker";
import { SCChannel } from "sc-channel";
import { EventEmitter } from "events";
import { AsyncResultArrayCallback } from "async";
import { KeyChain, FlexiMap } from "fleximap";
import { Keys } from "expirymanager";
import { ClientCluster } from "./clientcluster";
export class AbstractDataClient extends EventEmitter {
constructor(dataClient: ClientCluster);
set(keyChain: KeyChain, value: any, getValue?: boolean, callback?: (err?: Error) => void): void;
set(keyChain: KeyChain, value: any, callback?: (err?: Error) => void): void;
expire(keys: Keys, seconds: number, callback?: (err?: Error) => void): void;
unexpire(keys: Keys, callback?: (err?: Error) => void): void;
add(keyChain: KeyChain, value: any, getValue?: boolean, callback?: (err?: Error) => void): void;
add(keyChain: KeyChain, value: any, callback?: (err?: Error) => void): void;
get(keyChain: KeyChain, callback: (err: Error | null, value: any) => void): void;
getRange(keyChain: KeyChain, fromIndex: number, toIndex: number, callback: (err: Error | null, value: any) => void): void;
getRange(keyChain: KeyChain, fromIndex: number, callback: (err: Error | null, value: any) => void): void;
getAll(callback: (err: Error | null, value: any[] | object) => void): void;
count(keyChain: KeyChain, callback: (err: Error | null, value: number) => void): void;
remove(keyChain: KeyChain, getValue?: boolean, callback?: (err?: Error) => void): void;
remove(keyChain: KeyChain, callback?: (err?: Error) => void): void;
removeRange(keyChain: KeyChain, fromIndex: number, toIndex?: number, getValue?: boolean, callback?: (err?: Error) => void): void;
removeRange(keyChain: KeyChain, fromIndex: number, toIndex?: number, callback?: (err?: Error) => void): void;
removeRange(keyChain: KeyChain, fromIndex: number, callback?: (err?: Error) => void): void;
removeAll(callback?: (err: Error) => void): void;
splice(keyChain: KeyChain, options?: SpliceOptions, callback?: (err?: Error) => void): void;
splice(keyChain: KeyChain, callback?: (err?: Error) => void): void;
pop(keyChain: KeyChain, callback: (err: Error | null, data: any) => void): void;
hasKey(keyChain: KeyChain, callback: (err: Error | null, data: boolean) => void): void;
extractKeys(keyChain: KeyChain): string[];
extractValues(keyChain: KeyChain): any[];
exec(query: (datamap: FlexiMap) => void, options?: QueryOptions, callback?: (err: Error | null, data: any) => void): void;
exec(query: (datamap: FlexiMap) => void, callback: (err: Error | null, data: any) => void): void;
}
export type handlerFunction = (data: any) => void;
export type mapperFunction = (keyChain: KeyChain, method: string, clientIds: number[]) => number | number[];
/**
* The exchange object is a top-level SCBrokerClient which lets you publish events and manipulate data within your brokers - It represents a cluster of 1 or more brokers.
*/
export class SCExchange extends AbstractDataClient {
constructor(privateClientCluster: ClientCluster, publicClientCluster: ClientCluster, ioClusterClient: Client);
send(data: any, mapIndex: number | string | string[] | null, callback?: (err?: Error) => void): void;
publish(channelName: string, data: any, callback: (err?: Error) => void): void;
subscribe(channelName: string): SCChannel;
unsubscribe(channelName: string): void;
channel(channelName: string): SCChannel;
destroyChannel(channelName: string): void;
subscriptions(includePending?: boolean): string[];
isSubscribed(channelName: string, includePending?: boolean): boolean;
watch(channelName: string, handler: handlerFunction): void;
unwatch(channelName: string, handler?: handlerFunction): void;
watchers(channelName: string): handlerFunction[];
setMapper(mapper: mapperFunction): void;
getMapper(): mapperFunction;
map(keyChain: KeyChain, method: string): { type: string; targets: Client[] };
destroy(): void;
}
export interface SCBrokerClusterServerOptions {
brokers: string[];
debug?: boolean;
inspect?: boolean;
instanceId?: string;
secretKey?: string;
expiryAccuracy?: number;
downgradeToUser: number | string;
appBrokerControllerPath?: string;
processTermTimeout?: number;
ipcAckTimeout?: number;
brokerOptions?: SCServer.SCServerOptions;
}
export class Server extends EventEmitter {
constructor(options: SCBrokerClusterServerOptions);
on(event: "brokerStart", listener: (brokerInfo: BrokerStartInfo) => void): this;
on(event: "brokerExit", listener: (brokerInfo: BrokerExitInfo) => void): this;
on(event: "brokerMessage", listener: (brokerId: string, data: any, callback: (err: Error | null, data: any) => void) => void): this;
on(event: "ready", listener: () => void): this;
on(event: "error", listener: (err?: Error) => void): this;
sendToBroker(brokerId: string, data: any, callback: (err: Error | null, data: any) => void): void;
killBrokers(): void;
destroy(): void;
}
export interface SCBrokerClusterClientOptions {
brokers: string[];
secretKey?: string;
pubSubBatchDuration?: number;
connectRetryErrorThreshold: number;
}
export interface MessagePacket {
channel: string;
data: any;
}
export class Client extends EventEmitter {
constructor(options: SCBrokerClusterClientOptions);
exchange(): SCExchange;
options: SCBrokerClusterClientOptions;
on(event: "error", listener: (err?: Error) => void): this;
on(event: "warning", listener: (warning?: Error) => void): this;
on(event: "ready", listener: () => void): this;
on(event: "message", listener: (packet: MessagePacket) => void): this;
destroy(callback: AsyncResultArrayCallback<SCExchange>): void;
subscribe(channel: string, callback: (err?: Error) => void): void;
unsubscribe(channel: string, callback: () => void): void;
unsubscribeAll(callback: () => void): void;
isSubscribed(channel: string, includePending: boolean): boolean;
subscribeSocket(socket: SCServerSocket, channel: string, callback?: (err?: Error) => void): void;
unsubscribeSocket(socket: SCServerSocket, channel: string, callback?: () => void): void;
setSCServer(scServer: SCServer): void;
}
@@ -0,0 +1,29 @@
import { Client } from "sc-broker-cluster";
import { SCServer, SCServerSocket } from "socketcluster-server";
import WebSocket = require("ws");
const client = new Client({
brokers: [],
secretKey: "secretKey",
pubSubBatchDuration: 100,
connectRetryErrorThreshold: 5
});
client.on("error", err => {});
client.on("warning", err => {});
const exchange = client.exchange();
const scServer = new SCServer();
client.setSCServer(scServer);
client.once("ready", () => {});
const wsSocket = new WebSocket("address");
const socket = new SCServerSocket("id", scServer, wsSocket);
client.subscribeSocket(socket, "channelName", err => {});
client.unsubscribeSocket(socket, "channelName");
const data: any = {};
exchange.publish("channelName", data, err => {});
+3
View File
@@ -0,0 +1,3 @@
import SCBroker = require("sc-broker/scbroker");
export = SCBroker;
+25
View File
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"clientcluster.d.ts",
"scbroker.d.ts",
"sc-broker-cluster-tests.ts"
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"extends": "dtslint/dt.json"
}
+165
View File
@@ -0,0 +1,165 @@
// Type definitions for sc-broker 5.1
// Project: https://github.com/SocketCluster/sc-broker
// Definitions by: Daniel Rose <https://github.com/DanielRose>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.4
import { SCServer } from "socketcluster-server";
import { WorkerExitInfo } from "socketcluster";
import { EventEmitter } from "events";
import { KeyChain, FlexiMap } from "fleximap";
import { Keys, Key } from "expirymanager";
export interface SCBrokerServerOptions {
id?: string;
instanceId?: string;
debug?: boolean;
inspect?: boolean;
socketPath?: string;
port?: number;
expiryAccuracy?: number;
downgradeToUser: number | string;
brokerControllerPath?: string;
processTermTimeout?: number;
ipcAckTimeout?: number;
secretKey?: string;
brokerOptions?: SCServer.SCServerOptions;
}
export interface SCBrokerServer extends EventEmitter {
options: SCBrokerServerOptions;
socketPath?: string;
port?: number;
ipcAckTimeout: number;
on(event: "error", listener: (err?: Error) => void): this;
on(event: "brokerMessage", listener: (brokerId: string, data: any, callback: (err: Error | null, data: any) => void) => void): this;
on(event: "ready", listener: (data: any) => void): this;
on(event: "exit", listener: (data: WorkerExitInfo) => void): this;
sendToBroker(data: any, callback?: (err: Error | null, data: any, brokerId: string) => void): void;
}
export function createServer(options?: SCBrokerServerOptions): SCBrokerServer;
export interface AutoReconnectOptions {
initialDelay?: number;
randomness?: number;
multiplier?: number;
maxDelay?: number;
}
export interface SCBrokerClientOptions {
secretKey?: string;
timeout?: number;
socketPath?: string;
port?: number;
host?: string;
autoReconnect?: boolean;
autoReconnectOptions?: AutoReconnectOptions;
connectRetryErrorThreshold?: number;
pubSubBatchDuration?: number;
}
export interface QueryOptions {
baseKey?: KeyChain;
noAck?: boolean;
data?: any;
}
export interface SpliceOptions {
index?: number;
count?: number;
items?: any[];
getValue?: boolean;
noAck?: boolean;
}
export interface SCBrokerClient extends EventEmitter {
readonly CONNECTED: "connected";
readonly CONNECTING: "connecting";
readonly DISCONNECTED: "disconnected";
socketPath?: string;
port?: number;
host?: string;
autoReconnect: boolean;
autoReconnectOptions?: AutoReconnectOptions;
connectRetryErrorThreshold: number;
state: "connected" | "connecting" | "disconnected";
connectAttempts: number;
pendingReconnect: boolean;
pendingReconnectTimeout: number | null;
on(event: "error", listener: (err?: Error) => void): this;
on(event: "warning", listener: (warning?: Error) => void): this;
on(event: "ready", listener: (data: any) => void): this;
on(event: "message", listener: (channel: string, data: any) => void): this;
on(event: "subscribeFail", listener: (err: Error | null, channel: string) => void): this;
on(event: "subscribe", listener: (channel: string) => void): this;
on(event: "unsubscribe", listener: () => void): this;
isConnected(): boolean;
subscribe(channel: string, ackCallback: (err?: Error) => void, force?: boolean): void;
unsubscribe(channel: string, ackCallback: (err?: Error) => void): void;
subscriptions(includePending?: boolean): string[];
isSubscribed(channel: string, includePending?: boolean): boolean;
publish(channel: string, data: any, callback: (err?: Error) => void): void;
send(data: any, callback: (err?: Error) => void): void;
set(keyChain: KeyChain, value: any, getValue?: boolean, callback?: (err?: Error) => void): void;
set(keyChain: KeyChain, value: any, callback?: (err?: Error) => void): void;
expire(keys: Keys, seconds: number, callback?: (err?: Error) => void): void;
unexpire(keys: Keys, callback?: (err?: Error) => void): void;
getExpiry(key: Key, callback?: (err?: Error) => void): number;
add(keyChain: KeyChain, value: any, getValue?: boolean, callback?: (err?: Error) => void): void;
add(keyChain: KeyChain, value: any, callback?: (err?: Error) => void): void;
concat(keyChain: KeyChain, value: any, getValue?: boolean, callback?: (err?: Error) => void): void;
concat(keyChain: KeyChain, value: any, callback?: (err?: Error) => void): void;
get(keyChain: KeyChain, callback: (err: Error | null, value: any) => void): void;
getRange(keyChain: KeyChain, fromIndex: number, toIndex: number, callback: (err: Error | null, value: any) => void): void;
getRange(keyChain: KeyChain, fromIndex: number, callback: (err: Error | null, value: any) => void): void;
getAll(callback: (err: Error | null, value: any[] | object) => void): void;
count(keyChain: KeyChain, callback: (err: Error | null, value: number) => void): void;
exec(query: (datamap: FlexiMap) => void, options?: QueryOptions, callback?: (err: Error | null, data: any) => void): void;
exec(query: (datamap: FlexiMap) => void, callback: (err: Error | null, data: any) => void): void;
query(query: (datamap: FlexiMap) => void, data?: any, callback?: (err: Error | null, data: any) => void): void;
query(query: (datamap: FlexiMap) => void, callback: (err: Error | null, data: any) => void): void;
remove(keyChain: KeyChain, getValue?: boolean, callback?: (err?: Error) => void): void;
remove(keyChain: KeyChain, callback?: (err?: Error) => void): void;
removeRange(keyChain: KeyChain, fromIndex: number, toIndex?: number, getValue?: boolean, callback?: (err?: Error) => void): void;
removeRange(keyChain: KeyChain, fromIndex: number, toIndex?: number, callback?: (err?: Error) => void): void;
removeRange(keyChain: KeyChain, fromIndex: number, callback?: (err?: Error) => void): void;
removeAll(callback?: (err: Error) => void): void;
splice(keyChain: KeyChain, options?: SpliceOptions, callback?: (err?: Error) => void): void;
splice(keyChain: KeyChain, callback?: (err?: Error) => void): void;
pop(keyChain: KeyChain, callback: (err: Error | null, data: any) => void): void;
hasKey(keyChain: KeyChain, callback: (err: Error | null, data: boolean) => void): void;
extractKeys(keyChain: KeyChain): string[];
extractValues(keyChain: KeyChain): any[];
end(callback: (err?: Error) => void): void;
}
export function createClient(options?: SCBrokerClientOptions): SCBrokerClient;
+58
View File
@@ -0,0 +1,58 @@
import { SCServer, SCServerSocket } from "socketcluster-server";
import SCBroker = require("sc-broker/scbroker");
import { FlexiMap } from "fleximap";
import { ExpiryManager } from "expirymanager";
////////////////////////////////////////////////////
/// SCBroker tests
////////////////////////////////////////////////////
const options: SCServer.SCServerOptions = { port: 80 };
let scBroker = new SCBroker();
scBroker = new SCBroker(options);
scBroker.options = { environment: "prod" };
const id: number = scBroker.id;
const instanceId: number = scBroker.instanceId;
const dataMap: FlexiMap = scBroker.dataMap;
const dataExpirer: ExpiryManager = scBroker.dataExpirer;
const subscriptions = scBroker.subscriptions;
const socket: SCServerSocket = subscriptions[1]["test"];
scBroker.on("subscribe", channel => {
const subscribeChannel: string = channel;
});
scBroker.on("unsubscribe", channel => {
const unsubscribeChannel: string = channel;
});
scBroker.on("publish", (channel, data) => {
const publishChannel: string = channel;
const publishData: any = data;
});
scBroker.on("masterMessage", (data, masterMessageResponse) => {
const masterMessageData: any = data;
masterMessageResponse(null, "test");
masterMessageResponse(new Error(), null);
});
scBroker.publish("testChannel", 123);
scBroker.exec(dataMap => {
dataMap.set(["main", "message"], "Message");
return dataMap.get(["main"]);
});
scBroker.sendToMaster("data");
scBroker.sendToMaster(123, (err, response) => {
if (!err) {
const answer = response;
}
});
class MyBroker extends SCBroker {
run() {
this.on("subscribe", channel => {});
}
}
+32
View File
@@ -0,0 +1,32 @@
import { EventEmitter } from "events";
import { SCServer, SCServerSocket } from "socketcluster-server";
import { FlexiMap, KeyChain } from "fleximap";
import { ExpiryManager } from "expirymanager";
export = SCBroker;
interface Subscriptions {
[socketId: number]: {
[channel: string]: SCServerSocket;
};
}
declare class SCBroker extends EventEmitter {
id: number;
options: SCServer.SCServerOptions;
instanceId: number;
dataMap: FlexiMap;
dataExpirer: ExpiryManager;
subscriptions: Subscriptions;
constructor(options?: SCServer.SCServerOptions);
on(event: "subscribe" | "unsubscribe", listener: (channel: string) => void): this;
on(event: "publish", listener: (channel: string, data: any) => void): this;
on(event: "masterMessage", listener: (data: any, respond: (err: Error | null, responseData: any) => void) => void): this;
publish(channel: string, message: any): void;
run(): void;
exec(query: (dataMap: FlexiMap, dataExpirer: ExpiryManager, subscriptions: Subscriptions) => any, baseKey?: KeyChain): any;
sendToMaster(data: any, callback?: (err: Error | null, responseData: any) => void): void;
}
+24
View File
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"scbroker.d.ts",
"sc-broker-tests.ts"
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"extends": "dtslint/dt.json"
}
+45
View File
@@ -0,0 +1,45 @@
// Type definitions for sc-channel 1.2
// Project: https://github.com/SocketCluster/sc-channel
// Definitions by: Daniel Rose <https://github.com/DanielRose>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.4
import Emitter = require("component-emitter");
import { SCExchange, handlerFunction } from "sc-broker-cluster";
export interface SCChannelOptions {
waitForAuth?: boolean;
batch?: boolean;
data?: any;
}
export class SCChannel extends Emitter {
readonly PENDING: "pending";
readonly SUBSCRIBED: "subscribed";
readonly UNSUBSCRIBED: "unsubscribed";
name: string;
state: ChannelState;
waitForAuth: boolean;
batch: boolean;
data: any;
constructor(name: string, client: SCExchange, options?: SCChannelOptions);
setOptions(options?: SCChannelOptions): void;
getState(): "pending" | "subscribed" | "unsubscribed";
subscribe(options?: any): void;
unsubscribe(): void;
isSubscribed(includePending?: boolean): boolean;
publish(data: any, callback?: (err?: Error) => void): void;
watch(handler: handlerFunction): void;
unwatch(handler?: handlerFunction): void;
watchers(): handlerFunction[];
destroy(): void;
}
export type ChannelState = "pending" | "subscribed" | "unsubscribed";
+33
View File
@@ -0,0 +1,33 @@
import { SCChannel, SCChannelOptions } from "sc-channel";
import { handlerFunction, Client, SCBrokerClusterClientOptions } from "sc-broker-cluster";
const clientOptions: SCBrokerClusterClientOptions = { brokers: [], connectRetryErrorThreshold: 0 };
const client = new Client(clientOptions);
let channel = new SCChannel("channelName", client.exchange());
const channelOptions: SCChannelOptions = {};
channel = new SCChannel("channelName", client.exchange(), channelOptions);
channel.state = channel.PENDING;
channel.state = channel.SUBSCRIBED;
channel.state = channel.UNSUBSCRIBED;
const channelName: string = channel.name;
const handler: handlerFunction = () => { };
channel.watch(handler);
channel.unwatch();
channel.subscribe();
channel.subscribe(channelOptions);
channel.unsubscribe();
const data: any = channel.data;
channel.emit("subscribe", channelName);
channel.emit("unsubscribe", channelName);
channel.setOptions(channelOptions);
channel.publish(data);
+23
View File
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"sc-channel-tests.ts"
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"extends": "dtslint/dt.json"
}
+23
View File
@@ -0,0 +1,23 @@
// Type definitions for socketcluster-client 13.0
// Project: https://github.com/SocketCluster/socketcluster-client
// Definitions by: Daniel Rose <https://github.com/DanielRose>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.4
import { SCAuthEngine } from "sc-auth";
import { SCServer } from "socketcluster-server";
export import SCClientSocket = require("./lib/scclientsocket");
export function create(options?: SCClientSocket.ClientOptions): SCClientSocket;
/** @deprecated */
export function connect(options?: SCClientSocket.ClientOptions): SCClientSocket;
export function destroy(socket: SCClientSocket): void;
export const clients: {
[id: string]: SCClientSocket;
};
export const version: string;
+251
View File
@@ -0,0 +1,251 @@
import Emitter = require("component-emitter");
import { SCServer } from "socketcluster-server";
import { SCAuthEngine } from "sc-auth";
import { SCChannel, SCChannelOptions, ChannelState } from "sc-channel";
import WebSocket = require("ws");
declare class SCClientSocket extends Emitter {
constructor(opts: SCClientSocket.ClientOptions);
id: string;
channels: {
[channelName: string]: SCChannel;
};
CONNECTING: "connecting";
OPEN: "open";
CLOSED: "closed";
state: SCClientSocket.States;
getState(): SCClientSocket.States;
AUTHENTICATED: "authenticated";
UNAUTHENTICATED: "unauthenticated";
authState: SCClientSocket.AuthStates;
PENDING: "pending";
pendingReconnect: boolean;
pendingReconnectTimeout: number;
getBytesReceived(): number;
deauthenticate(callback?: (err: Error) => void): void;
connect(): void;
open(): void;
disconnect(code?: number, data?: string | object): void;
reconnect(code?: number, data?: string | object): void;
destroy(code?: number, data?: string | object): void;
decodeBase64(encodedString: string): string;
encodeBase64(decodedString: string): string;
getAuthToken(): object | null;
authToken: object | null;
getSignedAuthToken(): string | null;
signedAuthToken: string | null;
// Perform client-initiated authentication by providing an encrypted token string.
authenticate(signedAuthToken: string, callback?: (err: Error, authStatus: SCClientSocket.AuthStatus) => void): void;
decode(message: any): any;
encode(object: any): any;
send(data: any): void;
emit(event: string, data: any, callback?: (err: Error, responseData: any) => void): void;
publish(channelName: string, data: any, callback?: (err: Error, ackData: any) => void): void;
subscribe(channelName: string, options?: SCChannelOptions): SCChannel;
unsubscribe(channelName: string): void;
channel(channelName: string, options?: SCChannelOptions): SCChannel;
destroyChannel(channelName: string): void;
subscriptions(includePending?: boolean): string[];
isSubscribed(channelName: string, includePending?: boolean): boolean;
processPendingSubscriptions(): void;
watch(channelName: string, handler: SCClientSocket.WatcherFunction): void;
unwatch(channelName: string, handler?: SCClientSocket.WatcherFunction): void;
watchers(channelName: string): SCClientSocket.WatcherFunction[];
on(event: "connecting", listener: () => void): this;
on(event: "connect", listener: (status: SCClientSocket.ConnectStatus, processSubscriptions: () => void) => void): this;
on(event: "connectAbort" | "disconnect" | "close", listener: (code: number, data: string | object) => void): this;
on(event: "kickOut", listener: (message: string, channelName: string) => void): this;
on(event: "authenticate", listener: (signedAuthToken: string | null) => void): this;
on(event: "deauthenticate", listener: (oldSignedToken: string | null) => void): this;
on(event: "authStateChange", listener: (stateChangeData: SCClientSocket.AuthStateChangeData) => void): this;
on(event: "removeAuthToken", listener: (oldToken: object | null) => void): this;
on(event: "subscribe" | "subscribeRequest", listener: (channelName: string, subscriptionOptions: SCChannelOptions) => void): this;
on(event: "subscribeStateChange", listener: (stateChangeData: SCClientSocket.SubscribeStateChangeData) => void): this;
on(event: "subscribeFail", listener: (err: Error, channelName: string, subscriptionOptions: SCChannelOptions) => void): this;
on(event: "unsubscribe", listener: (channelName: string) => void): this;
on(event: "error", listener: (err: Error) => void): this;
on(event: "raw", listener: (data: any) => void): this;
on(event: "message", listener: (message: WebSocket.Data) => void): this;
// Implements Emitter interface
// tslint:disable:ban-types
// tslint:disable:adjacent-overload-signatures
on(event: string, listener: Function): this;
once(event: string, listener: Function): this;
off(event?: string, listener?: Function): this;
emit(event: string, ...args: any[]): boolean;
listeners(event: string): Function[];
hasListeners(event: string): boolean;
// tslint:enable:adjacent-overload-signatures
// tslint:enable:ban-types
}
export = SCClientSocket;
declare namespace SCClientSocket {
interface ClientOptions {
host?: string;
// Defaults to the current host (read from the URL).
hostname?: string;
// Defaults to false.
secure?: boolean;
// Defaults to 80 if !secure otherwise defaults to 443.
port?: number;
// The URL which SC uses to make the initial handshake for the WebSocket. Defaults to '/socketcluster/'.
path?: string;
// A map of key-value pairs which will be used as query parameters for the initial HTTP handshake which will initiate the WebSocket connection.
query?: string | { [key: string]: string };
// (milliseconds) - This is the timeout for getting a response to a SCSocket emit event (when a callback is provided).
ackTimeout?: number;
// (milliseconds)
connectTimeout?: number;
// Whether or not to automatically connect the socket as soon as it is created. Default is true.
autoConnect?: boolean;
// Whether or not to automatically reconnect the socket when it loses the connection.
autoReconnect?: boolean;
// Valid properties are: initialDelay (milliseconds), randomness (milliseconds), multiplier (decimal; default is 1.5) and maxDelay (milliseconds).
autoReconnectOptions?: AutoReconnectOptions;
// Whether or not a client automatically disconnects on page unload. If enabled, the client will disconnect when a user navigates away from the page.
// This can happen when a user closes the tab/window, clicks a link to leave the page, or types a new URL into the address bar. Defaults to true.
disconnectOnUnload?: boolean;
// Turn on/off per-message deflate compression. If this is true, you need to make sure that this property is also set to true on the server-side.
// Note that this option is only relevant when running the client from Node.js. Most modern browsers will automatically use perMessageDeflate so
// you only need to turn it on from the server-side.
perMessageDeflate?: boolean;
// Defaults to true; multiplexing allows you to reuse a socket instead of creating a second socket to the same address.
multiplex?: boolean;
// Defaults to null (0 milliseconds); this property affects channel subscription batching; it determines the period in milliseconds for batching
// multiple subscription requests together. It only affects channels that have the batch option set to true. A value of null or 0 means that all
// subscribe or unsubscribe requests which were made within the same call stack will be batched together. This property was introduced on the
// client-side in SC version 8 (both the client and server versions need to be >= 8.0.0). Note that there is also a separate property with the
// same name which can be configured on the server.
pubSubBatchDuration?: number;
// Whether or not to add a timestamp to the WebSocket handshake request.
timestampRequests?: boolean;
// The query parameter name to use to hold the timestamp.
timestampParam?: string;
// A custom engine to use for storing and loading JWT auth tokens on the client side.
authEngine?: SCAuthEngine | null;
// The name of the JWT auth token (provided to the authEngine - By default this is the localStorage variable name); defaults to 'socketCluster.authToken'.
authTokenName?: string;
// The type to use to represent binary on the client. Defaults to 'arraybuffer'.
binaryType?: string;
// Set this to false during debugging - Otherwise client connection will fail when using self-signed certificates.
rejectUnauthorized?: boolean;
// If you set this to true, any data/objects/arrays that you pass to the client socket will be cloned before being sent/queued up. If the socket
// is disconnected and you emit an event, it will be added to a queue which will be processed upon reconnection. The cloneData option is false
// by default; this means that if you emit/publish an object and that object changes somewhere else in your code before the queue is processed,
// then the changed version of that object will be sent out to the server.
cloneData?: boolean;
// This is true by default. If you set this to false, then the socket will not automatically try to subscribe to pending subscriptions on
// connect - Instead, you will have to manually invoke the processSubscriptions callback from inside the 'connect' event handler on the client side.
// See SCSocket Client API. This gives you more fine-grained control with regards to when pending subscriptions are processed after the socket
// connection is established (or re-established).
autoSubscribeOnConnect?: boolean;
// Lets you set a custom codec engine. This allows you to specify how data gets encoded before being sent over the wire and how it gets decoded
// once it reaches the other side. The codecEngine must be an object which exposes an encode(object) and a decode(encodedData) function.
// The encode function can return any data type - Commonly a string or a Buffer/ArrayBuffer. The decode function needs to return a JavaScript
// object which adheres to the SC protocol. The idea of using a custom codec is that it allows you to compress SC packets in any format you like
// (optimized for any use case) - By decoding these packets back into their original protocol form, SC will be able process them appropriately.
// Note that if you provide a codecEngine when creating a client socket see 'codecEngine', you will need to make sure that the server uses the
// same codec by passing the same engine to `worker.scServer.setCodecEngine(codecEngine)` when your SC worker initializes on the server side
// (see 'setCodecEngine' method here). The default codec engine used by SC is here.
codecEngine?: SCServer.SCCodecEngine | null;
// A prefix to add to the channel names.
channelPrefix?: string | null;
subscriptionRetryOptions?: object | null;
}
interface AutoReconnectOptions {
initialDelay?: number;
randomness?: number;
multiplier?: number;
maxDelay?: number;
}
interface AuthStatus {
isAuthenticated: AuthStates;
authError: Error;
}
interface AuthStateChangeData {
oldState: AuthStates;
newState: AuthStates;
}
interface ConnectStatus {
id: string;
pingTimeout: number;
isAuthenticated: boolean;
authToken?: object;
authError?: Error;
}
interface SubscribeStateChangeData {
channel: string;
oldState: ChannelState;
newState: ChannelState;
subscriptionOptions: SCChannelOptions;
}
type WatcherFunction = (data: any) => void;
type AuthStates = "authenticated" | "unauthenticated";
type States = "connecting" | "open" | "closed";
}
@@ -0,0 +1,75 @@
// Adapted from README
import { create, destroy } from "socketcluster-client";
import { ClientOptions } from "socketcluster-client/lib/scclientsocket";
const secureClientOptions: ClientOptions = {
hostname: "securedomain.com",
secure: true,
port: 443,
rejectUnauthorized: false
};
let socket = create(secureClientOptions);
socket.on("connect", () => {
console.log("CONNECTED");
});
// Listen to an event called 'rand' from the server
socket.on("rand", (num: any) => {
console.log("RANDOM: " + num);
});
const options: ClientOptions = {
path: "/socketcluster/",
port: 8000,
hostname: "127.0.0.1",
autoConnect: true,
secure: false,
rejectUnauthorized: false,
connectTimeout: 10000, // milliseconds
ackTimeout: 10000, // milliseconds
channelPrefix: null,
disconnectOnUnload: true,
multiplex: true,
autoReconnectOptions: {
initialDelay: 10000, // milliseconds
randomness: 10000, // milliseconds
multiplier: 1.5, // decimal
maxDelay: 60000 // milliseconds
},
authEngine: null,
codecEngine: null,
subscriptionRetryOptions: {},
query: {
yourparam: "hello"
}
};
socket = create(options);
socket.on("subscribe", channelname => {
console.log("subscribe:" + channelname);
});
socket.on("subscribeFail", channelname => {
console.log("subscribeFail:" + channelname);
});
socket.on("unsubscribe", channelname => {
console.log("unsubscribe:" + channelname);
});
socket.on("subscribeStateChange", data => {
console.log("subscribeStateChange:" + JSON.stringify(data));
});
socket.on("message", data => {
console.log("message:" + data);
});
const channels = socket.channels;
const testChannel = channels["test"];
const state = testChannel.getState();
destroy(socket);
+24
View File
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"lib/scclientsocket.d.ts",
"socketcluster-client-tests.ts"
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"extends": "dtslint/dt.json"
}
+15
View File
@@ -0,0 +1,15 @@
// Type definitions for socketcluster-server 13.1
// Project: https://github.com/SocketCluster/socketcluster-server
// Definitions by: Daniel Rose <https://github.com/DanielRose>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.4
import { Server } from "http";
export import SCServer = require("./scserver");
export import SCServerSocket = require("./scserversocket");
export function listen(port?: number, options?: SCServer.SCServerOptions, listeningListener?: () => void): SCServer;
export function listen(port?: number, listeningListener?: () => void): SCServer;
export function attach(server: Server, options?: SCServer.SCServerOptions): SCServer;
+315
View File
@@ -0,0 +1,315 @@
import { EventEmitter } from "events";
import { Secret } from "jsonwebtoken";
import { ServerOptions } from "https";
import { IncomingMessage, Server } from "http";
import { SCAuthEngine } from "sc-auth";
import { SCExchange } from "sc-broker-cluster";
import WebSocket = require("ws");
import SCServerSocket = require("./scserversocket");
declare class SCServer extends EventEmitter {
readonly MIDDLEWARE_HANDSHAKE_WS: "handshakeWS";
readonly MIDDLEWARE_HANDSHAKE_SC: "handshakeSC";
readonly MIDDLEWARE_AUTHENTICATE: "authenticate";
readonly MIDDLEWARE_SUBSCRIBE: "subscribe";
readonly MIDDLEWARE_PUBLISH_IN: "publishIn";
readonly MIDDLEWARE_PUBLISH_OUT: "publishOut";
readonly MIDDLEWARE_EMIT: "emit";
options: SCServer.SCServerOptions;
exchange: SCExchange;
clients: {
[id: string]: SCServerSocket;
};
clientsCount: number;
pendingClients: {
[id: string]: SCServerSocket;
};
pendingClientsCount: number;
constructor(options?: SCServer.SCServerOptions);
on(event: "connection", listener: SCServer.connectionListenerFunction): this;
addMiddleware(type: "handshakeWS", middlewareFn: (req: IncomingMessage, next: SCServer.nextMiddlewareFunction) => void): void;
addMiddleware(type: "handshakeSC", middlewareFn: (req: SCServer.HandshakeSCRequest, next: SCServer.nextHandshakeSCMiddlewareFunction) => void): void;
addMiddleware(type: "authenticate", middlewareFn: (req: SCServer.AuthenticateRequest, next: SCServer.nextAuthenticateMiddlewareFunction) => void): void;
addMiddleware(type: "subscribe", middlewareFn: (req: SCServer.SubscribeRequest, next: SCServer.nextMiddlewareFunction) => void): void;
addMiddleware(type: "publishIn", middlewareFn: (req: SCServer.PublishInRequest, next: SCServer.nextMiddlewareFunction) => void): void;
addMiddleware(type: "publishOut", middlewareFn: (req: SCServer.PublishOutRequest, next: SCServer.nextMiddlewareFunction) => void): void;
addMiddleware(type: "emit", middlewareFn: (req: SCServer.EmitRequest, next: SCServer.nextMiddlewareFunction) => void): void;
setAuthEngine(authEngine: SCAuthEngine): void;
setCodecEngine(codecEngine: SCServer.SCCodecEngine): void;
}
export = SCServer;
declare namespace SCServer {
interface AuthToken {
[x: string]: any;
}
interface SCServerOptions {
// The port on which to listen for outside connections/requests
port?: number;
// Number of worker processes
workers?: number;
// Number of broker processes
brokers?: number;
// Should be either 'dev' or 'prod' - This affects the shutdown procedure
// when a 'SIGUSR2' signal is received by master. In 'dev', a SIGUSR2 will
// trigger an immediate shutdown of workers. In 'prod' workers will
// be terminated progressively in accordance with processTermTimeout.
environment?: string;
// Setting this to true will cause the master process to shut down when
// it receives a SIGUSR2 signal (instead of just the workers).
// If you're using nodemon, set this to true.
killMasterOnSignal?: boolean;
// A unique name for your app (this is used internally for
// various things such as the directory name in which to store socket
// file descriptors) - If you don't provide an appName, SC will
// generate a random one (UUID v4)
appName?: string;
// This can be the name of an npm module or a path to a Node.js module
// to use as the WebSocket server engine.
// You can now set this to 'sc-uws' for a massive speedup of at least 2x!
wsEngine?: string;
// An ID to associate with this specific instance of SC
// this may be useful if you are running an SC app on multiple
// hosts - You can access the instanceId from the Broker object
// (inside brokerController) - If you don't provide an instanceId,
// SC will generate a random one (UUID v4)
instanceId?: string;
// A key which various SC processes will use to interact with
// scBroker broker processes securely, defaults to a 256 bits
// cryptographically random hex string
secretKey?: string;
// The key which SC will use to encrypt/decrypt authTokens, defaults
// to a 256 bits cryptographically random hex string
// The default JWT algorithm used is 'HS256'.
// If you want to use RSA or ECDSA, you should provide a authPrivateKey
// and authPublicKey instead of authKey.
authKey?: Secret;
// perMessageDeflate compression. Note that this option is passed directly to the wsEngine's
// Server object. So if you're using 'ws' as the engine, you can pass an object instead of
// a boolean. Search for perMessageDeflate here:
// https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback
// Note that by default, per-message deflate only kicks in for messages > 1024 bytes.
perMessageDeflate?: boolean;
// If using an RSA or ECDSA algorithm to sign the authToken, you will need
// to provide an authPrivateKey and authPublicKey in PEM format (string or Buffer).
authPrivateKey?: Secret;
authPublicKey?: Secret;
// The default expiry for auth tokens in seconds
authDefaultExpiry?: number;
// The algorithm to use to sign and verify JWT tokens.
authAlgorithm?: string;
// Crash workers when an error happens - This is the most sensible default
crashWorkerOnError?: boolean;
// Reboot workers when they crash - This is a necessity
// in production but can be turned off for debugging
rebootWorkerOnCrash?: boolean;
// Kill/respawn a worker process if its memory consumption exceeds this
// threshold (in bytes) - If this is null (default), this behavior
// will be switched off
killWorkerMemoryThreshold?: number;
// Can be 'http' or 'https'
protocol?: "http" | "https";
// This is the same as the object provided to Node.js's https server
protocolOptions?: ServerOptions;
// A log level of 3 will log everything, 2 will show notices and errors,
// 1 will only log errors, 0 will log nothing
logLevel?: 0 | 1 | 2 | 3;
// In milliseconds, how long a client has to connect to SC before timing out
connectTimeout?: number;
// In milliseconds - If the socket handshake hasn't been completed before
// this timeout is reached, the new connection attempt will be terminated.
handshakeTimeout?: number;
// In milliseconds, the timeout for calling res(err, data) when
// your emit() call expects an ACK response from the other side
// (when callback is provided to emit)
ackTimeout?: number;
// In milliseconds, the timeout for calling res(err, data) when
// your sendToWorker, sendToBroker or sendToMaster (IPC) call
// expects an ACK response from the other process
// (when callback is provided)
ipcAckTimeout?: number;
// In milliseconds - If the socket cannot upgrade transport
// within this period, it will stop trying
socketUpgradeTimeout?: number;
// Origins which are allowed to connect to the real-time scServer
origins?: string;
// The maximum number of unique channels which a single
// socket can subscribe to
socketChannelLimit?: number;
// The interval in milliseconds on which to
// send a ping to the client to check that
// it is still alive
pingInterval?: number;
// How many milliseconds to wait without receiving a ping
// before closing the socket
pingTimeout?: number;
// Maximum amount of milliseconds to wait before force-killing
// a process after it was passed a 'SIGTERM' or 'SIGUSR2' signal
processTermTimeout?: number;
// Whether or not errors from child processes (workers and brokers)
// should be passed to the current master process
propagateErrors?: boolean;
// Whether or not warnings from child processes (workers and brokers)
// should be passed to the current master process
propagateWarnings?: number;
// Whether or not a 'warning' event should be emitted (and logged to console)
// whenever an action is blocked by a middleware function
middlewareEmitWarnings?: number;
// Lets you specify a host name to bind to - Defaults to
// 127.0.0.1 (localhost)
host?: string;
// The path to a file used to bootstrap worker processes
workerController?: string;
// The path to a file used to bootstrap broker processes
brokerController?: string;
// The path to a file used to bootstrap the workerCluster process
workerClusterController?: string;
// By default, SC will reboot all workers when it receives a 'SIGUSR2' signal -
// This can be used for updating workers with fresh source code in production
rebootOnSignal?: boolean;
// If you run your master process (server.js) as super user, this option
// lets you downgrade worker and broker processes to run under
// the specified user (with fewer permissions than master) - You can provide
// a Linux UID or username
downgradeToUser?: number | string;
// The URL path reserved by SocketCluster clients to interact with the server
path?: string;
// The root directory in which to store your socket files in Linux.
socketRoot?: string;
// Defaults to "rr", but can be set to "none"
schedulingPolicy?: "rr" | "none";
// Whether or not clients are allowed to publish messages to channels
allowClientPublish?: boolean;
// This option is passed to the Node.js HTTP server if provided
tcpSynBacklog?: number;
// SC keeps track of request per minutes internally - This allows you to change
// how often this gets updated
workerStatusInterval?: number;
// This allows you to batch multiple messages together when passing them across
// message brokers. This may improve the efficiency of your pub/sub operations.
// This value is in milliseconds. 5 is generally a safe value to set this to.
pubSubBatchDuration?: number;
// The default clustering/brokering engine (Node.js module name) which provides the
// SCWorker.exchange object and manages brokers behind the scenes.
// You shouldn't need to change this unless you want to build your own
// process clustering engine (which is difficult to do).
brokerEngine?: string;
wsEngineServerOptions?: WebSocket.ClientOptions;
maxPayload?: number;
pingTimeoutDisabled?: boolean;
authSignAsync?: boolean;
authVerifyAsync?: boolean;
httpServer?: Server;
}
interface SCServerSocketStatus {
id: string;
pingTimeout: number;
}
interface HandshakeSCRequest {
socket: SCServerSocket;
}
interface AuthenticateRequest {
socket: SCServerSocket;
authToken: AuthToken;
}
interface SubscribeRequest {
socket: SCServerSocket;
authTokenExpiredError?: Error;
channel?: string;
waitForAuth?: boolean;
data?: any;
}
interface PublishInRequest {
socket: SCServerSocket;
authTokenExpiredError?: Error;
channel?: string;
data?: any;
ackData?: any;
}
interface PublishOutRequest {
socket: SCServerSocket;
channel?: string;
data?: any;
useCache?: boolean;
}
interface EmitRequest {
socket: SCServerSocket;
authTokenExpiredError?: Error;
event: string;
data?: any;
}
type nextMiddlewareFunction = (error?: true | string | Error) => void;
type nextHandshakeSCMiddlewareFunction = (error?: true | string | Error | null, statusCode?: number) => void;
type nextAuthenticateMiddlewareFunction = (error?: true | string | Error | null, isBadToken?: boolean) => void;
type connectionListenerFunction = (scSocket: SCServerSocket, serverSocketStatus: SCServerSocketStatus) => void;
interface SCCodecEngine {
decode: (input: any) => any;
ncode: (object: any) => any;
}
}
+43
View File
@@ -0,0 +1,43 @@
import Emitter = require("component-emitter");
import { IncomingMessage } from "http";
import { SCExchange } from "sc-broker-cluster";
import { SignOptions } from "jsonwebtoken";
import WebSocket = require("ws");
import SCServer = require("./scserver");
declare class SCServerSocket extends Emitter {
readonly CONNECTING: "connecting";
readonly OPEN: "open";
readonly CLOSED: "closed";
readonly AUTHENTICATED: "authenticated";
readonly UNAUTHENTICATED: "unauthenticated";
id: string;
request: IncomingMessage;
remoteAddress: string;
remoteFamily: string;
remotePort: number;
exchange: SCExchange;
state: "connecting" | "open" | "closed";
authState: "authenticated" | "unauthenticated";
authToken?: SCServer.AuthToken;
constructor(id: string, server: SCServer, socket: WebSocket);
getState(): "connecting" | "open" | "closed";
disconnect(code?: number, data?: any): void;
send(data: any, options: { mask?: boolean; binary?: boolean; compress?: boolean; fin?: boolean }): void;
getAuthToken(): SCServer.AuthToken;
setAuthToken(data: SCServer.AuthToken, options?: SignOptions): void;
deauthenticate(): void;
kickOut(channel?: string, message?: string, callback?: () => void): void;
subscriptions(): string[];
isSubscribed(channel?: string): boolean;
}
export = SCServerSocket;
@@ -0,0 +1,39 @@
// Adapted from README
// Using with basic http(s) module (example)
import http = require("http");
import * as socketClusterServer from "socketcluster-server";
let httpServer = http.createServer();
let scServer = socketClusterServer.attach(httpServer);
scServer.on("connection", socket => {
// ... Handle new socket connections here
});
httpServer.listen(8000);
// Using with Express (example)
import serveStatic = require("serve-static");
import path = require("path");
import express = require("express");
const app = express();
app.use(serveStatic(path.resolve(__dirname, "public")));
httpServer = http.createServer();
// Attach express to our httpServer
httpServer.on("request", app);
// Attach socketcluster-server to our httpServer
scServer = socketClusterServer.attach(httpServer);
scServer.on("connection", socket => {
// ... Handle new socket connections here
});
httpServer.listen(8000);
+25
View File
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"scserver.d.ts",
"scserversocket.d.ts",
"socketcluster-server-tests.ts"
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"extends": "dtslint/dt.json"
}
+11
View File
@@ -0,0 +1,11 @@
import { PathLike } from "fs";
export function fileExists(filePath: PathLike, callback: (exists: boolean) => void): void;
export function waitForFile(
filePath: PathLike,
checkInterval: number,
startTime: number,
maxWaitDuration: number,
timeoutErrorMessage?: string
): Promise<void>;
+84
View File
@@ -0,0 +1,84 @@
// Type definitions for socketcluster 14.0
// Project: https://github.com/SocketCluster/socketcluster
// Definitions by: Daniel Rose <https://github.com/DanielRose>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.4
import { EventEmitter } from "events";
import { SCServer } from "socketcluster-server";
import { ChildProcess } from "child_process";
interface WorkerStartInfo {
id: number;
pid: number;
respawn: boolean;
}
interface WorkerClusterStartInfo {
pid: number;
childProcess: ChildProcess;
}
interface WorkerClusterReadyInfo {
pid: number;
childProcess: ChildProcess;
}
interface WorkerClusterExitInfo {
pid: number;
code: number;
signal: string;
childProcess: ChildProcess;
}
export = SocketCluster;
declare class SocketCluster extends EventEmitter {
readonly EVENT_FAIL: "fail";
readonly EVENT_WARNING: "warning";
readonly EVENT_READY: "ready";
readonly EVENT_WORKER_START: "workerStart";
readonly EVENT_WORKER_EXIT: "workerExit";
readonly EVENT_BROKER_START: "brokerStart";
readonly EVENT_BROKER_EXIT: "brokerExit";
readonly EVENT_WORKER_CLUSTER_START: "workerClusterStart";
readonly EVENT_WORKER_CLUSTER_READY: "workerClusterReady";
readonly EVENT_WORKER_CLUSTER_EXIT: "workerClusterExit";
options: SCServer.SCServerOptions;
constructor(options?: SCServer.SCServerOptions);
on(event: "fail", listener: (err: Error) => void): this;
on(event: "warning", listener: (warning: Error) => void): this;
on(event: "ready", listener: () => void): this;
on(event: "workerStart", listener: (workerInfo: WorkerStartInfo) => void): this;
on(event: "workerExit", listener: (workerInfo: SocketCluster.WorkerExitInfo) => void): this;
on(event: "brokerStart", listener: (brokerInfo: SocketCluster.BrokerStartInfo) => void): this;
on(event: "brokerExit", listener: (brokerInfo: SocketCluster.BrokerExitInfo) => void): this;
on(event: "workerClusterStart", listener: (workerClusterInfo: WorkerClusterStartInfo) => void): this;
on(event: "workerClusterReady", listener: (workerClusterInfo: WorkerClusterReadyInfo) => void): this;
on(event: "workerClusterExit", listener: (workerClusterInfo: WorkerClusterExitInfo) => void): this;
}
declare namespace SocketCluster {
interface WorkerExitInfo {
id: number;
pid: number;
code: number;
signal: string;
}
interface BrokerStartInfo {
id: number;
pid: number;
respawn: boolean;
}
interface BrokerExitInfo {
id: number;
pid: number;
code: number;
signal: string;
}
}
+3
View File
@@ -0,0 +1,3 @@
import SCBroker = require("sc-broker-cluster/scbroker");
export = SCBroker;
+63
View File
@@ -0,0 +1,63 @@
import { EventEmitter } from "events";
import { Server as httpServer } from "http";
import { Server as httpsServer } from "https";
import { SCServer, SCServerSocket } from "socketcluster-server";
import { SCAuthEngine } from "sc-auth";
import { SCExchange } from "sc-broker-cluster";
export = SCWorker;
type middlewareFunction = (options: SCServer.SCServerOptions, next: (error?: string | Error) => void) => void;
declare class SCWorker extends EventEmitter {
readonly EVENT_ERROR: "error";
readonly EVENT_WARNING: "warning";
readonly EVENT_EXIT: "exit";
readonly EVENT_READY: "ready";
readonly EVENT_CONNECTION: "connection";
readonly MIDDLEWARE_START: "start";
id: number;
isLeader: boolean;
options: SCServer.SCServerOptions;
httpServer: httpServer | httpsServer;
scServer: SCServer;
exchange: SCExchange;
auth: SCAuthEngine;
constructor(options?: SCServer.SCServerOptions);
run(): void;
getSCServer(): SCServer;
getHTTPServer(): httpServer | httpsServer;
getSocketPath(): string;
setAuthEngine(authEngine: SCAuthEngine): void;
setCodecEngine(codecEngine: SCServer.SCCodecEngine): void;
open(): void;
close(callback?: () => void): void;
addMiddleware(type: "start", middlewareFn: middlewareFunction): void;
removeMiddleware(type: "start", middlewareFn: middlewareFunction): void;
startHTTPServer(): void;
start(): Promise<void>;
getStatus(): {
clientCount: any;
httpRPM: number;
wsRPM: number;
};
sendToMaster(data: any, callback: (err: Error | null, data: any) => void): void;
respondToMaster(err: Error | null, data: any, rid: number): void;
on(event: "connection", listener: (scSocket: SCServerSocket) => void): this;
on(event: "ready", listener: () => void): this;
on(event: "error", listener: (err: Error) => void): this;
on(event: "warning", listener: (warning: Error) => void): this;
on(event: "masterMessage", listener: (data: any, respond: (err: Error | null, responseData: any) => void) => void): this;
}
@@ -0,0 +1,76 @@
import * as fsutil from "socketcluster/fsutil";
import SocketCluster = require("socketcluster");
import { SCServer } from "socketcluster-server";
import { ChildProcess } from "child_process";
////////////////////////////////////////////////////
/// SocketCluster tests
////////////////////////////////////////////////////
{
const options: SCServer.SCServerOptions = { port: 80 };
let sc = new SocketCluster();
sc = new SocketCluster(options);
sc.options = { environment: "prod" };
sc.on(sc.EVENT_FAIL, err => {
const error: Error = err;
});
sc.on(sc.EVENT_WARNING, warning => {
const warn: Error = warning;
});
sc.on(sc.EVENT_READY, () => {});
sc.on(sc.EVENT_WORKER_START, workerInfo => {
const id: number = workerInfo.id;
const pid: number = workerInfo.pid;
const respawn: boolean = workerInfo.respawn;
});
sc.on(sc.EVENT_WORKER_EXIT, workerInfo => {
const id: number = workerInfo.id;
const pid: number = workerInfo.pid;
const code: number = workerInfo.code;
const signal: string = workerInfo.signal;
});
sc.on(sc.EVENT_BROKER_START, brokerInfo => {
const id: number = brokerInfo.id;
const pid: number = brokerInfo.pid;
const respawn: boolean = brokerInfo.respawn;
});
sc.on(sc.EVENT_BROKER_EXIT, brokerInfo => {
const id: number = brokerInfo.id;
const pid: number = brokerInfo.pid;
const code: number = brokerInfo.code;
const signal: string = brokerInfo.signal;
});
sc.on(sc.EVENT_WORKER_CLUSTER_START, workerClusterInfo => {
const pid: number = workerClusterInfo.pid;
const childProcess: ChildProcess = workerClusterInfo.childProcess;
});
sc.on(sc.EVENT_WORKER_CLUSTER_READY, workerClusterInfo => {
const pid: number = workerClusterInfo.pid;
const childProcess: ChildProcess = workerClusterInfo.childProcess;
});
sc.on(sc.EVENT_WORKER_CLUSTER_EXIT, workerClusterInfo => {
const pid: number = workerClusterInfo.pid;
const code: number = workerClusterInfo.code;
const signal: string = workerClusterInfo.signal;
const childProcess: ChildProcess = workerClusterInfo.childProcess;
});
}
////////////////////////////////////////////////////
/// fsutil tests
////////////////////////////////////////////////////
{
fsutil.fileExists("/path/to/folder", err => {});
fsutil.fileExists(Buffer.from(""), err => {});
const pathPromise: Promise<void> = fsutil.waitForFile("/path/to/folder", 100, 0, 100);
const bufferPromise: Promise<void> = fsutil.waitForFile(Buffer.from(""), 0, 0, 0, "timeout");
}
+26
View File
@@ -0,0 +1,26 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"fsutil.d.ts",
"scbroker.d.ts",
"scworker.d.ts",
"socketcluster-tests.ts"
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"extends": "dtslint/dt.json"
}