Comparing version 2.10.3 to 2.11.0
@@ -49,2 +49,2 @@ export { NatsConnectionImpl } from "./nats"; | ||
export { ServiceError, ServiceErrorCodeHeader, ServiceErrorHeader, ServiceVerb, } from "./service"; | ||
export type { Endpoint, EndpointStats, SchemaInfo, Service, ServiceConfig, ServiceIdentity, ServiceInfo, ServiceMsg, ServiceSchema, ServiceStats, } from "./service"; | ||
export type { Endpoint, EndpointOptions, EndpointSchema, EndpointStats, NamedEndpointStats, SchemaInfo, Service, ServiceConfig, ServiceGroup, ServiceHandler, ServiceIdentity, ServiceInfo, ServiceMsg, ServiceResponse, ServiceResponseType, ServiceSchema, ServiceStats, } from "./service"; |
export { AckPolicy, AdvisoryKind, Bench, canonicalMIMEHeaderKey, checkJsError, consumerOpts, createInbox, credsAuthenticator, DebugEvents, deferred, DeliverPolicy, DiscardPolicy, Empty, ErrorCode, Events, headers, isFlowControlMsg, isHeartbeatMsg, JsHeaders, JSONCodec, jwtAuthenticator, Match, Metric, millis, MsgHdrsImpl, nanos, NatsError, nkeyAuthenticator, Nuid, nuid, ReplayPolicy, RequestStrategy, RetentionPolicy, ServiceError, ServiceErrorCodeHeader, ServiceErrorHeader, ServiceVerb, StorageType, StringCodec, toJsMsg, tokenAuthenticator, usernamePasswordAuthenticator, } from "./internal_mod"; | ||
export type { AccountLimits, Advisory, ApiError, ApiPagedRequest, Auth, Authenticator, BenchOpts, callbackFn, Closed, ClusterInfo, Codec, ConnectionOptions, Consumer, ConsumerAPI, ConsumerConfig, ConsumerInfo, ConsumerInfoable, ConsumerOpts, ConsumerOptsBuilder, ConsumerUpdateConfig, Deferred, DeliveryInfo, Destroyable, DirectMsgHeaders, DispatchedFn, Endpoint, EndpointStats, ExternalStream, IngestionFilterFn, IngestionFilterFnResult, JetStreamAccountStats, JetStreamApiStats, JetStreamClient, JetStreamManager, JetStreamOptions, JetStreamPublishOptions, JetStreamPullSubscription, JetStreamSubscription, JetStreamSubscriptionOptions, JetStreamUsageAccountLimits, JsMsg, JsMsgCallback, JwtAuth, KV, KvCodec, KvCodecs, KvEntry, KvLimits, KvOptions, KvPutOptions, KvStatus, KvWatchOptions, LastForMsgRequest, Lister, LostStreamData, Msg, MsgAdapter, MsgDeleteRequest, MsgHdrs, MsgRequest, Nanos, NatsConnection, NKeyAuth, NoAuth, ObjectInfo, ObjectResult, ObjectStore, ObjectStoreLink, ObjectStoreMeta, ObjectStoreMetaOptions, ObjectStoreOptions, ObjectStorePutOpts, ObjectStoreStatus, PeerInfo, Perf, Placement, ProtocolFilterFn, PubAck, PublishOptions, Pullable, PullOptions, PurgeBySeq, PurgeBySubject, PurgeOpts, PurgeResponse, PurgeTrimOpts, QueuedIterator, Republish, RepublishHeaders, RequestManyOptions, RequestOptions, RoKV, SchemaInfo, SeqMsgRequest, SequenceInfo, ServerInfo, ServersChanged, Service, ServiceClient, ServiceConfig, ServiceIdentity, ServiceInfo, ServiceMsg, ServicesAPI, ServiceSchema, ServiceStats, Stats, Status, StoredMsg, StreamAlternate, StreamAPI, StreamConfig, StreamInfo, StreamInfoRequestOptions, StreamNames, StreamSource, StreamSourceInfo, StreamState, StreamUpdateConfig, Sub, SubOpts, Subscription, SubscriptionOptions, TlsOptions, TokenAuth, TypedCallback, TypedSubscriptionOptions, UserPass, Views, } from "./internal_mod"; | ||
export type { AccountLimits, Advisory, ApiError, ApiPagedRequest, Auth, Authenticator, BenchOpts, callbackFn, Closed, ClusterInfo, Codec, ConnectionOptions, Consumer, ConsumerAPI, ConsumerConfig, ConsumerInfo, ConsumerInfoable, ConsumerOpts, ConsumerOptsBuilder, ConsumerUpdateConfig, Deferred, DeliveryInfo, Destroyable, DirectMsgHeaders, DispatchedFn, Endpoint, EndpointOptions, EndpointSchema, EndpointStats, ExternalStream, IngestionFilterFn, IngestionFilterFnResult, JetStreamAccountStats, JetStreamApiStats, JetStreamClient, JetStreamManager, JetStreamOptions, JetStreamPublishOptions, JetStreamPullSubscription, JetStreamSubscription, JetStreamSubscriptionOptions, JetStreamUsageAccountLimits, JsMsg, JsMsgCallback, JwtAuth, KV, KvCodec, KvCodecs, KvEntry, KvLimits, KvOptions, KvPutOptions, KvStatus, KvWatchOptions, LastForMsgRequest, Lister, LostStreamData, Msg, MsgAdapter, MsgDeleteRequest, MsgHdrs, MsgRequest, NamedEndpointStats, Nanos, NatsConnection, NKeyAuth, NoAuth, ObjectInfo, ObjectResult, ObjectStore, ObjectStoreLink, ObjectStoreMeta, ObjectStoreMetaOptions, ObjectStoreOptions, ObjectStorePutOpts, ObjectStoreStatus, PeerInfo, Perf, Placement, ProtocolFilterFn, PubAck, PublishOptions, Pullable, PullOptions, PurgeBySeq, PurgeBySubject, PurgeOpts, PurgeResponse, PurgeTrimOpts, QueuedIterator, Republish, RepublishHeaders, RequestManyOptions, RequestOptions, RoKV, SchemaInfo, SeqMsgRequest, SequenceInfo, ServerInfo, ServersChanged, Service, ServiceClient, ServiceConfig, ServiceGroup, ServiceHandler, ServiceIdentity, ServiceInfo, ServiceMsg, ServiceResponse, ServiceResponseType, ServicesAPI, ServiceSchema, ServiceStats, Stats, Status, StoredMsg, StreamAlternate, StreamAPI, StreamConfig, StreamInfo, StreamInfoRequestOptions, StreamNames, StreamSource, StreamSourceInfo, StreamState, StreamUpdateConfig, Sub, SubOpts, Subscription, SubscriptionOptions, TlsOptions, TokenAuth, TypedCallback, TypedSubscriptionOptions, UserPass, Views, } from "./internal_mod"; |
@@ -22,4 +22,16 @@ import { Deferred } from "./util"; | ||
} | ||
export interface ServiceIdentity { | ||
export declare enum ServiceResponseType { | ||
STATS = "io.nats.micro.v1.stats_response", | ||
INFO = "io.nats.micro.v1.info_response", | ||
PING = "io.nats.micro.v1.ping_response", | ||
SCHEMA = "io.nats.micro.v1.schema_response" | ||
} | ||
export interface ServiceResponse { | ||
/** | ||
* Response type schema | ||
*/ | ||
type: ServiceResponseType; | ||
} | ||
export type ServiceIdentity = ServiceResponse & { | ||
/** | ||
* The kind of the service reporting the stats | ||
@@ -36,3 +48,3 @@ */ | ||
version: string; | ||
} | ||
}; | ||
export interface ServiceMsg extends Msg { | ||
@@ -50,4 +62,28 @@ respondError(code: number, description: string, data?: Uint8Array, opts?: PublishOptions): boolean; | ||
} | ||
export interface Service extends QueuedIterator<ServiceMsg> { | ||
export interface ServiceGroup { | ||
/** | ||
* The name of the endpoint must be a simple subject token with no wildcards | ||
* @param name | ||
* @param opts is either a handler or a more complex options which allows a | ||
* subject, handler, and/or schema | ||
*/ | ||
addEndpoint(name: string, opts?: ServiceHandler | EndpointOptions): QueuedIterator<ServiceMsg>; | ||
/** | ||
* A group is a subject prefix from which endpoints can be added. | ||
* Can be empty to allow for prefixes or tokens that are set at runtime | ||
* without requiring editing of the service. | ||
* @param subject | ||
*/ | ||
addGroup(subject?: string): ServiceGroup; | ||
} | ||
export declare class ServiceGroupImpl implements ServiceGroup { | ||
subject: string; | ||
srv: ServiceImpl; | ||
constructor(parent: ServiceGroup, name?: string); | ||
calcSubject(root: string, name?: string): string; | ||
addEndpoint(name?: string, opts?: ServiceHandler | EndpointOptions): QueuedIterator<ServiceMsg>; | ||
addGroup(name?: string): ServiceGroup; | ||
} | ||
export interface Service extends ServiceGroup, QueuedIterator<ServiceMsg> { | ||
/** | ||
* A promise that gets resolved to null or Error once the service ends. | ||
@@ -80,7 +116,12 @@ * If an error, then service exited because of an error. | ||
} | ||
/** | ||
* Statistics for an endpoint | ||
*/ | ||
export type EndpointStats = ServiceIdentity & { | ||
export type NamedEndpointStats = { | ||
/** | ||
* The name of the endpoint | ||
*/ | ||
name: string; | ||
/** | ||
* The subject the endpoint is listening on | ||
*/ | ||
subject: string; | ||
/** | ||
* The number of requests received by the endpoint | ||
@@ -109,2 +150,8 @@ */ | ||
average_processing_time: Nanos; | ||
}; | ||
/** | ||
* Statistics for an endpoint | ||
*/ | ||
export type EndpointStats = ServiceIdentity & { | ||
endpoints?: NamedEndpointStats[]; | ||
/** | ||
@@ -116,3 +163,4 @@ * ISO Date string when the service started | ||
export type ServiceSchema = ServiceIdentity & { | ||
schema: SchemaInfo; | ||
api_url?: string; | ||
endpoints: EndpointSchema[]; | ||
}; | ||
@@ -123,2 +171,16 @@ export type SchemaInfo = { | ||
}; | ||
export type EndpointSchema = { | ||
/** | ||
* Endpoint Name | ||
*/ | ||
name: string; | ||
/** | ||
* Subject the endpoint receiving requests on | ||
*/ | ||
subject: string; | ||
/** | ||
* Optional schema if defined | ||
*/ | ||
schema?: SchemaInfo; | ||
}; | ||
export type ServiceInfo = ServiceIdentity & { | ||
@@ -132,3 +194,3 @@ /** | ||
*/ | ||
subject: string; | ||
subjects: string[]; | ||
}; | ||
@@ -151,8 +213,9 @@ export type ServiceConfig = { | ||
*/ | ||
schema?: SchemaInfo; | ||
apiURL?: string; | ||
/** | ||
* A list of endpoints, typically one, but some services may | ||
* want more than one endpoint | ||
* An optional endpoint mapping a handler to a subject. | ||
* More complex multi-endpoint services can be achieved by | ||
* {@link Service}.addEndpoint() and addGroup(). | ||
*/ | ||
endpoint: Endpoint; | ||
endpoint?: Endpoint; | ||
/** | ||
@@ -165,2 +228,3 @@ * A customized handler for the stats of an endpoint. The | ||
}; | ||
export type ServiceHandler = (err: NatsError | null, msg: ServiceMsg) => void; | ||
/** | ||
@@ -171,12 +235,17 @@ * A service Endpoint | ||
/** | ||
* Subject where the endpoint is listening | ||
* Subject where the endpoint listens | ||
*/ | ||
subject: string; | ||
/** | ||
* Handler for the endpoint - if not set the service is an iterator | ||
* An optional handler - if not set the service is an iterator | ||
* @param err | ||
* @param msg | ||
*/ | ||
handler?: (err: NatsError | null, msg: ServiceMsg) => void; | ||
handler?: ServiceHandler; | ||
/** | ||
* An optional schema | ||
*/ | ||
schema?: SchemaInfo; | ||
}; | ||
export type EndpointOptions = Partial<Endpoint>; | ||
/** | ||
@@ -186,5 +255,11 @@ * The stats of a service | ||
export type ServiceStats = ServiceIdentity & EndpointStats; | ||
type ServiceSubscription<T = unknown> = Endpoint & { | ||
type NamedEndpoint = { | ||
name: string; | ||
} & Endpoint; | ||
type ServiceSubscription<T = unknown> = NamedEndpoint & { | ||
internal: boolean; | ||
sub: Sub<T>; | ||
qi?: QueuedIterator<T>; | ||
stats: NamedEndpointStatsImpl; | ||
schema?: SchemaInfo; | ||
}; | ||
@@ -201,9 +276,8 @@ export declare class ServiceError extends Error { | ||
config: ServiceConfig; | ||
handler: ServiceSubscription; | ||
handlers: ServiceSubscription[]; | ||
internal: ServiceSubscription[]; | ||
_stopped: boolean; | ||
_done: Deferred<Error | null>; | ||
_stats: EndpointStats; | ||
_lastException?: Error; | ||
_schema?: Uint8Array; | ||
started: string; | ||
/** | ||
@@ -216,4 +290,4 @@ * @param verb | ||
static controlSubject(verb: ServiceVerb, name?: string, id?: string, prefix?: string): string; | ||
constructor(nc: NatsConnection, config: ServiceConfig); | ||
get subject(): string; | ||
constructor(nc: NatsConnection, config?: ServiceConfig); | ||
get subjects(): string[]; | ||
get id(): string; | ||
@@ -224,4 +298,3 @@ get name(): string; | ||
errorToHeader(err: Error): MsgHdrs; | ||
countError(err: Error): void; | ||
setupNATS(h: Endpoint, internal?: boolean): void; | ||
setupHandler(h: NamedEndpoint, internal?: boolean): ServiceSubscription; | ||
info(): ServiceInfo; | ||
@@ -236,5 +309,24 @@ stats(): Promise<ServiceStats>; | ||
stop(err?: Error): Promise<null | Error>; | ||
get schema(): Uint8Array; | ||
schema(): ServiceSchema; | ||
reset(): void; | ||
addGroup(name: string): ServiceGroup; | ||
addEndpoint(name: string, handler?: ServiceHandler | EndpointOptions): QueuedIterator<ServiceMsg>; | ||
_addEndpoint(e: NamedEndpoint, main?: boolean): QueuedIterator<ServiceMsg>; | ||
} | ||
declare class NamedEndpointStatsImpl implements NamedEndpointStats { | ||
name: string; | ||
subject: string; | ||
average_processing_time: Nanos; | ||
num_requests: number; | ||
processing_time: Nanos; | ||
num_errors: number; | ||
last_error?: string; | ||
data?: unknown; | ||
constructor(name: string, subject: string); | ||
reset(qi?: QueuedIterator<unknown>): void; | ||
countLatency(start: number): void; | ||
countError(err: Error): void; | ||
_stats(): NamedEndpointStats; | ||
stats(qi?: QueuedIterator<unknown>): NamedEndpointStats; | ||
} | ||
export {}; |
@@ -12,5 +12,5 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ServiceImpl = exports.ServiceError = exports.ServiceMsgImpl = exports.ServiceVerb = exports.ServiceErrorCodeHeader = exports.ServiceErrorHeader = exports.ServiceApiPrefix = void 0; | ||
exports.ServiceImpl = exports.ServiceError = exports.ServiceGroupImpl = exports.ServiceMsgImpl = exports.ServiceResponseType = exports.ServiceVerb = exports.ServiceErrorCodeHeader = exports.ServiceErrorHeader = exports.ServiceApiPrefix = void 0; | ||
/* | ||
* Copyright 2022 The NATS Authors | ||
* Copyright 2022-2023 The NATS Authors | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
@@ -55,2 +55,9 @@ * you may not use this file except in compliance with the License. | ||
})(ServiceVerb = exports.ServiceVerb || (exports.ServiceVerb = {})); | ||
var ServiceResponseType; | ||
(function (ServiceResponseType) { | ||
ServiceResponseType["STATS"] = "io.nats.micro.v1.stats_response"; | ||
ServiceResponseType["INFO"] = "io.nats.micro.v1.info_response"; | ||
ServiceResponseType["PING"] = "io.nats.micro.v1.ping_response"; | ||
ServiceResponseType["SCHEMA"] = "io.nats.micro.v1.schema_response"; | ||
})(ServiceResponseType = exports.ServiceResponseType || (exports.ServiceResponseType = {})); | ||
class ServiceMsgImpl { | ||
@@ -82,3 +89,71 @@ constructor(msg) { | ||
exports.ServiceMsgImpl = ServiceMsgImpl; | ||
// FIXME: perhaps the client is presented with a Request = Msg, but adds a respondError(code, description) | ||
class ServiceGroupImpl { | ||
constructor(parent, name = "") { | ||
if (name !== "") { | ||
validInternalToken("service group", name); | ||
} | ||
let root = ""; | ||
if (parent instanceof ServiceImpl) { | ||
this.srv = parent; | ||
root = ""; | ||
} | ||
else if (parent instanceof ServiceGroupImpl) { | ||
const sg = parent; | ||
this.srv = sg.srv; | ||
root = sg.subject; | ||
} | ||
else { | ||
throw new Error("unknown ServiceGroup type"); | ||
} | ||
this.subject = this.calcSubject(root, name); | ||
} | ||
calcSubject(root, name = "") { | ||
if (name === "") { | ||
return root; | ||
} | ||
return root !== "" ? `${root}.${name}` : name; | ||
} | ||
addEndpoint(name = "", opts) { | ||
opts = opts || { subject: name }; | ||
const args = typeof opts === "function" | ||
? { handler: opts, subject: name } | ||
: opts; | ||
(0, jsutil_1.validateName)("endpoint", name); | ||
let { subject, handler, schema } = args; | ||
subject = subject || name; | ||
validSubjectName("endpoint subject", subject); | ||
subject = this.calcSubject(this.subject, subject); | ||
const ne = { name, subject, handler, schema }; | ||
return this.srv._addEndpoint(ne); | ||
} | ||
addGroup(name = "") { | ||
return new ServiceGroupImpl(this, name); | ||
} | ||
} | ||
exports.ServiceGroupImpl = ServiceGroupImpl; | ||
function validSubjectName(context, subj) { | ||
if (subj === "") { | ||
throw new Error(`${context} cannot be empty`); | ||
} | ||
if (subj.indexOf(" ") !== -1) { | ||
throw new Error(`${context} cannot contain spaces: '${subj}'`); | ||
} | ||
const tokens = subj.split("."); | ||
tokens.forEach((v, idx) => { | ||
if (v === ">" && idx !== tokens.length - 1) { | ||
throw new Error(`${context} cannot have internal '>': '${subj}'`); | ||
} | ||
}); | ||
} | ||
function validInternalToken(context, subj) { | ||
if (subj.indexOf(" ") !== -1) { | ||
throw new Error(`${context} cannot contain spaces: '${subj}'`); | ||
} | ||
const tokens = subj.split("."); | ||
tokens.forEach((v) => { | ||
if (v === ">") { | ||
throw new Error(`${context} name cannot contain internal '>': '${subj}'`); | ||
} | ||
}); | ||
} | ||
class ServiceError extends Error { | ||
@@ -118,5 +193,5 @@ constructor(code, message) { | ||
} | ||
(0, jsutil_1.validName)(name); | ||
(0, jsutil_1.validateName)("control subject name", name); | ||
if (id !== "") { | ||
(0, jsutil_1.validName)(id); | ||
(0, jsutil_1.validateName)("control subject id", id); | ||
return `${pre}.${verb}.${name}.${id}`; | ||
@@ -126,27 +201,28 @@ } | ||
} | ||
constructor(nc, config) { | ||
var _a; | ||
constructor(nc, config = { name: "", version: "" }) { | ||
var _a, _b, _c; | ||
super(); | ||
this.nc = nc; | ||
config.name = (config === null || config === void 0 ? void 0 : config.name) || ""; | ||
this.config = config; | ||
const n = (0, jsutil_1.validName)(this.name); | ||
if (n !== "") { | ||
throw new Error(`name ${n}`); | ||
} | ||
// this will throw if no name | ||
(0, jsutil_1.validateName)("name", this.config.name); | ||
// this will throw if not semver | ||
(0, semver_1.parseSemVer)(this.config.version); | ||
this.noIterator = typeof ((_a = config === null || config === void 0 ? void 0 : config.endpoint) === null || _a === void 0 ? void 0 : _a.handler) === "function"; | ||
if (!this.noIterator) { | ||
this.config.endpoint.handler = (err, msg) => { | ||
err ? this.stop(err).catch() : this.push(new ServiceMsgImpl(msg)); | ||
}; | ||
} | ||
// initialize the stats | ||
this.reset(); | ||
this._id = nuid_1.nuid.next(); | ||
this.handler = config.endpoint; | ||
this.internal = []; | ||
this._done = (0, util_1.deferred)(); | ||
this._stopped = false; | ||
this.handlers = []; | ||
this.noIterator = true; | ||
this.started = new Date().toISOString(); | ||
// initialize the stats | ||
this.reset(); | ||
if (this.config.endpoint) { | ||
this._addEndpoint({ | ||
name: "default", | ||
subject: (_a = this.config.endpoint) === null || _a === void 0 ? void 0 : _a.subject, | ||
handler: (_b = this.config.endpoint) === null || _b === void 0 ? void 0 : _b.handler, | ||
schema: (_c = this.config.endpoint) === null || _c === void 0 ? void 0 : _c.schema, | ||
}, true); | ||
} | ||
// close if the connection closes | ||
@@ -160,15 +236,9 @@ this.nc.closed() | ||
}); | ||
// close the service if the iterator closes | ||
if (!this.noIterator) { | ||
this.iterClosed.then(() => { | ||
this.close().catch(); | ||
}); | ||
} | ||
} | ||
get subject() { | ||
const { subject } = this.config.endpoint; | ||
if (subject !== "") { | ||
return subject; | ||
} | ||
return ""; | ||
get subjects() { | ||
return this.handlers.filter((s) => { | ||
return s.internal === false; | ||
}).map((s) => { | ||
return s.subject; | ||
}); | ||
} | ||
@@ -201,11 +271,6 @@ get id() { | ||
} | ||
countError(err) { | ||
this._lastException = err; | ||
this._stats.num_errors++; | ||
this._stats.last_error = err.message; | ||
} | ||
setupNATS(h, internal = false) { | ||
setupHandler(h, internal = false) { | ||
// internals don't use a queue | ||
const queue = internal ? "" : "q"; | ||
const { subject, handler } = h; | ||
const { name, subject, handler, schema } = h; | ||
const sv = h; | ||
@@ -216,9 +281,4 @@ sv.internal = internal; | ||
} | ||
const countLatency = (start) => { | ||
if (internal) | ||
return; | ||
this._stats.num_requests++; | ||
this._stats.processing_time = (0, jsutil_1.nanos)(Date.now() - start); | ||
this._stats.average_processing_time = Math.round(this._stats.processing_time / this._stats.num_requests); | ||
}; | ||
sv.stats = new NamedEndpointStatsImpl(name, subject); | ||
sv.schema = schema; | ||
const callback = handler | ||
@@ -235,7 +295,7 @@ ? (err, msg) => { | ||
catch (err) { | ||
this.countError(err); | ||
sv.stats.countError(err); | ||
msg === null || msg === void 0 ? void 0 : msg.respond(types_1.Empty, { headers: this.errorToHeader(err) }); | ||
} | ||
finally { | ||
countLatency(start); | ||
sv.stats.countLatency(start); | ||
} | ||
@@ -262,5 +322,7 @@ } | ||
}); | ||
return sv; | ||
} | ||
info() { | ||
return { | ||
type: ServiceResponseType.INFO, | ||
name: this.name, | ||
@@ -270,3 +332,3 @@ id: this.id, | ||
description: this.description, | ||
subject: this.config.endpoint.subject, | ||
subjects: this.subjects, | ||
}; | ||
@@ -276,22 +338,22 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (typeof this.config.statsHandler === "function") { | ||
try { | ||
this._stats.data = yield this.config.statsHandler(this.handler); | ||
const endpoints = []; | ||
for (const h of this.handlers) { | ||
if (typeof this.config.statsHandler === "function") { | ||
try { | ||
h.stats.data = yield this.config.statsHandler(h); | ||
} | ||
catch (err) { | ||
h.stats.countError(err); | ||
} | ||
} | ||
catch (err) { | ||
this.countError(err); | ||
} | ||
endpoints.push(h.stats.stats(h.qi)); | ||
} | ||
if (!this.noIterator) { | ||
this._stats.processing_time = this.time; | ||
this._stats.num_requests = this.processed; | ||
this._stats.average_processing_time = this.time > 0 && this.processed > 0 | ||
? this.time / this.processed | ||
: 0; | ||
} | ||
return Object.assign({ | ||
return { | ||
type: ServiceResponseType.STATS, | ||
name: this.name, | ||
id: this.id, | ||
version: this.version, | ||
}, this._stats); | ||
started: this.started, | ||
endpoints, | ||
}; | ||
}); | ||
@@ -310,3 +372,3 @@ } | ||
endpoint.handler = handler; | ||
this.setupNATS(endpoint, true); | ||
this.setupHandler(endpoint, true); | ||
} | ||
@@ -334,2 +396,3 @@ start() { | ||
const ping = jc.encode({ | ||
type: ServiceResponseType.PING, | ||
name: this.name, | ||
@@ -352,3 +415,3 @@ id: this.id, | ||
} | ||
msg === null || msg === void 0 ? void 0 : msg.respond(this.schema); | ||
msg === null || msg === void 0 ? void 0 : msg.respond((0, codec_1.JSONCodec)().encode(this.schema())); | ||
return Promise.resolve(); | ||
@@ -361,4 +424,3 @@ }; | ||
// now the actual service | ||
const handlers = [this.handler]; | ||
handlers.forEach((h) => { | ||
this.handlers.forEach((h) => { | ||
const { subject } = h; | ||
@@ -368,3 +430,9 @@ if (typeof subject !== "string") { | ||
} | ||
this.setupNATS(h); | ||
// this is expected in cases where main subject is just | ||
// a root subject for multiple endpoints - user can disable | ||
// listening to the root endpoint, by specifying null | ||
if (h.handler === null) { | ||
return; | ||
} | ||
this.setupHandler(h); | ||
}); | ||
@@ -378,7 +446,6 @@ return Promise.resolve(this); | ||
this._stopped = true; | ||
const buf = []; | ||
let buf = []; | ||
if (!this.nc.isClosed()) { | ||
buf.push(this.handler.sub.drain()); | ||
this.internal.forEach((serviceSub) => { | ||
buf.push(serviceSub.sub.drain()); | ||
buf = this.handlers.concat(this.internal).map((h) => { | ||
return h.sub.drain(); | ||
}); | ||
@@ -401,31 +468,111 @@ } | ||
} | ||
get schema() { | ||
const jc = (0, codec_1.JSONCodec)(); | ||
if (!this._schema) { | ||
this._schema = jc.encode({ | ||
name: this.name, | ||
id: this.id, | ||
version: this.version, | ||
schema: this.config.schema, | ||
schema() { | ||
const v = { | ||
type: ServiceResponseType.SCHEMA, | ||
name: this.name, | ||
id: this.id, | ||
version: this.version, | ||
api_url: this.config.apiURL, | ||
endpoints: [], | ||
}; | ||
v.endpoints = this.handlers.map((h) => { | ||
const { schema, subject, name } = h; | ||
return { schema, subject, name }; | ||
}); | ||
return v; | ||
} | ||
reset() { | ||
// pretend we restarted | ||
this.started = new Date().toISOString(); | ||
if (this.handlers) { | ||
for (const h of this.handlers) { | ||
h.stats.reset(h.qi); | ||
} | ||
} | ||
} | ||
addGroup(name) { | ||
return new ServiceGroupImpl(this, name); | ||
} | ||
addEndpoint(name, handler) { | ||
const sg = new ServiceGroupImpl(this); | ||
return sg.addEndpoint(name, handler); | ||
} | ||
_addEndpoint(e, main = false) { | ||
const qi = main ? this : new queued_iterator_1.QueuedIteratorImpl(); | ||
qi.noIterator = typeof e.handler === "function"; | ||
if (!qi.noIterator) { | ||
e.handler = (err, msg) => { | ||
err ? this.stop(err).catch() : qi.push(new ServiceMsgImpl(msg)); | ||
}; | ||
// close the service if the iterator closes | ||
qi.iterClosed.then(() => { | ||
this.close().catch(); | ||
}); | ||
} | ||
return this._schema; | ||
// track the iterator for stats | ||
const ss = this.setupHandler(e, false); | ||
ss.qi = qi; | ||
this.handlers.push(ss); | ||
return qi; | ||
} | ||
reset() { | ||
this._lastException = undefined; | ||
this._stats = { | ||
name: this.name, | ||
num_requests: 0, | ||
num_errors: 0, | ||
processing_time: 0, | ||
average_processing_time: 0, | ||
started: new Date().toISOString(), | ||
} | ||
exports.ServiceImpl = ServiceImpl; | ||
class NamedEndpointStatsImpl { | ||
constructor(name, subject) { | ||
this.name = name; | ||
this.subject = subject; | ||
this.average_processing_time = 0; | ||
this.num_errors = 0; | ||
this.num_requests = 0; | ||
this.processing_time = 0; | ||
} | ||
reset(qi) { | ||
this.num_requests = 0; | ||
this.processing_time = 0; | ||
this.average_processing_time = 0; | ||
this.num_errors = 0; | ||
this.last_error = undefined; | ||
this.data = undefined; | ||
const qii = qi; | ||
if (qii) { | ||
qii.time = 0; | ||
qii.processed = 0; | ||
} | ||
} | ||
countLatency(start) { | ||
this.num_requests++; | ||
this.processing_time += (0, jsutil_1.nanos)(Date.now() - start); | ||
this.average_processing_time = Math.round(this.processing_time / this.num_requests); | ||
} | ||
countError(err) { | ||
this.num_errors++; | ||
this.last_error = err.message; | ||
} | ||
_stats() { | ||
const { name, subject, average_processing_time, num_errors, num_requests, processing_time, last_error, data, } = this; | ||
return { | ||
name, | ||
subject, | ||
average_processing_time, | ||
num_errors, | ||
num_requests, | ||
processing_time, | ||
last_error, | ||
data, | ||
}; | ||
if (!this.noIterator) { | ||
this.processed = 0; | ||
this.time = 0; | ||
} | ||
stats(qi) { | ||
const qii = qi; | ||
if ((qii === null || qii === void 0 ? void 0 : qii.noIterator) === false) { | ||
// grab stats in the iterator | ||
this.processing_time = qii.time; | ||
this.num_requests = qii.processed; | ||
this.average_processing_time = | ||
this.processing_time > 0 && this.num_requests > 0 | ||
? this.processing_time / this.num_requests | ||
: 0; | ||
} | ||
return this._stats(); | ||
} | ||
} | ||
exports.ServiceImpl = ServiceImpl; | ||
//# sourceMappingURL=service.js.map |
@@ -21,3 +21,3 @@ "use strict"; | ||
/* | ||
* Copyright 2022 The NATS Authors | ||
* Copyright 2022-2023 The NATS Authors | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
@@ -24,0 +24,0 @@ * you may not use this file except in compliance with the License. |
@@ -46,3 +46,3 @@ "use strict"; | ||
const dns = require("dns"); | ||
const VERSION = "2.10.3"; | ||
const VERSION = "2.11.0"; | ||
const LANG = "nats.js"; | ||
@@ -49,0 +49,0 @@ class NodeTransport { |
{ | ||
"name": "nats", | ||
"version": "2.10.3", | ||
"version": "2.11.0", | ||
"description": "Node.js client for NATS, a lightweight, high-performance cloud native messaging system", | ||
@@ -43,3 +43,3 @@ "keywords": [ | ||
"clean": "shx rm -Rf ./lib/* ./nats-base-client ./.deps", | ||
"clone-nbc": "shx mkdir -p ./.deps && cd ./.deps && git clone --branch v1.10.3 https://github.com/nats-io/nats.deno.git", | ||
"clone-nbc": "shx mkdir -p ./.deps && cd ./.deps && git clone --branch v1.11.0 https://github.com/nats-io/nats.deno.git", | ||
"fmt": "deno fmt ./src/ ./examples/ ./test/", | ||
@@ -46,0 +46,0 @@ "prepack": "npm run clone-nbc && npm run cjs && npm run check-package && npm run build", |
@@ -813,2 +813,8 @@ # NATS.js - A [NATS](http://nats.io) client for [Node.Js](https://nodejs.org/en/) | ||
## Service API | ||
The service API allows you to [easily build NATS services](https://github.com/nats-io/nats.deno/blob/main/services.md) The | ||
services API is currently in beta functionality. | ||
## Contributing | ||
@@ -815,0 +821,0 @@ |
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
946270
16328
837