@irsdk-node/native 5.2.2 → 5.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.
@@ -1,61 +1,72 @@
1
- #include "./irsdk_defines.h"
2
1
  #include "./irsdk_node.h"
2
+ #include "./irsdk/irsdk_defines.h"
3
3
  #include "./logger.h"
4
4
  #include <cstdio>
5
- #include <napi.h>
6
5
  #include <napi-inl.h>
6
+ #include <napi.h>
7
7
  #include <string.h>
8
8
 
9
- static const char *K_IRSDK_CLASS_EXPORT_NAME = "iRacingSdkNode";
9
+ using namespace irsdk_node;
10
+
11
+ static const char* K_IRSDK_CLASS_EXPORT_NAME = "iRacingSdkNode";
10
12
 
11
13
  // ---------------------------
12
14
  // Constructors
13
15
  // ---------------------------
14
16
  Napi::Object iRacingSdkNode::Init(Napi::Env aEnv, Napi::Object aExports)
15
17
  {
16
- Napi::Function func = DefineClass(aEnv, K_IRSDK_CLASS_EXPORT_NAME, {
17
- // Properties
18
- InstanceAccessor<&iRacingSdkNode::_napi_prop_getCurrSessionDataVer>("currDataVersion"),
19
- InstanceAccessor<&iRacingSdkNode::_napi_prop_getEnableLogging, &iRacingSdkNode::_napi_prop_setEnableLogging>("enableLogging"),
20
- InstanceAccessor<&iRacingSdkNode::_napi_prop_getLogLevel, &iRacingSdkNode::_napi_prop_setLogLevel>("logLevel"),
21
- InstanceAccessor<&iRacingSdkNode::_napi_prop_getIsMocked>("isMocked"),
22
-
23
- // Methods
24
- // Control
25
- InstanceMethod("startSDK", &iRacingSdkNode::_napi_startSdk),
26
- InstanceMethod("stopSDK", &iRacingSdkNode::_napi_stopSdk),
27
- InstanceMethod("waitForData", &iRacingSdkNode::_napi_waitForData),
28
- InstanceMethod("broadcast", &iRacingSdkNode::_napi_broadcastMessage),
29
- // Getters
30
- InstanceMethod("isRunning", &iRacingSdkNode::_napi_isRunning),
31
- InstanceMethod("getSessionVersionNum", &iRacingSdkNode::_napi_getSessionVersionNum),
32
- InstanceMethod("getSessionConnectionID", &iRacingSdkNode::_napi_getSessionConnectionID),
33
- InstanceMethod("getSessionData", &iRacingSdkNode::_napi_getSessionData),
34
- InstanceMethod("getTelemetryData", &iRacingSdkNode::_napi_getTelemetryData),
35
- InstanceMethod("getTelemetryVariable", &iRacingSdkNode::GetTelemetryVar),
36
- // Helpers
37
- InstanceMethod("__getTelemetryTypes", &iRacingSdkNode::_napi_getTelemetryTypes)
38
- });
39
-
40
- Napi::FunctionReference *constructor = new Napi::FunctionReference();
41
- *constructor = Napi::Persistent(func);
42
- aEnv.SetInstanceData(constructor);
43
-
44
- aExports.Set(K_IRSDK_CLASS_EXPORT_NAME, func);
45
- return aExports;
46
- }
47
-
48
- iRacingSdkNode::iRacingSdkNode(const Napi::CallbackInfo &aInfo)
49
- : Napi::ObjectWrap<iRacingSdkNode>(aInfo),
50
- _data(NULL),
51
- _bufLineLen(0),
52
- _sessionStatusID(0),
53
- _lastSessionCt(-1),
54
- _sessionData(NULL),
55
- _logger(irsdk_node::LogLevel_None)
56
- {
57
- printf("Initializing iRacingSdkNode\n");
58
- }
18
+ Napi::Function func = DefineClass(
19
+ aEnv,
20
+ K_IRSDK_CLASS_EXPORT_NAME,
21
+ { // Properties
22
+ InstanceAccessor<&iRacingSdkNode::_napi_prop_getCurrSessionDataVer>("currDataVersion"),
23
+ InstanceAccessor(
24
+ "enableLogging",
25
+ &iRacingSdkNode::_napi_prop_getEnableLogging,
26
+ &iRacingSdkNode::_napi_prop_setEnableLogging
27
+ ),
28
+ InstanceAccessor(
29
+ "logLevel",
30
+ &iRacingSdkNode::_napi_prop_getLogLevel,
31
+ &iRacingSdkNode::_napi_prop_setLogLevel
32
+ ),
33
+ InstanceAccessor<&iRacingSdkNode::_napi_prop_getIsMocked>("isMocked"),
34
+
35
+ // Methods
36
+ // Control
37
+ InstanceMethod("startSDK", &iRacingSdkNode::_napi_startSdk),
38
+ InstanceMethod("stopSDK", &iRacingSdkNode::_napi_stopSdk),
39
+ InstanceMethod("waitForData", &iRacingSdkNode::_napi_waitForData),
40
+ InstanceMethod("broadcast", &iRacingSdkNode::_napi_broadcastMessage),
41
+ // Getters
42
+ InstanceMethod("isRunning", &iRacingSdkNode::_napi_isRunning),
43
+ InstanceMethod("getSessionVersionNum", &iRacingSdkNode::_napi_getSessionVersionNum),
44
+ InstanceMethod("getSessionConnectionID", &iRacingSdkNode::_napi_getSessionConnectionID),
45
+ InstanceMethod("getSessionData", &iRacingSdkNode::_napi_getSessionData),
46
+ InstanceMethod("getTelemetryData", &iRacingSdkNode::_napi_getTelemetryData),
47
+ InstanceMethod("getTelemetryVariable", &iRacingSdkNode::_napi_getTelemetryVar),
48
+ InstanceMethod("getTelemetryVariableIndex", &iRacingSdkNode::_napi_getTelemetryVarIndex),
49
+ // Helpers
50
+ InstanceMethod("__getTelemetryTypes", &iRacingSdkNode::_napi_getTelemetryTypes) }
51
+ );
52
+
53
+ Napi::FunctionReference* constructor = new Napi::FunctionReference();
54
+ *constructor = Napi::Persistent(func);
55
+ aEnv.SetInstanceData(constructor);
56
+
57
+ aExports.Set(K_IRSDK_CLASS_EXPORT_NAME, func);
58
+ return aExports;
59
+ }
60
+
61
+ iRacingSdkNode::iRacingSdkNode(const Napi::CallbackInfo& aInfo)
62
+ : Napi::ObjectWrap<iRacingSdkNode>(aInfo)
63
+ , _data(NULL)
64
+ , _bufLineLen(0)
65
+ , _sessionStatusID(0)
66
+ , _lastSessionCt(-1)
67
+ , _sessionData(NULL)
68
+ , _logger(irsdk_node::LogLevel_None)
69
+ { }
59
70
 
