secutorpro commited on
Commit
606de33
·
verified ·
1 Parent(s): 861754e

fleet simulator

Browse files
Files changed (1) hide show
  1. server/simulator.js +23 -23
server/simulator.js CHANGED
@@ -1,13 +1,12 @@
1
- // Simulated fleet: drives GPS updates, an SOS and PTT floor requests against a
2
- // running server, so you can watch the console move without real devices.
3
- //
4
- // cd server && npm run sim
5
- // SERVER_URL=http://localhost:8080 SIM_CENTER=48.8566,2.3522 node simulator.js
6
  import WebSocket from 'ws';
7
 
8
  const BASE = process.env.SERVER_URL || 'http://localhost:8080';
9
- const N = Number(process.env.SIM_UNITS) || 5;
10
- const [clat, clng] = (process.env.SIM_CENTER || '48.8566,2.3522').split(',').map(Number);
 
11
 
12
  async function main() {
13
  const login = await fetch(`${BASE}/api/login`, {
@@ -17,23 +16,23 @@ async function main() {
17
  });
18
  if (!login.ok) throw new Error(`login failed: ${login.status}`);
19
  const { token } = await login.json();
20
- const headers = { authorization: `Bearer ${token}`, 'content-type': 'application/json' };
21
 
22
- const groups = await (await fetch(`${BASE}/api/groups`, { headers })).json();
23
- if (!groups.length) throw new Error('no talkgroups exist');
24
  const groupId = groups[0].id;
25
 
26
- const existing = await (await fetch(`${BASE}/api/members`, { headers })).json();
27
  const units = [];
28
  for (let i = 1; i <= N; i++) {
29
  const deviceId = `sim-${i}`;
30
  let m = existing.find((x) => x.device_id === deviceId);
31
  if (!m) {
32
  const res = await fetch(`${BASE}/api/members`, {
33
- method: 'POST', headers,
 
34
  body: JSON.stringify({ name: `SIM Unit ${i}`, callsign: `SIM-${i}`, device_id: deviceId, group_id: groupId }),
35
  });
36
- if (!res.ok) throw new Error(`could not create ${deviceId}: ${await res.text()}`);
37
  m = await res.json();
38
  }
39
  units.push(m);
@@ -41,19 +40,21 @@ async function main() {
41
 
42
  const states = units.map((m) => ({
43
  m,
44
- lat: clat + (Math.random() - 0.5) * 0.08,
45
- lng: clng + (Math.random() - 0.5) * 0.12,
46
- battery: 60 + Math.floor(Math.random() * 40),
47
  ws: null,
 
 
 
48
  }));
49
 
50
  for (const s of states) {
51
- const ws = new WebSocket(BASE.replace(/^http/, 'ws') + '/ws');
52
  ws.on('open', () => ws.send(JSON.stringify({ type: 'auth', token, memberId: s.m.id })));
53
  ws.on('message', (d) => {
54
  const msg = JSON.parse(d.toString());
55
- if (msg.type === 'ptt_denied') console.log(`[${s.m.name}] PTT denied — floor held by ${msg.holder}`);
 
56
  });
 
57
  s.ws = ws;
58
  }
59
 
@@ -68,19 +69,18 @@ async function main() {
68
  }
69
  }, 5000);
70
 
71
- // one unit raises an SOS shortly after start
72
  setTimeout(() => {
73
  const s = states[0];
74
  if (s.ws.readyState === WebSocket.OPEN) {
75
  s.ws.send(JSON.stringify({ type: 'sos' }));
76
- console.log(`[${s.m.name}] SOS sent`);
77
  }
78
  }, 25000);
79
 
80
- // units take turns requesting the PTT floor
81
  let turn = 0;
82
  setInterval(() => {
83
- const s = states[turn++ % states.length];
 
84
  if (s.ws.readyState !== WebSocket.OPEN) return;
85
  s.ws.send(JSON.stringify({ type: 'ptt_start' }));
86
  setTimeout(() => {
@@ -88,7 +88,7 @@ async function main() {
88
  }, 4000);
89
  }, 30000);
90
 
91
- console.log(`simulating ${N} units against ${BASE} — Ctrl+C to stop`);
92
  }
93
 
94
  main().catch((e) => { console.error(e); process.exit(1); });
 
1
+ // Simulated fleet for the dispatch console.
2
+ // Usage (server running on :8080): node simulator.js
3
+ // Env: SERVER_URL, SIM_UNITS, SIM_CENTER="lat,lng", ADMIN_USER, ADMIN_PASS
 
 
4
  import WebSocket from 'ws';
5
 
6
  const BASE = process.env.SERVER_URL || 'http://localhost:8080';
7
+ const WS_URL = BASE.replace(/^http/, 'ws') + '/ws';
8
+ const N = Number(process.env.SIM_UNITS || 5);
9
+ const CENTER = (process.env.SIM_CENTER || '48.8566,2.3522').split(',').map(Number);
10
 
11
  async function main() {
12
  const login = await fetch(`${BASE}/api/login`, {
 
16
  });
17
  if (!login.ok) throw new Error(`login failed: ${login.status}`);
18
  const { token } = await login.json();
19
+ const auth = { authorization: `Bearer ${token}`, 'content-type': 'application/json' };
20
 
21
+ const groups = await (await fetch(`${BASE}/api/groups`, { headers: auth })).json();
22
+ if (!groups.length) throw new Error('no talkgroups exist — create one first');
23
  const groupId = groups[0].id;
24
 
25
+ const existing = await (await fetch(`${BASE}/api/members`, { headers: auth })).json();
26
  const units = [];
27
  for (let i = 1; i <= N; i++) {
28
  const deviceId = `sim-${i}`;
29
  let m = existing.find((x) => x.device_id === deviceId);
30
  if (!m) {
31
  const res = await fetch(`${BASE}/api/members`, {
32
+ method: 'POST',
33
+ headers: auth,
34
  body: JSON.stringify({ name: `SIM Unit ${i}`, callsign: `SIM-${i}`, device_id: deviceId, group_id: groupId }),
35
  });
 
36
  m = await res.json();
37
  }
38
  units.push(m);
 
40
 
41
  const states = units.map((m) => ({
42
  m,
 
 
 
43
  ws: null,
44
+ lat: CENTER[0] + (Math.random() - 0.5) * 0.08,
45
+ lng: CENTER[1] + (Math.random() - 0.5) * 0.12,
46
+ battery: 60 + Math.floor(Math.random() * 40),
47
  }));
48
 
49
  for (const s of states) {
50
+ const ws = new WebSocket(WS_URL);
51
  ws.on('open', () => ws.send(JSON.stringify({ type: 'auth', token, memberId: s.m.id })));
52
  ws.on('message', (d) => {
53
  const msg = JSON.parse(d.toString());
54
+ if (msg.type === 'ptt_denied') console.log(`[${s.m.name}] ptt denied (held by ${msg.holder})`);
55
+ if (msg.type === 'floor' && msg.memberId === s.m.id) console.log(`[${s.m.name}] holding the floor on group ${msg.groupId}`);
56
  });
57
+ ws.on('error', (e) => console.error(`[${s.m.name}] ws error:`, e.message));
58
  s.ws = ws;
59
  }
60
 
 
69
  }
70
  }, 5000);
71
 
 
72
  setTimeout(() => {
73
  const s = states[0];
74
  if (s.ws.readyState === WebSocket.OPEN) {
75
  s.ws.send(JSON.stringify({ type: 'sos' }));
76
+ console.log('[SIM Unit 1] SOS sent');
77
  }
78
  }, 25000);
79
 
 
80
  let turn = 0;
81
  setInterval(() => {
82
+ const s = states[turn % states.length];
83
+ turn++;
84
  if (s.ws.readyState !== WebSocket.OPEN) return;
85
  s.ws.send(JSON.stringify({ type: 'ptt_start' }));
86
  setTimeout(() => {
 
88
  }, 4000);
89
  }, 30000);
90
 
91
+ console.log(`Simulating ${N} units against ${BASE} — Ctrl+C to stop.`);
92
  }
93
 
94
  main().catch((e) => { console.error(e); process.exit(1); });