@sellout/service 0.0.1

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.
Files changed (67) hide show
  1. package/.dist/BaseService.d.ts +22 -0
  2. package/.dist/BaseService.js +77 -0
  3. package/.dist/BaseService.js.map +1 -0
  4. package/.dist/ConsoleLogManager.d.ts +9 -0
  5. package/.dist/ConsoleLogManager.js +18 -0
  6. package/.dist/ConsoleLogManager.js.map +1 -0
  7. package/.dist/MongoConnectionManager.d.ts +9 -0
  8. package/.dist/MongoConnectionManager.js +52 -0
  9. package/.dist/MongoConnectionManager.js.map +1 -0
  10. package/.dist/NatsConnectionManager.d.ts +115 -0
  11. package/.dist/NatsConnectionManager.js +215 -0
  12. package/.dist/NatsConnectionManager.js.map +1 -0
  13. package/.dist/PbAsyncMessageHandler.d.ts +15 -0
  14. package/.dist/PbAsyncMessageHandler.js +26 -0
  15. package/.dist/PbAsyncMessageHandler.js.map +1 -0
  16. package/.dist/PbBroadcastProxy.d.ts +25 -0
  17. package/.dist/PbBroadcastProxy.js +41 -0
  18. package/.dist/PbBroadcastProxy.js.map +1 -0
  19. package/.dist/PbMessageHandler.d.ts +26 -0
  20. package/.dist/PbMessageHandler.js +46 -0
  21. package/.dist/PbMessageHandler.js.map +1 -0
  22. package/.dist/PbServiceProxy.d.ts +38 -0
  23. package/.dist/PbServiceProxy.js +64 -0
  24. package/.dist/PbServiceProxy.js.map +1 -0
  25. package/.dist/Segment.d.ts +12 -0
  26. package/.dist/Segment.js +34 -0
  27. package/.dist/Segment.js.map +1 -0
  28. package/.dist/Tracer.d.ts +22 -0
  29. package/.dist/Tracer.js +49 -0
  30. package/.dist/Tracer.js.map +1 -0
  31. package/.dist/TracerExpress.d.ts +1 -0
  32. package/.dist/TracerExpress.js +42 -0
  33. package/.dist/TracerExpress.js.map +1 -0
  34. package/.dist/build/tsconfig.json +32 -0
  35. package/.dist/build/tslint.json +17 -0
  36. package/.dist/env.d.ts +5 -0
  37. package/.dist/env.js +8 -0
  38. package/.dist/env.js.map +1 -0
  39. package/.dist/interfaces.d.ts +31 -0
  40. package/.dist/interfaces.js +3 -0
  41. package/.dist/interfaces.js.map +1 -0
  42. package/.dist/joiToErrors.d.ts +3 -0
  43. package/.dist/joiToErrors.js +43 -0
  44. package/.dist/joiToErrors.js.map +1 -0
  45. package/.dist/schemas.d.ts +0 -0
  46. package/.dist/schemas.js +1 -0
  47. package/.dist/schemas.js.map +1 -0
  48. package/package.json +34 -0
  49. package/src/BaseService.ts +98 -0
  50. package/src/ConsoleLogManager.ts +23 -0
  51. package/src/MongoConnectionManager.ts +49 -0
  52. package/src/NatsConnectionManager.ts +268 -0
  53. package/src/PbAsyncMessageHandler.ts +28 -0
  54. package/src/PbBroadcastProxy.ts +41 -0
  55. package/src/PbMessageHandler.ts +49 -0
  56. package/src/PbServiceProxy.ts +66 -0
  57. package/src/Segment.ts +35 -0
  58. package/src/Tracer.ts +55 -0
  59. package/src/TracerExpress.ts +36 -0
  60. package/src/build/tsconfig.json +32 -0
  61. package/src/build/tslint.json +17 -0
  62. package/src/env.ts +5 -0
  63. package/src/interfaces.ts +47 -0
  64. package/src/joiToErrors.ts +48 -0
  65. package/src/schemas.ts +0 -0
  66. package/tsconfig.json +28 -0
  67. package/tslint.json +21 -0
@@ -0,0 +1,98 @@
1
+ import { IConnectionManager, ILogManager, IServiceOpts } from "./interfaces";
2
+ import * as Prometheus from 'prom-client';
3
+ import * as express from 'express';
4
+ import {
5
+ DISABLE_PROMETHEUS,
6
+ SENTRY_DSN,
7
+ NODE_ENV,
8
+ SEGMENT_IO_WRITE_KEY,
9
+ } from "./env";
10
+ import * as Sentry from "@sentry/node";
11
+ import Segment from "./Segment";
12
+
13
+ /**
14
+ * Provides the abstract class for all service implementations.
15
+ */
16
+ class BaseService {
17
+ public opts: IServiceOpts;
18
+ public serviceName: string;
19
+ public connectionMgr: IConnectionManager;
20
+ public logger: ILogManager;
21
+ public storage;
22
+ public segment: Segment;
23
+ public collectDefaultMetrics;
24
+
25
+ constructor(opts: IServiceOpts) {
26
+ this.opts = opts;
27
+ this.connectionMgr = this.opts.connectionMgr;
28
+ this.logger = this.opts.logManager;
29
+ this.serviceName = this.opts.serviceName;
30
+ this.storage = this.opts.storageManager;
31
+ this.segment = new Segment(SEGMENT_IO_WRITE_KEY, this.logger);
32
+
33
+ /**
34
+ * Initialize Sentry
35
+ */
36
+ if (SENTRY_DSN) {
37
+ this.logger.info("Sentry - Initializing with environment ${NODE_ENV}...");
38
+ Sentry.init({
39
+ dsn: SENTRY_DSN,
40
+ environment: NODE_ENV,
41
+ });
42
+ } else {
43
+ this.logger.warn("Sentry - No DSN supplied, skipping initialization...");
44
+ }
45
+
46
+ // Enable/Disable Prometheus
47
+ if(!DISABLE_PROMETHEUS) {
48
+ // set up Prometheus client metrics gathering
49
+ const collectDefaultMetrics = Prometheus.collectDefaultMetrics;
50
+ // collectDefaultMetrics({ timeout: 5000 });
51
+ collectDefaultMetrics();
52
+
53
+ // initialize Express app
54
+ const app = express();
55
+ const metricsPort = 5499; // todo: parameterize this
56
+
57
+ // Metrics endpoint
58
+ app.get('/metrics', (req, res) => {
59
+ res.set('Content-Type', Prometheus.register.contentType)
60
+ res.end(Prometheus.register.metrics())
61
+ });
62
+
63
+ app.get('/readiness', (req, res) => {
64
+ if (this.isReady()) {
65
+ res.status(200).send('OK');
66
+ } else {
67
+ res.status(500).send('Not ready');
68
+ }
69
+ });
70
+
71
+ // as long as the event loop is running this should run
72
+ app.get('/liveness', (req, res) => {
73
+ res.status(200).send('OK');
74
+ });
75
+
76
+ // listen for metrics requests
77
+ app.listen(metricsPort, () => this.logger.info(`Service '${this.serviceName}' listening for metrics requests on port ${metricsPort}.`));
78
+ }
79
+ }
80
+
81
+ // override to have derived classes declare non-readiness to k8s
82
+ public isReady() : boolean {
83
+ return true;
84
+ }
85
+
86
+ /**
87
+ * Register message listeners here.
88
+ */
89
+ public register() {
90
+ throw new Error("Not Implemented: register method in Service class.");
91
+ }
92
+
93
+ public run() {
94
+ throw new Error("Not Implemented: run method in Service class.");
95
+ }
96
+ }
97
+
98
+ export default BaseService;
@@ -0,0 +1,23 @@
1
+ import { ILogManager, ILogManagerOpts } from "./interfaces";
2
+
3
+ class ConsoleLogManager implements ILogManager {
4
+ public opts: ILogManagerOpts;
5
+
6
+ constructor(opts: ILogManagerOpts) {
7
+ this.opts = opts;
8
+ }
9
+
10
+ public info(msg: string, ...params: string[]): void {
11
+ console.info(msg, ...params);
12
+ }
13
+
14
+ public warn(msg: string, ...params: string[]): void {
15
+ console.warn(msg, ...params);
16
+ }
17
+
18
+ public error(msg: string, ...params: string[]): void {
19
+ console.error(msg, ...params);
20
+ }
21
+ }
22
+
23
+ export default ConsoleLogManager;
@@ -0,0 +1,49 @@
1
+ import wait from '@sellout/utils/.dist/wait';
2
+
3
+ export default class MongoConnectionManager {
4
+ public connected: boolean;
5
+ public mongoConnectionString: string;
6
+ public isReplicaSet: boolean;
7
+ private mongoose: any;
8
+ private mongoConnectionStringInternal: string;
9
+
10
+ constructor(mongoose: any, mongoConnectionString: string, username: string = '', password: string = '') {
11
+ const parsed = new URL(mongoConnectionString);
12
+
13
+ parsed.username = username;
14
+ parsed.password = password;
15
+ parsed.pathname = '/admin';
16
+
17
+ this.connected = false;
18
+ this.mongoConnectionStringInternal = parsed.toString();
19
+ this.isReplicaSet = parsed.protocol === 'mongodb+srv:';
20
+
21
+ // redact username/password from publicly available connection string
22
+ parsed.username = '__user__';
23
+ parsed.password = '__pass__';
24
+ this.mongoConnectionString = parsed.toString();
25
+ this.mongoose = mongoose;
26
+ }
27
+
28
+ public async connect() {
29
+ while(!this.connected) {
30
+ console.log('Attempting to connect to Mongo...');
31
+ this.mongoose.connect(this.mongoConnectionStringInternal, {
32
+ ssl: false,
33
+ useUnifiedTopology: true,
34
+ useNewUrlParser: true,
35
+ })
36
+ .then(() => {
37
+ this.connected = true;
38
+ console.log(`Connected to MongoDB: ${this.mongoConnectionString}`);
39
+ })
40
+ .catch((e: any) => {
41
+ console.error(`There was an error connecting to MongoDB: ${this.mongoConnectionString}`);
42
+ console.error(e);
43
+ });
44
+
45
+ // wait five seconds before trying again
46
+ await wait(5000);
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,268 @@
1
+ 'use strict';
2
+ import * as NATS from 'nats';
3
+ import { IConnectionManager, ILogManager, ISubscriptionRoutes } from '@sellout/models/.dist/interfaces';
4
+
5
+ const BROADCAST_PREFIX = 'BROADCAST'; /* Prefix for broadcast messages */
6
+
7
+ /**
8
+ * Exposes connection operations for NATS.
9
+ */
10
+ class NatsConnectionManager implements IConnectionManager {
11
+
12
+ /**
13
+ * Exception representing an error that occurred during invocation of
14
+ * a message handler.
15
+ *
16
+ */
17
+ public static MESSAGE_HANDLER_ERROR = class extends Error {
18
+ public errors;
19
+
20
+ constructor(errors, messageSubject: string) {
21
+ super(`Error from message handler for '${messageSubject}'. Reason = ${JSON.stringify(errors)}`);
22
+ this.errors = errors;
23
+ }
24
+ };
25
+
26
+ /**
27
+ * Exception caused by request timeout.
28
+ */
29
+ public static TIMEOUT_ERROR = class extends Error {
30
+ public errors;
31
+
32
+ constructor(errors) {
33
+ super('NATS Timeout');
34
+ this.errors = errors;
35
+ }
36
+ };
37
+
38
+ public natsServers: string[];
39
+ private verbose: boolean;
40
+ private defaultRequestTimeout: number;
41
+
42
+ private conn: NATS.Client;
43
+ private logPrefix = 'NatsConnectionManager';
44
+ private logger;
45
+
46
+ /**
47
+ * Manages connections to NATS servers.
48
+ * @constructor
49
+ *
50
+ * @param {boolean} verbose - Log all events if true
51
+ */
52
+ constructor(natsServers: string[], logger: ILogManager, verbose = false, defaultRequestTimeout = 60000) {
53
+ this.logger = logger;
54
+ this.natsServers = natsServers;
55
+ this.verbose = verbose;
56
+ if (process.env.NATS_TIMEOUT) {
57
+ this.defaultRequestTimeout = parseInt(process.env.NATS_TIMEOUT, 10);
58
+ } else {
59
+ this.defaultRequestTimeout = defaultRequestTimeout;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Connect to one of the specified servers.
65
+ *
66
+ * @param {string[]} servers - Array of server URLs for NATS (server is randomly chosen)
67
+ */
68
+ public connect(waitForConnect = true) {
69
+ const opts: NATS.ClientOpts = {};
70
+ opts.servers = this.natsServers;
71
+ opts.preserveBuffers = true;
72
+ opts.verbose = this.verbose;
73
+ opts.waitOnFirstConnect = waitForConnect;
74
+ opts.maxReconnectAttempts = -1; /* Infinite reconnect attempts */
75
+
76
+ this.conn = NATS.connect(opts);
77
+ this.enableLogging();
78
+ }
79
+
80
+ /**
81
+ * Close active connections.
82
+ */
83
+ public close() {
84
+ this.conn.close();
85
+ }
86
+
87
+ /**
88
+ * Expose event system of Nats client.
89
+ *
90
+ * @param event
91
+ * @callback cb
92
+ */
93
+ public on(event: string, cb: (...args: any[]) => void) {
94
+ this.conn.on(event, cb);
95
+ }
96
+
97
+ /**
98
+ * Subscribes a service listener to its methods within a NATS queue.
99
+ *
100
+ * IMPORTANT: Ensure service message handlers are defined via arrow functions
101
+ * to ensure instance variables of the class are accessible within
102
+ * the scope of the handlers.
103
+ *
104
+ * @param service - Service Id of listener
105
+ * @param @optional {string} - Optional name of queue to subscribe
106
+ * @param {SubscriptionRoutes} routes - Mapping of method Ids to handlers
107
+ */
108
+ public subscribe(serviceId: string, queue: string, routes: ISubscriptionRoutes) {
109
+ this.logMessage(`Subscribing handlers for service='${serviceId}', queue='${queue}'`);
110
+ const topic = [serviceId, '>'].join('.');
111
+ return this.subscribeTopic(topic, queue, routes); /* Match all topics containing Service Id */
112
+ }
113
+
114
+ public subscribeBroadcast(serviceId: string, routes: ISubscriptionRoutes) {
115
+ const routeNames = Object.keys(routes);
116
+ this.logMessage(`Subscribing handlers for broadcast: [${routeNames.join(', ')}]`);
117
+ routeNames.forEach((r) => {
118
+ const topic = [BROADCAST_PREFIX, r].join('.');
119
+ const queue = `${serviceId}-${r}`;
120
+ this.subscribeTopic(topic, queue, { [r]: routes[r] });
121
+ });
122
+ }
123
+
124
+ public subscribeTopic(topicQualifier: string, queue: string | undefined, routes: ISubscriptionRoutes) {
125
+ const opts: NATS.SubscribeOptions = {};
126
+ opts.queue = queue;
127
+ this.conn.subscribe(topicQualifier, opts, (req, reply, subject: string) => {
128
+ const method = subject.substring(subject.indexOf('.') + 1);
129
+ const handler = routes[method];
130
+ this.logMessage(`Receive message: full subject=${subject}, method=${method}, replyTo=${reply} `);
131
+
132
+ handler.process(req).then(
133
+ (resp: Buffer) => {
134
+ if (reply) {
135
+ this.logMessage(`Publishing reply: ${reply}`);
136
+ this.conn.publish(reply, resp);
137
+ } else {
138
+ this.logMessage('No reply required');
139
+ }
140
+ },
141
+ (reason) => {
142
+ this.logMessage(`Handler failed. Reason= ${reason}`, false);
143
+ throw new NatsConnectionManager.MESSAGE_HANDLER_ERROR(reason, subject);
144
+ });
145
+ });
146
+ }
147
+
148
+ /**
149
+ * Publish request for service.
150
+ *
151
+ * @param {string} serviceId - Service Id of receipient
152
+ * @param {string} method - Id of method to call
153
+ * @param {Buffer} req - Request buffer
154
+ * @callback cb - Reply callback
155
+ * @param { number} [timeout] - Register a default timeout for requests
156
+ */
157
+ // tslint:disable-next-line:max-line-length
158
+ public send = (serviceId: string, method: string, req: Buffer, cb: (error, reply) => void, timeout?: number): void => {
159
+
160
+ const subject = [serviceId, method].join('.');
161
+
162
+ const msgId = this.conn.requestOne(
163
+ subject,
164
+ req,
165
+ {},
166
+ timeout == null ? this.defaultRequestTimeout : timeout,
167
+ (reply) => {
168
+
169
+ this.logMessage(`Sending message: ${subject} (${msgId})`);
170
+
171
+ if (reply.code && reply.code === NATS.REQ_TIMEOUT) {
172
+
173
+ this.logMessage(`Reply for (${msgId}): ${JSON.stringify(reply)}`, true);
174
+
175
+ const error = new NatsConnectionManager.TIMEOUT_ERROR({
176
+ message: `Timeout sending request: ${subject} (${msgId})`,
177
+ });
178
+ cb(error, null);
179
+ return;
180
+ }
181
+
182
+ this.logMessage(`Received reply: ${subject} (${msgId})`);
183
+ cb(null, reply);
184
+ },
185
+ );
186
+ }
187
+
188
+ /**
189
+ * Publish a broadcast message
190
+ */
191
+ public sendBroadcast = (messageId: string, req: Buffer, cb: (error, reply) => void): void => {
192
+ return this.sendAsync(BROADCAST_PREFIX, messageId, req, cb);
193
+ }
194
+
195
+ /**
196
+ * Publish asynchronous request for service.
197
+ *
198
+ * @param {string} serviceId - Service Id of receipient
199
+ * @param {string} method - Id of method to call
200
+ * @param {Buffer} req - Request buffer
201
+ * @callback cb - Reply callback
202
+ */
203
+ public sendAsync = (serviceId: string, method: string, req: Buffer, cb: (error, reply) => void): void => {
204
+
205
+ const subject = [serviceId, method].join('.');
206
+
207
+ this.conn.publish(
208
+ subject,
209
+ req,
210
+ (reply) => {
211
+ this.logMessage(`Queued message: ${subject}`);
212
+
213
+ // NATS always returns "undefined" for publish, since reply is N/A.
214
+ // Protobuf Services require _some_ kind of Type (cannot be undefined or void).
215
+ // thus, return an empty `<Buffer >` here, which can be marshalled to the `google.protobuf.Empty` type.
216
+ const empty = Buffer.from([]);
217
+ cb(null, empty);
218
+ });
219
+ }
220
+
221
+ /**
222
+ * Register for logged connection events
223
+ */
224
+ private enableLogging(): void {
225
+ /**
226
+ * GENERIC ERROR LOGGING
227
+ */
228
+ this.conn.on('error', (err) => {
229
+ this.logMessage(err, false);
230
+ });
231
+
232
+ if (!this.verbose) {
233
+ return;
234
+ }
235
+
236
+ /**
237
+ * VERBOSE EVENT LOGGING
238
+ */
239
+ this.conn.on('connect', (conn) => {
240
+ this.logMessage(`Connection established to ${conn.currentServer.url.host}`);
241
+ });
242
+
243
+ this.conn.on('disconnect', () => {
244
+ this.logMessage('Disconnected', false);
245
+ });
246
+
247
+ this.conn.on('reconnect', () => {
248
+ this.logMessage('Reconnected', false);
249
+ });
250
+
251
+ this.conn.on('close', () => {
252
+ this.logMessage('Connection closed');
253
+ });
254
+ }
255
+
256
+ /**
257
+ * Log a message
258
+ *
259
+ * @param msg
260
+ */
261
+ private logMessage(msg, info = true): void {
262
+ if (!info || this.verbose) {
263
+ this.logger.info(`(${this.logPrefix}) ${msg}`);
264
+ }
265
+ }
266
+ }
267
+
268
+ export default NatsConnectionManager;
@@ -0,0 +1,28 @@
1
+ import * as pb from "@sellout/models/.dist/sellout-proto";
2
+ import { PbMessageHandler } from './PbMessageHandler';
3
+
4
+
5
+ /* Message handler wrapper method for unidirectional calls */
6
+ function invokeWithEmptyResponse(method) {
7
+ return (req: Buffer) => method(req).then(() => Promise.resolve(pb.google.protobuf.Empty.create()));
8
+ }
9
+
10
+ /**
11
+ * Provides a wrapper around asynchronous Protobuf messages that don't return a response.
12
+ * Incoming buffers are decoded, the handler method is called using staticly-compiled
13
+ * Protobuf definitions.
14
+ */
15
+ export class PbAsyncMessageHandler extends PbMessageHandler {
16
+
17
+ /**
18
+ * @constructor
19
+ * @param method - Message handler method to be invoked
20
+ * @param requestCls - Request class provided by Protobuf
21
+ */
22
+ constructor(method, requestCls) {
23
+ super(invokeWithEmptyResponse(method), requestCls, pb.google.protobuf.Empty);
24
+ }
25
+
26
+ }
27
+
28
+ export default PbAsyncMessageHandler;
@@ -0,0 +1,41 @@
1
+ import { Broadcast } from "@sellout/models/.dist/sellout-proto";
2
+ import { IConnectionManager } from '@sellout/models/.dist/interfaces';
3
+ import { PbServiceProxy } from './PbServiceProxy';
4
+
5
+ export default class PbBroadcastProxy extends PbServiceProxy<Broadcast.Publisher> {
6
+ constructor(conn: IConnectionManager) {
7
+ super(conn, 'BROADCAST');
8
+ }
9
+
10
+ public activate(svc = Broadcast.Publisher): Broadcast.Publisher {
11
+ return super.activate(svc, true);
12
+ }
13
+
14
+ /**
15
+ * Provides handler logic for RPC sender. Note: use of arrow function
16
+ * required to maintain instance context.
17
+ *
18
+ * @param method
19
+ * @param requestData
20
+ * @param callback
21
+ */
22
+ protected sendRpcImpl = (method, requestData, callback) => {
23
+ throw('PbBroadcastProxy does not support synchronous calls');
24
+ }
25
+
26
+ /**
27
+ * Provides handler logic for RPC sender. Note: use of arrow function
28
+ * required to maintain instance context.
29
+ *
30
+ * @param method
31
+ * @param requestData
32
+ * @param callback
33
+ */
34
+ protected sendRpcImplAsync = (method, requestData, callback) => {
35
+ try {
36
+ this.conn.sendBroadcast(method.name, requestData, callback);
37
+ } catch (e) {
38
+ callback(e, null);
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Provides a wrapper around Protobuf messages. Incoming buffers are decoded, the
3
+ * handler method is called using staticly-compiled Protobuf definitions, and returned
4
+ * reponse objects are encoded and marshalled into Buffer.
5
+ */
6
+ export class PbMessageHandler {
7
+
8
+ public method;
9
+ public requestCls;
10
+ public responseCls;
11
+
12
+ /**
13
+ * @constructor
14
+ * @param method - Message handler method to be invoked
15
+ * @param requestCls - Request class provided by Protobuf
16
+ * @param responseCls - Response class provided by Protobuf
17
+ */
18
+ constructor(method, requestCls, responseCls) {
19
+ this.method = method;
20
+ this.requestCls = requestCls;
21
+ this.responseCls = responseCls;
22
+ }
23
+
24
+ /**
25
+ * Invoke registered message handler.
26
+ *
27
+ * @param {Buffer} req - Incoming request
28
+ * @returns {Promise<Buffer>} - Promise for buffer containing encoded response object
29
+ */
30
+ public process(req: Buffer): Promise<Buffer> {
31
+ return new Promise<Buffer>((resolve, reject) => {
32
+ const decoded = this.requestCls.decode(req);
33
+ // Pass plain JS object. I think this is a good idea?
34
+ // Idk about the performance but we'll see :)
35
+ // TODO: enable defaults when decoding messages
36
+ const reqObj = this.requestCls.toObject(decoded);
37
+ this.method(reqObj).then((respObj) => {
38
+ const respEncoded = this.responseCls.encode(respObj).finish();
39
+ resolve(respEncoded);
40
+ })
41
+ .catch((e) => {
42
+ console.log(`Error processing message for method = ${this.method}`);
43
+ reject(e);
44
+ });
45
+ });
46
+ }
47
+ }
48
+
49
+ export default PbMessageHandler;
@@ -0,0 +1,66 @@
1
+ import { IConnectionManager } from "./interfaces";
2
+
3
+ /**
4
+ * Provides a client proxy that wraps a Service definition generated by staticly compiled Protobuf definition.
5
+ */
6
+ export class PbServiceProxy<T> {
7
+ protected conn: IConnectionManager;
8
+ protected serviceName: string;
9
+
10
+ /**
11
+ * @coonstructor
12
+ * @param conn - Connection manager to handle outbound requests
13
+ * @param serviceName
14
+ */
15
+ public constructor(conn: IConnectionManager, serviceName: string) {
16
+ this.conn = conn;
17
+ this.serviceName = serviceName;
18
+ }
19
+
20
+ /**
21
+ *
22
+ * @param svc Create and activate an instance of a service
23
+ */
24
+ public activate(svc, async?): T {
25
+ if (async === true) {
26
+ return svc.create(this.sendRpcImplAsync);
27
+ } else {
28
+ // tslint:disable-line
29
+ return svc.create(this.sendRpcImpl);
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Provides handler logic for RPC sender. Note: use of arrow function
35
+ * required to maintain instance context.
36
+ *
37
+ * @param method
38
+ * @param requestData
39
+ * @param callback
40
+ */
41
+ protected sendRpcImpl = (method, requestData, callback) => {
42
+ try {
43
+ this.conn.send(this.serviceName, method.name, requestData, callback);
44
+ } catch (e) {
45
+ callback(e, null);
46
+ }
47
+ };
48
+
49
+ /**
50
+ * Provides handler logic for RPC sender. Note: use of arrow function
51
+ * required to maintain instance context.
52
+ *
53
+ * @param method
54
+ * @param requestData
55
+ * @param callback
56
+ */
57
+ protected sendRpcImplAsync = (method, requestData, callback) => {
58
+ try {
59
+ this.conn.sendAsync(this.serviceName, method.name, requestData, callback);
60
+ } catch (e) {
61
+ callback(e, null);
62
+ }
63
+ };
64
+ }
65
+
66
+ export default PbServiceProxy;
package/src/Segment.ts ADDED
@@ -0,0 +1,35 @@
1
+ import { ILogManager } from "./interfaces";
2
+
3
+ const Analytics = require('analytics-node');
4
+
5
+ /**
6
+ * Segment class to allow for
7
+ * tracking only in production
8
+ */
9
+ export default class Segment {
10
+ private segment: any;
11
+ private logger: ILogManager
12
+ constructor(SEGMENT_IO_WRITE_KEY: string | undefined, logger: ILogManager) {
13
+ this.segment = null;
14
+ this.logger = logger;
15
+
16
+ if(SEGMENT_IO_WRITE_KEY) {
17
+ this.logger.info("Segment - Initializing...");
18
+ this.segment = new Analytics(SEGMENT_IO_WRITE_KEY);
19
+ } else {
20
+ this.logger.warn("Segment - No write key supplied, skipping initialization...");
21
+ }
22
+ }
23
+ track(params) {
24
+ if (this.segment) {
25
+ this.logger.info(`Segment - Tracking event ${params.event}.`);
26
+ this.segment.track(params);
27
+ }
28
+ }
29
+ identify(params) {
30
+ if (this.segment) {
31
+ this.logger.info(`Segment - Identified user.`);
32
+ this.segment.identify(params);
33
+ }
34
+ }
35
+ }