60
71
  // Internal implementation ----------------------------------------------------
61
72
 
@@ -64,108 +75,91 @@ iRacingSdkNode::iRacingSdkNode(const Napi::CallbackInfo &aInfo)
64
75
 
65
76
  bool iRacingSdkNode::startup()
66
77
  {
67
- _logger.debug("StartSdk: Attempting to connect to SDK");
78
+ _logger.debug("StartSdk: Attempting to connect to SDK");
68
79
 
69
- if (!irsdk_isConnected())
70
- {
71
- _logger.debug("iRacing SDK not connected, connecting\n");
72
- bool result = irsdk_startup();
73
- _logger.info("Attempted SDK startup (result: %i)\n", result);
80
+ if (!irsdk_isConnected()) {
81
+ _logger.debug("iRacing SDK not connected, connecting\n");
82
+ bool result = irsdk_startup();
83
+ _logger.info("Attempted SDK startup (result: %i)\n", result);
74
84
 
75
- return result;
76
- }
85
+ return result;
86
+ }
77
87
 
78
- return true;
88
+ return true;
79
89
  }
80
90
 
81
91
  void iRacingSdkNode::shutdown()
82
92
  {
83
- _logger.info("Running irsdk-node shutdown");
84
- irsdk_shutdown();
85
- _resetData();
93
+ _logger.info("Running irsdk-node shutdown");
94
+ irsdk_shutdown();
95
+ _resetData();
86
96
  }
87
97
 
88
- bool iRacingSdkNode::isConnected() const
89
- {
90
- return _data != NULL && irsdk_isConnected();
91
- }
98
+ bool iRacingSdkNode::isConnected() const { return _data != NULL && irsdk_isConnected(); }
92
99
 
93
- int iRacingSdkNode::getSessionInfoStrCount()
94
- {
95
- return irsdk_getSessionInfoStrUpdate();
96
- }
100
+ int iRacingSdkNode::getSessionInfoStrCount() { return irsdk_getSessionInfoStrUpdate(); }
97
101
 
98
- bool iRacingSdkNode::wasSessionStrUpdated()
99
- {
100
- return _lastSessionCt != getSessionInfoStrCount();
101
- }
102
+ bool iRacingSdkNode::wasSessionStrUpdated() { return _lastSessionCt != getSessionInfoStrCount(); }
102
103
 
103
104
  bool iRacingSdkNode::waitForData(int aTimeoutMs)
104
105
  {
105
- // Wait for new data or for a session to start
106
- if (irsdk_waitForDataReady(aTimeoutMs, _data) && irsdk_getHeader())
107
- {
108
- _logger.debug("Got data from iRacing SDK\n");
109
- const irsdk_header *header = irsdk_getHeader();
110
-
111
- // New connection or data changed length
112
- if (!_data || _bufLineLen != header->bufLen)
113
- {
114
- _logger.debug("Connection started / data changed length\n");
115
-
116
- // Reset memory to hold incoming data
117
- if (_data) delete[] _data;
118
- _bufLineLen = header->bufLen;
119
- _data = new char[_bufLineLen];
120
-
121
- // Increment connection and reset info string and buffer length
122
- _sessionStatusID++;
123
- _lastSessionCt = -1;
124
-
125
- // Try to fill in the new data
126
- if (irsdk_getNewData(_data))
127
- {
128
- _logger.debug("New data retrieved successfully\n");
129
- return true;
130
- }
131
- } else if (_data)
132
- {
133
- _logger.debug("Data already available, ready for processing\n");
134
- return true;
135
- }
136
- } else if (!isConnected())
137
- {
138
- _logger.debug("Session ended. Cleaning up.\n");
139
- _resetData();
140
- }
141
-
142
- _logger.debug("No data available.\n");
143
- return false;
144
- }
106
+ // Wait for new data or for a session to start
107
+ if (irsdk_waitForDataReady(aTimeoutMs, _data) && irsdk_getHeader()) {
108
+ _logger.debug("Got data from iRacing SDK\n");
109
+ const irsdk_header* header = irsdk_getHeader();
110
+
111
+ // New connection or data changed length
112
+ if (!_data || _bufLineLen != header->bufLen) {
113
+ _logger.debug("Connection started / data changed length\n");
114
+
115
+ // Reset memory to hold incoming data
116
+ if (_data)
117
+ delete[] _data;
118
+ _bufLineLen = header->bufLen;
119
+ _data = new char[_bufLineLen];
145
120
 
121
+ // Increment connection and reset info string and buffer length
122
+ _sessionStatusID++;
123
+ _lastSessionCt = -1;
146
124
 
147
- const char *iRacingSdkNode::getSessionStr()
125
+ // Try to fill in the new data
126
+ if (irsdk_getNewData(_data)) {
127
+ _logger.debug("New data retrieved successfully\n");
128
+ return true;
129
+ }
130
+ } else if (_data) {
131
+ _logger.debug("Data already available, ready for processing\n");
132
+ return true;
133
+ }
134
+ } else if (!isConnected()) {
135
+ _logger.debug("Session ended. Cleaning up.\n");
136
+ _resetData();
137
+ }
138
+
139
+ _logger.debug("No data available.\n");
140
+ return false;
141
+ }
142
+
143
+ const char* iRacingSdkNode::getSessionStr()
148
144
  {
149
- if (!isConnected())
150
- return NULL;
151
-
152
- // If there is no session data cached or the session string is out of date,
153
- // fetch the latest and update the cached session count.
154
- if (!_sessionData || wasSessionStrUpdated())
155
- {
156
- _logger.debug("Invalid session data, fetching latest\n");
157
-
158
- int latestUpdate = getSessionInfoStrCount();
159
- _logger.info("Session data has been updated (prev: %d, new: %d)\n", _lastSessionCt, latestUpdate);
160
-
161
- _lastSessionCt = latestUpdate;
162
- _sessionData = irsdk_getSessionInfoStr();
163
- } else
164
- {
165
- _logger.debug("Session data is valid, re-using cached\n");
166
- }
167
-
168
- return _sessionData;
145
+ if (!isConnected())
146
+ return NULL;
147
+
148
+ // If there is no session data cached or the session string is out of date,
149
+ // fetch the latest and update the cached session count.
150
+ if (!_sessionData || wasSessionStrUpdated()) {
151
+ _logger.debug("Invalid session data, fetching latest\n");
152
+
153
+ int latestUpdate = getSessionInfoStrCount();
154
+ _logger.info("Session data has been updated (prev: %d, new: %d)\n", _lastSessionCt, latestUpdate);
155
+
156
+ _lastSessionCt = latestUpdate;
157
+ _sessionData = irsdk_getSessionInfoStr();
158
+ } else {
159
+ _logger.debug("Session data is valid, re-using cached\n");
160
+ }
161
+
162
+ return _sessionData;
169
163
  }
170
164
 
171
165
  // Private API
@@ -173,14 +167,15 @@ const char *iRacingSdkNode::getSessionStr()
173
167
 
174
168
  void iRacingSdkNode::_resetData()
175
169
  {
176
- _logger.debug("Resetting cached data...\n");
170
+ _logger.debug("Resetting cached data...\n");
177
171
 
178
- if (_data) delete[] _data;
179
- _data = NULL;
180
- _sessionData = NULL;
181
- _lastSessionCt = -1;
172
+ if (_data)
173
+ delete[] _data;
174
+ _data = NULL;
175
+ _sessionData = NULL;
176
+ _lastSessionCt = -1;
182
177
 
183
- _logger.debug("Finished resetting cached data\n");
178
+ _logger.debug("Finished resetting cached data\n");
184
179
  }
185
180
 
186
181
  // Node API -------------------------------------------------------------------
@@ -188,346 +183,354 @@ void iRacingSdkNode::_resetData()
188
183
  // Property implementations
189
184
  // -------------------------
190
185
 
191
- Napi::Value iRacingSdkNode::_napi_prop_getCurrSessionDataVer(const Napi::CallbackInfo &aInfo)
186
+ Napi::Value iRacingSdkNode::_napi_prop_getCurrSessionDataVer(const Napi::CallbackInfo& aInfo)
192
187
  {
193
- return Napi::Number::New(aInfo.Env(), this->_lastSessionCt);
188
+ return Napi::Number::New(aInfo.Env(), _lastSessionCt);
194
189
  }
195
190
 
196
- Napi::Value iRacingSdkNode::_napi_prop_getEnableLogging(const Napi::CallbackInfo &aInfo)
191
+ Napi::Value iRacingSdkNode::_napi_prop_getEnableLogging(const Napi::CallbackInfo& aInfo)
197
192
  {
198
- bool enabled = this->_logger.logLevel > irsdk_node::LogLevel_None;
199
- return Napi::Boolean::New(aInfo.Env(), enabled);
193
+ bool enabled = _logger.logLevel > irsdk_node::LogLevel_None;
194
+ return Napi::Boolean::New(aInfo.Env(), enabled);
200
195
  }
201
196
 
202
- void iRacingSdkNode::_napi_prop_setEnableLogging(const Napi::CallbackInfo &aInfo, const Napi::Value &aValue)
197
+ void iRacingSdkNode::_napi_prop_setEnableLogging(const Napi::CallbackInfo& aInfo, const Napi::Value& aValue)
203
198
  {
204
- Napi::Boolean enable;
205
- if (!aValue.IsBoolean())
206
- {
207
- enable = Napi::Boolean::New(aInfo.Env(), false);
208
- } else
209
- {
210
- enable = aValue.As<Napi::Boolean>();
211
- }
212
-
213
- this->_logger.logLevel = enable ? irsdk_node::LogLevel_Error : irsdk_node::LogLevel_None;
214
- this->_logger.warn("DEPRECATION WARNING: .enableLogging is deprecated, please use .logLevel instead\n");
199
+ Napi::Boolean enable;
200
+ if (!aValue.IsBoolean()) {
201
+ enable = Napi::Boolean::New(aInfo.Env(), false);
202
+ } else {
203
+ enable = aValue.As<Napi::Boolean>();
204
+ }
205
+
206
+ _logger.logLevel = enable ? irsdk_node::LogLevel_Error : irsdk_node::LogLevel_None;
207
+ _logger.warn("DEPRECATION WARNING: .enableLogging is deprecated, please use .logLevel instead\n");
215
208
  }
216
209
 
217
- Napi::Value iRacingSdkNode::_napi_prop_getLogLevel(const Napi::CallbackInfo &aInfo)
210
+ Napi::Value iRacingSdkNode::_napi_prop_getLogLevel(const Napi::CallbackInfo& aInfo)
218
211
  {
219
- return Napi::Number::New(aInfo.Env(), this->_logger.logLevel);
212
+ return Napi::Number::New(aInfo.Env(), _logger.logLevel);
220
213
  }
221
214
 
