@grpc/grpc-js
Advanced tools
Comparing version 1.10.1 to 1.10.2
@@ -31,2 +31,3 @@ import { CompressionAlgorithms } from './compression-algorithms'; | ||
'grpc.max_connection_age_grace_ms'?: number; | ||
'grpc.max_connection_idle_ms'?: number; | ||
'grpc-node.max_session_memory'?: number; | ||
@@ -33,0 +34,0 @@ 'grpc.service_config_disable_resolution'?: number; |
@@ -5,3 +5,3 @@ import { ChannelCredentials } from './channel-credentials'; | ||
import { ConnectivityState } from './connectivity-state'; | ||
import { ChannelRef } from './channelz'; | ||
import type { ChannelRef } from './channelz'; | ||
import { Call } from './call-interface'; | ||
@@ -8,0 +8,0 @@ import { Deadline } from './deadline'; |
/// <reference types="node" /> | ||
import { OrderedMap } from '@js-sdsl/ordered-map'; | ||
import { ConnectivityState } from './connectivity-state'; | ||
@@ -7,21 +8,19 @@ import { ChannelTrace } from './generated/grpc/channelz/v1/ChannelTrace'; | ||
export type TraceSeverity = 'CT_UNKNOWN' | 'CT_INFO' | 'CT_WARNING' | 'CT_ERROR'; | ||
export interface ChannelRef { | ||
kind: 'channel'; | ||
interface Ref { | ||
kind: EntityTypes; | ||
id: number; | ||
name: string; | ||
} | ||
export interface SubchannelRef { | ||
kind: 'subchannel'; | ||
id: number; | ||
name: string; | ||
export interface ChannelRef extends Ref { | ||
kind: EntityTypes.channel; | ||
} | ||
export interface ServerRef { | ||
kind: 'server'; | ||
id: number; | ||
export interface SubchannelRef extends Ref { | ||
kind: EntityTypes.subchannel; | ||
} | ||
export interface SocketRef { | ||
kind: 'socket'; | ||
id: number; | ||
name: string; | ||
export interface ServerRef extends Ref { | ||
kind: EntityTypes.server; | ||
} | ||
export interface SocketRef extends Ref { | ||
kind: EntityTypes.socket; | ||
} | ||
interface TraceEvent { | ||
@@ -34,2 +33,9 @@ description: string; | ||
} | ||
export declare class ChannelzTraceStub { | ||
readonly events: TraceEvent[]; | ||
readonly creationTimestamp: Date; | ||
readonly eventsLogged = 0; | ||
addTrace(): void; | ||
getTraceMessage(): ChannelTrace; | ||
} | ||
export declare class ChannelzTrace { | ||
@@ -47,2 +53,3 @@ events: TraceEvent[]; | ||
private socketChildren; | ||
private trackerMap; | ||
refChild(child: ChannelRef | SubchannelRef | SocketRef): void; | ||
@@ -52,2 +59,6 @@ unrefChild(child: ChannelRef | SubchannelRef | SocketRef): void; | ||
} | ||
export declare class ChannelzChildrenTrackerStub extends ChannelzChildrenTracker { | ||
refChild(): void; | ||
unrefChild(): void; | ||
} | ||
export declare class ChannelzCallTracker { | ||
@@ -62,6 +73,20 @@ callsStarted: number; | ||
} | ||
export declare class ChannelzCallTrackerStub extends ChannelzCallTracker { | ||
addCallStarted(): void; | ||
addCallSucceeded(): void; | ||
addCallFailed(): void; | ||
} | ||
export interface ChannelzChildren { | ||
channels: ChannelRef[]; | ||
subchannels: SubchannelRef[]; | ||
sockets: SocketRef[]; | ||
channels: OrderedMap<number, { | ||
ref: ChannelRef; | ||
count: number; | ||
}>; | ||
subchannels: OrderedMap<number, { | ||
ref: SubchannelRef; | ||
count: number; | ||
}>; | ||
sockets: OrderedMap<number, { | ||
ref: SocketRef; | ||
count: number; | ||
}>; | ||
} | ||
@@ -71,4 +96,4 @@ export interface ChannelInfo { | ||
state: ConnectivityState; | ||
trace: ChannelzTrace; | ||
callTracker: ChannelzCallTracker; | ||
trace: ChannelzTrace | ChannelzTraceStub; | ||
callTracker: ChannelzCallTracker | ChannelzCallTrackerStub; | ||
children: ChannelzChildren; | ||
@@ -107,6 +132,31 @@ } | ||
} | ||
export declare function registerChannelzChannel(name: string, getInfo: () => ChannelInfo, channelzEnabled: boolean): ChannelRef; | ||
export declare function registerChannelzSubchannel(name: string, getInfo: () => SubchannelInfo, channelzEnabled: boolean): SubchannelRef; | ||
export declare function registerChannelzServer(getInfo: () => ServerInfo, channelzEnabled: boolean): ServerRef; | ||
export declare function registerChannelzSocket(name: string, getInfo: () => SocketInfo, channelzEnabled: boolean): SocketRef; | ||
interface ChannelEntry { | ||
ref: ChannelRef; | ||
getInfo(): ChannelInfo; | ||
} | ||
interface SubchannelEntry { | ||
ref: SubchannelRef; | ||
getInfo(): SubchannelInfo; | ||
} | ||
interface ServerEntry { | ||
ref: ServerRef; | ||
getInfo(): ServerInfo; | ||
} | ||
interface SocketEntry { | ||
ref: SocketRef; | ||
getInfo(): SocketInfo; | ||
} | ||
export declare const enum EntityTypes { | ||
channel = "channel", | ||
subchannel = "subchannel", | ||
server = "server", | ||
socket = "socket" | ||
} | ||
export type RefByType<T extends EntityTypes> = T extends EntityTypes.channel ? ChannelRef : T extends EntityTypes.server ? ServerRef : T extends EntityTypes.socket ? SocketRef : T extends EntityTypes.subchannel ? SubchannelRef : never; | ||
export type EntryByType<T extends EntityTypes> = T extends EntityTypes.channel ? ChannelEntry : T extends EntityTypes.server ? ServerEntry : T extends EntityTypes.socket ? SocketEntry : T extends EntityTypes.subchannel ? SubchannelEntry : never; | ||
export type InfoByType<T extends EntityTypes> = T extends EntityTypes.channel ? ChannelInfo : T extends EntityTypes.subchannel ? SubchannelInfo : T extends EntityTypes.server ? ServerInfo : T extends EntityTypes.socket ? SocketInfo : never; | ||
export declare const registerChannelzChannel: (name: string, getInfo: () => ChannelInfo, channelzEnabled: boolean) => ChannelRef; | ||
export declare const registerChannelzSubchannel: (name: string, getInfo: () => ChannelInfo, channelzEnabled: boolean) => SubchannelRef; | ||
export declare const registerChannelzServer: (name: string, getInfo: () => ServerInfo, channelzEnabled: boolean) => ServerRef; | ||
export declare const registerChannelzSocket: (name: string, getInfo: () => SocketInfo, channelzEnabled: boolean) => SocketRef; | ||
export declare function unregisterChannelzRef(ref: ChannelRef | SubchannelRef | ServerRef | SocketRef): void; | ||
@@ -113,0 +163,0 @@ export declare function getChannelzHandlers(): ChannelzHandlers; |
@@ -19,4 +19,5 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.setup = exports.getChannelzServiceDefinition = exports.getChannelzHandlers = exports.unregisterChannelzRef = exports.registerChannelzSocket = exports.registerChannelzServer = exports.registerChannelzSubchannel = exports.registerChannelzChannel = exports.ChannelzCallTracker = exports.ChannelzChildrenTracker = exports.ChannelzTrace = void 0; | ||
exports.setup = exports.getChannelzServiceDefinition = exports.getChannelzHandlers = exports.unregisterChannelzRef = exports.registerChannelzSocket = exports.registerChannelzServer = exports.registerChannelzSubchannel = exports.registerChannelzChannel = exports.ChannelzCallTrackerStub = exports.ChannelzCallTracker = exports.ChannelzChildrenTrackerStub = exports.ChannelzChildrenTracker = exports.ChannelzTrace = exports.ChannelzTraceStub = void 0; | ||
const net_1 = require("net"); | ||
const ordered_map_1 = require("@js-sdsl/ordered-map"); | ||
const connectivity_state_1 = require("./connectivity-state"); | ||
@@ -57,2 +58,22 @@ const constants_1 = require("./constants"); | ||
const TARGET_RETAINED_TRACES = 32; | ||
/** | ||
* Default number of sockets/servers/channels/subchannels to return | ||
*/ | ||
const DEFAULT_MAX_RESULTS = 100; | ||
class ChannelzTraceStub { | ||
constructor() { | ||
this.events = []; | ||
this.creationTimestamp = new Date(); | ||
this.eventsLogged = 0; | ||
} | ||
addTrace() { } | ||
getTraceMessage() { | ||
return { | ||
creation_timestamp: dateToProtoTimestamp(this.creationTimestamp), | ||
num_events_logged: this.eventsLogged, | ||
events: [], | ||
}; | ||
} | ||
} | ||
exports.ChannelzTraceStub = ChannelzTraceStub; | ||
class ChannelzTrace { | ||
@@ -102,98 +123,48 @@ constructor() { | ||
constructor() { | ||
this.channelChildren = new Map(); | ||
this.subchannelChildren = new Map(); | ||
this.socketChildren = new Map(); | ||
this.channelChildren = new ordered_map_1.OrderedMap(); | ||
this.subchannelChildren = new ordered_map_1.OrderedMap(); | ||
this.socketChildren = new ordered_map_1.OrderedMap(); | ||
this.trackerMap = { | ||
["channel" /* EntityTypes.channel */]: this.channelChildren, | ||
["subchannel" /* EntityTypes.subchannel */]: this.subchannelChildren, | ||
["socket" /* EntityTypes.socket */]: this.socketChildren, | ||
}; | ||
} | ||
refChild(child) { | ||
var _a, _b, _c; | ||
switch (child.kind) { | ||
case 'channel': { | ||
const trackedChild = (_a = this.channelChildren.get(child.id)) !== null && _a !== void 0 ? _a : { | ||
ref: child, | ||
count: 0, | ||
}; | ||
trackedChild.count += 1; | ||
this.channelChildren.set(child.id, trackedChild); | ||
break; | ||
} | ||
case 'subchannel': { | ||
const trackedChild = (_b = this.subchannelChildren.get(child.id)) !== null && _b !== void 0 ? _b : { | ||
ref: child, | ||
count: 0, | ||
}; | ||
trackedChild.count += 1; | ||
this.subchannelChildren.set(child.id, trackedChild); | ||
break; | ||
} | ||
case 'socket': { | ||
const trackedChild = (_c = this.socketChildren.get(child.id)) !== null && _c !== void 0 ? _c : { | ||
ref: child, | ||
count: 0, | ||
}; | ||
trackedChild.count += 1; | ||
this.socketChildren.set(child.id, trackedChild); | ||
break; | ||
} | ||
const tracker = this.trackerMap[child.kind]; | ||
const trackedChild = tracker.find(child.id); | ||
if (trackedChild.equals(tracker.end())) { | ||
tracker.setElement(child.id, { | ||
ref: child, | ||
count: 1, | ||
}, trackedChild); | ||
} | ||
else { | ||
trackedChild.pointer[1].count += 1; | ||
} | ||
} | ||
unrefChild(child) { | ||
switch (child.kind) { | ||
case 'channel': { | ||
const trackedChild = this.channelChildren.get(child.id); | ||
if (trackedChild !== undefined) { | ||
trackedChild.count -= 1; | ||
if (trackedChild.count === 0) { | ||
this.channelChildren.delete(child.id); | ||
} | ||
else { | ||
this.channelChildren.set(child.id, trackedChild); | ||
} | ||
} | ||
break; | ||
const tracker = this.trackerMap[child.kind]; | ||
const trackedChild = tracker.getElementByKey(child.id); | ||
if (trackedChild !== undefined) { | ||
trackedChild.count -= 1; | ||
if (trackedChild.count === 0) { | ||
tracker.eraseElementByKey(child.id); | ||
} | ||
case 'subchannel': { | ||
const trackedChild = this.subchannelChildren.get(child.id); | ||
if (trackedChild !== undefined) { | ||
trackedChild.count -= 1; | ||
if (trackedChild.count === 0) { | ||
this.subchannelChildren.delete(child.id); | ||
} | ||
else { | ||
this.subchannelChildren.set(child.id, trackedChild); | ||
} | ||
} | ||
break; | ||
} | ||
case 'socket': { | ||
const trackedChild = this.socketChildren.get(child.id); | ||
if (trackedChild !== undefined) { | ||
trackedChild.count -= 1; | ||
if (trackedChild.count === 0) { | ||
this.socketChildren.delete(child.id); | ||
} | ||
else { | ||
this.socketChildren.set(child.id, trackedChild); | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
getChildLists() { | ||
const channels = []; | ||
for (const { ref } of this.channelChildren.values()) { | ||
channels.push(ref); | ||
} | ||
const subchannels = []; | ||
for (const { ref } of this.subchannelChildren.values()) { | ||
subchannels.push(ref); | ||
} | ||
const sockets = []; | ||
for (const { ref } of this.socketChildren.values()) { | ||
sockets.push(ref); | ||
} | ||
return { channels, subchannels, sockets }; | ||
return { | ||
channels: this.channelChildren, | ||
subchannels: this.subchannelChildren, | ||
sockets: this.socketChildren, | ||
}; | ||
} | ||
} | ||
exports.ChannelzChildrenTracker = ChannelzChildrenTracker; | ||
class ChannelzChildrenTrackerStub extends ChannelzChildrenTracker { | ||
refChild() { } | ||
unrefChild() { } | ||
} | ||
exports.ChannelzChildrenTrackerStub = ChannelzChildrenTrackerStub; | ||
class ChannelzCallTracker { | ||
@@ -218,61 +189,35 @@ constructor() { | ||
exports.ChannelzCallTracker = ChannelzCallTracker; | ||
let nextId = 1; | ||
function getNextId() { | ||
return nextId++; | ||
class ChannelzCallTrackerStub extends ChannelzCallTracker { | ||
addCallStarted() { } | ||
addCallSucceeded() { } | ||
addCallFailed() { } | ||
} | ||
const channels = []; | ||
const subchannels = []; | ||
const servers = []; | ||
const sockets = []; | ||
function registerChannelzChannel(name, getInfo, channelzEnabled) { | ||
const id = getNextId(); | ||
const ref = { id, name, kind: 'channel' }; | ||
if (channelzEnabled) { | ||
channels[id] = { ref, getInfo }; | ||
exports.ChannelzCallTrackerStub = ChannelzCallTrackerStub; | ||
const entityMaps = { | ||
["channel" /* EntityTypes.channel */]: new ordered_map_1.OrderedMap(), | ||
["subchannel" /* EntityTypes.subchannel */]: new ordered_map_1.OrderedMap(), | ||
["server" /* EntityTypes.server */]: new ordered_map_1.OrderedMap(), | ||
["socket" /* EntityTypes.socket */]: new ordered_map_1.OrderedMap(), | ||
}; | ||
const generateRegisterFn = (kind) => { | ||
let nextId = 1; | ||
function getNextId() { | ||
return nextId++; | ||
} | ||
return ref; | ||
} | ||
exports.registerChannelzChannel = registerChannelzChannel; | ||
function registerChannelzSubchannel(name, getInfo, channelzEnabled) { | ||
const id = getNextId(); | ||
const ref = { id, name, kind: 'subchannel' }; | ||
if (channelzEnabled) { | ||
subchannels[id] = { ref, getInfo }; | ||
} | ||
return ref; | ||
} | ||
exports.registerChannelzSubchannel = registerChannelzSubchannel; | ||
function registerChannelzServer(getInfo, channelzEnabled) { | ||
const id = getNextId(); | ||
const ref = { id, kind: 'server' }; | ||
if (channelzEnabled) { | ||
servers[id] = { ref, getInfo }; | ||
} | ||
return ref; | ||
} | ||
exports.registerChannelzServer = registerChannelzServer; | ||
function registerChannelzSocket(name, getInfo, channelzEnabled) { | ||
const id = getNextId(); | ||
const ref = { id, name, kind: 'socket' }; | ||
if (channelzEnabled) { | ||
sockets[id] = { ref, getInfo }; | ||
} | ||
return ref; | ||
} | ||
exports.registerChannelzSocket = registerChannelzSocket; | ||
const entityMap = entityMaps[kind]; | ||
return (name, getInfo, channelzEnabled) => { | ||
const id = getNextId(); | ||
const ref = { id, name, kind }; | ||
if (channelzEnabled) { | ||
entityMap.setElement(id, { ref, getInfo }); | ||
} | ||
return ref; | ||
}; | ||
}; | ||
exports.registerChannelzChannel = generateRegisterFn("channel" /* EntityTypes.channel */); | ||
exports.registerChannelzSubchannel = generateRegisterFn("subchannel" /* EntityTypes.subchannel */); | ||
exports.registerChannelzServer = generateRegisterFn("server" /* EntityTypes.server */); | ||
exports.registerChannelzSocket = generateRegisterFn("socket" /* EntityTypes.socket */); | ||
function unregisterChannelzRef(ref) { | ||
switch (ref.kind) { | ||
case 'channel': | ||
delete channels[ref.id]; | ||
return; | ||
case 'subchannel': | ||
delete subchannels[ref.id]; | ||
return; | ||
case 'server': | ||
delete servers[ref.id]; | ||
return; | ||
case 'socket': | ||
delete sockets[ref.id]; | ||
return; | ||
} | ||
entityMaps[ref.kind].eraseElementByKey(ref.id); | ||
} | ||
@@ -376,2 +321,10 @@ exports.unregisterChannelzRef = unregisterChannelzRef; | ||
const resolvedInfo = channelEntry.getInfo(); | ||
const channelRef = []; | ||
const subchannelRef = []; | ||
resolvedInfo.children.channels.forEach(el => { | ||
channelRef.push(channelRefToMessage(el[1].ref)); | ||
}); | ||
resolvedInfo.children.subchannels.forEach(el => { | ||
subchannelRef.push(subchannelRefToMessage(el[1].ref)); | ||
}); | ||
return { | ||
@@ -388,9 +341,9 @@ ref: channelRefToMessage(channelEntry.ref), | ||
}, | ||
channel_ref: resolvedInfo.children.channels.map(ref => channelRefToMessage(ref)), | ||
subchannel_ref: resolvedInfo.children.subchannels.map(ref => subchannelRefToMessage(ref)), | ||
channel_ref: channelRef, | ||
subchannel_ref: subchannelRef, | ||
}; | ||
} | ||
function GetChannel(call, callback) { | ||
const channelId = Number.parseInt(call.request.channel_id); | ||
const channelEntry = channels[channelId]; | ||
const channelId = parseInt(call.request.channel_id, 10); | ||
const channelEntry = entityMaps["channel" /* EntityTypes.channel */].getElementByKey(channelId); | ||
if (channelEntry === undefined) { | ||
@@ -406,18 +359,13 @@ callback({ | ||
function GetTopChannels(call, callback) { | ||
const maxResults = Number.parseInt(call.request.max_results); | ||
const maxResults = parseInt(call.request.max_results, 10) || DEFAULT_MAX_RESULTS; | ||
const resultList = []; | ||
let i = Number.parseInt(call.request.start_channel_id); | ||
for (; i < channels.length; i++) { | ||
const channelEntry = channels[i]; | ||
if (channelEntry === undefined) { | ||
continue; | ||
} | ||
resultList.push(getChannelMessage(channelEntry)); | ||
if (resultList.length >= maxResults) { | ||
break; | ||
} | ||
const startId = parseInt(call.request.start_channel_id, 10); | ||
const channelEntries = entityMaps["channel" /* EntityTypes.channel */]; | ||
let i; | ||
for (i = channelEntries.lowerBound(startId); !i.equals(channelEntries.end()) && resultList.length < maxResults; i = i.next()) { | ||
resultList.push(getChannelMessage(i.pointer[1])); | ||
} | ||
callback(null, { | ||
channel: resultList, | ||
end: i >= servers.length, | ||
end: i.equals(channelEntries.end()), | ||
}); | ||
@@ -427,2 +375,6 @@ } | ||
const resolvedInfo = serverEntry.getInfo(); | ||
const listenSocket = []; | ||
resolvedInfo.listenerChildren.sockets.forEach(el => { | ||
listenSocket.push(socketRefToMessage(el[1].ref)); | ||
}); | ||
return { | ||
@@ -437,8 +389,9 @@ ref: serverRefToMessage(serverEntry.ref), | ||
}, | ||
listen_socket: resolvedInfo.listenerChildren.sockets.map(ref => socketRefToMessage(ref)), | ||
listen_socket: listenSocket, | ||
}; | ||
} | ||
function GetServer(call, callback) { | ||
const serverId = Number.parseInt(call.request.server_id); | ||
const serverEntry = servers[serverId]; | ||
const serverId = parseInt(call.request.server_id, 10); | ||
const serverEntries = entityMaps["server" /* EntityTypes.server */]; | ||
const serverEntry = serverEntries.getElementByKey(serverId); | ||
if (serverEntry === undefined) { | ||
@@ -454,23 +407,18 @@ callback({ | ||
function GetServers(call, callback) { | ||
const maxResults = Number.parseInt(call.request.max_results); | ||
const maxResults = parseInt(call.request.max_results, 10) || DEFAULT_MAX_RESULTS; | ||
const startId = parseInt(call.request.start_server_id, 10); | ||
const serverEntries = entityMaps["server" /* EntityTypes.server */]; | ||
const resultList = []; | ||
let i = Number.parseInt(call.request.start_server_id); | ||
for (; i < servers.length; i++) { | ||
const serverEntry = servers[i]; | ||
if (serverEntry === undefined) { | ||
continue; | ||
} | ||
resultList.push(getServerMessage(serverEntry)); | ||
if (resultList.length >= maxResults) { | ||
break; | ||
} | ||
let i; | ||
for (i = serverEntries.lowerBound(startId); !i.equals(serverEntries.end()) && resultList.length < maxResults; i = i.next()) { | ||
resultList.push(getServerMessage(i.pointer[1])); | ||
} | ||
callback(null, { | ||
server: resultList, | ||
end: i >= servers.length, | ||
end: i.equals(serverEntries.end()), | ||
}); | ||
} | ||
function GetSubchannel(call, callback) { | ||
const subchannelId = Number.parseInt(call.request.subchannel_id); | ||
const subchannelEntry = subchannels[subchannelId]; | ||
const subchannelId = parseInt(call.request.subchannel_id, 10); | ||
const subchannelEntry = entityMaps["subchannel" /* EntityTypes.subchannel */].getElementByKey(subchannelId); | ||
if (subchannelEntry === undefined) { | ||
@@ -484,2 +432,6 @@ callback({ | ||
const resolvedInfo = subchannelEntry.getInfo(); | ||
const listenSocket = []; | ||
resolvedInfo.children.sockets.forEach(el => { | ||
listenSocket.push(socketRefToMessage(el[1].ref)); | ||
}); | ||
const subchannelMessage = { | ||
@@ -496,3 +448,3 @@ ref: subchannelRefToMessage(subchannelEntry.ref), | ||
}, | ||
socket_ref: resolvedInfo.children.sockets.map(ref => socketRefToMessage(ref)), | ||
socket_ref: listenSocket, | ||
}; | ||
@@ -523,4 +475,4 @@ callback(null, { subchannel: subchannelMessage }); | ||
var _a, _b, _c, _d, _e; | ||
const socketId = Number.parseInt(call.request.socket_id); | ||
const socketEntry = sockets[socketId]; | ||
const socketId = parseInt(call.request.socket_id, 10); | ||
const socketEntry = entityMaps["socket" /* EntityTypes.socket */].getElementByKey(socketId); | ||
if (socketEntry === undefined) { | ||
@@ -580,4 +532,4 @@ callback({ | ||
function GetServerSockets(call, callback) { | ||
const serverId = Number.parseInt(call.request.server_id); | ||
const serverEntry = servers[serverId]; | ||
const serverId = parseInt(call.request.server_id, 10); | ||
const serverEntry = entityMaps["server" /* EntityTypes.server */].getElementByKey(serverId); | ||
if (serverEntry === undefined) { | ||
@@ -590,4 +542,4 @@ callback({ | ||
} | ||
const startId = Number.parseInt(call.request.start_socket_id); | ||
const maxResults = Number.parseInt(call.request.max_results); | ||
const startId = parseInt(call.request.start_socket_id, 10); | ||
const maxResults = parseInt(call.request.max_results, 10) || DEFAULT_MAX_RESULTS; | ||
const resolvedInfo = serverEntry.getInfo(); | ||
@@ -597,16 +549,11 @@ // If we wanted to include listener sockets in the result, this line would | ||
// const allSockets = resolvedInfo.listenerChildren.sockets.concat(resolvedInfo.sessionChildren.sockets).sort((ref1, ref2) => ref1.id - ref2.id); | ||
const allSockets = resolvedInfo.sessionChildren.sockets.sort((ref1, ref2) => ref1.id - ref2.id); | ||
const allSockets = resolvedInfo.sessionChildren.sockets; | ||
const resultList = []; | ||
let i = 0; | ||
for (; i < allSockets.length; i++) { | ||
if (allSockets[i].id >= startId) { | ||
resultList.push(socketRefToMessage(allSockets[i])); | ||
if (resultList.length >= maxResults) { | ||
break; | ||
} | ||
} | ||
let i; | ||
for (i = allSockets.lowerBound(startId); !i.equals(allSockets.end()) && resultList.length < maxResults; i = i.next()) { | ||
resultList.push(socketRefToMessage(i.pointer[1].ref)); | ||
} | ||
callback(null, { | ||
socket_ref: resultList, | ||
end: i >= allSockets.length, | ||
end: i.equals(allSockets.end()), | ||
}); | ||
@@ -613,0 +560,0 @@ } |
@@ -0,1 +1,2 @@ | ||
/// <reference types="node" /> | ||
import { ClientDuplexStream, ClientReadableStream, ClientUnaryCall, ClientWritableStream, ServiceError } from './call'; | ||
@@ -54,3 +55,3 @@ import { CallCredentials, OAuth2Client } from './call-credentials'; | ||
export declare const waitForClientReady: (client: Client, deadline: Date | number, callback: (error?: Error) => void) => void; | ||
export { sendUnaryData, ChannelCredentials, CallCredentials, Deadline, Serialize as serialize, Deserialize as deserialize, ClientUnaryCall, ClientReadableStream, ClientWritableStream, ClientDuplexStream, CallOptions, MethodDefinition, StatusObject, ServiceError, ServerUnaryCall, ServerReadableStream, ServerWritableStream, ServerDuplexStream, ServerErrorResponse, ServiceDefinition, UntypedHandleCall, UntypedServiceImplementation, VerifyOptions }; | ||
export { sendUnaryData, ChannelCredentials, CallCredentials, Deadline, Serialize as serialize, Deserialize as deserialize, ClientUnaryCall, ClientReadableStream, ClientWritableStream, ClientDuplexStream, CallOptions, MethodDefinition, StatusObject, ServiceError, ServerUnaryCall, ServerReadableStream, ServerWritableStream, ServerDuplexStream, ServerErrorResponse, ServiceDefinition, UntypedHandleCall, UntypedServiceImplementation, VerifyOptions, }; | ||
/**** Server ****/ | ||
@@ -75,6 +76,6 @@ export { handleBidiStreamingCall, handleServerStreamingCall, handleUnaryCall, handleClientStreamingCall, }; | ||
export { addAdminServicesToServer } from './admin'; | ||
export { ServiceConfig, LoadBalancingConfig, MethodConfig, RetryPolicy } from './service-config'; | ||
export { ServerListener, FullServerListener, ServerListenerBuilder, Responder, FullResponder, ResponderBuilder, ServerInterceptingCallInterface, ServerInterceptingCall, ServerInterceptor } from './server-interceptors'; | ||
export { ServiceConfig, LoadBalancingConfig, MethodConfig, RetryPolicy, } from './service-config'; | ||
export { ServerListener, FullServerListener, ServerListenerBuilder, Responder, FullResponder, ResponderBuilder, ServerInterceptingCallInterface, ServerInterceptingCall, ServerInterceptor, } from './server-interceptors'; | ||
import * as experimental from './experimental'; | ||
export { experimental }; | ||
import { Deadline } from './deadline'; |
@@ -408,3 +408,4 @@ "use strict"; | ||
maybeStartIdleTimer() { | ||
if (this.connectivityState !== connectivity_state_1.ConnectivityState.SHUTDOWN && !this.idleTimer) { | ||
if (this.connectivityState !== connectivity_state_1.ConnectivityState.SHUTDOWN && | ||
!this.idleTimer) { | ||
this.startIdleTimeout(this.idleTimeoutMs); | ||
@@ -411,0 +412,0 @@ } |
@@ -209,3 +209,5 @@ "use strict"; | ||
if (this.stickyTransientFailureMode) { | ||
this.updateState(connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE, new picker_1.UnavailablePicker({ details: `No connection established. Last error: ${this.lastError}` })); | ||
this.updateState(connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE, new picker_1.UnavailablePicker({ | ||
details: `No connection established. Last error: ${this.lastError}`, | ||
})); | ||
} | ||
@@ -264,3 +266,2 @@ else { | ||
this.calculateAndReportNewState(); | ||
this.requestReresolution(); | ||
} | ||
@@ -324,5 +325,6 @@ return; | ||
} | ||
this.connectionDelayTimeout = (_b = (_a = setTimeout(() => { | ||
this.connectionDelayTimeout = setTimeout(() => { | ||
this.startNextSubchannelConnecting(subchannelIndex + 1); | ||
}, CONNECTION_DELAY_INTERVAL_MS)).unref) === null || _b === void 0 ? void 0 : _b.call(_a); | ||
}, CONNECTION_DELAY_INTERVAL_MS); | ||
(_b = (_a = this.connectionDelayTimeout).unref) === null || _b === void 0 ? void 0 : _b.call(_a); | ||
} | ||
@@ -355,3 +357,4 @@ pickSubchannel(subchannel) { | ||
for (const child of this.children) { | ||
if (!(this.currentPick && child.subchannel.realSubchannelEquals(this.currentPick))) { | ||
if (!(this.currentPick && | ||
child.subchannel.realSubchannelEquals(this.currentPick))) { | ||
/* The connectivity state listener is the same whether the subchannel | ||
@@ -424,3 +427,4 @@ * is in the list of children or it is the currentPick, so if it is in | ||
exitIdle() { | ||
if (this.currentState === connectivity_state_1.ConnectivityState.IDLE && this.latestAddressList) { | ||
if (this.currentState === connectivity_state_1.ConnectivityState.IDLE && | ||
this.latestAddressList) { | ||
this.connectToAddressList(this.latestAddressList); | ||
@@ -427,0 +431,0 @@ } |
@@ -108,3 +108,5 @@ "use strict"; | ||
else if (this.countChildrenWithState(connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE) > 0) { | ||
this.updateState(connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE, new picker_1.UnavailablePicker({ details: `No connection established. Last error: ${this.lastError}` })); | ||
this.updateState(connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE, new picker_1.UnavailablePicker({ | ||
details: `No connection established. Last error: ${this.lastError}`, | ||
})); | ||
} | ||
@@ -111,0 +113,0 @@ else { |
@@ -5,3 +5,3 @@ import { ChannelOptions } from './channel-options'; | ||
import { Picker } from './picker'; | ||
import { ChannelRef, SubchannelRef } from './channelz'; | ||
import type { ChannelRef, SubchannelRef } from './channelz'; | ||
import { SubchannelInterface } from './subchannel-interface'; | ||
@@ -8,0 +8,0 @@ import { LoadBalancingConfig } from './service-config'; |
@@ -0,1 +1,2 @@ | ||
/// <reference types="node" /> | ||
import { LogVerbosity } from './constants'; | ||
@@ -2,0 +3,0 @@ export declare const getLogger: () => Partial<Console>; |
@@ -106,3 +106,11 @@ "use strict"; | ||
if (isTracerEnabled(tracer)) { | ||
(0, exports.log)(severity, new Date().toISOString() + ' | v' + clientVersion + ' ' + process_1.pid + ' | ' + tracer + ' | ' + text); | ||
(0, exports.log)(severity, new Date().toISOString() + | ||
' | v' + | ||
clientVersion + | ||
' ' + | ||
process_1.pid + | ||
' | ' + | ||
tracer + | ||
' | ' + | ||
text); | ||
} | ||
@@ -109,0 +117,0 @@ } |
@@ -242,3 +242,3 @@ "use strict"; | ||
clearTimeout(this.nextResolutionTimer); | ||
this.nextResolutionTimer = (_b = (_a = setTimeout(() => { | ||
this.nextResolutionTimer = setTimeout(() => { | ||
this.stopNextResolutionTimer(); | ||
@@ -248,3 +248,4 @@ if (this.continueResolving) { | ||
} | ||
}, this.minTimeBetweenResolutionsMs)).unref) === null || _b === void 0 ? void 0 : _b.call(_a); | ||
}, this.minTimeBetweenResolutionsMs); | ||
(_b = (_a = this.nextResolutionTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a); | ||
this.isNextResolutionTimerRunning = true; | ||
@@ -275,3 +276,4 @@ } | ||
else { | ||
trace('resolution update delayed by backoff timer until ' + this.backoff.getEndTime().toISOString()); | ||
trace('resolution update delayed by backoff timer until ' + | ||
this.backoff.getEndTime().toISOString()); | ||
} | ||
@@ -278,0 +280,0 @@ this.continueResolving = true; |
@@ -160,3 +160,4 @@ "use strict"; | ||
if (this.backoffTimeout.isRunning()) { | ||
trace('requestReresolution delayed by backoff timer until ' + this.backoffTimeout.getEndTime().toISOString()); | ||
trace('requestReresolution delayed by backoff timer until ' + | ||
this.backoffTimeout.getEndTime().toISOString()); | ||
this.continueResolving = true; | ||
@@ -163,0 +164,0 @@ } |
@@ -5,8 +5,8 @@ /// <reference types="node" /> | ||
import { Duplex, Readable, Writable } from 'stream'; | ||
import { Deserialize, Serialize } from './make-client'; | ||
import type { Deserialize, Serialize } from './make-client'; | ||
import { Metadata } from './metadata'; | ||
import { ObjectReadable, ObjectWritable } from './object-stream'; | ||
import { StatusObject, PartialStatusObject } from './call-interface'; | ||
import { Deadline } from './deadline'; | ||
import { ServerInterceptingCallInterface } from './server-interceptors'; | ||
import type { ObjectReadable, ObjectWritable } from './object-stream'; | ||
import type { StatusObject, PartialStatusObject } from './call-interface'; | ||
import type { Deadline } from './deadline'; | ||
import type { ServerInterceptingCallInterface } from './server-interceptors'; | ||
export type ServerStatusResponse = Partial<StatusObject>; | ||
@@ -102,3 +102,3 @@ export type ServerErrorResponse = ServerStatusResponse & Error; | ||
deserialize: Deserialize<RequestType>; | ||
type: HandlerType; | ||
type: 'unary'; | ||
path: string; | ||
@@ -110,3 +110,3 @@ } | ||
deserialize: Deserialize<RequestType>; | ||
type: HandlerType; | ||
type: 'clientStream'; | ||
path: string; | ||
@@ -118,3 +118,3 @@ } | ||
deserialize: Deserialize<RequestType>; | ||
type: HandlerType; | ||
type: 'serverStream'; | ||
path: string; | ||
@@ -126,3 +126,3 @@ } | ||
deserialize: Deserialize<RequestType>; | ||
type: HandlerType; | ||
type: 'bidi'; | ||
path: string; | ||
@@ -129,0 +129,0 @@ } |
@@ -29,3 +29,3 @@ "use strict"; | ||
details: 'message' in error ? error.message : 'Unknown Error', | ||
metadata: (_a = overrideTrailers !== null && overrideTrailers !== void 0 ? overrideTrailers : error.metadata) !== null && _a !== void 0 ? _a : null | ||
metadata: (_a = overrideTrailers !== null && overrideTrailers !== void 0 ? overrideTrailers : error.metadata) !== null && _a !== void 0 ? _a : null, | ||
}; | ||
@@ -100,3 +100,3 @@ if ('code' in error && | ||
code: constants_1.Status.OK, | ||
details: 'OK' | ||
details: 'OK', | ||
}; | ||
@@ -129,4 +129,4 @@ this.cancelled = false; | ||
var _a; | ||
callback(null); | ||
this.call.sendStatus(Object.assign(Object.assign({}, this.pendingStatus), { metadata: (_a = this.pendingStatus.metadata) !== null && _a !== void 0 ? _a : this.trailingMetadata })); | ||
callback(null); | ||
} | ||
@@ -150,3 +150,3 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
code: constants_1.Status.OK, | ||
details: 'OK' | ||
details: 'OK', | ||
}; | ||
@@ -182,4 +182,4 @@ this.cancelled = false; | ||
var _a; | ||
callback(null); | ||
this.call.sendStatus(Object.assign(Object.assign({}, this.pendingStatus), { metadata: (_a = this.pendingStatus.metadata) !== null && _a !== void 0 ? _a : this.trailingMetadata })); | ||
callback(null); | ||
} | ||
@@ -186,0 +186,0 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any |
/// <reference types="node" /> | ||
import { PartialStatusObject } from "./call-interface"; | ||
import { ServerMethodDefinition } from "./make-client"; | ||
import { Metadata } from "./metadata"; | ||
import { ChannelOptions } from "./channel-options"; | ||
import { Handler } from "./server-call"; | ||
import { Deadline } from "./deadline"; | ||
import { PartialStatusObject } from './call-interface'; | ||
import { ServerMethodDefinition } from './make-client'; | ||
import { Metadata } from './metadata'; | ||
import { ChannelOptions } from './channel-options'; | ||
import { Handler } from './server-call'; | ||
import { Deadline } from './deadline'; | ||
import * as http2 from 'http2'; | ||
import { CallEventTracker } from "./transport"; | ||
import { CallEventTracker } from './transport'; | ||
export interface ServerMetadataListener { | ||
@@ -11,0 +11,0 @@ (metadata: Metadata, next: (metadata: Metadata) => void): void; |
@@ -62,3 +62,3 @@ "use strict"; | ||
onReceiveHalfClose: this.halfClose, | ||
onCancel: this.cancel | ||
onCancel: this.cancel, | ||
}; | ||
@@ -69,3 +69,4 @@ } | ||
function isInterceptingServerListener(listener) { | ||
return listener.onReceiveMetadata !== undefined && listener.onReceiveMetadata.length === 1; | ||
return (listener.onReceiveMetadata !== undefined && | ||
listener.onReceiveMetadata.length === 1); | ||
} | ||
@@ -185,3 +186,3 @@ exports.isInterceptingServerListener = isInterceptingServerListener; | ||
sendMessage: this.message, | ||
sendStatus: this.status | ||
sendStatus: this.status, | ||
}; | ||
@@ -201,6 +202,6 @@ } | ||
}, | ||
onCancel: () => { } | ||
onCancel: () => { }, | ||
}; | ||
const defaultResponder = { | ||
start: (next) => { | ||
start: next => { | ||
next(); | ||
@@ -216,3 +217,3 @@ }, | ||
next(status); | ||
} | ||
}, | ||
}; | ||
@@ -358,3 +359,3 @@ class ServerInterceptingCall { | ||
details: 'Stream closed before sending status', | ||
metadata: null | ||
metadata: null, | ||
}); | ||
@@ -407,3 +408,3 @@ } | ||
details: `Invalid ${GRPC_TIMEOUT_HEADER} value "${timeoutHeader}"`, | ||
metadata: null | ||
metadata: null, | ||
}; | ||
@@ -423,3 +424,3 @@ // Wait for the constructor to complete before sending the error. | ||
details: 'Deadline exceeded', | ||
metadata: null | ||
metadata: null, | ||
}; | ||
@@ -500,3 +501,5 @@ this.sendStatus(status); | ||
const compressed = queueEntry.compressedMessage.readUInt8(0) === 1; | ||
const compressedMessageEncoding = compressed ? this.incomingEncoding : 'identity'; | ||
const compressedMessageEncoding = compressed | ||
? this.incomingEncoding | ||
: 'identity'; | ||
const decompressedMessage = await this.decompressMessage(queueEntry.compressedMessage, compressedMessageEncoding); | ||
@@ -509,3 +512,3 @@ try { | ||
code: constants_1.Status.INTERNAL, | ||
details: `Error deserializing request: ${err.message}` | ||
details: `Error deserializing request: ${err.message}`, | ||
}); | ||
@@ -518,3 +521,6 @@ return; | ||
maybePushNextMessage() { | ||
if (this.listener && this.isReadPending && this.readQueue.length > 0 && this.readQueue[0].type !== 'COMPRESSED') { | ||
if (this.listener && | ||
this.isReadPending && | ||
this.readQueue.length > 0 && | ||
this.readQueue[0].type !== 'COMPRESSED') { | ||
this.isReadPending = false; | ||
@@ -536,11 +542,15 @@ const nextQueueEntry = this.readQueue.shift(); | ||
} | ||
trace('Request to ' + this.handler.path + ' received data frame of size ' + data.length); | ||
trace('Request to ' + | ||
this.handler.path + | ||
' received data frame of size ' + | ||
data.length); | ||
const rawMessages = this.decoder.write(data); | ||
for (const messageBytes of rawMessages) { | ||
this.stream.pause(); | ||
if (this.maxReceiveMessageSize !== -1 && messageBytes.length - 5 > this.maxReceiveMessageSize) { | ||
if (this.maxReceiveMessageSize !== -1 && | ||
messageBytes.length - 5 > this.maxReceiveMessageSize) { | ||
this.sendStatus({ | ||
code: constants_1.Status.RESOURCE_EXHAUSTED, | ||
details: `Received message larger than max (${messageBytes.length - 5} vs. ${this.maxReceiveMessageSize})`, | ||
metadata: null | ||
metadata: null, | ||
}); | ||
@@ -552,3 +562,3 @@ return; | ||
compressedMessage: messageBytes, | ||
parsedMessage: null | ||
parsedMessage: null, | ||
}; | ||
@@ -564,3 +574,3 @@ this.readQueue.push(queueEntry); | ||
compressedMessage: null, | ||
parsedMessage: null | ||
parsedMessage: null, | ||
}); | ||
@@ -602,3 +612,3 @@ this.receivedHalfClose = true; | ||
details: `Error serializing response: ${(0, error_1.getErrorMessage)(e)}`, | ||
metadata: null | ||
metadata: null, | ||
}); | ||
@@ -612,3 +622,3 @@ return; | ||
details: `Sent message larger than max (${response.length} vs. ${this.maxSendMessageSize})`, | ||
metadata: null | ||
metadata: null, | ||
}); | ||
@@ -618,3 +628,6 @@ return; | ||
this.maybeSendMetadata(); | ||
trace('Request to ' + this.handler.path + ' sent data frame of size ' + response.length); | ||
trace('Request to ' + | ||
this.handler.path + | ||
' sent data frame of size ' + | ||
response.length); | ||
this.stream.write(response, error => { | ||
@@ -626,3 +639,3 @@ var _a; | ||
details: `Error writing message: ${(0, error_1.getErrorMessage)(error)}`, | ||
metadata: null | ||
metadata: null, | ||
}); | ||
@@ -640,3 +653,2 @@ return; | ||
} | ||
this.notifyOnCancel(); | ||
trace('Request to method ' + | ||
@@ -660,5 +672,9 @@ ((_a = this.handler) === null || _a === void 0 ? void 0 : _a.path) + | ||
this.stream.sendTrailers(trailersToSend); | ||
this.notifyOnCancel(); | ||
}); | ||
this.stream.end(); | ||
} | ||
else { | ||
this.notifyOnCancel(); | ||
} | ||
} | ||
@@ -674,2 +690,3 @@ else { | ||
this.stream.respond(trailersToSend, { endStream: true }); | ||
this.notifyOnCancel(); | ||
} | ||
@@ -718,3 +735,3 @@ } | ||
requestDeserialize: handler.deserialize, | ||
responseSerialize: handler.serialize | ||
responseSerialize: handler.serialize, | ||
}; | ||
@@ -721,0 +738,0 @@ const baseCall = new BaseServerInterceptingCall(stream, headers, callEventTracker, handler, options); |
@@ -17,2 +17,3 @@ import { Deserialize, Serialize, ServiceDefinition } from './make-client'; | ||
private http2Servers; | ||
private sessionIdleTimeouts; | ||
private handlers; | ||
@@ -38,2 +39,3 @@ private sessions; | ||
private readonly keepaliveTimeoutMs; | ||
private readonly sessionIdleTimeout; | ||
private readonly interceptors; | ||
@@ -47,3 +49,3 @@ /** | ||
private getChannelzInfo; | ||
private getChannelzSessionInfoGetter; | ||
private getChannelzSessionInfo; | ||
private trace; | ||
@@ -108,2 +110,8 @@ addProtoService(): never; | ||
private _setupHandlers; | ||
private _sessionHandler; | ||
private _channelzSessionHandler; | ||
private enableIdleTimeout; | ||
private onIdleTimeout; | ||
private onStreamOpened; | ||
private onStreamClose; | ||
} |
@@ -256,3 +256,3 @@ "use strict"; | ||
return { | ||
[keys[0]]: obj[keys[0]] | ||
[keys[0]]: obj[keys[0]], | ||
}; | ||
@@ -259,0 +259,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { SubchannelRef } from './channelz'; | ||
import type { SubchannelRef } from './channelz'; | ||
import { ConnectivityState } from './connectivity-state'; | ||
@@ -3,0 +3,0 @@ import { Subchannel } from './subchannel'; |
@@ -76,6 +76,2 @@ "use strict"; | ||
this.channelzEnabled = true; | ||
this.callTracker = new channelz_1.ChannelzCallTracker(); | ||
this.childrenTracker = new channelz_1.ChannelzChildrenTracker(); | ||
// Channelz socket info | ||
this.streamTracker = new channelz_1.ChannelzCallTracker(); | ||
const backoffOptions = { | ||
@@ -93,8 +89,15 @@ initialDelay: options['grpc.initial_reconnect_backoff_ms'], | ||
this.channelzEnabled = false; | ||
this.channelzTrace = new channelz_1.ChannelzTraceStub(); | ||
this.callTracker = new channelz_1.ChannelzCallTrackerStub(); | ||
this.childrenTracker = new channelz_1.ChannelzChildrenTrackerStub(); | ||
this.streamTracker = new channelz_1.ChannelzCallTrackerStub(); | ||
} | ||
this.channelzTrace = new channelz_1.ChannelzTrace(); | ||
else { | ||
this.channelzTrace = new channelz_1.ChannelzTrace(); | ||
this.callTracker = new channelz_1.ChannelzCallTracker(); | ||
this.childrenTracker = new channelz_1.ChannelzChildrenTracker(); | ||
this.streamTracker = new channelz_1.ChannelzCallTracker(); | ||
} | ||
this.channelzRef = (0, channelz_1.registerChannelzSubchannel)(this.subchannelAddressString, () => this.getChannelzInfo(), this.channelzEnabled); | ||
if (this.channelzEnabled) { | ||
this.channelzTrace.addTrace('CT_INFO', 'Subchannel created'); | ||
} | ||
this.channelzTrace.addTrace('CT_INFO', 'Subchannel created'); | ||
this.trace('Subchannel constructed with options ' + | ||
@@ -244,8 +247,4 @@ JSON.stringify(options, undefined, 2)); | ||
if (this.refcount === 0) { | ||
if (this.channelzEnabled) { | ||
this.channelzTrace.addTrace('CT_INFO', 'Shutting down'); | ||
} | ||
if (this.channelzEnabled) { | ||
(0, channelz_1.unregisterChannelzRef)(this.channelzRef); | ||
} | ||
this.channelzTrace.addTrace('CT_INFO', 'Shutting down'); | ||
(0, channelz_1.unregisterChannelzRef)(this.channelzRef); | ||
process.nextTick(() => { | ||
@@ -252,0 +251,0 @@ this.transitionToState([connectivity_state_1.ConnectivityState.CONNECTING, connectivity_state_1.ConnectivityState.READY], connectivity_state_1.ConnectivityState.IDLE); |
@@ -76,3 +76,2 @@ "use strict"; | ||
this.channelzEnabled = true; | ||
this.streamTracker = new channelz_1.ChannelzCallTracker(); | ||
this.keepalivesSent = 0; | ||
@@ -88,3 +87,7 @@ this.messagesSent = 0; | ||
this.channelzEnabled = false; | ||
this.streamTracker = new channelz_1.ChannelzCallTrackerStub(); | ||
} | ||
else { | ||
this.streamTracker = new channelz_1.ChannelzCallTracker(); | ||
} | ||
this.channelzRef = (0, channelz_1.registerChannelzSocket)(this.subchannelAddressString, () => this.getChannelzInfo(), this.channelzEnabled); | ||
@@ -126,3 +129,6 @@ // Build user-agent string. | ||
} | ||
this.trace('connection closed by GOAWAY with code ' + errorCode + ' and data ' + (opaqueData === null || opaqueData === void 0 ? void 0 : opaqueData.toString())); | ||
this.trace('connection closed by GOAWAY with code ' + | ||
errorCode + | ||
' and data ' + | ||
(opaqueData === null || opaqueData === void 0 ? void 0 : opaqueData.toString())); | ||
this.reportDisconnectToOwner(tooManyPings); | ||
@@ -336,5 +342,6 @@ }); | ||
this.keepaliveTrace('Starting keepalive timer for ' + this.keepaliveTimeMs + 'ms'); | ||
this.keepaliveTimerId = (_b = (_a = setTimeout(() => { | ||
this.keepaliveTimerId = setTimeout(() => { | ||
this.maybeSendPing(); | ||
}, this.keepaliveTimeMs)).unref) === null || _b === void 0 ? void 0 : _b.call(_a); | ||
}, this.keepaliveTimeMs); | ||
(_b = (_a = this.keepaliveTimerId).unref) === null || _b === void 0 ? void 0 : _b.call(_a); | ||
} | ||
@@ -341,0 +348,0 @@ /* Otherwise, there is already either a keepalive timer or a ping pending, |
{ | ||
"name": "@grpc/grpc-js", | ||
"version": "1.10.1", | ||
"version": "1.10.2", | ||
"description": "gRPC Library for Node - pure JS implementation", | ||
@@ -9,3 +9,3 @@ "homepage": "https://grpc.io/", | ||
"engines": { | ||
"node": "^8.13.0 || >=10.10.0" | ||
"node": ">=12.10.0" | ||
}, | ||
@@ -19,13 +19,14 @@ "keywords": [], | ||
"devDependencies": { | ||
"@types/gulp": "^4.0.6", | ||
"@types/gulp-mocha": "0.0.32", | ||
"@types/lodash": "^4.14.186", | ||
"@types/mocha": "^5.2.6", | ||
"@types/ncp": "^2.0.1", | ||
"@types/pify": "^3.0.2", | ||
"@types/semver": "^7.3.9", | ||
"@typescript-eslint/eslint-plugin": "^5.59.11", | ||
"@typescript-eslint/parser": "^5.59.11", | ||
"@typescript-eslint/typescript-estree": "^5.59.11", | ||
"clang-format": "^1.0.55", | ||
"@types/gulp": "^4.0.17", | ||
"@types/gulp-mocha": "0.0.37", | ||
"@types/lodash": "^4.14.202", | ||
"@types/mocha": "^10.0.6", | ||
"@types/ncp": "^2.0.8", | ||
"@types/node": ">=20.11.20", | ||
"@types/pify": "^5.0.4", | ||
"@types/semver": "^7.5.8", | ||
"@typescript-eslint/eslint-plugin": "^7.1.0", | ||
"@typescript-eslint/parser": "^7.1.0", | ||
"@typescript-eslint/typescript-estree": "^7.1.0", | ||
"clang-format": "^1.8.0", | ||
"eslint": "^8.42.0", | ||
@@ -38,3 +39,3 @@ "eslint-config-prettier": "^8.8.0", | ||
"gulp-mocha": "^6.0.0", | ||
"lodash": "^4.17.4", | ||
"lodash": "^4.17.21", | ||
"madge": "^5.0.1", | ||
@@ -46,5 +47,5 @@ "mocha-jenkins-reporter": "^0.4.1", | ||
"rimraf": "^3.0.2", | ||
"semver": "^7.3.5", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^5.1.3" | ||
"semver": "^7.6.0", | ||
"ts-node": "^10.9.2", | ||
"typescript": "^5.3.3" | ||
}, | ||
@@ -72,4 +73,4 @@ "contributors": [ | ||
"dependencies": { | ||
"@grpc/proto-loader": "^0.7.8", | ||
"@types/node": ">=12.12.47" | ||
"@grpc/proto-loader": "^0.7.10", | ||
"@js-sdsl/ordered-map": "^4.4.2" | ||
}, | ||
@@ -76,0 +77,0 @@ "files": [ |
@@ -63,2 +63,5 @@ # Pure JavaScript gRPC Client | ||
- `grpc.enable_retries` | ||
- `grpc.max_connection_age_ms` | ||
- `grpc.max_connection_age_grace_ms` | ||
- `grpc.max_connection_idle_ms` | ||
- `grpc.per_rpc_retry_buffer_size` | ||
@@ -65,0 +68,0 @@ - `grpc.retry_buffer_size` |
@@ -109,3 +109,5 @@ /* | ||
this.endTime = this.startTime; | ||
this.endTime.setMilliseconds(this.endTime.getMilliseconds() + this.nextDelay); | ||
this.endTime.setMilliseconds( | ||
this.endTime.getMilliseconds() + this.nextDelay | ||
); | ||
clearTimeout(this.timerId); | ||
@@ -112,0 +114,0 @@ this.timerId = setTimeout(() => { |
@@ -57,2 +57,3 @@ /* | ||
'grpc.max_connection_age_grace_ms'?: number; | ||
'grpc.max_connection_idle_ms'?: number; | ||
'grpc-node.max_session_memory'?: number; | ||
@@ -59,0 +60,0 @@ 'grpc.service_config_disable_resolution'?: number; |
@@ -23,3 +23,3 @@ /* | ||
import { ConnectivityState } from './connectivity-state'; | ||
import { ChannelRef } from './channelz'; | ||
import type { ChannelRef } from './channelz'; | ||
import { Call } from './call-interface'; | ||
@@ -26,0 +26,0 @@ import { InternalChannel } from './internal-channel'; |
@@ -19,2 +19,3 @@ /* | ||
import { isIPv4, isIPv6 } from 'net'; | ||
import { OrderedMap, type OrderedMapIterator } from '@js-sdsl/ordered-map'; | ||
import { ConnectivityState } from './connectivity-state'; | ||
@@ -69,4 +70,4 @@ import { Status } from './constants'; | ||
export interface ChannelRef { | ||
kind: 'channel'; | ||
interface Ref { | ||
kind: EntityTypes; | ||
id: number; | ||
@@ -76,19 +77,18 @@ name: string; | ||
export interface SubchannelRef { | ||
kind: 'subchannel'; | ||
id: number; | ||
name: string; | ||
export interface ChannelRef extends Ref { | ||
kind: EntityTypes.channel; | ||
} | ||
export interface ServerRef { | ||
kind: 'server'; | ||
id: number; | ||
export interface SubchannelRef extends Ref { | ||
kind: EntityTypes.subchannel; | ||
} | ||
export interface SocketRef { | ||
kind: 'socket'; | ||
id: number; | ||
name: string; | ||
export interface ServerRef extends Ref { | ||
kind: EntityTypes.server; | ||
} | ||
export interface SocketRef extends Ref { | ||
kind: EntityTypes.socket; | ||
} | ||
function channelRefToMessage(ref: ChannelRef): ChannelRefMessage { | ||
@@ -137,2 +137,22 @@ return { | ||
/** | ||
* Default number of sockets/servers/channels/subchannels to return | ||
*/ | ||
const DEFAULT_MAX_RESULTS = 100; | ||
export class ChannelzTraceStub { | ||
readonly events: TraceEvent[] = []; | ||
readonly creationTimestamp: Date = new Date(); | ||
readonly eventsLogged = 0; | ||
addTrace(): void {} | ||
getTraceMessage(): ChannelTrace { | ||
return { | ||
creation_timestamp: dateToProtoTimestamp(this.creationTimestamp), | ||
num_events_logged: this.eventsLogged, | ||
events: [], | ||
}; | ||
} | ||
} | ||
export class ChannelzTrace { | ||
@@ -188,41 +208,32 @@ events: TraceEvent[] = []; | ||
type RefOrderedMap = OrderedMap< | ||
number, | ||
{ ref: { id: number; kind: EntityTypes; name: string }; count: number } | ||
>; | ||
export class ChannelzChildrenTracker { | ||
private channelChildren: Map<number, { ref: ChannelRef; count: number }> = | ||
new Map<number, { ref: ChannelRef; count: number }>(); | ||
private subchannelChildren: Map< | ||
number, | ||
{ ref: SubchannelRef; count: number } | ||
> = new Map<number, { ref: SubchannelRef; count: number }>(); | ||
private socketChildren: Map<number, { ref: SocketRef; count: number }> = | ||
new Map<number, { ref: SocketRef; count: number }>(); | ||
private channelChildren: RefOrderedMap = new OrderedMap(); | ||
private subchannelChildren: RefOrderedMap = new OrderedMap(); | ||
private socketChildren: RefOrderedMap = new OrderedMap(); | ||
private trackerMap = { | ||
[EntityTypes.channel]: this.channelChildren, | ||
[EntityTypes.subchannel]: this.subchannelChildren, | ||
[EntityTypes.socket]: this.socketChildren, | ||
} as const; | ||
refChild(child: ChannelRef | SubchannelRef | SocketRef) { | ||
switch (child.kind) { | ||
case 'channel': { | ||
const trackedChild = this.channelChildren.get(child.id) ?? { | ||
const tracker = this.trackerMap[child.kind]; | ||
const trackedChild = tracker.find(child.id); | ||
if (trackedChild.equals(tracker.end())) { | ||
tracker.setElement( | ||
child.id, | ||
{ | ||
ref: child, | ||
count: 0, | ||
}; | ||
trackedChild.count += 1; | ||
this.channelChildren.set(child.id, trackedChild); | ||
break; | ||
} | ||
case 'subchannel': { | ||
const trackedChild = this.subchannelChildren.get(child.id) ?? { | ||
ref: child, | ||
count: 0, | ||
}; | ||
trackedChild.count += 1; | ||
this.subchannelChildren.set(child.id, trackedChild); | ||
break; | ||
} | ||
case 'socket': { | ||
const trackedChild = this.socketChildren.get(child.id) ?? { | ||
ref: child, | ||
count: 0, | ||
}; | ||
trackedChild.count += 1; | ||
this.socketChildren.set(child.id, trackedChild); | ||
break; | ||
} | ||
count: 1, | ||
}, | ||
trackedChild | ||
); | ||
} else { | ||
trackedChild.pointer[1].count += 1; | ||
} | ||
@@ -232,39 +243,9 @@ } | ||
unrefChild(child: ChannelRef | SubchannelRef | SocketRef) { | ||
switch (child.kind) { | ||
case 'channel': { | ||
const trackedChild = this.channelChildren.get(child.id); | ||
if (trackedChild !== undefined) { | ||
trackedChild.count -= 1; | ||
if (trackedChild.count === 0) { | ||
this.channelChildren.delete(child.id); | ||
} else { | ||
this.channelChildren.set(child.id, trackedChild); | ||
} | ||
} | ||
break; | ||
const tracker = this.trackerMap[child.kind]; | ||
const trackedChild = tracker.getElementByKey(child.id); | ||
if (trackedChild !== undefined) { | ||
trackedChild.count -= 1; | ||
if (trackedChild.count === 0) { | ||
tracker.eraseElementByKey(child.id); | ||
} | ||
case 'subchannel': { | ||
const trackedChild = this.subchannelChildren.get(child.id); | ||
if (trackedChild !== undefined) { | ||
trackedChild.count -= 1; | ||
if (trackedChild.count === 0) { | ||
this.subchannelChildren.delete(child.id); | ||
} else { | ||
this.subchannelChildren.set(child.id, trackedChild); | ||
} | ||
} | ||
break; | ||
} | ||
case 'socket': { | ||
const trackedChild = this.socketChildren.get(child.id); | ||
if (trackedChild !== undefined) { | ||
trackedChild.count -= 1; | ||
if (trackedChild.count === 0) { | ||
this.socketChildren.delete(child.id); | ||
} else { | ||
this.socketChildren.set(child.id, trackedChild); | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
@@ -274,18 +255,15 @@ } | ||
getChildLists(): ChannelzChildren { | ||
const channels: ChannelRef[] = []; | ||
for (const { ref } of this.channelChildren.values()) { | ||
channels.push(ref); | ||
} | ||
const subchannels: SubchannelRef[] = []; | ||
for (const { ref } of this.subchannelChildren.values()) { | ||
subchannels.push(ref); | ||
} | ||
const sockets: SocketRef[] = []; | ||
for (const { ref } of this.socketChildren.values()) { | ||
sockets.push(ref); | ||
} | ||
return { channels, subchannels, sockets }; | ||
return { | ||
channels: this.channelChildren as ChannelzChildren['channels'], | ||
subchannels: this.subchannelChildren as ChannelzChildren['subchannels'], | ||
sockets: this.socketChildren as ChannelzChildren['sockets'], | ||
}; | ||
} | ||
} | ||
export class ChannelzChildrenTrackerStub extends ChannelzChildrenTracker { | ||
override refChild(): void {} | ||
override unrefChild(): void {} | ||
} | ||
export class ChannelzCallTracker { | ||
@@ -309,6 +287,12 @@ callsStarted = 0; | ||
export class ChannelzCallTrackerStub extends ChannelzCallTracker { | ||
override addCallStarted() {} | ||
override addCallSucceeded() {} | ||
override addCallFailed() {} | ||
} | ||
export interface ChannelzChildren { | ||
channels: ChannelRef[]; | ||
subchannels: SubchannelRef[]; | ||
sockets: SocketRef[]; | ||
channels: OrderedMap<number, { ref: ChannelRef; count: number }>; | ||
subchannels: OrderedMap<number, { ref: SubchannelRef; count: number }>; | ||
sockets: OrderedMap<number, { ref: SocketRef; count: number }>; | ||
} | ||
@@ -319,4 +303,4 @@ | ||
state: ConnectivityState; | ||
trace: ChannelzTrace; | ||
callTracker: ChannelzCallTracker; | ||
trace: ChannelzTrace | ChannelzTraceStub; | ||
callTracker: ChannelzCallTracker | ChannelzCallTrackerStub; | ||
children: ChannelzChildren; | ||
@@ -380,81 +364,81 @@ } | ||
let nextId = 1; | ||
function getNextId(): number { | ||
return nextId++; | ||
export const enum EntityTypes { | ||
channel = 'channel', | ||
subchannel = 'subchannel', | ||
server = 'server', | ||
socket = 'socket', | ||
} | ||
const channels: (ChannelEntry | undefined)[] = []; | ||
const subchannels: (SubchannelEntry | undefined)[] = []; | ||
const servers: (ServerEntry | undefined)[] = []; | ||
const sockets: (SocketEntry | undefined)[] = []; | ||
type EntryOrderedMap = OrderedMap<number, { ref: Ref; getInfo: () => any }>; | ||
export function registerChannelzChannel( | ||
name: string, | ||
getInfo: () => ChannelInfo, | ||
channelzEnabled: boolean | ||
): ChannelRef { | ||
const id = getNextId(); | ||
const ref: ChannelRef = { id, name, kind: 'channel' }; | ||
if (channelzEnabled) { | ||
channels[id] = { ref, getInfo }; | ||
} | ||
return ref; | ||
} | ||
const entityMaps = { | ||
[EntityTypes.channel]: new OrderedMap<number, ChannelEntry>(), | ||
[EntityTypes.subchannel]: new OrderedMap<number, SubchannelEntry>(), | ||
[EntityTypes.server]: new OrderedMap<number, ServerEntry>(), | ||
[EntityTypes.socket]: new OrderedMap<number, SocketEntry>(), | ||
} as const; | ||
export function registerChannelzSubchannel( | ||
name: string, | ||
getInfo: () => SubchannelInfo, | ||
channelzEnabled: boolean | ||
): SubchannelRef { | ||
const id = getNextId(); | ||
const ref: SubchannelRef = { id, name, kind: 'subchannel' }; | ||
if (channelzEnabled) { | ||
subchannels[id] = { ref, getInfo }; | ||
} | ||
return ref; | ||
} | ||
export type RefByType<T extends EntityTypes> = T extends EntityTypes.channel | ||
? ChannelRef | ||
: T extends EntityTypes.server | ||
? ServerRef | ||
: T extends EntityTypes.socket | ||
? SocketRef | ||
: T extends EntityTypes.subchannel | ||
? SubchannelRef | ||
: never; | ||
export function registerChannelzServer( | ||
getInfo: () => ServerInfo, | ||
channelzEnabled: boolean | ||
): ServerRef { | ||
const id = getNextId(); | ||
const ref: ServerRef = { id, kind: 'server' }; | ||
if (channelzEnabled) { | ||
servers[id] = { ref, getInfo }; | ||
} | ||
return ref; | ||
} | ||
export type EntryByType<T extends EntityTypes> = T extends EntityTypes.channel | ||
? ChannelEntry | ||
: T extends EntityTypes.server | ||
? ServerEntry | ||
: T extends EntityTypes.socket | ||
? SocketEntry | ||
: T extends EntityTypes.subchannel | ||
? SubchannelEntry | ||
: never; | ||
export function registerChannelzSocket( | ||
name: string, | ||
getInfo: () => SocketInfo, | ||
channelzEnabled: boolean | ||
): SocketRef { | ||
const id = getNextId(); | ||
const ref: SocketRef = { id, name, kind: 'socket' }; | ||
if (channelzEnabled) { | ||
sockets[id] = { ref, getInfo }; | ||
export type InfoByType<T extends EntityTypes> = T extends EntityTypes.channel | ||
? ChannelInfo | ||
: T extends EntityTypes.subchannel | ||
? SubchannelInfo | ||
: T extends EntityTypes.server | ||
? ServerInfo | ||
: T extends EntityTypes.socket | ||
? SocketInfo | ||
: never; | ||
const generateRegisterFn = <R extends EntityTypes>(kind: R) => { | ||
let nextId = 1; | ||
function getNextId(): number { | ||
return nextId++; | ||
} | ||
return ref; | ||
} | ||
const entityMap: EntryOrderedMap = entityMaps[kind]; | ||
return ( | ||
name: string, | ||
getInfo: () => InfoByType<R>, | ||
channelzEnabled: boolean | ||
): RefByType<R> => { | ||
const id = getNextId(); | ||
const ref = { id, name, kind } as RefByType<R>; | ||
if (channelzEnabled) { | ||
entityMap.setElement(id, { ref, getInfo }); | ||
} | ||
return ref; | ||
}; | ||
}; | ||
export const registerChannelzChannel = generateRegisterFn(EntityTypes.channel); | ||
export const registerChannelzSubchannel = generateRegisterFn( | ||
EntityTypes.subchannel | ||
); | ||
export const registerChannelzServer = generateRegisterFn(EntityTypes.server); | ||
export const registerChannelzSocket = generateRegisterFn(EntityTypes.socket); | ||
export function unregisterChannelzRef( | ||
ref: ChannelRef | SubchannelRef | ServerRef | SocketRef | ||
) { | ||
switch (ref.kind) { | ||
case 'channel': | ||
delete channels[ref.id]; | ||
return; | ||
case 'subchannel': | ||
delete subchannels[ref.id]; | ||
return; | ||
case 'server': | ||
delete servers[ref.id]; | ||
return; | ||
case 'socket': | ||
delete sockets[ref.id]; | ||
return; | ||
} | ||
entityMaps[ref.kind].eraseElementByKey(ref.id); | ||
} | ||
@@ -569,2 +553,13 @@ | ||
const resolvedInfo = channelEntry.getInfo(); | ||
const channelRef: ChannelRefMessage[] = []; | ||
const subchannelRef: SubchannelRefMessage[] = []; | ||
resolvedInfo.children.channels.forEach(el => { | ||
channelRef.push(channelRefToMessage(el[1].ref)); | ||
}); | ||
resolvedInfo.children.subchannels.forEach(el => { | ||
subchannelRef.push(subchannelRefToMessage(el[1].ref)); | ||
}); | ||
return { | ||
@@ -583,8 +578,4 @@ ref: channelRefToMessage(channelEntry.ref), | ||
}, | ||
channel_ref: resolvedInfo.children.channels.map(ref => | ||
channelRefToMessage(ref) | ||
), | ||
subchannel_ref: resolvedInfo.children.subchannels.map(ref => | ||
subchannelRefToMessage(ref) | ||
), | ||
channel_ref: channelRef, | ||
subchannel_ref: subchannelRef, | ||
}; | ||
@@ -597,4 +588,5 @@ } | ||
): void { | ||
const channelId = Number.parseInt(call.request.channel_id); | ||
const channelEntry = channels[channelId]; | ||
const channelId = parseInt(call.request.channel_id, 10); | ||
const channelEntry = | ||
entityMaps[EntityTypes.channel].getElementByKey(channelId); | ||
if (channelEntry === undefined) { | ||
@@ -614,18 +606,20 @@ callback({ | ||
): void { | ||
const maxResults = Number.parseInt(call.request.max_results); | ||
const maxResults = | ||
parseInt(call.request.max_results, 10) || DEFAULT_MAX_RESULTS; | ||
const resultList: ChannelMessage[] = []; | ||
let i = Number.parseInt(call.request.start_channel_id); | ||
for (; i < channels.length; i++) { | ||
const channelEntry = channels[i]; | ||
if (channelEntry === undefined) { | ||
continue; | ||
} | ||
resultList.push(getChannelMessage(channelEntry)); | ||
if (resultList.length >= maxResults) { | ||
break; | ||
} | ||
const startId = parseInt(call.request.start_channel_id, 10); | ||
const channelEntries = entityMaps[EntityTypes.channel]; | ||
let i: OrderedMapIterator<number, ChannelEntry>; | ||
for ( | ||
i = channelEntries.lowerBound(startId); | ||
!i.equals(channelEntries.end()) && resultList.length < maxResults; | ||
i = i.next() | ||
) { | ||
resultList.push(getChannelMessage(i.pointer[1])); | ||
} | ||
callback(null, { | ||
channel: resultList, | ||
end: i >= servers.length, | ||
end: i.equals(channelEntries.end()), | ||
}); | ||
@@ -636,2 +630,8 @@ } | ||
const resolvedInfo = serverEntry.getInfo(); | ||
const listenSocket: SocketRefMessage[] = []; | ||
resolvedInfo.listenerChildren.sockets.forEach(el => { | ||
listenSocket.push(socketRefToMessage(el[1].ref)); | ||
}); | ||
return { | ||
@@ -648,5 +648,3 @@ ref: serverRefToMessage(serverEntry.ref), | ||
}, | ||
listen_socket: resolvedInfo.listenerChildren.sockets.map(ref => | ||
socketRefToMessage(ref) | ||
), | ||
listen_socket: listenSocket, | ||
}; | ||
@@ -659,4 +657,5 @@ } | ||
): void { | ||
const serverId = Number.parseInt(call.request.server_id); | ||
const serverEntry = servers[serverId]; | ||
const serverId = parseInt(call.request.server_id, 10); | ||
const serverEntries = entityMaps[EntityTypes.server]; | ||
const serverEntry = serverEntries.getElementByKey(serverId); | ||
if (serverEntry === undefined) { | ||
@@ -676,18 +675,20 @@ callback({ | ||
): void { | ||
const maxResults = Number.parseInt(call.request.max_results); | ||
const maxResults = | ||
parseInt(call.request.max_results, 10) || DEFAULT_MAX_RESULTS; | ||
const startId = parseInt(call.request.start_server_id, 10); | ||
const serverEntries = entityMaps[EntityTypes.server]; | ||
const resultList: ServerMessage[] = []; | ||
let i = Number.parseInt(call.request.start_server_id); | ||
for (; i < servers.length; i++) { | ||
const serverEntry = servers[i]; | ||
if (serverEntry === undefined) { | ||
continue; | ||
} | ||
resultList.push(getServerMessage(serverEntry)); | ||
if (resultList.length >= maxResults) { | ||
break; | ||
} | ||
let i: OrderedMapIterator<number, ServerEntry>; | ||
for ( | ||
i = serverEntries.lowerBound(startId); | ||
!i.equals(serverEntries.end()) && resultList.length < maxResults; | ||
i = i.next() | ||
) { | ||
resultList.push(getServerMessage(i.pointer[1])); | ||
} | ||
callback(null, { | ||
server: resultList, | ||
end: i >= servers.length, | ||
end: i.equals(serverEntries.end()), | ||
}); | ||
@@ -700,4 +701,5 @@ } | ||
): void { | ||
const subchannelId = Number.parseInt(call.request.subchannel_id); | ||
const subchannelEntry = subchannels[subchannelId]; | ||
const subchannelId = parseInt(call.request.subchannel_id, 10); | ||
const subchannelEntry = | ||
entityMaps[EntityTypes.subchannel].getElementByKey(subchannelId); | ||
if (subchannelEntry === undefined) { | ||
@@ -711,2 +713,8 @@ callback({ | ||
const resolvedInfo = subchannelEntry.getInfo(); | ||
const listenSocket: SocketRefMessage[] = []; | ||
resolvedInfo.children.sockets.forEach(el => { | ||
listenSocket.push(socketRefToMessage(el[1].ref)); | ||
}); | ||
const subchannelMessage: SubchannelMessage = { | ||
@@ -725,5 +733,3 @@ ref: subchannelRefToMessage(subchannelEntry.ref), | ||
}, | ||
socket_ref: resolvedInfo.children.sockets.map(ref => | ||
socketRefToMessage(ref) | ||
), | ||
socket_ref: listenSocket, | ||
}; | ||
@@ -759,4 +765,4 @@ callback(null, { subchannel: subchannelMessage }); | ||
): void { | ||
const socketId = Number.parseInt(call.request.socket_id); | ||
const socketEntry = sockets[socketId]; | ||
const socketId = parseInt(call.request.socket_id, 10); | ||
const socketEntry = entityMaps[EntityTypes.socket].getElementByKey(socketId); | ||
if (socketEntry === undefined) { | ||
@@ -834,4 +840,5 @@ callback({ | ||
): void { | ||
const serverId = Number.parseInt(call.request.server_id); | ||
const serverEntry = servers[serverId]; | ||
const serverId = parseInt(call.request.server_id, 10); | ||
const serverEntry = entityMaps[EntityTypes.server].getElementByKey(serverId); | ||
if (serverEntry === undefined) { | ||
@@ -844,4 +851,6 @@ callback({ | ||
} | ||
const startId = Number.parseInt(call.request.start_socket_id); | ||
const maxResults = Number.parseInt(call.request.max_results); | ||
const startId = parseInt(call.request.start_socket_id, 10); | ||
const maxResults = | ||
parseInt(call.request.max_results, 10) || DEFAULT_MAX_RESULTS; | ||
const resolvedInfo = serverEntry.getInfo(); | ||
@@ -851,18 +860,17 @@ // If we wanted to include listener sockets in the result, this line would | ||
// const allSockets = resolvedInfo.listenerChildren.sockets.concat(resolvedInfo.sessionChildren.sockets).sort((ref1, ref2) => ref1.id - ref2.id); | ||
const allSockets = resolvedInfo.sessionChildren.sockets.sort( | ||
(ref1, ref2) => ref1.id - ref2.id | ||
); | ||
const allSockets = resolvedInfo.sessionChildren.sockets; | ||
const resultList: SocketRefMessage[] = []; | ||
let i = 0; | ||
for (; i < allSockets.length; i++) { | ||
if (allSockets[i].id >= startId) { | ||
resultList.push(socketRefToMessage(allSockets[i])); | ||
if (resultList.length >= maxResults) { | ||
break; | ||
} | ||
} | ||
let i: OrderedMapIterator<number, { ref: SocketRef }>; | ||
for ( | ||
i = allSockets.lowerBound(startId); | ||
!i.equals(allSockets.end()) && resultList.length < maxResults; | ||
i = i.next() | ||
) { | ||
resultList.push(socketRefToMessage(i.pointer[1].ref)); | ||
} | ||
callback(null, { | ||
socket_ref: resultList, | ||
end: i >= allSockets.length, | ||
end: i.equals(allSockets.end()), | ||
}); | ||
@@ -869,0 +877,0 @@ } |
@@ -186,3 +186,3 @@ /* | ||
UntypedServiceImplementation, | ||
VerifyOptions | ||
VerifyOptions, | ||
}; | ||
@@ -267,3 +267,8 @@ | ||
export { ServiceConfig, LoadBalancingConfig, MethodConfig, RetryPolicy } from './service-config'; | ||
export { | ||
ServiceConfig, | ||
LoadBalancingConfig, | ||
MethodConfig, | ||
RetryPolicy, | ||
} from './service-config'; | ||
@@ -279,3 +284,3 @@ export { | ||
ServerInterceptingCall, | ||
ServerInterceptor | ||
ServerInterceptor, | ||
} from './server-interceptors'; | ||
@@ -282,0 +287,0 @@ |
@@ -586,3 +586,4 @@ /* | ||
const now = new Date(); | ||
const timeSinceLastActivity = now.valueOf() - this.lastActivityTimestamp.valueOf(); | ||
const timeSinceLastActivity = | ||
now.valueOf() - this.lastActivityTimestamp.valueOf(); | ||
if (timeSinceLastActivity >= this.idleTimeoutMs) { | ||
@@ -607,3 +608,6 @@ this.trace( | ||
private maybeStartIdleTimer() { | ||
if (this.connectivityState !== ConnectivityState.SHUTDOWN && !this.idleTimer) { | ||
if ( | ||
this.connectivityState !== ConnectivityState.SHUTDOWN && | ||
!this.idleTimer | ||
) { | ||
this.startIdleTimeout(this.idleTimeoutMs); | ||
@@ -610,0 +614,0 @@ } |
@@ -28,3 +28,3 @@ /* | ||
import { Picker } from './picker'; | ||
import { ChannelRef, SubchannelRef } from './channelz'; | ||
import type { ChannelRef, SubchannelRef } from './channelz'; | ||
import { SubchannelInterface } from './subchannel-interface'; | ||
@@ -31,0 +31,0 @@ |
@@ -201,3 +201,8 @@ /* | ||
) => { | ||
this.onSubchannelStateUpdate(subchannel, previousState, newState, errorMessage); | ||
this.onSubchannelStateUpdate( | ||
subchannel, | ||
previousState, | ||
newState, | ||
errorMessage | ||
); | ||
}; | ||
@@ -279,3 +284,5 @@ | ||
ConnectivityState.TRANSIENT_FAILURE, | ||
new UnavailablePicker({details: `No connection established. Last error: ${this.lastError}`}) | ||
new UnavailablePicker({ | ||
details: `No connection established. Last error: ${this.lastError}`, | ||
}) | ||
); | ||
@@ -346,3 +353,2 @@ } else { | ||
this.calculateAndReportNewState(); | ||
this.requestReresolution(); | ||
} | ||
@@ -414,3 +420,4 @@ return; | ||
this.startNextSubchannelConnecting(subchannelIndex + 1); | ||
}, CONNECTION_DELAY_INTERVAL_MS).unref?.(); | ||
}, CONNECTION_DELAY_INTERVAL_MS); | ||
this.connectionDelayTimeout.unref?.(); | ||
} | ||
@@ -448,3 +455,8 @@ | ||
for (const child of this.children) { | ||
if (!(this.currentPick && child.subchannel.realSubchannelEquals(this.currentPick))) { | ||
if ( | ||
!( | ||
this.currentPick && | ||
child.subchannel.realSubchannelEquals(this.currentPick) | ||
) | ||
) { | ||
/* The connectivity state listener is the same whether the subchannel | ||
@@ -531,3 +543,6 @@ * is in the list of children or it is the currentPick, so if it is in | ||
exitIdle() { | ||
if (this.currentState === ConnectivityState.IDLE && this.latestAddressList) { | ||
if ( | ||
this.currentState === ConnectivityState.IDLE && | ||
this.latestAddressList | ||
) { | ||
this.connectToAddressList(this.latestAddressList); | ||
@@ -534,0 +549,0 @@ } |
@@ -159,3 +159,5 @@ /* | ||
ConnectivityState.TRANSIENT_FAILURE, | ||
new UnavailablePicker({details: `No connection established. Last error: ${this.lastError}`}) | ||
new UnavailablePicker({ | ||
details: `No connection established. Last error: ${this.lastError}`, | ||
}) | ||
); | ||
@@ -162,0 +164,0 @@ } else { |
@@ -22,3 +22,3 @@ /* | ||
import { Picker } from './picker'; | ||
import { ChannelRef, SubchannelRef } from './channelz'; | ||
import type { ChannelRef, SubchannelRef } from './channelz'; | ||
import { SubchannelInterface } from './subchannel-interface'; | ||
@@ -25,0 +25,0 @@ import { LoadBalancingConfig } from './service-config'; |
@@ -148,3 +148,5 @@ /* | ||
if (this.ended) { | ||
this.trace('Credentials metadata generation finished after call ended'); | ||
this.trace( | ||
'Credentials metadata generation finished after call ended' | ||
); | ||
return; | ||
@@ -151,0 +153,0 @@ } |
@@ -115,3 +115,14 @@ /* | ||
if (isTracerEnabled(tracer)) { | ||
log(severity, new Date().toISOString() + ' | v' + clientVersion + ' ' + pid + ' | ' + tracer + ' | ' + text); | ||
log( | ||
severity, | ||
new Date().toISOString() + | ||
' | v' + | ||
clientVersion + | ||
' ' + | ||
pid + | ||
' | ' + | ||
tracer + | ||
' | ' + | ||
text | ||
); | ||
} | ||
@@ -118,0 +129,0 @@ } |
@@ -312,3 +312,4 @@ /* | ||
} | ||
}, this.minTimeBetweenResolutionsMs).unref?.(); | ||
}, this.minTimeBetweenResolutionsMs); | ||
this.nextResolutionTimer.unref?.(); | ||
this.isNextResolutionTimerRunning = true; | ||
@@ -339,5 +340,10 @@ } | ||
if (this.isNextResolutionTimerRunning) { | ||
trace('resolution update delayed by "min time between resolutions" rate limit'); | ||
trace( | ||
'resolution update delayed by "min time between resolutions" rate limit' | ||
); | ||
} else { | ||
trace('resolution update delayed by backoff timer until ' + this.backoff.getEndTime().toISOString()); | ||
trace( | ||
'resolution update delayed by backoff timer until ' + | ||
this.backoff.getEndTime().toISOString() | ||
); | ||
} | ||
@@ -344,0 +350,0 @@ this.continueResolving = true; |
@@ -215,2 +215,3 @@ /* | ||
} | ||
this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); | ||
@@ -227,4 +228,7 @@ this.childLoadBalancer = new ChildLoadBalancerHandler( | ||
if (this.backoffTimeout.isRunning()) { | ||
trace('requestReresolution delayed by backoff timer until ' + this.backoffTimeout.getEndTime().toISOString()); | ||
this.continueResolving = true; | ||
trace( | ||
'requestReresolution delayed by backoff timer until ' + | ||
this.backoffTimeout.getEndTime().toISOString() | ||
); | ||
this.continueResolving = true; | ||
} else { | ||
@@ -231,0 +235,0 @@ this.updateResolution(); |
@@ -21,11 +21,9 @@ /* | ||
import { | ||
Status, | ||
} from './constants'; | ||
import { Deserialize, Serialize } from './make-client'; | ||
import { Status } from './constants'; | ||
import type { Deserialize, Serialize } from './make-client'; | ||
import { Metadata } from './metadata'; | ||
import { ObjectReadable, ObjectWritable } from './object-stream'; | ||
import { StatusObject, PartialStatusObject } from './call-interface'; | ||
import { Deadline } from './deadline'; | ||
import { ServerInterceptingCallInterface } from './server-interceptors'; | ||
import type { ObjectReadable, ObjectWritable } from './object-stream'; | ||
import type { StatusObject, PartialStatusObject } from './call-interface'; | ||
import type { Deadline } from './deadline'; | ||
import type { ServerInterceptingCallInterface } from './server-interceptors'; | ||
@@ -60,7 +58,10 @@ export type ServerStatusResponse = Partial<StatusObject>; | ||
export function serverErrorToStatus(error: ServerErrorResponse | ServerStatusResponse, overrideTrailers?: Metadata | undefined): PartialStatusObject { | ||
export function serverErrorToStatus( | ||
error: ServerErrorResponse | ServerStatusResponse, | ||
overrideTrailers?: Metadata | undefined | ||
): PartialStatusObject { | ||
const status: PartialStatusObject = { | ||
code: Status.UNKNOWN, | ||
details: 'message' in error ? error.message : 'Unknown Error', | ||
metadata: overrideTrailers ?? error.metadata ?? null | ||
metadata: overrideTrailers ?? error.metadata ?? null, | ||
}; | ||
@@ -159,3 +160,3 @@ | ||
code: Status.OK, | ||
details: 'OK' | ||
details: 'OK', | ||
}; | ||
@@ -205,2 +206,3 @@ | ||
_final(callback: Function): void { | ||
callback(null); | ||
this.call.sendStatus({ | ||
@@ -210,3 +212,2 @@ ...this.pendingStatus, | ||
}); | ||
callback(null); | ||
} | ||
@@ -232,3 +233,3 @@ | ||
code: Status.OK, | ||
details: 'OK' | ||
details: 'OK', | ||
}; | ||
@@ -281,2 +282,3 @@ | ||
_final(callback: Function): void { | ||
callback(null); | ||
this.call.sendStatus({ | ||
@@ -286,3 +288,2 @@ ...this.pendingStatus, | ||
}); | ||
callback(null); | ||
} | ||
@@ -340,3 +341,3 @@ | ||
deserialize: Deserialize<RequestType>; | ||
type: HandlerType; | ||
type: 'unary'; | ||
path: string; | ||
@@ -349,3 +350,3 @@ } | ||
deserialize: Deserialize<RequestType>; | ||
type: HandlerType; | ||
type: 'clientStream'; | ||
path: string; | ||
@@ -358,3 +359,3 @@ } | ||
deserialize: Deserialize<RequestType>; | ||
type: HandlerType; | ||
type: 'serverStream'; | ||
path: string; | ||
@@ -367,3 +368,3 @@ } | ||
deserialize: Deserialize<RequestType>; | ||
type: HandlerType; | ||
type: 'bidi'; | ||
path: string; | ||
@@ -370,0 +371,0 @@ } |
@@ -18,15 +18,20 @@ /* | ||
import { PartialStatusObject} from "./call-interface"; | ||
import { ServerMethodDefinition } from "./make-client"; | ||
import { Metadata } from "./metadata"; | ||
import { ChannelOptions } from "./channel-options"; | ||
import { Handler, ServerErrorResponse } from "./server-call"; | ||
import { Deadline } from "./deadline"; | ||
import { DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, DEFAULT_MAX_SEND_MESSAGE_LENGTH, LogVerbosity, Status } from "./constants"; | ||
import { PartialStatusObject } from './call-interface'; | ||
import { ServerMethodDefinition } from './make-client'; | ||
import { Metadata } from './metadata'; | ||
import { ChannelOptions } from './channel-options'; | ||
import { Handler, ServerErrorResponse } from './server-call'; | ||
import { Deadline } from './deadline'; | ||
import { | ||
DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, | ||
DEFAULT_MAX_SEND_MESSAGE_LENGTH, | ||
LogVerbosity, | ||
Status, | ||
} from './constants'; | ||
import * as http2 from 'http2'; | ||
import { getErrorMessage } from "./error"; | ||
import { getErrorMessage } from './error'; | ||
import * as zlib from 'zlib'; | ||
import { promisify } from "util"; | ||
import { StreamDecoder } from "./stream-decoder"; | ||
import { CallEventTracker } from "./transport"; | ||
import { promisify } from 'util'; | ||
import { StreamDecoder } from './stream-decoder'; | ||
import { CallEventTracker } from './transport'; | ||
import * as logging from './logging'; | ||
@@ -100,3 +105,3 @@ | ||
onReceiveHalfClose: this.halfClose, | ||
onCancel: this.cancel | ||
onCancel: this.cancel, | ||
}; | ||
@@ -114,4 +119,9 @@ } | ||
export function isInterceptingServerListener(listener: ServerListener | InterceptingServerListener): listener is InterceptingServerListener { | ||
return listener.onReceiveMetadata !== undefined && listener.onReceiveMetadata.length === 1; | ||
export function isInterceptingServerListener( | ||
listener: ServerListener | InterceptingServerListener | ||
): listener is InterceptingServerListener { | ||
return ( | ||
listener.onReceiveMetadata !== undefined && | ||
listener.onReceiveMetadata.length === 1 | ||
); | ||
} | ||
@@ -123,10 +133,13 @@ | ||
*/ | ||
private cancelled: boolean = false; | ||
private processingMetadata: boolean = false; | ||
private hasPendingMessage: boolean = false; | ||
private cancelled = false; | ||
private processingMetadata = false; | ||
private hasPendingMessage = false; | ||
private pendingMessage: any = null; | ||
private processingMessage: boolean = false; | ||
private hasPendingHalfClose: boolean = false; | ||
private processingMessage = false; | ||
private hasPendingHalfClose = false; | ||
constructor(private listener: FullServerListener, private nextListener: InterceptingServerListener) {} | ||
constructor( | ||
private listener: FullServerListener, | ||
private nextListener: InterceptingServerListener | ||
) {} | ||
@@ -202,3 +215,2 @@ private processPendingMessage() { | ||
} | ||
} | ||
@@ -220,3 +232,6 @@ | ||
export interface StatusResponder { | ||
(status: PartialStatusObject, next: (status: PartialStatusObject) => void): void; | ||
( | ||
status: PartialStatusObject, | ||
next: (status: PartialStatusObject) => void | ||
): void; | ||
} | ||
@@ -264,3 +279,3 @@ | ||
sendMessage: this.message, | ||
sendStatus: this.status | ||
sendStatus: this.status, | ||
}; | ||
@@ -280,7 +295,7 @@ } | ||
}, | ||
onCancel: () => {} | ||
onCancel: () => {}, | ||
}; | ||
const defaultResponder: FullResponder = { | ||
start: (next) => { | ||
start: next => { | ||
next(); | ||
@@ -296,3 +311,3 @@ }, | ||
next(status); | ||
} | ||
}, | ||
}; | ||
@@ -333,9 +348,12 @@ | ||
private responder: FullResponder; | ||
private processingMetadata: boolean = false; | ||
private processingMessage: boolean = false; | ||
private processingMetadata = false; | ||
private processingMessage = false; | ||
private pendingMessage: any = null; | ||
private pendingMessageCallback: (() => void) | null = null; | ||
private pendingStatus: PartialStatusObject | null = null; | ||
constructor(private nextCall: ServerInterceptingCallInterface, responder?: Responder) { | ||
this.responder = {...defaultResponder, ...responder}; | ||
constructor( | ||
private nextCall: ServerInterceptingCallInterface, | ||
responder?: Responder | ||
) { | ||
this.responder = { ...defaultResponder, ...responder }; | ||
} | ||
@@ -345,3 +363,6 @@ | ||
if (this.pendingMessageCallback) { | ||
this.nextCall.sendMessage(this.pendingMessage, this.pendingMessageCallback); | ||
this.nextCall.sendMessage( | ||
this.pendingMessage, | ||
this.pendingMessageCallback | ||
); | ||
this.pendingMessage = null; | ||
@@ -361,4 +382,10 @@ this.pendingMessageCallback = null; | ||
this.responder.start(interceptedListener => { | ||
const fullInterceptedListener: FullServerListener = {...defaultServerListener, ...interceptedListener}; | ||
const finalInterceptingListener = new InterceptingServerListenerImpl(fullInterceptedListener, listener); | ||
const fullInterceptedListener: FullServerListener = { | ||
...defaultServerListener, | ||
...interceptedListener, | ||
}; | ||
const finalInterceptingListener = new InterceptingServerListenerImpl( | ||
fullInterceptedListener, | ||
listener | ||
); | ||
this.nextCall.start(finalInterceptingListener); | ||
@@ -409,3 +436,6 @@ }); | ||
export interface ServerInterceptor { | ||
(methodDescriptor: ServerMethodDefinition<any, any>, call: ServerInterceptingCallInterface): ServerInterceptingCall; | ||
( | ||
methodDescriptor: ServerMethodDefinition<any, any>, | ||
call: ServerInterceptingCallInterface | ||
): ServerInterceptingCall; | ||
} | ||
@@ -454,3 +484,5 @@ | ||
export class BaseServerInterceptingCall implements ServerInterceptingCallInterface { | ||
export class BaseServerInterceptingCall | ||
implements ServerInterceptingCallInterface | ||
{ | ||
private listener: InterceptingServerListener | null = null; | ||
@@ -466,3 +498,3 @@ private metadata: Metadata; | ||
private cancelNotified = false; | ||
private incomingEncoding: string = 'identity'; | ||
private incomingEncoding = 'identity'; | ||
private decoder = new StreamDecoder(); | ||
@@ -503,3 +535,3 @@ private readQueue: ReadQueueEntry[] = []; | ||
details: 'Stream closed before sending status', | ||
metadata: null | ||
metadata: null, | ||
}); | ||
@@ -567,3 +599,3 @@ } | ||
details: `Invalid ${GRPC_TIMEOUT_HEADER} value "${timeoutHeader}"`, | ||
metadata: null | ||
metadata: null, | ||
}; | ||
@@ -585,7 +617,6 @@ // Wait for the constructor to complete before sending the error. | ||
details: 'Deadline exceeded', | ||
metadata: null | ||
metadata: null, | ||
}; | ||
this.sendStatus(status); | ||
}, timeout); | ||
} | ||
@@ -671,4 +702,9 @@ | ||
const compressed = queueEntry.compressedMessage!.readUInt8(0) === 1; | ||
const compressedMessageEncoding = compressed ? this.incomingEncoding : 'identity'; | ||
const decompressedMessage = await this.decompressMessage(queueEntry.compressedMessage!, compressedMessageEncoding); | ||
const compressedMessageEncoding = compressed | ||
? this.incomingEncoding | ||
: 'identity'; | ||
const decompressedMessage = await this.decompressMessage( | ||
queueEntry.compressedMessage!, | ||
compressedMessageEncoding | ||
); | ||
try { | ||
@@ -679,3 +715,3 @@ queueEntry.parsedMessage = this.handler.deserialize(decompressedMessage); | ||
code: Status.INTERNAL, | ||
details: `Error deserializing request: ${(err as Error).message}` | ||
details: `Error deserializing request: ${(err as Error).message}`, | ||
}); | ||
@@ -689,3 +725,8 @@ return; | ||
private maybePushNextMessage() { | ||
if (this.listener && this.isReadPending && this.readQueue.length > 0 && this.readQueue[0].type !== 'COMPRESSED') { | ||
if ( | ||
this.listener && | ||
this.isReadPending && | ||
this.readQueue.length > 0 && | ||
this.readQueue[0].type !== 'COMPRESSED' | ||
) { | ||
this.isReadPending = false; | ||
@@ -706,3 +747,8 @@ const nextQueueEntry = this.readQueue.shift()!; | ||
} | ||
trace('Request to ' + this.handler.path + ' received data frame of size ' + data.length); | ||
trace( | ||
'Request to ' + | ||
this.handler.path + | ||
' received data frame of size ' + | ||
data.length | ||
); | ||
const rawMessages = this.decoder.write(data); | ||
@@ -712,7 +758,12 @@ | ||
this.stream.pause(); | ||
if (this.maxReceiveMessageSize !== -1 && messageBytes.length - 5 > this.maxReceiveMessageSize) { | ||
if ( | ||
this.maxReceiveMessageSize !== -1 && | ||
messageBytes.length - 5 > this.maxReceiveMessageSize | ||
) { | ||
this.sendStatus({ | ||
code: Status.RESOURCE_EXHAUSTED, | ||
details: `Received message larger than max (${messageBytes.length - 5} vs. ${this.maxReceiveMessageSize})`, | ||
metadata: null | ||
details: `Received message larger than max (${ | ||
messageBytes.length - 5 | ||
} vs. ${this.maxReceiveMessageSize})`, | ||
metadata: null, | ||
}); | ||
@@ -724,3 +775,3 @@ return; | ||
compressedMessage: messageBytes, | ||
parsedMessage: null | ||
parsedMessage: null, | ||
}; | ||
@@ -736,3 +787,3 @@ this.readQueue.push(queueEntry); | ||
compressedMessage: null, | ||
parsedMessage: null | ||
parsedMessage: null, | ||
}); | ||
@@ -779,3 +830,3 @@ this.receivedHalfClose = true; | ||
details: `Error serializing response: ${getErrorMessage(e)}`, | ||
metadata: null | ||
metadata: null, | ||
}); | ||
@@ -792,3 +843,3 @@ return; | ||
details: `Sent message larger than max (${response.length} vs. ${this.maxSendMessageSize})`, | ||
metadata: null | ||
metadata: null, | ||
}); | ||
@@ -798,3 +849,8 @@ return; | ||
this.maybeSendMetadata(); | ||
trace('Request to ' + this.handler.path + ' sent data frame of size ' + response.length); | ||
trace( | ||
'Request to ' + | ||
this.handler.path + | ||
' sent data frame of size ' + | ||
response.length | ||
); | ||
this.stream.write(response, error => { | ||
@@ -805,3 +861,3 @@ if (error) { | ||
details: `Error writing message: ${getErrorMessage(error)}`, | ||
metadata: null | ||
metadata: null, | ||
}); | ||
@@ -818,3 +874,2 @@ return; | ||
} | ||
this.notifyOnCancel(); | ||
@@ -846,4 +901,7 @@ trace( | ||
this.stream.sendTrailers(trailersToSend); | ||
this.notifyOnCancel(); | ||
}); | ||
this.stream.end(); | ||
} else { | ||
this.notifyOnCancel(); | ||
} | ||
@@ -864,2 +922,3 @@ } else { | ||
this.stream.respond(trailersToSend, { endStream: true }); | ||
this.notifyOnCancel(); | ||
} | ||
@@ -906,3 +965,2 @@ } | ||
) { | ||
const methodDefinition: ServerMethodDefinition<any, any> = { | ||
@@ -913,8 +971,17 @@ path: handler.path, | ||
requestDeserialize: handler.deserialize, | ||
responseSerialize: handler.serialize | ||
} | ||
const baseCall = new BaseServerInterceptingCall(stream, headers, callEventTracker, handler, options); | ||
return interceptors.reduce((call: ServerInterceptingCallInterface, interceptor: ServerInterceptor) => { | ||
return interceptor(methodDefinition, call); | ||
}, baseCall); | ||
responseSerialize: handler.serialize, | ||
}; | ||
const baseCall = new BaseServerInterceptingCall( | ||
stream, | ||
headers, | ||
callEventTracker, | ||
handler, | ||
options | ||
); | ||
return interceptors.reduce( | ||
(call: ServerInterceptingCallInterface, interceptor: ServerInterceptor) => { | ||
return interceptor(methodDefinition, call); | ||
}, | ||
baseCall | ||
); | ||
} |
@@ -58,7 +58,16 @@ /* | ||
} from './subchannel-address'; | ||
import { GrpcUri, combineHostPort, parseUri, splitHostPort, uriToString } from './uri-parser'; | ||
import { | ||
GrpcUri, | ||
combineHostPort, | ||
parseUri, | ||
splitHostPort, | ||
uriToString, | ||
} from './uri-parser'; | ||
import { | ||
ChannelzCallTracker, | ||
ChannelzCallTrackerStub, | ||
ChannelzChildrenTracker, | ||
ChannelzChildrenTrackerStub, | ||
ChannelzTrace, | ||
ChannelzTraceStub, | ||
registerChannelzServer, | ||
@@ -74,3 +83,7 @@ registerChannelzSocket, | ||
import { CipherNameAndProtocol, TLSSocket } from 'tls'; | ||
import { ServerInterceptingCallInterface, ServerInterceptor, getServerInterceptingCall } from './server-interceptors'; | ||
import { | ||
ServerInterceptingCallInterface, | ||
ServerInterceptor, | ||
getServerInterceptingCall, | ||
} from './server-interceptors'; | ||
import { PartialStatusObject } from './call-interface'; | ||
@@ -82,2 +95,3 @@ import { CallEventTracker } from './transport'; | ||
const KEEPALIVE_TIMEOUT_MS = 20000; | ||
const MAX_CONNECTION_IDLE_MS = ~(1 << 31); | ||
@@ -87,2 +101,3 @@ const { HTTP2_HEADER_PATH } = http2.constants; | ||
const TRACER_NAME = 'server'; | ||
const kMaxAge = Buffer.from('max_age'); | ||
@@ -110,5 +125,11 @@ type AnyHttp2Server = http2.Http2Server | http2.Http2SecureServer; | ||
function deprecate(message: string) { | ||
return function <This, Args extends any[], Return>(target: (this: This, ...args: Args) => Return, context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>) { | ||
return function <This, Args extends any[], Return>( | ||
target: (this: This, ...args: Args) => Return, | ||
context: ClassMethodDecoratorContext< | ||
This, | ||
(this: This, ...args: Args) => Return | ||
> | ||
) { | ||
return util.deprecate(target, message); | ||
} | ||
}; | ||
} | ||
@@ -169,5 +190,6 @@ | ||
ref: SocketRef; | ||
streamTracker: ChannelzCallTracker; | ||
streamTracker: ChannelzCallTracker | ChannelzCallTrackerStub; | ||
messagesSent: number; | ||
messagesReceived: number; | ||
keepAlivesSent: number; | ||
lastMessageSentTimestamp: Date | null; | ||
@@ -218,3 +240,3 @@ lastMessageReceivedTimestamp: Date | null; | ||
*/ | ||
listeningServers: Set<AnyHttp2Server> | ||
listeningServers: Set<AnyHttp2Server>; | ||
} | ||
@@ -230,9 +252,20 @@ | ||
interface SessionIdleTimeoutTracker { | ||
activeStreams: number; | ||
lastIdle: number; | ||
timeout: NodeJS.Timeout; | ||
onClose: (session: http2.ServerHttp2Session) => void | null; | ||
} | ||
export interface ServerOptions extends ChannelOptions { | ||
interceptors?: ServerInterceptor[] | ||
interceptors?: ServerInterceptor[]; | ||
} | ||
export class Server { | ||
private boundPorts: Map<string, BoundPort>= new Map(); | ||
private boundPorts: Map<string, BoundPort> = new Map(); | ||
private http2Servers: Map<AnyHttp2Server, Http2ServerInfo> = new Map(); | ||
private sessionIdleTimeouts = new Map< | ||
http2.ServerHttp2Session, | ||
SessionIdleTimeoutTracker | ||
>(); | ||
@@ -256,6 +289,10 @@ private handlers: Map<string, UntypedHandler> = new Map< | ||
private channelzRef: ServerRef; | ||
private channelzTrace = new ChannelzTrace(); | ||
private callTracker = new ChannelzCallTracker(); | ||
private listenerChildrenTracker = new ChannelzChildrenTracker(); | ||
private sessionChildrenTracker = new ChannelzChildrenTracker(); | ||
private channelzTrace: ChannelzTrace | ChannelzTraceStub; | ||
private callTracker: ChannelzCallTracker | ChannelzCallTrackerStub; | ||
private listenerChildrenTracker: | ||
| ChannelzChildrenTracker | ||
| ChannelzChildrenTrackerStub; | ||
private sessionChildrenTracker: | ||
| ChannelzChildrenTracker | ||
| ChannelzChildrenTrackerStub; | ||
@@ -268,2 +305,4 @@ private readonly maxConnectionAgeMs: number; | ||
private readonly sessionIdleTimeout: number; | ||
private readonly interceptors: ServerInterceptor[]; | ||
@@ -281,10 +320,20 @@ | ||
this.channelzEnabled = false; | ||
this.channelzTrace = new ChannelzTraceStub(); | ||
this.callTracker = new ChannelzCallTrackerStub(); | ||
this.listenerChildrenTracker = new ChannelzChildrenTrackerStub(); | ||
this.sessionChildrenTracker = new ChannelzChildrenTrackerStub(); | ||
} else { | ||
this.channelzTrace = new ChannelzTrace(); | ||
this.callTracker = new ChannelzCallTracker(); | ||
this.listenerChildrenTracker = new ChannelzChildrenTracker(); | ||
this.sessionChildrenTracker = new ChannelzChildrenTracker(); | ||
} | ||
this.channelzRef = registerChannelzServer( | ||
'server', | ||
() => this.getChannelzInfo(), | ||
this.channelzEnabled | ||
); | ||
if (this.channelzEnabled) { | ||
this.channelzTrace.addTrace('CT_INFO', 'Server created'); | ||
} | ||
this.channelzTrace.addTrace('CT_INFO', 'Server created'); | ||
this.maxConnectionAgeMs = | ||
@@ -299,2 +348,5 @@ this.options['grpc.max_connection_age_ms'] ?? UNLIMITED_CONNECTION_AGE_MS; | ||
this.options['grpc.keepalive_timeout_ms'] ?? KEEPALIVE_TIMEOUT_MS; | ||
this.sessionIdleTimeout = | ||
this.options['grpc.max_connection_idle_ms'] ?? MAX_CONNECTION_IDLE_MS; | ||
this.commonServerOptions = { | ||
@@ -331,63 +383,59 @@ maxSendHeaderBlockLength: Number.MAX_SAFE_INTEGER, | ||
private getChannelzSessionInfoGetter( | ||
private getChannelzSessionInfo( | ||
session: http2.ServerHttp2Session | ||
): () => SocketInfo { | ||
return () => { | ||
const sessionInfo = this.sessions.get(session)!; | ||
const sessionSocket = session.socket; | ||
const remoteAddress = sessionSocket.remoteAddress | ||
? stringToSubchannelAddress( | ||
sessionSocket.remoteAddress, | ||
sessionSocket.remotePort | ||
) | ||
: null; | ||
const localAddress = sessionSocket.localAddress | ||
? stringToSubchannelAddress( | ||
sessionSocket.localAddress!, | ||
sessionSocket.localPort | ||
) | ||
: null; | ||
let tlsInfo: TlsInfo | null; | ||
if (session.encrypted) { | ||
const tlsSocket: TLSSocket = sessionSocket as TLSSocket; | ||
const cipherInfo: CipherNameAndProtocol & { standardName?: string } = | ||
tlsSocket.getCipher(); | ||
const certificate = tlsSocket.getCertificate(); | ||
const peerCertificate = tlsSocket.getPeerCertificate(); | ||
tlsInfo = { | ||
cipherSuiteStandardName: cipherInfo.standardName ?? null, | ||
cipherSuiteOtherName: cipherInfo.standardName | ||
? null | ||
: cipherInfo.name, | ||
localCertificate: | ||
certificate && 'raw' in certificate ? certificate.raw : null, | ||
remoteCertificate: | ||
peerCertificate && 'raw' in peerCertificate | ||
? peerCertificate.raw | ||
: null, | ||
}; | ||
} else { | ||
tlsInfo = null; | ||
} | ||
const socketInfo: SocketInfo = { | ||
remoteAddress: remoteAddress, | ||
localAddress: localAddress, | ||
security: tlsInfo, | ||
remoteName: null, | ||
streamsStarted: sessionInfo.streamTracker.callsStarted, | ||
streamsSucceeded: sessionInfo.streamTracker.callsSucceeded, | ||
streamsFailed: sessionInfo.streamTracker.callsFailed, | ||
messagesSent: sessionInfo.messagesSent, | ||
messagesReceived: sessionInfo.messagesReceived, | ||
keepAlivesSent: 0, | ||
lastLocalStreamCreatedTimestamp: null, | ||
lastRemoteStreamCreatedTimestamp: | ||
sessionInfo.streamTracker.lastCallStartedTimestamp, | ||
lastMessageSentTimestamp: sessionInfo.lastMessageSentTimestamp, | ||
lastMessageReceivedTimestamp: sessionInfo.lastMessageReceivedTimestamp, | ||
localFlowControlWindow: session.state.localWindowSize ?? null, | ||
remoteFlowControlWindow: session.state.remoteWindowSize ?? null, | ||
): SocketInfo { | ||
const sessionInfo = this.sessions.get(session)!; | ||
const sessionSocket = session.socket; | ||
const remoteAddress = sessionSocket.remoteAddress | ||
? stringToSubchannelAddress( | ||
sessionSocket.remoteAddress, | ||
sessionSocket.remotePort | ||
) | ||
: null; | ||
const localAddress = sessionSocket.localAddress | ||
? stringToSubchannelAddress( | ||
sessionSocket.localAddress!, | ||
sessionSocket.localPort | ||
) | ||
: null; | ||
let tlsInfo: TlsInfo | null; | ||
if (session.encrypted) { | ||
const tlsSocket: TLSSocket = sessionSocket as TLSSocket; | ||
const cipherInfo: CipherNameAndProtocol & { standardName?: string } = | ||
tlsSocket.getCipher(); | ||
const certificate = tlsSocket.getCertificate(); | ||
const peerCertificate = tlsSocket.getPeerCertificate(); | ||
tlsInfo = { | ||
cipherSuiteStandardName: cipherInfo.standardName ?? null, | ||
cipherSuiteOtherName: cipherInfo.standardName ? null : cipherInfo.name, | ||
localCertificate: | ||
certificate && 'raw' in certificate ? certificate.raw : null, | ||
remoteCertificate: | ||
peerCertificate && 'raw' in peerCertificate | ||
? peerCertificate.raw | ||
: null, | ||
}; | ||
return socketInfo; | ||
} else { | ||
tlsInfo = null; | ||
} | ||
const socketInfo: SocketInfo = { | ||
remoteAddress: remoteAddress, | ||
localAddress: localAddress, | ||
security: tlsInfo, | ||
remoteName: null, | ||
streamsStarted: sessionInfo.streamTracker.callsStarted, | ||
streamsSucceeded: sessionInfo.streamTracker.callsSucceeded, | ||
streamsFailed: sessionInfo.streamTracker.callsFailed, | ||
messagesSent: sessionInfo.messagesSent, | ||
messagesReceived: sessionInfo.messagesReceived, | ||
keepAlivesSent: sessionInfo.keepAlivesSent, | ||
lastLocalStreamCreatedTimestamp: null, | ||
lastRemoteStreamCreatedTimestamp: | ||
sessionInfo.streamTracker.lastCallStartedTimestamp, | ||
lastMessageSentTimestamp: sessionInfo.lastMessageSentTimestamp, | ||
lastMessageReceivedTimestamp: sessionInfo.lastMessageReceivedTimestamp, | ||
localFlowControlWindow: session.state.localWindowSize ?? null, | ||
remoteFlowControlWindow: session.state.remoteWindowSize ?? null, | ||
}; | ||
return socketInfo; | ||
} | ||
@@ -542,6 +590,7 @@ | ||
private bindOneAddress(address: SubchannelAddress, boundPortObject: BoundPort): Promise<SingleAddressBindResult> { | ||
this.trace( | ||
'Attempting to bind ' + subchannelAddressToString(address) | ||
); | ||
private bindOneAddress( | ||
address: SubchannelAddress, | ||
boundPortObject: BoundPort | ||
): Promise<SingleAddressBindResult> { | ||
this.trace('Attempting to bind ' + subchannelAddressToString(address)); | ||
const http2Server = this.createHttp2Server(boundPortObject.credentials); | ||
@@ -558,3 +607,3 @@ return new Promise<SingleAddressBindResult>((resolve, reject) => { | ||
port: 'port' in address ? address.port : 1, | ||
error: err.message | ||
error: err.message, | ||
}); | ||
@@ -579,9 +628,10 @@ }; | ||
const channelzRef = this.registerListenerToChannelz(boundSubchannelAddress); | ||
if (this.channelzEnabled) { | ||
this.listenerChildrenTracker.refChild(channelzRef); | ||
} | ||
const channelzRef = this.registerListenerToChannelz( | ||
boundSubchannelAddress | ||
); | ||
this.listenerChildrenTracker.refChild(channelzRef); | ||
this.http2Servers.set(http2Server, { | ||
channelzRef: channelzRef, | ||
sessions: new Set() | ||
sessions: new Set(), | ||
}); | ||
@@ -594,5 +644,4 @@ boundPortObject.listeningServers.add(http2Server); | ||
resolve({ | ||
port: 'port' in boundSubchannelAddress | ||
? boundSubchannelAddress.port | ||
: 1 | ||
port: | ||
'port' in boundSubchannelAddress ? boundSubchannelAddress.port : 1, | ||
}); | ||
@@ -604,3 +653,6 @@ http2Server.removeListener('error', onError); | ||
private async bindManyPorts(addressList: SubchannelAddress[], boundPortObject: BoundPort): Promise<BindResult> { | ||
private async bindManyPorts( | ||
addressList: SubchannelAddress[], | ||
boundPortObject: BoundPort | ||
): Promise<BindResult> { | ||
if (addressList.length === 0) { | ||
@@ -610,3 +662,3 @@ return { | ||
port: 0, | ||
errors: [] | ||
errors: [], | ||
}; | ||
@@ -617,14 +669,30 @@ } | ||
* the rest of the address list to the specific port that it binds. */ | ||
const firstAddressResult = await this.bindOneAddress(addressList[0], boundPortObject); | ||
const firstAddressResult = await this.bindOneAddress( | ||
addressList[0], | ||
boundPortObject | ||
); | ||
if (firstAddressResult.error) { | ||
/* If the first address fails to bind, try the same operation starting | ||
* from the second item in the list. */ | ||
const restAddressResult = await this.bindManyPorts(addressList.slice(1), boundPortObject); | ||
const restAddressResult = await this.bindManyPorts( | ||
addressList.slice(1), | ||
boundPortObject | ||
); | ||
return { | ||
...restAddressResult, | ||
errors: [firstAddressResult.error, ...restAddressResult.errors] | ||
errors: [firstAddressResult.error, ...restAddressResult.errors], | ||
}; | ||
} else { | ||
const restAddresses = addressList.slice(1).map(address => isTcpSubchannelAddress(address) ? {host: address.host, port: firstAddressResult.port} : address) | ||
const restAddressResult = await Promise.all(restAddresses.map(address => this.bindOneAddress(address, boundPortObject))); | ||
const restAddresses = addressList | ||
.slice(1) | ||
.map(address => | ||
isTcpSubchannelAddress(address) | ||
? { host: address.host, port: firstAddressResult.port } | ||
: address | ||
); | ||
const restAddressResult = await Promise.all( | ||
restAddresses.map(address => | ||
this.bindOneAddress(address, boundPortObject) | ||
) | ||
); | ||
const allResults = [firstAddressResult, ...restAddressResult]; | ||
@@ -634,11 +702,19 @@ return { | ||
port: firstAddressResult.port, | ||
errors: allResults.filter(result => result.error).map(result => result.error!) | ||
errors: allResults | ||
.filter(result => result.error) | ||
.map(result => result.error!), | ||
}; | ||
} | ||
} else { | ||
const allResults = await Promise.all(addressList.map(address => this.bindOneAddress(address, boundPortObject))); | ||
const allResults = await Promise.all( | ||
addressList.map(address => | ||
this.bindOneAddress(address, boundPortObject) | ||
) | ||
); | ||
return { | ||
count: allResults.filter(result => result.error === undefined).length, | ||
port: allResults[0].port, | ||
errors: allResults.filter(result => result.error).map(result => result.error!) | ||
errors: allResults | ||
.filter(result => result.error) | ||
.map(result => result.error!), | ||
}; | ||
@@ -648,9 +724,7 @@ } | ||
private async bindAddressList(addressList: SubchannelAddress[], boundPortObject: BoundPort): Promise<number> { | ||
let bindResult: BindResult; | ||
try { | ||
bindResult = await this.bindManyPorts(addressList, boundPortObject); | ||
} catch (error) { | ||
throw error; | ||
} | ||
private async bindAddressList( | ||
addressList: SubchannelAddress[], | ||
boundPortObject: BoundPort | ||
): Promise<number> { | ||
const bindResult = await this.bindManyPorts(addressList, boundPortObject); | ||
if (bindResult.count > 0) { | ||
@@ -667,3 +741,5 @@ if (bindResult.count < addressList.length) { | ||
logging.log(LogVerbosity.ERROR, errorString); | ||
throw new Error(`${errorString} errors: [${bindResult.errors.join(',')}]`); | ||
throw new Error( | ||
`${errorString} errors: [${bindResult.errors.join(',')}]` | ||
); | ||
} | ||
@@ -686,5 +762,3 @@ } | ||
if (addressList.length === 0) { | ||
reject( | ||
new Error(`No addresses resolved for port ${port}`) | ||
); | ||
reject(new Error(`No addresses resolved for port ${port}`)); | ||
return; | ||
@@ -703,3 +777,6 @@ } | ||
private async bindPort(port: GrpcUri, boundPortObject: BoundPort): Promise<number> { | ||
private async bindPort( | ||
port: GrpcUri, | ||
boundPortObject: BoundPort | ||
): Promise<number> { | ||
const addressList = await this.resolvePort(port); | ||
@@ -719,3 +796,2 @@ if (boundPortObject.cancelled) { | ||
private normalizePort(port: string): GrpcUri { | ||
const initialPortUri = parseUri(port); | ||
@@ -765,3 +841,6 @@ if (initialPortUri === null) { | ||
if (!creds._equals(boundPortObject.credentials)) { | ||
deferredCallback(new Error(`${port} already bound with incompatible credentials`), 0); | ||
deferredCallback( | ||
new Error(`${port} already bound with incompatible credentials`), | ||
0 | ||
); | ||
return; | ||
@@ -773,3 +852,6 @@ } | ||
if (boundPortObject.completionPromise) { | ||
boundPortObject.completionPromise.then(portNum => callback(null, portNum), error => callback(error as Error, 0)); | ||
boundPortObject.completionPromise.then( | ||
portNum => callback(null, portNum), | ||
error => callback(error as Error, 0) | ||
); | ||
} else { | ||
@@ -787,3 +869,3 @@ deferredCallback(null, boundPortObject.portNumber); | ||
credentials: creds, | ||
listeningServers: new Set() | ||
listeningServers: new Set(), | ||
}; | ||
@@ -797,25 +879,31 @@ const splitPort = splitHostPort(portUri.path); | ||
if (splitPort?.port === 0) { | ||
completionPromise.then(portNum => { | ||
const finalUri: GrpcUri = { | ||
scheme: portUri.scheme, | ||
authority: portUri.authority, | ||
path: combineHostPort({host: splitPort.host, port: portNum}) | ||
}; | ||
boundPortObject!.mapKey = uriToString(finalUri); | ||
boundPortObject!.completionPromise = null; | ||
boundPortObject!.portNumber = portNum; | ||
this.boundPorts.set(boundPortObject!.mapKey, boundPortObject!); | ||
callback(null, portNum); | ||
}, error => { | ||
callback(error, 0); | ||
}) | ||
completionPromise.then( | ||
portNum => { | ||
const finalUri: GrpcUri = { | ||
scheme: portUri.scheme, | ||
authority: portUri.authority, | ||
path: combineHostPort({ host: splitPort.host, port: portNum }), | ||
}; | ||
boundPortObject!.mapKey = uriToString(finalUri); | ||
boundPortObject!.completionPromise = null; | ||
boundPortObject!.portNumber = portNum; | ||
this.boundPorts.set(boundPortObject!.mapKey, boundPortObject!); | ||
callback(null, portNum); | ||
}, | ||
error => { | ||
callback(error, 0); | ||
} | ||
); | ||
} else { | ||
this.boundPorts.set(boundPortObject.mapKey, boundPortObject); | ||
completionPromise.then(portNum => { | ||
boundPortObject!.completionPromise = null; | ||
boundPortObject!.portNumber = portNum; | ||
callback(null, portNum); | ||
}, error => { | ||
callback(error, 0); | ||
}); | ||
completionPromise.then( | ||
portNum => { | ||
boundPortObject!.completionPromise = null; | ||
boundPortObject!.portNumber = portNum; | ||
callback(null, portNum); | ||
}, | ||
error => { | ||
callback(error, 0); | ||
} | ||
); | ||
} | ||
@@ -825,6 +913,8 @@ } | ||
private closeServer(server: AnyHttp2Server, callback?: () => void) { | ||
this.trace('Closing server with address ' + JSON.stringify(server.address())); | ||
this.trace( | ||
'Closing server with address ' + JSON.stringify(server.address()) | ||
); | ||
const serverInfo = this.http2Servers.get(server); | ||
server.close(() => { | ||
if (this.channelzEnabled && serverInfo) { | ||
if (serverInfo) { | ||
this.listenerChildrenTracker.unrefChild(serverInfo.channelzRef); | ||
@@ -836,18 +926,19 @@ unregisterChannelzRef(serverInfo.channelzRef); | ||
}); | ||
} | ||
private closeSession(session: http2.ServerHttp2Session, callback?: () => void) { | ||
private closeSession( | ||
session: http2.ServerHttp2Session, | ||
callback?: () => void | ||
) { | ||
this.trace('Closing session initiated by ' + session.socket?.remoteAddress); | ||
const sessionInfo = this.sessions.get(session); | ||
const closeCallback = () => { | ||
if (this.channelzEnabled && sessionInfo) { | ||
if (sessionInfo) { | ||
this.sessionChildrenTracker.unrefChild(sessionInfo.ref); | ||
unregisterChannelzRef(sessionInfo.ref); | ||
} | ||
this.sessions.delete(session); | ||
callback?.(); | ||
}; | ||
if (session.closed) { | ||
process.nextTick(closeCallback); | ||
queueMicrotask(closeCallback); | ||
} else { | ||
@@ -889,3 +980,8 @@ session.close(closeCallback); | ||
if (boundPortObject) { | ||
this.trace('unbinding ' + boundPortObject.mapKey + ' originally bound as ' + uriToString(boundPortObject.originalUri)); | ||
this.trace( | ||
'unbinding ' + | ||
boundPortObject.mapKey + | ||
' originally bound as ' + | ||
uriToString(boundPortObject.originalUri) | ||
); | ||
/* If the bind operation is pending, the cancelled flag will trigger | ||
@@ -926,11 +1022,10 @@ * the unbind operation later. */ | ||
const serverEntry = this.http2Servers.get(http2Server); | ||
if (!serverEntry) { | ||
continue; | ||
if (serverEntry) { | ||
for (const session of serverEntry.sessions) { | ||
allSessions.add(session); | ||
this.closeSession(session, () => { | ||
allSessions.delete(session); | ||
}); | ||
} | ||
} | ||
for (const session of serverEntry.sessions) { | ||
allSessions.add(session); | ||
this.closeSession(session, () => { | ||
allSessions.delete(session); | ||
}); | ||
} | ||
} | ||
@@ -966,5 +1061,3 @@ /* After the grace time ends, send another goaway to all remaining sessions | ||
this.sessions.clear(); | ||
if (this.channelzEnabled) { | ||
unregisterChannelzRef(this.channelzRef); | ||
} | ||
unregisterChannelzRef(this.channelzRef); | ||
@@ -1002,9 +1095,9 @@ this.shutdown = true; | ||
*/ | ||
@deprecate('Calling start() is no longer necessary. It can be safely omitted.') | ||
@deprecate( | ||
'Calling start() is no longer necessary. It can be safely omitted.' | ||
) | ||
start(): void { | ||
if ( | ||
this.http2Servers.size === 0 || | ||
[...this.http2Servers.keys()].every( | ||
server => !server.listening | ||
) | ||
[...this.http2Servers.keys()].every(server => !server.listening) | ||
) { | ||
@@ -1022,5 +1115,3 @@ throw new Error('server must be bound in order to start'); | ||
const wrappedCallback = (error?: Error) => { | ||
if (this.channelzEnabled) { | ||
unregisterChannelzRef(this.channelzRef); | ||
} | ||
unregisterChannelzRef(this.channelzRef); | ||
callback(error); | ||
@@ -1039,20 +1130,22 @@ }; | ||
for (const server of this.http2Servers.keys()) { | ||
for (const [serverKey, server] of this.http2Servers.entries()) { | ||
pendingChecks++; | ||
const serverString = this.http2Servers.get(server)!.channelzRef.name; | ||
const serverString = server.channelzRef.name; | ||
this.trace('Waiting for server ' + serverString + ' to close'); | ||
this.closeServer(server, () => { | ||
this.closeServer(serverKey, () => { | ||
this.trace('Server ' + serverString + ' finished closing'); | ||
maybeCallback(); | ||
}); | ||
for (const session of server.sessions.keys()) { | ||
pendingChecks++; | ||
const sessionString = session.socket?.remoteAddress; | ||
this.trace('Waiting for session ' + sessionString + ' to close'); | ||
this.closeSession(session, () => { | ||
this.trace('Session ' + sessionString + ' finished closing'); | ||
maybeCallback(); | ||
}); | ||
} | ||
} | ||
for (const session of this.sessions.keys()) { | ||
pendingChecks++; | ||
const sessionString = session.socket?.remoteAddress; | ||
this.trace('Waiting for session ' + sessionString + ' to close'); | ||
this.closeSession(session, () => { | ||
this.trace('Session ' + sessionString + ' finished closing'); | ||
maybeCallback(); | ||
}); | ||
} | ||
if (pendingChecks === 0) { | ||
@@ -1131,10 +1224,8 @@ wrappedCallback(); | ||
[http2.constants.HTTP2_HEADER_CONTENT_TYPE]: 'application/grpc+proto', | ||
...err.metadata?.toHttp2Headers() | ||
...err.metadata?.toHttp2Headers(), | ||
}; | ||
stream.respond(trailersToSend, {endStream: true}); | ||
stream.respond(trailersToSend, { endStream: true }); | ||
if (this.channelzEnabled) { | ||
this.callTracker.addCallFailed(); | ||
channelzSessionInfo?.streamTracker.addCallFailed(); | ||
} | ||
this.callTracker.addCallFailed(); | ||
channelzSessionInfo?.streamTracker.addCallFailed(); | ||
} | ||
@@ -1146,2 +1237,5 @@ | ||
) { | ||
// for handling idle timeout | ||
this.onStreamOpened(stream); | ||
const channelzSessionInfo = this.sessions.get( | ||
@@ -1172,3 +1266,3 @@ stream.session as http2.ServerHttp2Session | ||
let callEventTracker: CallEventTracker = { | ||
const callEventTracker: CallEventTracker = { | ||
addMessageSent: () => { | ||
@@ -1201,6 +1295,13 @@ if (channelzSessionInfo) { | ||
} | ||
} | ||
} | ||
}, | ||
}; | ||
const call = getServerInterceptingCall(this.interceptors, stream, headers, callEventTracker, handler, this.options); | ||
const call = getServerInterceptingCall( | ||
this.interceptors, | ||
stream, | ||
headers, | ||
callEventTracker, | ||
handler, | ||
this.options | ||
); | ||
@@ -1222,2 +1323,5 @@ if (!this._runHandlerForCall(call, handler)) { | ||
) { | ||
// for handling idle timeout | ||
this.onStreamOpened(stream); | ||
if (this._verifyContentType(stream, headers) !== true) { | ||
@@ -1239,3 +1343,10 @@ return; | ||
const call = getServerInterceptingCall(this.interceptors, stream, headers, null, handler, this.options); | ||
const call = getServerInterceptingCall( | ||
this.interceptors, | ||
stream, | ||
headers, | ||
null, | ||
handler, | ||
this.options | ||
); | ||
@@ -1252,23 +1363,17 @@ if (!this._runHandlerForCall(call, handler)) { | ||
call: ServerInterceptingCallInterface, | ||
handler: Handler<any, any> | ||
handler: | ||
| UntypedUnaryHandler | ||
| UntypedClientStreamingHandler | ||
| UntypedServerStreamingHandler | ||
| UntypedBidiStreamingHandler | ||
): boolean { | ||
const { type } = handler; | ||
if (type === 'unary') { | ||
handleUnary(call, handler as UntypedUnaryHandler); | ||
handleUnary(call, handler); | ||
} else if (type === 'clientStream') { | ||
handleClientStreaming( | ||
call, | ||
handler as UntypedClientStreamingHandler | ||
); | ||
handleClientStreaming(call, handler); | ||
} else if (type === 'serverStream') { | ||
handleServerStreaming( | ||
call, | ||
handler as UntypedServerStreamingHandler | ||
); | ||
handleServerStreaming(call, handler); | ||
} else if (type === 'bidi') { | ||
handleBidiStreaming( | ||
call, | ||
handler as UntypedBidiStreamingHandler | ||
); | ||
handleBidiStreaming(call, handler); | ||
} else { | ||
@@ -1303,8 +1408,137 @@ return false; | ||
const sessionHandler = this.channelzEnabled | ||
? this._channelzSessionHandler(http2Server) | ||
: this._sessionHandler(http2Server); | ||
http2Server.on('stream', handler.bind(this)); | ||
http2Server.on('session', session => { | ||
http2Server.on('session', sessionHandler); | ||
} | ||
private _sessionHandler( | ||
http2Server: http2.Http2Server | http2.Http2SecureServer | ||
) { | ||
return (session: http2.ServerHttp2Session) => { | ||
this.http2Servers.get(http2Server)?.sessions.add(session); | ||
let connectionAgeTimer: NodeJS.Timeout | null = null; | ||
let connectionAgeGraceTimer: NodeJS.Timeout | null = null; | ||
let keeapliveTimeTimer: NodeJS.Timeout | null = null; | ||
let keepaliveTimeoutTimer: NodeJS.Timeout | null = null; | ||
let sessionClosedByServer = false; | ||
const idleTimeoutObj = this.enableIdleTimeout(session); | ||
if (this.maxConnectionAgeMs !== UNLIMITED_CONNECTION_AGE_MS) { | ||
// Apply a random jitter within a +/-10% range | ||
const jitterMagnitude = this.maxConnectionAgeMs / 10; | ||
const jitter = Math.random() * jitterMagnitude * 2 - jitterMagnitude; | ||
connectionAgeTimer = setTimeout(() => { | ||
sessionClosedByServer = true; | ||
this.trace( | ||
'Connection dropped by max connection age: ' + | ||
session.socket?.remoteAddress | ||
); | ||
try { | ||
session.goaway( | ||
http2.constants.NGHTTP2_NO_ERROR, | ||
~(1 << 31), | ||
kMaxAge | ||
); | ||
} catch (e) { | ||
// The goaway can't be sent because the session is already closed | ||
session.destroy(); | ||
return; | ||
} | ||
session.close(); | ||
/* Allow a grace period after sending the GOAWAY before forcibly | ||
* closing the connection. */ | ||
if (this.maxConnectionAgeGraceMs !== UNLIMITED_CONNECTION_AGE_MS) { | ||
connectionAgeGraceTimer = setTimeout(() => { | ||
session.destroy(); | ||
}, this.maxConnectionAgeGraceMs); | ||
connectionAgeGraceTimer.unref?.(); | ||
} | ||
}, this.maxConnectionAgeMs + jitter); | ||
connectionAgeTimer.unref?.(); | ||
} | ||
if (this.keepaliveTimeMs < KEEPALIVE_MAX_TIME_MS) { | ||
keeapliveTimeTimer = setInterval(() => { | ||
keepaliveTimeoutTimer = setTimeout(() => { | ||
sessionClosedByServer = true; | ||
session.close(); | ||
}, this.keepaliveTimeoutMs); | ||
keepaliveTimeoutTimer.unref?.(); | ||
try { | ||
session.ping( | ||
(err: Error | null, duration: number, payload: Buffer) => { | ||
if (keepaliveTimeoutTimer) { | ||
clearTimeout(keepaliveTimeoutTimer); | ||
} | ||
if (err) { | ||
sessionClosedByServer = true; | ||
this.trace( | ||
'Connection dropped due to error of a ping frame ' + | ||
err.message + | ||
' return in ' + | ||
duration | ||
); | ||
session.close(); | ||
} | ||
} | ||
); | ||
} catch (e) { | ||
clearTimeout(keepaliveTimeoutTimer); | ||
// The ping can't be sent because the session is already closed | ||
session.destroy(); | ||
} | ||
}, this.keepaliveTimeMs); | ||
keeapliveTimeTimer.unref?.(); | ||
} | ||
session.on('close', () => { | ||
if (!sessionClosedByServer) { | ||
this.trace( | ||
`Connection dropped by client ${session.socket?.remoteAddress}` | ||
); | ||
} | ||
if (connectionAgeTimer) { | ||
clearTimeout(connectionAgeTimer); | ||
} | ||
if (connectionAgeGraceTimer) { | ||
clearTimeout(connectionAgeGraceTimer); | ||
} | ||
if (keeapliveTimeTimer) { | ||
clearInterval(keeapliveTimeTimer); | ||
if (keepaliveTimeoutTimer) { | ||
clearTimeout(keepaliveTimeoutTimer); | ||
} | ||
} | ||
if (idleTimeoutObj !== null) { | ||
clearTimeout(idleTimeoutObj.timeout); | ||
this.sessionIdleTimeouts.delete(session); | ||
} | ||
this.http2Servers.get(http2Server)?.sessions.delete(session); | ||
}); | ||
}; | ||
} | ||
private _channelzSessionHandler( | ||
http2Server: http2.Http2Server | http2.Http2SecureServer | ||
) { | ||
return (session: http2.ServerHttp2Session) => { | ||
const channelzRef = registerChannelzSocket( | ||
session.socket.remoteAddress ?? 'unknown', | ||
this.getChannelzSessionInfoGetter(session), | ||
session.socket?.remoteAddress ?? 'unknown', | ||
this.getChannelzSessionInfo.bind(this, session), | ||
this.channelzEnabled | ||
@@ -1318,2 +1552,3 @@ ); | ||
messagesReceived: 0, | ||
keepAlivesSent: 0, | ||
lastMessageSentTimestamp: null, | ||
@@ -1325,13 +1560,19 @@ lastMessageReceivedTimestamp: null, | ||
this.sessions.set(session, channelzSessionInfo); | ||
const clientAddress = session.socket.remoteAddress; | ||
if (this.channelzEnabled) { | ||
this.channelzTrace.addTrace( | ||
'CT_INFO', | ||
'Connection established by client ' + clientAddress | ||
); | ||
this.sessionChildrenTracker.refChild(channelzRef); | ||
} | ||
const clientAddress = `${session.socket.remoteAddress}:${session.socket.remotePort}`; | ||
this.channelzTrace.addTrace( | ||
'CT_INFO', | ||
'Connection established by client ' + clientAddress | ||
); | ||
this.trace('Connection established by client ' + clientAddress); | ||
this.sessionChildrenTracker.refChild(channelzRef); | ||
let connectionAgeTimer: NodeJS.Timeout | null = null; | ||
let connectionAgeGraceTimer: NodeJS.Timeout | null = null; | ||
let keeapliveTimeTimer: NodeJS.Timeout | null = null; | ||
let keepaliveTimeoutTimer: NodeJS.Timeout | null = null; | ||
let sessionClosedByServer = false; | ||
const idleTimeoutObj = this.enableIdleTimeout(session); | ||
if (this.maxConnectionAgeMs !== UNLIMITED_CONNECTION_AGE_MS) { | ||
@@ -1341,10 +1582,10 @@ // Apply a random jitter within a +/-10% range | ||
const jitter = Math.random() * jitterMagnitude * 2 - jitterMagnitude; | ||
connectionAgeTimer = setTimeout(() => { | ||
sessionClosedByServer = true; | ||
if (this.channelzEnabled) { | ||
this.channelzTrace.addTrace( | ||
'CT_INFO', | ||
'Connection dropped by max connection age from ' + clientAddress | ||
); | ||
} | ||
this.channelzTrace.addTrace( | ||
'CT_INFO', | ||
'Connection dropped by max connection age from ' + clientAddress | ||
); | ||
try { | ||
@@ -1354,3 +1595,3 @@ session.goaway( | ||
~(1 << 31), | ||
Buffer.from('max_age') | ||
kMaxAge | ||
); | ||
@@ -1363,2 +1604,3 @@ } catch (e) { | ||
session.close(); | ||
/* Allow a grace period after sending the GOAWAY before forcibly | ||
@@ -1369,10 +1611,13 @@ * closing the connection. */ | ||
session.destroy(); | ||
}, this.maxConnectionAgeGraceMs).unref?.(); | ||
}, this.maxConnectionAgeGraceMs); | ||
connectionAgeGraceTimer.unref?.(); | ||
} | ||
}, this.maxConnectionAgeMs + jitter).unref?.(); | ||
}, this.maxConnectionAgeMs + jitter); | ||
connectionAgeTimer.unref?.(); | ||
} | ||
const keeapliveTimeTimer: NodeJS.Timeout | null = setInterval(() => { | ||
const timeoutTImer = setTimeout(() => { | ||
sessionClosedByServer = true; | ||
if (this.channelzEnabled) { | ||
if (this.keepaliveTimeMs < KEEPALIVE_MAX_TIME_MS) { | ||
keeapliveTimeTimer = setInterval(() => { | ||
keepaliveTimeoutTimer = setTimeout(() => { | ||
sessionClosedByServer = true; | ||
this.channelzTrace.addTrace( | ||
@@ -1382,41 +1627,167 @@ 'CT_INFO', | ||
); | ||
session.close(); | ||
}, this.keepaliveTimeoutMs); | ||
keepaliveTimeoutTimer.unref?.(); | ||
try { | ||
session.ping( | ||
(err: Error | null, duration: number, payload: Buffer) => { | ||
if (keepaliveTimeoutTimer) { | ||
clearTimeout(keepaliveTimeoutTimer); | ||
} | ||
if (err) { | ||
sessionClosedByServer = true; | ||
this.channelzTrace.addTrace( | ||
'CT_INFO', | ||
'Connection dropped due to error of a ping frame ' + | ||
err.message + | ||
' return in ' + | ||
duration | ||
); | ||
session.close(); | ||
} | ||
} | ||
); | ||
channelzSessionInfo.keepAlivesSent += 1; | ||
} catch (e) { | ||
clearTimeout(keepaliveTimeoutTimer); | ||
// The ping can't be sent because the session is already closed | ||
session.destroy(); | ||
} | ||
session.close(); | ||
}, this.keepaliveTimeoutMs).unref?.(); | ||
try { | ||
session.ping( | ||
(err: Error | null, duration: number, payload: Buffer) => { | ||
clearTimeout(timeoutTImer); | ||
} | ||
}, this.keepaliveTimeMs); | ||
keeapliveTimeTimer.unref?.(); | ||
} | ||
session.on('close', () => { | ||
if (!sessionClosedByServer) { | ||
this.channelzTrace.addTrace( | ||
'CT_INFO', | ||
'Connection dropped by client ' + clientAddress | ||
); | ||
} catch (e) { | ||
// The ping can't be sent because the session is already closed | ||
session.destroy(); | ||
} | ||
}, this.keepaliveTimeMs).unref?.(); | ||
session.on('close', () => { | ||
if (this.channelzEnabled) { | ||
if (!sessionClosedByServer) { | ||
this.channelzTrace.addTrace( | ||
'CT_INFO', | ||
'Connection dropped by client ' + clientAddress | ||
); | ||
} | ||
this.sessionChildrenTracker.unrefChild(channelzRef); | ||
unregisterChannelzRef(channelzRef); | ||
} | ||
this.sessionChildrenTracker.unrefChild(channelzRef); | ||
unregisterChannelzRef(channelzRef); | ||
if (connectionAgeTimer) { | ||
clearTimeout(connectionAgeTimer); | ||
} | ||
if (connectionAgeGraceTimer) { | ||
clearTimeout(connectionAgeGraceTimer); | ||
} | ||
if (keeapliveTimeTimer) { | ||
clearTimeout(keeapliveTimeTimer); | ||
clearInterval(keeapliveTimeTimer); | ||
if (keepaliveTimeoutTimer) { | ||
clearTimeout(keepaliveTimeoutTimer); | ||
} | ||
} | ||
if (idleTimeoutObj !== null) { | ||
clearTimeout(idleTimeoutObj.timeout); | ||
this.sessionIdleTimeouts.delete(session); | ||
} | ||
this.http2Servers.get(http2Server)?.sessions.delete(session); | ||
this.sessions.delete(session); | ||
}); | ||
}); | ||
}; | ||
} | ||
private enableIdleTimeout( | ||
session: http2.ServerHttp2Session | ||
): SessionIdleTimeoutTracker | null { | ||
if (this.sessionIdleTimeout >= MAX_CONNECTION_IDLE_MS) { | ||
return null; | ||
} | ||
const idleTimeoutObj: SessionIdleTimeoutTracker = { | ||
activeStreams: 0, | ||
lastIdle: Date.now(), | ||
onClose: this.onStreamClose.bind(this, session), | ||
timeout: setTimeout( | ||
this.onIdleTimeout, | ||
this.sessionIdleTimeout, | ||
this, | ||
session | ||
), | ||
}; | ||
idleTimeoutObj.timeout.unref?.(); | ||
this.sessionIdleTimeouts.set(session, idleTimeoutObj); | ||
const { socket } = session; | ||
this.trace( | ||
'Enable idle timeout for ' + | ||
socket.remoteAddress + | ||
':' + | ||
socket.remotePort | ||
); | ||
return idleTimeoutObj; | ||
} | ||
private onIdleTimeout( | ||
this: undefined, | ||
ctx: Server, | ||
session: http2.ServerHttp2Session | ||
) { | ||
const { socket } = session; | ||
const sessionInfo = ctx.sessionIdleTimeouts.get(session); | ||
// if it is called while we have activeStreams - timer will not be rescheduled | ||
// until last active stream is closed, then it will call .refresh() on the timer | ||
// important part is to not clearTimeout(timer) or it becomes unusable | ||
// for future refreshes | ||
if ( | ||
sessionInfo !== undefined && | ||
sessionInfo.activeStreams === 0 && | ||
Date.now() - sessionInfo.lastIdle >= ctx.sessionIdleTimeout | ||
) { | ||
ctx.trace( | ||
'Session idle timeout triggered for ' + | ||
socket?.remoteAddress + | ||
':' + | ||
socket?.remotePort + | ||
' last idle at ' + | ||
sessionInfo.lastIdle | ||
); | ||
ctx.closeSession(session); | ||
} | ||
} | ||
private onStreamOpened(stream: http2.ServerHttp2Stream) { | ||
const session = stream.session as http2.ServerHttp2Session; | ||
const idleTimeoutObj = this.sessionIdleTimeouts.get(session); | ||
if (idleTimeoutObj) { | ||
idleTimeoutObj.activeStreams += 1; | ||
stream.once('close', idleTimeoutObj.onClose); | ||
} | ||
} | ||
private onStreamClose(session: http2.ServerHttp2Session) { | ||
const idleTimeoutObj = this.sessionIdleTimeouts.get(session); | ||
if (idleTimeoutObj) { | ||
idleTimeoutObj.activeStreams -= 1; | ||
if (idleTimeoutObj.activeStreams === 0) { | ||
idleTimeoutObj.lastIdle = Date.now(); | ||
idleTimeoutObj.timeout.refresh(); | ||
this.trace( | ||
'Session onStreamClose' + | ||
session.socket?.remoteAddress + | ||
':' + | ||
session.socket?.remotePort + | ||
' at ' + | ||
idleTimeoutObj.lastIdle | ||
); | ||
} | ||
} | ||
} | ||
} | ||
@@ -1444,3 +1815,3 @@ | ||
details: 'OK', | ||
metadata: trailer ?? null | ||
metadata: trailer ?? null, | ||
}); | ||
@@ -1462,3 +1833,3 @@ }); | ||
details: `Received a second request message for server streaming method ${handler.path}`, | ||
metadata: null | ||
metadata: null, | ||
}); | ||
@@ -1475,7 +1846,12 @@ return; | ||
details: `Received no request message for server streaming method ${handler.path}`, | ||
metadata: null | ||
metadata: null, | ||
}); | ||
return; | ||
} | ||
stream = new ServerWritableStreamImpl(handler.path, call, requestMetadata, requestMessage); | ||
stream = new ServerWritableStreamImpl( | ||
handler.path, | ||
call, | ||
requestMetadata, | ||
requestMessage | ||
); | ||
try { | ||
@@ -1486,4 +1862,6 @@ handler.func(stream, respond); | ||
code: Status.UNKNOWN, | ||
details: `Server method handler threw error ${(err as Error).message}`, | ||
metadata: null | ||
details: `Server method handler threw error ${ | ||
(err as Error).message | ||
}`, | ||
metadata: null, | ||
}); | ||
@@ -1521,3 +1899,3 @@ } | ||
details: 'OK', | ||
metadata: trailer ?? null | ||
metadata: trailer ?? null, | ||
}); | ||
@@ -1535,4 +1913,6 @@ }); | ||
code: Status.UNKNOWN, | ||
details: `Server method handler threw error ${(err as Error).message}`, | ||
metadata: null | ||
details: `Server method handler threw error ${ | ||
(err as Error).message | ||
}`, | ||
metadata: null, | ||
}); | ||
@@ -1575,3 +1955,3 @@ } | ||
details: `Received a second request message for server streaming method ${handler.path}`, | ||
metadata: null | ||
metadata: null, | ||
}); | ||
@@ -1588,7 +1968,12 @@ return; | ||
details: `Received no request message for server streaming method ${handler.path}`, | ||
metadata: null | ||
metadata: null, | ||
}); | ||
return; | ||
} | ||
stream = new ServerWritableStreamImpl(handler.path, call, requestMetadata, requestMessage); | ||
stream = new ServerWritableStreamImpl( | ||
handler.path, | ||
call, | ||
requestMetadata, | ||
requestMessage | ||
); | ||
try { | ||
@@ -1599,4 +1984,6 @@ handler.func(stream); | ||
code: Status.UNKNOWN, | ||
details: `Server method handler threw error ${(err as Error).message}`, | ||
metadata: null | ||
details: `Server method handler threw error ${ | ||
(err as Error).message | ||
}`, | ||
metadata: null, | ||
}); | ||
@@ -1629,4 +2016,6 @@ } | ||
code: Status.UNKNOWN, | ||
details: `Server method handler threw error ${(err as Error).message}`, | ||
metadata: null | ||
details: `Server method handler threw error ${ | ||
(err as Error).message | ||
}`, | ||
metadata: null, | ||
}); | ||
@@ -1633,0 +2022,0 @@ } |
@@ -359,13 +359,19 @@ /* | ||
if (!(typeof obj === 'object' && obj !== null)) { | ||
throw new Error(`Invalid loadBalancingConfig: unexpected type ${typeof obj}`); | ||
throw new Error( | ||
`Invalid loadBalancingConfig: unexpected type ${typeof obj}` | ||
); | ||
} | ||
const keys = Object.keys(obj); | ||
if (keys.length > 1) { | ||
throw new Error(`Invalid loadBalancingConfig: unexpected multiple keys ${keys}`); | ||
throw new Error( | ||
`Invalid loadBalancingConfig: unexpected multiple keys ${keys}` | ||
); | ||
} | ||
if (keys.length === 0) { | ||
throw new Error('Invalid loadBalancingConfig: load balancing policy name required'); | ||
throw new Error( | ||
'Invalid loadBalancingConfig: load balancing policy name required' | ||
); | ||
} | ||
return { | ||
[keys[0]]: obj[keys[0]] | ||
[keys[0]]: obj[keys[0]], | ||
}; | ||
@@ -389,3 +395,2 @@ } | ||
for (const config of obj.loadBalancingConfig) { | ||
result.loadBalancingConfig.push(validateLoadBalancingConfig(config)); | ||
@@ -392,0 +397,0 @@ } |
@@ -18,3 +18,3 @@ /* | ||
import { SubchannelRef } from './channelz'; | ||
import type { SubchannelRef } from './channelz'; | ||
import { ConnectivityState } from './connectivity-state'; | ||
@@ -21,0 +21,0 @@ import { Subchannel } from './subchannel'; |
@@ -34,6 +34,9 @@ /* | ||
ChannelzChildrenTracker, | ||
ChannelzChildrenTrackerStub, | ||
SubchannelInfo, | ||
registerChannelzSubchannel, | ||
ChannelzCallTracker, | ||
ChannelzCallTrackerStub, | ||
unregisterChannelzRef, | ||
ChannelzTraceStub, | ||
} from './channelz'; | ||
@@ -93,8 +96,11 @@ import { | ||
private channelzRef: SubchannelRef; | ||
private channelzTrace: ChannelzTrace; | ||
private callTracker = new ChannelzCallTracker(); | ||
private childrenTracker = new ChannelzChildrenTracker(); | ||
private channelzTrace: ChannelzTrace | ChannelzTraceStub; | ||
private callTracker: ChannelzCallTracker | ChannelzCallTrackerStub; | ||
private childrenTracker: | ||
| ChannelzChildrenTracker | ||
| ChannelzChildrenTrackerStub; | ||
// Channelz socket info | ||
private streamTracker = new ChannelzCallTracker(); | ||
private streamTracker: ChannelzCallTracker | ChannelzCallTrackerStub; | ||
@@ -132,4 +138,13 @@ /** | ||
this.channelzEnabled = false; | ||
this.channelzTrace = new ChannelzTraceStub(); | ||
this.callTracker = new ChannelzCallTrackerStub(); | ||
this.childrenTracker = new ChannelzChildrenTrackerStub(); | ||
this.streamTracker = new ChannelzCallTrackerStub(); | ||
} else { | ||
this.channelzTrace = new ChannelzTrace(); | ||
this.callTracker = new ChannelzCallTracker(); | ||
this.childrenTracker = new ChannelzChildrenTracker(); | ||
this.streamTracker = new ChannelzCallTracker(); | ||
} | ||
this.channelzTrace = new ChannelzTrace(); | ||
this.channelzRef = registerChannelzSubchannel( | ||
@@ -140,5 +155,4 @@ this.subchannelAddressString, | ||
); | ||
if (this.channelzEnabled) { | ||
this.channelzTrace.addTrace('CT_INFO', 'Subchannel created'); | ||
} | ||
this.channelzTrace.addTrace('CT_INFO', 'Subchannel created'); | ||
this.trace( | ||
@@ -345,8 +359,4 @@ 'Subchannel constructed with options ' + | ||
if (this.refcount === 0) { | ||
if (this.channelzEnabled) { | ||
this.channelzTrace.addTrace('CT_INFO', 'Shutting down'); | ||
} | ||
if (this.channelzEnabled) { | ||
unregisterChannelzRef(this.channelzRef); | ||
} | ||
this.channelzTrace.addTrace('CT_INFO', 'Shutting down'); | ||
unregisterChannelzRef(this.channelzRef); | ||
process.nextTick(() => { | ||
@@ -353,0 +363,0 @@ this.transitionToState( |
@@ -31,2 +31,3 @@ /* | ||
ChannelzCallTracker, | ||
ChannelzCallTrackerStub, | ||
registerChannelzSocket, | ||
@@ -140,3 +141,3 @@ SocketInfo, | ||
private readonly channelzEnabled: boolean = true; | ||
private streamTracker = new ChannelzCallTracker(); | ||
private streamTracker: ChannelzCallTracker | ChannelzCallTrackerStub; | ||
private keepalivesSent = 0; | ||
@@ -164,3 +165,7 @@ private messagesSent = 0; | ||
this.channelzEnabled = false; | ||
this.streamTracker = new ChannelzCallTrackerStub(); | ||
} else { | ||
this.streamTracker = new ChannelzCallTracker(); | ||
} | ||
this.channelzRef = registerChannelzSocket( | ||
@@ -171,2 +176,3 @@ this.subchannelAddressString, | ||
); | ||
// Build user-agent string. | ||
@@ -199,2 +205,3 @@ this.userAgent = [ | ||
}); | ||
session.once( | ||
@@ -213,6 +220,12 @@ 'goaway', | ||
} | ||
this.trace('connection closed by GOAWAY with code ' + errorCode + ' and data ' + opaqueData?.toString()); | ||
this.trace( | ||
'connection closed by GOAWAY with code ' + | ||
errorCode + | ||
' and data ' + | ||
opaqueData?.toString() | ||
); | ||
this.reportDisconnectToOwner(tooManyPings); | ||
} | ||
); | ||
session.once('error', error => { | ||
@@ -223,2 +236,3 @@ /* Do nothing here. Any error should also trigger a close event, which is | ||
}); | ||
if (logging.isTracerEnabled(TRACER_NAME)) { | ||
@@ -242,2 +256,3 @@ session.on('remoteSettings', (settings: http2.Settings) => { | ||
} | ||
/* Start the keepalive timer last, because this can trigger trace logs, | ||
@@ -473,3 +488,4 @@ * which should only happen after everything else is set up. */ | ||
this.maybeSendPing(); | ||
}, this.keepaliveTimeMs).unref?.(); | ||
}, this.keepaliveTimeMs); | ||
this.keepaliveTimerId.unref?.(); | ||
} | ||
@@ -632,2 +648,3 @@ /* Otherwise, there is already either a keepalive timer or a ping pending, | ||
constructor(private channelTarget: GrpcUri) {} | ||
private trace(text: string) { | ||
@@ -640,2 +657,3 @@ logging.trace( | ||
} | ||
private createSession( | ||
@@ -650,2 +668,3 @@ address: SubchannelAddress, | ||
} | ||
return new Promise<Http2Transport>((resolve, reject) => { | ||
@@ -777,2 +796,3 @@ let remoteName: string | null; | ||
} | ||
connect( | ||
@@ -779,0 +799,0 @@ address: SubchannelAddress, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1827838
37573
83
29
+ Added@js-sdsl/ordered-map@^4.4.2
+ Added@js-sdsl/ordered-map@4.4.2(transitive)
- Removed@types/node@>=12.12.47
Updated@grpc/proto-loader@^0.7.10