linny-r 1.4.1 → 1.4.3
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/README.md +69 -35
- package/package.json +1 -1
- package/server.js +114 -43
- package/static/images/octaeder.svg +993 -0
- package/static/index.html +22 -617
- package/static/linny-r.css +32 -378
- package/static/scripts/linny-r-ctrl.js +59 -5
- package/static/scripts/linny-r-gui.js +198 -56
- package/static/scripts/linny-r-model.js +127 -41
- package/static/scripts/linny-r-utils.js +32 -11
- package/static/scripts/linny-r-vm.js +40 -14
package/README.md
CHANGED
@@ -25,7 +25,7 @@ Technical documentation will be developed on GitHub: https://github.com/pwgbots/
|
|
25
25
|
Linny-R is developed as a JavaScript package, and requires that **Node.js** is installed on your computer.
|
26
26
|
This software can be downloaded from <a href="https://nodejs.org" target="_blank">https://nodejs.org</a>.
|
27
27
|
Make sure that you choose the correct installer for your computer.
|
28
|
-
Linny-R is developed using the _current_ release. Presently (
|
28
|
+
Linny-R is developed using the _current_ release. Presently (August 2023) this is 20.5.1.
|
29
29
|
|
30
30
|
Run the installer and accept the default settings.
|
31
31
|
There is **no** need to install the optional _Tools for Native Modules_.
|
@@ -36,33 +36,33 @@ Verify the installation by typing:
|
|
36
36
|
|
37
37
|
``node --version``
|
38
38
|
|
39
|
-
The response should be the version number of Node.js, for example: v20.
|
39
|
+
The response should be the version number of Node.js, for example: v20.5.1.
|
40
40
|
|
41
41
|
## Installing Linny-R
|
42
42
|
It is advisable to install Linny-R in a directory on your computer, not in a cloud.
|
43
|
-
In this installation guide, the path to this directory is denoted by `
|
43
|
+
In this installation guide, the path to this directory is denoted by `Linny-R`,
|
44
44
|
so in all commands you should replace this with the actual directory path.
|
45
|
-
On a Windows machine
|
46
|
-
and on a macOS machine
|
45
|
+
On a Windows machine the suggested path is `C:\Users\(your user name)\Documents\Linny-R`,
|
46
|
+
and on a macOS machine `/Users/(your user name)/Linny-R`.
|
47
47
|
|
48
48
|
To install Linny-R in this directory, first create it:
|
49
49
|
|
50
|
-
``mkdir
|
50
|
+
``mkdir Linny-R``
|
51
51
|
|
52
52
|
then change to it:
|
53
53
|
|
54
|
-
``cd
|
54
|
+
``cd Linny-R``
|
55
55
|
|
56
56
|
and then type at the command line prompt:
|
57
57
|
|
58
58
|
``npm install --prefix . linny-r``
|
59
59
|
|
60
|
-
**NOTE:** The spacing around the dot is important.
|
60
|
+
**NOTE:** The spacing around the dot is important. Type the command in lower case.
|
61
61
|
|
62
|
-
After installation has completed, `
|
62
|
+
After installation has completed, `Linny-R` should have this directory tree structure:
|
63
63
|
|
64
64
|
<pre>
|
65
|
-
|
65
|
+
Linny-R
|
66
66
|
|
|
67
67
|
+-node_modules
|
68
68
|
|
|
@@ -81,7 +81,7 @@ WORKING_DIRECTORY
|
|
81
81
|
+-sounds
|
82
82
|
</pre>
|
83
83
|
|
84
|
-
`
|
84
|
+
`Linny-R` should contain two JSON files `package.json` and `package-lock.json`
|
85
85
|
that should **not** be removed, or you will have to re-install Linny-R. It should also contain
|
86
86
|
a script file to facilitate (single click) launch: on a macOS machine the shell script `linny-r.command`,
|
87
87
|
on a Windows machine the batch script `linny-r.bat`. By default, this script file contains
|
@@ -109,17 +109,18 @@ The sub-directories of `static` contain files that are served to the browser by
|
|
109
109
|
|
110
110
|
## Configuring the MILP solver
|
111
111
|
|
112
|
-
Linny-R presently supports
|
113
|
-
Gurobi
|
114
|
-
but
|
112
|
+
Linny-R presently supports four MILP solvers: Gurobi, CPLEX, SCIP and LP_solve.
|
113
|
+
Gurobi and CPLEX are _considerably_ more powerful than the open source solvers SCIP and LP_solve,
|
114
|
+
but they require a license.
|
115
115
|
Academic licenses can be obtained by students and staff of eligible institutions.
|
116
116
|
|
117
117
|
#### Installing Gurobi
|
118
118
|
|
119
|
-
The software you need to install is
|
119
|
+
The software you need to install is **Gurobi Optimizer**.
|
120
120
|
More information on how to obtain a license, and instructions for installing
|
121
121
|
Gurobi on your computer can be obtained via this URL:
|
122
|
-
https://www.gurobi.com/academia/academic-program-and-licenses/
|
122
|
+
<a href="https://www.gurobi.com/academia/academic-program-and-licenses/"
|
123
|
+
target="_blank">https://www.gurobi.com/academia/academic-program-and-licenses/</a>
|
123
124
|
|
124
125
|
When running a model, Linny-R will try to execute the command line application `gurobi_cl`.
|
125
126
|
It will look for this application in the directory specified in the environment variable PATH on your computer.
|
@@ -127,23 +128,51 @@ It will look for this application in the directory specified in the environment
|
|
127
128
|
When installing Gurobi, please accept the default file locations that are proposed by the installer.
|
128
129
|
Then do **not** move Gurobi files to some other directory, as this is bound to cause problems.
|
129
130
|
|
131
|
+
#### Installing CPLEX
|
132
|
+
|
133
|
+
The software you need to install is **CPLEX**.
|
134
|
+
More information on how to obtain a license, and instructions for installing
|
135
|
+
CPLEX on your computer can be obtained via this URL:
|
136
|
+
<a href="https://www.ibm.com/products/ilog-cplex-optimization-studio"
|
137
|
+
target="_blank">https://www.ibm.com/products/ilog-cplex-optimization-studio</a>
|
138
|
+
|
139
|
+
When running a model, Linny-R will try to execute the command line application `cplex`.
|
140
|
+
It will look for this application in the directory specified in the environment variable PATH
|
141
|
+
or more specifically in the environment variable CPLEX_STUDIO_BINARIES<em>nnnn</em>
|
142
|
+
(where _nnnn_ denotes the CPLEX version number) on your computer.
|
143
|
+
|
144
|
+
When installing CPLEX, please accept the default file locations that are proposed by the installer.
|
145
|
+
Then do **not** move CPLEX files to some other directory, as this is bound to cause problems.
|
146
|
+
|
147
|
+
#### Installing SCIP
|
148
|
+
|
149
|
+
The SCIP software is open source. Instructions for installation can be found via this URL:
|
150
|
+
<a href="https://scipopt.org/doc/html/INSTALL.php" target="_blank">https://scipopt.org/doc/html/INSTALL.php</a>
|
151
|
+
|
152
|
+
When running a model, Linny-R will try to execute the command line application `scip`.
|
153
|
+
It will look for this application in the directory specified in the environment variable PATH on your computer.
|
154
|
+
|
155
|
+
When installing SCIP, please accept the default file locations that are proposed by the installer.
|
156
|
+
Then do **not** move SCIP files to some other directory, as this is bound to cause problems.
|
157
|
+
|
130
158
|
#### Installing LP_solve
|
131
159
|
|
132
160
|
The LP_solve software is open source and can be downloaded via this URL:
|
133
|
-
https://sourceforge.net/projects/lpsolve
|
161
|
+
<a href="https://sourceforge.net/projects/lpsolve" target="_blank">https://sourceforge.net/projects/lpsolve</a>
|
134
162
|
|
135
|
-
To facilitate installation, the executable files for Windows and macOS can be downloaded from the Linny-R website
|
136
|
-
|
163
|
+
To facilitate installation, the executable files for Windows and macOS can be downloaded from the Linny-R website
|
164
|
+
at Delft University of Technology:
|
165
|
+
<a href="https://sysmod.tbm.tudelft.nl/linny-r/lp_solve" target="_blank">https://sysmod.tbm.tudelft.nl/linny-r/lp_solve</a>
|
137
166
|
|
138
167
|
There you will find links to download LP_solve applications that have been compiled for different platforms.
|
139
168
|
If you do not know which platform to choose, run Linny-R as described below, and the platform will be listed in its output.
|
140
169
|
If no matching LP_solve version is listed, you can try to compile the software from its source.
|
141
170
|
How to do this is explained on the page "Installing LP_solve on a Mac" on the Linny-R documentation site:
|
142
|
-
https://linny-r.info
|
171
|
+
<a href="https://linny-r.info" target="_blank">https://linny-r.info</a>
|
143
172
|
|
144
173
|
When you have downloaded the file (just `lp_solve` for macOS, `lp_solve.exe` for Windows),
|
145
|
-
you must copy or move this file to your `
|
146
|
-
as this is where Linny-R will look for it when it does not find
|
174
|
+
you must copy or move this file to your `Linny-R` directory,
|
175
|
+
as this is where Linny-R will look for it when it does not find one of the other solvers.
|
147
176
|
|
148
177
|
On a macOS machine, you must then make the file `lp_solve` executable.
|
149
178
|
Open Terminal and change to your Linny-R directory, and then type:
|
@@ -163,15 +192,15 @@ If you reach this stage, Linny-R will be able to run LP_solve.
|
|
163
192
|
|
164
193
|
## Running Linny-R
|
165
194
|
|
166
|
-
Open the Command Line Interface (CLI) of your computer, change to your
|
195
|
+
Open the Command Line Interface (CLI) of your computer, change to your Linny-R directory and type:
|
167
196
|
|
168
197
|
``node node_modules/linny-r/server launch``
|
169
198
|
|
170
199
|
This response should be something similar to:
|
171
200
|
|
172
201
|
<pre>
|
173
|
-
Node.js server for Linny-R version 1.2
|
174
|
-
Node.js version: v20.
|
202
|
+
Node.js server for Linny-R version 1.4.2
|
203
|
+
Node.js version: v20.5.1
|
175
204
|
... etc.
|
176
205
|
</pre>
|
177
206
|
|
@@ -181,9 +210,9 @@ The Linny-R GUI should show in your browser window,
|
|
181
210
|
while in the CLI you should see a long series of server log messages like:
|
182
211
|
|
183
212
|
<pre>
|
184
|
-
[2023-
|
185
|
-
[2023-
|
186
|
-
[2023-
|
213
|
+
[2023-08-29 22:55:17] Static file: /index.html
|
214
|
+
[2023-08-29 22:55:17] Static file: /scripts/iro.min.js
|
215
|
+
[2023-08-29 22:55:17] Static file: /images/open.png
|
187
216
|
... etc.
|
188
217
|
</pre>
|
189
218
|
|
@@ -222,7 +251,7 @@ Optionally, you can add more arguments to the `node` command:
|
|
222
251
|
dpi=[number] to overrule the default resolution (300 dpi) for Inkscape
|
223
252
|
launch to automatically launch Linny-R in your default browser
|
224
253
|
port=[number] to overrule the default port number (5050)
|
225
|
-
solver=[name] to overrule the default sequence (Gurobi, LP_solve)
|
254
|
+
solver=[name] to overrule the default sequence (Gurobi, CPLEX, SCIP, LP_solve)
|
226
255
|
workspace=[path] to overrule the default path for the user directory
|
227
256
|
</pre>
|
228
257
|
|
@@ -237,14 +266,14 @@ The dialog that then appears will allow you to go to the sub-folder `node_module
|
|
237
266
|
where you should select the file `linny-r.ico`.
|
238
267
|
Finally, rename the shortcut to `Linny-R` and move or copy it to your desktop.
|
239
268
|
|
240
|
-
On a macOS machine, open
|
269
|
+
On a macOS machine, open Terminal and change to your Linny-R directory, and then type:
|
241
270
|
|
242
271
|
``chmod +x linny-r.command``
|
243
272
|
|
244
273
|
to make the script file executable.
|
245
|
-
To set the icon, open the folder that contains the file `linny-r.command`,
|
274
|
+
To set the icon, use Finder to open the folder that contains the file `linny-r.command`,
|
246
275
|
click on its icon (which still is plain) and open the _Info dialog_ by pressing ``Cmd+I``.
|
247
|
-
Then open your Linny-R folder in
|
276
|
+
Then open your Linny-R folder in Finder, change to the sub-folder `node_modules/linny-r/static/images`,
|
248
277
|
and from there drag/drop the file `linny-r.icns` on the icon shown in the top left corner of the _Info dialog_.
|
249
278
|
|
250
279
|
## User workspace
|
@@ -254,13 +283,17 @@ The sub-directories of this directory `user` are used by Linny-R to store files.
|
|
254
283
|
|
255
284
|
* `autosave` will contain models that have been _auto-saved_
|
256
285
|
* `channel` and `callback` will be used to interact with Linny-R via its _Receiver_
|
286
|
+
* `data` will be used by the _Dataset Manager_ to locate datasets for which a path
|
287
|
+
has been specified
|
257
288
|
* `diagrams` will be used to render Scalable Vector Graphics (SVG) files as
|
258
289
|
Portable Network Graphics (PNG) using Inkscape (if installed)
|
259
290
|
* `modules` will contain models stored in the `local host` _repository_
|
291
|
+
* `reports` will contain text files with time series data and statistics in tab-separated
|
292
|
+
format that can be imported or copy/pasted into Excel
|
260
293
|
* `solver` will contain the files that are exchanged with the Mixed Integer Linear Programming (MILP) solver
|
261
294
|
(the names of the files that will appear in this directory may vary, depending on the MILP-solver you use)
|
262
295
|
|
263
|
-
By default, the `user` directory is created in your `
|
296
|
+
By default, the `user` directory is created in your `Linny-R` directory.
|
264
297
|
You can overrule this by specifying the path to another directory when you start the server.
|
265
298
|
Note that doing this will create a new, empty workspace (the directories listed above)
|
266
299
|
in the specified path. It will **not** affect or duplicate information from existing workspaces.
|
@@ -281,7 +314,8 @@ Meanwhile, the browser will have opened a new tab that will be "waiting" for thi
|
|
281
314
|
If rendering was successful, the image will appear in this browser tab;
|
282
315
|
if rendering failed, the original SVG image will be shown.
|
283
316
|
|
284
|
-
To install Inkscape, please look here:
|
317
|
+
To install Inkscape, please look here:
|
318
|
+
<a href="https://inkscape.org/release" target="_blank">https://inkscape.org/release</a>
|
285
319
|
|
286
320
|
Linny-R will automatically detect whether Inkscape is installed by searching for it in the environment variable PATH on your computer.
|
287
321
|
On a macOS computer, Linny-R will look for Inkscape in /Applications/Inkscape.app/Contents/MacOS.
|
@@ -293,7 +327,7 @@ Please check whether you need to do this yourself.
|
|
293
327
|
|
294
328
|
The console-only version of Linny-R allows you to run a Linny-R model without a web browser.
|
295
329
|
This may be useful when you want run models from a script (shell script, Python, ...).
|
296
|
-
If you open a CLI box, change to your `
|
330
|
+
If you open a CLI box, change to your `Linny-R` directory, and then type:
|
297
331
|
|
298
332
|
``node node_modules/linny-r/console`` _(on Windows, use backslashes)_
|
299
333
|
|
package/package.json
CHANGED
package/server.js
CHANGED
@@ -87,9 +87,10 @@ function getVersionInfo() {
|
|
87
87
|
info.current_time = new Date(Date.parse(obj.time[info.current]));
|
88
88
|
info.up_to_date = info.current === info.latest;
|
89
89
|
} catch(err) {
|
90
|
-
// `latest` = 0 indicates that version check failed
|
90
|
+
// `latest` = 0 indicates that version check failed.
|
91
91
|
info.latest = 0;
|
92
92
|
}
|
93
|
+
clearNewerVersion();
|
93
94
|
if(!info.latest) {
|
94
95
|
console.log(connectionErrorText('Could not connect to https://registry.npmjs.org/'));
|
95
96
|
} else if(!info.up_to_date) {
|
@@ -145,12 +146,13 @@ const SOLVER = new MILPSolver(SETTINGS, WORKSPACE);
|
|
145
146
|
// Create launch script
|
146
147
|
createLaunchScript();
|
147
148
|
|
148
|
-
// Create the HTTP server
|
149
|
+
// Create the HTTP server.
|
149
150
|
const SERVER = http.createServer((req, res) => {
|
150
151
|
const u = new URL(req.url, 'http://127.0.0.1:' + SETTINGS.port);
|
151
|
-
// When POST, first get all the full body
|
152
|
+
// When POST, first get all the full body.
|
152
153
|
if(req.method === 'POST') {
|
153
154
|
let body = '';
|
155
|
+
// @@TO DO: For big data requests, string may become too long.
|
154
156
|
req.on('data', (data) => body += data);
|
155
157
|
req.on('end', () => processRequest(req, res, u.pathname, body));
|
156
158
|
} else if(req.method === 'GET') {
|
@@ -198,7 +200,7 @@ function logAction(msg) {
|
|
198
200
|
|
199
201
|
function autoCheck(res) {
|
200
202
|
// Serves a string with the current version number plus info on a
|
201
|
-
// newer release if this is available
|
203
|
+
// newer release if this is available.
|
202
204
|
let check = VERSION_INFO.current + '|';
|
203
205
|
if(VERSION_INFO.up_to_date) {
|
204
206
|
check += 'up-to-date';
|
@@ -208,22 +210,46 @@ function autoCheck(res) {
|
|
208
210
|
servePlainText(res, check);
|
209
211
|
}
|
210
212
|
|
211
|
-
|
213
|
+
function setNewerVersion() {
|
214
|
+
// Creates the file "newer_version" in the working directory, so that
|
215
|
+
// when the server is run from the standard batch script it will detect
|
216
|
+
// that an update is required.
|
217
|
+
const nvf = path.join(WORKING_DIRECTORY, 'newer_version');
|
218
|
+
try {
|
219
|
+
fs.writeFileSync(nvf, VERSION_INFO.latest);
|
220
|
+
} catch(err) {
|
221
|
+
console.log('WARNING: Failed to create file:', nvf);
|
222
|
+
console.log(err);
|
223
|
+
}
|
224
|
+
}
|
225
|
+
|
226
|
+
function clearNewerVersion() {
|
227
|
+
// Forestalls auto-update by deleting the file "newer_version" that may
|
228
|
+
// have been created at start-up from the working directory.
|
229
|
+
try {
|
230
|
+
fs.unlink(path.join(WORKING_DIRECTORY, 'newer_version'));
|
231
|
+
} catch(err) {
|
232
|
+
// No action, as error is nogt fatal.
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
236
|
+
// HTML page to show when the server is shut down by the user.
|
212
237
|
// NOTE: on a macOS machine, this is slightly more work
|
213
|
-
const
|
214
|
-
|
238
|
+
const OS_TEXT = {close: '', reopen: ''};
|
239
|
+
if(PLATFORM === 'darwin') {
|
240
|
+
OS_TEXT.close =
|
215
241
|
`<p>You can close the <em>Terminal</em> window that shows
|
216
242
|
<tt>[Process Terminated]</tt> at the bottom.
|
217
|
-
</p
|
243
|
+
</p>`;
|
244
|
+
OS_TEXT.reopen =
|
218
245
|
`open <em>Terminal</em> again, change to your Linny-R directory by typing:
|
219
246
|
</p>
|
220
247
|
<p><code>cd ${WORKING_DIRECTORY}</code></p>
|
221
|
-
<p
|
222
|
-
|
223
|
-
''
|
224
|
-
|
225
|
-
|
226
|
-
SHUTDOWN_MESSAGE = `<!DOCTYPE html>
|
248
|
+
<p>`;
|
249
|
+
} else {
|
250
|
+
OS_TEXT.reopen = 'switch to your <em>Command Prompt</em> window ';
|
251
|
+
}
|
252
|
+
const SHUTDOWN_MESSAGE = `<!DOCTYPE html>
|
227
253
|
<html lang="en-US">
|
228
254
|
<head>
|
229
255
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
@@ -243,13 +269,8 @@ const
|
|
243
269
|
</style>
|
244
270
|
</head>
|
245
271
|
<body>
|
246
|
-
<h3>Linny-R server (127.0.0.1) is shutting down</h3
|
247
|
-
<p>To restart Linny-R,
|
248
|
-
(VERSION_INFO.up_to_date ? '' : `
|
249
|
-
first type:</p>
|
250
|
-
<p><code>npm update linny-r</code><p>
|
251
|
-
to upgrade to Linny-R version ${VERSION_INFO.latest}, and then`) +
|
252
|
-
` type:</p>
|
272
|
+
<h3>Linny-R server (127.0.0.1) is shutting down</h3>${OS_TEXT.close}
|
273
|
+
<p>To restart Linny-R, ${OS_TEXT.reopen} and then at the prompt type:</p>
|
253
274
|
<p><code>node node_modules${path.sep}linny-r${path.sep}server</code></p>
|
254
275
|
<p>
|
255
276
|
Then switch back to this window, and click this
|
@@ -1064,7 +1085,7 @@ function rcvrReport(res, rpath, rfile, run, data, stats, log) {
|
|
1064
1085
|
}
|
1065
1086
|
}
|
1066
1087
|
}
|
1067
|
-
if(n) console.log(n + 'report file' + (n > 1 ? 's' : '') + 'purged');
|
1088
|
+
if(n) console.log(n + ' report file' + (n > 1 ? 's' : '') + ' purged');
|
1068
1089
|
} catch(err) {
|
1069
1090
|
// Log error, but do not abort.
|
1070
1091
|
console.log(err);
|
@@ -1207,16 +1228,20 @@ function processRequest(req, res, cmd, data) {
|
|
1207
1228
|
// NOTE: `data` is a string of form field1=value1&field2=value2& ... etc.
|
1208
1229
|
// regardless of the request method (GET or POST)
|
1209
1230
|
if(permittedFile(cmd)) {
|
1210
|
-
// Path contains valid MIME file type extension => serve if allowed
|
1231
|
+
// Path contains valid MIME file type extension => serve if allowed.
|
1211
1232
|
serveStaticFile(res, cmd);
|
1212
|
-
|
1233
|
+
return;
|
1234
|
+
}
|
1235
|
+
// Be permissive w.r.t. leading and trailing slashes.
|
1236
|
+
cmd = cmd.replace(/^\/+/, '').replace(/\/+$/, '');
|
1237
|
+
if(cmd === 'solver') {
|
1213
1238
|
const
|
1214
1239
|
sp = new URLSearchParams(data),
|
1215
1240
|
action = sp.get('action');
|
1216
|
-
// NOTE:
|
1241
|
+
// NOTE: On remote servers, solver actions require authentication.
|
1217
1242
|
if(action === 'logon') {
|
1218
|
-
// No authentication -- simply return the passed token, "local host"
|
1219
|
-
// server name, and the identifier of the solver
|
1243
|
+
// No authentication -- simply return the passed token, "local host"
|
1244
|
+
// as server name, and the identifier of the solver.
|
1220
1245
|
serveJSON(res,
|
1221
1246
|
{token: 'local host', server: 'local host', solver: SOLVER.id});
|
1222
1247
|
} else if(action === 'png') {
|
@@ -1229,19 +1254,40 @@ function processRequest(req, res, cmd, data) {
|
|
1229
1254
|
console.log(msg);
|
1230
1255
|
serveJSON(res, {error: msg});
|
1231
1256
|
}
|
1232
|
-
} else if(cmd === '
|
1233
|
-
// Shut down this server
|
1257
|
+
} else if(cmd === 'shutdown') {
|
1258
|
+
// Shut down this server WITHOUT updating, and show page with
|
1259
|
+
// "shut down" message and restart button.
|
1260
|
+
clearNewerVersion();
|
1234
1261
|
serveHTML(res, SHUTDOWN_MESSAGE);
|
1235
1262
|
SERVER.close();
|
1236
|
-
} else if(cmd === '
|
1263
|
+
} else if(cmd === 'version') {
|
1264
|
+
logAction('HERE version = ' + VERSION_INFO.current);
|
1265
|
+
servePlainText(res, 'Current version is ' + VERSION_INFO.current);
|
1266
|
+
} else if(cmd === 'update') {
|
1267
|
+
// Shut down this server silently. When the server was started from
|
1268
|
+
// a batch script, this will update via npm, and then restart.
|
1269
|
+
// NOTE: Self-protect against overwriting development scripts.
|
1270
|
+
if(WORKING_DIRECTORY.indexOf('LTR3') >= 0) {
|
1271
|
+
servePlainText(res, 'No version update in development environment');
|
1272
|
+
} else {
|
1273
|
+
setNewerVersion();
|
1274
|
+
servePlainText(res, 'Installing Linny-R version ' + VERSION_INFO.latest);
|
1275
|
+
SERVER.close();
|
1276
|
+
}
|
1277
|
+
} else if(cmd === 'no-update') {
|
1278
|
+
// Remove file "newer_version" so no update will take place when
|
1279
|
+
// server is shut down.
|
1280
|
+
clearNewerVersion();
|
1281
|
+
servePlainText(res, 'No update to version ' + VERSION_INFO.latest);
|
1282
|
+
} else if(cmd === 'auto-check') {
|
1237
1283
|
autoCheck(res);
|
1238
|
-
} else if(cmd === '
|
1284
|
+
} else if(cmd === 'autosave') {
|
1239
1285
|
autoSave(res, new URLSearchParams(data));
|
1240
|
-
} else if(cmd === '
|
1286
|
+
} else if(cmd === 'repo') {
|
1241
1287
|
repo(res, new URLSearchParams(data));
|
1242
|
-
} else if(cmd === '
|
1288
|
+
} else if(cmd === 'load-data') {
|
1243
1289
|
loadData(res, (new URLSearchParams(data)).get('url'));
|
1244
|
-
} else if(cmd === '
|
1290
|
+
} else if(cmd === 'receiver') {
|
1245
1291
|
receiver(res, new URLSearchParams(data));
|
1246
1292
|
} else {
|
1247
1293
|
serveJSON(res, {error: `Unknown Linny-R request: "${cmd}"`});
|
@@ -1249,7 +1295,7 @@ function processRequest(req, res, cmd, data) {
|
|
1249
1295
|
}
|
1250
1296
|
|
1251
1297
|
function servePlainText(res, msg) {
|
1252
|
-
// Serve string `msg` as plain text
|
1298
|
+
// Serve string `msg` as plain text.
|
1253
1299
|
res.setHeader('Content-Type', 'text/plain');
|
1254
1300
|
res.writeHead(200);
|
1255
1301
|
res.end(msg);
|
@@ -1698,28 +1744,53 @@ function createLaunchScript() {
|
|
1698
1744
|
// Creates platform-specific script with Linny-R start-up command
|
1699
1745
|
const lines = [
|
1700
1746
|
'# The first line (without the comment symbol #) should be like this:',
|
1701
|
-
'
|
1747
|
+
'',
|
1702
1748
|
'',
|
1703
1749
|
'# Then this command to launch the Linny-R server should work:',
|
1704
|
-
'
|
1750
|
+
'',
|
1751
|
+
'# After shut-down, check whether new version should be installed:'
|
1705
1752
|
];
|
1753
|
+
lines[2] = 'cd ' + WORKING_DIRECTORY;
|
1706
1754
|
let sp;
|
1707
1755
|
if(PLATFORM.startsWith('win')) {
|
1708
1756
|
sp = path.join(WORKING_DIRECTORY, 'linny-r.bat');
|
1709
|
-
lines
|
1757
|
+
lines.push(
|
1758
|
+
':loop',
|
1759
|
+
'if exist newer_version (',
|
1760
|
+
' del newer_version',
|
1761
|
+
' npm update linny-r',
|
1762
|
+
' node node_modules\\linny-r\\server',
|
1763
|
+
' goto loop',
|
1764
|
+
')');
|
1765
|
+
lines[1] = '# cd C:\\path\\to\\main\\Linny-R\\directory';
|
1766
|
+
lines[4] = 'node node_modules\\linny-r\\server launch';
|
1710
1767
|
} else {
|
1711
1768
|
sp = path.join(WORKING_DIRECTORY, 'linny-r.command');
|
1712
|
-
lines
|
1769
|
+
lines.push(
|
1770
|
+
'while test -f newer_version; do',
|
1771
|
+
' unlink newer_version',
|
1772
|
+
' npm update linny-r',
|
1773
|
+
' node node_modules/linny-r/server',
|
1774
|
+
'done');
|
1775
|
+
lines[1] = '# cd /path/to/main/Linny-R/directory';
|
1776
|
+
lines[4] = 'node node_modules/linny-r/server launch';
|
1713
1777
|
}
|
1714
|
-
lines[2] = 'cd ' + WORKING_DIRECTORY;
|
1715
1778
|
try {
|
1779
|
+
let make_script = false,
|
1780
|
+
code = lines.join(os.EOL);
|
1781
|
+
if(PLATFORM.startsWith('win')) code = code.replaceAll('#', '::');
|
1716
1782
|
try {
|
1717
1783
|
fs.accessSync(sp);
|
1784
|
+
// Only write the script content if the file has not been customized
|
1785
|
+
// by the user...
|
1786
|
+
const data = fs.readFileSync(sp, 'utf-8');
|
1787
|
+
make_script = code.indexOf(data) >= 0;
|
1718
1788
|
} catch(err) {
|
1719
|
-
//
|
1789
|
+
// ... or if it does not exist yet.
|
1790
|
+
make_script = true;
|
1791
|
+
}
|
1792
|
+
if(make_script) {
|
1720
1793
|
console.log('Creating launch script:', sp);
|
1721
|
-
let code = lines.join(os.EOL);
|
1722
|
-
if(PLATFORM.startsWith('win')) code = code.replaceAll('#', '::');
|
1723
1794
|
fs.writeFileSync(sp, code, 'utf8');
|
1724
1795
|
}
|
1725
1796
|
} catch(err) {
|