orator-conversion 1.0.2 → 1.0.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.
@@ -6,8 +6,14 @@ const libFS = require('fs');
6
6
  const libPath = require('path');
7
7
  const libOS = require('os');
8
8
 
9
+ const libBeaconService = require('ultravisor-beacon');
10
+ const libOratorConversionBeaconProvider = require('./Orator-Conversion-BeaconProvider.js');
11
+
9
12
  const libEndpointImageJpgToPng = require('./endpoints/Endpoint-Image-JpgToPng.js');
10
13
  const libEndpointImagePngToJpg = require('./endpoints/Endpoint-Image-PngToJpg.js');
14
+ const libEndpointImageResize = require('./endpoints/Endpoint-Image-Resize.js');
15
+ const libEndpointImageRotate = require('./endpoints/Endpoint-Image-Rotate.js');
16
+ const libEndpointImageConvert = require('./endpoints/Endpoint-Image-Convert.js');
11
17
  const libEndpointPdfPageToPng = require('./endpoints/Endpoint-Pdf-PageToPng.js');
12
18
  const libEndpointPdfPageToJpg = require('./endpoints/Endpoint-Pdf-PageToJpg.js');
13
19
  const libEndpointPdfPageToPngSized = require('./endpoints/Endpoint-Pdf-PageToPng-Sized.js');
@@ -75,6 +81,9 @@ class OratorFileTranslation extends libFableServiceProviderBase
75
81
  // Array of instantiated endpoint services
76
82
  this._endpointServices = [];
77
83
 
84
+ // Beacon service reference (created on connectBeacon)
85
+ this._BeaconService = null;
86
+
78
87
  // Initialize the built-in converters
79
88
  this.initializeDefaultConverters();
80
89
  }
@@ -89,6 +98,9 @@ class OratorFileTranslation extends libFableServiceProviderBase
89
98
  // Register endpoint service types with fable
90
99
  this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-ImageJpgToPng', libEndpointImageJpgToPng);
91
100
  this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-ImagePngToJpg', libEndpointImagePngToJpg);
101
+ this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-ImageResize', libEndpointImageResize);
102
+ this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-ImageRotate', libEndpointImageRotate);
103
+ this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-ImageConvert', libEndpointImageConvert);
92
104
  this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-PdfPageToPng', libEndpointPdfPageToPng);
93
105
  this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-PdfPageToJpg', libEndpointPdfPageToJpg);
94
106
  this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-PdfPageToPngSized', libEndpointPdfPageToPngSized);
@@ -100,6 +112,9 @@ class OratorFileTranslation extends libFableServiceProviderBase
100
112
  [
101
113
  'OratorFileTranslationEndpoint-ImageJpgToPng',
102
114
  'OratorFileTranslationEndpoint-ImagePngToJpg',
115
+ 'OratorFileTranslationEndpoint-ImageResize',
116
+ 'OratorFileTranslationEndpoint-ImageRotate',
117
+ 'OratorFileTranslationEndpoint-ImageConvert',
103
118
  'OratorFileTranslationEndpoint-PdfPageToPng',
104
119
  'OratorFileTranslationEndpoint-PdfPageToJpg',
105
120
  'OratorFileTranslationEndpoint-PdfPageToPngSized',
@@ -499,6 +514,145 @@ class OratorFileTranslation extends libFableServiceProviderBase
499
514
 
500
515
  return true;
501
516
  }
