@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.
- package/LICENSE +21 -0
- package/binding.gyp +2 -2
- package/dist/cjs/index.cjs +3 -0
- package/dist/esm/index.js +3 -0
- package/dist/types/INativeSDK.d.ts +3 -2
- package/dist/types/MockSdk.d.ts +1 -0
- 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 +405 -402
- package/lib/irsdk_node.h +96 -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,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
|
-
|
|
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
|
+
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
|
-
|
|
78
|
+
_logger.debug("StartSdk: Attempting to connect to SDK");
|
|
68
79
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
76
|
-
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
77
87
|
|
|
78
|
-
|
|
88
|
+
return true;
|
|
79
89
|
}
|
|
80
90
|
|
|
81
91
|
void iRacingSdkNode::shutdown()
|
|
82
92
|
{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
170
|
+
_logger.debug("Resetting cached data...\n");
|
|
177
171
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
172
|
+
if (_data)
|
|
173
|
+
delete[] _data;
|
|
174
|
+
_data = NULL;
|
|
175
|
+
_sessionData = NULL;
|
|
176
|
+
_lastSessionCt = -1;
|
|
182
177
|
|
|
183
|
-
|
|
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
|
|
186
|
+
Napi::Value iRacingSdkNode::_napi_prop_getCurrSessionDataVer(const Napi::CallbackInfo& aInfo)
|
|
192
187
|
{
|
|
193
|
-
|
|
188
|
+
return Napi::Number::New(aInfo.Env(), _lastSessionCt);
|
|
194
189
|
}
|
|
195
190
|
|
|
196
|
-
Napi::Value iRacingSdkNode::_napi_prop_getEnableLogging(const Napi::CallbackInfo
|
|
191
|
+
Napi::Value iRacingSdkNode::_napi_prop_getEnableLogging(const Napi::CallbackInfo& aInfo)
|
|
197
192
|
{
|
|
198
|
-
|
|
199
|
-
|
|
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
|
|
197
|
+
void iRacingSdkNode::_napi_prop_setEnableLogging(const Napi::CallbackInfo& aInfo, const Napi::Value& aValue)
|
|
203
198
|
{
|
|
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");
|
|
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
|
|
210
|
+
Napi::Value iRacingSdkNode::_napi_prop_getLogLevel(const Napi::CallbackInfo& aInfo)
|
|
218
211
|
{
|
|
219
|
-
|
|
212
|
+
return Napi::Number::New(aInfo.Env(), _logger.logLevel);
|
|
220
213
|
}
|
|
221
214
|
|
|
222
|
-
void iRacingSdkNode::_napi_prop_setLogLevel(const Napi::CallbackInfo
|
|
215
|
+
void iRacingSdkNode::_napi_prop_setLogLevel(const Napi::CallbackInfo& aInfo, const Napi::Value& aValue)
|
|
223
216
|
{
|
|
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));
|
|
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
|
|
232
|
+
Napi::Value iRacingSdkNode::_napi_prop_getIsMocked(const Napi::CallbackInfo& aInfo)
|
|
242
233
|
{
|
|
243
|
-
|
|
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
|
|
241
|
+
Napi::Value iRacingSdkNode::_napi_startSdk(const Napi::CallbackInfo& aInfo)
|
|
252
242
|
{
|
|
253
|
-
|
|
243
|
+
return Napi::Boolean::New(aInfo.Env(), startup());
|
|
254
244
|
}
|
|
255
245
|
|
|
256
|
-
Napi::Value iRacingSdkNode::_napi_stopSdk(const Napi::CallbackInfo
|
|
246
|
+
Napi::Value iRacingSdkNode::_napi_stopSdk(const Napi::CallbackInfo& aInfo)
|
|
257
247
|
{
|
|
258
|
-
|
|
259
|
-
|
|
248
|
+
shutdown();
|
|
249
|
+
return Napi::Boolean::New(aInfo.Env(), true);
|
|
260
250
|
}
|
|
261
251
|
|
|
262
|
-
Napi::Value iRacingSdkNode::_napi_waitForData(const Napi::CallbackInfo
|
|
252
|
+
Napi::Value iRacingSdkNode::_napi_waitForData(const Napi::CallbackInfo& aInfo)
|
|
263
253
|
{
|
|
264
|
-
|
|
265
|
-
|
|
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
|
-
|
|
257
|
+
if (timeout < 16)
|
|
258
|
+
timeout = 16;
|
|
269
259
|
|
|
270
|
-
|
|
260
|
+
return Napi::Boolean::New(aInfo.Env(), waitForData(timeout));
|
|
271
261
|
}
|
|
272
262
|
|
|
273
|
-
Napi::Value iRacingSdkNode::_napi_broadcastMessage(const Napi::CallbackInfo
|
|
263
|
+
Napi::Value iRacingSdkNode::_napi_broadcastMessage(const Napi::CallbackInfo& aInfo)
|
|
274
264
|
{
|
|
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);
|
|
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
|
|
380
|
+
Napi::Value iRacingSdkNode::_napi_isRunning(const Napi::CallbackInfo& aInfo)
|
|
396
381
|
{
|
|
397
|
-
|
|
382
|
+
return Napi::Boolean::New(aInfo.Env(), isConnected());
|
|
398
383
|
}
|
|
399
384
|
|
|
400
|
-
Napi::Value iRacingSdkNode::_napi_getSessionVersionNum(const Napi::CallbackInfo
|
|
385
|
+
Napi::Value iRacingSdkNode::_napi_getSessionVersionNum(const Napi::CallbackInfo& aInfo)
|
|
401
386
|
{
|
|
402
|
-
|
|
387
|
+
return Napi::Number::New(aInfo.Env(), getSessionInfoStrCount());
|
|
403
388
|
}
|
|
404
389
|
|
|
405
|
-
Napi::Value iRacingSdkNode::_napi_getSessionConnectionID(const Napi::CallbackInfo
|
|
390
|
+
Napi::Value iRacingSdkNode::_napi_getSessionConnectionID(const Napi::CallbackInfo& aInfo)
|
|
406
391
|
{
|
|
407
|
-
|
|
392
|
+
return Napi::Number::New(aInfo.Env(), _sessionStatusID);
|
|
408
393
|
}
|
|
409
394
|
|
|
410
|
-
Napi::Value iRacingSdkNode::_napi_getSessionData(const Napi::CallbackInfo
|
|
395
|
+
Napi::Value iRacingSdkNode::_napi_getSessionData(const Napi::CallbackInfo& aInfo)
|
|
411
396
|
{
|
|
412
|
-
|
|
397
|
+
auto session = getSessionStr();
|
|
413
398
|
|
|
414
|
-
|
|
415
|
-
|
|
399
|
+
if (session == NULL)
|
|
400
|
+
return Napi::String::New(aInfo.Env(), "");
|
|
416
401
|
|
|
417
|
-
|
|
402
|
+
return Napi::String::New(aInfo.Env(), session);
|
|
418
403
|
}
|
|
419
404
|
|
|
420
|
-
Napi::Value iRacingSdkNode::
|
|
405
|
+
Napi::Value iRacingSdkNode::_napi_getTelemetryVar(const Napi::CallbackInfo& aInfo)
|
|
421
406
|
{
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
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::
|
|
434
|
+
Napi::Value iRacingSdkNode::_napi_getTelemetryVarIndex(const Napi::CallbackInfo& aInfo)
|
|
442
435
|
{
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
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
|
-
|
|
461
|
-
Napi::Value iRacingSdkNode::_napi_getTelemetryTypes(const Napi::CallbackInfo &aInfo)
|
|
449
|
+
Napi::Value iRacingSdkNode::_napi_getTelemetryData(const Napi::CallbackInfo& aInfo)
|
|
462
450
|
{
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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
|
-
|
|
483
|
-
|
|
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
|
-
|
|
481
|
+
// Helpers ---------------------------------------------------------------------
|
|
482
|
+
bool iRacingSdkNode::_getTelemetryBool(int aEntry, int aIndex)
|
|
487
483
|
{
|
|
488
|
-
|
|
489
|
-
|
|
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
|
-
|
|
488
|
+
int iRacingSdkNode::_getTelemetryInt(int aEntry, int aIndex)
|
|
494
489
|
{
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
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
|
-
|
|
495
|
+
float iRacingSdkNode::_getTelemetryFloat(int aEntry, int aIndex)
|
|
501
496
|
{
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
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
|
-
|
|
502
|
+
double iRacingSdkNode::_getTelemetryDouble(int aEntry, int aIndex)
|
|
508
503
|
{
|
|
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;
|
|
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
|
-
|
|
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
|
-
|
|
531
|
-
|
|
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
|
+
}
|