8000 Added `persistent` mode for `Python` component. · totaljs/flowstreamcomponents@6bf43b7 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6bf43b7

Browse files
committed
Added persistent mode for Python component.
1 parent bea06ec commit 6bf43b7

File tree

1 file changed

+84
-11
lines changed

1 file changed

+84
-11
lines changed

components/python.html

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,22 @@
66
exports.version = '2';
77
exports.icon = 'ti ti-script';
88
exports.author = 'Total.js';
9-
exports.config = { code: '# Python code\nimport sys\nimport json\n\ndata = json.loads(sys.argv[1])\n\nprint(data)', json: true };
9+
exports.config = { code: `# Python code
10+
import sys
11+
import json
12+
13+
# For non-persistent data:
14+
data = json.loads(sys.argv[1])
15+
print(data)
16+
17+
# Or for persistent data:
18+
while True:
19+
\tline = sys.stdin.readline().strip()
20+
\tif not line:
21+
\t\tbreak
22+
\tprint(line)
23+
\tsys.stdout.flush()
24+
`, json: true, persistent: false };
1025
exports.inputs = [{ id: 'input', name: 'Input' }];
1126
exports.outputs = [{ id: 'output', name: 'Output' }, { id: 'error', name: 'Error' }];
1227
exports.meta = { settingswidth: 1200 };
@@ -18,6 +33,7 @@
1833
exports.make = function(instance, config) {
1934

2035
var filename = PATH.temp(instance.id + '.py');
36+
var spawned = null;
2137

2238
instance.message = function($) {
2339

@@ -26,18 +42,67 @@
2642
return;
2743
}
2844

29-
F.Child.execFile('python3', [filename, JSON.stringify($.data)], function(err, response, error) {
30-
if (err) {
31-
$.send('error', error || err);
32-
} else {
33-
$.send('output', config.json ? response.parseJSON(true) : response);
34-
}
35-
});
45+
if (config.persistent) {
46+
if (spawned)
47+
spawned.stdin.write(JSON.stringify($.data) + '\n');
48+
$.destroy();
49+
} else {
50+
F.Child.execFile('python3', [filename, JSON.stringify($.data)], function(err, response, error) {
51+
if (err) {
52+
$.send('error', error || err);
53+
} else {
54+
$.send('output', config.json ? response.parseJSON(true) : response);
55+
}
56+
});
57+
}
3658
};
3759

3860
instance.configure = function() {
61+
3962
if (config.code)
4063
F.Fs.writeFile(filename, config.code, err => err && instance.throw(err));
64+
65+
let ready = false;
66+
let prev = spawned;
67+
68+
if (spawned) {
69+
spawned.removeAllListeners('close');
70+
spawned.removeAllListeners('error');
71+
spawned.kill(9);
72+
}
73+
74+
if (config.persistent && config.code) {
75+
76+
spawned = F.Child.spawn('python3', [filename], { stdio: ['pipe', 'pipe', process.stderr] });//, { stdio: 'inherit' }
77+
78+
spawned.on('error', function(err) {
79+
instance.newmessage(err.toString()).send('error');
80+
});
81+
82+
spawned.stdout.on('data', function(chunk) {
83+
let text = chunk.toString('utf8');
84+
if (config.json)
85+
instance.newmessage(text.parseJSON(true)).send('output');
86+
else
87+
instance.newmessage(text).send('output');
88+
});
89+
90+
spawned.on('close', function(code) {
91+
if (this == spawned)
92+
spawned = null;
93+
instance.status('Exited: ' + code);
94+
});
95+
96+
instance.status('Running');
97+
98+
} else if (spawned) {
99+
spawned.kill(9);
100+
spawned = null;
101+
ready = true;
102+
} else
103+
ready = true;
104+
105+
ready && instance.status('Ready');
41106
};
42107

43108
instance.configure();
@@ -47,18 +112,26 @@
47112
</script>
48113

49114
<readme>
50-
This component executes a custom Python code as it is.
115+
This component executes custom Python code as is. The input data must be a serializable JSON object. Non-persistent mode evaluates the Python code for each input.
116+
117+
The persistent mode can include an HTTP server or an infinite loop. Input data is sent to the `stdin` stream in serialized JSON format.
118+
119+
> __Good to know__: The output message in persistent mode doesn't container the previous message reference.
51120
</readme>
52121

53122
<settings>
54123
<div class="padding">
55-
<ui-component name="codemirror" path="?.code" config="type:python;minheight:300;parent:auto;margin:80;tabs:true;trim:true" class="m"></ui-component>
124+
<ui-component name="codemirror" path="?.code" config="type:python;minheight:300;parent:auto;margin:100;tabs:true;trim:true" class="m"></ui-component>
56125
<ui-component name="input" path="?.json" config="type:checkbox">Parse output to JSON</ui-component>
126+
<ui-component name="input" path="?.persistent" config="type:checkbox">Run the script as a persistent process</ui-component>
57127
</div>
58128
</settings>
59129

60130
<body>
61131
<header>
62-
<i class="ICON"></i>NAME
132+
<i class="$ICON"></i>$NAME
63133
</header>
134+
<footer style="padding:10px" class="fs12">
135+
<ui-bind path="$STATUS" config="text;empty" child="b" class="block">Status: <b></b></ui-bind>
136+
</footer>
64137
</body>

0 commit comments

Comments
 (0)
0