ultravisor 1.0.18 → 1.0.20
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultravisor",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20",
|
|
4
4
|
"description": "Cyclic process execution with ai integration.",
|
|
5
5
|
"main": "source/Ultravisor.cjs",
|
|
6
6
|
"bin": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"pict": "^1.0.361",
|
|
35
35
|
"pict-service-commandlineutility": "^1.0.19",
|
|
36
36
|
"pict-serviceproviderbase": "^1.0.4",
|
|
37
|
-
"ultravisor-beacon": "^0.0.
|
|
37
|
+
"ultravisor-beacon": "^0.0.10",
|
|
38
38
|
"ws": "^8.20.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
@@ -116,6 +116,34 @@ if (_LogFilePath)
|
|
|
116
116
|
console.log(`[Ultravisor] Logging to file: ${_LogFilePath}`);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
// Apply LogNoisiness from RETOLD_LOG_NOISINESS env var. Pict-style log
|
|
120
|
+
// noisiness is a 0-5 scale where 0 is silent (production default) and 5 shows
|
|
121
|
+
// everything. Diagnostic log statements throughout Ultravisor (especially the
|
|
122
|
+
// shared-fs reachability auto-detect path and the platform tasks) are gated
|
|
123
|
+
// with `if (this.fable.LogNoisiness >= N)` so they're free at level 0 and
|
|
124
|
+
// explosively detailed at level 4-5.
|
|
125
|
+
//
|
|
126
|
+
// Useful values:
|
|
127
|
+
// 1 — high-level decisions (auto-detected shared-fs peer X)
|
|
128
|
+
// 2 — entry points and decisions in shared-fs / dispatch paths
|
|
129
|
+
// 3 — per-candidate iteration in reachability
|
|
130
|
+
// 4 — per-mount comparison details
|
|
131
|
+
// 5 — everything
|
|
132
|
+
//
|
|
133
|
+
// In stack-mode the launcher inherits process.env into the child Ultravisor
|
|
134
|
+
// process automatically, so setting RETOLD_LOG_NOISINESS once on the host
|
|
135
|
+
// (or in the docker-compose `environment:` block) lights up both processes.
|
|
136
|
+
let _LogNoisiness = parseInt(process.env.RETOLD_LOG_NOISINESS, 10);
|
|
137
|
+
if (!isNaN(_LogNoisiness) && _LogNoisiness > 0)
|
|
138
|
+
{
|
|
139
|
+
_Ultravisor_Pict.LogNoisiness = _LogNoisiness;
|
|
140
|
+
if (_Ultravisor_Pict.fable && _Ultravisor_Pict.fable !== _Ultravisor_Pict)
|
|
141
|
+
{
|
|
142
|
+
_Ultravisor_Pict.fable.LogNoisiness = _LogNoisiness;
|
|
143
|
+
}
|
|
144
|
+
console.log(`[Ultravisor] LogNoisiness=${_LogNoisiness} (verbose diagnostics enabled).`);
|
|
145
|
+
}
|
|
146
|
+
|
|
119
147
|
// If a config file override was passed via --config / -c, apply it on top of the gathered config
|
|
120
148
|
if (_ConfigFileOverride)
|
|
121
149
|
{
|
|
@@ -474,6 +474,135 @@ class UltravisorBeaconReachability extends libPictService
|
|
|
474
474
|
}
|
|
475
475
|
return null;
|
|
476
476
|
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Walk all online beacons looking for one that shares a filesystem with
|
|
480
|
+
* the given source beacon. Returns the first peer that:
|
|
481
|
+
* 1. is not the source beacon itself
|
|
482
|
+
* 2. has the same HostID as the source
|
|
483
|
+
* 3. has at least one MountID overlap with the source
|
|
484
|
+
*
|
|
485
|
+
* This is used by the resolve-address task to auto-detect when a shared-fs
|
|
486
|
+
* fast path is available even when the caller did not explicitly identify
|
|
487
|
+
* a "requesting beacon". The typical case: retold-remote dispatches a media
|
|
488
|
+
* operation, the file lives on retold-remote, and orator-conversion (which
|
|
489
|
+
* will eventually consume the file) runs in the same process / on the same
|
|
490
|
+
* host with the same content mount. The auto-detection finds orator-conversion
|
|
491
|
+
* as a peer of retold-remote and reports the shared-fs strategy so the
|
|
492
|
+
* file-transfer task can short-circuit.
|
|
493
|
+
*
|
|
494
|
+
* Diagnostic logging is gated by Fable.LogNoisiness (set via the
|
|
495
|
+
* RETOLD_LOG_NOISINESS env var, 0-5):
|
|
496
|
+
* >= 2: log entry, source beacon summary, final decision
|
|
497
|
+
* >= 3: per-candidate iteration with rejection reasons
|
|
498
|
+
* >= 4: per-mount comparison details
|
|
499
|
+
*
|
|
500
|
+
* @param {string} pSourceBeaconID
|
|
501
|
+
* @returns {object|null} { Peer, Mount } or null if no shared-fs peer exists
|
|
502
|
+
*/
|
|
503
|
+
findSharedFsPeer(pSourceBeaconID)
|
|
504
|
+
{
|
|
505
|
+
let tmpNoisy = (this.fable && this.fable.LogNoisiness) || 0;
|
|
506
|
+
|
|
507
|
+
let tmpCoordinator = this._getService('UltravisorBeaconCoordinator');
|
|
508
|
+
if (!tmpCoordinator)
|
|
509
|
+
{
|
|
510
|
+
if (tmpNoisy >= 2)
|
|
511
|
+
{
|
|
512
|
+
this.log.info(`[Reachability] findSharedFsPeer(${pSourceBeaconID}): no UltravisorBeaconCoordinator service registered, returning null.`);
|
|
513
|
+
}
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
let tmpSource = tmpCoordinator.getBeacon(pSourceBeaconID);
|
|
518
|
+
if (!tmpSource)
|
|
519
|
+
{
|
|
520
|
+
if (tmpNoisy >= 2)
|
|
521
|
+
{
|
|
522
|
+
this.log.info(`[Reachability] findSharedFsPeer(${pSourceBeaconID}): source beacon not in coordinator registry, returning null.`);
|
|
523
|
+
}
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
if (!tmpSource.HostID)
|
|
527
|
+
{
|
|
528
|
+
if (tmpNoisy >= 2)
|
|
529
|
+
{
|
|
530
|
+
this.log.info(`[Reachability] findSharedFsPeer(${pSourceBeaconID}): source beacon has no HostID (legacy beacon), returning null.`);
|
|
531
|
+
}
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
if (!Array.isArray(tmpSource.SharedMounts) || tmpSource.SharedMounts.length === 0)
|
|
535
|
+
{
|
|
536
|
+
if (tmpNoisy >= 2)
|
|
537
|
+
{
|
|
538
|
+
this.log.info(`[Reachability] findSharedFsPeer(${pSourceBeaconID}): source beacon advertises no SharedMounts, returning null.`);
|
|
539
|
+
}
|
|
540
|
+
return null;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (tmpNoisy >= 2)
|
|
544
|
+
{
|
|
545
|
+
this.log.info(`[Reachability] findSharedFsPeer(${pSourceBeaconID}): source HostID=${tmpSource.HostID}, ${tmpSource.SharedMounts.length} mount(s)=${JSON.stringify(tmpSource.SharedMounts.map((m) => m.MountID))}`);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
let tmpAllBeacons = tmpCoordinator.listBeacons();
|
|
549
|
+
if (tmpNoisy >= 2)
|
|
550
|
+
{
|
|
551
|
+
this.log.info(`[Reachability] findSharedFsPeer(${pSourceBeaconID}): scanning ${tmpAllBeacons.length} registered beacon(s) for shared-fs peers...`);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
for (let i = 0; i < tmpAllBeacons.length; i++)
|
|
555
|
+
{
|
|
556
|
+
let tmpPeer = tmpAllBeacons[i];
|
|
557
|
+
if (!tmpPeer || tmpPeer.BeaconID === pSourceBeaconID)
|
|
558
|
+
{
|
|
559
|
+
if (tmpNoisy >= 3)
|
|
560
|
+
{
|
|
561
|
+
this.log.info(`[Reachability] skip [${tmpPeer ? tmpPeer.BeaconID : '(null)'}]: ${tmpPeer ? 'self' : 'null entry'}`);
|
|
562
|
+
}
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
if (tmpPeer.Status && tmpPeer.Status !== 'Online')
|
|
566
|
+
{
|
|
567
|
+
if (tmpNoisy >= 3)
|
|
568
|
+
{
|
|
569
|
+
this.log.info(`[Reachability] skip [${tmpPeer.BeaconID}]: status=${tmpPeer.Status} (not Online)`);
|
|
570
|
+
}
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
if (!tmpPeer.HostID || tmpPeer.HostID !== tmpSource.HostID)
|
|
574
|
+
{
|
|
575
|
+
if (tmpNoisy >= 3)
|
|
576
|
+
{
|
|
577
|
+
this.log.info(`[Reachability] skip [${tmpPeer.BeaconID}]: HostID=${tmpPeer.HostID || '(none)'} != source ${tmpSource.HostID}`);
|
|
578
|
+
}
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
if (tmpNoisy >= 4)
|
|
582
|
+
{
|
|
583
|
+
this.log.info(`[Reachability] compare mounts for [${tmpPeer.BeaconID}]: source=${JSON.stringify(tmpSource.SharedMounts.map((m) => m.MountID))} vs peer=${JSON.stringify((tmpPeer.SharedMounts || []).map((m) => m.MountID))}`);
|
|
584
|
+
}
|
|
585
|
+
let tmpSharedMount = this._findSharedMount(tmpSource.SharedMounts, tmpPeer.SharedMounts);
|
|
586
|
+
if (tmpSharedMount)
|
|
587
|
+
{
|
|
588
|
+
if (tmpNoisy >= 2)
|
|
589
|
+
{
|
|
590
|
+
this.log.info(`[Reachability] findSharedFsPeer(${pSourceBeaconID}): MATCH peer=[${tmpPeer.BeaconID}] mount=[${tmpSharedMount.MountID}] root=${tmpSharedMount.Root}`);
|
|
591
|
+
}
|
|
592
|
+
return { Peer: tmpPeer, Mount: tmpSharedMount };
|
|
593
|
+
}
|
|
594
|
+
if (tmpNoisy >= 3)
|
|
595
|
+
{
|
|
596
|
+
this.log.info(`[Reachability] skip [${tmpPeer.BeaconID}]: same HostID but no overlapping MountID`);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
if (tmpNoisy >= 2)
|
|
601
|
+
{
|
|
602
|
+
this.log.info(`[Reachability] findSharedFsPeer(${pSourceBeaconID}): no shared-fs peer found among ${tmpAllBeacons.length} beacon(s).`);
|
|
603
|
+
}
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
477
606
|
}
|
|
478
607
|
|
|
479
608
|
module.exports = UltravisorBeaconReachability;
|
|
@@ -25,6 +25,18 @@ function _getService(pTask, pTypeName)
|
|
|
25
25
|
: null;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Get the LogNoisiness level (0-5) from the Fable instance attached to a task.
|
|
30
|
+
* Used to gate verbose diagnostic logging in the platform tasks. The user
|
|
31
|
+
* controls this via the RETOLD_LOG_NOISINESS environment variable, which the
|
|
32
|
+
* stack launcher applies to both the retold-remote Fable and the Ultravisor
|
|
33
|
+
* Pict instance at startup.
|
|
34
|
+
*/
|
|
35
|
+
function _getNoisiness(pTask)
|
|
36
|
+
{
|
|
37
|
+
return (pTask && pTask.fable && pTask.fable.LogNoisiness) || 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
28
40
|
|
|
29
41
|
module.exports =
|
|
30
42
|
[
|
|
@@ -106,55 +118,115 @@ module.exports =
|
|
|
106
118
|
return pDirectBaseURL.replace(/\/$/, '') + tmpContextPath + tmpEncodedPath;
|
|
107
119
|
};
|
|
108
120
|
|
|
121
|
+
// Helper: compute the absolute path on the source beacon's filesystem
|
|
122
|
+
// for the resolved resource. Returns null if the source beacon does
|
|
123
|
+
// not have a BasePath registered for this context.
|
|
124
|
+
let _computeSharedFsLocalPath = function ()
|
|
125
|
+
{
|
|
126
|
+
let tmpSourceBeacon = tmpCoordinator.getBeacon(tmpResolved.BeaconID);
|
|
127
|
+
let tmpCtx = tmpSourceBeacon && tmpSourceBeacon.Contexts
|
|
128
|
+
? tmpSourceBeacon.Contexts[tmpResolved.Context]
|
|
129
|
+
: null;
|
|
130
|
+
if (tmpCtx && tmpCtx.BasePath)
|
|
131
|
+
{
|
|
132
|
+
return libPath.join(tmpCtx.BasePath, tmpResolved.Path);
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
let tmpReachability = _getService(pTask, 'UltravisorBeaconReachability');
|
|
138
|
+
let tmpNoisy = _getNoisiness(pTask);
|
|
139
|
+
|
|
140
|
+
if (tmpNoisy >= 2)
|
|
141
|
+
{
|
|
142
|
+
pTask.log.info(`[ResolveAddress] entry: address=${tmpAddress} sourceBeacon=${tmpResolved.BeaconID} requestingBeacon=${pResolvedSettings.RequestingBeaconID || '(none)'} reachability=${tmpReachability ? 'present' : 'missing'}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
109
145
|
// Resolve transfer strategy when a requesting beacon is specified
|
|
110
146
|
let tmpRequestingBeaconID = pResolvedSettings.RequestingBeaconID;
|
|
111
|
-
if (tmpRequestingBeaconID)
|
|
147
|
+
if (tmpRequestingBeaconID && tmpReachability)
|
|
112
148
|
{
|
|
113
|
-
|
|
114
|
-
if (tmpReachability)
|
|
149
|
+
if (tmpNoisy >= 2)
|
|
115
150
|
{
|
|
116
|
-
|
|
117
|
-
|
|
151
|
+
pTask.log.info(`[ResolveAddress] explicit RequestingBeaconID=${tmpRequestingBeaconID} provided — calling resolveStrategy directly.`);
|
|
152
|
+
}
|
|
153
|
+
let tmpStrategyResult = tmpReachability.resolveStrategy(tmpResolved.BeaconID, tmpRequestingBeaconID);
|
|
154
|
+
tmpOutputs.Strategy = tmpStrategyResult.Strategy;
|
|
118
155
|
|
|
119
|
-
|
|
156
|
+
if (tmpStrategyResult.Strategy === 'shared-fs')
|
|
157
|
+
{
|
|
158
|
+
// Both beacons see the same filesystem mount. Look up the
|
|
159
|
+
// source beacon's context BasePath and join it with the inner
|
|
160
|
+
// resource path to get an absolute path that's also valid on
|
|
161
|
+
// the requesting beacon (because they share the mount).
|
|
162
|
+
let tmpAbsPath = _computeSharedFsLocalPath();
|
|
163
|
+
if (tmpAbsPath)
|
|
120
164
|
{
|
|
121
|
-
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
// the
|
|
125
|
-
let tmpSourceBeacon = tmpCoordinator.getBeacon(tmpResolved.BeaconID);
|
|
126
|
-
let tmpCtx = tmpSourceBeacon && tmpSourceBeacon.Contexts
|
|
127
|
-
? tmpSourceBeacon.Contexts[tmpResolved.Context]
|
|
128
|
-
: null;
|
|
129
|
-
if (tmpCtx && tmpCtx.BasePath)
|
|
130
|
-
{
|
|
131
|
-
let tmpAbsPath = libPath.join(tmpCtx.BasePath, tmpResolved.Path);
|
|
132
|
-
tmpOutputs.LocalPath = tmpAbsPath;
|
|
133
|
-
// URL is intentionally left as the original (relative) URL
|
|
134
|
-
// — file-transfer will see LocalPath and short-circuit, so
|
|
135
|
-
// the URL is never actually fetched.
|
|
136
|
-
}
|
|
137
|
-
else
|
|
138
|
-
{
|
|
139
|
-
// No BasePath available — fall back to direct so the
|
|
140
|
-
// transfer still works via HTTP.
|
|
141
|
-
pTask.log.warn(`Resolve Address: shared-fs strategy chosen but no BasePath available for context [${tmpResolved.Context}] on beacon [${tmpResolved.BeaconID}], falling back to direct.`);
|
|
142
|
-
tmpOutputs.Strategy = 'direct';
|
|
143
|
-
}
|
|
165
|
+
tmpOutputs.LocalPath = tmpAbsPath;
|
|
166
|
+
// URL is intentionally left as the original (relative) URL
|
|
167
|
+
// — file-transfer will see LocalPath and short-circuit, so
|
|
168
|
+
// the URL is never actually fetched.
|
|
144
169
|
}
|
|
145
|
-
else
|
|
170
|
+
else
|
|
171
|
+
{
|
|
172
|
+
// No BasePath available — fall back to direct so the
|
|
173
|
+
// transfer still works via HTTP.
|
|
174
|
+
pTask.log.warn(`Resolve Address: shared-fs strategy chosen but no BasePath available for context [${tmpResolved.Context}] on beacon [${tmpResolved.BeaconID}], falling back to direct.`);
|
|
175
|
+
tmpOutputs.Strategy = 'direct';
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else if (tmpStrategyResult.Strategy === 'direct' && tmpStrategyResult.DirectURL)
|
|
179
|
+
{
|
|
180
|
+
tmpOutputs.DirectURL = _buildDirectURL(tmpStrategyResult.DirectURL);
|
|
181
|
+
tmpOutputs.URL = tmpOutputs.DirectURL;
|
|
182
|
+
}
|
|
183
|
+
else if (tmpStrategyResult.Strategy === 'proxy')
|
|
184
|
+
{
|
|
185
|
+
// Proxy URL: Ultravisor's own endpoint serves the file
|
|
186
|
+
tmpOutputs.ProxyURL = tmpResolved.URL;
|
|
187
|
+
tmpOutputs.URL = tmpResolved.URL;
|
|
188
|
+
}
|
|
189
|
+
// 'local' strategy: URL stays as the context BaseURL (same host)
|
|
190
|
+
}
|
|
191
|
+
else if (tmpReachability)
|
|
192
|
+
{
|
|
193
|
+
// Auto-detect a shared-fs peer when no RequestingBeaconID was passed.
|
|
194
|
+
// This is the common case for retold-remote: it dispatches a media
|
|
195
|
+
// operation, the file lives on the retold-remote beacon, and an
|
|
196
|
+
// orator-conversion beacon on the same host shares the mount. The
|
|
197
|
+
// auto-detection finds the orator-conversion peer and lets us
|
|
198
|
+
// short-circuit the file-transfer entirely.
|
|
199
|
+
if (tmpNoisy >= 2)
|
|
200
|
+
{
|
|
201
|
+
pTask.log.info(`[ResolveAddress] no RequestingBeaconID — entering auto-detect path for source ${tmpResolved.BeaconID}`);
|
|
202
|
+
}
|
|
203
|
+
let tmpPeerInfo = tmpReachability.findSharedFsPeer(tmpResolved.BeaconID);
|
|
204
|
+
if (tmpPeerInfo)
|
|
205
|
+
{
|
|
206
|
+
let tmpAbsPath = _computeSharedFsLocalPath();
|
|
207
|
+
if (tmpAbsPath)
|
|
146
208
|
{
|
|
147
|
-
tmpOutputs.
|
|
148
|
-
tmpOutputs.
|
|
209
|
+
tmpOutputs.Strategy = 'shared-fs';
|
|
210
|
+
tmpOutputs.LocalPath = tmpAbsPath;
|
|
211
|
+
pTask.log.info(`Resolve Address: auto-detected shared-fs peer [${tmpPeerInfo.Peer.BeaconID}] for source [${tmpResolved.BeaconID}] via mount [${tmpPeerInfo.Mount.MountID}].`);
|
|
212
|
+
if (tmpNoisy >= 2)
|
|
213
|
+
{
|
|
214
|
+
pTask.log.info(`[ResolveAddress] auto-detect SUCCESS: LocalPath=${tmpAbsPath} (peer=${tmpPeerInfo.Peer.BeaconID}, mount=${tmpPeerInfo.Mount.MountID})`);
|
|
215
|
+
}
|
|
149
216
|
}
|
|
150
|
-
else if (
|
|
217
|
+
else if (tmpNoisy >= 2)
|
|
151
218
|
{
|
|
152
|
-
|
|
153
|
-
tmpOutputs.ProxyURL = tmpResolved.URL;
|
|
154
|
-
tmpOutputs.URL = tmpResolved.URL;
|
|
219
|
+
pTask.log.info(`[ResolveAddress] auto-detect found peer [${tmpPeerInfo.Peer.BeaconID}] but source beacon has no BasePath for context [${tmpResolved.Context}] — cannot use shared-fs.`);
|
|
155
220
|
}
|
|
156
|
-
// 'local' strategy: URL stays as the context BaseURL (same host)
|
|
157
221
|
}
|
|
222
|
+
else if (tmpNoisy >= 2)
|
|
223
|
+
{
|
|
224
|
+
pTask.log.info(`[ResolveAddress] auto-detect found NO shared-fs peer for source ${tmpResolved.BeaconID} — falling through to default direct/proxy strategy.`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else if (tmpNoisy >= 2)
|
|
228
|
+
{
|
|
229
|
+
pTask.log.info(`[ResolveAddress] reachability service not available — skipping auto-detect, default strategy will be used.`);
|
|
158
230
|
}
|
|
159
231
|
|
|
160
232
|
// If the URL is still relative (no protocol), use the beacon's first
|
|
@@ -218,6 +290,12 @@ module.exports =
|
|
|
218
290
|
let tmpSourceURL = pResolvedSettings.SourceURL;
|
|
219
291
|
let tmpSourceLocalPath = pResolvedSettings.SourceLocalPath;
|
|
220
292
|
let tmpFilename = pResolvedSettings.Filename;
|
|
293
|
+
let tmpNoisy = _getNoisiness(pTask);
|
|
294
|
+
|
|
295
|
+
if (tmpNoisy >= 2)
|
|
296
|
+
{
|
|
297
|
+
pTask.log.info(`[FileTransfer] entry: SourceURL=${tmpSourceURL ? tmpSourceURL.substring(0, 80) : '(none)'} SourceLocalPath=${tmpSourceLocalPath || '(none)'} Filename=${tmpFilename || '(none)'}`);
|
|
298
|
+
}
|
|
221
299
|
|
|
222
300
|
// Shared-filesystem fast path: if the source beacon and the requesting
|
|
223
301
|
// beacon both report the same MountID, resolve-address will populate
|
|
@@ -259,6 +337,14 @@ module.exports =
|
|
|
259
337
|
// Path was provided but doesn't exist on this beacon — log and fall
|
|
260
338
|
// through to the HTTP path so we still satisfy the request.
|
|
261
339
|
pTask.log.warn(`File Transfer: SourceLocalPath [${tmpSourceLocalPath}] does not exist on this beacon, falling back to HTTP transfer.`);
|
|
340
|
+
if (tmpNoisy >= 2)
|
|
341
|
+
{
|
|
342
|
+
pTask.log.info(`[FileTransfer] SourceLocalPath was set but file is missing on this beacon — the requesting beacon doesn't actually share this filesystem at the expected path.`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
else if (tmpNoisy >= 2)
|
|
346
|
+
{
|
|
347
|
+
pTask.log.info(`[FileTransfer] no SourceLocalPath in settings — running standard HTTP download path. (Either resolve-address chose 'direct'/'proxy', or the operation graph isn't wiring resolve.LocalPath → transfer.SourceLocalPath.)`);
|
|
262
348
|
}
|
|
263
349
|
|
|
264
350
|
if (!tmpSourceURL)
|
|
@@ -2055,6 +2055,11 @@ class UltravisorAPIServer extends libPictService
|
|
|
2055
2055
|
return;
|
|
2056
2056
|
}
|
|
2057
2057
|
|
|
2058
|
+
// IMPORTANT: this enumeration must include every field the coordinator
|
|
2059
|
+
// cares about, including HostID and SharedMounts (used by the shared-fs
|
|
2060
|
+
// reachability auto-detect). Forgetting to forward a field here means
|
|
2061
|
+
// the WebSocket-registered beacon record will have that field set to
|
|
2062
|
+
// null/empty in the coordinator, even though the client sent the value.
|
|
2058
2063
|
let tmpBeacon = tmpCoordinator.registerBeacon({
|
|
2059
2064
|
Name: pData.Name,
|
|
2060
2065
|
Capabilities: pData.Capabilities,
|
|
@@ -2063,7 +2068,9 @@ class UltravisorAPIServer extends libPictService
|
|
|
2063
2068
|
MaxConcurrent: pData.MaxConcurrent,
|
|
2064
2069
|
Tags: pData.Tags,
|
|
2065
2070
|
Contexts: pData.Contexts,
|
|
2066
|
-
BindAddresses: pData.BindAddresses
|
|
2071
|
+
BindAddresses: pData.BindAddresses,
|
|
2072
|
+
HostID: pData.HostID,
|
|
2073
|
+
SharedMounts: pData.SharedMounts
|
|
2067
2074
|
});
|
|
2068
2075
|
|
|
2069
2076
|
pWebSocket._BeaconID = tmpBeacon.BeaconID;
|