Step 3 of the brief: the device now holds a ScaleLighting and pushes every
scale Live reports to the Apex 7, instead of only printing it.
The controller is created lazily and injected (start(max, { createLights })),
so the device stays testable with no Max and no hardware. Around the call:
lighting work is serialized on one queue so a burst of LOM changes cannot
interleave two POSTs, an unchanged scale is never re-sent, and a GameSense
that is missing or restarted is printed once rather than on every scale
change — the scale keeps being tracked so a later retry lands on the right one.
New messages: lights 0|1, retry, address <host:port>, shutdown. The patcher
gets boxes for them plus closebang -> shutdown, and the launcher blanks the
board on SIGTERM/SIGINT, so deleting the device hands lighting back to GG.
The test runner now supports async tests, since the lighting half is async.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
49 lines
1.6 KiB
JavaScript
49 lines
1.6 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Launcher for the `node.script` object — the same trick as bin/apex7-scale.js.
|
|
*
|
|
* The device logic is TypeScript (`src/max/device.ts`); this file stays plain
|
|
* CommonJS because Node for Max runs it on a Node version we do not control,
|
|
* with no loader and no build step of its own.
|
|
*
|
|
* `max-api` is required *here*, in the folder Node for Max resolves modules
|
|
* from, and handed to the compiled module — which keeps that module importable
|
|
* (and testable) outside of Max.
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const Max = require('max-api');
|
|
|
|
const compiled = path.join(__dirname, '..', 'dist', 'src', 'max', 'device.js');
|
|
|
|
if (!fs.existsSync(compiled)) {
|
|
Max.post(
|
|
'scale: not built yet — run `npm install` (or `npm run build`) in ' +
|
|
path.join(__dirname, '..'),
|
|
Max.POST_LEVELS.ERROR
|
|
);
|
|
} else {
|
|
const device = require(compiled).start(Max);
|
|
|
|
// Node for Max kills this process when the device is deleted or the Live set
|
|
// is closed. Blank the board on the way out so the Apex 7 goes back to its
|
|
// SteelSeries GG profile rather than sitting on the last scale. Best effort:
|
|
// if the signal never arrives, GameSense drops the effect ~15s after the
|
|
// heartbeat stops anyway. The patcher's `closebang` covers device deletion,
|
|
// which is the case Live does not signal.
|
|
let leaving = false;
|
|
const leave = () => {
|
|
if (leaving) return;
|
|
leaving = true;
|
|
device
|
|
.shutdown()
|
|
.catch(() => {})
|
|
.then(() => process.exit(0));
|
|
};
|
|
process.on('SIGTERM', leave);
|
|
process.on('SIGINT', leave);
|
|
}
|