@tiledesk/tiledesk-server 2.5.3 → 2.7.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.
package/routes/kb.js CHANGED
@@ -2,8 +2,26 @@ var express = require('express');
2
2
  var { KB } = require('../models/kb_setting');
3
3
  var router = express.Router();
4
4
  var winston = require('../config/winston');
5
+ var multer = require('multer')
6
+ var upload = multer()
5
7
  const openaiService = require('../services/openaiService');
8
+ const JobManager = require('../utils/jobs-worker-queue-manager/JobManagerV2');
9
+ const { Scheduler } = require('../services/Scheduler');
6
10
 
11
+ const Sitemapper = require('sitemapper');
12
+
13
+ const AMQP_MANAGER_URL = process.env.AMQP_MANAGER_URL;
14
+ const JOB_TOPIC_EXCHANGE = process.env.JOB_TOPIC_EXCHANGE_TRAIN || 'tiledesk-trainer';
15
+
16
+ let jobManager = new JobManager(AMQP_MANAGER_URL, {
17
+ debug: false,
18
+ topic: JOB_TOPIC_EXCHANGE,
19
+ exchange: JOB_TOPIC_EXCHANGE
20
+ })
21
+
22
+ jobManager.connectAndStartPublisher(() => {
23
+ winston.info("ConnectPublisher done");
24
+ })
7
25
 
