Adding support for multiple callbacks per client side method
...and a possibility to remove callbacks Fixes: #807
This commit is contained in:
parent
48d97bf271
commit
bee9fcb0d8
|
|
@ -7,14 +7,16 @@ import { DataReceived, ConnectionClosed } from "../Microsoft.AspNetCore.SignalR.
|
||||||
import { TransportType, ITransport, TransferMode } from "../Microsoft.AspNetCore.SignalR.Client.TS/Transports"
|
import { TransportType, ITransport, TransferMode } from "../Microsoft.AspNetCore.SignalR.Client.TS/Transports"
|
||||||
import { Observer } from "../Microsoft.AspNetCore.SignalR.Client.TS/Observable"
|
import { Observer } from "../Microsoft.AspNetCore.SignalR.Client.TS/Observable"
|
||||||
import { TextMessageFormat } from "../Microsoft.AspNetCore.SignalR.Client.TS/Formatters"
|
import { TextMessageFormat } from "../Microsoft.AspNetCore.SignalR.Client.TS/Formatters"
|
||||||
|
import { ILogger, LogLevel } from "../Microsoft.AspNetCore.SignalR.Client.TS/ILogger"
|
||||||
|
|
||||||
import { asyncit as it, captureException } from './JasmineUtils';
|
import { asyncit as it, captureException } from './JasmineUtils';
|
||||||
|
|
||||||
describe("HubConnection", () => {
|
describe("HubConnection", () => {
|
||||||
|
|
||||||
describe("start", () => {
|
describe("start", () => {
|
||||||
it("sends negotiation message", async () => {
|
it("sends negotiation message", async () => {
|
||||||
let connection = new TestConnection();
|
let connection = new TestConnection();
|
||||||
let hubConnection = new HubConnection(connection);
|
let hubConnection = new HubConnection(connection, { logging: null });
|
||||||
await hubConnection.start();
|
await hubConnection.start();
|
||||||
expect(connection.sentData.length).toBe(1)
|
expect(connection.sentData.length).toBe(1)
|
||||||
expect(JSON.parse(connection.sentData[0])).toEqual({
|
expect(JSON.parse(connection.sentData[0])).toEqual({
|
||||||
|
|
@ -135,6 +137,146 @@ describe("HubConnection", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("on", () => {
|
||||||
|
it("invocations ignored in callbacks not registered", async () => {
|
||||||
|
let warnings: string[] = [];
|
||||||
|
let logger = <ILogger>{
|
||||||
|
log: function(logLevel: LogLevel, message: string) {
|
||||||
|
if (logLevel === LogLevel.Warning) {
|
||||||
|
warnings.push(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let connection = new TestConnection();
|
||||||
|
let hubConnection = new HubConnection(connection, { logging: logger });
|
||||||
|
|
||||||
|
connection.receive({
|
||||||
|
type: 1,
|
||||||
|
invocationId: 0,
|
||||||
|
target: "message",
|
||||||
|
arguments: ["test"],
|
||||||
|
nonblocking: true
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(warnings).toEqual(["No client method with the name 'message' found."]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("callback invoked when servers invokes a method on the client", async () => {
|
||||||
|
let connection = new TestConnection();
|
||||||
|
let hubConnection = new HubConnection(connection);
|
||||||
|
let value = 0;
|
||||||
|
hubConnection.on("message", v => value = v);
|
||||||
|
|
||||||
|
connection.receive({
|
||||||
|
type: 1,
|
||||||
|
invocationId: 0,
|
||||||
|
target: "message",
|
||||||
|
arguments: ["test"],
|
||||||
|
nonblocking: true
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(value).toBe("test");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can have multiple callbacks", async () => {
|
||||||
|
let connection = new TestConnection();
|
||||||
|
let hubConnection = new HubConnection(connection);
|
||||||
|
let numInvocations1 = 0;
|
||||||
|
let numInvocations2 = 0;
|
||||||
|
hubConnection.on("message", () => numInvocations1++);
|
||||||
|
hubConnection.on("message", () => numInvocations2++);
|
||||||
|
|
||||||
|
connection.receive({
|
||||||
|
type: 1,
|
||||||
|
invocationId: 0,
|
||||||
|
target: "message",
|
||||||
|
arguments: [],
|
||||||
|
nonblocking: true
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(numInvocations1).toBe(1);
|
||||||
|
expect(numInvocations2).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can unsubscribe from on", async () => {
|
||||||
|
let connection = new TestConnection();
|
||||||
|
let hubConnection = new HubConnection(connection);
|
||||||
|
|
||||||
|
var numInvocations = 0;
|
||||||
|
var callback = () => numInvocations++;
|
||||||
|
hubConnection.on("message", callback);
|
||||||
|
|
||||||
|
connection.receive({
|
||||||
|
type: 1,
|
||||||
|
invocationId: 0,
|
||||||
|
target: "message",
|
||||||
|
arguments: [],
|
||||||
|
nonblocking: true
|
||||||
|
});
|
||||||
|
|
||||||
|
hubConnection.off("message", callback);
|
||||||
|
|
||||||
|
connection.receive({
|
||||||
|
type: 1,
|
||||||
|
invocationId: 0,
|
||||||
|
target: "message",
|
||||||
|
arguments: [],
|
||||||
|
nonblocking: true
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(numInvocations).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("unsubscribing from non-existing callbacks no-ops", async () => {
|
||||||
|
let connection = new TestConnection();
|
||||||
|
let hubConnection = new HubConnection(connection);
|
||||||
|
|
||||||
|
hubConnection.off("_", () => {});
|
||||||
|
hubConnection.on("message", t => {});
|
||||||
|
hubConnection.on("message", () => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("using null/undefined for methodName or method no-ops", async () => {
|
||||||
|
let warnings: string[] = [];
|
||||||
|
let logger = <ILogger>{
|
||||||
|
log: function(logLevel: LogLevel, message: string) {
|
||||||
|
if (logLevel === LogLevel.Warning) {
|
||||||
|
warnings.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let connection = new TestConnection();
|
||||||
|
let hubConnection = new HubConnection(connection, { logging: logger });
|
||||||
|
|
||||||
|
hubConnection.on(null, undefined);
|
||||||
|
hubConnection.on(undefined, null);
|
||||||
|
hubConnection.on("message", null);
|
||||||
|
hubConnection.on("message", undefined);
|
||||||
|
hubConnection.on(null, () => {});
|
||||||
|
hubConnection.on(undefined, () => {});
|
||||||
|
|
||||||
|
// invoke a method to make sure we are not trying to use null/undefined
|
||||||
|
connection.receive({
|
||||||
|
type: 1,
|
||||||
|
invocationId: 0,
|
||||||
|
target: "message",
|
||||||
|
arguments: [],
|
||||||
|
nonblocking: true
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(warnings).toEqual(["No client method with the name 'message' found."]);
|
||||||
|
|
||||||
|
hubConnection.off(null, undefined);
|
||||||
|
hubConnection.off(undefined, null);
|
||||||
|
hubConnection.off("message", null);
|
||||||
|
hubConnection.off("message", undefined);
|
||||||
|
hubConnection.off(null, () => {});
|
||||||
|
hubConnection.off(undefined, () => {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("stream", () => {
|
describe("stream", () => {
|
||||||
it("sends an invocation", async () => {
|
it("sends an invocation", async () => {
|
||||||
let connection = new TestConnection();
|
let connection = new TestConnection();
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export class HubConnection {
|
||||||
private readonly logger: ILogger;
|
private readonly logger: ILogger;
|
||||||
private protocol: IHubProtocol;
|
private protocol: IHubProtocol;
|
||||||
private callbacks: Map<string, (invocationUpdate: CompletionMessage | ResultMessage) => void>;
|
private callbacks: Map<string, (invocationUpdate: CompletionMessage | ResultMessage) => void>;
|
||||||
private methods: Map<string, (...args: any[]) => void>;
|
private methods: Map<string, ((...args: any[]) => void)[]>;
|
||||||
private id: number;
|
private id: number;
|
||||||
private connectionClosedCallback: ConnectionClosed;
|
private connectionClosedCallback: ConnectionClosed;
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ export class HubConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.callbacks = new Map<string, (invocationEvent: CompletionMessage | ResultMessage) => void>();
|
this.callbacks = new Map<string, (invocationEvent: CompletionMessage | ResultMessage) => void>();
|
||||||
this.methods = new Map<string, (...args: any[]) => void>();
|
this.methods = new Map<string, ((...args: any[]) => void)[]>();
|
||||||
this.id = 0;
|
this.id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,9 +82,9 @@ export class HubConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
private invokeClientMethod(invocationMessage: InvocationMessage) {
|
private invokeClientMethod(invocationMessage: InvocationMessage) {
|
||||||
let method = this.methods.get(invocationMessage.target.toLowerCase());
|
let methods = this.methods.get(invocationMessage.target.toLowerCase());
|
||||||
if (method) {
|
if (methods) {
|
||||||
method.apply(this, invocationMessage.arguments);
|
methods.forEach(m => m.apply(this, invocationMessage.arguments));
|
||||||
if (!invocationMessage.nonblocking) {
|
if (!invocationMessage.nonblocking) {
|
||||||
// TODO: send result back to the server?
|
// TODO: send result back to the server?
|
||||||
}
|
}
|
||||||
|
|
@ -211,7 +211,32 @@ export class HubConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
on(methodName: string, method: (...args: any[]) => void) {
|
on(methodName: string, method: (...args: any[]) => void) {
|
||||||
this.methods.set(methodName.toLowerCase(), method);
|
if (!methodName || !method) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
methodName = methodName.toLowerCase();
|
||||||
|
if (!this.methods.has(methodName)) {
|
||||||
|
this.methods.set(methodName, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.methods.get(methodName).push(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
off(methodName: string, method: (...args: any[]) => void) {
|
||||||
|
if (!methodName || !method) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
methodName = methodName.toLowerCase();
|
||||||
|
let handlers = this.methods.get(methodName);
|
||||||
|
if (!handlers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var removeIdx = handlers.indexOf(method);
|
||||||
|
if (removeIdx != -1) {
|
||||||
|
handlers.splice(removeIdx, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set onClosed(callback: ConnectionClosed) {
|
set onClosed(callback: ConnectionClosed) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue