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