8
26
  router.get('/', async (req, res) => {
9
27
 
@@ -27,7 +45,7 @@ router.get('/', async (req, res) => {
27
45
  limit = parseInt(req.query.limit);
28
46
  winston.debug("Get kb limit: " + limit)
29
47
  }
30
-
48
+
31
49
  if (req.query.page) {
32
50
  page = parseInt(req.query.page);
33
51
  winston.debug("Get kb page: " + page)
@@ -55,54 +73,54 @@ router.get('/', async (req, res) => {
55
73
  let sortQuery = {};
56
74
  sortQuery[sortField] = direction;
57
75
  winston.debug("Get kb sortQuery: " + sortQuery);
58
-
76
+
59
77
  KB.countDocuments(query, (err, kbs_count) => {
60
- if (err) {
61
- winston.error("Find all kbs error: ", err);
62
- }
63
- winston.debug("KBs count: ", kbs_count);
64
-
65
- KB.find(query)
66
- .skip(skip)
67
- .limit(limit)
68
- .sort(sortQuery)
69
- .exec((err, kbs) => {
70
- if (err) {
71
- winston.error("Find all kbs error: ", err);
72
- return res.status(500).send({ success: false, error: err });
73
- }
74
-
75
- winston.debug("KBs found: ", kbs);
76
-
77
- let response = {
78
- count: kbs_count,
79
- query: {},
80
- kbs: kbs
81
- }
82
- if (status) {
83
- response.query.status = status;
84
- }
85
- if (limit) {
86
- response.query.limit = limit;
87
- }
88
- if (status) {
89
- response.query.page = page;
90
- }
91
- if (sortField) {
92
- response.query.sortField = sortField;
93
- }
94
- if (direction) {
95
- response.query.direction = direction;
96
- }
97
- if (text) {
98
- response.query.search = text;
99
- }
100
-
101
-
102
- return res.status(200).send(response);
103
- })
78
+ if (err) {
79
+ winston.error("Find all kbs error: ", err);
80
+ }
81
+ winston.debug("KBs count: ", kbs_count);
104
82
 
105
- })
83
+ KB.find(query)
84
+ .skip(skip)
85
+ .limit(limit)
86
+ .sort(sortQuery)
87
+ .exec((err, kbs) => {
88
+ if (err) {
89
+ winston.error("Find all kbs error: ", err);
90
+ return res.status(500).send({ success: false, error: err });
91
+ }
92
+
93
+ winston.debug("KBs found: ", kbs);
94
+
95
+ let response = {
96
+ count: kbs_count,
97
+ query: {},
98
+ kbs: kbs
99
+ }
100
+ if (status) {
101
+ response.query.status = status;
102
+ }
103
+ if (limit) {
104
+ response.query.limit = limit;
105
+ }
106
+ if (status) {
107
+ response.query.page = page;
108
+ }
109
+ if (sortField) {
110
+ response.query.sortField = sortField;
111
+ }
112
+ if (direction) {
113
+ response.query.direction = direction;
114
+ }
115
+ if (text) {
116
+ response.query.search = text;
117
+ }
118
+
119
+
120
+ return res.status(200).send(response);
121
+ })
122
+
123
+ })
106
124
 
107
125
 
108
126
  })
@@ -127,6 +145,31 @@ router.post('/', async (req, res) => {
127
145
  let project_id = req.projectid;
128
146
  let body = req.body;
129
147
 
148
+ // add or override namespace value if it is passed for security reason
149
+ body.namespace = project_id;
150
+
151
+ // if (req.body.namespace) {
152
+ // if (req.body.namespace != req.projectid) {
153
+ // return res.status(403).send({ success: false, error: "Not allowed. The namespace does not belong to the current project."})
154
+ // }
155
+ // }
156
+
157
+ let quoteManager = req.app.get('quote_manager');
158
+ let limits = await quoteManager.getPlanLimits(req.project);
159
+ let kbs_limit = limits.kbs;
160
+ winston.verbose("Limit of kbs for current plan: " + kbs_limit);
161
+
162
+ let kbs_count = await KB.countDocuments({ id_project: project_id }).exec();
163
+ winston.verbose("Kbs count: " + kbs_count);
164
+
165
+ if (kbs_count >= kbs_limit) {
166
+ return res.status(403).send({ success: false, error: "Maximum number of resources reached for the current plan", plan_limit: kbs_limit })
167
+ }
168
+
169
+ let total_count = kbs_count + 1;
170
+ if (total_count > kbs_limit) {
171
+ return res.status(403).send({ success: false, error: "Cannot exceed the number of resources in the current plan", plan_limit: kbs_limit })
172
+ }
130
173
  let new_kb = {
131
174
  id_project: project_id,
132
175
  name: body.name,
@@ -141,7 +184,6 @@ router.post('/', async (req, res) => {
141
184
  }
142
185
  winston.debug("adding kb: ", new_kb);
143
186
 
144
-
145
187
  KB.findOneAndUpdate({ id_project: project_id, type: 'url', source: new_kb.source }, new_kb, { upsert: true, new: true, rawResult: true }, async (err, raw) => {
146
188
  if (err) {
147
189
  winston.error("findOneAndUpdate with upsert error: ", err);
@@ -163,17 +205,118 @@ router.post('/', async (req, res) => {
163
205
  json.content = raw.value.content;
164
206
  }
165
207
 
166
- startScrape(json).then((response) => {
167
- winston.verbose("startScrape response: ", response);
168
- }).catch((err) => {
169
- winston.error("startScrape err: ", err);
170
- })
208
+ let resources = [];
209
+
210
+ resources.push(json);
211
+ scheduleScrape(resources);
212
+
213
+ // startScrape(json).then((response) => {
214
+ // winston.verbose("startScrape response: ", response);
215
+ // }).catch((err) => {
216
+ // winston.error("startScrape err: ", err);
217
+ // })
218
+
219
+ }
220
+ })
221
+
222
+ })
223
+
224
+
225
+ router.post('/multi', upload.single('uploadFile'), async (req, res) => {
226
+
227
+ let list;
228
+ if (req.file) {
229
+ file_string = req.file.buffer.toString('utf-8');
230
+ list = file_string.trim().split('\n');
231
+ } else {
232
+ list = req.body.list;
233
+ }
234
+
235
+ let project_id = req.projectid;
236
+
237
+ let quoteManager = req.app.get('quote_manager');
238
+ let limits = await quoteManager.getPlanLimits(req.project);
239
+ let kbs_limit = limits.kbs;
240
+ winston.verbose("Limit of kbs for current plan: " + kbs_limit);
241
+
242
+ let kbs_count = await KB.countDocuments({ id_project: project_id }).exec();
243
+ winston.verbose("Kbs count: " + kbs_count);
244
+
245
+ if (kbs_count >= kbs_limit) {
246
+ return res.status(403).send({ success: false, error: "Maximum number of resources reached for the current plan", plan_limit: kbs_limit })
247
+ }
248
+
249
+ let total_count = kbs_count + list.length;
250
+ if (total_count > kbs_limit) {
251
+ return res.status(403).send({ success: false, error: "Cannot exceed the number of resources in the current plan", plan_limit: kbs_limit })
252
+ }
253
+
254
+ if (list.length > 300) {
255
+ winston.error("Too many urls. Can't index more than 300 urls at a time.");
256
+ return res.status(403).send({ success: false, error: "Too many urls. Can't index more than 300 urls at a time."})
257
+ }
171
258
 
259
+ let kbs = [];
260
+ list.forEach(url => {
261
+ kbs.push({
262
+ id_project: project_id,
263
+ name: url,
264
+ source: url,
265
+ type: 'url',
266
+ content: "",
267
+ namespace: project_id,
268
+ status: -1
269
+ })
270
+ })
271
+
272
+ let operations = kbs.map(doc => {
273
+ return {
274
+ updateOne: {
275
+ filter: { id_project: doc.id_project, type: 'url', source: doc.source },
276
+ update: doc,
277
+ upsert: true,
278
+ returnOriginal: false
279
+ }
172
280
  }
173
281
  })
174
282
 
283
+ saveBulk(operations, kbs, project_id).then((result) => {
284
+
285
+ let resources = result.map(({ name, status, __v, createdAt, updatedAt, id_project, ...keepAttrs }) => keepAttrs)
286
+ resources = resources.map(({ _id, ...rest }) => {
287
+ return { id: _id, ...rest };
288
+ });
289
+ winston.verbose("resources to be sent to worker: ", resources)
290
+ scheduleScrape(resources);
291
+ res.status(200).send(result);
292
+
293
+ }).catch((err) => {
294
+ winston.error("Unable to save kbs in bulk ", err)
295
+ res.status(500).send(err);
296
+ })
297
+
298
+ })
299
+
300
+ router.post('/sitemap', async (req, res) => {
301
+
302
+ let sitemap_url = req.body.sitemap;
303
+
304
+ const sitemap = new Sitemapper({
305
+ url: sitemap_url,
306
+ timeout: 15000
307
+ });
308
+
309
+ sitemap.fetch().then((data) => {
310
+ winston.debug("data: ", data);
311
+ res.status(200).send(data);
312
+ }).catch((err) => {
313
+ console.error("err ", err)
314
+ res.status(500).send({ success: false, error: err });
315
+ })
316
+
175
317
  })
176
318
 
319
+
177
320
  router.put('/:kb_id', async (req, res) => {
178
321
 
179
322
  let kb_id = req.params.kb_id;
@@ -230,10 +373,14 @@ router.post('/scrape/single', async (req, res) => {
230
373
  id: kb._id,
231
374
  type: kb.type,
232
375
  source: kb.source,
233
- content: kb.content,
376
+ content: "",
234
377
  namespace: kb.namespace
235
378
  }
236
379
 
380
+ if (kb.content) {
381
+ json.content = kb.content;
382
+ }
383
+
237
384
  startScrape(json).then((response) => {
238
385
  winston.verbose("startScrape response: ", response);
239
386
  res.status(200).send(response);
@@ -256,24 +403,27 @@ router.post('/scrape/status', async (req, res) => {
256
403
 
257
404
  if (req.query &&
258
405
  req.query.returnObject &&
259
- (req.query.returnObject === true || req.query.returnObject === true)) {
406
+ (req.query.returnObject === true || req.query.returnObject === 'true')) {
260
407
  returnObject = true;
261
408
  }
262
409
 
263
- openaiService.scrapeStatus(data).then((response) => {
410
+ openaiService.scrapeStatus(data).then( async (response) => {
264
411
 
265
412
  winston.debug("scrapeStatus response.data: ", response.data);
266
413
 
267
414
  let update = {};
268
415
 
269
416
  if (response.data.status_code) {
270
- update.status = response.data.status_code;
417
+ // update.status = response.data.status_code;
418
+ update.status = await statusConverter(response.data.status_code)
419
+
271
420
  }
272
421
 
273
422
  KB.findByIdAndUpdate(data.id, update, { new: true }, (err, savedKb) => {
274
423
 
275
424
  if (err) {
276
425
  winston.verbose("Status was successfully recovered, but the update on the db failed");
426
+ winston.error("find kb by id and updated error: ", err);
277
427
 
278
428
  if (returnObject) {
279
429
  return res.status(206).send({ warning: "Unable to udpate content on db", message: "The original reply was forwarded", data: response.data });
@@ -298,8 +448,14 @@ router.post('/scrape/status', async (req, res) => {
298
448
 
299
449
  router.post('/qa', async (req, res) => {
300
450
  let data = req.body;
451
+ // add or override namespace value if it is passed for security reason
452
+ data.namespace = req.projectid;
301
453
  winston.debug("/qa data: ", data);
302
454
 
455
+ // if (req.body.namespace != req.projectid) {
456
+ // return res.status(403).send({ success: false, error: "Not allowed. The namespace does not belong to the current project."})
457
+ // }
458
+
303
459
  if (!data.gptkey) {
304
460
  let gptkey = process.env.GPTKEY;
305
461
  if (!gptkey) {
@@ -310,11 +466,38 @@ router.post('/qa', async (req, res) => {
310
466
 
311
467
  openaiService.askNamespace(data).then((resp) => {
312
468
  winston.debug("qa resp: ", resp.data);
313
- res.status(200).send(resp.data);
469
+ let answer = resp.data;
470
+
471
+ let id = answer.id;
472
+ let index = id.indexOf("#");
473
+ if (index != -1) {
474
+ id = id.substring(index + 1);
475
+ }
476
+
477
+ KB.findById(id, (err, resource) => {
478
+
479
+ if (err) {
480
+ winston.error("Unable to find resource with id " + id + " in namespace " + answer.namespace + ". The standard answer is returned.")
481
+ return res.status(200).send(resp.data);
482
+ }
483
+
484
+ answer.source = resource.name;
485
+ return res.status(200).send(answer);
486
+ })
487
+
488
+
314
489
  }).catch((err) => {
315
490
  winston.error("qa err: ", err);
316
- let status = err.response.status;
317
- res.status(status).send({ success: false, statusText: err.response.statusText, error: err.response.data.detail });
491
+ console.log(err.response)
492
+ if (err.response
493
+ && err.response.status) {
494
+ let status = err.response.status;
495
+ res.status(status).send({ success: false, statusText: err.response.statusText, error: err.response.data.detail });
496
+ }
497
+ else {
498
+ res.status(500).send({ success: false, error: err });
499
+ }
500
+
318
501
  })
319
502
  })
320
503
 
@@ -375,7 +558,7 @@ router.delete('/:kb_id', async (req, res) => {
375
558
  })
376
559
 
377
560
  } else {
378
- winston.info("resp.data: ", resp.data);
561
+ winston.verbose("resp.data: ", resp.data);
379
562
 
380
563
  KB.findOneAndDelete({ _id: kb_id, status: { $in: [-1, 3, 4] } }, (err, deletedKb) => {
381
564
  if (err) {
@@ -398,6 +581,51 @@ router.delete('/:kb_id', async (req, res) => {
398
581
 
399
582
  })
400
583
 
584
+ async function saveBulk(operations, kbs, project_id) {
585
+
586
+ return new Promise((resolve, reject) => {
587
+ KB.bulkWrite(operations, { ordered: false }).then((result) => {
588
+ winston.verbose("bulkWrite operations result: ", result);
589
+
590
+ KB.find({ id_project: project_id, source: { $in: kbs.map(kb => kb.source) } }).lean().then((documents) => {
591
+ winston.debug("documents: ", documents);
592
+ resolve(documents)
593
+ }).catch((err) => {
594
+ winston.error("Error finding documents ", err)
595
+ reject(err);
596
+ })
597
+
598
+ }).catch((err) => {
599
+ reject(err);
600
+ })
601
+ })
602
+
603
+ }
604
+
605
+ async function statusConverter(status) {
606
+ return new Promise((resolve) => {
607
+
608
+ let td_status;
609
+ switch(status) {
610
+ case 0:
611
+ td_status = -1;
612
+ break;
613
+ case 2:
614
+ td_status = 200;
615
+ break;
616
+ case 3:
617
+ td_status = 300;
618
+ break;
619
+ case 4:
620
+ td_status = 400;
621
+ break;
622
+ default:
623
+ td_status = -1
624
+ }
625
+ resolve(td_status);
626
+ })
627
+ }
628
+
401
629
  async function updateStatus(id, status) {
402
630
  return new Promise((resolve) => {
403
631
 
@@ -412,6 +640,23 @@ async function updateStatus(id, status) {
412
640
  })
413
641
  }
414
642
 
643
+ async function scheduleScrape(resources) {
644
+
645
+ let data = {
646
+ resources: resources
647
+ }
648
+ winston.info("Schedule job with following data: ", data);
649
+ let scheduler = new Scheduler({ jobManager: jobManager });
650
+ scheduler.trainSchedule(data, (err, result) => {
651
+ if (err) {
652
+ winston.error("Scheduling error: ", err);
653
+ }
654
+ winston.info("Scheduling result: ", result);
655
+ });
656
+
657
+ return true;
658
+ }
659
+
415
660
  async function startScrape(data) {
416
661
 
417
662
  if (!data.gptkey) {
@@ -425,7 +670,7 @@ async function startScrape(data) {
425
670
  return new Promise((resolve, reject) => {
426
671
  openaiService.singleScrape(data).then(async (resp) => {
427
672
  winston.debug("singleScrape resp: ", resp.data);
428
- let status_updated = await updateStatus(data.id, 0);
673
+ let status_updated = await updateStatus(data.id, 100);
429
674
  winston.verbose("status of kb " + data.id + " updated: " + status_updated);
430
675
  resolve(resp.data);
431
676
  }).catch((err) => {
@@ -5,11 +5,11 @@ const messageEvent = require('../event/messageEvent');
5
5
  const emailEvent = require('../event/emailEvent');
6
6
 
7
7
  const PLANS_LIST = {
8
- FREE_TRIAL: { requests: 3000, messages: 0, tokens: 250000, email: 200 }, // same as PREMIUM
9
- SANDBOX: { requests: 200, messages: 0, tokens: 10000, email: 200 },
10
- BASIC: { requests: 800, messages: 0, tokens: 50000, email: 200 },
11
- PREMIUM: { requests: 3000, messages: 0, tokens: 250000, email: 200 },
12
- CUSTOM: { requests: 3000, messages: 0, tokens: 250000, email: 200 }
8
+ FREE_TRIAL: { requests: 3000, messages: 0, tokens: 250000, email: 200, kbs: 50 }, // same as PREMIUM
9
+ SANDBOX: { requests: 200, messages: 0, tokens: 10000, email: 200, kbs: 50 },
10
+ BASIC: { requests: 800, messages: 0, tokens: 50000, email: 200, kbs: 150},
11
+ PREMIUM: { requests: 3000, messages: 0, tokens: 250000, email: 200, kbs: 300},
12
+ CUSTOM: { requests: 3000, messages: 0, tokens: 250000, email: 200, kbs: 300}
13
13
  }
14
14
 
15
15
  const typesList = ['requests', 'messages', 'email', 'tokens']
@@ -58,7 +58,7 @@ class QuoteManager {
58
58
 
59
59
  this.project = project;
60
60
  let key = await this.generateKey(email, 'email');
61
- winston.info("[QuoteManager] incrementEmailCount key: " + key);
61
+ winston.verbose("[QuoteManager] incrementEmailCount key: " + key);
62
62
 
63
63
  await this.tdCache.incr(key)
64
64
  return key;
@@ -68,7 +68,7 @@ class QuoteManager {
68
68
 
69
69
  this.project = project;
70
70
  let key = await this.generateKey(data, 'tokens');
71
- winston.info("[QuoteManager] incrementTokenCount key: " + key);
71
+ winston.verbose("[QuoteManager] incrementTokenCount key: " + key);
72
72
 
73
73
  if (quotes_enabled === false) {
74
74
  winston.debug("QUOTES DISABLED - incrementTokenCount")
@@ -83,8 +83,8 @@ class QuoteManager {
83
83
 
84
84
  async generateKey(object, type) {
85
85
 
86
- winston.info("generateKey object ", object)
87
- winston.info("generateKey type " + type)
86
+ winston.debug("generateKey object ", object)
87
+ winston.debug("generateKey type " + type)
88
88
  let subscriptionDate;
89
89
  if (this.project.profile.subStart) {
90
90
  subscriptionDate = this.project.profile.subStart;
@@ -92,7 +92,7 @@ class QuoteManager {
92
92
  subscriptionDate = this.project.createdAt;
93
93
  }
94
94
  let objectDate = object.createdAt;
95
- winston.info("objectDate " + objectDate);
95
+ winston.debug("objectDate " + objectDate);
96
96
 
97
97
  // converts date in timestamps and transform from ms to s
98
98
  const objectDateTimestamp = ceil(objectDate.getTime() / 1000);
@@ -114,7 +114,7 @@ class QuoteManager {
114
114
 
115
115
  this.project = project;
116
116
  let key = await this.generateKey(object, type);
117
- winston.info("[QuoteManager] getCurrentQuote key: " + key);
117
+ winston.verbose("[QuoteManager] getCurrentQuote key: " + key);
118
118
 
119
119
  let quote = await this.tdCache.get(key);
120
120
  return Number(quote);
@@ -147,17 +147,17 @@ class QuoteManager {
147
147
  */
148
148
  async checkQuote(project, object, type) {
149
149
 
150
- winston.info("checkQuote type " + type);
150
+ winston.verbose("checkQuote type " + type);
151
151
  if (quotes_enabled === false) {
152
- winston.info("QUOTES DISABLED - checkQuote for type " + type);
152
+ winston.verbose("QUOTES DISABLED - checkQuote for type " + type);
153
153
  return true;
154
154
  }
155
155
 
156
156
  this.project = project;
157
157
  let limits = await this.getPlanLimits();
158
- winston.info("limits for current plan: ", limits)
158
+ winston.verbose("limits for current plan: ", limits)
159
159
  let quote = await this.getCurrentQuote(project, object, type);
160
- winston.info("getCurrentQuote resp: ", quote)
160
+ winston.verbose("getCurrentQuote resp: ", quote)
161
161
 
162
162
  if (quote == null) {
163
163
  return true;
@@ -171,7 +171,11 @@ class QuoteManager {
171
171
  }
172
172
 
173
173
 
174
- async getPlanLimits() {
174
+ async getPlanLimits(project) {
175
+
176
+ if (project) {
177
+ this.project = project
178
+ };
175
179
 
176
180
  let limits;
177
181
  if (this.project.profile.type === 'payment') {
@@ -222,6 +226,8 @@ class QuoteManager {
222
226
  }
223
227
  }
224
228
 
229
+ winston.info("QUOTES ENABLED ? ", quotes_enabled);
230
+
225
231
  // TODO - Try to generalize to avoid repetition
226
232
  let incrementEventHandler = (object) => { }
227
233
  let checkEventHandler = (object) => { }
@@ -244,7 +250,7 @@ class QuoteManager {
244
250
  let result = await this.incrementRequestsCount(payload.project, payload.request);
245
251
  return result;
246
252
  } else {
247
- winston.info("QUOTES DISABLED - request.create.quote event")
253
+ winston.verbose("QUOTES DISABLED - request.create.quote event")
248
254
  }
249
255
  })
250
256
  // REQUESTS EVENTS - END
@@ -267,7 +273,7 @@ class QuoteManager {
267
273
  let result = await this.incrementMessagesCount(payload.project, payload.message);
268
274
  return result;
269
275
  } else {
270
- winston.info("QUOTES DISABLED - message.create.quote event")
276
+ winston.verbose("QUOTES DISABLED - message.create.quote event")
271
277
  }
272
278
  })
273
279
  // MESSAGES EVENTS - END
@@ -286,11 +292,11 @@ class QuoteManager {
286
292
 
287
293
  emailEvent.on('email.send.quote', async (payload) => {
288
294
  if (quotes_enabled === true) {
289
- winston.info("email.send event catched");
295
+ winston.verbose("email.send event catched");
290
296
  let result = await this.incrementEmailCount(payload.project, payload.email);
291
297
  return result;
292
298
  } else {
293
- winston.info("QUOTES DISABLED - email.send event")
299
+ winston.verbose("QUOTES DISABLED - email.send event")
294
300
  }
295
301
  })
296
302
  // EMAIL EVENTS - END
@@ -0,0 +1,33 @@
1
+ let JobManager = require("jobs-worker-queued");
2
+ let winston = require('../config/winston');
3
+
4
+ let jobManager;
5
+
6
+ class Scheduler {
7
+
8
+ constructor(config) {
9
+
10
+ if (!config) {
11
+ throw new Error('(Scheduler) config is mandatory');
12
+ }
13
+
14
+ if (!config.jobManager) {
15
+ throw new Error('(Scheduler) config.jobManager is mandatory');
16
+ }
17
+
18
+ this.jobManager = config.jobManager;
19
+ }
20
+
21
+ trainSchedule(data, callback) {
22
+
23
+ winston.debug("(trainScheduler) data: ", data);
24
+ this.jobManager.publish(data, (err, ok) => {
25
+ let response_data = { success: true, message: "Scheduled" };
26
+ if (callback) {
27
+ callback(err, response_data);
28
+ }
29
+ });
30
+ }
31
+ }
32
+
33
+ module.exports = { Scheduler };