222
- void iRacingSdkNode::_napi_prop_setLogLevel(const Napi::CallbackInfo &aInfo, const Napi::Value &aValue)
215
+ void iRacingSdkNode::_napi_prop_setLogLevel(const Napi::CallbackInfo& aInfo, const Napi::Value& aValue)
223
216
  {
224
- if (!aValue.IsNumber())
225
- {
226
- this->_logger.warn(".logLevel must be given a number (or the LogLevel enum)\n");
227
- return;
228
- }
229
-
230
- irsdk_node::LogLevel level = static_cast<irsdk_node::LogLevel>(aValue.As<Napi::Number>().Int32Value());
231
- if (level < irsdk_node::LogLevel_None || level > irsdk_node::LogLevel_Debug)
232
- {
233
- this->_logger.warn("logLevel given an invalid value\n");
234
- return;
235
- }
236
-
237
- this->_logger.logLevel = level;
238
- this->_logger.info("Log level changed to %s\n", irsdk_node::Logger::GetLabelForLevel(level));
217
+ if (!aValue.IsNumber()) {
218
+ _logger.warn(".logLevel must be given a number (or the LogLevel enum)\n");
219
+ return;
220
+ }
221
+
222
+ irsdk_node::LogLevel level = static_cast<irsdk_node::LogLevel>(aValue.As<Napi::Number>().Int32Value());
223
+ if (level < irsdk_node::LogLevel_None || level > irsdk_node::LogLevel_Debug) {
224
+ _logger.warn("logLevel given an invalid value\n");
225
+ return;
226
+ }
227
+
228
+ _logger.logLevel = level;
229
+ _logger.info("Log level changed to %s\n", irsdk_node::Logger::GetLabelForLevel(level));
239
230
  }
240
231
 
241
- Napi::Value iRacingSdkNode::_napi_prop_getIsMocked(const Napi::CallbackInfo &aInfo)
232
+ Napi::Value iRacingSdkNode::_napi_prop_getIsMocked(const Napi::CallbackInfo& aInfo)
242
233
  {
243
- return Napi::Boolean::New(aInfo.Env(), false);
234
+ return Napi::Boolean::New(aInfo.Env(), false);
244
235
  }
245
236
 
246
-
247
237
  // Instance implementations
248
238
  // ---------------------------
249
239
 
250
240
  // SDK Control
251
- Napi::Value iRacingSdkNode::_napi_startSdk(const Napi::CallbackInfo &aInfo)
241
+ Napi::Value iRacingSdkNode::_napi_startSdk(const Napi::CallbackInfo& aInfo)
252
242
  {
253
- return Napi::Boolean::New(aInfo.Env(), startup());
243
+ return Napi::Boolean::New(aInfo.Env(), startup());
254
244
  }
255
245
 
256
- Napi::Value iRacingSdkNode::_napi_stopSdk(const Napi::CallbackInfo &aInfo)
246
+ Napi::Value iRacingSdkNode::_napi_stopSdk(const Napi::CallbackInfo& aInfo)
257
247
  {
258
- shutdown();
259
- return Napi::Boolean::New(aInfo.Env(), true);
248
+ shutdown();
249
+ return Napi::Boolean::New(aInfo.Env(), true);
260
250
  }
261
251
 
262
- Napi::Value iRacingSdkNode::_napi_waitForData(const Napi::CallbackInfo &aInfo)
252
+ Napi::Value iRacingSdkNode::_napi_waitForData(const Napi::CallbackInfo& aInfo)
263
253
  {
264
- int timeout = aInfo.Length() <= 0 || !aInfo[0].IsNumber()
265
- ? K_DEFAULT_TIMEOUT_MS
266
- : aInfo[0].As<Napi::Number>().Int32Value();
254
+ int timeout
255
+ = aInfo.Length() <= 0 || !aInfo[0].IsNumber() ? K_DEFAULT_TIMEOUT_MS : aInfo[0].As<Napi::Number>().Int32Value();
267
256
 
268
- if (timeout < 16) timeout = 16;
257
+ if (timeout < 16)
258
+ timeout = 16;
269
259
 
270
- return Napi::Boolean::New(aInfo.Env(), waitForData(timeout));
260
+ return Napi::Boolean::New(aInfo.Env(), waitForData(timeout));
271
261
  }
272
262
 
