44#include <QTemporaryFile>
66 const QVariantMap& graphInputs)
72 for (
auto it = graphInputs.constBegin(); it != graphInputs.constEnd(); ++it) {
73 ctx.
results.insert(QStringLiteral(
"graph::") + it.key(), it.value());
83 int sep = path.indexOf(QLatin1Char(
'/'));
85 QString nodeId = path.left(sep);
86 QString attrKey = path.mid(sep + 1);
95 const int total = order.size();
97 for (
int i = 0; i < total; ++i) {
98 const QString& nodeId = order[i];
100 if (s_progressCallback) {
101 s_progressCallback(nodeId, i + 1, total);
119 for (
auto it = outputs.constBegin(); it != outputs.constEnd(); ++it) {
120 ctx.
results.insert(nodeId + QStringLiteral(
"::") + it.key(), it.value());
124 n.
executedAt = QDateTime::currentDateTimeUtc();
140 QSet<QString> toExecute;
141 for (
const QString& nodeId : dirty) {
142 toExecute.insert(nodeId);
144 for (
const QString& d : downstream) {
152 for (
const QString& nodeId : fullOrder) {
153 if (toExecute.contains(nodeId)) {
154 order.append(nodeId);
158 const int total = order.size();
160 for (
int i = 0; i < total; ++i) {
161 const QString& nodeId = order[i];
163 if (s_progressCallback) {
164 s_progressCallback(nodeId, i + 1, total);
173 inputs.insert(p.
name, existing.
results.value(key));
179 for (
auto it = outputs.constBegin(); it != outputs.constEnd(); ++it) {
180 existing.
results.insert(nodeId + QStringLiteral(
"::") + it.key(), it.value());
184 n.
executedAt = QDateTime::currentDateTimeUtc();
195 const QVariantMap& inputs)
201 outputs.insert(QStringLiteral(
"stderr"), QStringLiteral(
"Script execution not supported in WebAssembly build (QProcess unavailable)"));
202 outputs.insert(QStringLiteral(
"exit_code"), -1);
208 QString ext = QStringLiteral(
".txt");
209 if (script.
language == QLatin1String(
"python")) ext = QStringLiteral(
".py");
210 else if (script.
language == QLatin1String(
"shell")) ext = QStringLiteral(
".sh");
211 else if (script.
language == QLatin1String(
"r")) ext = QStringLiteral(
".R");
212 else if (script.
language == QLatin1String(
"matlab")) ext = QStringLiteral(
".m");
213 else if (script.
language == QLatin1String(
"octave")) ext = QStringLiteral(
".m");
214 else if (script.
language == QLatin1String(
"julia")) ext = QStringLiteral(
".jl");
217 QString code = script.
code;
218 for (
auto it = inputs.constBegin(); it != inputs.constEnd(); ++it) {
219 code.replace(QStringLiteral(
"{{") + it.key() + QStringLiteral(
"}}"),
220 it.value().toString());
223 code.replace(QStringLiteral(
"{{") + it.key() + QStringLiteral(
"}}"),
224 it.value().toString());
228 QTemporaryFile tempFile(QDir::tempPath() + QStringLiteral(
"/mna_script_XXXXXX") + ext);
230 if (!tempFile.open()) {
232 outputs.insert(QStringLiteral(
"stderr"), QStringLiteral(
"Failed to create temporary script file"));
233 outputs.insert(QStringLiteral(
"exit_code"), -1);
236 tempFile.write(code.toUtf8());
241 if (interpreter.isEmpty()) {
242 if (script.
language == QLatin1String(
"python")) interpreter = QStringLiteral(
"python3");
243 else if (script.
language == QLatin1String(
"shell")) interpreter = QStringLiteral(
"/bin/bash");
244 else if (script.
language == QLatin1String(
"r")) interpreter = QStringLiteral(
"Rscript");
245 else if (script.
language == QLatin1String(
"matlab")) interpreter = QStringLiteral(
"matlab");
246 else if (script.
language == QLatin1String(
"octave")) interpreter = QStringLiteral(
"octave");
247 else if (script.
language == QLatin1String(
"julia")) interpreter = QStringLiteral(
"julia");
251 args.append(tempFile.fileName());
254 process.start(interpreter, args);
255 process.waitForFinished(-1);
258 outputs.insert(QStringLiteral(
"stdout"), QString::fromUtf8(process.readAllStandardOutput()));
259 outputs.insert(QStringLiteral(
"stderr"), QString::fromUtf8(process.readAllStandardError()));
260 outputs.insert(QStringLiteral(
"exit_code"), process.exitCode());
270 outputs.insert(QStringLiteral(
"stderr"), QStringLiteral(
"IPC execution not supported in WebAssembly build (QProcess unavailable)"));
271 outputs.insert(QStringLiteral(
"exit_code"), -1);
280 QStringList resolvedArgs;
281 for (
const QString& arg : node.
ipcArgs) {
282 QString resolved = arg;
283 for (
auto it = inputs.constBegin(); it != inputs.constEnd(); ++it) {
284 resolved.replace(QStringLiteral(
"{{") + it.key() + QStringLiteral(
"}}"),
285 it.value().toString());
289 resolved.replace(QStringLiteral(
"{{") + it.key() + QStringLiteral(
"}}"),
290 it.value().toString());
292 resolvedArgs.append(resolved);
296 process.waitForFinished(-1);
299 outputs.insert(QStringLiteral(
"stdout"), QString::fromUtf8(process.readAllStandardOutput()));
300 outputs.insert(QStringLiteral(
"stderr"), QString::fromUtf8(process.readAllStandardError()));
301 outputs.insert(QStringLiteral(
"exit_code"), process.exitCode());
330 s_progressCallback = cb;
346 qWarning() <<
"MnaGraphExecutor::startStream - graph validation failed:" << errors;
356 int sep = path.indexOf(QLatin1Char(
'/'));
358 QString nodeId = path.left(sep);
359 QString attrKey = path.mid(sep + 1);
360 if (nodeId == n.id) {
370 QObject* plugin = factory(n.
opType);
372 qWarning() <<
"MnaGraphExecutor::startStream - factory returned nullptr for opType:" << n.
opType;
MnaOpRegistry class declaration — singleton catalog of operation schemas.
MnaGraph class declaration — directed acyclic graph of processing nodes.
MnaGraphExecutor class declaration — executes a computational graph.
MNE Analysis Container Format (mna/mnx).
@ Ipc
Delegates to an external process via inter-process communication.
@ Script
Inline code executed via interpreter (Python, shell, R, …).
MnaNode & node(const QString &nodeId)
bool validate(QStringList *errors=nullptr) const
QStringList dirtyNodes() const
QStringList downstreamNodes(const QString &nodeId) const
MnaParamTree paramTree
Hierarchical parameter store with formula-driven bindings.
QList< MnaNode > & nodes()
QStringList topologicalSort() const
static void setProgressCallback(ProgressCallback cb)
static Context executeIncremental(MnaGraph &graph, Context &existing)
static StreamContext startStream(MnaGraph &graph, PluginFactory factory)
static QVariantMap executeNode(const MnaNode &node, const QVariantMap &inputs)
std::function< QObject *(const QString &opType)> PluginFactory
static void stopStream(StreamContext &ctx)
static Context execute(MnaGraph &graph, const QVariantMap &graphInputs)
std::function< void(const QString &nodeId, int current, int total)> ProgressCallback
Progress callback type.
QMap< QString, QVariant > results
nodeId::portName → data (QVariant wrapping domain objects or file paths)
QVariantMap graphInputs
Graph-level inputs (populated before execution).
QStringList executionOrder
Topological order used for startup/shutdown.
bool running
Whether the stream is active.
MnaGraph * graph
The pipeline graph (owned externally).
QMap< QString, QObject * > livePlugins
nodeId → live plugin instance (QObject* avoids scan dependency)
Graph node representing a processing step.
MnaNodeExecMode execMode
Execution mode.
QString ipcCommand
External executable command.
QStringList ipcArgs
Command-line arguments (supports {{placeholder}} tokens).
bool dirty
Whether node needs re-execution.
MnaScript script
Inline source code, interpreter, language.
QList< MnaPort > inputs
Input ports.
QVariantMap attributes
Operation parameters.
QDateTime executedAt
Timestamp of last execution.
QString opType
Operation type (looked up in MnaOpRegistry).
QString ipcWorkDir
Working directory for external process.
QList< MnaPort > outputs
Output ports.
Operation registry for the MNA graph model.
static MnaOpRegistry & instance()
OpFunc opFunc(const QString &opType) const
std::function< QVariantMap(const QVariantMap &inputs, const QVariantMap &attributes)> OpFunc
Operation implementation callback type.
QStringList evaluate(const QMap< QString, QVariant > &results)
QStringList allPaths() const
QVariant param(const QString &path) const
QString name
Port name (unique within a node).
QString sourcePortName
Which output port on that node?
QString cachedResultPath
Relative path to cached result.
QString sourceNodeId
Which node produces this input? (empty → graph-level input).
Inline code for script-type graph nodes.
bool keepTempFile
true → preserve temp script file after execution (debug aid)
QString code
The inline source code (resolved at save-time if sourceUri is set).
QString language
"python", "shell", "r", "matlab", "octave", "julia"
QStringList interpreterArgs
Extra args before the script file (e.g. ["-u"] for unbuffered Python).