jmri-client 4.2.0-beta.2 → 5.0.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/README.md +3 -1
- package/dist/cjs/index.js +2382 -31
- package/dist/esm/index.js +2333 -17
- package/docs/BROWSER.md +4 -4
- package/docs/MIGRATION.md +30 -1
- package/package.json +17 -18
- package/dist/cjs/client.js +0 -366
- package/dist/cjs/core/connection-state-manager.js +0 -84
- package/dist/cjs/core/heartbeat-manager.js +0 -79
- package/dist/cjs/core/index.js +0 -25
- package/dist/cjs/core/message-queue.js +0 -59
- package/dist/cjs/core/reconnection-manager.js +0 -97
- package/dist/cjs/core/websocket-adapter.js +0 -135
- package/dist/cjs/core/websocket-client.js +0 -388
- package/dist/cjs/managers/index.js +0 -25
- package/dist/cjs/managers/light-manager.js +0 -111
- package/dist/cjs/managers/power-manager.js +0 -90
- package/dist/cjs/managers/roster-manager.js +0 -118
- package/dist/cjs/managers/system-connections-manager.js +0 -28
- package/dist/cjs/managers/throttle-manager.js +0 -233
- package/dist/cjs/managers/turnout-manager.js +0 -111
- package/dist/cjs/mocks/index.js +0 -12
- package/dist/cjs/mocks/mock-data.js +0 -237
- package/dist/cjs/mocks/mock-response-manager.js +0 -290
- package/dist/cjs/types/client-options.js +0 -66
- package/dist/cjs/types/events.js +0 -16
- package/dist/cjs/types/index.js +0 -23
- package/dist/cjs/types/jmri-messages.js +0 -95
- package/dist/cjs/types/throttle.js +0 -19
- package/dist/cjs/utils/exponential-backoff.js +0 -40
- package/dist/cjs/utils/index.js +0 -21
- package/dist/cjs/utils/message-id.js +0 -40
- package/dist/esm/client.js +0 -362
- package/dist/esm/core/connection-state-manager.js +0 -80
- package/dist/esm/core/heartbeat-manager.js +0 -75
- package/dist/esm/core/index.js +0 -9
- package/dist/esm/core/message-queue.js +0 -55
- package/dist/esm/core/reconnection-manager.js +0 -93
- package/dist/esm/core/websocket-adapter.js +0 -98
- package/dist/esm/core/websocket-client.js +0 -384
- package/dist/esm/managers/index.js +0 -9
- package/dist/esm/managers/light-manager.js +0 -107
- package/dist/esm/managers/power-manager.js +0 -86
- package/dist/esm/managers/roster-manager.js +0 -114
- package/dist/esm/managers/system-connections-manager.js +0 -24
- package/dist/esm/managers/throttle-manager.js +0 -229
- package/dist/esm/managers/turnout-manager.js +0 -107
- package/dist/esm/mocks/index.js +0 -6
- package/dist/esm/mocks/mock-data.js +0 -234
- package/dist/esm/mocks/mock-response-manager.js +0 -286
- package/dist/esm/types/client-options.js +0 -62
- package/dist/esm/types/events.js +0 -13
- package/dist/esm/types/index.js +0 -7
- package/dist/esm/types/jmri-messages.js +0 -89
- package/dist/esm/types/throttle.js +0 -15
- package/dist/esm/utils/exponential-backoff.js +0 -36
- package/dist/esm/utils/index.js +0 -5
- package/dist/esm/utils/message-id.js +0 -36
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Turnout (switch) manager
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.TurnoutManager = void 0;
|
|
7
|
-
const eventemitter3_1 = require("eventemitter3");
|
|
8
|
-
const jmri_messages_js_1 = require("../types/jmri-messages.js");
|
|
9
|
-
/**
|
|
10
|
-
* Manages JMRI turnout (track switch) state
|
|
11
|
-
*/
|
|
12
|
-
class TurnoutManager extends eventemitter3_1.EventEmitter {
|
|
13
|
-
constructor(client) {
|
|
14
|
-
super();
|
|
15
|
-
this.turnouts = new Map();
|
|
16
|
-
this.client = client;
|
|
17
|
-
this.client.on('update', (message) => {
|
|
18
|
-
if (message.type === 'turnout') {
|
|
19
|
-
this.handleTurnoutUpdate(message);
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Get the current state of a turnout.
|
|
25
|
-
* Also registers a server-side listener so subsequent changes are pushed.
|
|
26
|
-
*/
|
|
27
|
-
async getTurnout(name) {
|
|
28
|
-
const message = {
|
|
29
|
-
type: 'turnout',
|
|
30
|
-
data: { name }
|
|
31
|
-
};
|
|
32
|
-
const response = await this.client.request(message);
|
|
33
|
-
const state = response.data?.state ?? jmri_messages_js_1.TurnoutState.UNKNOWN;
|
|
34
|
-
this.turnouts.set(name, state);
|
|
35
|
-
return state;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Set a turnout to the given state
|
|
39
|
-
*/
|
|
40
|
-
async setTurnout(name, state) {
|
|
41
|
-
const message = {
|
|
42
|
-
type: 'turnout',
|
|
43
|
-
method: 'post',
|
|
44
|
-
data: { name, state }
|
|
45
|
-
};
|
|
46
|
-
await this.client.request(message);
|
|
47
|
-
const oldState = this.turnouts.get(name);
|
|
48
|
-
this.turnouts.set(name, state);
|
|
49
|
-
if (oldState !== state) {
|
|
50
|
-
this.emit('turnout:changed', name, state);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Throw a turnout (diverging route)
|
|
55
|
-
*/
|
|
56
|
-
async throwTurnout(name) {
|
|
57
|
-
return this.setTurnout(name, jmri_messages_js_1.TurnoutState.THROWN);
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Close a turnout (straight through / normal)
|
|
61
|
-
*/
|
|
62
|
-
async closeTurnout(name) {
|
|
63
|
-
return this.setTurnout(name, jmri_messages_js_1.TurnoutState.CLOSED);
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* List all turnouts known to JMRI
|
|
67
|
-
*/
|
|
68
|
-
async listTurnouts() {
|
|
69
|
-
const message = {
|
|
70
|
-
type: 'turnout',
|
|
71
|
-
method: 'list'
|
|
72
|
-
};
|
|
73
|
-
const response = await this.client.request(message);
|
|
74
|
-
const entries = Array.isArray(response?.data)
|
|
75
|
-
? response.data.map((r) => r.data ?? r)
|
|
76
|
-
: [];
|
|
77
|
-
for (const entry of entries) {
|
|
78
|
-
if (entry.name && entry.state !== undefined) {
|
|
79
|
-
this.turnouts.set(entry.name, entry.state);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return entries;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Get cached turnout state without a network request
|
|
86
|
-
*/
|
|
87
|
-
getTurnoutState(name) {
|
|
88
|
-
return this.turnouts.get(name);
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Get all cached turnout states
|
|
92
|
-
*/
|
|
93
|
-
getCachedTurnouts() {
|
|
94
|
-
return new Map(this.turnouts);
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Handle unsolicited turnout state updates from JMRI
|
|
98
|
-
*/
|
|
99
|
-
handleTurnoutUpdate(message) {
|
|
100
|
-
const name = message.data?.name;
|
|
101
|
-
const state = message.data?.state;
|
|
102
|
-
if (!name || state === undefined)
|
|
103
|
-
return;
|
|
104
|
-
const oldState = this.turnouts.get(name);
|
|
105
|
-
this.turnouts.set(name, state);
|
|
106
|
-
if (oldState !== state) {
|
|
107
|
-
this.emit('turnout:changed', name, state);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
exports.TurnoutManager = TurnoutManager;
|
package/dist/cjs/mocks/index.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Mock system exports
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.mockData = exports.mockResponseManager = exports.MockResponseManager = void 0;
|
|
7
|
-
var mock_response_manager_js_1 = require("./mock-response-manager.js");
|
|
8
|
-
Object.defineProperty(exports, "MockResponseManager", { enumerable: true, get: function () { return mock_response_manager_js_1.MockResponseManager; } });
|
|
9
|
-
Object.defineProperty(exports, "mockResponseManager", { enumerable: true, get: function () { return mock_response_manager_js_1.mockResponseManager; } });
|
|
10
|
-
// Re-export mock data for direct access if needed
|
|
11
|
-
var mock_data_js_1 = require("./mock-data.js");
|
|
12
|
-
Object.defineProperty(exports, "mockData", { enumerable: true, get: function () { return mock_data_js_1.mockData; } });
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Mock data for JMRI responses
|
|
4
|
-
* Used for testing and demo mode
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.mockData = void 0;
|
|
8
|
-
exports.mockData = {
|
|
9
|
-
"hello": {
|
|
10
|
-
"type": "hello",
|
|
11
|
-
"data": {
|
|
12
|
-
"JMRI": "5.9.2",
|
|
13
|
-
"json": "5.0",
|
|
14
|
-
"version": "v5",
|
|
15
|
-
"heartbeat": 13500,
|
|
16
|
-
"railroad": "Demo Railroad",
|
|
17
|
-
"node": "jmri-server",
|
|
18
|
-
"activeProfile": "Demo Profile"
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
"power": {
|
|
22
|
-
"get": {
|
|
23
|
-
"on": {
|
|
24
|
-
"type": "power",
|
|
25
|
-
"data": {
|
|
26
|
-
"state": 2
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
"off": {
|
|
30
|
-
"type": "power",
|
|
31
|
-
"data": {
|
|
32
|
-
"state": 4
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
"post": {
|
|
37
|
-
"success": {
|
|
38
|
-
"type": "power",
|
|
39
|
-
"data": {
|
|
40
|
-
"state": 2
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
"roster": {
|
|
46
|
-
"list": [
|
|
47
|
-
{
|
|
48
|
-
"type": "rosterEntry",
|
|
49
|
-
"data": {
|
|
50
|
-
"name": "CSX754",
|
|
51
|
-
"address": "754",
|
|
52
|
-
"isLongAddress": true,
|
|
53
|
-
"road": "CSX",
|
|
54
|
-
"number": "754",
|
|
55
|
-
"mfg": "Athearn",
|
|
56
|
-
"decoderModel": "DH163D",
|
|
57
|
-
"decoderFamily": "Digitrax DH163",
|
|
58
|
-
"model": "GP38-2",
|
|
59
|
-
"comment": "Blue and yellow scheme",
|
|
60
|
-
"maxSpeedPct": 100,
|
|
61
|
-
"image": null,
|
|
62
|
-
"icon": "/roster/CSX754/icon",
|
|
63
|
-
"shuntingFunction": "",
|
|
64
|
-
"owner": "",
|
|
65
|
-
"dateModified": "2026-02-10T00:00:00.000+00:00",
|
|
66
|
-
"functionKeys": [
|
|
67
|
-
{ "name": "F0", "label": "Headlight", "lockable": true, "icon": null, "selectedIcon": null },
|
|
68
|
-
{ "name": "F1", "label": "Bell", "lockable": true, "icon": null, "selectedIcon": null },
|
|
69
|
-
{ "name": "F2", "label": "Horn", "lockable": false, "icon": null, "selectedIcon": null },
|
|
70
|
-
{ "name": "F3", "label": null, "lockable": false, "icon": null, "selectedIcon": null },
|
|
71
|
-
{ "name": "F4", "label": "Dynamic Brake", "lockable": true, "icon": null, "selectedIcon": null },
|
|
72
|
-
{ "name": "F5", "label": null, "lockable": false, "icon": null, "selectedIcon": null }
|
|
73
|
-
],
|
|
74
|
-
"attributes": [],
|
|
75
|
-
"rosterGroups": []
|
|
76
|
-
},
|
|
77
|
-
"id": 1
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
"type": "rosterEntry",
|
|
81
|
-
"data": {
|
|
82
|
-
"name": "UP3985",
|
|
83
|
-
"address": "3985",
|
|
84
|
-
"isLongAddress": true,
|
|
85
|
-
"road": "Union Pacific",
|
|
86
|
-
"number": "3985",
|
|
87
|
-
"mfg": "Rivarossi",
|
|
88
|
-
"decoderModel": "Sound decoder",
|
|
89
|
-
"decoderFamily": "ESU LokSound",
|
|
90
|
-
"model": "Challenger 4-6-6-4",
|
|
91
|
-
"comment": "Steam locomotive",
|
|
92
|
-
"maxSpeedPct": 100,
|
|
93
|
-
"image": null,
|
|
94
|
-
"icon": "/roster/UP3985/icon",
|
|
95
|
-
"shuntingFunction": "",
|
|
96
|
-
"owner": "",
|
|
97
|
-
"dateModified": "2026-02-10T00:00:00.000+00:00",
|
|
98
|
-
"functionKeys": [
|
|
99
|
-
{ "name": "F0", "label": "Headlight", "lockable": true, "icon": null, "selectedIcon": null },
|
|
100
|
-
{ "name": "F1", "label": "Bell", "lockable": true, "icon": null, "selectedIcon": null },
|
|
101
|
-
{ "name": "F2", "label": "Whistle", "lockable": false, "icon": null, "selectedIcon": null },
|
|
102
|
-
{ "name": "F3", "label": "Steam", "lockable": true, "icon": null, "selectedIcon": null },
|
|
103
|
-
{ "name": "F4", "label": null, "lockable": false, "icon": null, "selectedIcon": null }
|
|
104
|
-
],
|
|
105
|
-
"attributes": [],
|
|
106
|
-
"rosterGroups": []
|
|
107
|
-
},
|
|
108
|
-
"id": 2
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
"type": "rosterEntry",
|
|
112
|
-
"data": {
|
|
113
|
-
"name": "BNSF5240",
|
|
114
|
-
"address": "5240",
|
|
115
|
-
"isLongAddress": true,
|
|
116
|
-
"road": "BNSF",
|
|
117
|
-
"number": "5240",
|
|
118
|
-
"mfg": "Kato",
|
|
119
|
-
"decoderModel": "DCC Sound",
|
|
120
|
-
"decoderFamily": "Kato",
|
|
121
|
-
"model": "SD40-2",
|
|
122
|
-
"comment": "Heritage II paint",
|
|
123
|
-
"maxSpeedPct": 100,
|
|
124
|
-
"image": null,
|
|
125
|
-
"icon": "/roster/BNSF5240/icon",
|
|
126
|
-
"shuntingFunction": "",
|
|
127
|
-
"owner": "",
|
|
128
|
-
"dateModified": "2026-02-10T00:00:00.000+00:00",
|
|
129
|
-
"functionKeys": [
|
|
130
|
-
{ "name": "F0", "label": "Headlight", "lockable": true, "icon": null, "selectedIcon": null },
|
|
131
|
-
{ "name": "F1", "label": "Bell", "lockable": true, "icon": null, "selectedIcon": null },
|
|
132
|
-
{ "name": "F2", "label": "Horn", "lockable": false, "icon": null, "selectedIcon": null },
|
|
133
|
-
{ "name": "F3", "label": "Dynamic Brake", "lockable": true, "icon": null, "selectedIcon": null },
|
|
134
|
-
{ "name": "F4", "label": null, "lockable": false, "icon": null, "selectedIcon": null },
|
|
135
|
-
{ "name": "F5", "label": "Mars Light", "lockable": true, "icon": null, "selectedIcon": null }
|
|
136
|
-
],
|
|
137
|
-
"attributes": [],
|
|
138
|
-
"rosterGroups": []
|
|
139
|
-
},
|
|
140
|
-
"id": 3
|
|
141
|
-
}
|
|
142
|
-
]
|
|
143
|
-
},
|
|
144
|
-
"throttle": {
|
|
145
|
-
"acquire": {
|
|
146
|
-
"success": {
|
|
147
|
-
"type": "throttle",
|
|
148
|
-
"data": {
|
|
149
|
-
"throttle": "{THROTTLE_ID}",
|
|
150
|
-
"address": "{ADDRESS}",
|
|
151
|
-
"speed": 0,
|
|
152
|
-
"forward": true,
|
|
153
|
-
"F0": false,
|
|
154
|
-
"F1": false,
|
|
155
|
-
"F2": false,
|
|
156
|
-
"F3": false,
|
|
157
|
-
"F4": false
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
"release": {
|
|
162
|
-
"success": {
|
|
163
|
-
"type": "throttle",
|
|
164
|
-
"data": {}
|
|
165
|
-
}
|
|
166
|
-
},
|
|
167
|
-
"control": {
|
|
168
|
-
"speed": {
|
|
169
|
-
"type": "throttle",
|
|
170
|
-
"data": {
|
|
171
|
-
"throttle": "{THROTTLE_ID}",
|
|
172
|
-
"speed": "{SPEED}"
|
|
173
|
-
}
|
|
174
|
-
},
|
|
175
|
-
"direction": {
|
|
176
|
-
"type": "throttle",
|
|
177
|
-
"data": {
|
|
178
|
-
"throttle": "{THROTTLE_ID}",
|
|
179
|
-
"forward": "{FORWARD}"
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
"function": {
|
|
183
|
-
"type": "throttle",
|
|
184
|
-
"data": {
|
|
185
|
-
"throttle": "{THROTTLE_ID}",
|
|
186
|
-
"{FUNCTION}": "{VALUE}"
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
},
|
|
191
|
-
"light": {
|
|
192
|
-
"list": [
|
|
193
|
-
{ "type": "light", "data": { "name": "IL1", "userName": "Yard Light", "comment": null, "properties": [], "state": 4 } },
|
|
194
|
-
{ "type": "light", "data": { "name": "IL2", "userName": "Platform Light", "comment": null, "properties": [], "state": 4 } },
|
|
195
|
-
{ "type": "light", "data": { "name": "IL3", "userName": "Signal Lamp", "comment": null, "properties": [], "state": 2 } }
|
|
196
|
-
]
|
|
197
|
-
},
|
|
198
|
-
"turnout": {
|
|
199
|
-
"list": [
|
|
200
|
-
{ "type": "turnout", "data": { "name": "LT1", "userName": "Main Diverge", "state": 2 } },
|
|
201
|
-
{ "type": "turnout", "data": { "name": "LT2", "userName": "Yard Lead", "state": 2 } },
|
|
202
|
-
{ "type": "turnout", "data": { "name": "LT3", "userName": "Siding Entry", "state": 4 } }
|
|
203
|
-
]
|
|
204
|
-
},
|
|
205
|
-
"ping": {
|
|
206
|
-
"type": "ping"
|
|
207
|
-
},
|
|
208
|
-
"pong": {
|
|
209
|
-
"type": "pong"
|
|
210
|
-
},
|
|
211
|
-
"goodbye": {
|
|
212
|
-
"type": "goodbye"
|
|
213
|
-
},
|
|
214
|
-
"error": {
|
|
215
|
-
"throttleNotFound": {
|
|
216
|
-
"type": "error",
|
|
217
|
-
"data": {
|
|
218
|
-
"code": 404,
|
|
219
|
-
"message": "Throttle not found"
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
"invalidSpeed": {
|
|
223
|
-
"type": "error",
|
|
224
|
-
"data": {
|
|
225
|
-
"code": 400,
|
|
226
|
-
"message": "Invalid speed value"
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
"connectionError": {
|
|
230
|
-
"type": "error",
|
|
231
|
-
"data": {
|
|
232
|
-
"code": 500,
|
|
233
|
-
"message": "Connection error"
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
};
|
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Mock Response Manager
|
|
4
|
-
* Generates mock JMRI responses for testing and demo purposes
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.mockResponseManager = exports.MockResponseManager = void 0;
|
|
8
|
-
const jmri_messages_js_1 = require("../types/jmri-messages.js");
|
|
9
|
-
const mock_data_js_1 = require("./mock-data.js");
|
|
10
|
-
/**
|
|
11
|
-
* Manages mock responses for JMRI protocol
|
|
12
|
-
*/
|
|
13
|
-
class MockResponseManager {
|
|
14
|
-
constructor(options = {}) {
|
|
15
|
-
this.throttles = new Map();
|
|
16
|
-
this.lights = new Map([
|
|
17
|
-
['IL1', jmri_messages_js_1.LightState.OFF],
|
|
18
|
-
['IL2', jmri_messages_js_1.LightState.OFF],
|
|
19
|
-
['IL3', jmri_messages_js_1.LightState.ON]
|
|
20
|
-
]);
|
|
21
|
-
this.turnouts = new Map([
|
|
22
|
-
['LT1', jmri_messages_js_1.TurnoutState.CLOSED],
|
|
23
|
-
['LT2', jmri_messages_js_1.TurnoutState.CLOSED],
|
|
24
|
-
['LT3', jmri_messages_js_1.TurnoutState.THROWN]
|
|
25
|
-
]);
|
|
26
|
-
this.responseDelay = options.responseDelay ?? 50;
|
|
27
|
-
this.powerState = options.initialPowerState ?? jmri_messages_js_1.PowerState.OFF;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Get a mock response for a given message
|
|
31
|
-
*/
|
|
32
|
-
async getMockResponse(message) {
|
|
33
|
-
// Simulate network delay
|
|
34
|
-
if (this.responseDelay > 0) {
|
|
35
|
-
await this.delay(this.responseDelay);
|
|
36
|
-
}
|
|
37
|
-
// Route to appropriate handler based on message type
|
|
38
|
-
switch (message.type) {
|
|
39
|
-
case 'hello':
|
|
40
|
-
return this.getHelloResponse();
|
|
41
|
-
case 'power':
|
|
42
|
-
return this.getPowerResponse(message);
|
|
43
|
-
case 'roster':
|
|
44
|
-
return this.getRosterResponse(message);
|
|
45
|
-
case 'throttle':
|
|
46
|
-
return this.getThrottleResponse(message);
|
|
47
|
-
case 'light':
|
|
48
|
-
return this.getLightResponse(message);
|
|
49
|
-
case 'turnout':
|
|
50
|
-
return this.getTurnoutResponse(message);
|
|
51
|
-
case 'ping':
|
|
52
|
-
return this.getPingResponse();
|
|
53
|
-
case 'goodbye':
|
|
54
|
-
return this.getGoodbyeResponse();
|
|
55
|
-
default:
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Get hello response (connection establishment)
|
|
61
|
-
*/
|
|
62
|
-
getHelloResponse() {
|
|
63
|
-
return JSON.parse(JSON.stringify(mock_data_js_1.mockData.hello));
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Get power response
|
|
67
|
-
*/
|
|
68
|
-
getPowerResponse(message) {
|
|
69
|
-
// Handle power state change
|
|
70
|
-
if (message.data?.state !== undefined) {
|
|
71
|
-
this.powerState = message.data.state;
|
|
72
|
-
return {
|
|
73
|
-
type: 'power',
|
|
74
|
-
data: { state: this.powerState }
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
// Return current power state
|
|
78
|
-
return {
|
|
79
|
-
type: 'power',
|
|
80
|
-
data: { state: this.powerState }
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Get roster response
|
|
85
|
-
*/
|
|
86
|
-
getRosterResponse(message) {
|
|
87
|
-
if (message.type === 'roster' && message.method === 'list') {
|
|
88
|
-
return {
|
|
89
|
-
type: 'roster',
|
|
90
|
-
data: JSON.parse(JSON.stringify(mock_data_js_1.mockData.roster.list))
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
type: 'roster',
|
|
95
|
-
data: []
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Get throttle response
|
|
100
|
-
*/
|
|
101
|
-
getThrottleResponse(message) {
|
|
102
|
-
const data = message.data || {};
|
|
103
|
-
// Acquire throttle
|
|
104
|
-
if (data.address !== undefined && !data.throttle) {
|
|
105
|
-
const throttleId = data.name || `MOCK-${data.address}`;
|
|
106
|
-
const throttleState = {
|
|
107
|
-
throttle: throttleId,
|
|
108
|
-
address: data.address,
|
|
109
|
-
speed: 0,
|
|
110
|
-
forward: true,
|
|
111
|
-
F0: false,
|
|
112
|
-
F1: false,
|
|
113
|
-
F2: false,
|
|
114
|
-
F3: false,
|
|
115
|
-
F4: false
|
|
116
|
-
};
|
|
117
|
-
this.throttles.set(throttleId, throttleState);
|
|
118
|
-
return {
|
|
119
|
-
type: 'throttle',
|
|
120
|
-
data: { ...throttleState }
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
// Release throttle
|
|
124
|
-
if (data.release !== undefined && data.throttle) {
|
|
125
|
-
this.throttles.delete(data.throttle);
|
|
126
|
-
return {
|
|
127
|
-
type: 'throttle',
|
|
128
|
-
data: {}
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
// Throttle control (speed, direction, functions)
|
|
132
|
-
if (data.throttle) {
|
|
133
|
-
const throttleState = this.throttles.get(data.throttle);
|
|
134
|
-
if (!throttleState) {
|
|
135
|
-
// Throttle not found - this shouldn't normally happen in mock mode
|
|
136
|
-
// but we'll create it on the fly
|
|
137
|
-
const newState = {
|
|
138
|
-
throttle: data.throttle,
|
|
139
|
-
address: 0,
|
|
140
|
-
speed: 0,
|
|
141
|
-
forward: true
|
|
142
|
-
};
|
|
143
|
-
this.throttles.set(data.throttle, newState);
|
|
144
|
-
return {
|
|
145
|
-
type: 'throttle',
|
|
146
|
-
data: { ...newState }
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
// Update throttle state
|
|
150
|
-
if (data.speed !== undefined) {
|
|
151
|
-
throttleState.speed = data.speed;
|
|
152
|
-
}
|
|
153
|
-
if (data.forward !== undefined) {
|
|
154
|
-
throttleState.forward = data.forward;
|
|
155
|
-
}
|
|
156
|
-
// Update function keys
|
|
157
|
-
for (let i = 0; i <= 28; i++) {
|
|
158
|
-
const key = `F${i}`;
|
|
159
|
-
if (data[key] !== undefined) {
|
|
160
|
-
throttleState[key] = data[key];
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
// Return updated state (no response for throttle control commands)
|
|
164
|
-
return {
|
|
165
|
-
type: 'throttle',
|
|
166
|
-
data: {}
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
return {
|
|
170
|
-
type: 'throttle',
|
|
171
|
-
data: {}
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Get light response
|
|
176
|
-
*/
|
|
177
|
-
getLightResponse(message) {
|
|
178
|
-
// List all lights
|
|
179
|
-
if (message.method === 'list') {
|
|
180
|
-
return {
|
|
181
|
-
type: 'light',
|
|
182
|
-
data: JSON.parse(JSON.stringify(mock_data_js_1.mockData.light.list))
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
const name = message.data?.name;
|
|
186
|
-
if (!name) {
|
|
187
|
-
return { type: 'light', data: { name: '', state: jmri_messages_js_1.LightState.UNKNOWN } };
|
|
188
|
-
}
|
|
189
|
-
// Set light state
|
|
190
|
-
if (message.method === 'post' && message.data?.state !== undefined) {
|
|
191
|
-
this.lights.set(name, message.data.state);
|
|
192
|
-
}
|
|
193
|
-
// Get or confirm current state
|
|
194
|
-
const state = this.lights.get(name) ?? jmri_messages_js_1.LightState.UNKNOWN;
|
|
195
|
-
return { type: 'light', data: { name, state } };
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Get turnout response
|
|
199
|
-
*/
|
|
200
|
-
getTurnoutResponse(message) {
|
|
201
|
-
// List all turnouts
|
|
202
|
-
if (message.method === 'list') {
|
|
203
|
-
return {
|
|
204
|
-
type: 'turnout',
|
|
205
|
-
data: JSON.parse(JSON.stringify(mock_data_js_1.mockData.turnout.list))
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
const name = message.data?.name;
|
|
209
|
-
if (!name) {
|
|
210
|
-
return { type: 'turnout', data: { name: '', state: jmri_messages_js_1.TurnoutState.UNKNOWN } };
|
|
211
|
-
}
|
|
212
|
-
// Set turnout state
|
|
213
|
-
if (message.method === 'post' && message.data?.state !== undefined) {
|
|
214
|
-
this.turnouts.set(name, message.data.state);
|
|
215
|
-
}
|
|
216
|
-
// Get or confirm current state
|
|
217
|
-
const state = this.turnouts.get(name) ?? jmri_messages_js_1.TurnoutState.UNKNOWN;
|
|
218
|
-
return { type: 'turnout', data: { name, state } };
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Get ping response (pong)
|
|
222
|
-
*/
|
|
223
|
-
getPingResponse() {
|
|
224
|
-
return JSON.parse(JSON.stringify(mock_data_js_1.mockData.pong));
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Get goodbye response
|
|
228
|
-
*/
|
|
229
|
-
getGoodbyeResponse() {
|
|
230
|
-
return JSON.parse(JSON.stringify(mock_data_js_1.mockData.goodbye));
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Get current power state
|
|
234
|
-
*/
|
|
235
|
-
getPowerState() {
|
|
236
|
-
return this.powerState;
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Set power state (for testing)
|
|
240
|
-
*/
|
|
241
|
-
setPowerState(state) {
|
|
242
|
-
this.powerState = state;
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Get all throttles (for testing)
|
|
246
|
-
*/
|
|
247
|
-
getThrottles() {
|
|
248
|
-
return this.throttles;
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Get all light states (for testing)
|
|
252
|
-
*/
|
|
253
|
-
getLights() {
|
|
254
|
-
return this.lights;
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Get all turnout states (for testing)
|
|
258
|
-
*/
|
|
259
|
-
getTurnouts() {
|
|
260
|
-
return this.turnouts;
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Reset all state (for testing)
|
|
264
|
-
*/
|
|
265
|
-
reset() {
|
|
266
|
-
this.powerState = jmri_messages_js_1.PowerState.OFF;
|
|
267
|
-
this.throttles.clear();
|
|
268
|
-
this.lights = new Map([
|
|
269
|
-
['IL1', jmri_messages_js_1.LightState.OFF],
|
|
270
|
-
['IL2', jmri_messages_js_1.LightState.OFF],
|
|
271
|
-
['IL3', jmri_messages_js_1.LightState.ON]
|
|
272
|
-
]);
|
|
273
|
-
this.turnouts = new Map([
|
|
274
|
-
['LT1', jmri_messages_js_1.TurnoutState.CLOSED],
|
|
275
|
-
['LT2', jmri_messages_js_1.TurnoutState.CLOSED],
|
|
276
|
-
['LT3', jmri_messages_js_1.TurnoutState.THROWN]
|
|
277
|
-
]);
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Delay helper
|
|
281
|
-
*/
|
|
282
|
-
delay(ms) {
|
|
283
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
exports.MockResponseManager = MockResponseManager;
|
|
287
|
-
/**
|
|
288
|
-
* Singleton instance for shared use across tests
|
|
289
|
-
*/
|
|
290
|
-
exports.mockResponseManager = new MockResponseManager({ responseDelay: 0 });
|