273
- Napi::Value iRacingSdkNode::_napi_broadcastMessage(const Napi::CallbackInfo &aInfo)
263
+ Napi::Value iRacingSdkNode::_napi_broadcastMessage(const Napi::CallbackInfo& aInfo)
274
264
  {
275
- auto env = aInfo.Env();
276
-
277
- // Determine message type
278
- if (aInfo.Length() <= 2 || !aInfo[0].IsNumber())
279
- {
280
- return Napi::Boolean::New(env, false);
281
- }
282
-
283
- if (aInfo.Length() == 4 && !aInfo[2].IsNumber())
284
- {
285
- return Napi::Boolean::New(env, false);
286
- }
287
-
288
- Napi::Number msgEnumIndex = aInfo[0].As<Napi::Number>();
289
- irsdk_BroadcastMsg msgType = static_cast<irsdk_BroadcastMsg>(msgEnumIndex.Int32Value());
290
-
291
- // Args
292
- Napi::Number arg1 = aInfo[1].As<Napi::Number>();
293
- Napi::Number arg2 = aInfo[2].As<Napi::Number>();
294
- Napi::Number arg3 = aInfo[3].As<Napi::Number>();
295
-
296
- irsdk_ChatCommandMode chatCommand = irsdk_ChatCommand_Cancel;
297
-
298
-
299
- // Handle each message independently.
300
- //
301
- // This could be consolidated, but then it becomes way too difficult to easily
302
- // grep what each messages expected API is, as some are not necessarily what
303
- switch (msgType)
304
- {
305
- // BroadcastCamSwitchPos: car position, group, camera
306
- // BroadcastCamSwitchNum: driver #, group, camera
307
- case irsdk_BroadcastCamSwitchPos:
308
- case irsdk_BroadcastCamSwitchNum:
309
- // First arg can be irsdk_csMode enum.
310
- // Any value above -1 equates to focusing on a specific driver.
311
- irsdk_broadcastMsg(msgType, arg1.Int32Value(), arg2.Int32Value(), arg3.Int32Value());
312
- break;
313
-
314
- // irsdk_CameraState, unused, unused
315
- case irsdk_BroadcastCamSetState:
316
- irsdk_broadcastMsg(msgType, static_cast<irsdk_CameraState>(arg1.Int32Value()), 0);
317
- break;
318
-
319
- // speed, slowMotion, unused
320
- case irsdk_BroadcastReplaySetPlaySpeed:
321
- // Speed (arg1) should be multiples of 2 (0, 1, 2, 4, 8, 16), can be negative
322
- // Slow mo (arg2) should be 1 | 0
323
- irsdk_broadcastMsg(msgType, arg1.Int32Value(), arg2.ToBoolean().Value());
324
- break;
325
-
326
- // irsdk_RpyPosMode, Frame Number (high, low)
327
- case irsdk_BroadcastReplaySetPlayPosition:
328
- irsdk_broadcastMsg(msgType, static_cast<irsdk_RpyPosMode>(arg1.Int32Value()), arg2.Int32Value());
329
- break;
330
-
331
- // irsdk_RpySrchMode, unused, unused
332
- case irsdk_BroadcastReplaySearch:
333
- irsdk_broadcastMsg(msgType, static_cast<irsdk_RpySrchMode>(arg1.Int32Value()), 0, 0);
334
- break;
335
-
336
- // irsdk_RpyStateMode, unused, unused
337
- case irsdk_BroadcastReplaySetState:
338
- irsdk_broadcastMsg(msgType, static_cast<irsdk_RpyStateMode>(arg1.Int32Value()), 0);
339
- break;
340
-
341
- // irsdk_ReloadTexturesMode, carIdx, unused
342
- case irsdk_BroadcastReloadTextures:
343
- irsdk_broadcastMsg(msgType, static_cast<irsdk_ReloadTexturesMode>(arg1.Int32Value()), arg2.Int32Value(), 0);
344
- break;
345
-
346
- // irsdk_ChatCommandMode, subCommand, unused
347
- case irsdk_BroadcastChatComand:
348
- chatCommand = static_cast<irsdk_ChatCommandMode>(arg1.Int32Value());
349
- if (chatCommand != irsdk_ChatCommand_Macro)
350
- {
351
- irsdk_broadcastMsg(msgType, chatCommand, 0);
352
- break;
353
- }
354
-
355
- // If the chat command is to use a macro, parse the macro id (1 - 15) (2nd arg)
356
- irsdk_broadcastMsg(msgType, chatCommand, arg2.Int32Value(), 0);
357
- break;
358
-
359
- // irsdk_PitCommandMode, parameter
360
- case irsdk_BroadcastPitCommand:
361
- irsdk_broadcastMsg(msgType, static_cast<irsdk_PitCommandMode>(arg1.Int32Value()), arg2.Int32Value());
362
- break;
363
-
364
- // irsdk_TelemCommandMode, unused, unused
365
- case irsdk_BroadcastTelemCommand:
366
- irsdk_broadcastMsg(msgType, static_cast<irsdk_TelemCommandMode>(arg1.Int32Value()), 0, 0);
367
- break;
368
-
369
- // irsdk_FFBCommandMode, value (float, high, low)
370
- case irsdk_BroadcastFFBCommand:
371
- irsdk_broadcastMsg(msgType, static_cast<irsdk_FFBCommandMode>(arg1.Int32Value()), arg2.FloatValue());
372
- break;
373
-
374
- // This does a search and not a direct jump, so it may take a while
375
- // sessionNum, sessionTimeMS (high, low)
376
- case irsdk_BroadcastReplaySearchSessionTime:
377
- irsdk_broadcastMsg(msgType, arg1.Int32Value(), arg2.Int32Value());
378
- break;
379
-
380
- // irsdk_VideoCaptureMode, unused, unused
381
- case irsdk_BroadcastVideoCapture:
382
- irsdk_broadcastMsg(msgType, static_cast<irsdk_VideoCaptureMode>(arg1.Int32Value()), 0);
383
- break;
384
-
385
- // Unused + out-of-bounds
386
- default:
387
- this->_logger.error("Attempted to broadcast an unsupported message.\n");
388
- return Napi::Boolean::New(env, false);
389
- }
390
-
391
- return Napi::Boolean::New(env, true);
265
+ auto env = aInfo.Env();
266
+
267
+ // Determine message type
268
+ if (aInfo.Length() <= 2 || !aInfo[0].IsNumber()) {
269
+ return Napi::Boolean::New(env, false);
270
+ }
271
+
272
+ if (aInfo.Length() == 4 && !aInfo[2].IsNumber()) {
273
+ return Napi::Boolean::New(env, false);
274
+ }
275
+
276
+ Napi::Number msgEnumIndex = aInfo[0].As<Napi::Number>();
277
+ irsdk_BroadcastMsg msgType = static_cast<irsdk_BroadcastMsg>(msgEnumIndex.Int32Value());
278
+
279
+ // Args
280
+ Napi::Number arg1 = aInfo[1].As<Napi::Number>();
281
+ Napi::Number arg2 = aInfo[2].As<Napi::Number>();
282
+ Napi::Number arg3 = aInfo[3].As<Napi::Number>();
283
+
284
+ irsdk_ChatCommandMode chatCommand = irsdk_ChatCommand_Cancel;
285
+
286
+ // Handle each message independently.
287
+ //
288
+ // This could be consolidated, but then it becomes way too difficult to easily
289
+ // grep what each messages expected API is, as some are not necessarily what
290
+ switch (msgType) {
291
+ // BroadcastCamSwitchPos: car position, group, camera
292
+ // BroadcastCamSwitchNum: driver #, group, camera
293
+ case irsdk_BroadcastCamSwitchPos:
294
+ case irsdk_BroadcastCamSwitchNum:
295
+ // First arg can be irsdk_csMode enum.
296
+ // Any value above -1 equates to focusing on a specific driver.
297
+ irsdk_broadcastMsg(msgType, arg1.Int32Value(), arg2.Int32Value(), arg3.Int32Value());
298
+ break;
299
+
300
+ // irsdk_CameraState, unused, unused
301
+ case irsdk_BroadcastCamSetState:
302
+ irsdk_broadcastMsg(msgType, static_cast<irsdk_CameraState>(arg1.Int32Value()), 0);
303
+ break;
304
+
305
+ // speed, slowMotion, unused
306
+ case irsdk_BroadcastReplaySetPlaySpeed:
307
+ // Speed (arg1) should be multiples of 2 (0, 1, 2, 4, 8, 16), can be negative
308
+ // Slow mo (arg2) should be 1 | 0
309
+ irsdk_broadcastMsg(msgType, arg1.Int32Value(), arg2.ToBoolean().Value());
310
+ break;
311
+
312
+ // irsdk_RpyPosMode, Frame Number (high, low)
313
+ case irsdk_BroadcastReplaySetPlayPosition:
314
+ irsdk_broadcastMsg(msgType, static_cast<irsdk_RpyPosMode>(arg1.Int32Value()), arg2.Int32Value());
315
+ break;
316
+
317
+ // irsdk_RpySrchMode, unused, unused
318
+ case irsdk_BroadcastReplaySearch:
319
+ irsdk_broadcastMsg(msgType, static_cast<irsdk_RpySrchMode>(arg1.Int32Value()), 0, 0);
320
+ break;
321
+
322
+ // irsdk_RpyStateMode, unused, unused
323
+ case irsdk_BroadcastReplaySetState:
324
+ irsdk_broadcastMsg(msgType, static_cast<irsdk_RpyStateMode>(arg1.Int32Value()), 0);
325
+ break;
326
+
327
+ // irsdk_ReloadTexturesMode, carIdx, unused
328
+ case irsdk_BroadcastReloadTextures:
329
+ irsdk_broadcastMsg(msgType, static_cast<irsdk_ReloadTexturesMode>(arg1.Int32Value()), arg2.Int32Value(), 0);
330
+ break;
331
+
332
+ // irsdk_ChatCommandMode, subCommand, unused
333
+ case irsdk_BroadcastChatComand:
334
+ chatCommand = static_cast<irsdk_ChatCommandMode>(arg1.Int32Value());
335
+ if (chatCommand != irsdk_ChatCommand_Macro) {
336
+ irsdk_broadcastMsg(msgType, chatCommand, 0);
337
+ break;
338
+ }
339
+
340
+ // If the chat command is to use a macro, parse the macro id (1 - 15) (2nd arg)
341
+ irsdk_broadcastMsg(msgType, chatCommand, arg2.Int32Value(), 0);
342
+ break;
343
+
344
+ // irsdk_PitCommandMode, parameter
345
+ case irsdk_BroadcastPitCommand:
346
+ irsdk_broadcastMsg(msgType, static_cast<irsdk_PitCommandMode>(arg1.Int32Value()), arg2.Int32Value());
347
+ break;
348
+
349
+ // irsdk_TelemCommandMode, unused, unused
350
+ case irsdk_BroadcastTelemCommand:
351
+ irsdk_broadcastMsg(msgType, static_cast<irsdk_TelemCommandMode>(arg1.Int32Value()), 0, 0);
352
+ break;
353
+
354
+ // irsdk_FFBCommandMode, value (float, high, low)
355
+ case irsdk_BroadcastFFBCommand:
356
+ irsdk_broadcastMsg(msgType, static_cast<irsdk_FFBCommandMode>(arg1.Int32Value()), arg2.FloatValue());
357
+ break;
358
+
359
+ // This does a search and not a direct jump, so it may take a while
360
+ // sessionNum, sessionTimeMS (high, low)
361
+ case irsdk_BroadcastReplaySearchSessionTime:
362
+ irsdk_broadcastMsg(msgType, arg1.Int32Value(), arg2.Int32Value());
363
+ break;
364
+
365
+ // irsdk_VideoCaptureMode, unused, unused
366
+ case irsdk_BroadcastVideoCapture:
367
+ irsdk_broadcastMsg(msgType, static_cast<irsdk_VideoCaptureMode>(arg1.Int32Value()), 0);
368
+ break;
369
+
370
+ // Unused + out-of-bounds
371
+ default:
372
+ _logger.error("Attempted to broadcast an unsupported message.\n");
373
+ return Napi::Boolean::New(env, false);
374
+ }
375
+
376
+ return Napi::Boolean::New(env, true);
392
377
  }
