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.
- package/debug/Harness.js +86 -1
- package/package.json +8 -6
- package/source/Conversion-Core.js +939 -0
- package/source/Orator-Conversion-BeaconProvider.js +852 -0
- package/source/Orator-File-Translation.js +154 -0
- package/source/endpoints/Endpoint-Image-Convert.js +33 -0
- package/source/endpoints/Endpoint-Image-Resize.js +49 -0
- package/source/endpoints/Endpoint-Image-Rotate.js +34 -0
- package/test/Conversion-Core_tests.js +442 -0
- package/test/Orator-File-Translation_basic_tests.js +10 -4
- package/test/Orator-File-Translation_tests.js +148 -0
|
@@ -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;
|