@stemy/backend 2.9.8 → 3.1.0

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.
@@ -23,10 +23,9 @@ import sharp_ from 'sharp';
23
23
  import axios from 'axios';
24
24
  import { GridFSBucket } from 'mongodb';
25
25
  import dotenv from 'dotenv';
26
- import { Queue, Worker, Scheduler } from 'node-resque';
27
26
  import { validate, schedule } from 'node-cron';
28
- import ioredis from 'ioredis';
29
- import socket_io_client from 'socket.io-client';
27
+ import { socket } from 'zeromq';
28
+ import { filter as filter$1, map } from 'rxjs/operators';
30
29
  import { createServer } from 'http';
31
30
  import express_, { static as static$1 } from 'express';
32
31
  import socket_io from 'socket.io';
@@ -363,10 +362,14 @@ function writeFile(path, data) {
363
362
  function valueToPromise(value) {
364
363
  return value instanceof Promise ? value : Promise.resolve(value);
365
364
  }
366
- function promiseTimeout(timeout = 1000) {
367
- return new Promise((resolve) => {
365
+ function promiseTimeout(timeout = 1000, error = false) {
366
+ return new Promise((resolve, reject) => {
368
367
  setTimeout(() => {
369
- resolve();
368
+ if (error) {
369
+ reject(`Timeout exceeded: ${timeout}ms`);
370
+ return;
371
+ }
372
+ resolve(`Timeout: ${timeout}ms`);
370
373
  }, timeout);
371
374
  });
372
375
  }
@@ -640,6 +643,72 @@ function runCommand(scriptPath, expectedCode = 0) {
640
643
  console.error(data.toString());
641
644
  });
642
645
  });
646
+ }
647
+ var ConsoleColor;
648
+ (function (ConsoleColor) {
649
+ ConsoleColor["Reset"] = "\u001B[0m";
650
+ ConsoleColor["Bright"] = "\u001B[1m";
651
+ ConsoleColor["Dim"] = "\u001B[2m";
652
+ ConsoleColor["Underscore"] = "\u001B[4m";
653
+ ConsoleColor["Blink"] = "\u001B[5m";
654
+ ConsoleColor["Reverse"] = "\u001B[7m";
655
+ ConsoleColor["Hidden"] = "\u001B[8m";
656
+ ConsoleColor["FgBlack"] = "\u001B[30m";
657
+ ConsoleColor["FgRed"] = "\u001B[31m";
658
+ ConsoleColor["FgGreen"] = "\u001B[32m";
659
+ ConsoleColor["FgYellow"] = "\u001B[33m";
660
+ ConsoleColor["FgBlue"] = "\u001B[34m";
661
+ ConsoleColor["FgMagenta"] = "\u001B[35m";
662
+ ConsoleColor["FgCyan"] = "\u001B[36m";
663
+ ConsoleColor["FgWhite"] = "\u001B[37m";
664
+ ConsoleColor["FgDefault"] = "\u001B[38m";
665
+ ConsoleColor["BgBlack"] = "\u001B[40m";
666
+ ConsoleColor["BgRed"] = "\u001B[41m";
667
+ ConsoleColor["BgGreen"] = "\u001B[42m";
668
+ ConsoleColor["BgYellow"] = "\u001B[43m";
669
+ ConsoleColor["BgBlue"] = "\u001B[44m";
670
+ ConsoleColor["BgMagenta"] = "\u001B[45m";
671
+ ConsoleColor["BgCyan"] = "\u001B[46m";
672
+ ConsoleColor["BgWhite"] = "\u001B[47m";
673
+ ConsoleColor["BgDefault"] = "\u001B[48m";
674
+ })(ConsoleColor || (ConsoleColor = {}));
675
+ const defaultColors = {
676
+ keyColor: ConsoleColor.FgWhite,
677
+ numberColor: ConsoleColor.FgBlue,
678
+ stringColor: ConsoleColor.FgYellow,
679
+ trueColor: ConsoleColor.FgGreen,
680
+ falseColor: ConsoleColor.FgRed,
681
+ nullColor: ConsoleColor.BgMagenta
682
+ };
683
+ const MAX_TIMEOUT = 120000;
684
+ function colorize(input, color) {
685
+ return `${color}${input}${ConsoleColor.Reset}`;
686
+ }
687
+ function jsonHighlight(input, colorOptions) {
688
+ const colors = Object.assign({}, defaultColors, colorOptions);
689
+ const json = (isString(input) ? input : JSON.stringify(input, null, 2)).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
690
+ return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+]?\d+)?)/g, (match) => {
691
+ let color = colors.numberColor;
692
+ if (/^"/.test(match)) {
693
+ if (/:$/.test(match)) {
694
+ color = colors.keyColor;
695
+ }
696
+ else {
697
+ color = colors.stringColor;
698
+ match = '"' + match.substr(1, match.length - 2) + '"';
699
+ }
700
+ }
701
+ else {
702
+ color = /true/.test(match)
703
+ ? colors.trueColor
704
+ : /false/.test(match)
705
+ ? colors.falseColor
706
+ : /null/.test(match)
707
+ ? colors.nullColor
708
+ : color;
709
+ }
710
+ return `${color}${match}${ConsoleColor.Reset}`;
711
+ });
643
712
  }