393
378
 
394
379
  // SDK State Getters
395
- Napi::Value iRacingSdkNode::_napi_isRunning(const Napi::CallbackInfo &aInfo)
380
+ Napi::Value iRacingSdkNode::_napi_isRunning(const Napi::CallbackInfo& aInfo)
396
381
  {
397
- return Napi::Boolean::New(aInfo.Env(), isConnected());
382
+ return Napi::Boolean::New(aInfo.Env(), isConnected());
398
383
  }
399
384
 
400
- Napi::Value iRacingSdkNode::_napi_getSessionVersionNum(const Napi::CallbackInfo &aInfo)
385
+ Napi::Value iRacingSdkNode::_napi_getSessionVersionNum(const Napi::CallbackInfo& aInfo)
401
386
  {
402
- return Napi::Number::New(aInfo.Env(), getSessionInfoStrCount());
387
+ return Napi::Number::New(aInfo.Env(), getSessionInfoStrCount());
403
388
  }
404
389
 
405
- Napi::Value iRacingSdkNode::_napi_getSessionConnectionID(const Napi::CallbackInfo &aInfo)
390
+ Napi::Value iRacingSdkNode::_napi_getSessionConnectionID(const Napi::CallbackInfo& aInfo)
406
391
  {
407
- return Napi::Number::New(aInfo.Env(), this->_sessionStatusID);
392
+ return Napi::Number::New(aInfo.Env(), _sessionStatusID);
408
393
  }
