@rsdk/nats.producer.direct 5.3.0-next.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/direct/direct.autodoc.d.ts +7 -0
- package/dist/direct/direct.autodoc.js +28 -0
- package/dist/direct/direct.autodoc.js.map +1 -0
- package/dist/direct/direct.constants.d.ts +3 -0
- package/dist/direct/direct.constants.js +7 -0
- package/dist/direct/direct.constants.js.map +1 -0
- package/dist/direct/direct.decorator.d.ts +2 -0
- package/dist/direct/direct.decorator.js +16 -0
- package/dist/direct/direct.decorator.js.map +1 -0
- package/dist/direct/direct.event-factory.d.ts +10 -0
- package/dist/direct/direct.event-factory.js +23 -0
- package/dist/direct/direct.event-factory.js.map +1 -0
- package/dist/direct/direct.module-generator.d.ts +5 -0
- package/dist/direct/direct.module-generator.js +51 -0
- package/dist/direct/direct.module-generator.js.map +1 -0
- package/dist/direct/direct.module.d.ts +2 -0
- package/dist/direct/direct.module.js +22 -0
- package/dist/direct/direct.module.js.map +1 -0
- package/dist/direct/direct.producer.d.ts +13 -0
- package/dist/direct/direct.producer.js +40 -0
- package/dist/direct/direct.producer.js.map +1 -0
- package/dist/direct/index.d.ts +2 -0
- package/dist/direct/index.js +8 -0
- package/dist/direct/index.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/jest.config.js +1 -0
- package/jest.config.unit.js +1 -0
- package/package.json +33 -0
- package/src/direct/direct.autodoc.ts +48 -0
- package/src/direct/direct.constants.ts +6 -0
- package/src/direct/direct.decorator.ts +26 -0
- package/src/direct/direct.event-factory.ts +30 -0
- package/src/direct/direct.module-generator.ts +68 -0
- package/src/direct/direct.module.ts +10 -0
- package/src/direct/direct.producer.ts +52 -0
- package/src/direct/index.ts +2 -0
- package/src/direct.spec.ts +200 -0
- package/src/index.ts +1 -0
- package/tsconfig.build.json +12 -0
- package/tsconfig.json +7 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## [5.3.0-next.4](https://github.com/R-Vision/rsdk/compare/v5.3.0-next.3...v5.3.0-next.4) (2024-11-05)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **nats.producer:** direct nats producer alpha implementation ([#301](https://github.com/R-Vision/rsdk/issues/301)) ([d173b51](https://github.com/R-Vision/rsdk/commit/d173b51c664c718a214cdc695708cfdd40fc4dcb))
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DocumentResolver } from '@rsdk/autodoc.protocol';
|
|
2
|
+
import { Composite } from '@rsdk/autodoc.protocol';
|
|
3
|
+
import type { RsdkMetadataProvider } from '@rsdk/metadata';
|
|
4
|
+
export declare class NatsProducerDirectAutodocResolver implements DocumentResolver {
|
|
5
|
+
getNode(rsdkMetadataProvider: RsdkMetadataProvider): Composite | null;
|
|
6
|
+
}
|
|
7
|
+
export declare const natsProducerDirectAutodocResolver: NatsProducerDirectAutodocResolver;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.natsProducerDirectAutodocResolver = exports.NatsProducerDirectAutodocResolver = void 0;
|
|
4
|
+
const autodoc_protocol_1 = require("@rsdk/autodoc.protocol");
|
|
5
|
+
const nats_common_1 = require("@rsdk/nats.common");
|
|
6
|
+
const direct_constants_1 = require("./direct.constants");
|
|
7
|
+
class NatsProducerDirectAutodocResolver {
|
|
8
|
+
getNode(rsdkMetadataProvider) {
|
|
9
|
+
const resources = rsdkMetadataProvider.get(direct_constants_1.NATS_PRODUCED_RSDK_METADATA_SCOPE);
|
|
10
|
+
if (!resources) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return new autodoc_protocol_1.Composite(new autodoc_protocol_1.Table(resources
|
|
14
|
+
.filter((resource) => resource.value.type === nats_common_1.TopicType.PRODUCE)
|
|
15
|
+
.map((resource) => {
|
|
16
|
+
const { topicName, group: group, partitionKeyField, eventType, } = resource.value;
|
|
17
|
+
return {
|
|
18
|
+
TopicName: topicName,
|
|
19
|
+
Group: group ?? '-',
|
|
20
|
+
PartitionKeyField: partitionKeyField ?? '-',
|
|
21
|
+
EventType: eventType?.$type ?? '-',
|
|
22
|
+
};
|
|
23
|
+
})), 'Nats JetStream producer direct');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.NatsProducerDirectAutodocResolver = NatsProducerDirectAutodocResolver;
|
|
27
|
+
exports.natsProducerDirectAutodocResolver = new NatsProducerDirectAutodocResolver();
|
|
28
|
+
//# sourceMappingURL=direct.autodoc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"direct.autodoc.js","sourceRoot":"","sources":["../../src/direct/direct.autodoc.ts"],"names":[],"mappings":";;;AACA,6DAA0D;AAM1D,mDAA8C;AAE9C,yDAAuE;AAEvE,MAAa,iCAAiC;IAC5C,OAAO,CAAC,oBAA0C;QAChD,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CACxC,oDAAiC,CAClC,CAAC;QAEF,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,IAAI,4BAAS,CAClB,IAAI,wBAAK,CACP,SAAS;aACN,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,uBAAS,CAAC,OAAO,CAAC;aAC/D,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;YAChB,MAAM,EACJ,SAAS,EACT,KAAK,EAAE,KAAK,EACZ,iBAAiB,EACjB,SAAS,GACV,GAAiC,QAAQ,CAAC,KAAK,CAAC;YAEjD,OAAO;gBACL,SAAS,EAAE,SAAS;gBACpB,KAAK,EAAE,KAAK,IAAI,GAAG;gBACnB,iBAAiB,EAAE,iBAAiB,IAAI,GAAG;gBAC3C,SAAS,EAAE,SAAS,EAAE,KAAK,IAAI,GAAG;aACnC,CAAC;QACJ,CAAC,CAAC,CACL,EACD,gCAAgC,CACjC,CAAC;IACJ,CAAC;CACF;AAjCD,8EAiCC;AAEY,QAAA,iCAAiC,GAC5C,IAAI,iCAAiC,EAAE,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDirectProducerToken = exports.NATS_PRODUCED_RSDK_METADATA_SCOPE = void 0;
|
|
4
|
+
exports.NATS_PRODUCED_RSDK_METADATA_SCOPE = 'nats-producer-direct';
|
|
5
|
+
const createDirectProducerToken = (eventType) => `DIRECT_NATS_PRODUCER_${eventType.$type}`;
|
|
6
|
+
exports.createDirectProducerToken = createDirectProducerToken;
|
|
7
|
+
//# sourceMappingURL=direct.constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"direct.constants.js","sourceRoot":"","sources":["../../src/direct/direct.constants.ts"],"names":[],"mappings":";;;AAEa,QAAA,iCAAiC,GAAG,sBAAsB,CAAC;AAEjE,MAAM,yBAAyB,GAAG,CAAC,SAAyB,EAAU,EAAE,CAC7E,wBAAwB,SAAS,CAAC,KAAK,EAAE,CAAC;AAD/B,QAAA,yBAAyB,6BACM"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InjectDirectProducer = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const metadata_1 = require("@rsdk/metadata");
|
|
6
|
+
const direct_constants_1 = require("./direct.constants");
|
|
7
|
+
const direct_module_generator_1 = require("./direct.module-generator");
|
|
8
|
+
const InjectDirectProducer = (eventType) => {
|
|
9
|
+
return (target, propertyKey, parameterIndex) => {
|
|
10
|
+
const directProducerToken = (0, direct_constants_1.createDirectProducerToken)(eventType);
|
|
11
|
+
(0, common_1.Inject)(directProducerToken)(target, propertyKey, parameterIndex);
|
|
12
|
+
metadata_1.RsdkMetadata.setWithScope(target, metadata_1.PLATFORM_RAW_GLOBAL_METADATA_SCOPE, directProducerToken, direct_module_generator_1.DirectModuleGenerator.createModule(eventType), true);
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
exports.InjectDirectProducer = InjectDirectProducer;
|
|
16
|
+
//# sourceMappingURL=direct.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"direct.decorator.js","sourceRoot":"","sources":["../../src/direct/direct.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAAwC;AACxC,6CAGwB;AAGxB,yDAA+D;AAC/D,uEAAkE;AAE3D,MAAM,oBAAoB,GAAG,CAClC,SAAoB,EACA,EAAE;IACtB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,EAAE;QAC7C,MAAM,mBAAmB,GAAG,IAAA,4CAAyB,EAAC,SAAS,CAAC,CAAC;QAEjE,IAAA,eAAM,EAAC,mBAAmB,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;QACjE,uBAAY,CAAC,YAAY,CACvB,MAAM,EACN,6CAAkC,EAClC,mBAAmB,EACnB,+CAAqB,CAAC,YAAY,CAAC,SAAS,CAAC,EAC7C,IAAI,CACL,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC,CAAC;AAfW,QAAA,oBAAoB,wBAe/B"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { EventPayload, EventType } from '@rsdk/nats.common';
|
|
2
|
+
import { EventsFactory } from '@rsdk/nats.producer';
|
|
3
|
+
import type { MsgHdrs, Payload } from 'nats';
|
|
4
|
+
export declare class EventsFactoryDirect<E extends EventType> extends EventsFactory<E, Payload> {
|
|
5
|
+
create<P extends EventPayload<E>>(payload: P): {
|
|
6
|
+
headers: MsgHdrs;
|
|
7
|
+
payload: Payload;
|
|
8
|
+
};
|
|
9
|
+
private buildHeaders;
|
|
10
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventsFactoryDirect = void 0;
|
|
4
|
+
const nats_producer_1 = require("@rsdk/nats.producer");
|
|
5
|
+
const nats_1 = require("nats");
|
|
6
|
+
class EventsFactoryDirect extends nats_producer_1.EventsFactory {
|
|
7
|
+
create(payload) {
|
|
8
|
+
const metadata = this.getMetadata(this.eventType.$type, null);
|
|
9
|
+
return {
|
|
10
|
+
headers: this.buildHeaders(metadata),
|
|
11
|
+
payload: this.serializePayload(payload),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
buildHeaders(metadata) {
|
|
15
|
+
const headers = new nats_1.MsgHdrsImpl();
|
|
16
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
17
|
+
headers.set(key, value);
|
|
18
|
+
}
|
|
19
|
+
return headers;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.EventsFactoryDirect = EventsFactoryDirect;
|
|
23
|
+
//# sourceMappingURL=direct.event-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"direct.event-factory.js","sourceRoot":"","sources":["../../src/direct/direct.event-factory.ts"],"names":[],"mappings":";;;AACA,uDAAoD;AAEpD,+BAAmC;AAEnC,MAAa,mBAAyC,SAAQ,6BAG7D;IACC,MAAM,CACJ,OAAU;QAEV,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAE9D,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC;YACpC,OAAO,EAAE,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC;SACxC,CAAC;IACJ,CAAC;IAEO,YAAY,CAAC,QAAgC;QACnD,MAAM,OAAO,GAAG,IAAI,kBAAW,EAAE,CAAC;QAElC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC1B,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAxBD,kDAwBC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DirectModuleGenerator = void 0;
|
|
7
|
+
const autodoc_protocol_1 = require("@rsdk/autodoc.protocol");
|
|
8
|
+
const core_1 = require("@rsdk/core");
|
|
9
|
+
const metadata_1 = require("@rsdk/metadata");
|
|
10
|
+
const nats_common_1 = require("@rsdk/nats.common");
|
|
11
|
+
const nats_producer_1 = require("@rsdk/nats.producer");
|
|
12
|
+
const omit_1 = __importDefault(require("lodash/omit"));
|
|
13
|
+
const direct_autodoc_1 = require("./direct.autodoc");
|
|
14
|
+
const direct_constants_1 = require("./direct.constants");
|
|
15
|
+
const direct_module_1 = require("./direct.module");
|
|
16
|
+
const direct_producer_1 = require("./direct.producer");
|
|
17
|
+
class DirectModuleGenerator {
|
|
18
|
+
static createModule(eventType) {
|
|
19
|
+
const providers = [
|
|
20
|
+
{
|
|
21
|
+
inject: [nats_common_1.NATS_PRODUCER_INJECTION_TOKEN, nats_producer_1.ProducerConfig],
|
|
22
|
+
provide: (0, direct_constants_1.createDirectProducerToken)(eventType),
|
|
23
|
+
useFactory: (client, config) => {
|
|
24
|
+
return new direct_producer_1.DirectProducer(client, eventType, config);
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
const moduleDef = {
|
|
29
|
+
imports: [
|
|
30
|
+
nats_common_1.NatsClientModule,
|
|
31
|
+
direct_module_1.DirectNatsProducerModule,
|
|
32
|
+
core_1.PlatformConfigModule.forFeature(nats_producer_1.ProducerConfig),
|
|
33
|
+
],
|
|
34
|
+
providers,
|
|
35
|
+
module: DirectModuleGenerator,
|
|
36
|
+
exports: providers,
|
|
37
|
+
};
|
|
38
|
+
const rsdkNatsMetadata = new metadata_1.RsdkMetadata(moduleDef, nats_common_1.NATS_TOPIC_RSDK_METADATA_SCOPE);
|
|
39
|
+
rsdkNatsMetadata.add({
|
|
40
|
+
type: nats_common_1.TopicType.PRODUCE,
|
|
41
|
+
topicName: (0, nats_common_1.getSubjectName)(eventType),
|
|
42
|
+
group: eventType.$group,
|
|
43
|
+
partitionKeyField: eventType.$partitionKeyField,
|
|
44
|
+
eventType: (0, omit_1.default)(eventType, 'toJSON', 'encode', 'decode'),
|
|
45
|
+
});
|
|
46
|
+
autodoc_protocol_1.AutodocMetadata.defineResolver(moduleDef, nats_common_1.NATS_TOPIC_RSDK_METADATA_SCOPE, direct_autodoc_1.natsProducerDirectAutodocResolver);
|
|
47
|
+
return moduleDef;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.DirectModuleGenerator = DirectModuleGenerator;
|
|
51
|
+
//# sourceMappingURL=direct.module-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"direct.module-generator.js","sourceRoot":"","sources":["../../src/direct/direct.module-generator.ts"],"names":[],"mappings":";;;;;;AACA,6DAAyD;AACzD,qCAAkD;AAClD,6CAA8C;AAE9C,mDAM2B;AAC3B,uDAAqD;AACrD,uDAA+B;AAE/B,qDAAqE;AACrE,yDAA+D;AAC/D,mDAA2D;AAC3D,uDAAmD;AAEnD,MAAa,qBAAqB;IAChC,MAAM,CAAC,YAAY,CAAC,SAAoB;QACtC,MAAM,SAAS,GAAsB;YACnC;gBACE,MAAM,EAAE,CAAC,2CAA6B,EAAE,8BAAc,CAAC;gBACvD,OAAO,EAAE,IAAA,4CAAyB,EAAC,SAAS,CAAC;gBAC7C,UAAU,EAAE,CACV,MAAgB,EAChB,MAAsB,EACK,EAAE;oBAC7B,OAAO,IAAI,gCAAc,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;gBACvD,CAAC;aACF;SACF,CAAC;QAEF,MAAM,SAAS,GAAG;YAChB,OAAO,EAAE;gBACP,8BAAgB;gBAChB,wCAAwB;gBACxB,2BAAoB,CAAC,UAAU,CAAC,8BAAc,CAAC;aAChD;YACD,SAAS;YACT,MAAM,EAAE,qBAAqB;YAC7B,OAAO,EAAE,SAAS;SACnB,CAAC;QAEF,MAAM,gBAAgB,GAAG,IAAI,uBAAY,CACvC,SAAS,EACT,4CAA8B,CAC/B,CAAC;QAEF,gBAAgB,CAAC,GAAG,CAAC;YACnB,IAAI,EAAE,uBAAS,CAAC,OAAO;YACvB,SAAS,EAAE,IAAA,4BAAc,EAAC,SAAS,CAAC;YACpC,KAAK,EAAE,SAAS,CAAC,MAAM;YACvB,iBAAiB,EAAE,SAAS,CAAC,kBAAkB;YAC/C,SAAS,EAAE,IAAA,cAAI,EAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;SACzD,CAAC,CAAC;QAEH,kCAAe,CAAC,cAAc,CAC5B,SAAS,EACT,4CAA8B,EAC9B,kDAAiC,CAClC,CAAC;QAEF,OAAO,SAAS,CAAC;IACnB,CAAC;CACF;AA/CD,sDA+CC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.DirectNatsProducerModule = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const nats_common_1 = require("@rsdk/nats.common");
|
|
12
|
+
// import { DirectProducerIndicator } from './kafka-producer-direct.health-indicator';
|
|
13
|
+
let DirectNatsProducerModule = class DirectNatsProducerModule {
|
|
14
|
+
};
|
|
15
|
+
exports.DirectNatsProducerModule = DirectNatsProducerModule;
|
|
16
|
+
exports.DirectNatsProducerModule = DirectNatsProducerModule = __decorate([
|
|
17
|
+
(0, common_1.Module)({
|
|
18
|
+
imports: [nats_common_1.NatsClientModule],
|
|
19
|
+
// providers: [DirectProducerIndicator],
|
|
20
|
+
})
|
|
21
|
+
], DirectNatsProducerModule);
|
|
22
|
+
//# sourceMappingURL=direct.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"direct.module.js","sourceRoot":"","sources":["../../src/direct/direct.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,mDAAqD;AAErD,sFAAsF;AAM/E,IAAM,wBAAwB,GAA9B,MAAM,wBAAwB;CAAG,CAAA;AAA3B,4DAAwB;mCAAxB,wBAAwB;IAJpC,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,8BAAgB,CAAC;QAC3B,wCAAwC;KACzC,CAAC;GACW,wBAAwB,CAAG"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EventPayload, EventType, Producer } from '@rsdk/nats.common';
|
|
2
|
+
import type { NatsProducer, ProducerOptions, PublishOptions } from '@rsdk/nats.producer';
|
|
3
|
+
/**
|
|
4
|
+
* Producer, специализированный под конкретный ивент.
|
|
5
|
+
*/
|
|
6
|
+
export declare class DirectProducer<T extends EventType> implements NatsProducer<T> {
|
|
7
|
+
private readonly client;
|
|
8
|
+
private readonly eventType;
|
|
9
|
+
private readonly factory;
|
|
10
|
+
private readonly logger;
|
|
11
|
+
constructor(client: Producer, eventType: T, config: ProducerOptions);
|
|
12
|
+
publish<P extends EventPayload<T>>(payload: P, options?: PublishOptions): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DirectProducer = void 0;
|
|
4
|
+
const logging_1 = require("@rsdk/logging");
|
|
5
|
+
const nats_common_1 = require("@rsdk/nats.common");
|
|
6
|
+
const direct_event_factory_1 = require("./direct.event-factory");
|
|
7
|
+
/**
|
|
8
|
+
* Producer, специализированный под конкретный ивент.
|
|
9
|
+
*/
|
|
10
|
+
class DirectProducer {
|
|
11
|
+
client;
|
|
12
|
+
eventType;
|
|
13
|
+
factory;
|
|
14
|
+
logger = logging_1.LoggerFactory.create(DirectProducer.name);
|
|
15
|
+
constructor(client, eventType, config) {
|
|
16
|
+
this.client = client;
|
|
17
|
+
this.eventType = eventType;
|
|
18
|
+
this.client = client;
|
|
19
|
+
this.eventType = eventType;
|
|
20
|
+
this.factory = new direct_event_factory_1.EventsFactoryDirect(eventType, config);
|
|
21
|
+
}
|
|
22
|
+
async publish(payload, options) {
|
|
23
|
+
const message = this.factory.create(payload);
|
|
24
|
+
const partitionKey = this.factory.getPartitionKey(payload, options);
|
|
25
|
+
if (!partitionKey) {
|
|
26
|
+
this.logger.warn('Partition key field is not found in the payload. It may lead to performance issues', { options });
|
|
27
|
+
}
|
|
28
|
+
const subject = (0, nats_common_1.getSubjectName)(this.eventType, partitionKey);
|
|
29
|
+
try {
|
|
30
|
+
await this.client.publish(subject, message.payload, {
|
|
31
|
+
headers: message.headers,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
(0, nats_common_1.handleNatsException)(error, subject, options);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.DirectProducer = DirectProducer;
|
|
40
|
+
//# sourceMappingURL=direct.producer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"direct.producer.js","sourceRoot":"","sources":["../../src/direct/direct.producer.ts"],"names":[],"mappings":";;;AACA,2CAA8C;AAE9C,mDAAwE;AAOxE,iEAA6D;AAE7D;;GAEG;AACH,MAAa,cAAc;IAKN;IACA;IALF,OAAO,CAAyB;IAChC,MAAM,GAAY,uBAAa,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAE7E,YACmB,MAAgB,EAChB,SAAY,EAC7B,MAAuB;QAFN,WAAM,GAAN,MAAM,CAAU;QAChB,cAAS,GAAT,SAAS,CAAG;QAG7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,IAAI,0CAAmB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,OAAO,CACX,OAAU,EACV,OAAwB;QAExB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACpE,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,oFAAoF,EACpF,EAAE,OAAO,EAAE,CACZ,CAAC;QACJ,CAAC;QACD,MAAM,OAAO,GAAG,IAAA,4BAAc,EAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QAE7D,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE;gBAClD,OAAO,EAAE,OAAO,CAAC,OAAO;aACzB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAA,iCAAmB,EAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;CACF;AApCD,wCAoCC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InjectDirectProducer = exports.DirectProducer = void 0;
|
|
4
|
+
var direct_producer_1 = require("./direct.producer");
|
|
5
|
+
Object.defineProperty(exports, "DirectProducer", { enumerable: true, get: function () { return direct_producer_1.DirectProducer; } });
|
|
6
|
+
var direct_decorator_1 = require("./direct.decorator");
|
|
7
|
+
Object.defineProperty(exports, "InjectDirectProducer", { enumerable: true, get: function () { return direct_decorator_1.InjectDirectProducer; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/direct/index.ts"],"names":[],"mappings":";;;AAAA,qDAAmD;AAA1C,iHAAA,cAAc,OAAA;AACvB,uDAA0D;AAAjD,wHAAA,oBAAoB,OAAA"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DirectProducer, InjectDirectProducer } from './direct';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InjectDirectProducer = exports.DirectProducer = void 0;
|
|
4
|
+
var direct_1 = require("./direct");
|
|
5
|
+
Object.defineProperty(exports, "DirectProducer", { enumerable: true, get: function () { return direct_1.DirectProducer; } });
|
|
6
|
+
Object.defineProperty(exports, "InjectDirectProducer", { enumerable: true, get: function () { return direct_1.InjectDirectProducer; } });
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAAgE;AAAvD,wGAAA,cAAc,OAAA;AAAE,8GAAA,oBAAoB,OAAA"}
|
package/jest.config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('@rsdk/jest/jest.config');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('@rsdk/jest/jest.config.unit');
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rsdk/nats.producer.direct",
|
|
3
|
+
"version": "5.3.0-next.4",
|
|
4
|
+
"description": "Publishing messages directly to nats jetstream",
|
|
5
|
+
"license": "Apache License 2.0",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"url": "https://github.com/R-Vision/rsdk"
|
|
11
|
+
},
|
|
12
|
+
"main": "dist/index.js",
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"@grpc/grpc-js": "^1.10.9",
|
|
15
|
+
"@nestjs/common": "^10.0.0",
|
|
16
|
+
"@nestjs/core": "^10.0.0",
|
|
17
|
+
"@nestjs/microservices": "^10.0.0",
|
|
18
|
+
"@rsdk/autodoc.protocol": "*",
|
|
19
|
+
"@rsdk/common": "*",
|
|
20
|
+
"@rsdk/core": "*",
|
|
21
|
+
"@rsdk/logging": "*",
|
|
22
|
+
"@rsdk/metadata": "*",
|
|
23
|
+
"@rsdk/nats.common": "*",
|
|
24
|
+
"@rsdk/nats.producer": "*",
|
|
25
|
+
"nats": "^2.28.2",
|
|
26
|
+
"reflect-metadata": "^0.1.12 || ^0.2.0",
|
|
27
|
+
"rxjs": "^7.8.1"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"lodash": "^4.17.21"
|
|
31
|
+
},
|
|
32
|
+
"gitHead": "6d80aacd87b9cc36cfcff8c0c050e4fe31810276"
|
|
33
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { DocumentResolver } from '@rsdk/autodoc.protocol';
|
|
2
|
+
import { Composite, Table } from '@rsdk/autodoc.protocol';
|
|
3
|
+
import type { RsdkMetadataProvider } from '@rsdk/metadata';
|
|
4
|
+
import type {
|
|
5
|
+
NatsTopicMetadata,
|
|
6
|
+
NatsTopicMetadataByEventType,
|
|
7
|
+
} from '@rsdk/nats.common';
|
|
8
|
+
import { TopicType } from '@rsdk/nats.common';
|
|
9
|
+
|
|
10
|
+
import { NATS_PRODUCED_RSDK_METADATA_SCOPE } from './direct.constants';
|
|
11
|
+
|
|
12
|
+
export class NatsProducerDirectAutodocResolver implements DocumentResolver {
|
|
13
|
+
getNode(rsdkMetadataProvider: RsdkMetadataProvider): Composite | null {
|
|
14
|
+
const resources = rsdkMetadataProvider.get<NatsTopicMetadata>(
|
|
15
|
+
NATS_PRODUCED_RSDK_METADATA_SCOPE,
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
if (!resources) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return new Composite(
|
|
23
|
+
new Table(
|
|
24
|
+
resources
|
|
25
|
+
.filter((resource) => resource.value.type === TopicType.PRODUCE)
|
|
26
|
+
.map((resource) => {
|
|
27
|
+
const {
|
|
28
|
+
topicName,
|
|
29
|
+
group: group,
|
|
30
|
+
partitionKeyField,
|
|
31
|
+
eventType,
|
|
32
|
+
} = <NatsTopicMetadataByEventType>resource.value;
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
TopicName: topicName,
|
|
36
|
+
Group: group ?? '-',
|
|
37
|
+
PartitionKeyField: partitionKeyField ?? '-',
|
|
38
|
+
EventType: eventType?.$type ?? '-',
|
|
39
|
+
};
|
|
40
|
+
}),
|
|
41
|
+
),
|
|
42
|
+
'Nats JetStream producer direct',
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const natsProducerDirectAutodocResolver =
|
|
48
|
+
new NatsProducerDirectAutodocResolver();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Inject } from '@nestjs/common';
|
|
2
|
+
import {
|
|
3
|
+
PLATFORM_RAW_GLOBAL_METADATA_SCOPE,
|
|
4
|
+
RsdkMetadata,
|
|
5
|
+
} from '@rsdk/metadata';
|
|
6
|
+
import type { EventType } from '@rsdk/nats.common';
|
|
7
|
+
|
|
8
|
+
import { createDirectProducerToken } from './direct.constants';
|
|
9
|
+
import { DirectModuleGenerator } from './direct.module-generator';
|
|
10
|
+
|
|
11
|
+
export const InjectDirectProducer = (
|
|
12
|
+
eventType: EventType,
|
|
13
|
+
): ParameterDecorator => {
|
|
14
|
+
return (target, propertyKey, parameterIndex) => {
|
|
15
|
+
const directProducerToken = createDirectProducerToken(eventType);
|
|
16
|
+
|
|
17
|
+
Inject(directProducerToken)(target, propertyKey, parameterIndex);
|
|
18
|
+
RsdkMetadata.setWithScope(
|
|
19
|
+
target,
|
|
20
|
+
PLATFORM_RAW_GLOBAL_METADATA_SCOPE,
|
|
21
|
+
directProducerToken,
|
|
22
|
+
DirectModuleGenerator.createModule(eventType),
|
|
23
|
+
true,
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { EventPayload, EventType } from '@rsdk/nats.common';
|
|
2
|
+
import { EventsFactory } from '@rsdk/nats.producer';
|
|
3
|
+
import type { MsgHdrs, Payload } from 'nats';
|
|
4
|
+
import { MsgHdrsImpl } from 'nats';
|
|
5
|
+
|
|
6
|
+
export class EventsFactoryDirect<E extends EventType> extends EventsFactory<
|
|
7
|
+
E,
|
|
8
|
+
Payload
|
|
9
|
+
> {
|
|
10
|
+
create<P extends EventPayload<E>>(
|
|
11
|
+
payload: P,
|
|
12
|
+
): { headers: MsgHdrs; payload: Payload } {
|
|
13
|
+
const metadata = this.getMetadata(this.eventType.$type, null);
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
headers: this.buildHeaders(metadata),
|
|
17
|
+
payload: this.serializePayload(payload),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private buildHeaders(metadata: Record<string, string>): MsgHdrs {
|
|
22
|
+
const headers = new MsgHdrsImpl();
|
|
23
|
+
|
|
24
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
25
|
+
headers.set(key, value);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return headers;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { DynamicModule, FactoryProvider } from '@nestjs/common';
|
|
2
|
+
import { AutodocMetadata } from '@rsdk/autodoc.protocol';
|
|
3
|
+
import { PlatformConfigModule } from '@rsdk/core';
|
|
4
|
+
import { RsdkMetadata } from '@rsdk/metadata';
|
|
5
|
+
import type { EventType, NatsTopicMetadata, Producer } from '@rsdk/nats.common';
|
|
6
|
+
import {
|
|
7
|
+
getSubjectName,
|
|
8
|
+
NATS_PRODUCER_INJECTION_TOKEN,
|
|
9
|
+
NATS_TOPIC_RSDK_METADATA_SCOPE,
|
|
10
|
+
NatsClientModule,
|
|
11
|
+
TopicType,
|
|
12
|
+
} from '@rsdk/nats.common';
|
|
13
|
+
import { ProducerConfig } from '@rsdk/nats.producer';
|
|
14
|
+
import omit from 'lodash/omit';
|
|
15
|
+
|
|
16
|
+
import { natsProducerDirectAutodocResolver } from './direct.autodoc';
|
|
17
|
+
import { createDirectProducerToken } from './direct.constants';
|
|
18
|
+
import { DirectNatsProducerModule } from './direct.module';
|
|
19
|
+
import { DirectProducer } from './direct.producer';
|
|
20
|
+
|
|
21
|
+
export class DirectModuleGenerator {
|
|
22
|
+
static createModule(eventType: EventType): DynamicModule {
|
|
23
|
+
const providers: FactoryProvider[] = [
|
|
24
|
+
{
|
|
25
|
+
inject: [NATS_PRODUCER_INJECTION_TOKEN, ProducerConfig],
|
|
26
|
+
provide: createDirectProducerToken(eventType),
|
|
27
|
+
useFactory: (
|
|
28
|
+
client: Producer,
|
|
29
|
+
config: ProducerConfig,
|
|
30
|
+
): DirectProducer<EventType> => {
|
|
31
|
+
return new DirectProducer(client, eventType, config);
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const moduleDef = {
|
|
37
|
+
imports: [
|
|
38
|
+
NatsClientModule,
|
|
39
|
+
DirectNatsProducerModule,
|
|
40
|
+
PlatformConfigModule.forFeature(ProducerConfig),
|
|
41
|
+
],
|
|
42
|
+
providers,
|
|
43
|
+
module: DirectModuleGenerator,
|
|
44
|
+
exports: providers,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const rsdkNatsMetadata = new RsdkMetadata<NatsTopicMetadata>(
|
|
48
|
+
moduleDef,
|
|
49
|
+
NATS_TOPIC_RSDK_METADATA_SCOPE,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
rsdkNatsMetadata.add({
|
|
53
|
+
type: TopicType.PRODUCE,
|
|
54
|
+
topicName: getSubjectName(eventType),
|
|
55
|
+
group: eventType.$group,
|
|
56
|
+
partitionKeyField: eventType.$partitionKeyField,
|
|
57
|
+
eventType: omit(eventType, 'toJSON', 'encode', 'decode'),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
AutodocMetadata.defineResolver(
|
|
61
|
+
moduleDef,
|
|
62
|
+
NATS_TOPIC_RSDK_METADATA_SCOPE,
|
|
63
|
+
natsProducerDirectAutodocResolver,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
return moduleDef;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { NatsClientModule } from '@rsdk/nats.common';
|
|
3
|
+
|
|
4
|
+
// import { DirectProducerIndicator } from './kafka-producer-direct.health-indicator';
|
|
5
|
+
|
|
6
|
+
@Module({
|
|
7
|
+
imports: [NatsClientModule],
|
|
8
|
+
// providers: [DirectProducerIndicator],
|
|
9
|
+
})
|
|
10
|
+
export class DirectNatsProducerModule {}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ILogger } from '@rsdk/logging';
|
|
2
|
+
import { LoggerFactory } from '@rsdk/logging';
|
|
3
|
+
import type { EventPayload, EventType, Producer } from '@rsdk/nats.common';
|
|
4
|
+
import { getSubjectName, handleNatsException } from '@rsdk/nats.common';
|
|
5
|
+
import type {
|
|
6
|
+
NatsProducer,
|
|
7
|
+
ProducerOptions,
|
|
8
|
+
PublishOptions,
|
|
9
|
+
} from '@rsdk/nats.producer';
|
|
10
|
+
|
|
11
|
+
import { EventsFactoryDirect } from './direct.event-factory';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Producer, специализированный под конкретный ивент.
|
|
15
|
+
*/
|
|
16
|
+
export class DirectProducer<T extends EventType> implements NatsProducer<T> {
|
|
17
|
+
private readonly factory: EventsFactoryDirect<T>;
|
|
18
|
+
private readonly logger: ILogger = LoggerFactory.create(DirectProducer.name);
|
|
19
|
+
|
|
20
|
+
constructor(
|
|
21
|
+
private readonly client: Producer,
|
|
22
|
+
private readonly eventType: T,
|
|
23
|
+
config: ProducerOptions,
|
|
24
|
+
) {
|
|
25
|
+
this.client = client;
|
|
26
|
+
this.eventType = eventType;
|
|
27
|
+
this.factory = new EventsFactoryDirect(eventType, config);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async publish<P extends EventPayload<T>>(
|
|
31
|
+
payload: P,
|
|
32
|
+
options?: PublishOptions,
|
|
33
|
+
): Promise<void> {
|
|
34
|
+
const message = this.factory.create(payload);
|
|
35
|
+
const partitionKey = this.factory.getPartitionKey(payload, options);
|
|
36
|
+
if (!partitionKey) {
|
|
37
|
+
this.logger.warn(
|
|
38
|
+
'Partition key field is not found in the payload. It may lead to performance issues',
|
|
39
|
+
{ options },
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
const subject = getSubjectName(this.eventType, partitionKey);
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
await this.client.publish(subject, message.payload, {
|
|
46
|
+
headers: message.headers,
|
|
47
|
+
});
|
|
48
|
+
} catch (error) {
|
|
49
|
+
handleNatsException(error, subject, options);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { Injectable, Module } from '@nestjs/common';
|
|
2
|
+
import type { EventType } from '@rsdk/nats.common';
|
|
3
|
+
import { X_FORMAT_HEADER, X_TYPE_HEADER } from '@rsdk/nats.common';
|
|
4
|
+
import { NatsProducer } from '@rsdk/nats.producer';
|
|
5
|
+
import type { PlatformTestingModule } from '@rsdk/testing';
|
|
6
|
+
import { PlatformTest } from '@rsdk/testing';
|
|
7
|
+
import { connect } from 'nats';
|
|
8
|
+
import { Reader, Writer } from 'protobufjs';
|
|
9
|
+
import type { StartedTestContainer } from 'testcontainers';
|
|
10
|
+
import { GenericContainer, Wait } from 'testcontainers';
|
|
11
|
+
|
|
12
|
+
import { InjectDirectProducer } from './direct';
|
|
13
|
+
|
|
14
|
+
jest.setTimeout(60_000);
|
|
15
|
+
|
|
16
|
+
type TestMessage = { content: string };
|
|
17
|
+
|
|
18
|
+
class TestEventContract implements EventType {
|
|
19
|
+
$type = TestEventContract.name;
|
|
20
|
+
|
|
21
|
+
constructor(
|
|
22
|
+
public readonly $group: string,
|
|
23
|
+
public readonly $partitionKeyField: string | null = null,
|
|
24
|
+
) {}
|
|
25
|
+
|
|
26
|
+
static encode(message: TestMessage): Writer {
|
|
27
|
+
return new Writer().string(message.content);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static decode(data: Uint8Array | Reader): TestMessage {
|
|
31
|
+
return data instanceof Uint8Array
|
|
32
|
+
? { content: new Reader(data).string() }
|
|
33
|
+
: { content: data.string() };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
encode(message: TestMessage): Writer {
|
|
37
|
+
return TestEventContract.encode(message);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
decode(data: Uint8Array | Reader): TestMessage {
|
|
41
|
+
return TestEventContract.decode(data);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
toJSON(message: TestMessage): string {
|
|
45
|
+
return JSON.stringify(message);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const TestEvent = new TestEventContract('kek', null);
|
|
50
|
+
|
|
51
|
+
@Injectable()
|
|
52
|
+
class TestService {
|
|
53
|
+
constructor(
|
|
54
|
+
@InjectDirectProducer(TestEvent)
|
|
55
|
+
public readonly producer: NatsProducer<TestEventContract>,
|
|
56
|
+
) {}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@Module({
|
|
60
|
+
providers: [TestService],
|
|
61
|
+
})
|
|
62
|
+
class AppModule {}
|
|
63
|
+
|
|
64
|
+
const buildModule = async (): Promise<PlatformTestingModule> => {
|
|
65
|
+
const Test = PlatformTest.create({});
|
|
66
|
+
|
|
67
|
+
return await Test.createTestingModule({
|
|
68
|
+
imports: [AppModule],
|
|
69
|
+
}).compile();
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
describe('nats direct producer', () => {
|
|
73
|
+
let natsContainer: StartedTestContainer;
|
|
74
|
+
let natsServers: string;
|
|
75
|
+
|
|
76
|
+
beforeAll(async () => {
|
|
77
|
+
const container = new GenericContainer('nats:latest')
|
|
78
|
+
.withExposedPorts({ container: 4222, host: 4222 })
|
|
79
|
+
.withCommand(['--jetstream'])
|
|
80
|
+
.withWaitStrategy(Wait.forLogMessage('Server is ready'));
|
|
81
|
+
|
|
82
|
+
natsContainer = await container.start();
|
|
83
|
+
natsServers = `nats://${natsContainer.getHost()}:${natsContainer.getMappedPort(4222)}`;
|
|
84
|
+
process.env.NATS_SERVERS = natsServers;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
afterAll(async () => {
|
|
88
|
+
await natsContainer.stop();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('injects producer to service', async () => {
|
|
92
|
+
const app = await buildModule();
|
|
93
|
+
const service = app.get(TestService);
|
|
94
|
+
|
|
95
|
+
expect(service).toBeDefined();
|
|
96
|
+
expect(service.producer).toBeDefined();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('allows to send message with json codec', async () => {
|
|
100
|
+
// Arrange
|
|
101
|
+
process.env.NATS_PAYLOAD_FORMAT = 'protobuf';
|
|
102
|
+
const connection = await connect({ servers: natsServers });
|
|
103
|
+
const jsm = await connection.jetstreamManager();
|
|
104
|
+
const streamName = TestEvent.$group;
|
|
105
|
+
|
|
106
|
+
await jsm.streams.add({ name: streamName, subjects: ['events.>'] });
|
|
107
|
+
|
|
108
|
+
const app = await buildModule();
|
|
109
|
+
const service = app.get(TestService);
|
|
110
|
+
const testMessage: TestMessage = { content: 'kek' };
|
|
111
|
+
|
|
112
|
+
// Ack
|
|
113
|
+
await service.producer.publish(testMessage);
|
|
114
|
+
|
|
115
|
+
// Assert
|
|
116
|
+
const message = await jsm.streams.getMessage(streamName, { seq: 1 });
|
|
117
|
+
|
|
118
|
+
expect(TestEvent.decode(message.data)).toStrictEqual(testMessage);
|
|
119
|
+
|
|
120
|
+
await jsm.streams.delete(streamName);
|
|
121
|
+
await connection.drain();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('allows to send message with json codec', async () => {
|
|
125
|
+
// Arrange
|
|
126
|
+
process.env.NATS_PAYLOAD_FORMAT = 'json';
|
|
127
|
+
const connection = await connect({ servers: natsServers });
|
|
128
|
+
const jsm = await connection.jetstreamManager();
|
|
129
|
+
const streamName = TestEvent.$group;
|
|
130
|
+
|
|
131
|
+
await jsm.streams.add({ name: streamName, subjects: ['events.>'] });
|
|
132
|
+
|
|
133
|
+
const app = await buildModule();
|
|
134
|
+
const service = app.get(TestService);
|
|
135
|
+
const testMessage: TestMessage = { content: 'kek' };
|
|
136
|
+
|
|
137
|
+
// Ack
|
|
138
|
+
await service.producer.publish(testMessage);
|
|
139
|
+
|
|
140
|
+
// Assert
|
|
141
|
+
const message = await jsm.streams.getMessage(streamName, { seq: 1 });
|
|
142
|
+
|
|
143
|
+
expect(message.json()).toStrictEqual(testMessage);
|
|
144
|
+
|
|
145
|
+
await jsm.streams.delete(streamName);
|
|
146
|
+
await connection.drain();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('uses partition key as part of the subject', async () => {
|
|
150
|
+
// Arrange
|
|
151
|
+
process.env.NATS_PAYLOAD_FORMAT = 'json';
|
|
152
|
+
const connection = await connect({ servers: natsServers });
|
|
153
|
+
const jsm = await connection.jetstreamManager();
|
|
154
|
+
const streamName = TestEvent.$group;
|
|
155
|
+
|
|
156
|
+
await jsm.streams.add({ name: streamName, subjects: ['events.>'] });
|
|
157
|
+
|
|
158
|
+
const app = await buildModule();
|
|
159
|
+
const service = app.get(TestService);
|
|
160
|
+
const testMessage: TestMessage = { content: 'kek' };
|
|
161
|
+
const options = { partitionKey: 'test-partition-key' };
|
|
162
|
+
|
|
163
|
+
// Ack
|
|
164
|
+
await service.producer.publish(testMessage, options);
|
|
165
|
+
|
|
166
|
+
// Assert
|
|
167
|
+
const message = await jsm.streams.getMessage(streamName, { seq: 1 });
|
|
168
|
+
|
|
169
|
+
expect(message.subject).toContain(options.partitionKey);
|
|
170
|
+
|
|
171
|
+
await jsm.streams.delete(streamName);
|
|
172
|
+
await connection.drain();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('provide type and used format if not default', async () => {
|
|
176
|
+
// Arrange
|
|
177
|
+
process.env.NATS_PAYLOAD_FORMAT = 'json';
|
|
178
|
+
const connection = await connect({ servers: natsServers });
|
|
179
|
+
const jsm = await connection.jetstreamManager();
|
|
180
|
+
const streamName = TestEvent.$group;
|
|
181
|
+
|
|
182
|
+
await jsm.streams.add({ name: streamName, subjects: ['events.>'] });
|
|
183
|
+
|
|
184
|
+
const app = await buildModule();
|
|
185
|
+
const service = app.get(TestService);
|
|
186
|
+
const testMessage: TestMessage = { content: 'kek' };
|
|
187
|
+
|
|
188
|
+
// Ack
|
|
189
|
+
await service.producer.publish(testMessage);
|
|
190
|
+
|
|
191
|
+
// Assert
|
|
192
|
+
const message = await jsm.streams.getMessage(streamName, { seq: 1 });
|
|
193
|
+
|
|
194
|
+
expect(message.header.get(X_FORMAT_HEADER)).toBe('json');
|
|
195
|
+
expect(message.header.get(X_TYPE_HEADER)).toBe(TestEvent.$type);
|
|
196
|
+
|
|
197
|
+
await jsm.streams.delete(streamName);
|
|
198
|
+
await connection.drain();
|
|
199
|
+
});
|
|
200
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DirectProducer, InjectDirectProducer } from './direct';
|