644
713
 
645
714
  var __decorate$x = (this && this.__decorate) || function (decorators, target, key, desc) {
@@ -1058,9 +1127,10 @@ class Asset extends BaseEntity {
1058
1127
  params = params || {};
1059
1128
  // Get default crop info
1060
1129
  const crop = Asset.toCropRegion(meta.crop);
1061
- // Return back the stream if there is no params and no default crop exists
1062
- if (Object.keys(params).length == 0 && !crop)
1130
+ // Return the stream if there is no params and no default crop exists
1131
+ if ((meta === null || meta === void 0 ? void 0 : meta.extension) === "svg" || (Object.keys(params).length == 0 && !crop)) {
1063
1132
  return stream;
1133
+ }
1064
1134
  // Parse params
1065
1135
  params.rotation = isNaN(params.rotation) ? 0 : Math.round(params.rotation / 90) * 90;
1066
1136
  params.canvasScaleX = isNaN(params.canvasScaleX) ? 1 : Number(params.canvasScaleX);
@@ -1075,51 +1145,43 @@ class Asset extends BaseEntity {
1075
1145
  const cropBefore = Asset.toCropRegion(params.cropBefore || (params.crop ? meta.cropBefore : null));
1076
1146
  const cropAfter = Asset.toCropRegion(params.cropAfter || (params.crop ? meta.cropAfter : null));
1077
1147
  // Get metadata
1078
- const imgMeta = yield sharp$2(buffer).metadata();
1079
- let width = imgMeta.width;
1080
- let height = imgMeta.height;
1148
+ let img = sharp$2(buffer);
1149
+ let { width, height } = yield img.metadata();
1081
1150
  // Crop before resize
1082
1151
  if (cropBefore) {
1083
- buffer = yield sharp$2(buffer)
1084
- .extract(cropBefore)
1085
- .toBuffer();
1086
1152
  width = cropBefore.width;
1087
1153
  height = cropBefore.height;
1154
+ img = img.extract(cropBefore);
1088
1155
  }
1089
1156
  else if (crop) {
1090
- buffer = yield sharp$2(buffer)
1091
- .extract(crop)
1092
- .toBuffer();
1093
1157
  width = crop.width;
1094
1158
  height = crop.height;
1159
+ img = img.extract(crop);
1095
1160
  }
1096
1161
  // Resize canvas
1097
- if (params.canvasScaleX !== 1 || params.canvasScaleY !== 1) {
1162
+ const canvasScaleX = (meta === null || meta === void 0 ? void 0 : meta.canvasScaleX) || 1;
1163
+ const canvasScaleY = (meta === null || meta === void 0 ? void 0 : meta.canvasScaleY) || 1;
1164
+ if (params.canvasScaleX !== canvasScaleX || params.canvasScaleY !== canvasScaleY) {
1098
1165
  width = Math.round(width * params.canvasScaleX);
1099
1166
  height = Math.round(height * params.canvasScaleY);
1100
- buffer = yield sharp$2(buffer)
1101
- .resize({ width, height, background: "#00000000", fit: "contain" })
1102
- .toBuffer();
1167
+ img = img.resize({ width, height, background: "#00000000", fit: "contain" });
1103
1168
  }
1104
1169
  // Resize image
1105
1170
  if (params.scaleX !== 1 || params.scaleY !== 1) {
1106
1171
  width = Math.round(width * params.scaleX);
1107
1172
  height = Math.round(height * params.scaleY);
1108
- buffer = yield sharp$2(buffer)
1109
- .resize({ width, height, background: "#00000000", fit: "fill" })
1110
- .toBuffer();
1173
+ img = img.resize({ width, height, background: "#00000000", fit: "fill" });
1111
1174
  }
1112
1175
  // Crop after resize
1113
1176
  if (cropAfter) {
1114
- buffer = yield sharp$2(buffer)
1115
- .extract(cropAfter)
1116
- .toBuffer();
1177
+ img = img.extract(cropAfter);
1117
1178
  }
1118
1179
  // Rotate
1119
1180
  if (params.rotation !== 0) {
1120
- buffer = yield sharp$2(buffer).rotate(params.rotation).toBuffer();
1181
+ buffer = yield img.toBuffer();
1182
+ img = sharp$2(buffer).rotate(params.rotation);
1121
1183
  }
1122
- return bufferToStream(buffer);
1184
+ return bufferToStream(yield img.toBuffer());
1123
1185
  }
1124
1186
  catch (e) {
1125
1187
  console.log("Asset image conversion error", e);
@@ -1401,11 +1463,10 @@ var __awaiter$p = (this && this.__awaiter) || function (thisArg, _arguments, P,
1401
1463
  });
1402
1464
  };
1403
1465
  class LazyAsset extends BaseEntity {
1404
- constructor(id, data, collection, assets, progresses, jobMan) {
1466
+ constructor(id, data, collection, assets, progresses) {
1405
1467
  super(id, data, collection);
1406
1468
  this.assets = assets;
1407
1469
  this.progresses = progresses;
1408
- this.jobMan = jobMan;
1409
1470
  }
1410
1471
  get jobName() {
1411
1472
  return this.data.jobName;
@@ -1438,7 +1499,7 @@ class LazyAsset extends BaseEntity {
1438
1499
  this.progresses.get(this.progressId).then(p => {
1439
1500
  p === null || p === void 0 ? void 0 : p.cancel();
1440
1501
  });
1441
- this.startWorkingOnAsset().then(() => {
1502
+ this.startWorkingOnAsset(false).then(() => {
1442
1503
  console.log(`Started working on lazy asset: ${this.id}`);
1443
1504
  }).catch(reason => {
1444
1505
  console.log(`Can't start working on lazy asset: ${this.id}\nReason: ${reason}`);
@@ -1457,7 +1518,7 @@ class LazyAsset extends BaseEntity {
1457
1518
  yield this.progresses.waitToFinish(this.progressId);
1458
1519
  return this.loadAsset();
1459
1520
  }
1460
- yield this.startWorkingOnAsset();
1521
+ yield this.startWorkingOnAsset(true);
1461
1522
  return this.loadAsset();
1462
1523
  });
1463
1524
  }
@@ -1468,12 +1529,12 @@ class LazyAsset extends BaseEntity {
1468
1529
  return asset;
1469
1530
  });
1470
1531
  }
1471
- startWorkingOnAsset() {
1532
+ startWorkingOnAsset(fromLoad) {
1472
1533
  return __awaiter$p(this, void 0, void 0, function* () {
1473
1534
  this.data.progressId = (yield this.progresses.create()).id;
1474
1535
  this.data.assetId = null;
1475
1536
  yield this.save();
1476
- yield this.jobMan.enqueueWithName(this.data.jobName, Object.assign(Object.assign({}, this.data.jobParams), { lazyId: this.id }));
1537
+ yield this.progresses.jobMan.enqueueWithName(this.data.jobName, Object.assign(Object.assign({}, this.data.jobParams), { lazyId: this.id, fromLoad }));
1477
1538
  });
1478
1539
  }
1479
1540
  }
@@ -1499,18 +1560,30 @@ var __awaiter$o = (this && this.__awaiter) || function (thisArg, _arguments, P,
1499
1560
  step((generator = generator.apply(thisArg, _arguments || [])).next());
1500
1561
  });
1501
1562
  };
1502
- const IORedis = ioredis;
1503
1563
  let JobManager = class JobManager {
1504
1564
  constructor(config, container, jobTypes) {
1505
1565
  this.config = config;
1506
1566
  this.container = container;
1507
1567
  this.jobTypes = jobTypes || [];
1508
1568
  this.jobs = this.jobTypes.reduce((res, jobType) => {
1509
- res[getConstructorName(jobType)] = {
1510
- perform: this.toPerformFunction(jobType)
1569
+ res[getConstructorName(jobType)] = (jobParams) => {
1570
+ const job = this.resolveJobInstance(jobType, jobParams);
1571
+ return job.process(this.messageBridge);
1511
1572
  };
1512
1573
  return res;
1513
1574
  }, {});
1575
+ this.messages = new Subject();
1576
+ this.messageBridge = {
1577
+ sendMessage: (message, params) => {
1578
+ this.workerPush.send([message, JSON.stringify(params)]);
1579
+ }
1580
+ };
1581
+ this.processing = false;
1582
+ }
1583
+ on(message, cb) {
1584
+ return this.messages
1585
+ .pipe(filter$1(t => t.message === message))
1586
+ .pipe(map(t => t.params)).subscribe(cb);
1514
1587
  }
1515
1588
  process(jobType, params = {}) {
1516
1589
  return __awaiter$o(this, void 0, void 0, function* () {
@@ -1525,31 +1598,17 @@ let JobManager = class JobManager {
1525
1598
  return instance.process();
1526
1599
  });
1527
1600
  }
1528
- enqueueWithName(name, params = {}, que = "main") {
1529
- return __awaiter$o(this, void 0, void 0, function* () {
1530
- const jobName = yield this.tryResolveFromName(name, params);
1531
- yield this.queue.enqueue(que, jobName, [params]);
1532
- });
1533
- }
1534
- enqueue(jobType, params = {}, que = "main") {
1535
- return __awaiter$o(this, void 0, void 0, function* () {
1536
- const jobName = yield this.tryResolveAndConnect(jobType, params);
1537
- yield this.queue.enqueue(que, jobName, [params]);
1538
- });
1539
- }
1540
- enqueueAt(timestamp, jobType, params = {}, que = "main") {
1601
+ enqueueWithName(name, params = {}) {
1541
1602
  return __awaiter$o(this, void 0, void 0, function* () {
1542
- const jobName = yield this.tryResolveAndConnect(jobType, params);
1543
- yield this.queue.enqueueAt(timestamp, que, jobName, [params]);
1603
+ return this.sendToWorkers(this.tryResolveFromName(name, params), params);
1544
1604
  });
1545
1605
  }
1546
- enqueueIn(time, jobType, params = {}, que = "main") {
1606
+ enqueue(jobType, params = {}) {
1547
1607
  return __awaiter$o(this, void 0, void 0, function* () {
1548
- const jobName = yield this.tryResolveAndConnect(jobType, params);
1549
- yield this.queue.enqueueIn(time, que, jobName, [params]);
1608
+ return this.sendToWorkers(this.tryResolveAndInit(jobType, params), params);
1550
1609
  });
1551
1610
  }
1552
- schedule(minute, hour, dayOfMonth, month, dayOfWeek, jobType, params = {}, que = "main") {
1611
+ schedule(minute, hour, dayOfMonth, month, dayOfWeek, jobType, params = {}) {
1553
1612
  const expression = [minute, hour, dayOfMonth, month, dayOfWeek].map(t => {
1554
1613
  if (isObject(t)) {
1555
1614
  const range = t;
@@ -1566,18 +1625,52 @@ let JobManager = class JobManager {
1566
1625
  return null;
1567
1626
  }
1568
1627
  return schedule(expression, () => {
1569
- this.enqueue(jobType, params, que).catch(e => {
1628
+ this.enqueue(jobType, params).catch(e => {
1570
1629
  console.log(`Can't enqueue job: '${jobName}' because: ${e}`);
1571
1630
  });
1572
1631
  });
1573
1632
  }
1574
1633
  startProcessing() {
1575
1634
  return __awaiter$o(this, void 0, void 0, function* () {
1576
- this.initialize();
1577
- yield this.worker.connect();
1578
- yield this.worker.start();
1579
- yield this.scheduler.connect();
1580
- yield this.scheduler.start();
1635
+ if (this.processing)
1636
+ return null;
1637
+ this.processing = true;
1638
+ if (!this.config.resolve("isWorker")) {
1639
+ console.log(colorize(`Processing can not be started because this is NOT a worker process!`, ConsoleColor.FgRed));
1640
+ return null;
1641
+ }
1642
+ const host = this.config.resolve("zmqRemoteHost");
1643
+ const pushHost = `${host}:${this.config.resolve("zmqBackPort")}`;
1644
+ this.workerPush = socket("push");
1645
+ yield this.workerPush.connect(pushHost);
1646
+ console.log(`Worker producer connected to: ${pushHost}`);
1647
+ const pullHost = `${host}:${this.config.resolve("zmqPort")}`;
1648
+ this.workerPull = socket("pull");
1649
+ yield this.workerPull.connect(pullHost);
1650
+ console.log(`Worker consumer connected to: ${pullHost}`);
1651
+ this.workerPull.on("message", (name, args, uniqueId) => __awaiter$o(this, void 0, void 0, function* () {
1652
+ try {
1653
+ const jobName = name.toString("utf8");
1654
+ const jobParams = JSON.parse(args.toString("utf8"));
1655
+ const timerId = uniqueId === null || uniqueId === void 0 ? void 0 : uniqueId.toString("utf8");
1656
+ const jobNameLog = `\x1b[36m"${jobName}"\x1b[0m`;
1657
+ const jobArgsLog = `\n${jsonHighlight(jobParams)}`;
1658
+ console.time(timerId);
1659
+ console.timeLog(timerId, `Started working on background job: ${jobNameLog} with args: ${jobArgsLog}\n\n`);
1660
+ this.messageBridge.sendMessage(`job-started`, { name: jobName });
1661
+ try {
1662
+ yield Promise.race([this.jobs[jobName](jobParams), promiseTimeout(MAX_TIMEOUT, true)]);
1663
+ console.timeLog(timerId, `Finished working on background job: ${jobNameLog}\n\n`);
1664
+ }
1665
+ catch (e) {
1666
+ console.timeLog(timerId, `Background job failed: ${jobNameLog}\n${e.message}\n\n`);
1667
+ }
1668
+ console.timeEnd(timerId);
1669
+ }
1670
+ catch (e) {
1671
+ console.log(`Failed to start job: ${e.message}`);
1672
+ }
1673
+ }));
1581
1674
  });
1582
1675
  }
1583
1676
  tryResolve(jobType, params) {
@@ -1593,47 +1686,6 @@ let JobManager = class JobManager {
1593
1686
  }
1594
1687
  return jobName;
1595
1688
  }
1596
- initialize() {
1597
- if (this.queue)
1598
- return;
1599
- const config = this.config;
1600
- const options = { password: config.resolve("redisPassword") };
1601
- const sentinels = config.resolve("redisSentinels");
1602
- const redis = !sentinels
1603
- ? null
1604
- : new IORedis({
1605
- sentinels,
1606
- name: config.resolve("redisCluster"),
1607
- });
1608
- const connection = {
1609
- pkg: "ioredis",
1610
- host: config.resolve("redisHost"),
1611
- password: options.password,
1612
- port: config.resolve("redisPort"),
1613
- namespace: config.resolve("redisNamespace"),
1614
- redis,
1615
- options
1616
- };
1617
- const queues = config.resolve("workQueues");
1618
- this.queue = new Queue({ connection }, this.jobs);
1619
- this.worker = new Worker({ connection, queues }, this.jobs);
1620
- this.worker.on("job", (queue, job) => {
1621
- console.log(`working job ${queue} ${JSON.stringify(job)}`);
1622
- });
1623
- this.worker.on("reEnqueue", (queue, job, plugin) => {
1624
- console.log(`reEnqueue job (${plugin}) ${queue} ${JSON.stringify(job)}`);
1625
- });
1626
- this.worker.on("success", (queue, job, result, duration) => {
1627
- console.log(`job success ${queue} ${JSON.stringify(job)} >> ${result} (${duration}ms)`);
1628
- });
1629
- this.worker.on("failure", (queue, job, failure, duration) => {
1630
- console.log(`job failure ${queue} ${JSON.stringify(job)} >> ${failure} (${duration}ms)`);
1631
- });
1632
- this.worker.on("error", (error, queue, job) => {
1633
- console.log(`error ${queue} ${JSON.stringify(job)} >> ${error}`);
1634
- });
1635
- this.scheduler = new Scheduler({ connection }, this.jobs);
1636
- }
1637
1689
  tryResolveFromName(jobName, params) {
1638
1690
  const jobType = this.jobTypes.find(type => {
1639
1691
  return getConstructorName(type) == jobName;
@@ -1641,15 +1693,28 @@ let JobManager = class JobManager {
1641
1693
  if (!jobType) {
1642
1694
  throw `Can't find job type with name: ${jobName} so it can't be enqueued!`;
1643
1695
  }
1644
- return this.tryResolveAndConnect(jobType, params);
1645
- }
1646
- tryResolveAndConnect(jobType, params) {
1647
- return __awaiter$o(this, void 0, void 0, function* () {
1648
- this.initialize();
1649
- const jobName = this.tryResolve(jobType, params);
1650
- yield this.queue.connect();
1651
- return jobName;
1652
- });
1696
+ return this.tryResolveAndInit(jobType, params);
1697
+ }
1698
+ tryResolveAndInit(jobType, params) {
1699
+ if (!this.apiPush) {
1700
+ const port = this.config.resolve("zmqPort");
1701
+ this.apiPush = socket("push");
1702
+ this.apiPush.bind(`tcp://0.0.0.0:${port}`);
1703
+ console.log(`API producer bound to port: ${port}`);
1704
+ }
1705
+ if (!this.apiPull) {
1706
+ const backPort = this.config.resolve("zmqBackPort");
1707
+ this.apiPull = socket("pull");
1708
+ this.apiPull.bind(`tcp://0.0.0.0:${backPort}`);
1709
+ this.apiPull.on("message", (name, args) => {
1710
+ const message = name.toString("utf8");
1711
+ const params = JSON.parse((args === null || args === void 0 ? void 0 : args.toString("utf8")) || "{}");
1712
+ console.log(`Received a message from worker: "${colorize(message, ConsoleColor.FgCyan)}" with args: ${jsonHighlight(params)}\n\n`);
1713
+ this.messages.next({ message, params });
1714
+ });
1715
+ console.log(`API consumer bound to port: ${backPort}`);
1716
+ }
1717
+ return this.tryResolve(jobType, params);
1653
1718
  }
1654
1719
  resolveJobInstance(jobType, params) {
1655
1720
  const container = this.container.createChildContainer();
@@ -1659,11 +1724,11 @@ let JobManager = class JobManager {
1659
1724
  container.register(jobType, jobType);
1660
1725
  return container.resolve(jobType);
1661
1726
  }
1662
- toPerformFunction(jobType) {
1663
- return (jobParams) => {
1664
- const job = this.resolveJobInstance(jobType, jobParams);
1665
- return job.process();
1666
- };
1727
+ sendToWorkers(jobName, params) {
1728
+ return __awaiter$o(this, void 0, void 0, function* () {
1729
+ const publisher = yield this.apiPush;
1730
+ yield publisher.send([jobName, JSON.stringify(params), new ObjectId().toHexString()]);
1731
+ });
1667
1732
  }
1668
1733
  };
1669
1734
  JobManager = __decorate$s([
@@ -1683,9 +1748,8 @@ var __awaiter$n = (this && this.__awaiter) || function (thisArg, _arguments, P,
1683
1748
  });
1684
1749
  };
1685
1750
  class Progress extends BaseEntity {
1686
- constructor(id, data, collection, client) {
1751
+ constructor(id, data, collection) {
1687
1752
  super(id, data, collection);
1688
- this.client = client;
1689
1753
  }
1690
1754
  get current() {
1691
1755
  return this.data.current;
@@ -1708,6 +1772,10 @@ class Progress extends BaseEntity {
1708
1772
  get remaining() {
1709
1773
  return this.max > 0 ? this.max - this.current : 0;
1710
1774
  }
1775
+ setMessageBridge(messageBridge) {
1776
+ this.messageBridge = messageBridge || this.messageBridge;
1777
+ return this;
1778
+ }
1711
1779
  createSubProgress(progressValue, max, message) {
1712
1780
  return __awaiter$n(this, void 0, void 0, function* () {
1713
1781
  if (max <= 0 && progressValue > 0) {
@@ -1751,9 +1819,6 @@ class Progress extends BaseEntity {
1751
1819
  return null;
1752
1820
  this.data.current = Math.min(this.max, this.current + value);
1753
1821
  yield this.save();
1754
- if (!this.client)
1755
- return;
1756
- this.client.emit("background-progress", this.id);
1757
1822
  });
1758
1823
  }
1759
1824
  cancel() {
@@ -1762,6 +1827,12 @@ class Progress extends BaseEntity {
1762
1827
  yield this.save();
1763
1828
  });
1764
1829
  }
1830
+ save() {
1831
+ if (this.messageBridge) {
1832
+ this.messageBridge.sendMessage(`progress-changed`, this.toJSON());
1833
+ }
1834
+ return super.save();
1835
+ }
1765
1836
  }
1766
1837
  class SubProgress {
1767
1838
  constructor(parent, progressFrom, progressValue, mMax = 100) {
@@ -1801,6 +1872,12 @@ class SubProgress {
1801
1872
  get canceled() {
1802
1873
  return !this.parent || this.parent.canceled;
1803
1874
  }
1875
+ setMessageBridge(messageBridge) {
1876
+ if (!this.parent)
1877
+ return this;
1878
+ this.parent.setMessageBridge(messageBridge);
1879
+ return this;
1880
+ }
1804
1881
  createSubProgress(progressValue, max, message) {
1805
1882
  return __awaiter$n(this, void 0, void 0, function* () {
1806
1883
  if (max <= 0 && progressValue > 0) {
@@ -1889,33 +1966,34 @@ var __awaiter$m = (this && this.__awaiter) || function (thisArg, _arguments, P,
1889
1966
  step((generator = generator.apply(thisArg, _arguments || [])).next());
1890
1967
  });
1891
1968
  };
1892
- const socketIOClient = socket_io_client;
1893
1969
  let Progresses = class Progresses {
1894
- constructor(connector, config) {
1970
+ constructor(connector, jobMan) {
1895
1971
  this.connector = connector;
1896
- this.config = config;
1897
- const mainEndpoint = this.config.resolve("mainEndpoint");
1898
- this.client = !mainEndpoint ? null : socketIOClient(mainEndpoint, { path: "/socket" });
1972
+ this.jobMan = jobMan;
1899
1973
  this.collection = connector.database.collection("progresses");
1974
+ this.progresses = {};
1975
+ this.jobMan.on("progress-changed", progress => {
1976
+ const id = progress.id;
1977
+ this.progresses[id] = new Progress(new ObjectId(id), progress, this.collection);
1978
+ });
1900
1979
  }
1901
1980
  waitToFinish(id) {
1902
1981
  return __awaiter$m(this, void 0, void 0, function* () {
1903
- let isFinished = false;
1904
- let progress = null;
1905
- while (!isFinished) {
1906
- progress = yield this.get(id);
1907
- if (!progress) {
1908
- throw `Progress does not exists with id: ${id}`;
1909
- }
1910
- if (progress.error) {
1911
- throw progress.error;
1912
- }
1913
- isFinished = progress.percent == 100;
1914
- if (!isFinished) {
1915
- yield promiseTimeout(50);
1916
- }
1917
- }
1918
- return progress;
1982
+ return Promise.race([
1983
+ this.waitForProgress(id, () => __awaiter$m(this, void 0, void 0, function* () {
1984
+ let progress = this.progresses[id];
1985
+ if (!progress || progress.percent < 100) {
1986
+ progress = yield this.get(id);
1987
+ }
1988
+ if (!progress) {
1989
+ throw new Error(`Progress does not exists with id: ${id}`);
1990
+ }
1991
+ return progress;
1992
+ }), 500),
1993
+ this.waitForProgress(id, () => __awaiter$m(this, void 0, void 0, function* () {
1994
+ return this.progresses[id] || null;
1995
+ }), 25)
1996
+ ]);
1919
1997
  });
1920
1998
  }
1921
1999
  get(id) {
@@ -1926,13 +2004,13 @@ let Progresses = class Progresses {
1926
2004
  find(where) {
1927
2005
  return __awaiter$m(this, void 0, void 0, function* () {
1928
2006
  const data = yield this.collection.findOne(where);
1929
- return !data ? null : new Progress(data._id, data, this.collection, this.client);
2007
+ return !data ? null : new Progress(data._id, data, this.collection);
1930
2008
  });
1931
2009
  }
1932
2010
  create(max = 100) {
1933
2011
  return __awaiter$m(this, void 0, void 0, function* () {
1934
2012
  if (isNaN(max) || max <= 0) {
1935
- throw "Max progress value must be bigger than zero";
2013
+ throw new Error(`Max progress value must be bigger than zero`);
1936
2014
  }
1937
2015
  const data = {
1938
2016
  current: 0,
@@ -1942,7 +2020,7 @@ let Progresses = class Progresses {
1942
2020
  canceled: false
1943
2021
  };
1944
2022
  const res = yield this.collection.insertOne(data);
1945
- return new Progress(res.insertedId, data, this.collection, this.client);
2023
+ return new Progress(res.insertedId, data, this.collection);
1946
2024
  });
1947
2025
  }
1948
2026
  remove(id) {
@@ -1951,11 +2029,35 @@ let Progresses = class Progresses {
1951
2029
  return id;
1952
2030
  });
1953
2031
  }
2032
+ waitForProgress(id, cb, delay) {
2033
+ return __awaiter$m(this, void 0, void 0, function* () {
2034
+ let isFinished = false;
2035
+ let progress = null;
2036
+ let waitTime = 0;
2037
+ while (!isFinished) {
2038
+ progress = yield cb();
2039
+ waitTime += delay;
2040
+ if (progress) {
2041
+ if (progress.error) {
2042
+ throw new Error(progress.error);
2043
+ }
2044
+ isFinished = progress.percent >= 100;
2045
+ }
2046
+ if (!isFinished) {
2047
+ if (waitTime >= MAX_TIMEOUT) {
2048
+ throw new Error(`Progress with id: ${id} probably never will be finished!`);
2049
+ }
2050
+ yield promiseTimeout(delay);
2051
+ }
2052
+ }
2053
+ return progress;
2054
+ });
2055
+ }
1954
2056
  };
1955
2057
  Progresses = __decorate$r([
1956
2058
  injectable(),
1957
2059
  singleton(),
1958
- __metadata$l("design:paramtypes", [MongoConnector, Configuration])
2060
+ __metadata$l("design:paramtypes", [MongoConnector, JobManager])
1959
2061
  ], Progresses);
1960
2062
 
1961
2063
  var __decorate$q = (this && this.__decorate) || function (decorators, target, key, desc) {
@@ -1996,7 +2098,7 @@ let LazyAssets = class LazyAssets {
1996
2098
  if (existingAsset)
1997
2099
  return existingAsset;
1998
2100
  const res = yield this.collection.insertOne(data);
1999
- return new LazyAsset(res.insertedId, data, this.collection, this.assets, this.progresses, this.jobMan);
2101
+ return new LazyAsset(res.insertedId, data, this.collection, this.assets, this.progresses);
2000
2102
  });
2001
2103
  }
2002
2104
  read(id) {
@@ -2009,7 +2111,7 @@ let LazyAssets = class LazyAssets {
2009
2111
  const data = yield this.collection.findOne(where);
2010
2112
  return !data
2011
2113
  ? null
2012
- : new LazyAsset(data._id, data, this.collection, this.assets, this.progresses, this.jobMan);
2114
+ : new LazyAsset(data._id, data, this.collection, this.assets, this.progresses);
2013
2115
  });
2014
2116
  }
2015
2117
  unlink(id) {
@@ -2024,8 +2126,10 @@ let LazyAssets = class LazyAssets {
2024
2126
  LazyAssets = __decorate$q([
2025
2127
  injectable(),
2026
2128
  scoped(Lifecycle.ContainerScoped),
2027
- __metadata$k("design:paramtypes", [MongoConnector, Assets,
2028
- Progresses, JobManager])
2129
+ __metadata$k("design:paramtypes", [MongoConnector,
2130
+ Assets,
2131
+ Progresses,
2132
+ JobManager])
2029
2133
  ], LazyAssets);
2030
2134
 
2031
2135
  var __decorate$p = (this && this.__decorate) || function (decorators, target, key, desc) {
@@ -2986,7 +3090,9 @@ let AssetsController = class AssetsController {
2986
3090
  getImageRotation(id, params, res, rotation = 0) {
2987
3091
  return __awaiter$7(this, void 0, void 0, function* () {
2988
3092
  const asset = yield this.getAsset("Image", id, params.lazy, res);
2989
- params.rotation = params.rotation || rotation;
3093
+ if (rotation !== 0) {
3094
+ params.rotation = params.rotation || rotation;
3095
+ }
2990
3096
  return asset.downloadImage(params);
2991
3097
  });
2992
3098
  }
@@ -3724,14 +3830,15 @@ class LazyAssetGenerator {
3724
3830
  get lazyAssets() {
3725
3831
  return this.assetResolver.lazyAssets;
3726
3832
  }
3727
- process() {
3833
+ process(messaging) {
3728
3834
  return __awaiter$1(this, void 0, void 0, function* () {
3729
3835
  const lazyAsset = yield this.lazyAssets.read(this.lazyId);
3730
3836
  let progress = yield this.progresses.get(lazyAsset.progressId);
3731
3837
  if (!progress || progress.canceled)
3732
3838
  return null;
3839
+ progress.setMessageBridge(messaging);
3733
3840
  try {
3734
- const asset = yield this.generate(progress);
3841
+ const asset = yield this.generate(progress, messaging);
3735
3842
  progress = yield progress.load();
3736
3843
  if (!progress || progress.canceled)
3737
3844
  return null;
@@ -3797,20 +3904,9 @@ function createServices() {
3797
3904
  new Parameter("mongoPassword", null),
3798
3905
  new Parameter("nodeEnv", "development"),
3799
3906
  new Parameter("appPort", 80),
3800
- new Parameter("redisHost", "127.0.0.1"),
3801
- new Parameter("redisPort", 6379),
3802
- new Parameter("redisPassword", "123456"),
3803
- new Parameter("redisNamespace", "resque"),
3804
- new Parameter("redisCluster", "mymaster"),
3805
- new Parameter("redisSentinels", null, value => {
3806
- if (!value)
3807
- return null;
3808
- return value.split(", ").map(item => {
3809
- const values = item.split(":");
3810
- return { host: values[0], port: Number(values[1]) };
3811
- });
3812
- }),
3813
- new Parameter("workQueues", ["main"]),
3907
+ new Parameter("zmqPort", 3000),
3908
+ new Parameter("zmqBackPort", 3100),
3909
+ new Parameter("zmqRemoteHost", "tcp://127.0.0.1"),
3814
3910
  new Parameter("isWorker", false),
3815
3911
  new Parameter("mainEndpoint", ""),
3816
3912
  new Parameter("idChars", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
@@ -4016,5 +4112,5 @@ function setupBackend(config, providers, parent) {
4016
4112
  * Generated bundle index. Do not edit.
4017
4113
  */
4018
4114
 
4019
- export { AssetProcessor, AssetResolver, Assets, AuthController, BackendProvider, Cache, CacheProcessor, Configuration, DI_CONTAINER, EXPRESS, EndpointProvider, ErrorHandlerMiddleware, FIXTURE, Fixtures, Gallery, GalleryCache, GalleryController, HTTP_SERVER, IdGenerator, IsFile, IsObjectId, JOB, JobManager, LanguageMiddleware, LazyAssetGenerator, LazyAssets, MailSender, MemoryCache, MongoConnector, PARAMETER, Parameter, Progresses, ResolveEntity, SOCKET_SERVER, TemplateRenderer, TranslationProvider, Translator, Type, UserManager, assign, broadcast, bufferToStream, convertValue, copy, copyStream, createServices, createTransformer, deleteFile, deleteFromBucket, filter, firstItem, getConstructorName, getExtension, getFileName, getFunctionParams, getType, getValue, groupBy, hydratePopulated, idToString, injectServices, isArray, isBoolean, isConstructor, isDate, isDefined, isFunction, isInterface, isNullOrUndefined, isObject, isPrimitive, isString, isType, lastItem, lcFirst, lookupPipelines, md5, mkdirRecursive, multiSubscription, observableFromFunction, padLeft, padRight, paginate, paginateAggregations, promiseTimeout, proxyFunction, proxyFunctions, rand, random, readAndDeleteFile, readFile, runCommand, setupBackend, streamToBuffer, ucFirst, valueToPromise, writeFile };
4115
+ export { AssetProcessor, AssetResolver, Assets, AuthController, BackendProvider, Cache, CacheProcessor, Configuration, ConsoleColor, DI_CONTAINER, EXPRESS, EndpointProvider, ErrorHandlerMiddleware, FIXTURE, Fixtures, Gallery, GalleryCache, GalleryController, HTTP_SERVER, IdGenerator, IsFile, IsObjectId, JOB, JobManager, LanguageMiddleware, LazyAssetGenerator, LazyAssets, MailSender, MemoryCache, MongoConnector, PARAMETER, Parameter, Progresses, ResolveEntity, SOCKET_SERVER, TemplateRenderer, TranslationProvider, Translator, Type, UserManager, assign, broadcast, bufferToStream, colorize, convertValue, copy, copyStream, createServices, createTransformer, deleteFile, deleteFromBucket, filter, firstItem, getConstructorName, getExtension, getFileName, getFunctionParams, getType, getValue, groupBy, hydratePopulated, idToString, injectServices, isArray, isBoolean, isConstructor, isDate, isDefined, isFunction, isInterface, isNullOrUndefined, isObject, isPrimitive, isString, isType, jsonHighlight, lastItem, lcFirst, lookupPipelines, md5, mkdirRecursive, multiSubscription, observableFromFunction, padLeft, padRight, paginate, paginateAggregations, promiseTimeout, proxyFunction, proxyFunctions, rand, random, readAndDeleteFile, readFile, runCommand, setupBackend, streamToBuffer, ucFirst, valueToPromise, writeFile };
4020
4116
  //# sourceMappingURL=stemy-backend.js.map