517
+
518
+ /**
519
+ * Connect to an Ultravisor coordinator as a beacon, exposing the same
520
+ * MediaConversion capabilities available through the HTTP endpoints.
521
+ *
522
+ * This makes the running orator-conversion server discoverable by
523
+ * Ultravisor and allows it to receive work items from the mesh.
524
+ *
525
+ * @param {object} pBeaconConfig Beacon configuration:
526
+ * - ServerURL {string} Ultravisor server URL (required)
527
+ * - Name {string} Beacon name (default: 'orator-conversion')
528
+ * - Password {string} Auth password (default: '')
529
+ * - MaxConcurrent {number} Max concurrent work items (default: 2)
530
+ * - StagingPath {string} Local staging directory (default: cwd)
531
+ * - Tags {object} Beacon tags (default: {})
532
+ * @param {Function} fCallback Called with (pError, pBeaconInfo)
533
+ */
534
+ connectBeacon(pBeaconConfig, fCallback)
535
+ {
536
+ if (!pBeaconConfig || !pBeaconConfig.ServerURL)
537
+ {
538
+ return fCallback(new Error('connectBeacon requires a ServerURL in the config.'));
539
+ }
540
+
541
+ if (this._BeaconService && this._BeaconService.isEnabled())
542
+ {
543
+ this.log.warn('OratorFileTranslation: beacon already connected.');
544
+ return fCallback(null);
545
+ }
546
+
547
+ // Register the beacon service type with fable if not already present
548
+ this.fable.addServiceTypeIfNotExists('UltravisorBeacon', libBeaconService);
549
+
550
+ // Default staging path to dist/orator-conversion-staging
551
+ let tmpStagingPath = pBeaconConfig.StagingPath || require('path').resolve(__dirname, '..', 'dist', 'orator-conversion-staging');
552
+
553
+ // Ensure staging directory exists
554
+ try
555
+ {
556
+ require('fs').mkdirSync(tmpStagingPath, { recursive: true });
557
+ }
558
+ catch (pMkdirError)
559
+ {
560
+ // Already exists — fine
561
+ }
562
+
563
+ // Instantiate the beacon service with the provided config
564
+ this._BeaconService = this.fable.instantiateServiceProviderWithoutRegistration('UltravisorBeacon',
565
+ {
566
+ ServerURL: pBeaconConfig.ServerURL,
567
+ Name: pBeaconConfig.Name || 'orator-conversion',
568
+ Password: pBeaconConfig.Password || '',
569
+ MaxConcurrent: pBeaconConfig.MaxConcurrent || 2,
570
+ StagingPath: tmpStagingPath,
571
+ Tags: pBeaconConfig.Tags || {},
572
+ BindAddresses: pBeaconConfig.BindAddresses || []
573
+ });
574
+
575
+ // Create the MediaConversion capability provider and register it
576
+ let tmpProvider = new libOratorConversionBeaconProvider(
577
+ {
578
+ PdftkPath: this.PdftkPath,
579
+ PdftoppmPath: this.PdftoppmPath,
580
+ FfmpegPath: pBeaconConfig.FfmpegPath || 'ffmpeg',
581
+ FfprobePath: pBeaconConfig.FfprobePath || 'ffprobe',
582
+ MaxFileSizeBytes: this.MaxFileSize,
583
+ LogLevel: this.LogLevel
584
+ });
585
+
586
+ // Initialize the provider (checks tool availability), then register and enable
587
+ tmpProvider.initialize(
588
+ (pInitError) =>
589
+ {
590
+ if (pInitError)
591
+ {
592
+ this.log.error(`OratorFileTranslation: beacon provider init failed: ${pInitError.message}`);
593
+ this._BeaconService = null;
594
+ return fCallback(pInitError);
595
+ }
596
+
597
+ // Register the capability with the beacon service
598
+ this._BeaconService.registerCapability(
599
+ {
600
+ Capability: tmpProvider.Capability,
601
+ Name: tmpProvider.Name,
602
+ actions: tmpProvider.actions,
603
+ execute: tmpProvider.execute.bind(tmpProvider),
604
+ initialize: (fCb) => { return fCb(null); }, // Already initialized above
605
+ shutdown: (fCb) => { return fCb(null); }
606
+ });
607
+
608
+ // Enable the beacon — authenticate, register, begin polling
609
+ this._BeaconService.enable(
610
+ (pEnableError, pBeaconInfo) =>
611
+ {
612
+ if (pEnableError)
613
+ {
614
+ this.log.error(`OratorFileTranslation: beacon enable failed: ${pEnableError.message}`);
615
+ this._BeaconService = null;
616
+ return fCallback(pEnableError);
617
+ }
618
+
619
+ this.log.info(`OratorFileTranslation: beacon connected as ${pBeaconInfo.BeaconID}`);
620
+ return fCallback(null, pBeaconInfo);
621
+ });
622
+ });
623
+ }
624
+
625
+ /**
626
+ * Disconnect the beacon from the Ultravisor coordinator.
627
+ *
628
+ * @param {Function} fCallback Called with (pError)
629
+ */
630
+ disconnectBeacon(fCallback)
631
+ {
632
+ if (!this._BeaconService || !this._BeaconService.isEnabled())
633
+ {
634
+ if (this.log)
635
+ {
636
+ this.log.info('OratorFileTranslation: beacon not connected, nothing to disconnect.');
637
+ }
638
+ return fCallback(null);
639
+ }
640
+
641
+ this._BeaconService.disable(
642
+ (pError) =>
643
+ {
644
+ if (pError)
645
+ {
646
+ this.log.warn(`OratorFileTranslation: beacon disconnect warning: ${pError.message}`);
647
+ }
648
+ else
649
+ {
650
+ this.log.info('OratorFileTranslation: beacon disconnected.');
651
+ }
652
+ this._BeaconService = null;
653
+ return fCallback(pError || null);
654
+ });
655
+ }
502
656
  }
503
657
 
504
658
  module.exports = OratorFileTranslation;