409
394
 
410
- Napi::Value iRacingSdkNode::_napi_getSessionData(const Napi::CallbackInfo &aInfo)
395
+ Napi::Value iRacingSdkNode::_napi_getSessionData(const Napi::CallbackInfo& aInfo)
411
396
  {
412
- auto session = getSessionStr();
397
+ auto session = getSessionStr();
413
398
 
414
- if (session == NULL)
415
- return Napi::String::New(aInfo.Env(), "");
399
+ if (session == NULL)
400
+ return Napi::String::New(aInfo.Env(), "");
416
401
 
417
- return Napi::String::New(aInfo.Env(), session);
402
+ return Napi::String::New(aInfo.Env(), session);
418
403
  }
419
404
 
420
- Napi::Value iRacingSdkNode::GetTelemetryVar(const Napi::CallbackInfo &aInfo)
405
+ Napi::Value iRacingSdkNode::_napi_getTelemetryVar(const Napi::CallbackInfo& aInfo)
421
406
  {
422
- Napi::Env env = aInfo.Env();
423
-
424
- int varIndex;
425
- if (aInfo.Length() <= 0)
426
- {
427
- varIndex = 0;
428
- } else if (!aInfo[0].IsNumber())
429
- {
430
- if (aInfo[0].IsString())
431
- {
432
- const char *name = aInfo[0].As<Napi::String>().Utf8Value().c_str();
433
- return this->GetTelemetryVar(env, name);
434
- }
435
- varIndex = 0;
436
- }
437
-
438
- return this->GetTelemetryVarByIndex(env, varIndex);
407
+ Napi::Env env = aInfo.Env();
408
+
409
+ // If given malformed input, return null
410
+ if (aInfo.Length() <= 0) {
411
+ return env.Null();
412
+ }
413
+
414
+ auto arg = aInfo[0];
415
+
416
+ // When given a number, it should just be converted to an int and used as
417
+ // the index.
418
+ if (arg.IsNumber()) {
419
+ return _getTelemetryVarByIndex(env, arg.ToNumber().Int32Value());
420
+ }
421
+
422
+ // If given a string, we are searching by name. Convert to a c string so we
423
+ // can use it for lookup.
424
+ if (arg.IsString()) {
425
+ auto nameNapiStr = arg.ToString().Utf8Value();
426
+ auto nameCStr = nameNapiStr.c_str();
427
+ return _getTelemetryVarByName(env, nameCStr);
428
+ }
429
+
430
+ // All other inputs are invalid, return null.
431
+ return env.Null();
439
432
  }
440
433
 
441
- Napi::Value iRacingSdkNode::_napi_getTelemetryData(const Napi::CallbackInfo &aInfo)
434
+ Napi::Value iRacingSdkNode::_napi_getTelemetryVarIndex(const Napi::CallbackInfo& aInfo)
442
435
  {
443
- const irsdk_header *header = irsdk_getHeader();
444
- auto env = aInfo.Env();
445
- auto telemVars = Napi::Object::New(env);
446
-
447
- int count = header->numVars;
448
- for (int i = 0; i < count; i++)
449
- {
450
- auto telemVariable = this->GetTelemetryVarByIndex(env, i);
451
- if (telemVariable.IsObject() && telemVariable.Has("name"))
452
- {
453
- telemVars.Set(telemVariable.Get("name"), telemVariable);
454
- }
455
- }
456
-
457
- return telemVars;
436
+ Napi::Env env = aInfo.Env();
437
+
438
+ // Null if given malformed input (expects one string).
439
+ if (aInfo.Length() <= 0 || !aInfo[0].IsString()) {
440
+ return env.Null();
441
+ }
442
+
443
+ auto napiStr = aInfo[0].ToString().Utf8Value();
444
+ auto cStr = napiStr.c_str();
445
+
446
+ return Napi::Number::New(env, irsdk_varNameToIndex(cStr));
458
447
  }
459
448
 
460
- // Helpers
461
- Napi::Value iRacingSdkNode::_napi_getTelemetryTypes(const Napi::CallbackInfo &aInfo)
449
+ Napi::Value iRacingSdkNode::_napi_getTelemetryData(const Napi::CallbackInfo& aInfo)
462
450
  {
463
- auto env = aInfo.Env();
464
- auto result = Napi::Object::New(env);
465
-
466
- const int count = irsdk_getHeader()->numVars;
467
- const irsdk_varHeader *varHeader;
468
- for (int i = 0; i < count; i++)
469
- {
470
- varHeader = irsdk_getVarHeaderEntry(i);
471
- result.Set(varHeader->name, Napi::Number::New(env, varHeader->type));
472
- }
473
-
474
- return result;
451
+ const irsdk_header* header = irsdk_getHeader();
452
+ auto env = aInfo.Env();
453
+ auto telemVars = Napi::Object::New(env);
454
+
455
+ int count = header->numVars;
456
+ for (int i = 0; i < count; i++) {
457
+ auto telemVariable = _getTelemetryVarByIndex(env, i);
458
+ if (telemVariable.IsObject() && telemVariable.Has("name")) {
459
+ telemVars.Set(telemVariable.Get("name"), telemVariable);
460
+ }
461
+ }
462
+
463
+ return telemVars;
475
464
  }
476
465
 
