@xiboplayer/xmr 0.3.6 → 0.4.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.
- package/package.json +2 -2
- package/src/xmr-wrapper.js +30 -11
- package/src/xmr-wrapper.test.js +5 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xiboplayer/xmr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "XMR WebSocket client for real-time Xibo CMS commands",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@xibosignage/xibo-communication-framework": "^0.0.6",
|
|
12
|
-
"@xiboplayer/utils": "0.
|
|
12
|
+
"@xiboplayer/utils": "0.4.0"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"vitest": "^2.0.0"
|
package/src/xmr-wrapper.js
CHANGED
|
@@ -156,10 +156,18 @@ export class XmrWrapper {
|
|
|
156
156
|
});
|
|
157
157
|
|
|
158
158
|
// CMS command: Change Layout
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
// Payload may be a layoutId string or an object with { layoutId, duration, downloadRequired, changeMode }
|
|
160
|
+
this.xmr.on('changeLayout', async (data) => {
|
|
161
|
+
const layoutId = typeof data === 'object' ? (data.layoutId || data) : data;
|
|
162
|
+
const duration = typeof data === 'object' ? (parseInt(data.duration) || 0) : 0;
|
|
163
|
+
const changeMode = typeof data === 'object' ? (data.changeMode || 'replace') : 'replace';
|
|
164
|
+
log.info('Received changeLayout command:', layoutId, duration ? `duration=${duration}s` : '', changeMode !== 'replace' ? `mode=${changeMode}` : '');
|
|
161
165
|
try {
|
|
162
|
-
|
|
166
|
+
if (typeof data === 'object' && data.downloadRequired === true) {
|
|
167
|
+
log.info('changeLayout: downloadRequired — triggering collection first');
|
|
168
|
+
await this.player.collect();
|
|
169
|
+
}
|
|
170
|
+
await this.player.changeLayout(layoutId, { duration, changeMode });
|
|
163
171
|
log.debug('changeLayout completed successfully');
|
|
164
172
|
} catch (error) {
|
|
165
173
|
log.error('changeLayout failed:', error);
|
|
@@ -167,10 +175,17 @@ export class XmrWrapper {
|
|
|
167
175
|
});
|
|
168
176
|
|
|
169
177
|
// CMS command: Overlay Layout
|
|
170
|
-
|
|
171
|
-
|
|
178
|
+
// Payload may be a layoutId string or an object with { layoutId, duration, downloadRequired }
|
|
179
|
+
this.xmr.on('overlayLayout', async (data) => {
|
|
180
|
+
const layoutId = typeof data === 'object' ? (data.layoutId || data) : data;
|
|
181
|
+
const duration = typeof data === 'object' ? (parseInt(data.duration) || 0) : 0;
|
|
182
|
+
log.info('Received overlayLayout command:', layoutId, duration ? `duration=${duration}s` : '');
|
|
172
183
|
try {
|
|
173
|
-
|
|
184
|
+
if (typeof data === 'object' && data.downloadRequired === true) {
|
|
185
|
+
log.info('overlayLayout: downloadRequired — triggering collection first');
|
|
186
|
+
await this.player.collect();
|
|
187
|
+
}
|
|
188
|
+
await this.player.overlayLayout(layoutId, { duration });
|
|
174
189
|
log.debug('overlayLayout completed successfully');
|
|
175
190
|
} catch (error) {
|
|
176
191
|
log.error('overlayLayout failed:', error);
|
|
@@ -200,10 +215,14 @@ export class XmrWrapper {
|
|
|
200
215
|
});
|
|
201
216
|
|
|
202
217
|
// CMS command: Execute Command
|
|
218
|
+
// Resolve command from local display settings (from RegisterDisplay), not from XMR payload
|
|
203
219
|
this.xmr.on('commandAction', async (data) => {
|
|
204
|
-
|
|
220
|
+
const commandCode = data?.commandCode || data;
|
|
221
|
+
log.info('Received commandAction command:', commandCode);
|
|
205
222
|
try {
|
|
206
|
-
|
|
223
|
+
// Use local commands from RegisterDisplay (stored on player), not XMR payload commands
|
|
224
|
+
const localCommands = this.player.displayCommands || data?.commands;
|
|
225
|
+
await this.player.executeCommand(commandCode, localCommands);
|
|
207
226
|
log.debug('commandAction completed successfully');
|
|
208
227
|
} catch (error) {
|
|
209
228
|
log.error('commandAction failed:', error);
|
|
@@ -232,9 +251,9 @@ export class XmrWrapper {
|
|
|
232
251
|
}
|
|
233
252
|
});
|
|
234
253
|
|
|
235
|
-
// CMS command: Rekey (RSA key pair rotation)
|
|
236
|
-
this.xmr.on('
|
|
237
|
-
log.info('Received
|
|
254
|
+
// CMS command: Rekey (RSA key pair rotation) — spec event name is 'rekeyAction'
|
|
255
|
+
this.xmr.on('rekeyAction', async () => {
|
|
256
|
+
log.info('Received rekeyAction command - rotating RSA key pair');
|
|
238
257
|
try {
|
|
239
258
|
this.config.data.xmrPubKey = '';
|
|
240
259
|
this.config.data.xmrPrivKey = '';
|
package/src/xmr-wrapper.test.js
CHANGED
|
@@ -287,7 +287,7 @@ describe('XmrWrapper', () => {
|
|
|
287
287
|
xmrInstance.simulateCommand('changeLayout', 'layout-123');
|
|
288
288
|
await vi.runAllTimersAsync();
|
|
289
289
|
|
|
290
|
-
expect(mockPlayer.changeLayout).toHaveBeenCalledWith('layout-123');
|
|
290
|
+
expect(mockPlayer.changeLayout).toHaveBeenCalledWith('layout-123', { duration: 0, changeMode: 'replace' });
|
|
291
291
|
});
|
|
292
292
|
|
|
293
293
|
it('should handle changeLayout failure gracefully', async () => {
|
|
@@ -310,7 +310,7 @@ describe('XmrWrapper', () => {
|
|
|
310
310
|
mockConfig.data.xmrPubKey = 'old-pub-key';
|
|
311
311
|
mockConfig.data.xmrPrivKey = 'old-priv-key';
|
|
312
312
|
|
|
313
|
-
xmrInstance.simulateCommand('
|
|
313
|
+
xmrInstance.simulateCommand('rekeyAction');
|
|
314
314
|
await vi.runAllTimersAsync();
|
|
315
315
|
|
|
316
316
|
// Should clear old keys before regenerating
|
|
@@ -326,7 +326,7 @@ describe('XmrWrapper', () => {
|
|
|
326
326
|
mockConfig.ensureXmrKeyPair.mockRejectedValue(new Error('Key generation failed'));
|
|
327
327
|
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
328
328
|
|
|
329
|
-
xmrInstance.simulateCommand('
|
|
329
|
+
xmrInstance.simulateCommand('rekeyAction');
|
|
330
330
|
await vi.runAllTimersAsync();
|
|
331
331
|
|
|
332
332
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
@@ -435,7 +435,7 @@ describe('XmrWrapper', () => {
|
|
|
435
435
|
xmrInstance.simulateCommand('overlayLayout', 'overlay-layout-456');
|
|
436
436
|
await vi.runAllTimersAsync();
|
|
437
437
|
|
|
438
|
-
expect(mockPlayer.overlayLayout).toHaveBeenCalledWith('overlay-layout-456');
|
|
438
|
+
expect(mockPlayer.overlayLayout).toHaveBeenCalledWith('overlay-layout-456', { duration: 0 });
|
|
439
439
|
});
|
|
440
440
|
|
|
441
441
|
it('should handle overlayLayout failure gracefully', async () => {
|
|
@@ -745,7 +745,7 @@ describe('XmrWrapper', () => {
|
|
|
745
745
|
|
|
746
746
|
expect(mockPlayer.collect).toHaveBeenCalled();
|
|
747
747
|
expect(mockPlayer.captureScreenshot).toHaveBeenCalled();
|
|
748
|
-
expect(mockPlayer.changeLayout).toHaveBeenCalledWith('layout-123');
|
|
748
|
+
expect(mockPlayer.changeLayout).toHaveBeenCalledWith('layout-123', { duration: 0, changeMode: 'replace' });
|
|
749
749
|
});
|
|
750
750
|
|
|
751
751
|
it('should handle rapid connect/disconnect cycles', async () => {
|