@@ -0,0 +1,33 @@
1
+ const libFableServiceProviderBase = require('fable-serviceproviderbase');
2
+
3
+ const libConversionCore = require('../Conversion-Core.js');
4
+
5
+ class EndpointImageConvert extends libFableServiceProviderBase
6
+ {
7
+ constructor(pFable, pOptions, pServiceHash)
8
+ {
9
+ super(pFable, pOptions, pServiceHash);
10
+
11
+ this.serviceType = 'OratorFileTranslationEndpoint-ImageConvert';
12
+
13
+ this.converterPath = 'image/convert/:Format';
14
+ }
15
+
16
+ convert(pInputBuffer, pRequest, fCallback)
17
+ {
18
+ let tmpParams = pRequest.params || {};
19
+ let tmpQuery = pRequest.query || {};
20
+
21
+ let tmpCore = new libConversionCore();
22
+
23
+ let tmpOptions =
24
+ {
25
+ Format: tmpParams.Format,
26
+ Quality: tmpQuery.Quality ? parseInt(tmpQuery.Quality, 10) : undefined
27
+ };
28
+
29
+ tmpCore.imageConvert(pInputBuffer, tmpOptions, fCallback);
30
+ }
31
+ }
32
+
33
+ module.exports = EndpointImageConvert;
@@ -0,0 +1,49 @@
1
+ const libFableServiceProviderBase = require('fable-serviceproviderbase');
2
+ const libURL = require('url');
3
+
4
+ const libConversionCore = require('../Conversion-Core.js');
5
+
6
+ class EndpointImageResize extends libFableServiceProviderBase
7
+ {
8
+ constructor(pFable, pOptions, pServiceHash)
9
+ {
10
+ super(pFable, pOptions, pServiceHash);
11
+
12
+ this.serviceType = 'OratorFileTranslationEndpoint-ImageResize';
13
+
14
+ this.converterPath = 'image/resize';
15
+ }
16
+
17
+ convert(pInputBuffer, pRequest, fCallback)
18
+ {
19
+ let tmpFileTranslation = this.options.FileTranslation;
20
+
21
+ let tmpCore = new libConversionCore({
22
+ MaxFileSize: tmpFileTranslation ? tmpFileTranslation.MaxFileSize : undefined
23
+ });
24
+
25
+ let tmpParams = pRequest.params || {};
26
+ // Parse query string from the URL if pRequest.query is not available
27
+ let tmpQuery = pRequest.query || {};
28
+ if (Object.keys(tmpQuery).length === 0 && pRequest.url)
29
+ {
30
+ let tmpParsed = libURL.parse(pRequest.url, true);
31
+ tmpQuery = tmpParsed.query || {};
32
+ }
33
+
34
+ let tmpOptions =
35
+ {
36
+ Width: tmpQuery.Width || tmpParams.Width,
37
+ Height: tmpQuery.Height || tmpParams.Height,
38
+ Format: tmpQuery.Format || tmpParams.Format,
39
+ Quality: tmpQuery.Quality || tmpParams.Quality,
40
+ Fit: tmpQuery.Fit || tmpParams.Fit,
41
+ Position: tmpQuery.Position || tmpParams.Position,
42
+ AutoOrient: tmpQuery.AutoOrient !== 'false'
43
+ };
44
+
45
+ tmpCore.imageResize(pInputBuffer, tmpOptions, fCallback);
46
+ }
47
+ }
48
+
49
+ module.exports = EndpointImageResize;
@@ -0,0 +1,34 @@
1
+ const libFableServiceProviderBase = require('fable-serviceproviderbase');
2
+
3
+ const libConversionCore = require('../Conversion-Core.js');
4
+
5
+ class EndpointImageRotate extends libFableServiceProviderBase
6
+ {
7
+ constructor(pFable, pOptions, pServiceHash)
8
+ {
9
+ super(pFable, pOptions, pServiceHash);
10
+
11
+ this.serviceType = 'OratorFileTranslationEndpoint-ImageRotate';
12
+
13
+ this.converterPath = 'image/rotate/:Angle';
14
+ }
15
+
16
+ convert(pInputBuffer, pRequest, fCallback)
17
+ {
18
+ let tmpCore = new libConversionCore();
19
+
20
+ let tmpParams = pRequest.params || {};
21
+ let tmpQuery = pRequest.query || {};
22
+
23
+ let tmpOptions =
24
+ {
25
+ Angle: tmpParams.Angle,
26
+ Flip: (tmpQuery.Flip === 'true' || tmpQuery.Flip === '1'),
27
+ Flop: (tmpQuery.Flop === 'true' || tmpQuery.Flop === '1')
28
+ };
29
+
30
+ tmpCore.imageRotate(pInputBuffer, tmpOptions, fCallback);
31
+ }
32
+ }
33
+
34
+ module.exports = EndpointImageRotate;