* @brief Runs the script's optional onConnect() hook synchronously BEFORE the connection opens, * so a control script can launch a server (TCP/Modbus) that Serial Studio then connects * to as a client. Uses a throwaway GUI-thread engine where apiCall dispatches inline, so * there is no deadlock with the connect path that called this. */
| 208 | * there is no deadlock with the connect path that called this. |
| 209 | */ |
| 210 | void DataModel::ControlScript::runOnConnect() |
| 211 | { |
| 212 | if (m_shutdown || m_code.trimmed().isEmpty() || SerialStudio::isAnyPlayerOpen() |
| 213 | || AppState::instance().operationMode() != SerialStudio::ProjectFile) |
| 214 | return; |
| 215 | |
| 216 | QJSEngine engine; |
| 217 | engine.installExtensions(QJSEngine::ConsoleExtension | QJSEngine::GarbageCollectionExtension); |
| 218 | DataModel::ScriptApiCall::installAll(&engine, 0); |
| 219 | |
| 220 | DataModel::JsWatchdog watchdog(&engine, 2000, QStringLiteral("Control script onConnect")); |
| 221 | watchdog.arm(); |
| 222 | const auto evaluated = engine.evaluate(m_code, QStringLiteral("control-script.js")); |
| 223 | watchdog.disarm(); |
| 224 | if (engine.isInterrupted()) |
| 225 | engine.setInterrupted(false); |
| 226 | |
| 227 | if (evaluated.isError()) |
| 228 | return; |
| 229 | |
| 230 | QJSValue onConnectFn = engine.globalObject().property(QStringLiteral("onConnect")); |
| 231 | if (!onConnectFn.isCallable()) |
| 232 | return; |
| 233 | |
| 234 | const QJSValue result = watchdog.call(onConnectFn, QJSValueList()); |
| 235 | if (result.isError()) |
| 236 | Q_EMIT error(QStringLiteral("onConnect() line %1: %2") |
| 237 | .arg(result.property(QStringLiteral("lineNumber")).toInt()) |
| 238 | .arg(result.toString())); |
| 239 | } |
| 240 | |
| 241 | //-------------------------------------------------------------------------------------------------- |
| 242 | // Lifecycle |
no test coverage detected