477
- // ---------------------------
478
- // Helper functions
479
- // ---------------------------
480
- bool iRacingSdkNode::GetTelemetryBool(int aEntry, int aIndex)
466
+ Napi::Value iRacingSdkNode::_napi_getTelemetryTypes(const Napi::CallbackInfo& aInfo)
481
467
  {
482
- const irsdk_varHeader *headerVar = irsdk_getVarHeaderEntry(aEntry);
483
- return *(reinterpret_cast<bool const *>(_data + headerVar->offset) + aIndex);
468
+ auto env = aInfo.Env();
469
+ auto result = Napi::Object::New(env);
470
+
471
+ const int count = irsdk_getHeader()->numVars;
472
+ const irsdk_varHeader* varHeader;
473
+ for (int i = 0; i < count; i++) {
474
+ varHeader = irsdk_getVarHeaderEntry(i);
475
+ result.Set(varHeader->name, Napi::Number::New(env, varHeader->type));
476
+ }
477
+
478
+ return result;
484
479
  }
485
480
 
486
- int iRacingSdkNode::GetTelemetryInt(int aEntry, int aIndex)
481
+ // Helpers ---------------------------------------------------------------------
482
+ bool iRacingSdkNode::_getTelemetryBool(int aEntry, int aIndex)
487
483
  {
488
- // Each int is 4 bytes
489
- const irsdk_varHeader *headerVar = irsdk_getVarHeaderEntry(aEntry);
490
- return *(reinterpret_cast<int const *>(_data + headerVar->offset) + aIndex * 4);
484
+ const irsdk_varHeader* headerVar = irsdk_getVarHeaderEntry(aEntry);
485
+ return *(reinterpret_cast<bool const*>(_data + headerVar->offset) + aIndex);
491
486
  }
492
487
 
493
- float iRacingSdkNode::GetTelemetryFloat(int aEntry, int aIndex)
488
+ int iRacingSdkNode::_getTelemetryInt(int aEntry, int aIndex)
494
489
  {
495
- // Each float is 4 bytes
496
- const irsdk_varHeader *headerVar = irsdk_getVarHeaderEntry(aEntry);
497
- return *(reinterpret_cast<float const *>(_data + headerVar->offset) + aIndex * 4);
490
+ // Each int is 4 bytes
491
+ const irsdk_varHeader* headerVar = irsdk_getVarHeaderEntry(aEntry);
492
+ return *(reinterpret_cast<int const*>(_data + headerVar->offset) + aIndex * 4);
498
493
  }
499
494
 
500
- double iRacingSdkNode::GetTelemetryDouble(int aEntry, int aIndex)
495
+ float iRacingSdkNode::_getTelemetryFloat(int aEntry, int aIndex)
501
496
  {
502
- // Each double is 8 bytes
503
- const irsdk_varHeader *headerVar = irsdk_getVarHeaderEntry(aEntry);
504
- return *(reinterpret_cast<double const *>(_data + headerVar->offset) + aIndex * 8);
497
+ // Each float is 4 bytes
498
+ const irsdk_varHeader* headerVar = irsdk_getVarHeaderEntry(aEntry);
499
+ return *(reinterpret_cast<float const*>(_data + headerVar->offset) + aIndex * 4);
505
500
  }
506
501
 
507
- Napi::Object iRacingSdkNode::GetTelemetryVarByIndex(const Napi::Env aEnv, int aIndex)
502
+ double iRacingSdkNode::_getTelemetryDouble(int aEntry, int aIndex)
508
503
  {
509
- auto headerVar = irsdk_getVarHeaderEntry(aIndex);
510
- auto telemVar = Napi::Object::New(aEnv);
511
-
512
- // Create entry object
513
- telemVar.Set("countAsTime", headerVar->countAsTime);
514
- telemVar.Set("length", headerVar->count);
515
- telemVar.Set("name", headerVar->name);
516
- telemVar.Set("description", headerVar->desc);
517
- telemVar.Set("unit", headerVar->unit);
518
- telemVar.Set("varType", headerVar->type);
519
-
520
- int dataSize = headerVar->count * irsdk_VarTypeBytes[headerVar->type];
521
- auto entryVal = Napi::ArrayBuffer::New(aEnv, dataSize);
522
- memcpy(entryVal.Data(), this->_data + headerVar->offset, dataSize);
523
-
524
- telemVar.Set("value", entryVal);
525
- return telemVar;
504
+ // Each double is 8 bytes
505
+ const irsdk_varHeader* headerVar = irsdk_getVarHeaderEntry(aEntry);
506
+ return *(reinterpret_cast<double const*>(_data + headerVar->offset) + aIndex * 8);
526
507
  }
527
508
 
528
- Napi::Object iRacingSdkNode::GetTelemetryVar(const Napi::Env aEnv, const char *aVarName)
509
+ // TODO: This should return null if the var is not found.
510
+ Napi::Object iRacingSdkNode::_getTelemetryVarByName(const Napi::Env aEnv, const char* aVarName)
529
511
  {
530
- int varIndex = irsdk_varNameToIndex(aVarName);
531
- return this->GetTelemetryVarByIndex(aEnv, varIndex);
512
+ int varIndex = irsdk_varNameToIndex(aVarName);
513
+ return _getTelemetryVarByIndex(aEnv, varIndex);
532
514
  }
533
515
 
516
+ // TODO: This should return null if the var is not found.
517
+ Napi::Object iRacingSdkNode::_getTelemetryVarByIndex(const Napi::Env aEnv, int aIndex)
518
+ {
519
+ auto headerVar = irsdk_getVarHeaderEntry(aIndex);
520
+ auto telemVar = Napi::Object::New(aEnv);
521
+
522
+ // Create entry object
523
+ telemVar.Set("countAsTime", headerVar->countAsTime);
524
+ telemVar.Set("length", headerVar->count);
525
+ telemVar.Set("name", headerVar->name);
526
+ telemVar.Set("description", headerVar->desc);
527
+ telemVar.Set("unit", headerVar->unit);
528
+ telemVar.Set("varType", headerVar->type);
529
+
530
+ int dataSize = headerVar->count * irsdk_VarTypeBytes[headerVar->type];
531
+ auto entryVal = Napi::ArrayBuffer::New(aEnv, dataSize);
532
+ memcpy(entryVal.Data(), _data + headerVar->offset, dataSize);
533
+
534
+ telemVar.Set("value", entryVal);
535
+ return telemVar;
536
+ }